diff --git a/src/Core/Authentication.php b/src/Core/Authentication.php index 4d227c2710..50825c525e 100644 --- a/src/Core/Authentication.php +++ b/src/Core/Authentication.php @@ -12,6 +12,7 @@ use Friendica\Core\L10n; use Friendica\Core\Logger; use Friendica\Core\PConfig; use Friendica\Database\DBA; +use Friendica\Model\User; use Friendica\Util\DateTimeFormat; /** @@ -103,55 +104,16 @@ class Authentication extends BaseObject $a->timezone = $a->user['timezone']; } - $master_record = $a->user; + $masterUid = $user_record['uid']; if ((x($_SESSION, 'submanage')) && intval($_SESSION['submanage'])) { - $user = DBA::selectFirst('user', [], ['uid' => $_SESSION['submanage']]); + $user = DBA::selectFirst('user', ['uid'], ['uid' => $_SESSION['submanage']]); if (DBA::isResult($user)) { - $master_record = $user; + $masterUid = $user['uid']; } } - if ($master_record['parent-uid'] == 0) { - // First add our own entry - $a->identities = [['uid' => $master_record['uid'], - 'username' => $master_record['username'], - 'nickname' => $master_record['nickname']]]; - - // Then add all the children - $r = DBA::select('user', ['uid', 'username', 'nickname'], - ['parent-uid' => $master_record['uid'], 'account_removed' => false]); - if (DBA::isResult($r)) { - $a->identities = array_merge($a->identities, DBA::toArray($r)); - } - } else { - // Just ensure that the array is always defined - $a->identities = []; - - // First entry is our parent - $r = DBA::select('user', ['uid', 'username', 'nickname'], - ['uid' => $master_record['parent-uid'], 'account_removed' => false]); - if (DBA::isResult($r)) { - $a->identities = DBA::toArray($r); - } - - // Then add all siblings - $r = DBA::select('user', ['uid', 'username', 'nickname'], - ['parent-uid' => $master_record['parent-uid'], 'account_removed' => false]); - if (DBA::isResult($r)) { - $a->identities = array_merge($a->identities, DBA::toArray($r)); - } - } - - $r = DBA::p("SELECT `user`.`uid`, `user`.`username`, `user`.`nickname` - FROM `manage` - INNER JOIN `user` ON `manage`.`mid` = `user`.`uid` - WHERE `user`.`account_removed` = 0 AND `manage`.`uid` = ?", - $master_record['uid'] - ); - if (DBA::isResult($r)) { - $a->identities = array_merge($a->identities, DBA::toArray($r)); - } + $a->identities = User::identities($masterUid); if ($login_initial) { Logger::log('auth_identities: ' . print_r($a->identities, true), Logger::DEBUG); @@ -174,7 +136,7 @@ class Authentication extends BaseObject // Set the login date for all identities of the user DBA::update('user', ['login_date' => DateTimeFormat::utcNow()], - ['parent-uid' => $master_record['uid'], 'account_removed' => false]); + ['parent-uid' => $masterUid, 'account_removed' => false]); } if ($login_initial) { diff --git a/src/Model/User.php b/src/Model/User.php index 43992cc5f3..a5db34bb44 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -813,4 +813,74 @@ class User $a->internalRedirect(); } } + + /** + * Return all identities to a user + * + * @param int $uid The user id + * @return array All identities for this user + * + * Example for a return: + * [ + * [ + * 'uid' => 1, + * 'username' => 'maxmuster', + * 'nickname' => 'Max Mustermann' + * ], + * [ + * 'uid' => 2, + * 'username' => 'johndoe', + * 'nickname' => 'John Doe' + * ] + * ] + */ + public static function identities($uid) + { + $identities = []; + + $user = DBA::selectFirst('user', ['uid', 'nickname', 'username', 'parent-uid'], ['uid' => $uid]); + if (!DBA::isResult($user)) { + return $identities; + } + + if ($user['parent-uid'] == 0) { + // First add our own entry + $identities = [['uid' => $user['uid'], + 'username' => $user['username'], + 'nickname' => $user['nickname']]]; + + // Then add all the children + $r = DBA::select('user', ['uid', 'username', 'nickname'], + ['parent-uid' => $user['uid'], 'account_removed' => false]); + if (DBA::isResult($r)) { + $identities = array_merge($identities, DBA::toArray($r)); + } + } else { + // First entry is our parent + $r = DBA::select('user', ['uid', 'username', 'nickname'], + ['uid' => $user['parent-uid'], 'account_removed' => false]); + if (DBA::isResult($r)) { + $identities = DBA::toArray($r); + } + + // Then add all siblings + $r = DBA::select('user', ['uid', 'username', 'nickname'], + ['parent-uid' => $user['parent-uid'], 'account_removed' => false]); + if (DBA::isResult($r)) { + $identities = array_merge($identities, DBA::toArray($r)); + } + } + + $r = DBA::p("SELECT `user`.`uid`, `user`.`username`, `user`.`nickname` + FROM `manage` + INNER JOIN `user` ON `manage`.`mid` = `user`.`uid` + WHERE `user`.`account_removed` = 0 AND `manage`.`uid` = ?", + $user['uid'] + ); + if (DBA::isResult($r)) { + $identities = array_merge($identities, DBA::toArray($r)); + } + + return $identities; + } } diff --git a/tests/Util/DBAMockTrait.php b/tests/Util/DBAMockTrait.php index 1bb69c27bf..2ee54adaa1 100644 --- a/tests/Util/DBAMockTrait.php +++ b/tests/Util/DBAMockTrait.php @@ -69,4 +69,117 @@ trait DBAMockTrait ->times($times) ->andReturn($return); } + + + /** + * Mocking DBA::select() + * + * @param string $tableName The name of the table + * @param array $select The Select Array (Default is []) + * @param array $where The Where Array (Default is []) + * @param object $return The array to return (Default is []) + * @param null|int $times How often the method will get used + */ + public function mockSelect($tableName, $select = [], $where = [], $return = null, $times = null) + { + if (!isset($this->dbaMock)) { + $this->dbaMock = \Mockery::mock('alias:Friendica\Database\DBA'); + } + + $this->dbaMock + ->shouldReceive('select') + ->with($tableName, $select, $where) + ->times($times) + ->andReturn($return); + } + + /** + * Mocking DBA::selectFirst() + * + * @param string $tableName The name of the table + * @param array $select The Select Array (Default is []) + * @param array $where The Where Array (Default is []) + * @param array $return The array to return (Default is []) + * @param null|int $times How often the method will get used + */ + public function mockSelectFirst($tableName, $select = [], $where = [], $return = [], $times = null) + { + if (!isset($this->dbaMock)) { + $this->dbaMock = \Mockery::mock('alias:Friendica\Database\DBA'); + } + + $this->dbaMock + ->shouldReceive('selectFirst') + ->with($tableName, $select, $where) + ->times($times) + ->andReturn($return); + } + + /** + * Mocking DBA::isResult() + * + * @param object $record The record to test + * @param bool $return True, if the DB is connected, otherwise false + * @param null|int $times How often the method will get used + */ + public function mockIsResult($record, $return = true, $times = null) + { + if (!isset($this->dbaMock)) { + $this->dbaMock = \Mockery::mock('alias:Friendica\Database\DBA'); + } + + $this->dbaMock + ->shouldReceive('isResult') + ->with($record) + ->times($times) + ->andReturn($return); + } + + /** + * Mocking DBA::isResult() + * + * @param object $record The record to test + * @param array $return The array to return + * @param null|int $times How often the method will get used + */ + public function mockToArray($record = null, $return = [], $times = null) + { + if (!isset($this->dbaMock)) { + $this->dbaMock = \Mockery::mock('alias:Friendica\Database\DBA'); + } + + $this->dbaMock + ->shouldReceive('toArray') + ->with($record) + ->times($times) + ->andReturn($return); + } + + + /** + * Mocking DBA::p() + * + * @param string $sql The SQL statement + * @param object $return The object to return + * @param null|int $times How often the method will get used + */ + public function mockP($sql = null, $return = null, $times = null) + { + if (!isset($this->dbaMock)) { + $this->dbaMock = \Mockery::mock('alias:Friendica\Database\DBA'); + } + + if (!isset($sql)) { + $this->dbaMock + ->shouldReceive('p') + ->times($times) + ->andReturn($return); + } else { + $this->dbaMock + ->shouldReceive('p') + ->with($sql) + ->times($times) + ->andReturn($return); + } + } } diff --git a/tests/src/Model/UserTest.php b/tests/src/Model/UserTest.php new file mode 100644 index 0000000000..6655575f87 --- /dev/null +++ b/tests/src/Model/UserTest.php @@ -0,0 +1,148 @@ +parent = [ + 'uid' => 1, + 'username' => 'maxmuster', + 'nickname' => 'Max Muster' + ]; + + $this->child = [ + 'uid' => 2, + 'username' => 'johndoe', + 'nickname' => 'John Doe' + ]; + + $this->manage = [ + 'uid' => 3, + 'username' => 'janesmith', + 'nickname' => 'Jane Smith' + ]; + } + + public function testIdentitiesEmpty() + { + $this->mockSelectFirst('user', + ['uid', 'nickname', 'username', 'parent-uid'], + ['uid' => $this->parent['uid']], + $this->parent, + 1 + ); + $this->mockIsResult($this->parent, false, 1); + + $record = User::identities($this->parent['uid']); + + $this->assertEquals([], $record); + } + + public function testIdentitiesAsParent() + { + $parentSelect = $this->parent; + $parentSelect['parent-uid'] = 0; + + // Select the user itself (=parent) + $this->mockSelectFirst('user', + ['uid', 'nickname', 'username', 'parent-uid'], + ['uid' => $this->parent['uid']], + $parentSelect, + 1 + ); + $this->mockIsResult($parentSelect, true, 1); + + // Select one child + $this->mockSelect('user', + ['uid', 'username', 'nickname'], + [ + 'parent-uid' => $this->parent['uid'], + 'account_removed' => false + ], + 'objectReturn', + 1 + ); + $this->mockIsResult('objectReturn', true, 1); + $this->mockToArray('objectReturn', [ $this->child ], 1); + + // Select the manage + $this->mockP(null, 'objectTwo', 1); + $this->mockIsResult('objectTwo', true, 1); + $this->mockToArray('objectTwo', [ $this->manage ], 1); + + $record = User::identities($this->parent['uid']); + + $this->assertEquals([ + $this->parent, + $this->child, + $this->manage + ], $record); + } + + public function testIdentitiesAsChild() + { + $childSelect = $this->child; + $childSelect['parent-uid'] = $this->parent['uid']; + + // Select the user itself (=child) + $this->mockSelectFirst('user', + ['uid', 'nickname', 'username', 'parent-uid'], + ['uid' => $this->child['uid']], + $childSelect, + 1 + ); + $this->mockIsResult($childSelect, true, 1); + + // Select the parent + $this->mockSelect('user', + ['uid', 'username', 'nickname'], + [ + 'uid' => $this->parent['uid'], + 'account_removed' => false + ], + 'objectReturn', + 1 + ); + $this->mockIsResult('objectReturn', true, 1); + $this->mockToArray('objectReturn', [ $this->parent ], 1); + + // Select the childs (user & manage) + $this->mockSelect('user', + ['uid', 'username', 'nickname'], + [ + 'parent-uid' => $this->parent['uid'], + 'account_removed' => false + ], + 'objectReturn', + 1 + ); + $this->mockIsResult('objectReturn', true, 1); + $this->mockToArray('objectReturn', [ $this->child, $this->manage ], 1); + + // Select the manage + $this->mockP(null, 'objectTwo', 1); + $this->mockIsResult('objectTwo', false, 1); + + $record = User::identities($this->child['uid']); + + $this->assertEquals([ + $this->parent, + $this->child, + $this->manage + ], $record); + } +}