X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FModel%2FUser.php;h=78ae95804122d062a1263163936ca6a362314c1d;hb=701dbdf7fc4979f05fde1c655b17ca3aff0a59e0;hp=0e8d11f7339e461d8f52c3222be36a220325eb3e;hpb=04d620fc2f567d32b50f5d5b0974acafeb072177;p=friendica.git diff --git a/src/Model/User.php b/src/Model/User.php index 0e8d11f733..78ae958041 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -1,15 +1,31 @@ . + * */ namespace Friendica\Model; use DivineOmega\PasswordExposed; use Exception; +use Friendica\Content\Pager; use Friendica\Core\Hook; +use Friendica\Core\L10n; use Friendica\Core\Logger; use Friendica\Core\Protocol; use Friendica\Core\System; @@ -17,6 +33,7 @@ use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\DI; use Friendica\Model\TwoFactor\AppSpecificPassword; +use Friendica\Network\HTTPException\InternalServerErrorException; use Friendica\Object\Image; use Friendica\Util\Crypto; use Friendica\Util\DateTimeFormat; @@ -178,66 +195,50 @@ class User */ public static function getOwnerDataById($uid, $check_valid = true) { - $r = DBA::fetchFirst( - "SELECT - `contact`.*, - `user`.`prvkey` AS `uprvkey`, - `user`.`timezone`, - `user`.`nickname`, - `user`.`sprvkey`, - `user`.`spubkey`, - `user`.`page-flags`, - `user`.`account-type`, - `user`.`prvnets`, - `user`.`account_removed`, - `user`.`hidewall` - FROM `contact` - INNER JOIN `user` - ON `user`.`uid` = `contact`.`uid` - WHERE `contact`.`uid` = ? - AND `contact`.`self` - LIMIT 1", - $uid - ); - if (!DBA::isResult($r)) { - return false; + $owner = DBA::selectFirst('owner-view', [], ['uid' => $uid]); + if (!DBA::isResult($owner)) { + if (!DBA::exists('user', ['uid' => $uid]) || !$check_valid) { + return false; + } + Contact::createSelfFromUserId($uid); + $owner = self::getOwnerDataById($uid, false); } - if (empty($r['nickname'])) { + if (empty($owner['nickname'])) { return false; } if (!$check_valid) { - return $r; + return $owner; } // Check if the returned data is valid, otherwise fix it. See issue #6122 // Check for correct url and normalised nurl - $url = DI::baseUrl() . '/profile/' . $r['nickname']; - $repair = ($r['url'] != $url) || ($r['nurl'] != Strings::normaliseLink($r['url'])); + $url = DI::baseUrl() . '/profile/' . $owner['nickname']; + $repair = ($owner['url'] != $url) || ($owner['nurl'] != Strings::normaliseLink($owner['url'])); if (!$repair) { // Check if "addr" is present and correct - $addr = $r['nickname'] . '@' . substr(DI::baseUrl(), strpos(DI::baseUrl(), '://') + 3); - $repair = ($addr != $r['addr']); + $addr = $owner['nickname'] . '@' . substr(DI::baseUrl(), strpos(DI::baseUrl(), '://') + 3); + $repair = ($addr != $owner['addr']); } if (!$repair) { // Check if the avatar field is filled and the photo directs to the correct path $avatar = Photo::selectFirst(['resource-id'], ['uid' => $uid, 'profile' => true]); if (DBA::isResult($avatar)) { - $repair = empty($r['avatar']) || !strpos($r['photo'], $avatar['resource-id']); + $repair = empty($owner['avatar']) || !strpos($owner['photo'], $avatar['resource-id']); } } if ($repair) { Contact::updateSelfFromUserID($uid); // Return the corrected data and avoid a loop - $r = self::getOwnerDataById($uid, false); + $owner = self::getOwnerDataById($uid, false); } - return $r; + return $owner; } /** @@ -265,7 +266,7 @@ class User * @param string $network network name * * @return int group id - * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws InternalServerErrorException */ public static function getDefaultGroup($uid, $network = '') { @@ -542,7 +543,7 @@ class User * * @param string $nickname The nickname that should be checked * @return boolean True is the nickname is blocked on the node - * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws InternalServerErrorException */ public static function isNicknameBlocked($nickname) { @@ -579,7 +580,7 @@ class User * @param array $data * @return array * @throws \ErrorException - * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws InternalServerErrorException * @throws \ImagickException * @throws Exception */ @@ -602,8 +603,7 @@ class User $verified = !empty($data['verified']); $language = !empty($data['language']) ? Strings::escapeTags(trim($data['language'])) : 'en'; - $publish = !empty($data['profile_publish_reg']); - $netpublish = $publish && DI::config()->get('system', 'directory'); + $netpublish = $publish = !empty($data['profile_publish_reg']); if ($password1 != $confirm) { throw new Exception(DI::l10n()->t('Passwords do not match. Password unchanged.')); @@ -782,9 +782,7 @@ class User 'photo' => DI::baseUrl() . "/photo/profile/{$uid}.jpg", 'thumb' => DI::baseUrl() . "/photo/avatar/{$uid}.jpg", 'publish' => $publish, - 'is-default' => 1, 'net-publish' => $netpublish, - 'profile-name' => DI::l10n()->t('default') ]); if (!$insert_result) { DBA::delete('user', ['uid' => $uid]); @@ -825,9 +823,16 @@ class User $photo_failure = false; $filename = basename($photo); - $img_str = Network::fetchUrl($photo, true); - // guess mimetype from headers or filename - $type = Images::guessType($photo, true); + $curlResult = DI::httpRequest()->get($photo, true); + if ($curlResult->isSuccess()) { + $img_str = $curlResult->getBody(); + $type = $curlResult->getContentType(); + } else { + $img_str = ''; + $type = ''; + } + + $type = Images::getMimeTypeByData($img_str, $photo, $type); $Image = new Image($img_str, $type); if ($Image->isValid()) { @@ -869,6 +874,166 @@ class User return $return; } + /** + * Sets block state for a given user + * + * @param int $uid The user id + * @param bool $block Block state (default is true) + * + * @return bool True, if successfully blocked + + * @throws Exception + */ + public static function block(int $uid, bool $block = true) + { + return DBA::update('user', ['blocked' => $block], ['uid' => $uid]); + } + + /** + * Allows a registration based on a hash + * + * @param string $hash + * + * @return bool True, if the allow was successful + * + * @throws InternalServerErrorException + * @throws Exception + */ + public static function allow(string $hash) + { + $register = Register::getByHash($hash); + if (!DBA::isResult($register)) { + return false; + } + + $user = User::getById($register['uid']); + if (!DBA::isResult($user)) { + return false; + } + + Register::deleteByHash($hash); + + DBA::update('user', ['blocked' => false, 'verified' => true], ['uid' => $register['uid']]); + + $profile = DBA::selectFirst('profile', ['net-publish'], ['uid' => $register['uid']]); + + if (DBA::isResult($profile) && $profile['net-publish'] && DI::config()->get('system', 'directory')) { + $url = DI::baseUrl() . '/profile/' . $user['nickname']; + Worker::add(PRIORITY_LOW, "Directory", $url); + } + + $l10n = DI::l10n()->withLang($register['language']); + + return User::sendRegisterOpenEmail( + $l10n, + $user, + DI::config()->get('config', 'sitename'), + DI::baseUrl()->get(), + ($register['password'] ?? '') ?: 'Sent in a previous email' + ); + } + + /** + * Denys a pending registration + * + * @param string $hash The hash of the pending user + * + * This does not have to go through user_remove() and save the nickname + * permanently against re-registration, as the person was not yet + * allowed to have friends on this system + * + * @return bool True, if the deny was successfull + * @throws Exception + */ + public static function deny(string $hash) + { + $register = Register::getByHash($hash); + if (!DBA::isResult($register)) { + return false; + } + + $user = User::getById($register['uid']); + if (!DBA::isResult($user)) { + return false; + } + + return DBA::delete('user', ['uid' => $register['uid']]) && + Register::deleteByHash($register['hash']); + } + + /** + * Creates a new user based on a minimal set and sends an email to this user + * + * @param string $name The user's name + * @param string $email The user's email address + * @param string $nick The user's nick name + * @param string $lang The user's language (default is english) + * + * @return bool True, if the user was created successfully + * @throws InternalServerErrorException + * @throws \ErrorException + * @throws \ImagickException + */ + public static function createMinimal(string $name, string $email, string $nick, string $lang = L10n::DEFAULT) + { + if (empty($name) || + empty($email) || + empty($nick)) { + throw new InternalServerErrorException('Invalid arguments.'); + } + + $result = self::create([ + 'username' => $name, + 'email' => $email, + 'nickname' => $nick, + 'verified' => 1, + 'language' => $lang + ]); + + $user = $result['user']; + $preamble = Strings::deindent(DI::l10n()->t(' + Dear %1$s, + the administrator of %2$s has set up an account for you.')); + $body = Strings::deindent(DI::l10n()->t(' + The login details are as follows: + + Site Location: %1$s + Login Name: %2$s + Password: %3$s + + You may change your password from your account "Settings" page after logging + in. + + Please take a few moments to review the other account settings on that page. + + You may also wish to add some basic information to your default profile + (on the "Profiles" page) so that other people can easily find you. + + We recommend setting your full name, adding a profile photo, + adding some profile "keywords" (very useful in making new friends) - and + perhaps what country you live in; if you do not wish to be more specific + than that. + + We fully respect your right to privacy, and none of these items are necessary. + If you are new and do not know anybody here, they may help + you to make some new and interesting friends. + + If you ever want to delete your account, you can do so at %1$s/removeme + + Thank you and welcome to %4$s.')); + + $preamble = sprintf($preamble, $user['username'], DI::config()->get('config', 'sitename')); + $body = sprintf($body, DI::baseUrl()->get(), $user['nickname'], $result['password'], DI::config()->get('config', 'sitename')); + + $email = DI::emailer() + ->newSystemMail() + ->withMessage(DI::l10n()->t('Registration details for %s', DI::config()->get('config', 'sitename')), $preamble, $body) + ->forUser($user) + ->withRecipient($user['email']) + ->build(); + return DI::emailer()->send($email); + } + /** * Sends pending registration confirmation email * @@ -877,7 +1042,7 @@ class User * @param string $siteurl * @param string $password Plaintext password * @return NULL|boolean from notification() and email() inherited - * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws InternalServerErrorException */ public static function sendRegisterPendingEmail($user, $sitename, $siteurl, $password) { @@ -899,13 +1064,13 @@ class User $password )); - return notification([ - 'type' => SYSTEM_EMAIL, - 'uid' => $user['uid'], - 'to_email' => $user['email'], - 'subject' => DI::l10n()->t('Registration at %s', $sitename), - 'body' => $body - ]); + $email = DI::emailer() + ->newSystemMail() + ->withMessage(DI::l10n()->t('Registration at %s', $sitename), $body) + ->forUser($user) + ->withRecipient($user['email']) + ->build(); + return DI::emailer()->send($email); } /** @@ -920,7 +1085,7 @@ class User * @param string $password Plaintext password * * @return NULL|boolean from notification() and email() inherited - * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws InternalServerErrorException */ public static function sendRegisterOpenEmail(\Friendica\Core\L10n $l10n, $user, $sitename, $siteurl, $password) { @@ -967,23 +1132,21 @@ class User $password )); - return notification([ - 'uid' => $user['uid'], - 'language' => $user['language'], - 'type' => SYSTEM_EMAIL, - 'to_email' => $user['email'], - 'subject' => DI::l10n()->t('Registration details for %s', $sitename), - 'preamble' => $preamble, - 'body' => $body - ]); + $email = DI::emailer() + ->newSystemMail() + ->withMessage(DI::l10n()->t('Registration details for %s', $sitename), $preamble, $body) + ->forUser($user) + ->withRecipient($user['email']) + ->build(); + return DI::emailer()->send($email); } /** - * @param object $uid user to remove + * @param int $uid user to remove * @return bool - * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws InternalServerErrorException */ - public static function remove($uid) + public static function remove(int $uid) { if (!$uid) { return false; @@ -999,7 +1162,7 @@ class User // unique), so it cannot be re-registered in the future. DBA::insert('userd', ['username' => $user['nickname']]); - // The user and related data will be deleted in "cron_expire_and_remove_users" (cronjobs.php) + // The user and related data will be deleted in Friendica\Worker\CronJobs::expireAndRemoveUsers() DBA::update('user', ['account_removed' => true, 'account_expires_on' => DateTimeFormat::utc('now + 7 day')], ['uid' => $uid]); Worker::add(PRIORITY_HIGH, 'Notifier', Delivery::REMOVAL, $uid); @@ -1109,22 +1272,20 @@ class User 'total_users' => 0, 'active_users_halfyear' => 0, 'active_users_monthly' => 0, + 'active_users_weekly' => 0, ]; - $userStmt = DBA::p("SELECT `user`.`uid`, `user`.`login_date`, `contact`.`last-item` - FROM `user` - INNER JOIN `profile` ON `profile`.`uid` = `user`.`uid` AND `profile`.`is-default` - INNER JOIN `contact` ON `contact`.`uid` = `user`.`uid` AND `contact`.`self` - WHERE (`profile`.`publish` OR `profile`.`net-publish`) AND `user`.`verified` - AND NOT `user`.`blocked` AND NOT `user`.`account_removed` - AND NOT `user`.`account_expired`"); - + $userStmt = DBA::select('owner-view', ['uid', 'login_date', 'last-item'], + ["`verified` AND `login_date` > ? AND NOT `blocked` + AND NOT `account_removed` AND NOT `account_expired`", + DBA::NULL_DATETIME]); if (!DBA::isResult($userStmt)) { return $statistics; } $halfyear = time() - (180 * 24 * 60 * 60); $month = time() - (30 * 24 * 60 * 60); + $week = time() - (7 * 24 * 60 * 60); while ($user = DBA::fetch($userStmt)) { $statistics['total_users']++; @@ -1138,8 +1299,46 @@ class User ) { $statistics['active_users_monthly']++; } + + if ((strtotime($user['login_date']) > $week) || (strtotime($user['last-item']) > $week) + ) { + $statistics['active_users_weekly']++; + } } + DBA::close($userStmt); return $statistics; } + + /** + * Get all users of the current node + * + * @param int $start Start count (Default is 0) + * @param int $count Count of the items per page (Default is @see Pager::ITEMS_PER_PAGE) + * @param string $type The type of users, which should get (all, bocked, removed) + * @param string $order Order of the user list (Default is 'contact.name') + * @param bool $descending Order direction (Default is ascending) + * + * @return array The list of the users + * @throws Exception + */ + public static function getList($start = 0, $count = Pager::ITEMS_PER_PAGE, $type = 'all', $order = 'name', bool $descending = false) + { + $param = ['limit' => [$start, $count], 'order' => [$order => $descending]]; + $condition = []; + switch ($type) { + case 'active': + $condition['account_removed'] = false; + $condition['blocked'] = false; + break; + case 'blocked': + $condition['blocked'] = true; + break; + case 'removed': + $condition['account_removed'] = true; + break; + } + + return DBA::selectToArray('owner-view', [], $condition, $param); + } }