public function saveSocialNetworkPrivacySettings() { $settings = array('facebook' => $this->parameters['facebook'], 'google' => $this->parameters['google'], 'reddit' => $this->parameters['reddit'], 'twitter' => $this->parameters['twitter']); $userEditor = new UserEditor(WCF::getUser()); $userEditor->update(array('socialNetworkPrivacySettings' => serialize($settings))); return array('settings' => $settings); }
/** * Deletes this session and it's related data. */ public function delete() { // clear storage if ($this->user->userID) { self::resetSessions(array($this->user->userID)); // update last activity time if (!class_exists('\\wcf\\system\\WCFACP', false)) { $editor = new UserEditor($this->user); $editor->update(array('lastActivityTime' => TIME_NOW)); } } // 1st: Change user to guest, otherwise other the entire session, including // all virtual sessions of the user will be deleted $this->changeUser(new User(null)); // 2nd: Actually remove session $sessionEditor = new $this->sessionEditorClassName($this->session); $sessionEditor->delete(); // disable update $this->disableUpdate(); }
/** * @see \wcf\action\IAction::execute() */ public function execute() { parent::execute(); // user accepted the connection if (isset($_GET['code'])) { try { // fetch access_token $request = new HTTPRequest('https://github.com/login/oauth/access_token', array(), array('client_id' => StringUtil::trim(GITHUB_PUBLIC_KEY), 'client_secret' => StringUtil::trim(GITHUB_PRIVATE_KEY), 'code' => $_GET['code'])); $request->execute(); $reply = $request->getReply(); $content = $reply['body']; } catch (SystemException $e) { // force logging $e->getExceptionID(); throw new IllegalLinkException(); } // validate state, validation of state is executed after fetching the access_token to invalidate 'code' if (!isset($_GET['state']) || $_GET['state'] != WCF::getSession()->getVar('__githubInit')) { throw new IllegalLinkException(); } WCF::getSession()->unregister('__githubInit'); parse_str($content, $data); // check whether the token is okay if (isset($data['error'])) { throw new IllegalLinkException(); } // check whether a user is connected to this github account $user = $this->getUser($data['access_token']); if ($user->userID) { // a user is already connected, but we are logged in, break if (WCF::getUser()->userID) { throw new NamedUserException(WCF::getLanguage()->get('wcf.user.3rdparty.github.connect.error.inuse')); } else { if (UserAuthenticationFactory::getInstance()->getUserAuthentication()->supportsPersistentLogins()) { $password = StringUtil::getRandomID(); $userEditor = new UserEditor($user); $userEditor->update(array('password' => $password)); // reload user to retrieve salt $user = new User($user->userID); UserAuthenticationFactory::getInstance()->getUserAuthentication()->storeAccessData($user, $user->username, $password); } WCF::getSession()->changeUser($user); WCF::getSession()->update(); HeaderUtil::redirect(LinkHandler::getInstance()->getLink()); } } else { try { // fetch userdata $request = new HTTPRequest('https://api.github.com/user?access_token=' . $data['access_token']); $request->execute(); $reply = $request->getReply(); $userData = JSON::decode(StringUtil::trim($reply['body'])); } catch (SystemException $e) { // force logging $e->getExceptionID(); throw new IllegalLinkException(); } WCF::getSession()->register('__3rdPartyProvider', 'github'); // save data for connection if (WCF::getUser()->userID) { WCF::getSession()->register('__githubUsername', $userData['login']); WCF::getSession()->register('__githubToken', $data['access_token']); HeaderUtil::redirect(LinkHandler::getInstance()->getLink('AccountManagement') . '#3rdParty'); } else { WCF::getSession()->register('__githubData', $userData); WCF::getSession()->register('__username', $userData['login']); // check whether user has entered a public email if (isset($userData) && isset($userData['email']) && $userData['email'] !== null) { WCF::getSession()->register('__email', $userData['email']); } else { try { $request = new HTTPRequest('https://api.github.com/user/emails?access_token=' . $data['access_token']); $request->execute(); $reply = $request->getReply(); $emails = JSON::decode(StringUtil::trim($reply['body'])); // handle future response as well a current response (see. http://developer.github.com/v3/users/emails/) if (is_string($emails[0])) { $email = $emails[0]; } else { $email = $emails[0]['email']; foreach ($emails as $tmp) { if ($tmp['primary']) { $email = $tmp['email']; } break; } } WCF::getSession()->register('__email', $email); } catch (SystemException $e) { } } WCF::getSession()->register('__githubToken', $data['access_token']); // we assume that bots won't register on github first // thus no need for a captcha if (REGISTER_USE_CAPTCHA) { WCF::getSession()->register('noRegistrationCaptcha', true); } WCF::getSession()->update(); HeaderUtil::redirect(LinkHandler::getInstance()->getLink('Register')); } } $this->executed(); exit; } // user declined or any other error that may occur if (isset($_GET['error'])) { throw new NamedUserException(WCF::getLanguage()->get('wcf.user.3rdparty.github.login.error.' . $_GET['error'])); } // start auth by redirecting to github $token = StringUtil::getRandomID(); WCF::getSession()->register('__githubInit', $token); HeaderUtil::redirect("https://github.com/login/oauth/authorize?client_id=" . rawurlencode(StringUtil::trim(GITHUB_PUBLIC_KEY)) . "&scope=" . rawurlencode('user:email') . "&state=" . $token); $this->executed(); exit; }
/** * @see \wcf\action\IAction::execute() */ public function execute() { parent::execute(); if ($this->user->enableGravatar) { $fileExtension = $this->user->gravatarFileExtension ?: 'png'; // try to use cached gravatar $cachedFilename = sprintf(Gravatar::GRAVATAR_CACHE_LOCATION, md5(mb_strtolower($this->user->email)), $this->size, $fileExtension); if (file_exists(WCF_DIR . $cachedFilename) && filemtime(WCF_DIR . $cachedFilename) > TIME_NOW - Gravatar::GRAVATAR_CACHE_EXPIRE * 86400) { @header('Content-Type: image/png'); @readfile(WCF_DIR . $cachedFilename); exit; } // try to download new version $gravatarURL = sprintf(Gravatar::GRAVATAR_BASE, md5(mb_strtolower($this->user->email)), $this->size, GRAVATAR_DEFAULT_TYPE); try { $request = new HTTPRequest($gravatarURL); $request->execute(); $reply = $request->getReply(); // get mime type and file extension $fileExtension = 'png'; $mimeType = 'image/png'; if (isset($reply['headers']['Content-Type'])) { switch ($reply['headers']['Content-Type']) { case 'image/jpeg': $mimeType = 'image/jpeg'; $fileExtension = 'jpg'; break; case 'image/gif': $mimeType = 'image/gif'; $fileExtension = 'gif'; break; } } // save file $cachedFilename = sprintf(Gravatar::GRAVATAR_CACHE_LOCATION, md5(mb_strtolower($this->user->email)), $this->size, $fileExtension); file_put_contents(WCF_DIR . $cachedFilename, $reply['body']); FileUtil::makeWritable(WCF_DIR . $cachedFilename); // update file extension if ($fileExtension != $this->user->gravatarFileExtension) { $editor = new UserEditor($this->user); $editor->update(array('gravatarFileExtension' => $fileExtension)); } @header('Content-Type: ' . $mimeType); @readfile(WCF_DIR . $cachedFilename); exit; } catch (SystemException $e) { // disable gravatar $editor = new UserEditor($this->user); $editor->update(array('enableGravatar' => 0)); } } // fallback to default avatar @header('Content-Type: image/svg+xml'); @readfile(WCF_DIR . 'images/avatars/avatar-default.svg'); exit; }
/** * @see \wcf\action\IAction::execute() */ public function execute() { parent::execute(); $callbackURL = LinkHandler::getInstance()->getLink('FacebookAuth'); // Work around Facebook performing an illegal substitution of the Slash // by '%2F' when entering redirect URI (RFC 3986 sect. 2.2, sect. 3.4) $callbackURL = preg_replace_callback('/(?<=\\?).*/', function ($matches) { return rawurlencode($matches[0]); }, $callbackURL); // user accepted the connection if (isset($_GET['code'])) { try { // fetch access_token $request = new HTTPRequest('https://graph.facebook.com/oauth/access_token?client_id=' . StringUtil::trim(FACEBOOK_PUBLIC_KEY) . '&redirect_uri=' . rawurlencode($callbackURL) . '&client_secret=' . StringUtil::trim(FACEBOOK_PRIVATE_KEY) . '&code=' . rawurlencode($_GET['code'])); $request->execute(); $reply = $request->getReply(); $content = $reply['body']; } catch (SystemException $e) { // force logging $e->getExceptionID(); throw new IllegalLinkException(); } // validate state, validation of state is executed after fetching the access_token to invalidate 'code' if (!isset($_GET['state']) || $_GET['state'] != WCF::getSession()->getVar('__facebookInit')) { throw new IllegalLinkException(); } WCF::getSession()->unregister('__facebookInit'); parse_str($content, $data); try { // fetch userdata $request = new HTTPRequest('https://graph.facebook.com/me?access_token=' . rawurlencode($data['access_token']) . '&fields=birthday,bio,email,gender,id,location,name,picture.type(large),website'); $request->execute(); $reply = $request->getReply(); $content = $reply['body']; } catch (SystemException $e) { // force logging $e->getExceptionID(); throw new IllegalLinkException(); } $userData = JSON::decode($content); // check whether a user is connected to this facebook account $user = $this->getUser($userData['id']); if ($user->userID) { // a user is already connected, but we are logged in, break if (WCF::getUser()->userID) { throw new NamedUserException(WCF::getLanguage()->get('wcf.user.3rdparty.facebook.connect.error.inuse')); } else { if (UserAuthenticationFactory::getInstance()->getUserAuthentication()->supportsPersistentLogins()) { $password = StringUtil::getRandomID(); $userEditor = new UserEditor($user); $userEditor->update(array('password' => $password)); // reload user to retrieve salt $user = new User($user->userID); UserAuthenticationFactory::getInstance()->getUserAuthentication()->storeAccessData($user, $user->username, $password); } WCF::getSession()->changeUser($user); WCF::getSession()->update(); HeaderUtil::redirect(LinkHandler::getInstance()->getLink()); } } else { WCF::getSession()->register('__3rdPartyProvider', 'facebook'); // save data for connection if (WCF::getUser()->userID) { WCF::getSession()->register('__facebookUsername', $userData['name']); WCF::getSession()->register('__facebookData', $userData); HeaderUtil::redirect(LinkHandler::getInstance()->getLink('AccountManagement') . '#3rdParty'); } else { WCF::getSession()->register('__username', $userData['name']); if (isset($userData['email'])) { WCF::getSession()->register('__email', $userData['email']); } WCF::getSession()->register('__facebookData', $userData); // we assume that bots won't register on facebook first // thus no need for a captcha if (REGISTER_USE_CAPTCHA) { WCF::getSession()->register('noRegistrationCaptcha', true); } WCF::getSession()->update(); HeaderUtil::redirect(LinkHandler::getInstance()->getLink('Register')); } } $this->executed(); exit; } // user declined or any other error that may occur if (isset($_GET['error'])) { throw new NamedUserException(WCF::getLanguage()->get('wcf.user.3rdparty.facebook.login.error.' . $_GET['error'])); } // start auth by redirecting to facebook $token = StringUtil::getRandomID(); WCF::getSession()->register('__facebookInit', $token); HeaderUtil::redirect("https://www.facebook.com/dialog/oauth?client_id=" . StringUtil::trim(FACEBOOK_PUBLIC_KEY) . "&redirect_uri=" . rawurlencode($callbackURL) . "&state=" . $token . "&scope=email,user_about_me,user_birthday,user_location,user_website"); $this->executed(); exit; }
/** * Returns true if the given password is the correct password for this user. * * @param string $password * @return boolean password correct */ public function checkPassword($password) { $isValid = false; $rebuild = false; // check if password is a valid bcrypt hash if (PasswordUtil::isBlowfish($this->password)) { if (PasswordUtil::isDifferentBlowfish($this->password)) { $rebuild = true; } // password is correct if (PasswordUtil::secureCompare($this->password, PasswordUtil::getDoubleSaltedHash($password, $this->password))) { $isValid = true; } } else { // different encryption type if (PasswordUtil::checkPassword($this->username, $password, $this->password)) { $isValid = true; $rebuild = true; } } // create new password hash, either different encryption or different blowfish cost factor if ($rebuild) { $userEditor = new UserEditor($this); $userEditor->update(array( 'password' => $password )); } return $isValid; }
/** * @see \wcf\action\IAction::execute() */ public function execute() { parent::execute(); // user accepted if (isset($_GET['oauth_token']) && isset($_GET['oauth_verifier'])) { // fetch data created in the first step $initData = WCF::getSession()->getVar('__twitterInit'); WCF::getSession()->unregister('__twitterInit'); if (!$initData) { throw new IllegalLinkException(); } // validate oauth_token if ($_GET['oauth_token'] !== $initData['oauth_token']) { throw new IllegalLinkException(); } try { // fetch access_token $oauthHeader = array('oauth_consumer_key' => StringUtil::trim(TWITTER_PUBLIC_KEY), 'oauth_nonce' => StringUtil::getRandomID(), 'oauth_signature_method' => 'HMAC-SHA1', 'oauth_timestamp' => TIME_NOW, 'oauth_version' => '1.0', 'oauth_token' => $initData['oauth_token']); $postData = array('oauth_verifier' => $_GET['oauth_verifier']); $signature = $this->createSignature('https://api.twitter.com/oauth/access_token', array_merge($oauthHeader, $postData)); $oauthHeader['oauth_signature'] = $signature; $request = new HTTPRequest('https://api.twitter.com/oauth/access_token', array(), $postData); $request->addHeader('Authorization', 'OAuth ' . $this->buildOAuthHeader($oauthHeader)); $request->execute(); $reply = $request->getReply(); $content = $reply['body']; } catch (SystemException $e) { // force logging $e->getExceptionID(); throw new IllegalLinkException(); } parse_str($content, $data); // check whether a user is connected to this twitter account $user = $this->getUser($data['user_id']); if ($user->userID) { // a user is already connected, but we are logged in, break if (WCF::getUser()->userID) { throw new NamedUserException(WCF::getLanguage()->get('wcf.user.3rdparty.twitter.connect.error.inuse')); } else { if (UserAuthenticationFactory::getInstance()->getUserAuthentication()->supportsPersistentLogins()) { $password = StringUtil::getRandomID(); $userEditor = new UserEditor($user); $userEditor->update(array('password' => $password)); // reload user to retrieve salt $user = new User($user->userID); UserAuthenticationFactory::getInstance()->getUserAuthentication()->storeAccessData($user, $user->username, $password); } WCF::getSession()->changeUser($user); WCF::getSession()->update(); HeaderUtil::redirect(LinkHandler::getInstance()->getLink()); } } else { WCF::getSession()->register('__3rdPartyProvider', 'twitter'); // save data for connection if (WCF::getUser()->userID) { WCF::getSession()->register('__twitterUsername', $data['screen_name']); WCF::getSession()->register('__twitterData', $data); HeaderUtil::redirect(LinkHandler::getInstance()->getLink('AccountManagement') . '#3rdParty'); } else { // fetch user data $twitterData = null; try { $request = new HTTPRequest('https://api.twitter.com/1.1/users/show.json?screen_name=' . $data['screen_name']); $request->execute(); $reply = $request->getReply(); $twitterData = json_decode($reply['body'], true); } catch (SystemException $e) { /* ignore errors */ } WCF::getSession()->register('__username', $data['screen_name']); if ($twitterData !== null) { $data = $twitterData; } WCF::getSession()->register('__twitterData', $data); // we assume that bots won't register on twitter first // thus no need for a captcha if (REGISTER_USE_CAPTCHA) { WCF::getSession()->register('noRegistrationCaptcha', true); } WCF::getSession()->update(); HeaderUtil::redirect(LinkHandler::getInstance()->getLink('Register')); } } $this->executed(); exit; } // user declined if (isset($_GET['denied'])) { throw new NamedUserException(WCF::getLanguage()->get('wcf.user.3rdparty.twitter.login.error.denied')); } // start auth by fetching request_token try { $callbackURL = LinkHandler::getInstance()->getLink('TwitterAuth', array('appendSession' => false)); $oauthHeader = array('oauth_callback' => $callbackURL, 'oauth_consumer_key' => StringUtil::trim(TWITTER_PUBLIC_KEY), 'oauth_nonce' => StringUtil::getRandomID(), 'oauth_signature_method' => 'HMAC-SHA1', 'oauth_timestamp' => TIME_NOW, 'oauth_version' => '1.0'); $signature = $this->createSignature('https://api.twitter.com/oauth/request_token', $oauthHeader); $oauthHeader['oauth_signature'] = $signature; // call api $request = new HTTPRequest('https://api.twitter.com/oauth/request_token', array('method' => 'POST')); $request->addHeader('Authorization', 'OAuth ' . $this->buildOAuthHeader($oauthHeader)); $request->execute(); $reply = $request->getReply(); $content = $reply['body']; } catch (SystemException $e) { // force logging $e->getExceptionID(); throw new IllegalLinkException(); } parse_str($content, $data); if ($data['oauth_callback_confirmed'] != 'true') { throw new IllegalLinkException(); } WCF::getSession()->register('__twitterInit', $data); // redirect to twitter HeaderUtil::redirect('https://api.twitter.com/oauth/authenticate?oauth_token=' . rawurlencode($data['oauth_token'])); $this->executed(); exit; }
/** * Sends the mail notification. * * @param \wcf\data\user\notification\UserNotification $notification * @param \wcf\data\user\User $user * @param \wcf\system\user\notification\event\IUserNotificationEvent $event */ public function sendInstantMailNotification(UserNotification $notification, User $user, IUserNotificationEvent $event) { // no notifications for disabled or banned users if ($user->activationCode) { return; } if ($user->banned) { return; } // recipient's language $event->setLanguage($user->getLanguage()); // add mail header $message = $user->getLanguage()->getDynamicVariable('wcf.user.notification.mail.header', array('user' => $user)) . "\n\n"; // get message $message .= $event->getEmailMessage(); // append notification mail footer $token = $user->notificationMailToken; if (!$token) { // generate token if not present $token = mb_substr(StringUtil::getHash(serialize(array($user->userID, StringUtil::getRandomID()))), 0, 20); $editor = new UserEditor($user); $editor->update(array('notificationMailToken' => $token)); } $message .= "\n\n" . $user->getLanguage()->getDynamicVariable('wcf.user.notification.mail.footer', array('user' => $user, 'token' => $token, 'notification' => $notification)); // build mail $mail = new Mail(array($user->username => $user->email), $user->getLanguage()->getDynamicVariable('wcf.user.notification.mail.subject', array('title' => $event->getEmailTitle())), $message); $mail->setLanguage($user->getLanguage()); $mail->send(); }
/** * Handles uploaded attachments. */ public function upload() { // save files $files = $this->parameters['__files']->getFiles(); $userID = !empty($this->parameters['userID']) ? intval($this->parameters['userID']) : WCF::getUser()->userID; $user = $userID != WCF::getUser()->userID ? new User($userID) : WCF::getUser(); $file = $files[0]; try { if (!$file->getValidationErrorType()) { // shrink avatar if necessary $fileLocation = $this->enforceDimensions($file->getLocation()); $imageData = getimagesize($fileLocation); $data = array('avatarName' => $file->getFilename(), 'avatarExtension' => $file->getFileExtension(), 'width' => $imageData[0], 'height' => $imageData[1], 'userID' => $userID, 'fileHash' => sha1_file($fileLocation)); // create avatar $avatar = UserAvatarEditor::create($data); // check avatar directory // and create subdirectory if necessary $dir = dirname($avatar->getLocation()); if (!@file_exists($dir)) { FileUtil::makePath($dir, 0777); } // move uploaded file if (@copy($fileLocation, $avatar->getLocation())) { @unlink($fileLocation); // create thumbnails $action = new UserAvatarAction(array($avatar), 'generateThumbnails'); $action->executeAction(); // delete old avatar if ($user->avatarID) { $action = new UserAvatarAction(array($user->avatarID), 'delete'); $action->executeAction(); } // update user $userEditor = new UserEditor($user); $userEditor->update(array('avatarID' => $avatar->avatarID, 'enableGravatar' => 0)); // reset user storage UserStorageHandler::getInstance()->reset(array($userID), 'avatar'); // return result return array('avatarID' => $avatar->avatarID, 'canCrop' => $avatar->canCrop(), 'url' => $avatar->getURL(96)); } else { // moving failed; delete avatar $editor = new UserAvatarEditor($avatar); $editor->delete(); throw new UserInputException('avatar', 'uploadFailed'); } } } catch (UserInputException $e) { $file->setValidationErrorType($e->getType()); } return array('errorType' => $file->getValidationErrorType()); }
/** * @see \wcf\action\IAction::execute() */ public function execute() { parent::execute(); $callbackURL = LinkHandler::getInstance()->getLink('GoogleAuth', array('appendSession' => false)); // user accepted the connection if (isset($_GET['code'])) { try { // fetch access_token $request = new HTTPRequest('https://accounts.google.com/o/oauth2/token', array(), array('code' => $_GET['code'], 'client_id' => StringUtil::trim(GOOGLE_PUBLIC_KEY), 'client_secret' => StringUtil::trim(GOOGLE_PRIVATE_KEY), 'redirect_uri' => $callbackURL, 'grant_type' => 'authorization_code')); $request->execute(); $reply = $request->getReply(); $content = $reply['body']; } catch (SystemException $e) { // force logging $e->getExceptionID(); throw new IllegalLinkException(); } // validate state, validation of state is executed after fetching the access_token to invalidate 'code' if (!isset($_GET['state']) || $_GET['state'] != WCF::getSession()->getVar('__googleInit')) { throw new IllegalLinkException(); } WCF::getSession()->unregister('__googleInit'); $data = JSON::decode($content); try { // fetch userdata $request = new HTTPRequest('https://www.googleapis.com/plus/v1/people/me'); $request->addHeader('Authorization', 'Bearer ' . $data['access_token']); $request->execute(); $reply = $request->getReply(); $content = $reply['body']; } catch (SystemException $e) { // force logging $e->getExceptionID(); throw new IllegalLinkException(); } $userData = JSON::decode($content); // check whether a user is connected to this google account $user = $this->getUser($userData['id']); if ($user->userID) { // a user is already connected, but we are logged in, break if (WCF::getUser()->userID) { throw new NamedUserException(WCF::getLanguage()->get('wcf.user.3rdparty.google.connect.error.inuse')); } else { if (UserAuthenticationFactory::getInstance()->getUserAuthentication()->supportsPersistentLogins()) { $password = StringUtil::getRandomID(); $userEditor = new UserEditor($user); $userEditor->update(array('password' => $password)); // reload user to retrieve salt $user = new User($user->userID); UserAuthenticationFactory::getInstance()->getUserAuthentication()->storeAccessData($user, $user->username, $password); } WCF::getSession()->changeUser($user); WCF::getSession()->update(); HeaderUtil::redirect(LinkHandler::getInstance()->getLink()); } } else { WCF::getSession()->register('__3rdPartyProvider', 'google'); // save data for connection if (WCF::getUser()->userID) { WCF::getSession()->register('__googleUsername', $userData['displayName']); WCF::getSession()->register('__googleData', $userData); HeaderUtil::redirect(LinkHandler::getInstance()->getLink('AccountManagement') . '#3rdParty'); } else { WCF::getSession()->register('__username', $userData['displayName']); if (isset($userData['emails'][0]['value'])) { WCF::getSession()->register('__email', $userData['emails'][0]['value']); } WCF::getSession()->register('__googleData', $userData); // we assume that bots won't register on google first // thus no need for a captcha if (REGISTER_USE_CAPTCHA) { WCF::getSession()->register('noRegistrationCaptcha', true); } WCF::getSession()->update(); HeaderUtil::redirect(LinkHandler::getInstance()->getLink('Register')); } } $this->executed(); exit; } // user declined or any other error that may occur if (isset($_GET['error'])) { throw new NamedUserException(WCF::getLanguage()->get('wcf.user.3rdparty.google.login.error.' . $_GET['error'])); } // start auth by redirecting to google $token = StringUtil::getRandomID(); WCF::getSession()->register('__googleInit', $token); HeaderUtil::redirect("https://accounts.google.com/o/oauth2/auth?client_id=" . rawurlencode(StringUtil::trim(GOOGLE_PUBLIC_KEY)) . "&redirect_uri=" . rawurlencode($callbackURL) . "&state=" . $token . "&scope=profile+email&response_type=code"); $this->executed(); exit; }
/** * @see \wcf\system\cronjob\ICronjob::execute() */ public function execute(Cronjob $cronjob) { parent::execute($cronjob); // get user ids $userIDs = array(); $sql = "SELECT\tDISTINCT userID\n\t\t\tFROM\twcf" . WCF_N . "_user_notification\n\t\t\tWHERE\tmailNotified = ?\n\t\t\t\tAND time < ?\n\t\t\t\tAND confirmTime = ?"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute(array(0, TIME_NOW - 3600 * 23, 0)); while ($row = $statement->fetchArray()) { $userIDs[] = $row['userID']; } if (empty($userIDs)) { return; } // get users $userList = new UserList(); $userList->setObjectIDs($userIDs); $userList->readObjects(); $users = $userList->getObjects(); // get notifications $conditions = new PreparedStatementConditionBuilder(); $conditions->add("notification.userID IN (?)", array($userIDs)); $conditions->add("notification.mailNotified = ?", array(0)); $conditions->add("notification.confirmTime = ?", array(0)); $sql = "SELECT\t\tnotification.*, notification_event.eventID, object_type.objectType\n\t\t\tFROM\t\twcf" . WCF_N . "_user_notification notification\n\t\t\tLEFT JOIN\twcf" . WCF_N . "_user_notification_event notification_event\n\t\t\tON\t\t(notification_event.eventID = notification.eventID)\n\t\t\tLEFT JOIN\twcf" . WCF_N . "_object_type object_type\n\t\t\tON\t\t(object_type.objectTypeID = notification_event.objectTypeID)\n\t\t\t" . $conditions . "\n\t\t\tORDER BY\tnotification.time"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute($conditions->getParameters()); // mark notifications as done $conditions = new PreparedStatementConditionBuilder(); $conditions->add("userID IN (?)", array($userIDs)); $conditions->add("mailNotified = ?", array(0)); $sql = "UPDATE\twcf" . WCF_N . "_user_notification\n\t\t\tSET\tmailNotified = 1\n\t\t\t" . $conditions; $statement2 = WCF::getDB()->prepareStatement($sql); $statement2->execute($conditions->getParameters()); // collect data $eventsToUser = $objectTypes = $eventIDs = $notificationObjects = array(); $availableObjectTypes = UserNotificationHandler::getInstance()->getAvailableObjectTypes(); while ($row = $statement->fetchArray()) { if (!isset($eventsToUser[$row['userID']])) { $eventsToUser[$row['userID']] = array(); } $eventsToUser[$row['userID']][] = $row['notificationID']; // cache object types if (!isset($objectTypes[$row['objectType']])) { $objectTypes[$row['objectType']] = array('objectType' => $availableObjectTypes[$row['objectType']], 'objectIDs' => array(), 'objects' => array()); } $objectTypes[$row['objectType']]['objectIDs'][] = $row['objectID']; $eventIDs[] = $row['eventID']; $notificationObjects[$row['notificationID']] = new UserNotification(null, $row); } // load authors $conditions = new PreparedStatementConditionBuilder(); $conditions->add("notificationID IN (?)", array(array_keys($notificationObjects))); $sql = "SELECT\t\tnotificationID, authorID\n\t\t\tFROM\t\twcf" . WCF_N . "_user_notification_author\n\t\t\t" . $conditions . "\n\t\t\tORDER BY\ttime ASC"; $statement = WCF::getDB()->prepareStatement($sql); $statement->execute($conditions->getParameters()); $authorIDs = $authorToNotification = array(); while ($row = $statement->fetchArray()) { if ($row['authorID']) { $authorIDs[] = $row['authorID']; } if (!isset($authorToNotification[$row['notificationID']])) { $authorToNotification[$row['notificationID']] = array(); } $authorToNotification[$row['notificationID']][] = $row['authorID']; } // load authors $authors = UserProfile::getUserProfiles($authorIDs); $unknownAuthor = new UserProfile(new User(null, array('userID' => null, 'username' => WCF::getLanguage()->get('wcf.user.guest')))); // load objects associated with each object type foreach ($objectTypes as $objectType => $objectData) { $objectTypes[$objectType]['objects'] = $objectData['objectType']->getObjectsByIDs($objectData['objectIDs']); } // load required events $eventList = new UserNotificationEventList(); $eventList->getConditionBuilder()->add("user_notification_event.eventID IN (?)", array($eventIDs)); $eventList->readObjects(); $eventObjects = $eventList->getObjects(); foreach ($eventsToUser as $userID => $events) { if (!isset($users[$userID])) { continue; } $user = $users[$userID]; // no notifications for disabled or banned users if ($user->activationCode) { continue; } if ($user->banned) { continue; } // add mail header $message = $user->getLanguage()->getDynamicVariable('wcf.user.notification.mail.header', array('user' => $user)); foreach ($events as $notificationID) { $notification = $notificationObjects[$notificationID]; $className = $eventObjects[$notification->eventID]->className; $class = new $className($eventObjects[$notification->eventID]); $class->setObject($notification, $objectTypes[$notification->objectType]['objects'][$notification->objectID], isset($authors[$notification->authorID]) ? $authors[$notification->authorID] : $unknownAuthor, $notification->additionalData); $class->setLanguage($user->getLanguage()); if (isset($authorToNotification[$notification->notificationID])) { $eventAuthors = array(); foreach ($authorToNotification[$notification->notificationID] as $userID) { if (!$userID) { $eventAuthors[0] = $unknownAuthor; } else { if (isset($authors[$userID])) { $eventAuthors[$userID] = $authors[$userID]; } } } if (!empty($eventAuthors)) { $class->setAuthors($eventAuthors); } } $message .= "\n\n"; $message .= $class->getEmailMessage('daily'); } // append notification mail footer $token = $user->notificationMailToken; if (!$token) { // generate token if not present $token = mb_substr(StringUtil::getHash(serialize(array($user->userID, StringUtil::getRandomID()))), 0, 20); $editor = new UserEditor($user); $editor->update(array('notificationMailToken' => $token)); } $message .= "\n\n"; $message .= $user->getLanguage()->getDynamicVariable('wcf.user.notification.mail.daily.footer', array('user' => $user, 'token' => $token)); // build mail $mail = new Mail(array($user->username => $user->email), $user->getLanguage()->getDynamicVariable('wcf.user.notification.mail.daily.subject', array('count' => count($events))), $message); $mail->setLanguage($user->getLanguage()); $mail->send(); } }
/** * update email */ public function updateEmail($password, $email, &$resultMessage) { try { $oExttMbqUserAddForm = new ExttMbqUserAddForm(); try { $oUser = WCF::getSession()->getUser(); if ($oUser->checkPassword($password)) { $userEditor = new UserEditor($oUser); $userEditor->update(array('email' => $email)); } else { return "password is not valid"; } } catch (UserInputException $e) { return $e->getType(); } } catch (Exception $e) { return $e->getMessage(); } return true; }