HEX
Server: Apache
System: Linux WWW 6.1.0-40-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.153-1 (2025-09-20) x86_64
User: web11 (1011)
PHP: 8.2.29
Disabled: NONE
Upload Files
File: /var/www/intranet.kauko.lt/wp-content/plugins/wise-chat/src/services/user/WiseChatUserService.php
<?php

/**
 * WiseChat user services.
 *
 * @author Kainex <contact@kainex.pl>
 */
class WiseChatUserService {
	const USERS_ACTIVITY_TIME_FRAME = 30;
	const USERS_PRESENCE_TIME_FRAME = 86400;

	/**
	 * @var WiseChatClientSide
	 */
	private $clientSide;
	
	/**
	* @var WiseChatActions
	*/
	private $actions;

	/**
	* @var WiseChatMessagesDAO
	*/
	private $messagesDAO;

	/**
	* @var WiseChatUsersDAO
	*/
	private $usersDAO;
	
	/**
	* @var WiseChatChannelUsersDAO
	*/
	private $channelUsersDAO;

	/**
	 * @var WiseChatUserSettingsDAO
	 */
	private $userSettingsDAO;

	/**
	 * @var WiseChatAuthentication
	 */
	private $authentication;

	/**
	 * @var WiseChatAuthorization
	 */
	protected $authorization;

	/**
	 * @var WiseChatUserEvents
	 */
	private $userEvents;

	/**
	 * @var WiseChatService
	 */
	private $service;
	
	/**
	* @var WiseChatOptions
	*/
	private $options;
	
	public function __construct() {
		$this->options = WiseChatOptions::getInstance();
		$this->usersDAO = WiseChatContainer::getLazy('dao/user/WiseChatUsersDAO');
		$this->userSettingsDAO = WiseChatContainer::getLazy('dao/user/WiseChatUserSettingsDAO');
		$this->actions = WiseChatContainer::getLazy('services/user/WiseChatActions');
		$this->channelUsersDAO = WiseChatContainer::getLazy('dao/WiseChatChannelUsersDAO');
		$this->messagesDAO = WiseChatContainer::getLazy('dao/WiseChatMessagesDAO');
		$this->authentication = WiseChatContainer::getLazy('services/user/WiseChatAuthentication');
		$this->userEvents = WiseChatContainer::getLazy('services/user/WiseChatUserEvents');
		$this->service = WiseChatContainer::getLazy('services/WiseChatService');
		$this->authorization = WiseChatContainer::getLazy('services/user/WiseChatAuthorization');
		$this->clientSide = WiseChatContainer::getLazy('services/client-side/WiseChatClientSide');
	}

	/**
	 * Auto-authenticate user if no additional steps need to be taken (no external auth, no username forcing, etc.)
	 *
	 * @throws Exception
	 */
	public function autoAuthenticateOnMaintenance() {
		if ($this->authentication->isAuthenticated()) {
			return;
		}
		$user = null;

		// check if there is a WordPress user logged in:
		$currentWPUser = $this->usersDAO->getCurrentWpUser();
		if ($currentWPUser !== null) {
			$user = $this->authentication->authenticateWithWpUser($currentWPUser);
		}

		// authenticate only if anonymous login is not prohibited:
		if ($user === null && $this->options->getIntegerOption('access_mode', 0) != 1) {
			$user = $this->authentication->authenticateAnonymously();
		}

		if ($user !== null) {
			$this->actions->publishAction(
				'refreshPlainUserName', array('name' => $user->getName()), $user
			);

			/**
			 * Fires once user has started its session in the chat.
			 *
			 * @since 2.3.2
			 *
			 * @param WiseChatUser $user The user object
			 */
			do_action("wc_user_session_started", $user);

			$this->setCurrentUserOnlineStatus();
		}
	}

	/**
	 * Maintenance actions performed on users.
	 *
	 * @throws Exception
	 */
	public function periodicMaintenance() {
		$this->setCurrentUserOnlineStatus();
		$this->setInactiveUsersOfflineStatus();
	}
	
	/**
	 * Detects and marks offline users.
	 * TODO: possibly remove these queries or execute less often
	*/
	public function setInactiveUsersOfflineStatus() {
		$timeFrame = $this->options->getIntegerOption('user_name_lock_window_seconds', self::USERS_PRESENCE_TIME_FRAME);
		if ($timeFrame < 600) {
			$timeFrame = self::USERS_PRESENCE_TIME_FRAME;
		}
		$this->channelUsersDAO->deleteOlderByLastActivityTime($timeFrame);
		$this->channelUsersDAO->updateActiveForOlderByLastActivityTime(false, self::USERS_ACTIVITY_TIME_FRAME);
	}

	/**
	 * Checks if the current user has right to send a message.
	 *
	 * @return bool
	 */
	public function isSendingMessagesAllowed() {
		if ($this->usersDAO->isWpUserLogged()) {
			$targetRoles = (array) $this->options->getOption("read_only_for_roles", array());
			if (count($targetRoles) > 0) {
				$wpUser = $this->usersDAO->getCurrentWpUser();

				return !is_array($wpUser->roles) || count(array_intersect($targetRoles, $wpUser->roles)) == 0;
			} else {
				return true;
			}
		} else {
			return !$this->options->isOptionEnabled('read_only_for_anonymous', false);
		}
	}

	/**
	 * If the user has logged in then replace anonymous username with WordPress user name.
	 * If WordPress user logs out then the anonymous username is restored.
	 *
	 * @throws Exception
	 */
	public function switchUser() {
		$currentWPUser = $this->usersDAO->getCurrentWpUser();

		if (!$this->authentication->isAuthenticated()) {
			if ($currentWPUser !== null) {
				$user = $this->authentication->authenticateWithWpUser($currentWPUser);

				/**
				 * Fires once user has started its session in the chat.
				 *
				 * @since 2.3.2
				 *
				 * @param WiseChatUser $user The user object
				 */
				do_action("wc_user_session_started", $user);
			}
		} else {
			if ($this->authentication->isAuthenticatedExternally()) {
				return;
			}

			$wasAuthenticated = false;
			$user = $this->authentication->getUser();

			// anonymous switched to WP:
			if ($user->getWordPressId() === null && $currentWPUser !== null) {
				// forget the anonymous account:
				$this->authentication->dropAuthentication();

				$user = $this->authentication->authenticateWithWpUser($currentWPUser);
				$wasAuthenticated = true;
			}

			// WP switched to anonymous:
			if ($user->getWordPressId() !== null && $currentWPUser === null) {
				$this->authentication->dropAuthentication();
				$user = $this->authentication->authenticateAnonymously();
				$wasAuthenticated = true;
			}

			if ($wasAuthenticated) {
				/**
				 * Fires once user has started its session in the chat.
				 *
				 * @since 2.3.2
				 *
				 * @param WiseChatUser $user The user object
				 */
				do_action("wc_user_session_started", $user);
			}
		}
	}
	
	/**
	* Sets a new name for current user.
	*
	* @param string $userName A new username to set
	*
	* @return string New username
	* @throws Exception On validation error
	*/
	public function changeUserName($userName) {
		if (
			!$this->options->isOptionEnabled('allow_change_user_name') ||
			$this->usersDAO->getCurrentWpUser() !== null ||
			$this->authentication->isAuthenticatedExternally() ||
			!$this->authentication->isAuthenticated()
		) {
			throw new Exception('Unsupported operation');
		}

		$userName = $this->authentication->validateUserName($userName);
		$user = $this->authentication->getUser();
		$oldName = $user->getName();

		// set new username and refresh it:
		$user->setName($userName);
		$this->usersDAO->save($user);
		$this->refreshUserName($user);

		/**
		 * Fires once user has changed its name. It applies to anonymous users only.
		 *
		 * @since 2.3.2
		 *
		 * @param string $oldName The old name
		 * @param string $userName The new name
		 * @param WiseChatUser $user The user object
		 */
		do_action("wc_username_changed", $oldName, $userName, $user);

		return $userName;
	}
	
	/**
	* Sets text color for messages typed by the current user.
	*
	* @param string $color
	*
	* @throws Exception If an error occurred
	*/
	public function setUserTextColor($color) {
		if (!$this->authentication->isAuthenticated()) {
			throw new Exception('Unsupported operation');
		}
		if ($color != '' && !preg_match("/^#[a-fA-F0-9]{6}$/", $color)) {
			throw new Exception('Invalid color signature');
		}

		$user = $this->authentication->getUser();
		$user->setDataProperty('textColor', $color);
		$this->usersDAO->save($user);
		$this->userEvents->resetEventTracker('usersList');
		$this->actions->publishAction(
			'setMessagesProperty', array(
				'chatUserId' => $user->getId(),
				'propertyName' => 'textColor',
				'propertyValue' => $color
			)
		);

		/**
		 * Fires once user has set its color.
		 *
		 * @since 2.3.2
		 *
		 * @param string $color The color code
		 * @param WiseChatUser $user The user object
		 */
		do_action("wc_usercolor_set", $color, $user);
	}

	/**
	 * Gets user property.
	 *
	 * @param string $property
	 * @return mixed|null
	 *
	 * @throws Exception If an error occurred
	 */
	public function getProperty($property) {
		if (!$this->authentication->isAuthenticated()) {
			throw new Exception('Could not get a property on unauthenticated user');
		}

		$value = $this->authentication->getUser()->getDataProperty($property);

		/**
		 * Filters user property
		 *
		 * @since 2.4
		 *
		 * @param string $value Property value
		 * @param string $property Property name
		 */
		return apply_filters('wc_userproperty_get', $value, $property);
	}

	/**
	 * Sets user property.
	 *
	 * @param string $property
	 * @param mixed $value
	 *
	 * @throws Exception If an error occurred
	 */
	public function setProperty($property, $value) {
		if (!$this->authentication->isAuthenticated()) {
			throw new Exception('Could not set a property on unauthenticated user');
		}

		$user = $this->authentication->getUser();
		$user->setDataProperty($property, $value);
		$this->usersDAO->save($user);

		/**
		 * Fires once user property has been set.
		 *
		 * @since 2.3.2
		 *
		 * @param string $property Property name
		 * @param mixed $value Property value
		 * @param WiseChatUser $user The user object
		 */
		do_action("wc_userproperty_set", $property, $value, $user);
	}

	/**
	 * Unsets all properties that match the prefix.
	 *
	 * @param string $prefix
	 *
	 * @throws Exception If an error occurred
	 */
	public function unsetPropertiesByPrefix($prefix) {
		if (!$this->authentication->isAuthenticated()) {
			throw new Exception('Could not unset a property on unauthenticated user');
		}

		$user = $this->authentication->getUser();
		$allProperties = $user->getData();
		if (is_array($allProperties)) {
			foreach ($allProperties as $key => $value) {
				if (strpos($key, $prefix) === 0) {
					unset($allProperties[$key]);
				}
			}
			$user->setData($allProperties);
			$this->usersDAO->save($user);
		}
	}

	/**
	 * Checks if the first given user can communicate with the second user.
	 *
	 * @param WiseChatUser $user
	 * @param WiseChatUser $associatedUser
	 * @return bool
	 */
	public function isUsersConnectionAvailable($user, $associatedUser) {
		if (!$this->options->isOptionEnabled('enable_buddypress', false)) {
			return true;
		}
		if (!$this->options->isOptionEnabled('users_list_bp_users_only', false)) {
			return true;
		}

		if ($user === null || $associatedUser === null) {
			return false;
		}

		if (!($user->getWordPressId() > 0) || !($associatedUser->getWordPressId() > 0)) {
			return false;
		}

		if ($user->getWordPressId() == $associatedUser->getWordPressId()) {
			return true;
		}

		if (function_exists('friends_check_friendship')) {
			return friends_check_friendship($user->getWordPressId(), $associatedUser->getWordPressId());
		}

		return false;
	}

	/**
	 * Calculates hash for given user ID. Hash are unique across sites (multisite safe).
	 *
	 * @param string $userId
	 * @return string
	 */
	public static function getUserHash($userId) {
		return sha1(wp_salt().get_current_blog_id().$userId);
	}

	/**
	 * Handles WordPress user profile changes.
	 *
	 * @param integer $wpUserId
	 * @param WP_User $oldWpUser
	 */
	public function onWpUserProfileUpdate($wpUserId, $oldWpUser) {
		$wpUser = $this->usersDAO->getWpUserByID($wpUserId);

		if ($wpUser !== null && $oldWpUser !== false) {
			$userName = $this->usersDAO->getChatUserNameFromWpUser($wpUser);
			$this->usersDAO->updateNameByWordPressId($userName, $wpUser->ID);
			$this->messagesDAO->updateUserNameByWordPressUserId($userName, $wpUser->ID);
		}
	}

	/**
	 * Sets the status of the current user to "online".
	 *
	 * @throws Exception
	 */
	private function setCurrentUserOnlineStatus() {
		$user = $this->authentication->getUser();
		if ($user !== null) {
			$channelUser = $this->channelUsersDAO->getByUserId($user->getId());

			if ($channelUser === null) {
				$channelUser = new WiseChatChannelUser();
				$channelUser->setActive(true);
				$channelUser->setLastActivityTime(time());
				$channelUser->setUserId($user->getId());
				$this->channelUsersDAO->save($channelUser);
			} else {
				$channelUser->setActive(true);
				$channelUser->setLastActivityTime(time());
				$this->channelUsersDAO->save($channelUser);
			}
		}
	}

	/**
	 * Refreshes username after setting a new one.
	 *
	 * @param WiseChatUser $user
	 * @throws Exception
	 */
	private function refreshUserName($user) {
		$this->userEvents->resetEventTracker('browser');
        WiseChatContainer::load('dao/criteria/WiseChatMessagesCriteria');

		$updateCriteria = WiseChatMessagesCriteria::build()->setUserId($user->getId());
		if ($this->options->isOptionEnabled('enable_private_messages')) {
			$updateCriteria->setRecipientOrSenderId($user->getId());
		}
        $this->messagesDAO->updateUserNameByCriteria($user->getName(), $updateCriteria);
		$this->actions->publishAction(
			'refreshUserName', array(
				'name' => $user->getName(),
				'id' => $this->clientSide->encryptUserId($user->getId())
			)
		);
		$this->actions->publishAction(
			'refreshChannelName', array(
				'name' => $user->getName(),
				'id' => $this->clientSide->encryptDirectChannelId($user->getId())
			)
		);
	}

	/**
	 * Returns text color if the color is defined for user's role.
	 *
	 * @param WiseChatUser $user
	 * @return string|null
	 */
	public function getTextColorDefinedByUserRole($user) {
		$textColor = null;
		$userRoleToColorMap = $this->options->getOption('text_color_user_roles', array());

		if ($user !== null && $user->getWordPressId() > 0) {
			$wpUser = $this->usersDAO->getWpUserByID($user->getWordPressId());
			if (is_array($wpUser->roles)) {
				$commonRoles = array_intersect($wpUser->roles, array_keys($userRoleToColorMap));
				if (count($commonRoles) > 0 && array_key_exists(0, $commonRoles) && array_key_exists($commonRoles[0], $userRoleToColorMap)) {
					$userRoleColor = trim($userRoleToColorMap[$commonRoles[0]]);
					if ($userRoleColor) {
						$textColor = $userRoleColor;
					}
				}
			}
		}

		return $textColor;
	}

	/**
	 * @param WiseChatUser $user
	 * @param integer $priorityWordPressId
	 *
	 * @return string|null
	 */
	public function getUserAvatar($user, $priorityWordPressId = null) {
		$imageSrc = null;
		if ($priorityWordPressId > 0 || ($user !== null && $user->getWordPressId() !== null)) {
			$imageTag = $priorityWordPressId > 0 ? get_avatar($priorityWordPressId) : get_avatar($user->getWordPressId());
			if (!$imageTag) {
				return null;
			}
			$doc = new DOMDocument();
			@$doc->loadHTML($imageTag);
			$imageTags = $doc->getElementsByTagName('img');
			foreach($imageTags as $tag) {
				$imageSrc = $tag->getAttribute('src');
			}
		} else {
			$imageSrc = $this->options->getIconsURL().'user.png';
		}

		return $imageSrc;
	}

	/**
	 * Returns CSS classes declared to user roles.
	 *
	 * @param WiseChatUser $user
	 *
	 * @return string
	 */
	public function getCssClassesForUserRoles($user, $wpUser = null) {
		$classes = array();

		if ($user === null) {
			if ($wpUser !== null && is_array($wpUser->roles)) {
				foreach ($wpUser->roles as $role) {
					$classes[] = 'wcUserRole-' . $role;
				}
			} else {
				$classes[] = 'wcUserRoleAnonymous';
			}
		} else {
			if ($user->getWordPressId() > 0) {
				if ($wpUser === null) {
					$wpUser = $this->usersDAO->getWpUserByID($user->getWordPressId());
				}
				if (is_array($wpUser->roles)) {
					foreach ($wpUser->roles as $role) {
						$classes[] = 'wcUserRole-' . $role;
					}
				}
			} else {
				$classes[] = 'wcUserRoleAnonymous';
			}
		}

		return implode(' ', $classes);
	}

	public function getUserTextColor($user) {
		// get text color defined by role:
		$textColor = $this->getTextColorDefinedByUserRole($user);

		// get custom color (higher priority):
		if ($this->options->isOptionEnabled('allow_change_text_color') && $user !== null && $user->getDataProperty('textColor')) {
			$textColor = $user->getDataProperty('textColor');
		}

		return $textColor;
	}

	/**
	 * @param WiseChatUser $user
	 * @param string $userName
	 * @param integer $wordPressUserId
	 *
	 * @return string
	 */
	public function getUserProfileLink($user, $userName = null, $wordPressUserId = null) {
		$linkUserNameTemplate = $this->options->getOption('link_user_name_template', null);
		if ($wordPressUserId == null && $user != null) {
			$wordPressUserId = $user->getWordPressId();
		}
		if ($userName == null && $user != null) {
			$userName = $user->getName();
		}
		$wpUser = $wordPressUserId != null ? $this->usersDAO->getWpUserByID($wordPressUserId) : null;

		$variableId = '';
		$variableUserName = $variableDisplayName = $userName;
		if ($wpUser !== null) {
			$variableId = $wpUser->ID;
			$variableUserName = $wpUser->user_login;
			$variableDisplayName = $this->usersDAO->getChatUserNameFromWpUser($wpUser);
		}

		$profileLink = null;
		if ($linkUserNameTemplate != null && $wpUser) {
			$variables = array(
				'id' => $variableId,
				'username' => $variableUserName,
				'displayname' => $variableDisplayName
			);

			$profileLink = $this->getTemplatedString($variables, $linkUserNameTemplate);
		} else if ($wpUser !== null) {
			$profileLink = get_author_posts_url($wpUser->ID, $this->usersDAO->getChatUserNameFromWpUser($wpUser));
		}

		return $profileLink;
	}

	private function getTemplatedString($variables, $template, $encodeValues = true) {
		foreach ($variables as $key => $value) {
			$template = str_replace("{".$key."}", $encodeValues ? urlencode($value) : $value, $template);
		}

		return $template;
	}

	/**
	 * @param WiseChatMessage $message
	 *
	 * @return string|null
	 */
	public function getUserAvatarFromMessage($message) {
		if ($message->getAvatarUrl()) {
			return $message->getAvatarUrl();
		} else {
			return $this->getUserAvatar($message->getUser(), $message->getWordPressUserId());
		}
	}

	/**
	 * Checks if the current user can get the message content.
	 *
	 * @param WiseChatMessage $message
	 *
	 * @return boolean
	 */
	public function isUserAllowedToSeeTheContentOfMessage($message) {
		if ($this->options->isOptionEnabled('new_messages_hidden', false) === false) {
			return true;
		}

		if (!$message->isHidden()) {
			return true;
		}

		$wpUser = $this->usersDAO->getCurrentWpUser();
		if ($wpUser !== null) {
			$targetRoles = (array) $this->options->getOption("show_hidden_messages_roles", 'administrator');
			if ((is_array($wpUser->roles) && count(array_intersect($targetRoles, $wpUser->roles)) > 0)) {
				return true;
			}
		} else {
			return false;
		}
	}

	/**
	 * Determines if the user is in fact an anonymous user.
	 *
	 * @param WiseChatUser $user
	 * @return bool
	 */
	public function isAnonymousUser($user) {
		return !($user->getWordPressId() > 0);
	}

}