/**
  * Validate a username
  * 
  * @param                     $username
  *
  * @return bool|string
  */
 public static function ValidateUsername($username)
 {
     // Usernames need to be unique across the system, since they will be used as URL identifiers.
     // However, blank usernames are acceptable.
     if ($username == '') {
         return true;
     }
     // Usernames should start with a number at least.
     if (!preg_match('/^[a-zA-Z].*/', $username)) {
         return 'Please start nicknames with a letter.';
     }
     // and should not contain spaces
     if (strpos($username, ' ') !== false) {
         return 'Please do not include spaces in your nickname.';
     }
     // Usernames should be only a-z, 0-9, and a few standard characters.
     if (!preg_match('/^[a-zA-Z0-9\\-\\.@_+]*$/', $username)) {
         return 'Please ensure that your nickname only contains letters, numbers, and dashes.';
     }
     // Search the database for the same username.  Remember, THERE CAN ONLY BE ONE!
     $match = UserUserConfigModel::Find(array('key' => 'username', 'value' => $username), 1);
     //if($match && $match->get('user_id') != $userconfig->get('user_id')){
     if ($match) {
         return 'Requested username is already taken!';
     }
     // yay!
     return true;
 }
	public function testLinkedRecord1(){
		// Just get one UserUserConfigModel
		$model = UserUserConfigModel::Find([], 1);

		if(!$model){
			$this->markTestSkipped('No users found on the system, is Core installed?');
			return;
		}

		// Get the user by the linked key
		$user = $model->getLink('user_id');
		$this->assertInstanceOf('UserModel', $user);
	}
 /**
  * View a user's public profile
  */
 public function view()
 {
     $view = $this->getView();
     $request = $this->getPageRequest();
     $manager = \Core\user()->checkAccess('p:/user/users/manage');
     // Current user an admin?
     // First argument here will either be the username or user id.
     $arg1 = $request->getParameter(0);
     $user = UserModel::Construct($arg1);
     if (!($user && $user->exists())) {
         // Try by username instead.
         $match = UserUserConfigModel::Find(array('key' => 'username', 'value' => $arg1), 1);
         if (!$match) {
             return View::ERROR_NOTFOUND;
         }
         $user = UserModel::Construct($match->get('user_id'));
     }
     if (!$user) {
         return View::ERROR_NOTFOUND;
     }
     // If the UA requested the user by ID but the user has a username set, return a 404 as well.
     // This should help cut down on scanning attempts for userdata.
     if (is_numeric($arg1) && $user->get('username')) {
         return View::ERROR_NOTFOUND;
     }
     // Now see why username needs to not begin with a number? :p
     /** @var $user UserModel */
     // Only allow this if the user is either the same user or has the user manage permission.
     if ($user->get('id') == \Core\user()->get('id') || $manager) {
         $editor = true;
     } else {
         $editor = false;
     }
     $view->controls = ViewControls::DispatchModel($user);
     $view->title = $user->getDisplayName();
     $view->assign('user', $user);
     $view->assign('profiles', $user->get('external_profiles'));
 }
Example #4
0
	/**
	 * This set explicitly handles the value, and has the extended logic required
	 *  for error checking and validation.
	 *
	 * @param string $value The value to set
	 * @return boolean
	 */
	public function setValue($value) {

		$valid = $this->validate($value);
		if($valid !== true){
			$this->_error = $valid;
			return false;
		}

		if(!$value){
			// If it doesn't have a value, then GREAT!
			// The above validation handles if a value is required.
			$this->_attributes['value'] = '';
			return true;
		}

		// This determines what data will be passed in.
		// If the current user can lookup, then it'll be the ID of the user.
		// If the current user can't, then it'll be the full user name of of the user.
		$canlookup = \Core\user()->checkAccess('p:/user/search/autocomplete');

		if(!$canlookup){
			// I need to lookup the username here.
			$uuc = UserUserConfigModel::Find(['key = username', 'value = ' . $value], 1);
			if(!$uuc){
				$this->_error = 'Invalid user specified!';
				return false;
			}

			$value = $uuc->get('user_id');
		}

		$this->_attributes['value'] = $value;
		return true;
	}
Example #5
0
	/**
	 * Import the given data into the destination Model.
	 *
	 * @param array   $data            Indexed array of records to import/merge from the external source.
	 * @param array   $options         Any options required for the import, such as merge, key, etc.
	 * @param boolean $output_realtime Set to true to output the log in real time as the import happens.
	 *
	 * @throws Exception
	 *
	 * @return \Core\ModelImportLogger
	 */
	public static function Import($data, $options, $output_realtime = false) {
		$log = new \Core\ModelImportLogger('User Importer', $output_realtime);

		$merge = isset($options['merge']) ? $options['merge'] : true;
		$pk    = isset($options['key']) ? $options['key'] : null;

		if(!$pk) {
			throw new Exception(
				'Import requires a "key" field on options containing the primary key to compare against locally.'
			);
		}

		// Load in members from the group

		// Set the default group on new accounts, if a default is set.
		$defaultgroups = \UserGroupModel::Find(["default = 1"]);
		$groups        = [];
		$gnames        = [];
		foreach($defaultgroups as $g) {
			/** @var \UserGroupModel $g */
			$groups[] = $g->get('id');
			$gnames[] = $g->get('name');
		}
		if(sizeof($groups)) {
			$log->log('Found ' . sizeof($groups) . ' default groups for new users: ' . implode(', ', $gnames));
		}
		else {
			$log->log('No groups set as default, new users will not belong to any groups.');
		}
		
		$log->log('Starting ' . ($merge ? '*MERGE*' : '*skipping*' ) . ' import of ' . sizeof($data) . ' users');

		foreach($data as $dat) {

			if(isset($dat[$pk])){
				// Only check the information if the primary key is set on this record.
				if($pk == 'email' || $pk == 'id') {
					// These are the only two fields on the User object itself.
					$user = UserModel::Find([$pk . ' = ' . $dat[ $pk ]], 1);
				}
				else {
					$uucm = UserUserConfigModel::Find(['key = ' . $pk, 'value = ' . $dat[ $pk ]], 1);

					if($uucm) {
						$user = $uucm->getLink('UserModel');
					}
					else {

						// Try the lookup from the email address instead.
						// This will force accounts that exist to be synced up correctly.
						// The only caveat to this is that users will not be updated with the foreign key if merge is disabled.
						$user = UserModel::Find(['email = ' . $dat['email']], 1);
					}
				}
			}
			else{
				$user = null;
			}
			

			$status_type = $user ? 'Updated' : 'Created';

			if($user && !$merge) {
				$log->duplicate('Skipped user ' . $user->getLabel() . ', already exists and merge not requested');
				// Skip to the next record.
				continue;
			}

			if(!$user) {
				// All incoming users must have an email address!
				if(!isset($dat['email'])) {
					$log->error('Unable to import user without an email address!');
					// Skip to the next record.
					continue;
				}

				// Meta fields that may or may not be present, but should be for reporting purposes.
				if(!isset($dat['registration_ip'])) {
					$dat['registration_ip'] = REMOTE_IP;
				}
				if(!isset($dat['registration_source'])) {
					$dat['registration_source'] = \Core\user()->exists() ? 'admin' : 'self';
				}
				if(!isset($dat['registration_invitee'])) {
					$dat['registration_invitee'] = \Core\user()->get('id');
				}

				// New user!
				$user = new UserModel();
			}
			// No else needed, else is there IS a valid $user object and it's setup ready to go.

			
			// Handle all the properties for this user!
			foreach($dat as $key => $val){
				
				if($key == 'avatar' && strpos($val, '://') !== false){
					// Sync the user avatar.
					$log->actionStart('Downloading ' . $dat['avatar']);
					$f    = new \Core\Filestore\Backends\FileRemote($dat['avatar']);
					$dest = \Core\Filestore\Factory::File('public/user/avatar/' . $f->getBaseFilename());
					if($dest->identicalTo($f)) {
						$log->actionSkipped();
					}
					else {
						$f->copyTo($dest);
						$user->set('avatar', 'public/user/avatar/' . $dest->getBaseFilename());
						$log->actionSuccess();
					}
				}
				elseif($key == 'profiles' && is_array($val)) {
					$new_profiles = $val;

					// Pull the current profiles from the account
					$profiles = $user->get('external_profiles');
					if($profiles && is_array($profiles)) {
						$current_flat = [];
						foreach($profiles as $current_profile) {
							$current_flat[] = $current_profile['url'];
						}

						// Merge in any *actual* new profile
						foreach($new_profiles as $new_profile) {
							if(!in_array($new_profile['url'], $current_flat)) {
								$profiles[] = $new_profile;
							}
						}

						unset($new_profile, $new_profiles, $current_flat, $current_profile);
					}
					else {
						$profiles = $new_profiles;
						unset($new_profiles);
					}

					$user->set('external_profiles', $profiles);
				}
				elseif($key == 'backend'){
					// Was a backend requested?
					// This gets merged instead of replaced entirely.
					$user->enableAuthDriver($val);
				}
				elseif($key == 'groups'){
					$user->setGroups($val);
				}
				else{
					// Default Behaviour,
					// save the key into whatever field it was set to go to.
					$user->set($key, $val);
				}
			}

			try {
				// Set the default groups loaded from the system.
				if(!$user->exists()){
					$user->setGroups($groups);	
				}

				$status = $user->save();
			}
			catch(Exception $e) {
				$log->error($e->getMessage());
				// Skip to the next.
				continue;
			}
			
			if($status) {
				$log->success($status_type . ' user ' . $user->getLabel() . ' successfully!');
			}
			else {
				$log->skip('Skipped user ' . $user->getLabel() . ', no changes detected.');
			}
		}

		$log->finalize();

		return $log;
	}