/** * Generic save procedure. * * $Settings controls certain save functionality * * SaveRoles - Save 'RoleID' field as user's roles. Default false. * HashPassword - Hash the provided password on update. Default true. * FixUnique - Try to resolve conflicts with unique constraints on Name and Email. Default false. * ValidateEmail - Make sure the provided email addresses is formattted properly. Default true. * NoConfirmEmail - Disable email confirmation. Default false. * */ public function save($FormPostValues, $Settings = false) { // See if the user's related roles should be saved or not. $SaveRoles = val('SaveRoles', $Settings); // Define the primary key in this model's table. $this->defineSchema(); // Custom Rule: This will make sure that at least one role was selected if saving roles for this user. if ($SaveRoles) { $this->Validation->addRule('OneOrMoreArrayItemRequired', 'function:ValidateOneOrMoreArrayItemRequired'); // $this->Validation->AddValidationField('RoleID', $FormPostValues); $this->Validation->applyRule('RoleID', 'OneOrMoreArrayItemRequired'); } else { $this->Validation->unapplyRule('RoleID', 'OneOrMoreArrayItemRequired'); } // Make sure that checkbox vals are saved as the appropriate value if (array_key_exists('ShowEmail', $FormPostValues)) { $FormPostValues['ShowEmail'] = forceBool($FormPostValues['ShowEmail'], '0', '1', '0'); } if (array_key_exists('Banned', $FormPostValues)) { $FormPostValues['Banned'] = forceBool($FormPostValues['Banned'], '0', '1', '0'); } if (array_key_exists('Confirmed', $FormPostValues)) { $FormPostValues['Confirmed'] = forceBool($FormPostValues['Confirmed'], '0', '1', '0'); } if (array_key_exists('Verified', $FormPostValues)) { $FormPostValues['Verified'] = forceBool($FormPostValues['Verified'], '0', '1', '0'); } unset($FormPostValues['Admin']); // Validate the form posted values if (array_key_exists('Gender', $FormPostValues)) { $FormPostValues['Gender'] = self::fixGender($FormPostValues['Gender']); } if (array_key_exists('DateOfBirth', $FormPostValues) && $FormPostValues['DateOfBirth'] == '0-00-00') { $FormPostValues['DateOfBirth'] = null; } $UserID = val('UserID', $FormPostValues); $User = array(); $Insert = $UserID > 0 ? false : true; if ($Insert) { $this->addInsertFields($FormPostValues); } else { $this->addUpdateFields($FormPostValues); $User = $this->getID($UserID, DATASET_TYPE_ARRAY); if (!$User) { $User = array(); } // Block banning the superadmin or System accounts if (val('Admin', $User) == 2 && val('Banned', $FormPostValues)) { $this->Validation->addValidationResult('Banned', 'You may not ban a System user.'); } elseif (val('Admin', $User) && val('Banned', $FormPostValues)) { $this->Validation->addValidationResult('Banned', 'You may not ban a user with the Admin flag set.'); } } $this->EventArguments['FormPostValues'] = $FormPostValues; $this->fireEvent('BeforeSaveValidation'); $RecordRoleChange = true; if ($UserID && val('FixUnique', $Settings)) { $UniqueValid = $this->validateUniqueFields(val('Name', $FormPostValues), val('Email', $FormPostValues), $UserID, true); if (!$UniqueValid['Name']) { unset($FormPostValues['Name']); } if (!$UniqueValid['Email']) { unset($FormPostValues['Email']); } $UniqueValid = true; } else { $UniqueValid = $this->validateUniqueFields(val('Name', $FormPostValues), val('Email', $FormPostValues), $UserID); } // Add & apply any extra validation rules: if (array_key_exists('Email', $FormPostValues) && val('ValidateEmail', $Settings, true)) { $this->Validation->applyRule('Email', 'Email'); } // AllIPAdresses is stored as a CSV, so handle the case where an array is submitted. if (array_key_exists('AllIPAddresses', $FormPostValues) && is_array($FormPostValues['AllIPAddresses'])) { $FormPostValues['AllIPAddresses'] = implode(',', $FormPostValues['AllIPAddresses']); } if ($this->validate($FormPostValues, $Insert) && $UniqueValid) { // All fields on the form that need to be validated (including non-schema field rules defined above) $Fields = $this->Validation->validationFields(); $RoleIDs = val('RoleID', $Fields, 0); $Username = val('Name', $Fields); $Email = val('Email', $Fields); // Only fields that are present in the schema $Fields = $this->Validation->schemaValidationFields(); // Remove the primary key from the fields collection before saving $Fields = removeKeyFromArray($Fields, $this->PrimaryKey); if (!$Insert && array_key_exists('Password', $Fields) && val('HashPassword', $Settings, true)) { // Encrypt the password for saving only if it won't be hashed in _Insert() $PasswordHash = new Gdn_PasswordHash(); $Fields['Password'] = $PasswordHash->hashPassword($Fields['Password']); $Fields['HashMethod'] = 'Vanilla'; } // Check for email confirmation. if (self::requireConfirmEmail() && !val('NoConfirmEmail', $Settings)) { // Email address has changed if (isset($Fields['Email']) && (array_key_exists('Confirmed', $Fields) && $Fields['Confirmed'] == 0 || $UserID == Gdn::session()->UserID && $Fields['Email'] != Gdn::session()->User->Email && !Gdn::session()->checkPermission('Garden.Users.Edit'))) { $Attributes = val('Attributes', Gdn::session()->User); if (is_string($Attributes)) { $Attributes = @unserialize($Attributes); } $ConfirmEmailRoleID = RoleModel::getDefaultRoles(RoleModel::TYPE_UNCONFIRMED); if (!empty($ConfirmEmailRoleID)) { // The confirm email role is set and it exists so go ahead with the email confirmation. $NewKey = randomString(8); $EmailKey = touchValue('EmailKey', $Attributes, $NewKey); $Fields['Attributes'] = serialize($Attributes); $Fields['Confirmed'] = 0; } } } $this->EventArguments['SaveRoles'] =& $SaveRoles; $this->EventArguments['RoleIDs'] =& $RoleIDs; $this->EventArguments['Fields'] =& $Fields; $this->fireEvent('BeforeSave'); $User = array_merge($User, $Fields); // Check the validation results again in case something was added during the BeforeSave event. if (count($this->Validation->results()) == 0) { // If the primary key exists in the validated fields and it is a // numeric value greater than zero, update the related database row. if ($UserID > 0) { // If they are changing the username & email, make sure they aren't // already being used (by someone other than this user) if (val('Name', $Fields, '') != '' || val('Email', $Fields, '') != '') { if (!$this->validateUniqueFields($Username, $Email, $UserID)) { return false; } } if (array_key_exists('Attributes', $Fields) && !is_string($Fields['Attributes'])) { $Fields['Attributes'] = serialize($Fields['Attributes']); } // Perform save DB operation $this->SQL->put($this->Name, $Fields, array($this->PrimaryKey => $UserID)); // Record activity if the person changed his/her photo. $Photo = val('Photo', $FormPostValues); if ($Photo !== false) { if (val('CheckExisting', $Settings)) { $User = $this->getID($UserID); $OldPhoto = val('Photo', $User); } if (isset($OldPhoto) && $OldPhoto != $Photo) { if (IsUrl($Photo)) { $PhotoUrl = $Photo; } else { $PhotoUrl = Gdn_Upload::url(changeBasename($Photo, 'n%s')); } $ActivityModel = new ActivityModel(); if ($UserID == Gdn::session()->UserID) { $HeadlineFormat = t('HeadlineFormat.PictureChange', '{RegardingUserID,You} changed {ActivityUserID,your} profile picture.'); } else { $HeadlineFormat = t('HeadlineFormat.PictureChange.ForUser', '{RegardingUserID,You} changed the profile picture for {ActivityUserID,user}.'); } $ActivityModel->save(array('ActivityUserID' => $UserID, 'RegardingUserID' => Gdn::session()->UserID, 'ActivityType' => 'PictureChange', 'HeadlineFormat' => $HeadlineFormat, 'Story' => img($PhotoUrl, array('alt' => t('Thumbnail'))))); } } } else { $RecordRoleChange = false; if (!$this->validateUniqueFields($Username, $Email)) { return false; } // Define the other required fields: $Fields['Email'] = $Email; $Fields['Roles'] = $RoleIDs; // Make sure that the user is assigned to one or more roles: $SaveRoles = false; // And insert the new user. $UserID = $this->_insert($Fields, $Settings); if ($UserID) { // Report that the user was created. $ActivityModel = new ActivityModel(); $ActivityModel->save(array('ActivityType' => 'Registration', 'ActivityUserID' => $UserID, 'HeadlineFormat' => t('HeadlineFormat.Registration', '{ActivityUserID,You} joined.'), 'Story' => t('Welcome Aboard!')), false, array('GroupBy' => 'ActivityTypeID')); // Report the creation for mods. $ActivityModel->save(array('ActivityType' => 'Registration', 'ActivityUserID' => Gdn::session()->UserID, 'RegardingUserID' => $UserID, 'NotifyUserID' => ActivityModel::NOTIFY_MODS, 'HeadlineFormat' => t('HeadlineFormat.AddUser', '{ActivityUserID,user} added an account for {RegardingUserID,user}.'))); } } // Now update the role settings if necessary. if ($SaveRoles) { // If no RoleIDs were provided, use the system defaults if (!is_array($RoleIDs)) { $RoleIDs = RoleModel::getDefaultRoles(RoleModel::TYPE_MEMBER); } $this->saveRoles($UserID, $RoleIDs, $RecordRoleChange); } // Send the confirmation email. if (isset($EmailKey)) { if (!is_array($User)) { $User = $this->getID($UserID, DATASET_TYPE_ARRAY); } $this->sendEmailConfirmationEmail($User, true); } $this->EventArguments['UserID'] = $UserID; $this->fireEvent('AfterSave'); } else { $UserID = false; } } else { $UserID = false; } // Clear cached user data if (!$Insert && $UserID) { $this->clearCache($UserID, array('user')); } return $UserID; }
/** * {@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 = @unserialize($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) { $Fields = removeKeyFromArray($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; }
/** * Returns the xhtml for a list of checkboxes; sorted into groups related to * the TextField value of the dataset. * * @param string $FieldName The name of the field that is being displayed/posted with this input. It * should related directly to a field name in a user junction table. * ie. LUM_UserRole.RoleID * * @param mixed $DataSet The data to fill the options in the select list. Either an associative * array or a database dataset. ie. RoleID, Name from LUM_Role. * * @param mixed $ValueDataSet The data that should be checked in $DataSet. Either an associative array * or a database dataset. ie. RoleID from LUM_UserRole for a single user. * * @param array $Attributes An associative array of attributes for the select. Here is a list of * "special" attributes and their default values: * * Attribute Options Default * ------------------------------------------------------------------------ * ValueField The name of the field in 'value' * $DataSet that contains the * option values. * TextField The name of the field in 'text' * $DataSet that contains the * option text. * * @return string */ public function checkBoxGrid($FieldName, $DataSet, $ValueDataSet, $Attributes) { // Never display individual inline errors for these CheckBoxes $Attributes['InlineErrors'] = false; $Return = ''; $CheckedValues = $ValueDataSet; if (is_object($ValueDataSet)) { $CheckedValues = array_column($ValueDataSet->resultArray(), $FieldName); } $i = 1; if (is_object($DataSet)) { $ValueField = arrayValueI('ValueField', $Attributes, 'value'); $TextField = arrayValueI('TextField', $Attributes, 'text'); $LastGroup = ''; $Group = array(); $Rows = array(); $Cols = array(); $CheckBox = ''; foreach ($DataSet->result() as $Data) { // Define the checkbox $Instance = $Attributes; $Instance = removeKeyFromArray($Instance, array('TextField', 'ValueField')); $Instance['value'] = $Data->{$ValueField}; $Instance['id'] = $FieldName . $i; if (is_array($CheckedValues) && in_array($Data->{$ValueField}, $CheckedValues)) { $Instance['checked'] = 'checked'; } $CheckBox = $this->checkBox($FieldName . '[]', '', $Instance); // Organize the checkbox into an array for this group $CurrentTextField = $Data->{$TextField}; $aCurrentTextField = explode('.', $CurrentTextField); $aCurrentTextFieldCount = count($aCurrentTextField); $GroupName = array_shift($aCurrentTextField); $ColName = array_pop($aCurrentTextField); if ($aCurrentTextFieldCount >= 3) { $RowName = implode('.', $aCurrentTextField); if ($GroupName != $LastGroup && $LastGroup != '') { // Render the last group $Return .= $this->getCheckBoxGridGroup($LastGroup, $Group, $Rows, $Cols); // Clean out the $Group array & Rowcount $Group = array(); $Rows = array(); $Cols = array(); } if (array_key_exists($ColName, $Group) === false || is_array($Group[$ColName]) === false) { $Group[$ColName] = array(); if (!in_array($ColName, $Cols)) { $Cols[] = $ColName; } } if (!in_array($RowName, $Rows)) { $Rows[] = $RowName; } $Group[$ColName][$RowName] = $CheckBox; $LastGroup = $GroupName; } ++$i; } } return $Return . $this->getCheckBoxGridGroup($LastGroup, $Group, $Rows, $Cols); }
/** * Takes a set of form data ($Form->_PostValues), validates them, and * inserts or updates them to the datatabase. * * @param array $FormPostValues An associative array of $Field => $Value pairs that represent data posted * from the form in the $_POST or $_GET collection. * @param array $Settings If a custom model needs special settings in order to perform a save, they * would be passed in using this variable as an associative array. * @return unknown */ public function save($FormPostValues, $Settings = false) { // Define the primary key in this model's table. $this->defineSchema(); // See if a primary key value was posted and decide how to save $PrimaryKeyVal = val($this->PrimaryKey, $FormPostValues, false); $Insert = $PrimaryKeyVal == false ? true : false; if ($Insert) { $this->addInsertFields($FormPostValues); } else { $this->addUpdateFields($FormPostValues); } // Validate the form posted values if ($this->validate($FormPostValues, $Insert) === true) { $Fields = $this->Validation->validationFields(); $Fields = removeKeyFromArray($Fields, $this->PrimaryKey); // Don't try to insert or update the primary key if ($Insert === false) { $this->update($Fields, array($this->PrimaryKey => $PrimaryKeyVal)); } else { $PrimaryKeyVal = $this->insert($Fields); } } else { $PrimaryKeyVal = false; } return $PrimaryKeyVal; }