/**
  *
  *
  * @param $Row
  */
 protected static function calculate(&$Row)
 {
     if (!$Row) {
         return;
     }
     $Attributes = dbdecode($Row['Attributes']);
     if (is_array($Attributes)) {
         $Row = array_merge($Attributes, $Row);
     }
     unset($Row['Attributes']);
 }
Ejemplo n.º 2
0
 /**
  * {@inheritDoc}
  * @param array $Data
  * @param bool $Settings
  * @return bool|mixed Primary Key Value
  */
 public function save($Data, $Settings = false)
 {
     $this->defineSchema();
     $SchemaFields = $this->Schema->fields();
     $SaveData = array();
     $Attributes = array();
     // Grab the current attachment.
     if (isset($Data['AttachmentID'])) {
         $PrimaryKeyVal = $Data['AttachmentID'];
         $CurrentAttachment = $this->SQL->getWhere('Attachment', array('AttachmentID' => $PrimaryKeyVal))->firstRow(DATASET_TYPE_ARRAY);
         if ($CurrentAttachment) {
             $Attributes = dbdecode($CurrentAttachment['Attributes']);
             if (!$Attributes) {
                 $Attributes = array();
             }
             $Insert = false;
         } else {
             $Insert = true;
         }
     } else {
         $PrimaryKeyVal = false;
         $Insert = true;
     }
     // Grab any values that aren't in the db schema and stick them in attributes.
     foreach ($Data as $Name => $Value) {
         if ($Name == 'Attributes') {
             continue;
         }
         if (isset($SchemaFields[$Name])) {
             $SaveData[$Name] = $Value;
         } elseif ($Value === null) {
             unset($Attributes[$Name]);
         } else {
             $Attributes[$Name] = $Value;
         }
     }
     if (sizeof($Attributes)) {
         $SaveData['Attributes'] = $Attributes;
     } else {
         $SaveData['Attributes'] = null;
     }
     if ($Insert) {
         $this->addInsertFields($SaveData);
     } else {
         $this->addUpdateFields($SaveData);
     }
     // Validate the form posted values.
     if ($this->validate($SaveData, $Insert) === true) {
         $Fields = $this->Validation->validationFields();
         if ($Insert === false) {
             unset($Fields[$this->PrimaryKey]);
             // Don't try to update the primary key
             $this->update($Fields, array($this->PrimaryKey => $PrimaryKeyVal));
         } else {
             $PrimaryKeyVal = $this->insert($Fields);
         }
     } else {
         $PrimaryKeyVal = false;
     }
     return $PrimaryKeyVal;
 }
Ejemplo n.º 3
0
 /**
  *
  *
  * @param string $Column
  * @param int $RowID
  * @param string $Name
  * @param string $Value
  * @return bool|Gdn_DataSet|object|string
  * @throws Exception
  */
 public function saveToSerializedColumn($Column, $RowID, $Name, $Value = '')
 {
     if (!isset($this->Schema)) {
         $this->defineSchema();
     }
     // TODO: need to be sure that $this->PrimaryKey is only one primary key
     $FieldName = $this->PrimaryKey;
     // Load the existing values
     $Row = $this->SQL->select($Column)->from($this->Name)->where($FieldName, $RowID)->get()->firstRow();
     if (!$Row) {
         throw new Exception(T('ErrorRecordNotFound'));
     }
     $Values = dbdecode($Row->{$Column});
     if (is_string($Values) && $Values != '') {
         throw new Exception(T('Serialized column failed to be unserialized.'));
     }
     if (!is_array($Values)) {
         $Values = array();
     }
     if (!is_array($Name)) {
         // Assign the new value(s)
         $Name = array($Name => $Value);
     }
     $Values = dbencode(array_merge($Values, $Name));
     // Save the values back to the db
     return $this->SQL->from($this->Name)->where($FieldName, $RowID)->set($Column, $Values)->put();
 }
Ejemplo n.º 4
0
 /**
  *
  *
  * @param $Table
  * @param $Key
  * @param int $Limit
  * @param bool $Max
  * @return array|mixed
  */
 public function getBatch($Table, $Key, $Limit = 10000, $Max = false)
 {
     $Key = "DBA.Range.{$Key}";
     // See if there is already a range.
     $Current = dbdecode(Gdn::get($Key, ''));
     if (!is_array($Current) || !isset($Current['Min']) || !isset($Current['Max'])) {
         list($Current['Min'], $Current['Max']) = $this->primaryKeyRange($Table);
         if ($Max && $Current['Max'] > $Max) {
             $Current['Max'] = $Max;
         }
     }
     if (!isset($Current['To'])) {
         $Current['To'] = $Current['Max'];
     } else {
         $Current['To'] -= $Limit - 1;
     }
     $Current['From'] = $Current['To'] - $Limit;
     Gdn::set($Key, dbencode($Current));
     $Current['Complete'] = $Current['To'] < $Current['Min'];
     $Total = $Current['Max'] - $Current['Min'];
     if ($Total > 0) {
         $Complete = $Current['Max'] - $Current['From'];
         $Percent = 100 * $Complete / $Total;
         if ($Percent > 100) {
             $Percent = 100;
         }
         $Current['Percent'] = round($Percent) . '%';
     }
     return $Current;
 }
Ejemplo n.º 5
0
 /**
  *
  *
  * @param $Sender
  */
 public function discussionController_beforeDiscussionRender_handler($Sender)
 {
     if (!Gdn::session()->isValid()) {
         return;
     }
     $UserPrefs = dbdecode(Gdn::session()->User->Preferences);
     if (!is_array($UserPrefs)) {
         $UserPrefs = array();
     }
     $QuoteFolding = val('Quotes.Folding', $UserPrefs, '1');
     $Sender->addDefinition('QuotesFolding', $QuoteFolding);
 }
Ejemplo n.º 6
0
 /**
  *
  *
  * @param null $client_id
  * @return array|mixed
  */
 public static function getProvider($client_id = null)
 {
     if ($client_id !== null) {
         $Where = ['AuthenticationKey' => $client_id];
     } else {
         $Where = ['AuthenticationSchemeAlias' => 'jsconnect'];
     }
     $Result = Gdn::sql()->getWhere('UserAuthenticationProvider', $Where)->resultArray();
     foreach ($Result as &$Row) {
         $Attributes = dbdecode($Row['Attributes']);
         if (is_array($Attributes)) {
             $Row = array_merge($Attributes, $Row);
         }
     }
     if ($client_id) {
         return val(0, $Result, false);
     } else {
         return $Result;
     }
     return $Result;
 }
Ejemplo n.º 7
0
 /**
  * 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;
 }
Ejemplo n.º 8
0
 /**
  * Edit user's preferences (mostly notification settings).
  *
  * @since 2.0.0
  * @access public
  * @param mixed $UserReference Unique identifier, possibly username or ID.
  * @param string $Username .
  * @param int $UserID Unique identifier.
  */
 public function preferences($UserReference = '', $Username = '', $UserID = '')
 {
     $this->addJsFile('profile.js');
     $Session = Gdn::session();
     $this->permission('Garden.SignIn.Allow');
     // Get user data
     $this->getUserInfo($UserReference, $Username, $UserID, true);
     $UserPrefs = dbdecode($this->User->Preferences);
     if ($this->User->UserID != $Session->UserID) {
         $this->permission(array('Garden.Users.Edit', 'Moderation.Profiles.Edit'), false);
     }
     if (!is_array($UserPrefs)) {
         $UserPrefs = array();
     }
     $MetaPrefs = UserModel::GetMeta($this->User->UserID, 'Preferences.%', 'Preferences.');
     // Define the preferences to be managed
     $Notifications = array();
     if (c('Garden.Profile.ShowActivities', true)) {
         $Notifications = array('Email.WallComment' => t('Notify me when people write on my wall.'), 'Email.ActivityComment' => t('Notify me when people reply to my wall comments.'), 'Popup.WallComment' => t('Notify me when people write on my wall.'), 'Popup.ActivityComment' => t('Notify me when people reply to my wall comments.'));
     }
     $this->Preferences = array('Notifications' => $Notifications);
     // Allow email notification of applicants (if they have permission & are using approval registration)
     if (checkPermission('Garden.Users.Approve') && c('Garden.Registration.Method') == 'Approval') {
         $this->Preferences['Notifications']['Email.Applicant'] = array(t('NotifyApplicant', 'Notify me when anyone applies for membership.'), 'Meta');
     }
     $this->fireEvent('AfterPreferencesDefined');
     // Loop through the preferences looking for duplicates, and merge into a single row
     $this->PreferenceGroups = array();
     $this->PreferenceTypes = array();
     foreach ($this->Preferences as $PreferenceGroup => $Preferences) {
         $this->PreferenceGroups[$PreferenceGroup] = array();
         $this->PreferenceTypes[$PreferenceGroup] = array();
         foreach ($Preferences as $Name => $Description) {
             $Location = 'Prefs';
             if (is_array($Description)) {
                 list($Description, $Location) = $Description;
             }
             $NameParts = explode('.', $Name);
             $PrefType = val('0', $NameParts);
             $SubName = val('1', $NameParts);
             if ($SubName != false) {
                 // Save an array of all the different types for this group
                 if (!in_array($PrefType, $this->PreferenceTypes[$PreferenceGroup])) {
                     $this->PreferenceTypes[$PreferenceGroup][] = $PrefType;
                 }
                 // Store all the different subnames for the group
                 if (!array_key_exists($SubName, $this->PreferenceGroups[$PreferenceGroup])) {
                     $this->PreferenceGroups[$PreferenceGroup][$SubName] = array($Name);
                 } else {
                     $this->PreferenceGroups[$PreferenceGroup][$SubName][] = $Name;
                 }
             } else {
                 $this->PreferenceGroups[$PreferenceGroup][$Name] = array($Name);
             }
         }
     }
     // Loop the preferences, setting defaults from the configuration.
     $CurrentPrefs = array();
     foreach ($this->Preferences as $PrefGroup => $Prefs) {
         foreach ($Prefs as $Pref => $Desc) {
             $Location = 'Prefs';
             if (is_array($Desc)) {
                 list($Desc, $Location) = $Desc;
             }
             if ($Location == 'Meta') {
                 $CurrentPrefs[$Pref] = val($Pref, $MetaPrefs, false);
             } else {
                 $CurrentPrefs[$Pref] = val($Pref, $UserPrefs, c('Preferences.' . $Pref, '0'));
             }
             unset($MetaPrefs[$Pref]);
         }
     }
     $CurrentPrefs = array_merge($CurrentPrefs, $MetaPrefs);
     $CurrentPrefs = array_map('intval', $CurrentPrefs);
     $this->setData('Preferences', $CurrentPrefs);
     if (UserModel::noEmail()) {
         $this->PreferenceGroups = self::_removeEmailPreferences($this->PreferenceGroups);
         $this->PreferenceTypes = self::_removeEmailPreferences($this->PreferenceTypes);
         $this->setData('NoEmail', true);
     }
     $this->setData('PreferenceGroups', $this->PreferenceGroups);
     $this->setData('PreferenceTypes', $this->PreferenceTypes);
     $this->setData('PreferenceList', $this->Preferences);
     if ($this->Form->authenticatedPostBack()) {
         // Get, assign, and save the preferences.
         $NewMetaPrefs = array();
         foreach ($this->Preferences as $PrefGroup => $Prefs) {
             foreach ($Prefs as $Pref => $Desc) {
                 $Location = 'Prefs';
                 if (is_array($Desc)) {
                     list($Desc, $Location) = $Desc;
                 }
                 $Value = $this->Form->getValue($Pref, null);
                 if (is_null($Value)) {
                     continue;
                 }
                 if ($Location == 'Meta') {
                     $NewMetaPrefs[$Pref] = $Value ? $Value : null;
                     if ($Value) {
                         $UserPrefs[$Pref] = $Value;
                         // dup for notifications code.
                     }
                 } else {
                     if (!$CurrentPrefs[$Pref] && !$Value) {
                         unset($UserPrefs[$Pref]);
                         // save some space
                     } else {
                         $UserPrefs[$Pref] = $Value;
                     }
                 }
             }
         }
         $this->UserModel->savePreference($this->User->UserID, $UserPrefs);
         UserModel::setMeta($this->User->UserID, $NewMetaPrefs, 'Preferences.');
         $this->setData('Preferences', array_merge($this->data('Preferences', array()), $UserPrefs, $NewMetaPrefs));
         if (count($this->Form->errors() == 0)) {
             $this->informMessage(sprite('Check', 'InformSprite') . t('Your preferences have been saved.'), 'Dismissable AutoDismiss HasSprite');
         }
     } else {
         $this->Form->setData($CurrentPrefs);
     }
     $this->title(t('Notification Preferences'));
     $this->_setBreadcrumbs($this->data('Title'), $this->canonicalUrl());
     $this->render();
 }
Ejemplo n.º 9
0
 /**
  * Unserialize the fields in the dataset.
  *
  * @param array $Fields
  * @since 2.1
  */
 public function unserialize($Fields = array('Attributes', 'Data'))
 {
     $Result =& $this->result();
     $First = true;
     foreach ($Result as &$Row) {
         if ($First) {
             // Check which fields are in the dataset.
             foreach ($Fields as $Index => $Field) {
                 if (val($Field, $Row, false) === false) {
                     unset($Fields[$Index]);
                 }
             }
             $First = false;
         }
         foreach ($Fields as $Field) {
             if (is_object($Row)) {
                 if (is_string($Row->{$Field})) {
                     $Row->{$Field} = dbdecode($Row->{$Field});
                 }
             } else {
                 if (is_string($Row[$Field])) {
                     $Row[$Field] = dbdecode($Row[$Field]);
                 }
             }
         }
     }
 }
Ejemplo n.º 10
0
 /**
  *
  *
  * @param array $Data
  * @param bool $Preference
  * @param array $Options
  * @return array|bool|string|null
  * @throws Exception
  */
 public function save($Data, $Preference = false, $Options = [])
 {
     trace('ActivityModel->save()');
     $Activity = $Data;
     $this->_touch($Activity);
     if ($Activity['ActivityUserID'] == $Activity['NotifyUserID'] && !val('Force', $Options)) {
         trace('Skipping activity because it would notify the user of something they did.');
         return null;
         // don't notify users of something they did.
     }
     // Check the user's preference.
     if ($Preference) {
         list($Popup, $Email) = self::notificationPreference($Preference, $Activity['NotifyUserID'], 'both');
         if ($Popup && !$Activity['Notified']) {
             $Activity['Notified'] = self::SENT_PENDING;
         }
         if ($Email && !$Activity['Emailed']) {
             $Activity['Emailed'] = self::SENT_PENDING;
         }
         if (!$Activity['Notified'] && !$Activity['Emailed'] && !val('Force', $Options)) {
             trace("Skipping activity because the user has no preference set.");
             return null;
         }
     }
     $ActivityType = self::getActivityType($Activity['ActivityType']);
     $ActivityTypeID = val('ActivityTypeID', $ActivityType);
     if (!$ActivityTypeID) {
         trace("There is no {$ActivityType} activity type.", TRACE_WARNING);
         $ActivityType = self::getActivityType('Default');
         $ActivityTypeID = val('ActivityTypeID', $ActivityType);
     }
     $Activity['ActivityTypeID'] = $ActivityTypeID;
     $NotificationInc = 0;
     if ($Activity['NotifyUserID'] > 0 && $Activity['Notified']) {
         $NotificationInc = 1;
     }
     // Check to see if we are sharing this activity with another one.
     if ($CommentActivityID = val('CommentActivityID', $Activity['Data'])) {
         $CommentActivity = $this->getID($CommentActivityID);
         $Activity['Data']['CommentNotifyUserID'] = $CommentActivity['NotifyUserID'];
     }
     // Make sure this activity isn't a duplicate.
     if (val('CheckRecord', $Options)) {
         // Check to see if this record already notified so we don't notify multiple times.
         $Where = arrayTranslate($Activity, ['NotifyUserID', 'RecordType', 'RecordID']);
         $Where['DateUpdated >'] = Gdn_Format::toDateTime(strtotime('-2 days'));
         // index hint
         $CheckActivity = $this->SQL->getWhere('Activity', $Where)->firstRow();
         if ($CheckActivity) {
             return false;
         }
     }
     // Check to share the activity.
     if (val('Share', $Options)) {
         $this->share($Activity);
     }
     // Group he activity.
     if ($GroupBy = val('GroupBy', $Options)) {
         $GroupBy = (array) $GroupBy;
         $Where = [];
         foreach ($GroupBy as $ColumnName) {
             $Where[$ColumnName] = $Activity[$ColumnName];
         }
         $Where['NotifyUserID'] = $Activity['NotifyUserID'];
         // Make sure to only group activities by day.
         $Where['DateInserted >'] = Gdn_Format::toDateTime(strtotime('-1 day'));
         // See if there is another activity to group these into.
         $GroupActivity = $this->SQL->getWhere('Activity', $Where)->firstRow(DATASET_TYPE_ARRAY);
         if ($GroupActivity) {
             $GroupActivity['Data'] = dbdecode($GroupActivity['Data']);
             $Activity = $this->mergeActivities($GroupActivity, $Activity);
             $NotificationInc = 0;
         }
     }
     $Delete = false;
     if ($Activity['Emailed'] == self::SENT_PENDING) {
         $this->email($Activity);
         $Delete = val('_Delete', $Activity);
     }
     $ActivityData = $Activity['Data'];
     if (isset($Activity['Data']) && is_array($Activity['Data'])) {
         $Activity['Data'] = dbencode($Activity['Data']);
     }
     $this->defineSchema();
     $Activity = $this->filterSchema($Activity);
     $ActivityID = val('ActivityID', $Activity);
     if (!$ActivityID) {
         if (!$Delete) {
             $this->addInsertFields($Activity);
             touchValue('DateUpdated', $Activity, $Activity['DateInserted']);
             $this->EventArguments['Activity'] =& $Activity;
             $this->EventArguments['ActivityID'] = null;
             $Handled = false;
             $this->EventArguments['Handled'] =& $Handled;
             $this->fireEvent('BeforeSave');
             if (count($this->validationResults()) > 0) {
                 return false;
             }
             if ($Handled) {
                 // A plugin handled this activity so don't save it.
                 return $Activity;
             }
             if (val('CheckSpam', $Options)) {
                 // Check for spam
                 $Spam = SpamModel::isSpam('Activity', $Activity);
                 if ($Spam) {
                     return SPAM;
                 }
                 // Check for approval
                 $ApprovalRequired = checkRestriction('Vanilla.Approval.Require');
                 if ($ApprovalRequired && !val('Verified', Gdn::session()->User)) {
                     LogModel::insert('Pending', 'Activity', $Activity);
                     return UNAPPROVED;
                 }
             }
             $ActivityID = $this->SQL->insert('Activity', $Activity);
             $Activity['ActivityID'] = $ActivityID;
             $this->prune();
         }
     } else {
         $Activity['DateUpdated'] = Gdn_Format::toDateTime();
         unset($Activity['ActivityID']);
         $this->EventArguments['Activity'] =& $Activity;
         $this->EventArguments['ActivityID'] = $ActivityID;
         $this->fireEvent('BeforeSave');
         if (count($this->validationResults()) > 0) {
             return false;
         }
         $this->SQL->put('Activity', $Activity, ['ActivityID' => $ActivityID]);
         $Activity['ActivityID'] = $ActivityID;
     }
     $Activity['Data'] = $ActivityData;
     if (isset($CommentActivity)) {
         $CommentActivity['Data']['SharedActivityID'] = $Activity['ActivityID'];
         $CommentActivity['Data']['SharedNotifyUserID'] = $Activity['NotifyUserID'];
         $this->setField($CommentActivity['ActivityID'], 'Data', $CommentActivity['Data']);
     }
     if ($NotificationInc > 0) {
         $CountNotifications = Gdn::userModel()->getID($Activity['NotifyUserID'])->CountNotifications + $NotificationInc;
         Gdn::userModel()->setField($Activity['NotifyUserID'], 'CountNotifications', $CountNotifications);
     }
     // If this is a wall post then we need to notify on that.
     if (val('Name', $ActivityType) == 'WallPost' && $Activity['NotifyUserID'] == self::NOTIFY_PUBLIC) {
         $this->notifyWallPost($Activity);
     }
     return $Activity;
 }
Ejemplo n.º 11
0
 /**
  * Restores a single entry from the log.
  *
  * @param array $Log The log entry.
  * @param bool $DeleteLog Whether or not to delete the log entry after the restore.
  * @throws Exception Throws an exception if restoring the record causes a validation error.
  */
 private function restoreOne($Log, $DeleteLog = true)
 {
     // Throw an event to see if the restore is being overridden.
     $Handled = false;
     $this->EventArguments['Handled'] =& $Handled;
     $this->EventArguments['Log'] =& $Log;
     $this->fireEvent('BeforeRestore');
     if ($Handled) {
         return;
         // a plugin handled the restore.
     }
     if ($Log['RecordType'] == 'Configuration') {
         throw new Gdn_UserException('Restoring configuration edits is currently not supported.');
     }
     if ($Log['RecordType'] == 'Registration') {
         $TableName = 'User';
     } else {
         $TableName = $Log['RecordType'];
     }
     $Data = $Log['Data'];
     if (isset($Data['Attributes'])) {
         $Attr = 'Attributes';
     } elseif (isset($Data['Data'])) {
         $Attr = 'Data';
     } else {
         $Attr = '';
     }
     if ($Attr) {
         if (is_string($Data[$Attr])) {
             $Data[$Attr] = dbdecode($Data[$Attr]);
         }
         // Record a bit of information about the restoration.
         if (!is_array($Data[$Attr])) {
             $Data[$Attr] = [];
         }
         $Data[$Attr]['RestoreUserID'] = Gdn::session()->UserID;
         $Data[$Attr]['DateRestored'] = Gdn_Format::toDateTime();
     }
     if (!isset($Columns[$TableName])) {
         $Columns[$TableName] = Gdn::sql()->fetchColumns($TableName);
     }
     $Set = array_flip($Columns[$TableName]);
     // Set the sets from the data.
     foreach ($Set as $Key => $Value) {
         if (isset($Data[$Key])) {
             $Value = $Data[$Key];
             if (is_array($Value)) {
                 $Value = dbencode($Value);
             }
             $Set[$Key] = $Value;
         } else {
             unset($Set[$Key]);
         }
     }
     switch ($Log['Operation']) {
         case 'Edit':
             // We are restoring an edit so just update the record.
             $IDColumn = $Log['RecordType'] . 'ID';
             $Where = [$IDColumn => $Log['RecordID']];
             unset($Set[$IDColumn]);
             Gdn::sql()->put($TableName, $Set, $Where);
             break;
         case 'Delete':
         case 'Spam':
         case 'Moderate':
         case 'Pending':
         case 'Ban':
             if (!$Log['RecordID']) {
                 // This log entry was never in the table.
                 if (isset($Set['DateInserted'])) {
                     $Set['DateInserted'] = Gdn_Format::toDateTime();
                 }
             }
             // Insert the record back into the db.
             if ($Log['Operation'] == 'Spam' && $Log['RecordType'] == 'Registration') {
                 saveToConfig(['Garden.Registration.NameUnique' => false, 'Garden.Registration.EmailUnique' => false], '', false);
                 if (isset($Data['Username'])) {
                     $Set['Name'] = $Data['Username'];
                 }
                 $ID = Gdn::userModel()->insertForBasic($Set, false, ['ValidateSpam' => false]);
                 if (!$ID) {
                     throw new Exception(Gdn::userModel()->Validation->resultsText());
                 } else {
                     Gdn::userModel()->sendWelcomeEmail($ID, '', 'Register');
                 }
             } else {
                 $ID = Gdn::sql()->options('Replace', true)->insert($TableName, $Set);
                 if (!$ID && isset($Log['RecordID'])) {
                     $ID = $Log['RecordID'];
                 }
                 // Unban a user.
                 if ($Log['RecordType'] == 'User' && $Log['Operation'] == 'Ban') {
                     Gdn::userModel()->setField($ID, 'Banned', 0);
                 }
                 // Keep track of a discussion ID so that its count can be recalculated.
                 if ($Log['Operation'] != 'Edit') {
                     switch ($Log['RecordType']) {
                         case 'Discussion':
                             $this->recalcIDs['Discussion'][$ID] = true;
                             break;
                         case 'Comment':
                             $this->recalcIDs['Discussion'][$Log['ParentRecordID']] = true;
                             break;
                     }
                 }
                 if ($Log['Operation'] == 'Pending') {
                     switch ($Log['RecordType']) {
                         case 'Discussion':
                             if (val('UserDiscussion', $this->recalcIDs) && val($Log['RecordUserID'], $this->recalcIDs['UserDiscussion'])) {
                                 $this->recalcIDs['UserDiscussion'][$Log['RecordUserID']]++;
                             } else {
                                 $this->recalcIDs['UserDiscussion'][$Log['RecordUserID']] = 1;
                             }
                             break;
                         case 'Comment':
                             if (val('UserComment', $this->recalcIDs) && val($Log['RecordUserID'], $this->recalcIDs['UserComment'])) {
                                 $this->recalcIDs['UserComment'][$Log['RecordUserID']]++;
                             } else {
                                 $this->recalcIDs['UserComment'][$Log['RecordUserID']] = 1;
                             }
                             break;
                     }
                 }
             }
             break;
     }
     // Fire 'after' event
     if (isset($ID)) {
         $this->EventArguments['InsertID'] = $ID;
     }
     $this->fireEvent('AfterRestore');
     if ($DeleteLog) {
         Gdn::sql()->delete('Log', ['LogID' => $Log['LogID']]);
     }
 }
Ejemplo n.º 12
0
 /**
  * Used by $this->stash() to create & manage sessions for users & guests.
  *
  * This is a stop-gap solution until full session management for users &
  * guests can be implemented.
  *
  * @param Gdn_SQLDriver $sql          Local clone of the sql driver.
  * @param string        $valueToStash The value of the stash to set.
  *
  * @return bool|Gdn_DataSet Current session.
  */
 private function getStashSession($sql, $valueToStash)
 {
     $cookieName = c('Garden.Cookie.Name', 'Vanilla');
     $name = $cookieName . '-sid';
     // Grab the entire session record.
     $sessionID = val($name, $_COOKIE, '');
     // If there is no session, and no value for saving, return.
     if ($sessionID == '' && $valueToStash == '') {
         return false;
     }
     $session = $sql->select()->from('Session')->where('SessionID', $sessionID)->get()->firstRow();
     if (!$session) {
         $sessionID = betterRandomString(32);
         $transientKey = substr(md5(mt_rand()), 0, 11) . '!';
         // Save the session information to the database.
         $sql->insert('Session', ['SessionID' => $sessionID, 'UserID' => Gdn::session()->UserID, 'TransientKey' => $transientKey, 'DateInserted' => Gdn_Format::toDateTime(), 'DateUpdated' => Gdn_Format::toDateTime()]);
         trace("Inserting session stash {$sessionID}");
         $session = $sql->select()->from('Session')->where('SessionID', $sessionID)->get()->firstRow();
         // Save a session cookie.
         $path = c('Garden.Cookie.Path', '/');
         $domain = c('Garden.Cookie.Domain', '');
         $expire = 0;
         // If the domain being set is completely incompatible with the
         // current domain then make the domain work.
         $currentHost = Gdn::request()->host();
         if (!stringEndsWith($currentHost, trim($domain, '.'))) {
             $domain = '';
         }
         safeCookie($name, $sessionID, $expire, $path, $domain);
         $_COOKIE[$name] = $sessionID;
     }
     $session->Attributes = dbdecode($session->Attributes);
     if (!$session->Attributes) {
         $session->Attributes = [];
     }
     return $session;
 }
Ejemplo n.º 13
0
 /**
  * Convert tags from stored format to user-presentable format.
  *
  * @param string $Tags A string encoded with {@link dbencode()}.
  * @return string Comma-separated tags.
  * @since 2.1
  */
 private function formatTags($Tags)
 {
     // Don't bother if there aren't any tags
     if (!$Tags) {
         return '';
     }
     // Get the array.
     if (preg_match('`^(a:)|{|\\[`', $Tags)) {
         $TagsArray = dbdecode($Tags);
     } else {
         $TagsArray = $Tags;
     }
     // Compensate for deprecated space-separated format
     if (is_string($TagsArray) && $TagsArray == $Tags) {
         $TagsArray = explode(' ', $Tags);
     }
     // Safe format
     $TagsArray = Gdn_Format::text($TagsArray);
     // Send back an comma-separated string
     return is_array($TagsArray) ? implode(',', $TagsArray) : '';
 }
Ejemplo n.º 14
0
 /**
  * Calculate dynamic data on a category.
  *
  * @param array &$category The category to calculate.
  */
 private function calculate(&$category)
 {
     $category['CountAllDiscussions'] = $category['CountDiscussions'];
     $category['CountAllComments'] = $category['CountComments'];
     //        $category['Url'] = self::categoryUrl($category, false, '/');
     $category['ChildIDs'] = [];
     //        if (val('Photo', $category)) {
     //            $category['PhotoUrl'] = Gdn_Upload::url($category['Photo']);
     //        } else {
     //            $category['PhotoUrl'] = '';
     //        }
     if ($category['DisplayAs'] == 'Default') {
         if ($category['Depth'] <= $this->config('Vanilla.Categories.NavDepth', 0)) {
             $category['DisplayAs'] = 'Categories';
         } elseif ($category['Depth'] == $this->config('Vanilla.Categories.NavDepth', 0) + 1 && $this->config('Vanilla.Categories.DoHeadings')) {
             $category['DisplayAs'] = 'Heading';
         } else {
             $category['DisplayAs'] = 'Discussions';
         }
     }
     if (!val('CssClass', $category)) {
         $category['CssClass'] = 'Category-' . $category['UrlCode'];
     }
     if (isset($category['AllowedDiscussionTypes']) && is_string($category['AllowedDiscussionTypes'])) {
         $category['AllowedDiscussionTypes'] = dbdecode($category['AllowedDiscussionTypes']);
     }
 }
Ejemplo n.º 15
0
 /**
  * Calculate dynamic data on a category.
  *
  * This method is passed as a callback by default in {@link setCalculator}, but may not show up as used.
  *
  * @param array &$category The category to calculate.
  */
 private function defaultCalculator(&$category)
 {
     $category['CountAllDiscussions'] = $category['CountDiscussions'];
     $category['CountAllComments'] = $category['CountComments'];
     //        $category['Url'] = self::categoryUrl($category, false, '/');
     $category['ChildIDs'] = [];
     //        if (val('Photo', $category)) {
     //            $category['PhotoUrl'] = Gdn_Upload::url($category['Photo']);
     //        } else {
     //            $category['PhotoUrl'] = '';
     //        }
     CategoryModel::calculateDisplayAs($category);
     if (!val('CssClass', $category)) {
         $category['CssClass'] = 'Category-' . $category['UrlCode'];
     }
     if (isset($category['AllowedDiscussionTypes']) && is_string($category['AllowedDiscussionTypes'])) {
         $category['AllowedDiscussionTypes'] = dbdecode($category['AllowedDiscussionTypes']);
     }
 }
Ejemplo n.º 16
0
 /**
  * Format an encoded string of image properties as HTML.
  *
  * @param string $Body a encoded array of image properties (Image, Thumbnail, Caption)
  * @return string HTML
  */
 public static function image($Body)
 {
     if (is_string($Body)) {
         $Image = dbdecode($Body);
         if (!$Image) {
             return Gdn_Format::html($Body);
         }
     }
     $Url = val('Image', $Image);
     $Caption = Gdn_Format::plainText(val('Caption', $Image));
     return '<div class="ImageWrap">' . '<div class="Image">' . img($Url, array('alt' => $Caption, 'title' => $Caption)) . '</div>' . '<div class="Caption">' . $Caption . '</div>' . '</div>';
 }
Ejemplo n.º 17
0
 public function controller_index($Sender)
 {
     $Sender->Permission(array('Garden.Profiles.Edit'));
     $Args = $Sender->RequestArgs;
     if (sizeof($Args) < 2) {
         $Args = array_merge($Args, array(0, 0));
     } elseif (sizeof($Args) > 2) {
         $Args = array_slice($Args, 0, 2);
     }
     list($UserReference, $Username) = $Args;
     $canEditSignatures = CheckPermission('Plugins.Signatures.Edit');
     // Normalize no image config setting
     if (C('Plugins.Signatures.MaxNumberImages') === 0 || C('Plugins.Signatures.MaxNumberImages') === '0') {
         SaveToConfig('Plugins.Signatures.MaxNumberImages', 'None');
     }
     $Sender->GetUserInfo($UserReference, $Username);
     $UserPrefs = dbdecode($Sender->User->Preferences);
     if (!is_array($UserPrefs)) {
         $UserPrefs = array();
     }
     $Validation = new Gdn_Validation();
     $ConfigurationModel = new Gdn_ConfigurationModel($Validation);
     $ConfigArray = array('Plugin.Signatures.Sig' => NULL, 'Plugin.Signatures.HideAll' => NULL, 'Plugin.Signatures.HideImages' => NULL, 'Plugin.Signatures.HideMobile' => NULL, 'Plugin.Signatures.Format' => NULL);
     $SigUserID = $ViewingUserID = Gdn::Session()->UserID;
     if ($Sender->User->UserID != $ViewingUserID) {
         $Sender->Permission(array('Garden.Users.Edit', 'Moderation.Signatures.Edit'), FALSE);
         $SigUserID = $Sender->User->UserID;
         $canEditSignatures = true;
     }
     $Sender->SetData('CanEdit', $canEditSignatures);
     $Sender->SetData('Plugin-Signatures-ForceEditing', $SigUserID == Gdn::Session()->UserID ? FALSE : $Sender->User->Name);
     $UserMeta = $this->GetUserMeta($SigUserID, '%');
     if ($Sender->Form->AuthenticatedPostBack() === FALSE && is_array($UserMeta)) {
         $ConfigArray = array_merge($ConfigArray, $UserMeta);
     }
     $ConfigurationModel->SetField($ConfigArray);
     // Set the model on the form.
     $Sender->Form->SetModel($ConfigurationModel);
     $Data = $ConfigurationModel->Data;
     $Sender->SetData('Signature', $Data);
     $this->SetSignatureRules($Sender);
     // Form submission handling.
     if ($Sender->Form->AuthenticatedPostBack()) {
         $Values = $Sender->Form->FormValues();
         if ($canEditSignatures) {
             $Values['Plugin.Signatures.Sig'] = GetValue('Body', $Values, NULL);
             $Values['Plugin.Signatures.Format'] = GetValue('Format', $Values, NULL);
         }
         //$this->StripLineBreaks($Values['Plugin.Signatures.Sig']);
         $FrmValues = array_intersect_key($Values, $ConfigArray);
         if (sizeof($FrmValues)) {
             if (!GetValue($this->MakeMetaKey('Sig'), $FrmValues)) {
                 // Delete the signature.
                 $FrmValues[$this->MakeMetaKey('Sig')] = NULL;
                 $FrmValues[$this->MakeMetaKey('Format')] = NULL;
             }
             $this->CrossCheckSignature($Values, $Sender);
             if ($Sender->Form->ErrorCount() == 0) {
                 foreach ($FrmValues as $UserMetaKey => $UserMetaValue) {
                     $Key = $this->TrimMetaKey($UserMetaKey);
                     switch ($Key) {
                         case 'Format':
                             if (strcasecmp($UserMetaValue, 'Raw') == 0) {
                                 $UserMetaValue = NULL;
                             }
                             // don't allow raw signatures.
                             break;
                     }
                     $this->SetUserMeta($SigUserID, $Key, $UserMetaValue);
                 }
                 $Sender->InformMessage(T("Your changes have been saved."));
             }
         }
     } else {
         // Load form data.
         $Data['Body'] = GetValue('Plugin.Signatures.Sig', $Data);
         $Data['Format'] = GetValue('Plugin.Signatures.Format', $Data) ?: Gdn_Format::DefaultFormat();
         // Apply the config settings to the form.
         $Sender->Form->SetData($Data);
     }
     $Sender->Render('signature', '', 'plugins/Signatures');
 }
Ejemplo n.º 18
0
 /**
  * Get data for a single category selected by ID. Disregards permissions.
  *
  * @since 2.0.0
  *
  * @param int $categoryID The unique ID of category we're getting data for.
  * @param string $datasetType Not used.
  * @param array $options Not used.
  * @return object|array SQL results.
  */
 public function getID($categoryID, $datasetType = DATASET_TYPE_OBJECT, $options = [])
 {
     $category = $this->SQL->getWhere('Category', array('CategoryID' => $categoryID))->firstRow($datasetType);
     if (val('AllowedDiscussionTypes', $category) && is_string(val('AllowedDiscussionTypes', $category))) {
         setValue('AllowedDiscussionTypes', $category, dbdecode(val('AllowedDiscussionTypes', $category)));
     }
     return $category;
 }
Ejemplo n.º 19
0
 function writeReactions($Row)
 {
     $Attributes = GetValue('Attributes', $Row);
     if (is_string($Attributes)) {
         $Attributes = dbdecode($Attributes);
         SetValue('Attributes', $Row, $Attributes);
     }
     Gdn::controller()->EventArguments['ReactionTypes'] = array();
     if ($ID = GetValue('CommentID', $Row)) {
         $RecordType = 'comment';
     } elseif ($ID = GetValue('ActivityID', $Row)) {
         $RecordType = 'activity';
     } else {
         $RecordType = 'discussion';
         $ID = GetValue('DiscussionID', $Row);
     }
     Gdn::controller()->EventArguments['RecordType'] = $RecordType;
     Gdn::controller()->EventArguments['RecordID'] = $ID;
     echo '<div class="Reactions">';
     Gdn_Theme::bulletRow();
     // Write the flags.
     static $Flags = null;
     if ($Flags === null) {
         Gdn::controller()->EventArguments['Flags'] =& $Flags;
         Gdn::controller()->fireEvent('Flags');
     }
     // Allow addons to work with flags
     Gdn::controller()->EventArguments['Flags'] =& $Flags;
     Gdn::controller()->fireEvent('BeforeFlag');
     if (!empty($Flags) && is_array($Flags)) {
         echo Gdn_Theme::bulletItem('Flags');
         echo ' <span class="FlagMenu ToggleFlyout">';
         // Write the handle.
         echo anchor(sprite('ReactFlag', 'ReactSprite') . ' ' . wrap(t('Flag'), 'span', array('class' => 'ReactLabel')), '', 'Hijack ReactButton-Flag FlyoutButton', array('title' => t('Flag')), true);
         echo sprite('SpFlyoutHandle', 'Arrow');
         echo '<ul class="Flyout MenuItems Flags" style="display: none;">';
         foreach ($Flags as $Flag) {
             if (is_callable($Flag)) {
                 echo '<li>' . call_user_func($Flag, $Row, $RecordType, $ID) . '</li>';
             } else {
                 echo '<li>' . reactionButton($Row, $Flag['UrlCode']) . '</li>';
             }
         }
         Gdn::controller()->fireEvent('AfterFlagOptions');
         echo '</ul>';
         echo '</span> ';
     }
     Gdn::controller()->fireEvent('AfterFlag');
     Gdn::controller()->fireEvent('AfterReactions');
     echo '</div>';
     Gdn::controller()->fireEvent('Replies');
 }
Ejemplo n.º 20
0
 /**
  * Modifies comment data before it is returned.
  *
  * @since 2.1a32
  * @access public
  *
  * @param object $Data SQL result.
  */
 public function calculate($Comment)
 {
     // Do nothing yet.
     if ($Attributes = val('Attributes', $Comment)) {
         setValue('Attributes', $Comment, dbdecode($Attributes));
     }
     $this->EventArguments['Comment'] = $Comment;
     $this->fireEvent('SetCalculatedFields');
 }
Ejemplo n.º 21
0
 /**
  * Grab second forum's data and merge with current forum.
  *
  * Merge Users on email address. Keeps this forum's username/password.
  * Merge Roles, Tags, and Categories on precise name matches.
  *
  * @todo Compare column names between forums and use intersection
  */
 public function MergeForums($OldDatabase, $OldPrefix, $LegacySlug)
 {
     $NewPrefix = C('Database.DatabasePrefix');
     $this->OldDatabase = $OldDatabase;
     $this->OldPrefix = $OldPrefix;
     $DoLegacy = !empty($LegacySlug);
     // USERS //
     if ($this->OldTableExists('User')) {
         $UserColumns = $this->GetColumns('User', $OldDatabase, $OldPrefix);
         // Merge IDs of duplicate users
         Gdn::SQL()->Query('update ' . $NewPrefix . 'User u set u.OldID =
         (select u2.UserID from `' . $OldDatabase . '`.' . $OldPrefix . 'User u2 where u2.Email = u.Email limit 1)');
         // Copy non-duplicate users
         Gdn::SQL()->Query('insert into ' . $NewPrefix . 'User (' . $UserColumns . ', OldID)
         select ' . $UserColumns . ', UserID
         from `' . $OldDatabase . '`.' . $OldPrefix . 'User
         where Email not in (select Email from ' . $NewPrefix . 'User)');
         // UserMeta
         if ($this->OldTableExists('UserMeta')) {
             Gdn::SQL()->Query('insert ignore into ' . $NewPrefix . 'UserMeta (UserID, Name, Value)
            select u.UserID, um.Name, um.Value
            from ' . $NewPrefix . 'User u, `' . $OldDatabase . '`.' . $OldPrefix . 'UserMeta um
            where u.OldID = um.UserID');
         }
     }
     // ROLES //
     if ($this->OldTableExists('Role')) {
         $RoleColumns = $this->GetColumns('Role', $OldDatabase, $OldPrefix);
         // Merge IDs of duplicate roles
         Gdn::SQL()->Query('update ' . $NewPrefix . 'Role r set r.OldID =
         (select r2.RoleID from `' . $OldDatabase . '`.' . $OldPrefix . 'Role r2 where r2.Name = r.Name)');
         // Copy non-duplicate roles
         Gdn::SQL()->Query('insert into ' . $NewPrefix . 'Role (' . $RoleColumns . ', OldID)
         select ' . $RoleColumns . ', RoleID
         from `' . $OldDatabase . '`.' . $OldPrefix . 'Role
         where Name not in (select Name from ' . $NewPrefix . 'Role)');
         // UserRole
         if ($this->OldTableExists('UserRole')) {
             Gdn::SQL()->Query('insert ignore into ' . $NewPrefix . 'UserRole (RoleID, UserID)
            select r.RoleID, u.UserID
            from ' . $NewPrefix . 'User u, ' . $NewPrefix . 'Role r, `' . $OldDatabase . '`.' . $OldPrefix . 'UserRole ur
            where u.OldID = (ur.UserID) and r.OldID = (ur.RoleID)');
         }
     }
     // CATEGORIES //
     if ($this->OldTableExists('Category')) {
         $CategoryColumnOptions = array('Legacy' => $DoLegacy);
         $CategoryColumns = $this->GetColumns('Category', $OldDatabase, $OldPrefix, $CategoryColumnOptions);
         /*if ($this->MergeCategories) {
                     // Merge IDs of duplicate category names
                     Gdn::SQL()->Query('update '.$NewPrefix.'Category c set c.OldID =
                        (select c2.CategoryID from `'.$OldDatabase.'`.'.$OldPrefix.'Category c2 where c2.Name = c.Name)');
         
                     // Copy non-duplicate categories
                     Gdn::SQL()->Query('insert into '.$NewPrefix.'Category ('.$CategoryColumns.', OldID)
                        select '.$CategoryColumns.', CategoryID
                        from `'.$OldDatabase.'`.'.$OldPrefix.'Category
                        where Name not in (select Name from '.$NewPrefix.'Category)');
                  }
                  else {*/
         // Import categories
         if ($DoLegacy) {
             Gdn::SQL()->Query('insert into ' . $NewPrefix . 'Category (' . $CategoryColumns . ', OldID, ForeignID)
            select ' . $CategoryColumns . ', CategoryID, concat(\'' . $LegacySlug . '-\', CategoryID)
            from `' . $OldDatabase . '`.' . $OldPrefix . 'Category
            where Name <> "Root"');
         } else {
             Gdn::SQL()->Query('insert into ' . $NewPrefix . 'Category (' . $CategoryColumns . ', OldID)
            select ' . $CategoryColumns . ', CategoryID
            from `' . $OldDatabase . '`.' . $OldPrefix . 'Category
            where Name <> "Root"');
         }
         // Remap hierarchy in the ugliest way possible
         $CategoryMap = array();
         $Categories = Gdn::SQL()->Select('CategoryID')->Select('ParentCategoryID')->Select('OldID')->From('Category')->Where(array('OldID >' => 0))->Get()->Result(DATASET_TYPE_ARRAY);
         foreach ($Categories as $Category) {
             $CategoryMap[$Category['OldID']] = $Category['CategoryID'];
         }
         foreach ($Categories as $Category) {
             if ($Category['ParentCategoryID'] > 0 && !empty($CategoryMap[$Category['ParentCategoryID']])) {
                 $ParentID = $CategoryMap[$Category['ParentCategoryID']];
                 Gdn::SQL()->Update('Category')->Set(array('ParentCategoryID' => $ParentID))->Where(array('CategoryID' => $Category['CategoryID']))->Put();
             }
         }
         $CategoryModel = new CategoryModel();
         $CategoryModel->RebuildTree();
         //}
         // UserCategory
     }
     // DISCUSSIONS //
     if ($this->OldTableExists('Discussion')) {
         $DiscussionColumnOptions = array('Legacy' => $DoLegacy);
         $DiscussionColumns = $this->GetColumns('Discussion', $OldDatabase, $OldPrefix, $DiscussionColumnOptions);
         // Copy over all discussions
         if ($DoLegacy) {
             Gdn::SQL()->Query('insert into ' . $NewPrefix . 'Discussion (' . $DiscussionColumns . ', OldID, ForeignID)
            select ' . $DiscussionColumns . ', DiscussionID, concat(\'' . $LegacySlug . '-\', DiscussionID)
            from `' . $OldDatabase . '`.' . $OldPrefix . 'Discussion');
         } else {
             Gdn::SQL()->Query('insert into ' . $NewPrefix . 'Discussion (' . $DiscussionColumns . ', OldID)
            select ' . $DiscussionColumns . ', DiscussionID
            from `' . $OldDatabase . '`.' . $OldPrefix . 'Discussion');
         }
         // Convert imported discussions to use new UserIDs
         Gdn::SQL()->Query('update ' . $NewPrefix . 'Discussion d
        set d.InsertUserID = (SELECT u.UserID from ' . $NewPrefix . 'User u where u.OldID = d.InsertUserID)
        where d.OldID > 0');
         Gdn::SQL()->Query('update ' . $NewPrefix . 'Discussion d
        set d.UpdateUserID = (SELECT u.UserID from ' . $NewPrefix . 'User u where u.OldID = d.UpdateUserID)
        where d.OldID > 0
          and d.UpdateUserID is not null');
         Gdn::SQL()->Query('update ' . $NewPrefix . 'Discussion d
        set d.CategoryID = (SELECT c.CategoryID from ' . $NewPrefix . 'Category c where c.OldID = d.CategoryID)
        where d.OldID > 0');
         // UserDiscussion
         if ($this->OldTableExists('UserDiscussion')) {
             Gdn::SQL()->Query('insert ignore into ' . $NewPrefix . 'UserDiscussion
               (DiscussionID, UserID, Score, CountComments, DateLastViewed, Dismissed, Bookmarked)
            select d.DiscussionID, u.UserID, ud.Score, ud.CountComments, ud.DateLastViewed, ud.Dismissed, ud.Bookmarked
            from ' . $NewPrefix . 'User u, ' . $NewPrefix . 'Discussion d, `' . $OldDatabase . '`.' . $OldPrefix . 'UserDiscussion ud
            where u.OldID = (ud.UserID) and d.OldID = (ud.DiscussionID)');
         }
     }
     // COMMENTS //
     if ($this->OldTableExists('Comment')) {
         $CommentColumnOptions = array('Legacy' => $DoLegacy);
         $CommentColumns = $this->GetColumns('Comment', $OldDatabase, $OldPrefix, $CommentColumnOptions);
         // Copy over all comments
         if ($DoLegacy) {
             Gdn::SQL()->Query('insert into ' . $NewPrefix . 'Comment (' . $CommentColumns . ', OldID, ForeignID)
            select ' . $CommentColumns . ', CommentID, concat(\'' . $LegacySlug . '-\', CommentID)
            from `' . $OldDatabase . '`.' . $OldPrefix . 'Comment');
         } else {
             Gdn::SQL()->Query('insert into ' . $NewPrefix . 'Comment (' . $CommentColumns . ', OldID)
            select ' . $CommentColumns . ', CommentID
            from `' . $OldDatabase . '`.' . $OldPrefix . 'Comment');
         }
         // Convert imported comments to use new UserIDs
         Gdn::SQL()->Query('update ' . $NewPrefix . 'Comment c
        set c.InsertUserID = (SELECT u.UserID from ' . $NewPrefix . 'User u where u.OldID = c.InsertUserID)
        where c.OldID > 0');
         Gdn::SQL()->Query('update ' . $NewPrefix . 'Comment c
        set c.UpdateUserID = (SELECT u.UserID from ' . $NewPrefix . 'User u where u.OldID = c.UpdateUserID)
        where c.OldID > 0
          and c.UpdateUserID is not null');
         // Convert imported comments to use new DiscussionIDs
         Gdn::SQL()->Query('update ' . $NewPrefix . 'Comment c
        set c.DiscussionID = (SELECT d.DiscussionID from ' . $NewPrefix . 'Discussion d where d.OldID = c.DiscussionID)
        where c.OldID > 0');
     }
     // MEDIA //
     if ($this->OldTableExists('Media')) {
         $MediaColumns = $this->GetColumns('Media', $OldDatabase, $OldPrefix);
         // Copy over all media
         Gdn::SQL()->Query('insert into ' . $NewPrefix . 'Media (' . $MediaColumns . ', OldID)
         select ' . $MediaColumns . ', MediaID
         from `' . $OldDatabase . '`.' . $OldPrefix . 'Media');
         // InsertUserID
         Gdn::SQL()->Query('update ' . $NewPrefix . 'Media m
        set m.InsertUserID = (SELECT u.UserID from ' . $NewPrefix . 'User u where u.OldID = m.InsertUserID)
        where m.OldID > 0');
         // ForeignID / ForeignTable
         //Gdn::SQL()->Query('update '.$NewPrefix.'Media m
         //  set m.ForeignID = (SELECT c.CommentID from '.$NewPrefix.'Comment c where c.OldID = m.ForeignID)
         //  where m.OldID > 0 and m.ForeignTable = \'comment\'');
         Gdn::SQL()->Query('update ' . $NewPrefix . 'Media m
        set m.ForeignID = (SELECT d.DiscussionID from ' . $NewPrefix . 'Discussion d where d.OldID = m.ForeignID)
        where m.OldID > 0 and m.ForeignTable = \'discussion\'');
     }
     // CONVERSATION //
     if ($this->OldTableExists('Conversation')) {
         $ConversationColumns = $this->GetColumns('Conversation', $OldDatabase, $OldPrefix);
         // Copy over all Conversations
         Gdn::SQL()->Query('insert into ' . $NewPrefix . 'Conversation (' . $ConversationColumns . ', OldID)
         select ' . $ConversationColumns . ', ConversationID
         from `' . $OldDatabase . '`.' . $OldPrefix . 'Conversation');
         // InsertUserID
         Gdn::SQL()->Query('update ' . $NewPrefix . 'Conversation c
        set c.InsertUserID = (SELECT u.UserID from ' . $NewPrefix . 'User u where u.OldID = c.InsertUserID)
        where c.OldID > 0');
         // UpdateUserID
         Gdn::SQL()->Query('update ' . $NewPrefix . 'Conversation c
        set c.UpdateUserID = (SELECT u.UserID from ' . $NewPrefix . 'User u where u.OldID = c.UpdateUserID)
        where c.OldID > 0');
         // Contributors
         // a. Build userid lookup
         $Users = Gdn::SQL()->Query('select UserID, OldID from ' . $NewPrefix . 'User');
         $UserIDLookup = array();
         foreach ($Users->Result() as $User) {
             $OldID = GetValue('OldID', $User);
             $UserIDLookup[$OldID] = GetValue('UserID', $User);
         }
         // b. Translate contributor userids
         $Conversations = Gdn::SQL()->Query('select ConversationID, Contributors
         from ' . $NewPrefix . 'Conversation
         where Contributors <> ""');
         foreach ($Conversations->Result() as $Conversation) {
             $Contributors = dbdecode(GetValue('Contributors', $Conversation));
             if (!is_array($Contributors)) {
                 continue;
             }
             $UpdatedContributors = array();
             foreach ($Contributors as $UserID) {
                 if (isset($UserIDLookup[$UserID])) {
                     $UpdatedContributors[] = $UserIDLookup[$UserID];
                 }
             }
             // c. Update each conversation
             $ConversationID = GetValue('ConversationID', $Conversation);
             Gdn::SQL()->Query('update ' . $NewPrefix . 'Conversation
            set Contributors = "' . mysql_real_escape_string(dbencode($UpdatedContributors)) . '"
            where ConversationID = ' . $ConversationID);
         }
         // ConversationMessage
         // Copy over all ConversationMessages
         Gdn::SQL()->Query('insert into ' . $NewPrefix . 'ConversationMessage (ConversationID,Body,Format,
            InsertUserID,DateInserted,InsertIPAddress,OldID)
         select ConversationID,Body,Format,InsertUserID,DateInserted,InsertIPAddress,MessageID
         from `' . $OldDatabase . '`.' . $OldPrefix . 'ConversationMessage');
         // ConversationID
         Gdn::SQL()->Query('update ' . $NewPrefix . 'ConversationMessage cm
        set cm.ConversationID =
           (SELECT c.ConversationID from ' . $NewPrefix . 'Conversation c where c.OldID = cm.ConversationID)
        where cm.OldID > 0');
         // InsertUserID
         Gdn::SQL()->Query('update ' . $NewPrefix . 'ConversationMessage c
        set c.InsertUserID = (SELECT u.UserID from ' . $NewPrefix . 'User u where u.OldID = c.InsertUserID)
        where c.OldID > 0');
         // Conversation FirstMessageID
         Gdn::SQL()->Query('update ' . $NewPrefix . 'Conversation c
        set c.FirstMessageID =
           (SELECT cm.MessageID from ' . $NewPrefix . 'ConversationMessage cm where cm.OldID = c.FirstMessageID)
        where c.OldID > 0');
         // Conversation LastMessageID
         Gdn::SQL()->Query('update ' . $NewPrefix . 'Conversation c
        set c.LastMessageID =
           (SELECT cm.MessageID from ' . $NewPrefix . 'ConversationMessage cm where cm.OldID = c.LastMessageID)
        where c.OldID > 0');
         // UserConversation
         Gdn::SQL()->Query('insert ignore into ' . $NewPrefix . 'UserConversation
            (ConversationID, UserID, CountReadMessages, DateLastViewed, DateCleared,
            Bookmarked, Deleted, DateConversationUpdated)
         select c.ConversationID, u.UserID,  uc.CountReadMessages, uc.DateLastViewed, uc.DateCleared,
            uc.Bookmarked, uc.Deleted, uc.DateConversationUpdated
         from ' . $NewPrefix . 'User u, ' . $NewPrefix . 'Conversation c, `' . $OldDatabase . '`.' . $OldPrefix . 'UserConversation uc
         where u.OldID = (uc.UserID) and c.OldID = (uc.ConversationID)');
     }
     // POLLS //
     if ($this->OldTableExists('Poll')) {
         $PollColumns = $this->GetColumns('Poll', $OldDatabase, $OldPrefix);
         $PollOptionColumns = $this->GetColumns('PollOption', $OldDatabase, $OldPrefix);
         // Copy over all polls & options
         Gdn::SQL()->Query('insert into ' . $NewPrefix . 'Poll (' . $PollColumns . ', OldID)
         select ' . $PollColumns . ', PollID
         from `' . $OldDatabase . '`.' . $OldPrefix . 'Poll');
         Gdn::SQL()->Query('insert into ' . $NewPrefix . 'PollOption (' . $PollOptionColumns . ', OldID)
         select ' . $PollOptionColumns . ', PollOptionID
         from `' . $OldDatabase . '`.' . $OldPrefix . 'PollOption');
         // Convert imported options to use new PollIDs
         Gdn::SQL()->Query('update ' . $NewPrefix . 'PollOption o
        set o.PollID = (SELECT p.DiscussionID from ' . $NewPrefix . 'Poll p where p.OldID = o.PollID)
        where o.OldID > 0');
         // Convert imported polls & options to use new UserIDs
         Gdn::SQL()->Query('update ' . $NewPrefix . 'Poll p
        set p.InsertUserID = (SELECT u.UserID from ' . $NewPrefix . 'User u where u.OldID = p.InsertUserID)
        where p.OldID > 0');
         Gdn::SQL()->Query('update ' . $NewPrefix . 'PollOption o
        set o.InsertUserID = (SELECT u.UserID from ' . $NewPrefix . 'User u where u.OldID = o.InsertUserID)
        where o.OldID > 0');
     }
     // TAGS //
     if ($this->OldTableExists('Tag')) {
         $TagColumns = $this->GetColumns('Tag', $OldDatabase, $OldPrefix);
         $TagDiscussionColumns = $this->GetColumns('TagDiscussion', $OldDatabase, $OldPrefix);
         // Record reference of source forum tag ID
         Gdn::SQL()->Query('update ' . $NewPrefix . 'Tag t set t.OldID =
         (select t2.TagID from `' . $OldDatabase . '`.' . $OldPrefix . 'Tag t2 where t2.Name = t.Name limit 1)');
         // Import tags not present in destination forum
         Gdn::SQL()->Query('insert into ' . $NewPrefix . 'Tag (' . $TagColumns . ', OldID)
         select ' . $TagColumns . ', TagID
         from `' . $OldDatabase . '`.' . $OldPrefix . 'Tag
         where Name not in (select Name from ' . $NewPrefix . 'Tag)');
         // TagDiscussion
         if ($this->OldTableExists('TagDiscussion')) {
             // Insert source tag:discussion mapping
             Gdn::SQL()->Query('insert ignore into ' . $NewPrefix . 'TagDiscussion (TagID, DiscussionID, OldCategoryID)
            select t.TagID, d.DiscussionID, td.CategoryID
            from ' . $NewPrefix . 'Tag t, ' . $NewPrefix . 'Discussion d, `' . $OldDatabase . '`.' . $OldPrefix . 'TagDiscussion td
            where t.OldID = (td.TagID) and d.OldID = (td.DiscussionID)');
             /**
              * Incoming tags may or may not have CategoryIDs associated with them, so we'll need to update them with a
              * current CategoryID, if applicable, based on the original category ID (OldCategoryID) from the source
              */
             Gdn::SQL()->Query('update ' . $NewPrefix . 'TagDiscussion td set CategoryID =
            (select c.CategoryID from ' . $NewPrefix . 'Category c where c.OldID = td.OldCategoryID limit 1)
            where OldCategoryID > 0');
         }
     }
     ////
     // Draft - new UserIDs
     // Activity - wallpost, activitycomment
     // Tag - new UserID, merge on name
     // TagDiscussion - new DiscussionID, TagID
     // Update counters
     // LastCommentID
 }