/** * Synchronizes the user based on a given UserKey. * * @param string $UserKey A string that uniquely identifies this user. * @param array $Data Information to put in the user table. * @return int The ID of the user. */ public function synchronize($UserKey, $Data) { $UserID = 0; $Attributes = val('Attributes', $Data); if (is_string($Attributes)) { $Attributes = dbdecode($Attributes); } if (!is_array($Attributes)) { $Attributes = []; } // If the user didnt log in, they won't have a UserID yet. That means they want a new // account. So create one for them. if (!isset($Data['UserID']) || $Data['UserID'] <= 0) { // Prepare the user data. $UserData = []; $UserData['Name'] = $Data['Name']; $UserData['Password'] = randomString(16); $UserData['Email'] = val('Email', $Data, '*****@*****.**'); $UserData['Gender'] = strtolower(substr(val('Gender', $Data, 'u'), 0, 1)); $UserData['HourOffset'] = val('HourOffset', $Data, 0); $UserData['DateOfBirth'] = val('DateOfBirth', $Data, ''); $UserData['CountNotifications'] = 0; $UserData['Attributes'] = $Attributes; $UserData['InsertIPAddress'] = ipEncode(Gdn::request()->ipAddress()); if ($UserData['DateOfBirth'] == '') { $UserData['DateOfBirth'] = '1975-09-16'; } // Make sure there isn't another user with this username. if ($this->validateUniqueFields($UserData['Name'], $UserData['Email'])) { if (!BanModel::checkUser($UserData, $this->Validation, true)) { throw permissionException('Banned'); } // Insert the new user. $this->addInsertFields($UserData); $UserID = $this->insertInternal($UserData); } if ($UserID > 0) { $NewUserRoleIDs = $this->newUserRoleIDs(); // Save the roles. $Roles = val('Roles', $Data, false); if (empty($Roles)) { $Roles = $NewUserRoleIDs; } $this->saveRoles($UserID, $Roles, false); } } else { $UserID = $Data['UserID']; } // Synchronize the transientkey from the external user data source if it is present (eg. WordPress' wpnonce). if (array_key_exists('TransientKey', $Attributes) && $Attributes['TransientKey'] != '' && $UserID > 0) { $this->setTransientKey($UserID, $Attributes['TransientKey']); } return $UserID; }
/** * * * @param $Sender * @param $Args */ public function base_checkSpam_handler($Sender, $Args) { // Don't check for spam if another plugin has already determined it is. if ($Sender->EventArguments['IsSpam']) { return; } $RecordType = $Args['RecordType']; $Data =& $Args['Data']; $Options =& $Args['Options']; // Detect our favorite bot and short-circuit if ($Reason = val('DiscoveryText', $Data)) { if (substr($Reason, 0, 1) === '{') { $Sender->EventArguments['IsSpam'] = true; $Data['Log_InsertUserID'] = $this->userID(); $Data['RecordIPAddress'] = ipEncode(Gdn::request()->ipAddress()); return; } } $Result = false; switch ($RecordType) { case 'Registration': $Result = self::check($Data, $Options); if ($Result) { $Data['Log_InsertUserID'] = $this->userID(); $Data['RecordIPAddress'] = ipEncode(Gdn::request()->ipAddress()); } break; case 'Comment': case 'Discussion': case 'Activity': // $Result = $this->CheckTest($RecordType, $Data) || $this->CheckStopForumSpam($RecordType, $Data) || $this->CheckAkismet($RecordType, $Data); break; } $Sender->EventArguments['IsSpam'] = $Result; }
/** * Log an operation into the log table. * * @param string $Operation The operation being performed. This is usually one of: * - Delete: The record has been deleted. * - Edit: The record has been edited. * - Spam: The record has been marked spam. * - Moderate: The record requires moderation. * - Pending: The record needs pre-moderation. * @param string $RecordType The type of record being logged. This usually correspond to the tablename of the record. * @param array $Data The record data. * - If you are logging just one row then pass the row as an array. * - You can pass an additional _New element to tell the logger what the new data is. * @param array $Options Additional options to affect the insert. * @return int|false The log ID or **false** if there was a problem. */ public static function insert($Operation, $RecordType, $Data, $Options = []) { if ($Operation === false) { return false; } if (!is_array($Data)) { $Data = [$Data]; } // Check to see if we are storing two versions of the data. if (($InsertUserID = self::logValue($Data, 'Log_InsertUserID')) === null) { $InsertUserID = Gdn::session()->UserID; } if (($InsertIPAddress = self::logValue($Data, 'Log_InsertIPAddress')) == null) { $InsertIPAddress = ipEncode(Gdn::request()->ipAddress()); } // Do some known translations for the parent record ID. if (($ParentRecordID = self::logValue($Data, 'ParentRecordID')) === null) { switch ($RecordType) { case 'Activity': $ParentRecordID = self::logValue($Data, 'CommentActivityID', 'CommentActivityID'); break; case 'Comment': $ParentRecordID = self::logValue($Data, 'DiscussionID', 'DiscussionID'); break; } } // Get the row information from the data or determine it based on the type. $LogRow = ['Operation' => $Operation, 'RecordType' => $RecordType, 'RecordID' => self::logValue($Data, 'RecordID', $RecordType . 'ID'), 'RecordUserID' => self::logValue($Data, 'RecordUserID', 'UpdateUserID', 'InsertUserID'), 'RecordIPAddress' => self::logValue($Data, 'RecordIPAddress', 'LastIPAddress', 'InsertIPAddress'), 'RecordDate' => self::logValue($Data, 'RecordDate', 'DateUpdated', 'DateInserted'), 'InsertUserID' => $InsertUserID, 'InsertIPAddress' => $InsertIPAddress, 'DateInserted' => Gdn_Format::toDateTime(), 'ParentRecordID' => $ParentRecordID, 'CategoryID' => self::logValue($Data, 'CategoryID'), 'OtherUserIDs' => implode(',', val('OtherUserIDs', $Options, [])), 'Data' => dbencode($Data)]; if ($LogRow['RecordDate'] == null) { $LogRow['RecordDate'] = Gdn_Format::toDateTime(); } $GroupBy = val('GroupBy', $Options); // Make sure we aren't grouping by null values. if (is_array($GroupBy)) { foreach ($GroupBy as $Name) { if (val($Name, $LogRow) === null) { $GroupBy = false; break; } } } if ($GroupBy) { $GroupBy[] = 'Operation'; $GroupBy[] = 'RecordType'; // Check to see if there is a record already logged here. $Where = array_combine($GroupBy, arrayTranslate($LogRow, $GroupBy)); $LogRow2 = Gdn::sql()->getWhere('Log', $Where)->firstRow(DATASET_TYPE_ARRAY); if ($LogRow2) { $LogID = $LogRow2['LogID']; $Set = []; $Data = array_merge(dbdecode($LogRow2['Data']), $Data); $OtherUserIDs = explode(',', $LogRow2['OtherUserIDs']); if (!is_array($OtherUserIDs)) { $OtherUserIDs = []; } if (!$LogRow2['InsertUserID']) { $Set['InsertUserID'] = $InsertUserID; } elseif ($InsertUserID != $LogRow2['InsertUserID'] && !in_array($InsertUserID, $OtherUserIDs)) { $OtherUserIDs[] = $InsertUserID; } if (array_key_exists('OtherUserIDs', $Options)) { $OtherUserIDs = array_merge($OtherUserIDs, $Options['OtherUserIDs']); $OtherUserIDs = array_unique($OtherUserIDs); $OtherUserIDs = array_diff($OtherUserIDs, [$InsertUserID]); $Count = count($OtherUserIDs) + 1; } else { $Count = (int) $LogRow2['CountGroup'] + 1; } $Set['OtherUserIDs'] = implode(',', $OtherUserIDs); $Set['CountGroup'] = $Count; $Set['Data'] = dbencode($Data); $Set['DateUpdated'] = Gdn_Format::toDateTime(); if (self::$transactionID > 0) { $Set['TransactionLogID'] = self::$transactionID; } elseif (self::$transactionID === true) { if ($LogRow2['TransactionLogID']) { self::$transactionID = $LogRow2['TransactionLogID']; } else { self::$transactionID = $LogID; $Set['TransactionLogID'] = $LogID; } } Gdn::sql()->put('Log', $Set, ['LogID' => $LogID]); } else { $L = self::instance(); $L->EventArguments['Log'] =& $LogRow; $L->fireEvent('BeforeInsert'); if (self::$transactionID > 0) { $LogRow['TransactionLogID'] = self::$transactionID; } $LogID = Gdn::sql()->insert('Log', $LogRow); if (self::$transactionID === true) { // A new transaction was started and needs to assigned. self::$transactionID = $LogID; Gdn::sql()->put('Log', ['TransactionLogID' => $LogID], ['LogID' => $LogID]); } $L->EventArguments['LogID'] = $LogID; $L->fireEvent('AfterInsert'); } } else { if (self::$transactionID > 0) { $LogRow['TransactionLogID'] = self::$transactionID; } // Insert the log entry. $L = self::instance(); $L->EventArguments['Log'] =& $LogRow; $L->fireEvent('BeforeInsert'); $LogID = Gdn::sql()->insert('Log', $LogRow); if (self::$transactionID === true) { // A new transaction was started and needs to assigned. self::$transactionID = $LogID; Gdn::sql()->put('Log', ['TransactionLogID' => $LogID], ['LogID' => $LogID]); } $L->EventArguments['LogID'] = $LogID; $L->fireEvent('AfterInsert'); } return $LogID; }
/** * Save a comment on an activity. * * @param array $Comment * @return int|bool|string * @since 2.1 */ public function comment($Comment) { $Comment['InsertUserID'] = Gdn::session()->UserID; $Comment['DateInserted'] = Gdn_Format::toDateTime(); $Comment['InsertIPAddress'] = ipEncode(Gdn::request()->ipAddress()); $this->Validation->applyRule('ActivityID', 'Required'); $this->Validation->applyRule('Body', 'Required'); $this->Validation->applyRule('DateInserted', 'Required'); $this->Validation->applyRule('InsertUserID', 'Required'); $this->EventArguments['Comment'] =& $Comment; $this->fireEvent('BeforeSaveComment'); if ($this->validate($Comment)) { $Activity = $this->getID($Comment['ActivityID'], DATASET_TYPE_ARRAY); Gdn::controller()->json('Activity', $Activity); $_ActivityID = $Comment['ActivityID']; // Check to see if this is a shared activity/notification. if ($CommentActivityID = val('CommentActivityID', $Activity['Data'])) { Gdn::controller()->json('CommentActivityID', $CommentActivityID); $Comment['ActivityID'] = $CommentActivityID; } // Check for spam. $Spam = SpamModel::isSpam('ActivityComment', $Comment); if ($Spam) { return SPAM; } // Check for approval $ApprovalRequired = checkRestriction('Vanilla.Approval.Require'); if ($ApprovalRequired && !val('Verified', Gdn::session()->User)) { LogModel::insert('Pending', 'ActivityComment', $Comment); return UNAPPROVED; } $ID = $this->SQL->insert('ActivityComment', $Comment); if ($ID) { // Check to see if this comment bumps the activity. if ($Activity && val('Bump', $Activity['Data'])) { $this->SQL->put('Activity', ['DateUpdated' => $Comment['DateInserted']], ['ActivityID' => $Activity['ActivityID']]); if ($_ActivityID != $Comment['ActivityID']) { $this->SQL->put('Activity', ['DateUpdated' => $Comment['DateInserted']], ['ActivityID' => $_ActivityID]); } } // Send a notification to the original person. if (val('ActivityType', $Activity) === 'WallPost') { $this->notifyWallComment($Comment, $Activity); } } return $ID; } return false; }
/** * Recursively walk through all array elements or object properties and encode IP fields. * * @param array|object $input * @return array|object */ function ipEncodeRecursive($input) { walkAllRecursive($input, function (&$val, $key = null, $parent = null) { if (is_string($val)) { if (stringEndsWith($key, 'IPAddress', true) || stringEndsWith($parent, 'IPAddresses', true)) { $val = ipEncode($val); } } }); return $input; }
/** * Adds $this->UpdateUserID and $this->DateUpdated fields to an associative * array of fieldname/values if those fields exist on the table being updated. * * @param array $Fields The array of fields to add the values to. */ protected function addUpdateFields(&$Fields) { $this->defineSchema(); if ($this->Schema->fieldExists($this->Name, $this->DateUpdated)) { if (!isset($Fields[$this->DateUpdated])) { $Fields[$this->DateUpdated] = Gdn_Format::toDateTime(); } } $Session = Gdn::session(); if ($Session->UserID > 0 && $this->Schema->fieldExists($this->Name, $this->UpdateUserID)) { if (!isset($Fields[$this->UpdateUserID])) { $Fields[$this->UpdateUserID] = $Session->UserID; } } if ($this->Schema->FieldExists($this->Name, 'UpdateIPAddress') && !isset($Fields['UpdateIPAddress'])) { $Fields['UpdateIPAddress'] = ipEncode(Gdn::request()->ipAddress()); } }