/** * Creates a new redirect node * * @param mixed Array of field => value pairs which define the record. * @param array Array of options for the content being created. * Understands skipTransaction, skipFloodCheck, floodchecktime, skipDupCheck, skipNotification, nl2br, autoparselinks. * - nl2br: if TRUE, all \n will be converted to <br /> so that it's not removed by the html parser (e.g. comments). * @param bool Convert text to bbcode * * @return mixed array with nodeid (int), success (bool), cacheEvents (array of strings), nodeVals (array of field => value). */ public function add($data, array $options = array(), $convertWysiwygTextToBbcode = false) { $options['skipFloodCheck'] = true; $options['skipDupCheck'] = true; $options['skipNotification'] = true; $options['skipUpdateLastContent'] = true; return parent::add($data, $options, $convertWysiwygTextToBbcode); }
/** * Adds a new node. * * @param mixed Array of field => value pairs which define the record. * @param array Array of options for the content being created * Understands skipTransaction, skipFloodCheck, floodchecktime, skipDupCheck, skipNotification, nl2br, autoparselinks. * - nl2br: if TRUE, all \n will be converted to <br /> so that it's not removed by the html parser (e.g. comments). * @param bool Convert text to bbcode * * @return array array with * * nodeid (int) * * success (bool), * * cacheEvents (array of strings), * * nodeVals (array of field => value) * * attachments (array of attachment records). */ public function add($data, array $options = array(), $convertWysiwygTextToBbcode = true) { try { //Store this so we know whether we should call afterAdd() $skipTransaction = !empty($options['skipTransaction']); if (!$skipTransaction) { $this->assertor->beginTransaction(); } $options['skipTransaction'] = true; $result = parent::add($data, $options, $convertWysiwygTextToBbcode); // @todo is this not already done in the vB_Library_Content_Text class? //We want to save in one batch. Otherwise if moderation is set the attached photos will be lost. //See VBV-12360 if (is_int($result['nodeid']) and !empty($data['photos'])) { // Note, photos' data are now cleaned at the vB_Api_Content_Text level in cleanInput() if (!empty($data['photos']) and is_array($data['photos'])) { $photoLib = vB_Library::instance('content_photo'); $node = $this->getFullContent($result['nodeid']); $node = array_pop($node); $published = $node['showpublished']; foreach ($data['photos'] as $photo) { $photo['parentid'] = $result['nodeid']; $photo['showpublished'] = $published; $photo['showapproved'] = $published; if (!isset($photo['options'])) { $photo['options'] = $options; } //We must have skipTransaction set or the photo api will attempt to start a transaction and cause an exception $photo['options']['skipTransaction'] = true; $photoLib->add($photo, $photo['options']); } } } // Obtain and set generic conversation route $conversation = $this->getConversationParent($result['nodeid']); $routeid = vB_Api::instanceInternal('route')->getChannelConversationRoute($conversation['parentid']); $this->assertor->update('vBForum:node', array('routeid' => $routeid), array('nodeid' => $result['nodeid'])); if (!$skipTransaction) { $this->assertor->commitTransaction(); } } catch (exception $e) { if (!$skipTransaction) { $this->assertor->rollbackTransaction(); } throw $e; } if (!$skipTransaction) { //The child classes that have their own transactions all set this to true so afterAdd is always called just once. $this->afterAdd($result['nodeid'], $data, $options, $result['cacheEvents'], $result['nodeVals']); } //basic cache events are cleared in the parent class return $result; }
/** * Adds a new node. * * @param mixed Array of field => value pairs which define the record. * Understands skipTransaction, skipFloodCheck, floodchecktime, skipDupCheck, skipNotification, nl2br, autoparselinks. * - nl2br: if TRUE, all \n will be converted to <br /> so that it's not removed by the html parser (e.g. comments). * @param bool Convert text to bbcode * * @return mixed array with nodeid (int), success (bool), cacheEvents (array of strings), * nodeVals (array of field => value), attachments (array of attachment records). */ public function add($data, array $options = array(), $convertWysiwygTextToBbcode = true) { // TODO: Permission check // $loginuser = &vB::getCurrentSession()->fetch_userinfo(); // $usercontext = &vB::getUserContext($loginuser['userid']); // if (!$usercontext->hasPermission('forumpermissions', 'canpostvideo')) // { // throw new Exception('no_permission'); // } //Store this so we know whether we should call afterAdd() $skipTransaction = !empty($options['skipTransaction']); $videoitems = $this->checkVideoData($data); unset($data['videoitems']); if (!$videoitems) { throw new vB_Exception_Api("invalid_videoitems"); } try { if (!$skipTransaction) { $this->assertor->beginTransaction(); } $options['skipTransaction'] = true; $result = parent::add($data, $options, $convertWysiwygTextToBbcode); // Save video items foreach ($videoitems as $item) { $this->assertor->assertQuery("videoitem", array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_INSERT, 'nodeid' => $result['nodeid'], 'provider' => $item['provider'], 'code' => $item['code'], 'url' => $item['url'])); } if (!$skipTransaction) { $this->assertor->commitTransaction(); } } catch (exception $e) { if (!$skipTransaction) { $this->assertor->rollbackTransaction(); } throw $e; } if (!$skipTransaction) { //The child classes that have their own transactions all set this to true so afterAdd is always called just once. $this->afterAdd($result['nodeid'], $data, $options, $result['cacheEvents'], $result['nodeVals']); } //indexing is done in the parent class return $result; }
public function add($data, array $options = array(), $convertWysiwygTextToBbcode = true) { //Store this so we know whether we should call afterAdd() $skipTransaction = !empty($options['skipTransaction']); $this->checkPollOptions($data); // Add the poll options (answers) to the standard content add method $options array $options = array_merge($data['options'], $options); // Keep an array of *only* the poll options, without the other options in the standard array $pollOptions = $data['options']; if (isset($data['parseurl'])) { $parseurl = $data['parseurl']; if ($parseurl) { require_once DIR . '/includes/functions_newpost.php'; } } unset($data['options'], $data['parseurl']); // skip the index in the parent and do it here so it can include the options $data['noIndex'] = true; try { if (!$skipTransaction) { $this->assertor->beginTransaction(); } $options['skipTransaction'] = true; $result = parent::add($data, $options, $convertWysiwygTextToBbcode); // Save poll options foreach ($pollOptions as $option) { if (isset($parseurl) and $parseurl) { $option['title'] = convert_url_to_bbcode($option['title']); } // Insert new option $this->assertor->assertQuery('vBForum:polloption', array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_INSERT, 'nodeid' => $result['nodeid'], 'title' => $option['title'])); } if (!$skipTransaction) { $this->assertor->commitTransaction(); } } catch (exception $e) { if (!$skipTransaction) { $this->assertor->rollbackTransaction(); } throw $e; } if (!$skipTransaction) { //The child classes that have their own transactions all set this to true so afterAdd is always called just once. $this->afterAdd($result['nodeid'], $data, $options, $result['cacheEvents'], $result['nodeVals']); } $this->updatePollCache($result['nodeid']); // do the indexing after the options are added $this->nodeApi->clearCacheEvents(array($result['nodeid'], $data['parentid'])); vB_Api::instance('Search')->index($result['nodeid']); return $result; }
/** * Adds a new infraction node * * @param mixed Array of field => value pairs which define the record. * @param array Array of options for the content being created * Understands skipTransaction, skipFloodCheck, floodchecktime, skipDupCheck, skipNotification, nl2br, autoparselinks. * - nl2br: if TRUE, all \n will be converted to <br /> so that it's not removed by the html parser (e.g. comments). * @return mixed array with nodeid (int), success (bool), cacheEvents (array of strings), nodeVals (array of field => value), attachments (array of attachment records). */ public function add($data, array $options = array(), $convertWysiwygTextToBbcode = true) { //Store this so we know whether we should call afterAdd() $skipTransaction = !empty($options['skipTransaction']); $infractionLevels = $this->getInfractionLevels(); $this->validateInfractionData($data, $infractionLevels); //An infraction should never be rejected because of duplication. $options['skipDupCheck'] = true; $infractedNode = $this->getInfractedNode($data); $infractedUserInfo = vB_User::fetchUserinfo($data['infracteduserid']); $infractionLevelInfo = $this->getInfractionLevelInfo($data, $infractionLevels); $isWarning = $this->isWarning($data, $infractionLevelInfo); $banToApply = $this->getAutomaticBanToApply($infractedUserInfo, $data, $infractionLevelInfo, $isWarning); // set infraction level info $data['points'] = $isWarning ? 0 : $infractionLevelInfo['points']; $data['reputation_penalty'] = $isWarning ? 0 : $infractionLevelInfo['reputation_penalty']; $data['expires'] = $this->getExpires($infractionLevelInfo, $data['infracteduserid']); $data['customreason'] = !empty($data['customreason']) ? $data['customreason'] : ''; // make sure we have something for admin note and pm message $data['note'] = empty($data['note']) ? '' : $data['note']; $data['message'] = empty($data['message']) ? '' : $data['message']; // set parentid $data['parentid'] = $this->infractionChannel; // set title & pagetext $data['title'] = $this->getInfractionTitle($data, $infractedNode, $infractedUserInfo, $infractionLevelInfo, $isWarning); $data['rawtext'] = $this->getInfractionPagetext($data, $infractedNode, $infractedUserInfo, $infractionLevelInfo); try { if (!$skipTransaction) { $this->assertor->beginTransaction(); } $options['skipTransaction'] = true; // *** add the infraction and populate the return info*** $result = parent::add($data, $options, $convertWysiwygTextToBbcode); $result['infractionNodeid'] = $result['nodeid']; $result['isWarning'] = $isWarning ? 1 : 0; // applying the reputation penalty if ($data['reputation_penalty']) { $this->assertor->assertQuery('decUserReputation', array('penalty' => $data['reputation_penalty'], 'userid' => $infractedUserInfo['userid'])); vB_Cache::allCacheEvent('userChg_' . $infractedUserInfo['userid']); } // invalidate cache $clearCacheNodeIds = array($data['parentid']); if (!$skipTransaction) { $this->assertor->commitTransaction(); } } catch (exception $e) { if (!$skipTransaction) { $this->assertor->rollbackTransaction(); } throw $e; } if (!$skipTransaction) { //The child classes that have their own transactions all set this to true so afterAdd is always called just once. $this->afterAdd($result['nodeid'], $data, $options, $result['cacheEvents'], $result['nodeVals']); } // update denormalized values if (empty($result['errors'])) { if ($data['infractednodeid']) { // mark the infracted node's text record as having an infraction or warning // 1 = infraction, 2 = warning, 0 = no infraction or warning (or an expired/reversed infraction) $this->assertor->update('vBforum:text', array('infraction' => $isWarning ? 2 : 1), array('nodeid' => $data['infractednodeid'])); } // update user info for infractions, warnings, and ipoints $this->updateDenormalizedUserData($data['infracteduserid']); // update infractiongroupids $this->buildInfractionGroupIds(array($infractedUserInfo['userid'])); // send PM to infracted user if (!empty($data['message'])) { $result['pmNodeid'] = $this->sendPm($data, $infractedNode, $infractedUserInfo, $infractionLevelInfo, $isWarning, $banToApply); } $clearCacheNodeIds[] = $result['nodeid']; $clearCacheNodeIds[] = $data['infractednodeid']; } // ban user if applicable if ($banToApply) { $this->applyAutomaticBan($infractedUserInfo, $banToApply, $data); } $this->nodeApi->clearCacheEvents($clearCacheNodeIds); return $result; }
/** * This adds a new message * * @param mixed must include 'sentto', 'contenttypeid', and the necessary data for that contenttype. * @param array Array of options for the content being created. * Understands skipTransaction, skipFloodCheck, floodchecktime, skipDupCheck, skipNotification, nl2br, autoparselinks, skipNonExistentRecipients. * - nl2br: if TRUE, all \n will be converted to <br /> so that it's not removed by the html parser (e.g. comments). * - skipNonExistentRecipients (bool) skips recipients that don't exist instead of throwing an exception. * * @return mixed array with errors, or nodeid. * * Notes: For Notifications, go through the notification library. **/ public function add($data, array $options = array(), $convertWysiwygTextToBbcode = true) { //If we're installing, just abort. if (defined('VBINSTALL')) { return true; } //Store this so we know whether we should call afterAdd() $skipTransaction = !empty($options['skipTransaction']); $sender = $data['sender']; if (isset($data['msgRecipients']) and empty($data['sentto'])) { $recipientNames = explode(',', $data['msgRecipients']); foreach ($recipientNames as $k => $name) { $recipientNames[$k] = vB_String::htmlSpecialCharsUni($name); } $recipQry = $this->assertor->getRows('fetchPmRecipients', array('usernames' => $recipientNames, 'userid' => $sender)); if (!$recipQry or !empty($recipQry['errors'])) { throw new vB_Exception_Api('invalid_pm_recipients'); } foreach ($recipQry as $recipient) { $this->checkCanReceivePM($recipient); $data['sentto'][] = $recipient['userid']; } } if (!isset($data['msgtype']) or $data['msgtype'] != 'request' and $data['msgtype'] != 'notification') { $data['msgtype'] = 'message'; } else { if ($data['msgtype'] == 'notification') { if (empty($data['about']) or empty($data['aboutid']) or empty($data['sentto'])) { throw new vB_Exception_Api('invalid_data'); } } } //If we have a message we need text content if ($data['msgtype'] == 'message' and (empty($data['rawtext']) and empty($data['pagetext']))) { throw new vB_Exception_Api('need_privatemessage_text'); } if ($data['msgtype'] == 'request' and (empty($data['rawtext']) and empty($data['pagetext'])) and !empty($data['sentto'])) { $recipient = vB_User::fetchUserinfo($data['sentto']); switch ($data['about']) { case vB_Api_Node::REQUEST_TAKE_OWNER: $channel = vB_Library::instance('node')->getNodeBare($data['aboutid']); $phrase = vB_Api::instanceInternal('phrase')->fetch(array('sent_ownership_transfer_request_for_x_to_y')); $data['rawtext'] = $data['pagetext'] = vsprintf($phrase['sent_ownership_transfer_request_for_x_to_y'], array($channel['title'], $recipient['username'])); break; case vB_Api_Node::REQUEST_TAKE_MODERATOR: $channel = vB_Library::instance('node')->getNodeBare($data['aboutid']); $phrase = vB_Api::instanceInternal('phrase')->fetch(array('sent_moderation_request_for_x_to_y')); $data['rawtext'] = $data['pagetext'] = vsprintf($phrase['sent_moderation_request_for_x_to_y'], array($channel['title'], $recipient['username'])); break; case vB_Api_Node::REQUEST_GRANT_MEMBER: $channel = vB_Library::instance('node')->getNodeBare($data['aboutid']); $phrase = vB_Api::instanceInternal('phrase')->fetch(array('sent_subscription_request_to_x')); $data['rawtext'] = $data['pagetext'] = vsprintf($phrase['sent_subscription_request_to_x'], $channel['title']); break; case vB_Api_Node::REQUEST_SG_GRANT_SUBSCRIBER: $channel = vB_Library::instance('node')->getNodeBare($data['aboutid']); $phrase = vB_Api::instanceInternal('phrase')->fetch(array('sent_subscription_request_to_x')); $data['rawtext'] = $data['pagetext'] = vsprintf($phrase['sent_subscription_request_to_x'], $channel['title']); break; default: $phrase = vB_Api::instanceInternal('phrase')->fetch(array('sent_follow_request_to_x')); $data['rawtext'] = $data['pagetext'] = vsprintf($phrase['sent_follow_request_to_x'], $recipient['username']); break; } } // don't check the skipNonExistentRecipients option since // we're actually checking the *sender's* folders here. // I have added this option because of upgrade failure in specific circumstances described in VBV-13331 $skipNonExistentRecipients = !empty($options['skipNonExistentRecipients']); $this->checkFolders($sender, $skipNonExistentRecipients); $sendto = array(); if (isset($data['respondto'])) { //We have a forward/reply. We maintain the node hierarchy. If it's a reply // we also need to keep the list of recipients. $data['parentid'] = $data['respondto']; //Obviously we've read this, if we're forwarding it. $this->setRead($data['respondto'], 1, $sender); $recipients = $this->assertor->getRows('vBForum:getRecipientsForNode', array('nodeid' => $data['respondto'])); $msgSender = 0; $senderIncluded = false; foreach ($recipients as $recipient) { if ($msgSender) { continue; } if ($recipient['folder'] == self::SENT_FOLDER) { $msgSender = $recipient['userid']; } } foreach ($recipients as $recipient) { $this->checkCanReceivePM($recipient); if ($recipient['userid'] == $msgSender and $recipient['folder'] != self::SENT_FOLDER) { $senderIncluded = true; } $data['sentto'][] = intval($recipient['userid']); } } else { if (isset($data['forward'])) { if (empty($data['sentto'])) { throw new vB_Exception_Api('invalid_request'); } $data['parentid'] = $this->pmChannel; //Obviously we've read this, if we're forwarding it. $this->setRead($data['forward'], 1, $sender); } else { //We'll get the folders into which we need to insert this record. In the process we'll // validate that all the sentto id's are valid. $data['parentid'] = $this->pmChannel; } } if (empty($data['sentto'])) { throw new vB_Exception_Api('invalid_data'); } if (!is_array($data['sentto'])) { $sendto = array($data['sentto']); } else { $sendto = array_unique($data['sentto']); } //We can't pass recipients to the parent add method. $data['userid'] = $sender; $fields = array('parentid', 'rawtext', 'pagetext', 'msgtype', 'title', 'userid', 'about', 'aboutid', 'folderid', 'deleted', 'msgread', 'publishdate', 'url', 'filedataid', 'url_title', 'url_meta', 'url_image', 'attachments'); $contentData = array(); foreach ($fields as $field) { if (isset($data[$field])) { $contentData[$field] = $data[$field]; } } try { $options['skipTransaction'] = true; // create the node, unless it's a notification if (!($data['msgtype'] == 'notification')) { if (!$skipTransaction) { $this->assertor->beginTransaction(); } $result = parent::add($contentData, $options, $convertWysiwygTextToBbcode); } else { // USE THE NOTIFICATION LIBRARY throw new vB_Exception_Api('invalid_data'); } if (!$result or !empty($result['errors']) or !intval($result['nodeid'])) { if (!$skipTransaction) { $this->assertor->rollbackTransaction(); } throw new vB_Exception_Api('invalid_data'); } if (!$skipTransaction) { $this->assertor->commitTransaction(); } } catch (exception $e) { if (!$skipTransaction) { $this->assertor->rollbackTransaction(); } throw $e; } $nodeid = $result['nodeid']; //If we are passed 'request', then this is just inserted for the recipient. But the user must be an admin. $insertSent = false; if ($data['msgtype'] == 'notification') { // USE THE NOTIFICATION LIBRARY throw new vB_Exception_Api('invalid_request'); //$folderKey = self::NOTIFICATION_FOLDER; } else { if ($data['msgtype'] == 'request') { $folderKey = self::REQUEST_FOLDER; } else { $folderKey = self::MESSAGE_FOLDER; $insertSent = true; } } $userOptions = vB::getDatastore()->getValue('bf_misc_useroptions'); //Note that if this is a response, sendto is empty. foreach ($sendto as $recipient) { // verify recipient's folders, but instruct checkFolders to not throw // an exception if we have an invalid recipient $folderCheck = $this->checkFolders($recipient, $skipNonExistentRecipients); if ($skipNonExistentRecipients and isset($folderCheck['result']) and $folderCheck['result'] === 'user_skipped') { // bad recipient; skip this notification and continue continue; } $sendData = array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_INSERT, 'userid' => $recipient, 'nodeid' => $result['nodeid'], 'folderid' => $this->folders[$recipient]['systemfolders'][$folderKey]); // create a sentto record only if it's not an existing notification if (!($data['msgtype'] == 'notification' and ($existingNotification and !empty($existingNotification) and empty($existingNotification['errors'])))) { $this->assertor->assertQuery('vBForum:sentto', $sendData); } // Going through user LIB not API. The API will mask the email field unless current user // has canadminusers. $recipientInfo = vB_Library::instance('User')->fetchUserinfo($recipient); $emailOnPm = $recipientInfo['options'] & $userOptions['emailonpm']; if ($recipientInfo['emailnotification'] == 1) { if ($contentData['msgtype'] == 'request') { $contentData['sentto'] = $data['sentto']; $contentData['folderid'] = $this->folders[$recipient]['systemfolders'][$folderKey]; $contentData['email'] = $recipientInfo['email']; $contentData['username'] = $recipientInfo['username']; $this->sendEmailNotification($contentData); } } // only send email about PM if this is a message, recipient isn't the sender & the recipient opted in. $sendPMEmail = ($data['msgtype'] == 'message' and $recipient != vB::getCurrentSession()->get('userid') and $emailOnPm); if ($sendPMEmail) { $data['folderid'] = $this->folders[$recipient]['systemfolders'][$folderKey]; $data['recipient'] = $recipient; $data['contentid'] = $result['nodeid']; $data['email'] = $recipientInfo['email']; $data['username'] = $recipientInfo['username']; $this->sendEmailNotification($data); } } // insert message starter for sender if needed if (isset($data['respondto']) and $data['respondto'] and ($msgSender and !$senderIncluded)) { // don't check the skipNonExistentRecipients option since // we're actually checking the *sender's* folders here. // I added the flag bacause update failures described in VBV-13331 $this->checkFolders($msgSender, $skipNonExistentRecipients); $sendData = array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_INSERT, 'userid' => $msgSender, 'nodeid' => $data['respondto'], 'folderid' => $this->folders[$msgSender]['systemfolders'][$folderKey], 'msgread' => 1); $this->assertor->assertQuery('vBForum:sentto', $sendData); } //If this is a new message, we also insert a "sentto" record for the sender, but we mark that "read". //That ensures we properly handle replies. if (!in_array($data['msgtype'], array('notification', 'request'))) { //If someone deleted their message we need to restore it. For that we need the starter. //This can only occur, of course, if this is a response. $existing = $this->nodeApi->getNode($data['parentid']); // only check the "trash" and "messages" folders for everyone. We don't want to accidentally change // something in the sent_items folder, for instance $includeFoldersQry = $this->assertor->getRows('vBForum:messagefolder', array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_SELECT, 'titlephrase' => array(self::TRASH_FOLDER, self::MESSAGE_FOLDER), vB_Db_Query::COLUMNS_KEY => array('folderid'))); $includeFolders = array(-1); // -1 so that array is not empty. Other wise IN clause breaks foreach ($includeFoldersQry as $includeFolder) { $includeFolders[] = $includeFolder['folderid']; } $queryData = array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_UPDATE, vB_dB_Query::CONDITIONS_KEY => array(array('field' => 'nodeid', 'value' => $existing['starter']), array('field' => 'userid', 'value' => $sender, 'operator' => vB_dB_Query::OPERATOR_NE), 'folderid' => $includeFolders), 'msgread' => 0, 'deleted' => 0); $this->assertor->assertQuery('vBForum:sentto', $queryData); // @TODO : Shouldn't we move the "restored" messages back to the inbox...? $this->setRead($nodeid, 1, $sender, 'sent_items'); } if ($insertSent) { // don't check the skipNonExistentRecipients option since // we're actually checking the *sender's* folders here. $this->checkFolders($sender, $skipNonExistentRecipients); $queryData = array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_INSERT, 'userid' => $sender, 'nodeid' => $result['nodeid'], 'folderid' => $this->folders[$sender]['systemfolders'][self::SENT_FOLDER], 'msgread' => 1); $this->assertor->assertQuery('vBForum:sentto', $queryData); } $sendto[] = $sender; // duplicate ids is fine in this array $this->buildPmTotals($sendto); if (!$skipTransaction) { //The child classes that have their own transactions all set this to true so afterAdd is always called just once. $this->afterAdd($result['nodeid'], $data, $options, $result['cacheEvents'], $result['nodeVals']); } vB_Api::instance('Search')->index($result['nodeid']); //update user cached info if ($folderKey == self::MESSAGE_FOLDER) { vB_Library::instance('user')->clearUserInfo($sendto); } return $result; }
/** * Adds a new node. * * @param mixed Array of field => value pairs which define the record. * @param array Array of options for the content being created. * Understands skipTransaction, skipFloodCheck, floodchecktime, skipDupCheck, skipNotification, nl2br, autoparselinks. * - nl2br: if TRUE, all \n will be converted to <br /> so that it's not removed by the html parser (e.g. comments). * @param bool Convert text to bbcode * * @return mixed array with nodeid (int), success (bool), cacheEvents (array of strings), nodeVals (array of field => value), attachments (array of attachment records). */ public function add($data, array $options = array(), $convertWysiwygTextToBbcode = true) { //Store this so we know whether we should call afterAdd() $skipTransaction = !empty($options['skipTransaction']); $vboptions = vB::getDatastore()->getValue('options'); $reportemail = ($vboptions['enableemail'] and $vboptions['rpemail']); $data['reportnodeid'] = intval($data['reportnodeid']); // Build node title based on reportnodeid if (!$data['reportnodeid']) { throw new vB_Exception_Api('invalid_report_node'); } $data['parentid'] = $this->ReportChannel; if (empty($data['title'])) { $reportnode = $this->nodeApi->getNodeFullContent($data['reportnodeid']); $reportnode = $reportnode[$data['reportnodeid']]; $phraseapi = vB_Api::instanceInternal('phrase'); if ($reportnode['nodeid'] == $reportnode['starter']) { // Thread starter $data['title'] = $reportnode['title']; } elseif ($reportnode['parentid'] == $reportnode['starter']) { $phrases = $phraseapi->fetch(array('reply_to')); $data['title'] = $phrases['reply_to'] . ' ' . $reportnode['startertitle']; } else { $phrases = $phraseapi->fetch(array('comment_in_a_topic')); $data['title'] = $phrases['comment_in_a_topic'] . ' ' . $reportnode['startertitle']; } } $result = parent::add($data, $options, $convertWysiwygTextToBbcode); if (!$skipTransaction) { //The child classes that have their own transactions all set this to true so afterAdd is always called just once. $this->afterAdd($result['nodeid'], $data, $options, $result['cacheEvents'], $result['nodeVals']); } // send an email if ($reportemail) { $reporterInfo = vB::getCurrentSession()->fetch_userinfo(); $nodeLib = vB_Library::instance('node'); $moderators = array(); $moderatorUsernames = ''; // Get moderators on the reported node $moderatorsArray = $nodeLib->getNodeModerators($reportnode['nodeid']); foreach ($moderatorsArray as $moderator) { $moderators[$moderator['userid']] = $moderator['userid']; } if ($vboptions['rpemail'] == 2) { // Fetch admins and super moderators $allmoderators = $nodeLib->getForumSupermoderatorsAdmins($moderators); foreach ($allmoderators as $moderator) { $moderators[$moderator['userid']] = $moderator['userid']; } } // get user info foreach ($moderators as $moderatorid => $moderator) { $moderators[$moderatorid] = vB_Library::instance('user')->fetchUserinfo($moderatorid); $moderatorUsernames .= $moderators[$moderatorid]['username'] . ', '; } // Compose the email if ($reportnode['starter'] == $reportnode['nodeid']) { $maildata = vB_Api::instanceInternal('phrase')->fetchEmailPhrases('reportpost_newthread', array(vB5_Route::buildUrl('profile|fullurl', array('userid' => $reporterInfo['userid'])), $reporterInfo['username'], $data['rawtext'], vB5_Route::buildUrl($reportnode['routeid'] . '|fullurl', array('nodeid' => $reportnode['nodeid'], 'title' => $reportnode['title'])), $reportnode['title'], vB::getDatastore()->getOption('bbtitle'), substr($moderatorUsernames, 0, -2), $reportnode['authorname'], vB5_Route::buildUrl('profile|fullurl', array('userid' => $reportnode['userid'])), vB_String::getPreviewText($reportnode['rawtext'])), array($reporterInfo['username'])); } else { $maildata = vB_Api::instanceInternal('phrase')->fetchEmailPhrases('reportpost', array($reporterInfo['username'], $reporterInfo['email'], $reportnode['title'], vB5_Route::buildUrl($reportnode['routeid'] . '|fullurl', array('nodeid' => $reportnode['starter'], 'userid' => $reportnode['starteruserid'], 'username' => $reportnode['starterauthorname'], 'innerPost' => $reportnode['nodeid'], 'innerPostParent' => $reportnode['parentid'])), $reportnode['startertitle'], vB5_Route::buildUrl($reportnode['routeid'] . '|fullurl', array('nodeid' => $reportnode['starter'], 'title' => $reportnode['startertitle'])), $data['rawtext']), array(vB::getDatastore()->getOption('bbtitle'))); } // Send out the emails foreach ($moderators as $moderator) { if (!empty($moderator['email'])) { vB_Mail::vbmail($moderator['email'], $maildata['subject'], $maildata['message'], false); } } } return $result; }
public function add($data, array $options = array(), $convertWysiwygTextToBbcode = true) { $this->validateLinkData($data, __FUNCTION__); //Store this so we know whether we should call afterAdd() $skipTransaction = !empty($options['skipTransaction']); /** Validate Filedata */ if (!empty($data["filedataid"])) { $this->validateFileData($data['filedataid']); } // increment refcount for the image (if it has one) if ($data['filedataid'] > 0) { vB::getDbAssertor()->assertQuery('updateFiledataRefCount', array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_STORED, 'countChange' => 1, 'filedataid' => $data["filedataid"])); } $options['skipTransaction'] = true; $result = parent::add($data, $options, $convertWysiwygTextToBbcode); //indexing and cache clear are done in the parent if (!$skipTransaction) { //The child classes that have their own transactions all set this to true so afterAdd is always called just once. $this->afterAdd($result['nodeid'], $data, $options, $result['cacheEvents'], $result['nodeVals']); } return $result; }