From e70de897d6a7a221644bca33e30b9db55b094c1e Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Fri, 7 May 2021 01:31:05 +0300 Subject: [PATCH] Work in progress account/teams/users --- app/controllers/api/account.php | 543 ++++++++++++------------------- app/controllers/api/projects.php | 4 +- app/controllers/api/teams.php | 349 ++++++++------------ app/controllers/api/users.php | 243 ++++++-------- app/init.php | 22 +- 5 files changed, 448 insertions(+), 713 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 2cf9770fc..c7c8fe3ff 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -1,30 +1,30 @@ inject('request') ->inject('response') ->inject('project') - ->inject('projectDB') + ->inject('dbForInternal') ->inject('audits') - ->action(function ($email, $password, $name, $request, $response, $project, $projectDB, $audits) { + ->action(function ($email, $password, $name, $request, $response, $project, $dbForInternal, $audits) { /** @var Utopia\Swoole\Request $request */ /** @var Appwrite\Utopia\Response $response */ /** @var Appwrite\Database\Document $project */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Database $dbForInternal */ /** @var Appwrite\Event\Event $audits */ if ('console' === $project->getId()) { @@ -79,40 +79,21 @@ App::post('/v1/account') $limit = $project->getAttribute('usersAuthLimit', 0); if ($limit !== 0) { - $projectDB->getCollection([ // Count users - 'filters' => [ - '$collection='.Database::SYSTEM_COLLECTION_USERS, - ], - ]); - - $sum = $projectDB->getSum(); + $sum = $dbForInternal->count('users'); // Count users TODO: add a 10k limit here. if($sum >= $limit) { throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501); } } - $profile = $projectDB->getCollectionFirst([ // Get user by email address - 'limit' => 1, - 'filters' => [ - '$collection='.Database::SYSTEM_COLLECTION_USERS, - 'email='.$email, - ], - ]); - - if (!empty($profile)) { - throw new Exception('Account already exists', 409); - } - Authorization::disable(); try { - $user = $projectDB->createDocument([ - '$collection' => Database::SYSTEM_COLLECTION_USERS, - '$permissions' => [ - 'read' => ['*'], - 'write' => ['user:{self}'], - ], + $userId = $dbForInternal->getId(); + $user = $dbForInternal->createDocument('users', new Document([ + '$id' => $userId, + '$read' => ['*'], + '$write' => ['user:'.$userId], 'email' => $email, 'emailVerification' => false, 'status' => Auth::USER_STATUS_UNACTIVATED, @@ -121,7 +102,11 @@ App::post('/v1/account') 'registration' => \time(), 'reset' => false, 'name' => $name, - ], ['email' => $email]); + 'prefs' => [], + 'sessions' => [], + 'tokens' => [], + 'memberships' => [], + ])); } catch (Duplicate $th) { throw new Exception('Account already exists', 409); } @@ -142,10 +127,8 @@ App::post('/v1/account') ->setParam('resource', 'users/'.$user->getId()) ; - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($user, Response::MODEL_USER) - ; + $response->setStatusCode(Response::STATUS_CODE_CREATED); + $response->dynamic2($user, Response::MODEL_USER); }); App::post('/v1/account/sessions') @@ -167,28 +150,23 @@ App::post('/v1/account/sessions') ->param('password', '', new Password(), 'User password. Must be between 6 to 32 chars.') ->inject('request') ->inject('response') - ->inject('projectDB') + ->inject('dbForInternal') ->inject('locale') ->inject('geodb') ->inject('audits') - ->action(function ($email, $password, $request, $response, $projectDB, $locale, $geodb, $audits) { + ->action(function ($email, $password, $request, $response, $dbForInternal, $locale, $geodb, $audits) { /** @var Utopia\Swoole\Request $request */ /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Database $dbForInternal */ /** @var Utopia\Locale\Locale $locale */ /** @var MaxMind\Db\Reader $geodb */ /** @var Appwrite\Event\Event $audits */ $protocol = $request->getProtocol(); - $profile = $projectDB->getCollectionFirst([ // Get user by email address - 'limit' => 1, - 'filters' => [ - '$collection='.Database::SYSTEM_COLLECTION_USERS, - 'email='.$email, - ], - ]); + + $profile = $dbForInternal->findFirst('users', [new Query('email', Query::TYPE_EQUAL, [$email])], 1); // Get user by email address - if (false == $profile || !Auth::passwordVerify($password, $profile->getAttribute('password'))) { + if (!$profile || !Auth::passwordVerify($password, $profile->getAttribute('password'))) { $audits //->setParam('userId', $profile->getId()) ->setParam('event', 'account.sesssions.failed') @@ -208,9 +186,7 @@ App::post('/v1/account/sessions') $secret = Auth::tokenGenerator(); $session = new Document(array_merge( [ - '$collection' => Database::SYSTEM_COLLECTION_SESSIONS, - '$permissions' => ['read' => ['user:'.$profile->getId()], 'write' => ['user:'.$profile->getId()]], - 'userId' => $profile->getId(), + '$id' => $dbForInternal->getId(), 'provider' => Auth::SESSION_PROVIDER_EMAIL, 'providerUid' => $email, 'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak @@ -223,15 +199,9 @@ App::post('/v1/account/sessions') Authorization::setRole('user:'.$profile->getId()); - $session = $projectDB->createDocument($session->getArrayCopy()); - - if (false === $session) { - throw new Exception('Failed saving session to DB', 500); - } - $profile->setAttribute('sessions', $session, Document::SET_TYPE_APPEND); - $profile = $projectDB->updateDocument($profile->getArrayCopy()); + $profile = $dbForInternal->updateDocument('users', $profile->getId(), $profile); if (false === $profile) { throw new Exception('Failed saving user to DB', 500); @@ -262,7 +232,7 @@ App::post('/v1/account/sessions') ->setAttribute('countryName', (isset($countries[strtoupper($session->getAttribute('countryCode'))])) ? $countries[strtoupper($session->getAttribute('countryCode'))] : $locale->getText('locale.country.unknown')) ; - $response->dynamic($session, Response::MODEL_SESSION); + $response->dynamic2($session, Response::MODEL_SESSION); }); App::get('/v1/account/sessions/oauth2/:provider') @@ -388,15 +358,15 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') ->inject('response') ->inject('project') ->inject('user') - ->inject('projectDB') + ->inject('dbForInternal') ->inject('geodb') ->inject('audits') - ->action(function ($provider, $code, $state, $request, $response, $project, $user, $projectDB, $geodb, $audits) use ($oauthDefaultSuccess) { + ->action(function ($provider, $code, $state, $request, $response, $project, $user, $dbForInternal, $geodb, $audits) use ($oauthDefaultSuccess) { /** @var Utopia\Swoole\Request $request */ /** @var Appwrite\Utopia\Response $response */ /** @var Appwrite\Database\Document $project */ - /** @var Appwrite\Database\Document $user */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Document $user */ + /** @var Utopia\Database\Database $dbForInternal */ /** @var MaxMind\Db\Reader $geodb */ /** @var Appwrite\Event\Event $audits */ @@ -460,13 +430,19 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') throw new Exception('Missing ID from OAuth2 provider', 400); } - $current = Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret); + $sessions = $user->getAttribute('sessions', []); + $current = Auth::sessionVerify($sessions, Auth::$secret); - if ($current) { - $projectDB->deleteDocument($current); //throw new Exception('User already logged in', 401); + if($current) { // Delete current session of new one. + foreach ($sessions as $key => $session) { + if ($current === $session['$id']) { + unset($sessions[$key]); + $dbForInternal->updateDocument('users', $user->getId(), $user->setAttribute('sessions', $sessions)); + } + } } - $user = (empty($user->getId())) ? $projectDB->getCollectionFirst([ // Get user by provider id + $user = (empty($user->getId())) ? $dbForInternal->getCollectionFirst([ // Get user by provider id 'limit' => 1, 'filters' => [ '$collection='.Database::SYSTEM_COLLECTION_USERS, @@ -479,25 +455,13 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $name = $oauth2->getUserName($accessToken); $email = $oauth2->getUserEmail($accessToken); - $user = $projectDB->getCollectionFirst([ // Get user by provider email address - 'limit' => 1, - 'filters' => [ - '$collection='.Database::SYSTEM_COLLECTION_USERS, - 'email='.$email, - ], - ]); + $user = $dbForInternal->findFirst('users', [new Query('email', Query::TYPE_EQUAL, [$email])], 1); // Get user by email address if (!$user || empty($user->getId())) { // Last option -> create the user, generate random password $limit = $project->getAttribute('usersAuthLimit', 0); if ($limit !== 0) { - $projectDB->getCollection([ // Count users - 'filters' => [ - '$collection='.Database::SYSTEM_COLLECTION_USERS, - ], - ]); - - $sum = $projectDB->getSum(); + $sum = $dbForInternal->count('users'); // Count users TODO: add a 10k limit here. if($sum >= $limit) { throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501); @@ -507,9 +471,11 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') Authorization::disable(); try { - $user = $projectDB->createDocument([ - '$collection' => Database::SYSTEM_COLLECTION_USERS, - '$permissions' => ['read' => ['*'], 'write' => ['user:{self}']], + $userId = $dbForInternal->getId(); + $user = $dbForInternal->createDocument('users', new Document([ + '$id' => $userId, + '$read' => ['*'], + '$write' => ['user:'.$userId], 'email' => $email, 'emailVerification' => true, 'status' => Auth::USER_STATUS_ACTIVATED, // Email should already be authenticated by OAuth2 provider @@ -518,16 +484,12 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') 'registration' => \time(), 'reset' => false, 'name' => $name, - ], ['email' => $email]); + ])); } catch (Duplicate $th) { throw new Exception('Account already exists', 409); } Authorization::reset(); - - if (false === $user) { - throw new Exception('Failed saving user to DB', 500); - } } } @@ -542,9 +504,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $secret = Auth::tokenGenerator(); $expiry = \time() + Auth::TOKEN_EXPIRATION_LOGIN_LONG; $session = new Document(array_merge([ - '$collection' => Database::SYSTEM_COLLECTION_SESSIONS, - '$permissions' => ['read' => ['user:'.$user['$id']], 'write' => ['user:'.$user['$id']]], - 'userId' => $user->getId(), + '$id' => $dbForInternal->getId(), 'provider' => $provider, 'providerUid' => $oauth2ID, 'providerToken' => $accessToken, @@ -571,7 +531,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') Authorization::setRole('user:'.$user->getId()); - $user = $projectDB->updateDocument($user->getArrayCopy()); + $user = $dbForInternal->updateDocument('users', $user->getId(), $user); if (false === $user) { throw new Exception('Failed saving user to DB', 500); @@ -631,16 +591,16 @@ App::post('/v1/account/sessions/anonymous') ->inject('locale') ->inject('user') ->inject('project') - ->inject('projectDB') + ->inject('dbForInternal') ->inject('geodb') ->inject('audits') - ->action(function ($request, $response, $locale, $user, $project, $projectDB, $geodb, $audits) { + ->action(function ($request, $response, $locale, $user, $project, $dbForInternal, $geodb, $audits) { /** @var Utopia\Swoole\Request $request */ /** @var Appwrite\Utopia\Response $response */ /** @var Utopia\Locale\Locale $locale */ - /** @var Appwrite\Database\Document $user */ + /** @var Utopia\Database\Document $user */ /** @var Appwrite\Database\Document $project */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Database $dbForInternal */ /** @var MaxMind\Db\Reader $geodb */ /** @var Appwrite\Event\Event $audits */ @@ -657,13 +617,7 @@ App::post('/v1/account/sessions/anonymous') $limit = $project->getAttribute('usersAuthLimit', 0); if ($limit !== 0) { - $projectDB->getCollection([ // Count users - 'filters' => [ - '$collection='.Database::SYSTEM_COLLECTION_USERS, - ], - ]); - - $sum = $projectDB->getSum(); + $sum = $dbForInternal->count('users'); // Count users TODO: add a 10k limit here. if($sum >= $limit) { throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501); @@ -672,12 +626,11 @@ App::post('/v1/account/sessions/anonymous') Authorization::disable(); try { - $user = $projectDB->createDocument([ - '$collection' => Database::SYSTEM_COLLECTION_USERS, - '$permissions' => [ - 'read' => ['*'], - 'write' => ['user:{self}'] - ], + $userId = $dbForInternal->getId(); + $user = $dbForInternal->createDocument('users', new Document([ + '$id' => $userId, + '$read' => ['*'], + '$write' => ['user:'.$userId], 'email' => null, 'emailVerification' => false, 'status' => Auth::USER_STATUS_UNACTIVATED, @@ -686,7 +639,7 @@ App::post('/v1/account/sessions/anonymous') 'registration' => \time(), 'reset' => false, 'name' => null - ]); + ])); } catch (Exception $th) { throw new Exception('Failed saving user to DB', 500); } @@ -704,9 +657,7 @@ App::post('/v1/account/sessions/anonymous') $expiry = \time() + Auth::TOKEN_EXPIRATION_LOGIN_LONG; $session = new Document(array_merge( [ - '$collection' => Database::SYSTEM_COLLECTION_SESSIONS, - '$permissions' => ['read' => ['user:' . $user['$id']], 'write' => ['user:' . $user['$id']]], - 'userId' => $user->getId(), + '$id' => $dbForInternal->getId(), 'provider' => Auth::SESSION_PROVIDER_ANONYMOUS, 'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak 'expire' => $expiry, @@ -723,7 +674,7 @@ App::post('/v1/account/sessions/anonymous') Authorization::setRole('user:'.$user->getId()); - $user = $projectDB->updateDocument($user->getArrayCopy()); + $user = $dbForInternal->updateDocument('users', $user->getId(), $user); if (false === $user) { throw new Exception('Failed saving user to DB', 500); @@ -752,7 +703,7 @@ App::post('/v1/account/sessions/anonymous') ->setAttribute('countryName', (isset($countries[$session->getAttribute('countryCode')])) ? $countries[$session->getAttribute('countryCode')] : $locale->getText('locale.country.unknown')) ; - $response->dynamic($session, Response::MODEL_SESSION); + $response->dynamic2($session, Response::MODEL_SESSION); }); App::post('/v1/account/jwt') @@ -770,7 +721,7 @@ App::post('/v1/account/jwt') ->inject('user') ->action(function ($response, $user) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Document $user */ + /** @var Utopia\Database\Document $user */ $sessions = $user->getAttribute('sessions', []); $current = new Document(); @@ -789,16 +740,15 @@ App::post('/v1/account/jwt') $jwt = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway. - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic(new Document(['jwt' => $jwt->encode([ - // 'uid' => 1, - // 'aud' => 'http://site.com', - // 'scopes' => ['user'], - // 'iss' => 'http://api.mysite.com', - 'userId' => $user->getId(), - 'sessionId' => $current->getId(), - ])]), Response::MODEL_JWT); + $response->setStatusCode(Response::STATUS_CODE_CREATED); + $response->dynamic2(new Document(['jwt' => $jwt->encode([ + // 'uid' => 1, + // 'aud' => 'http://site.com', + // 'scopes' => ['user'], + // 'iss' => 'http://api.mysite.com', + 'userId' => $user->getId(), + 'sessionId' => $current->getId(), + ])]), Response::MODEL_JWT); }); App::get('/v1/account') @@ -816,9 +766,9 @@ App::get('/v1/account') ->inject('user') ->action(function ($response, $user) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Document $user */ + /** @var Utopia\Database\Document $user */ - $response->dynamic($user, Response::MODEL_USER); + $response->dynamic2($user, Response::MODEL_USER); }); App::get('/v1/account/prefs') @@ -836,11 +786,11 @@ App::get('/v1/account/prefs') ->inject('user') ->action(function ($response, $user) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Document $user */ + /** @var Utopia\Database\Document $user */ $prefs = $user->getAttribute('prefs', new \stdClass()); - $response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES); + $response->dynamic2(new Document($prefs), Response::MODEL_PREFERENCES); }); App::get('/v1/account/sessions') @@ -859,7 +809,7 @@ App::get('/v1/account/sessions') ->inject('locale') ->action(function ($response, $user, $locale) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Document $user */ + /** @var Utopia\Database\Document $user */ /** @var Utopia\Locale\Locale $locale */ $sessions = $user->getAttribute('sessions', []); @@ -877,7 +827,7 @@ App::get('/v1/account/sessions') $sessions[$key] = $session; } - $response->dynamic(new Document([ + $response->dynamic2(new Document([ 'sum' => count($sessions), 'sessions' => $sessions ]), Response::MODEL_SESSION_LIST); @@ -903,7 +853,7 @@ App::get('/v1/account/logs') ->action(function ($response, $register, $project, $user, $locale, $geodb) { /** @var Appwrite\Utopia\Response $response */ /** @var Appwrite\Database\Document $project */ - /** @var Appwrite\Database\Document $user */ + /** @var Utopia\Database\Document $user */ /** @var Utopia\Locale\Locale $locale */ /** @var MaxMind\Db\Reader $geodb */ @@ -956,7 +906,7 @@ App::get('/v1/account/logs') } - $response->dynamic(new Document(['logs' => $output]), Response::MODEL_LOG_LIST); + $response->dynamic2(new Document(['logs' => $output]), Response::MODEL_LOG_LIST); }); App::patch('/v1/account/name') @@ -974,21 +924,15 @@ App::patch('/v1/account/name') ->param('name', '', new Text(128), 'User name. Max length: 128 chars.') ->inject('response') ->inject('user') - ->inject('projectDB') + ->inject('dbForInternal') ->inject('audits') - ->action(function ($name, $response, $user, $projectDB, $audits) { + ->action(function ($name, $response, $user, $dbForInternal, $audits) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Document $user */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Document $user */ + /** @var Utopia\Database\Database $dbForInternal */ /** @var Appwrite\Event\Event $audits */ - $user = $projectDB->updateDocument(\array_merge($user->getArrayCopy(), [ - 'name' => $name, - ])); - - if (false === $user) { - throw new Exception('Failed saving user to DB', 500); - } + $user = $dbForInternal->updateDocument('users', $user->getId(), $user->setAttribute('name', $name)); $audits ->setParam('userId', $user->getId()) @@ -996,7 +940,7 @@ App::patch('/v1/account/name') ->setParam('resource', 'users/'.$user->getId()) ; - $response->dynamic($user, Response::MODEL_USER); + $response->dynamic2($user, Response::MODEL_USER); }); App::patch('/v1/account/password') @@ -1015,25 +959,19 @@ App::patch('/v1/account/password') ->param('oldPassword', '', new Password(), 'Old user password. Must be between 6 to 32 chars.') ->inject('response') ->inject('user') - ->inject('projectDB') + ->inject('dbForInternal') ->inject('audits') - ->action(function ($password, $oldPassword, $response, $user, $projectDB, $audits) { + ->action(function ($password, $oldPassword, $response, $user, $dbForInternal, $audits) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Document $user */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Document $user */ + /** @var Utopia\Database\Database $dbForInternal */ /** @var Appwrite\Event\Event $audits */ if (!Auth::passwordVerify($oldPassword, $user->getAttribute('password'))) { // Double check user password throw new Exception('Invalid credentials', 401); } - $user = $projectDB->updateDocument(\array_merge($user->getArrayCopy(), [ - 'password' => Auth::passwordHash($password), - ])); - - if (false === $user) { - throw new Exception('Failed saving user to DB', 500); - } + $user = $dbForInternal->updateDocument('users', $user->getId(), $user->setAttribute('password', Auth::passwordHash($password))); $audits ->setParam('userId', $user->getId()) @@ -1041,7 +979,7 @@ App::patch('/v1/account/password') ->setParam('resource', 'users/'.$user->getId()) ; - $response->dynamic($user, Response::MODEL_USER); + $response->dynamic2($user, Response::MODEL_USER); }); App::patch('/v1/account/email') @@ -1060,12 +998,12 @@ App::patch('/v1/account/email') ->param('password', '', new Password(), 'User password. Must be between 6 to 32 chars.') ->inject('response') ->inject('user') - ->inject('projectDB') + ->inject('dbForInternal') ->inject('audits') - ->action(function ($email, $password, $response, $user, $projectDB, $audits) { + ->action(function ($email, $password, $response, $user, $dbForInternal, $audits) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Document $user */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Document $user */ + /** @var Utopia\Database\Database $dbForInternal */ /** @var Appwrite\Event\Event $audits */ $isAnonymousUser = is_null($user->getAttribute('email')) && is_null($user->getAttribute('password')); // Check if request is from an anonymous account for converting @@ -1077,28 +1015,17 @@ App::patch('/v1/account/email') throw new Exception('Invalid credentials', 401); } - $profile = $projectDB->getCollectionFirst([ // Get user by email address - 'limit' => 1, - 'filters' => [ - '$collection='.Database::SYSTEM_COLLECTION_USERS, - 'email='.$email, - ], - ]); + $profile = $dbForInternal->findFirst('users', [new Query('email', Query::TYPE_EQUAL, [$email])], 1); // Get user by email address - if (!empty($profile)) { + if ($profile) { throw new Exception('User already registered', 400); } - // TODO after this user needs to confirm mail again - - $user = $projectDB->updateDocument(\array_merge( - $user->getArrayCopy(), - ($isAnonymousUser ? [ 'password' => Auth::passwordHash($password) ] : []), - [ - 'email' => $email, - 'emailVerification' => false, - ] - )); + $user = $dbForInternal->updateDocument('users', $user->getId(), $user + ->setAttribute('password', $isAnonymousUser ? Auth::passwordHash($password) : $user->getAttribute('password', '')) + ->setAttribute('email', $email) + ->setAttribute('emailVerification', false) // After this user needs to confirm mail again + ); if (false === $user) { throw new Exception('Failed saving user to DB', 500); @@ -1110,7 +1037,7 @@ App::patch('/v1/account/email') ->setParam('resource', 'users/'.$user->getId()) ; - $response->dynamic($user, Response::MODEL_USER); + $response->dynamic2($user, Response::MODEL_USER); }); App::patch('/v1/account/prefs') @@ -1128,28 +1055,22 @@ App::patch('/v1/account/prefs') ->param('prefs', [], new Assoc(), 'Prefs key-value JSON object.') ->inject('response') ->inject('user') - ->inject('projectDB') + ->inject('dbForInternal') ->inject('audits') - ->action(function ($prefs, $response, $user, $projectDB, $audits) { + ->action(function ($prefs, $response, $user, $dbForInternal, $audits) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Document $user */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Document $user */ + /** @var Utopia\Database\Database $dbForInternal */ /** @var Appwrite\Event\Event $audits */ - - $user = $projectDB->updateDocument(\array_merge($user->getArrayCopy(), [ - 'prefs' => $prefs, - ])); - if (false === $user) { - throw new Exception('Failed saving user to DB', 500); - } + $user = $dbForInternal->updateDocument('users', $user->getId(), $user->setAttribute('prefs', $prefs)); $audits ->setParam('event', 'account.update.prefs') ->setParam('resource', 'users/'.$user->getId()) ; - $response->dynamic($user, Response::MODEL_USER); + $response->dynamic2($user, Response::MODEL_USER); }); App::delete('/v1/account') @@ -1166,21 +1087,20 @@ App::delete('/v1/account') ->inject('request') ->inject('response') ->inject('user') - ->inject('projectDB') + ->inject('dbForInternal') ->inject('audits') ->inject('events') - ->action(function ($request, $response, $user, $projectDB, $audits, $events) { + ->action(function ($request, $response, $user, $dbForInternal, $audits, $events) { /** @var Utopia\Swoole\Request $request */ /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Document $user */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Document $user */ + /** @var Utopia\Database\Database $dbForInternal */ /** @var Appwrite\Event\Event $audits */ /** @var Appwrite\Event\Event $events */ $protocol = $request->getProtocol(); - $user = $projectDB->updateDocument(\array_merge($user->getArrayCopy(), [ - 'status' => Auth::USER_STATUS_BLOCKED, - ])); + $user = $dbForInternal->updateDocument('users', $user->getId(), $user->setAttribute('status', Auth::USER_STATUS_BLOCKED)); + if (false === $user) { throw new Exception('Failed saving user to DB', 500); @@ -1202,7 +1122,7 @@ App::delete('/v1/account') ; $events - ->setParam('eventData', $response->output($user, Response::MODEL_USER)) + ->setParam('eventData', $response->output2($user, Response::MODEL_USER)) ; if (!Config::getParam('domainVerification')) { @@ -1234,14 +1154,14 @@ App::delete('/v1/account/sessions/:sessionId') ->inject('request') ->inject('response') ->inject('user') - ->inject('projectDB') + ->inject('dbForInternal') ->inject('audits') ->inject('events') - ->action(function ($sessionId, $request, $response, $user, $projectDB, $audits, $events) { + ->action(function ($sessionId, $request, $response, $user, $dbForInternal, $audits, $events) { /** @var Utopia\Swoole\Request $request */ /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Document $user */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Document $user */ + /** @var Utopia\Database\Database $dbForInternal */ /** @var Appwrite\Event\Event $audits */ /** @var Appwrite\Event\Event $events */ @@ -1252,13 +1172,11 @@ App::delete('/v1/account/sessions/:sessionId') $sessions = $user->getAttribute('sessions', []); - foreach ($sessions as $session) { + foreach ($sessions as $key => $session) { /** @var Document $session */ - if (($sessionId == $session->getId())) { - if (!$projectDB->deleteDocument($session->getId())) { - throw new Exception('Failed to remove token from DB', 500); - } + if ($sessionId == $session->getId()) { + unset($sessions[$key]); $audits ->setParam('userId', $user->getId()) @@ -1283,8 +1201,10 @@ App::delete('/v1/account/sessions/:sessionId') ; } + $dbForInternal->updateDocument('users', $user->getId(), $user->setAttribute('sessions', $sessions)); + $events - ->setParam('eventData', $response->output($session, Response::MODEL_SESSION)) + ->setParam('eventData', $response->output2($session, Response::MODEL_SESSION)) ; return $response->noContent(); @@ -1309,14 +1229,14 @@ App::delete('/v1/account/sessions') ->inject('request') ->inject('response') ->inject('user') - ->inject('projectDB') + ->inject('dbForInternal') ->inject('audits') ->inject('events') - ->action(function ($request, $response, $user, $projectDB, $audits, $events) { + ->action(function ($request, $response, $user, $dbForInternal, $audits, $events) { /** @var Utopia\Swoole\Request $request */ /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Document $user */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Document $user */ + /** @var Utopia\Database\Database $dbForInternal */ /** @var Appwrite\Event\Event $audits */ /** @var Appwrite\Event\Event $events */ @@ -1326,10 +1246,6 @@ App::delete('/v1/account/sessions') foreach ($sessions as $session) { /** @var Document $session */ - if (!$projectDB->deleteDocument($session->getId())) { - throw new Exception('Failed to remove token from DB', 500); - } - $audits ->setParam('userId', $user->getId()) ->setParam('event', 'account.sessions.delete') @@ -1352,9 +1268,11 @@ App::delete('/v1/account/sessions') ; } } + + $dbForInternal->updateDocument('users', $user->getId(), $user->setAttribute('sessions', [])); $events - ->setParam('eventData', $response->output(new Document([ + ->setParam('eventData', $response->output2(new Document([ 'sum' => count($sessions), 'sessions' => $sessions ]), Response::MODEL_SESSION_LIST)) @@ -1381,16 +1299,16 @@ App::post('/v1/account/recovery') ->param('url', '', function ($clients) { return new Host($clients); }, 'URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients']) ->inject('request') ->inject('response') - ->inject('projectDB') + ->inject('dbForInternal') ->inject('project') ->inject('locale') ->inject('mails') ->inject('audits') ->inject('events') - ->action(function ($email, $url, $request, $response, $projectDB, $project, $locale, $mails, $audits, $events) { + ->action(function ($email, $url, $request, $response, $dbForInternal, $project, $locale, $mails, $audits, $events) { /** @var Utopia\Swoole\Request $request */ /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Database $dbForInternal */ /** @var Appwrite\Database\Document $project */ /** @var Utopia\Locale\Locale $locale */ /** @var Appwrite\Event\Event $mails */ @@ -1400,15 +1318,9 @@ App::post('/v1/account/recovery') $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::$roles); $isAppUser = Auth::isAppUser(Authorization::$roles); - $profile = $projectDB->getCollectionFirst([ // Get user by email address - 'limit' => 1, - 'filters' => [ - '$collection='.Database::SYSTEM_COLLECTION_USERS, - 'email='.$email, - ], - ]); + $profile = $dbForInternal->findFirst('users', [new Query('email', Query::TYPE_EQUAL, [$email])], 1); // Get user by email address - if (empty($profile)) { + if (!$profile) { throw new Exception('User not found', 404); // TODO maybe hide this } @@ -1418,9 +1330,7 @@ App::post('/v1/account/recovery') $secret = Auth::tokenGenerator(); $recovery = new Document([ - '$collection' => Database::SYSTEM_COLLECTION_TOKENS, - '$permissions' => ['read' => ['user:'.$profile->getId()], 'write' => ['user:'.$profile->getId()]], - 'userId' => $profile->getId(), + '$id' => $dbForInternal->getId(), 'type' => Auth::TOKEN_TYPE_RECOVERY, 'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak 'expire' => \time() + Auth::TOKEN_EXPIRATION_RECOVERY, @@ -1430,19 +1340,9 @@ App::post('/v1/account/recovery') Authorization::setRole('user:'.$profile->getId()); - $recovery = $projectDB->createDocument($recovery->getArrayCopy()); - - if (false === $recovery) { - throw new Exception('Failed saving recovery to DB', 500); - } - $profile->setAttribute('tokens', $recovery, Document::SET_TYPE_APPEND); - $profile = $projectDB->updateDocument($profile->getArrayCopy()); - - if (false === $profile) { - throw new Exception('Failed to save user to DB', 500); - } + $profile = $dbForInternal->updateDocument('users', $profile->getId(), $profile); $url = Template::parseURL($url); $url['query'] = Template::mergeQuery(((isset($url['query'])) ? $url['query'] : ''), ['userId' => $profile->getId(), 'secret' => $secret]); @@ -1480,7 +1380,7 @@ App::post('/v1/account/recovery') $events ->setParam('eventData', - $response->output($recovery->setAttribute('secret', $secret), + $response->output2($recovery->setAttribute('secret', $secret), Response::MODEL_TOKEN )) ; @@ -1495,10 +1395,8 @@ App::post('/v1/account/recovery') ->setParam('resource', 'users/'.$profile->getId()) ; - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($recovery, Response::MODEL_TOKEN) - ; + $response->setStatusCode(Response::STATUS_CODE_CREATED); + $response->dynamic2($recovery, Response::MODEL_TOKEN); }); App::put('/v1/account/recovery') @@ -1520,30 +1418,25 @@ App::put('/v1/account/recovery') ->param('password', '', new Password(), 'New password. Must be between 6 to 32 chars.') ->param('passwordAgain', '', new Password(), 'New password again. Must be between 6 to 32 chars.') ->inject('response') - ->inject('projectDB') + ->inject('dbForInternal') ->inject('audits') - ->action(function ($userId, $secret, $password, $passwordAgain, $response, $projectDB, $audits) { + ->action(function ($userId, $secret, $password, $passwordAgain, $response, $dbForInternal, $audits) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Database $dbForInternal */ /** @var Appwrite\Event\Event $audits */ if ($password !== $passwordAgain) { throw new Exception('Passwords must match', 400); } - $profile = $projectDB->getCollectionFirst([ // Get user by email address - 'limit' => 1, - 'filters' => [ - '$collection='.Database::SYSTEM_COLLECTION_USERS, - '$id='.$userId, - ], - ]); + $profile = $dbForInternal->getDocument('users', $userId); - if (empty($profile)) { + if ($profile->isEmpty()) { throw new Exception('User not found', 404); // TODO maybe hide this } - $recovery = Auth::tokenVerify($profile->getAttribute('tokens', []), Auth::TOKEN_TYPE_RECOVERY, $secret); + $tokens = $profile->getAttribute('tokens', []); + $recovery = Auth::tokenVerify($tokens, Auth::TOKEN_TYPE_RECOVERY, $secret); if (!$recovery) { throw new Exception('Invalid recovery token', 401); @@ -1551,33 +1444,33 @@ App::put('/v1/account/recovery') Authorization::setRole('user:'.$profile->getId()); - $profile = $projectDB->updateDocument(\array_merge($profile->getArrayCopy(), [ - 'password' => Auth::passwordHash($password), - 'passwordUpdate' => \time(), - 'emailVerification' => true, - ])); - - if (false === $profile) { - throw new Exception('Failed saving user to DB', 500); - } + $profile = $dbForInternal->updateDocument('users', $profile->getId(), $profile + ->setAttribute('password', Auth::passwordHash($password)) + ->setAttribute('passwordUpdate', \time()) + ->setAttribute('emailVerification', true) + ); /** * We act like we're updating and validating * the recovery token but actually we don't need it anymore. */ - if (!$projectDB->deleteDocument($recovery)) { - throw new Exception('Failed to remove recovery from DB', 500); + + foreach ($tokens as $key => $token) { + if($recovery === $token->getId()) { + $recovery = $token; + unset($tokens[$key]); + } } + $dbForInternal->updateDocument('users', $profile->getId(), $profile->setAttribute('tokens', $tokens)); + $audits ->setParam('userId', $profile->getId()) ->setParam('event', 'account.recovery.update') ->setParam('resource', 'users/'.$profile->getId()) ; - $recovery = $profile->search('$id', $recovery, $profile->getAttribute('tokens', [])); - - $response->dynamic($recovery, Response::MODEL_TOKEN); + $response->dynamic2($recovery, Response::MODEL_TOKEN); }); App::post('/v1/account/verification') @@ -1599,17 +1492,17 @@ App::post('/v1/account/verification') ->inject('response') ->inject('project') ->inject('user') - ->inject('projectDB') + ->inject('dbForInternal') ->inject('locale') ->inject('audits') ->inject('events') ->inject('mails') - ->action(function ($url, $request, $response, $project, $user, $projectDB, $locale, $audits, $events, $mails) { + ->action(function ($url, $request, $response, $project, $user, $dbForInternal, $locale, $audits, $events, $mails) { /** @var Utopia\Swoole\Request $request */ /** @var Appwrite\Utopia\Response $response */ /** @var Appwrite\Database\Document $project */ - /** @var Appwrite\Database\Document $user */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Document $user */ + /** @var Utopia\Database\Database $dbForInternal */ /** @var Utopia\Locale\Locale $locale */ /** @var Appwrite\Event\Event $audits */ /** @var Appwrite\Event\Event $events */ @@ -1621,9 +1514,7 @@ App::post('/v1/account/verification') $verificationSecret = Auth::tokenGenerator(); $verification = new Document([ - '$collection' => Database::SYSTEM_COLLECTION_TOKENS, - '$permissions' => ['read' => ['user:'.$user->getId()], 'write' => ['user:'.$user->getId()]], - 'userId' => $user->getId(), + '$id' => $dbForInternal->getId(), 'type' => Auth::TOKEN_TYPE_VERIFICATION, 'secret' => Auth::hash($verificationSecret), // One way hash encryption to protect DB leak 'expire' => \time() + Auth::TOKEN_EXPIRATION_CONFIRM, @@ -1633,19 +1524,9 @@ App::post('/v1/account/verification') Authorization::setRole('user:'.$user->getId()); - $verification = $projectDB->createDocument($verification->getArrayCopy()); - - if (false === $verification) { - throw new Exception('Failed saving verification to DB', 500); - } - $user->setAttribute('tokens', $verification, Document::SET_TYPE_APPEND); - $user = $projectDB->updateDocument($user->getArrayCopy()); - - if (false === $user) { - throw new Exception('Failed to save user to DB', 500); - } + $user = $dbForInternal->updateDocument('users', $user->getId(), $user); $url = Template::parseURL($url); $url['query'] = Template::mergeQuery(((isset($url['query'])) ? $url['query'] : ''), ['userId' => $user->getId(), 'secret' => $verificationSecret]); @@ -1683,7 +1564,7 @@ App::post('/v1/account/verification') $events ->setParam('eventData', - $response->output($verification->setAttribute('secret', $verificationSecret), + $response->output2($verification->setAttribute('secret', $verificationSecret), Response::MODEL_TOKEN )) ; @@ -1698,10 +1579,8 @@ App::post('/v1/account/verification') ->setParam('resource', 'users/'.$user->getId()) ; - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($verification, Response::MODEL_TOKEN) - ; + $response->setStatusCode(Response::STATUS_CODE_CREATED); + $response->dynamic2($verification, Response::MODEL_TOKEN); }); App::put('/v1/account/verification') @@ -1722,27 +1601,22 @@ App::put('/v1/account/verification') ->param('secret', '', new Text(256), 'Valid verification token.') ->inject('response') ->inject('user') - ->inject('projectDB') + ->inject('dbForInternal') ->inject('audits') - ->action(function ($userId, $secret, $response, $user, $projectDB, $audits) { + ->action(function ($userId, $secret, $response, $user, $dbForInternal, $audits) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Document $user */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Document $user */ + /** @var Utopia\Database\Database $dbForInternal */ /** @var Appwrite\Event\Event $audits */ - $profile = $projectDB->getCollectionFirst([ // Get user by email address - 'limit' => 1, - 'filters' => [ - '$collection='.Database::SYSTEM_COLLECTION_USERS, - '$id='.$userId, - ], - ]); + $profile = $dbForInternal->getDocument('users', $userId); - if (empty($profile)) { + if ($profile->isEmpty()) { throw new Exception('User not found', 404); // TODO maybe hide this } - $verification = Auth::tokenVerify($profile->getAttribute('tokens', []), Auth::TOKEN_TYPE_VERIFICATION, $secret); + $tokens = $profile->getAttribute('tokens', []); + $verification = Auth::tokenVerify($tokens, Auth::TOKEN_TYPE_VERIFICATION, $secret); if (!$verification) { throw new Exception('Invalid verification token', 401); @@ -1750,9 +1624,7 @@ App::put('/v1/account/verification') Authorization::setRole('user:'.$profile->getId()); - $profile = $projectDB->updateDocument(\array_merge($profile->getArrayCopy(), [ - 'emailVerification' => true, - ])); + $profile = $dbForInternal->updateDocument('users', $profile->getId(), $profile->setAttribute('emailVerification', true)); if (false === $profile) { throw new Exception('Failed saving user to DB', 500); @@ -1762,17 +1634,20 @@ App::put('/v1/account/verification') * We act like we're updating and validating * the verification token but actually we don't need it anymore. */ - if (!$projectDB->deleteDocument($verification)) { - throw new Exception('Failed to remove verification from DB', 500); + foreach ($tokens as $key => $token) { + if($token->getId() === $verification) { + $verification = $token; + unset($tokens[$key]); + } } + $dbForInternal->updateDocument('users', $profile->getId(), $profile->setAttribute('tokens', $tokens)); + $audits ->setParam('userId', $profile->getId()) ->setParam('event', 'account.verification.update') ->setParam('resource', 'users/'.$user->getId()) ; - $verification = $profile->search('$id', $verification, $profile->getAttribute('tokens', [])); - - $response->dynamic($verification, Response::MODEL_TOKEN); + $response->dynamic2($verification, Response::MODEL_TOKEN); }); \ No newline at end of file diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index ff845bd67..0b5c1cb20 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -54,9 +54,9 @@ App::post('/v1/projects') /** @var Utopia\Database\Database $dbForInternal */ /** @var Utopia\Database\Database $dbForExternal */ - $team = $projectDB->getDocument($teamId); + $team = $dbForInternal->getDocument('teams', $teamId); - if (empty($team->getId()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) { + if ($team->isEmpty()) { throw new Exception('Team not found', 404); } diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 910427da1..bc6ae280b 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -1,24 +1,24 @@ desc('Create Team') @@ -36,41 +36,33 @@ App::post('/v1/teams') ->param('roles', ['owner'], new ArrayList(new Key()), 'Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](/docs/permissions). Max length for each role is 32 chars.', true) ->inject('response') ->inject('user') - ->inject('projectDB') - ->action(function ($name, $roles, $response, $user, $projectDB) { + ->inject('dbForInternal') + ->action(function ($name, $roles, $response, $user, $dbForInternal) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Document $user */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Document $user */ + /** @var Utopia\Database\Database $dbForInternal */ Authorization::disable(); $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::$roles); $isAppUser = Auth::isAppUser(Authorization::$roles); - $team = $projectDB->createDocument([ - '$collection' => Database::SYSTEM_COLLECTION_TEAMS, - '$permissions' => [ - 'read' => ['team:{self}'], - 'write' => ['team:{self}/owner'], - ], + $teamId = $dbForInternal->getId(); + $team = $dbForInternal->createDocument('teams', new Document([ + '$id' => $teamId , + '$read' => ['team:'.$teamId ], + '$write' => ['team:'.$teamId .'/owner'], 'name' => $name, 'sum' => ($isPrivilegedUser || $isAppUser) ? 0 : 1, 'dateCreated' => \time(), - ]); + ])); Authorization::reset(); - if (false === $team) { - throw new Exception('Failed saving team to DB', 500); - } - if (!$isPrivilegedUser && !$isAppUser) { // Don't add user on server mode $membership = new Document([ - '$collection' => Database::SYSTEM_COLLECTION_MEMBERSHIPS, - '$permissions' => [ - 'read' => ['user:'.$user->getId(), 'team:'.$team->getId()], - 'write' => ['user:'.$user->getId(), 'team:'.$team->getId().'/owner'], - ], + '$read' => ['user:'.$user->getId(), 'team:'.$team->getId()], + '$write' => ['user:'.$user->getId(), 'team:'.$team->getId().'/owner'], 'userId' => $user->getId(), 'teamId' => $team->getId(), 'roles' => $roles, @@ -80,20 +72,16 @@ App::post('/v1/teams') 'secret' => '', ]); + $membership = $dbForInternal->createDocument('memberships', $membership); + // Attach user to team $user->setAttribute('memberships', $membership, Document::SET_TYPE_APPEND); - $user = $projectDB->updateDocument($user->getArrayCopy()); - - if (false === $user) { - throw new Exception('Failed saving user to DB', 500); - } + $user = $dbForInternal->updateDocument('users', $user->getId(), $user); } - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($team, Response::MODEL_TEAM) - ; + $response->setStatusCode(Response::STATUS_CODE_CREATED); + $response->dynamic2($team, Response::MODEL_TEAM); }); App::get('/v1/teams') @@ -112,23 +100,16 @@ App::get('/v1/teams') ->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true) ->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true) ->inject('response') - ->inject('projectDB') - ->action(function ($search, $limit, $offset, $orderType, $response, $projectDB) { + ->inject('dbForInternal') + ->action(function ($search, $limit, $offset, $orderType, $response, $dbForInternal) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Database $dbForInternal */ - $results = $projectDB->getCollection([ - 'limit' => $limit, - 'offset' => $offset, - 'orderType' => $orderType, - 'search' => $search, - 'filters' => [ - '$collection='.Database::SYSTEM_COLLECTION_TEAMS, - ], - ]); + $results = $dbForInternal->find('teams', [], $limit, $offset); + $sum = $dbForInternal->count('teams', [], 5000); - $response->dynamic(new Document([ - 'sum' => $projectDB->getSum(), + $response->dynamic2(new Document([ + 'sum' => $sum, 'teams' => $results ]), Response::MODEL_TEAM_LIST); }); @@ -146,18 +127,18 @@ App::get('/v1/teams/:teamId') ->label('sdk.response.model', Response::MODEL_TEAM) ->param('teamId', '', new UID(), 'Team unique ID.') ->inject('response') - ->inject('projectDB') - ->action(function ($teamId, $response, $projectDB) { + ->inject('dbForInternal') + ->action(function ($teamId, $response, $dbForInternal) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Database $dbForInternal */ - $team = $projectDB->getDocument($teamId); + $team = $dbForInternal->getDocument('teams', $teamId); - if (empty($team->getId()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) { + if (empty($team->getId())) { throw new Exception('Team not found', 404); } - $response->dynamic($team, Response::MODEL_TEAM); + $response->dynamic2($team, Response::MODEL_TEAM); }); App::put('/v1/teams/:teamId') @@ -175,26 +156,20 @@ App::put('/v1/teams/:teamId') ->param('teamId', '', new UID(), 'Team unique ID.') ->param('name', null, new Text(128), 'Team name. Max length: 128 chars.') ->inject('response') - ->inject('projectDB') - ->action(function ($teamId, $name, $response, $projectDB) { + ->inject('dbForInternal') + ->action(function ($teamId, $name, $response, $dbForInternal) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Database $dbForInternal */ - $team = $projectDB->getDocument($teamId); + $team = $dbForInternal->getDocument('teams', $teamId); - if (empty($team->getId()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) { + if (empty($team->getId())) { throw new Exception('Team not found', 404); } - $team = $projectDB->updateDocument(\array_merge($team->getArrayCopy(), [ - 'name' => $name, - ])); + $team = $dbForInternal->updateDocument('teams', $team->getId(), $team->setAttribute('name', $name)); - if (false === $team) { - throw new Exception('Failed saving team to DB', 500); - } - - $response->dynamic($team, Response::MODEL_TEAM); + $response->dynamic2($team, Response::MODEL_TEAM); }); App::delete('/v1/teams/:teamId') @@ -210,40 +185,37 @@ App::delete('/v1/teams/:teamId') ->label('sdk.response.model', Response::MODEL_NONE) ->param('teamId', '', new UID(), 'Team unique ID.') ->inject('response') - ->inject('projectDB') + ->inject('dbForInternal') ->inject('events') - ->action(function ($teamId, $response, $projectDB, $events) { + ->action(function ($teamId, $response, $dbForInternal, $events) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Database $dbForInternal */ /** @var Appwrite\Event\Event $events */ - $team = $projectDB->getDocument($teamId); + $team = $dbForInternal->getDocument('teams', $teamId); - if (empty($team->getId()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) { + if (empty($team->getId())) { throw new Exception('Team not found', 404); } - $memberships = $projectDB->getCollection([ - 'limit' => 2000, // TODO add members limit - 'offset' => 0, - 'filters' => [ - '$collection='.Database::SYSTEM_COLLECTION_MEMBERSHIPS, - 'teamId='.$teamId, - ], - ]); + $memberships = $dbForInternal->find('memberships', [ + new Query('teamId', Query::TYPE_EQUAL, [$teamId]), + ], 2000, 0); // TODO fix members limit + + // TODO delete all members individually from the user object foreach ($memberships as $member) { - if (!$projectDB->deleteDocument($member->getId())) { + if (!$dbForInternal->deleteDocument('memberships', $member->getId())) { throw new Exception('Failed to remove membership for team from DB', 500); } } - if (!$projectDB->deleteDocument($teamId)) { + if (!$dbForInternal->deleteDocument('teams', $teamId)) { throw new Exception('Failed to remove team from DB', 500); } $events - ->setParam('eventData', $response->output($team, Response::MODEL_TEAM)) + ->setParam('eventData', $response->output2($team, Response::MODEL_TEAM)) ; $response->noContent(); @@ -271,15 +243,15 @@ App::post('/v1/teams/:teamId/memberships') ->inject('response') ->inject('project') ->inject('user') - ->inject('projectDB') + ->inject('dbForInternal') ->inject('locale') ->inject('audits') ->inject('mails') - ->action(function ($teamId, $email, $name, $roles, $url, $response, $project, $user, $projectDB, $locale, $audits, $mails) { + ->action(function ($teamId, $email, $name, $roles, $url, $response, $project, $user, $dbForInternal, $locale, $audits, $mails) { /** @var Appwrite\Utopia\Response $response */ /** @var Appwrite\Database\Document $project */ /** @var Appwrite\Database\Document $user */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Database $dbForInternal */ /** @var Appwrite\Event\Event $audits */ /** @var Appwrite\Event\Event $mails */ @@ -287,41 +259,21 @@ App::post('/v1/teams/:teamId/memberships') $isAppUser = Auth::isAppUser(Authorization::$roles); $name = (empty($name)) ? $email : $name; - $team = $projectDB->getDocument($teamId); + $team = $dbForInternal->getDocument('teams', $teamId); - if (empty($team->getId()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) { + if (empty($team->getId())) { throw new Exception('Team not found', 404); } - $memberships = $projectDB->getCollection([ - 'limit' => 50, - 'offset' => 0, - 'filters' => [ - '$collection='.Database::SYSTEM_COLLECTION_MEMBERSHIPS, - 'teamId='.$team->getId(), - ], - ]); - - $invitee = $projectDB->getCollectionFirst([ // Get user by email address - 'limit' => 1, - 'filters' => [ - '$collection='.Database::SYSTEM_COLLECTION_USERS, - 'email='.$email, - ], - ]); + $memberships = $dbForInternal->findFirst('memberships', [new Query('teamId', Query::TYPE_EQUAL, [$team->getId()])], 2000, 0); + $invitee = $dbForInternal->findFirst('users', [new Query('email', Query::TYPE_EQUAL, [$email])], 1); // Get user by email address if (empty($invitee)) { // Create new user if no user with same email found $limit = $project->getAttribute('usersAuthLimit', 0); if ($limit !== 0 && $project->getId() !== 'console') { // check users limit, console invites are allways allowed. - $projectDB->getCollection([ // Count users - 'filters' => [ - '$collection='.Database::SYSTEM_COLLECTION_USERS, - ], - ]); - - $sum = $projectDB->getSum(); + $sum = $dbForInternal->count('users'); // Count users TODO: add a 10k limit here. if($sum >= $limit) { throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501); @@ -331,12 +283,11 @@ App::post('/v1/teams/:teamId/memberships') Authorization::disable(); try { - $invitee = $projectDB->createDocument([ - '$collection' => Database::SYSTEM_COLLECTION_USERS, - '$permissions' => [ - 'read' => ['user:{self}', '*'], - 'write' => ['user:{self}'], - ], + $userId = $dbForInternal->getId(); + $invitee = $dbForInternal->createDocument('users', new Document([ + '$id' => $userId, + '$read' => ['user:'.$userId, '*'], + '$write' => ['user:'.$userId], 'email' => $email, 'emailVerification' => false, 'status' => Auth::USER_STATUS_UNACTIVATED, @@ -347,16 +298,12 @@ App::post('/v1/teams/:teamId/memberships') 'name' => $name, 'sessions' => [], 'tokens' => [], - ], ['email' => $email]); + ])); } catch (Duplicate $th) { throw new Exception('Account already exists', 409); } Authorization::reset(); - - if (false === $invitee) { - throw new Exception('Failed saving user to DB', 500); - } } $isOwner = false; @@ -378,11 +325,9 @@ App::post('/v1/teams/:teamId/memberships') $secret = Auth::tokenGenerator(); $membership = new Document([ - '$collection' => Database::SYSTEM_COLLECTION_MEMBERSHIPS, - '$permissions' => [ - 'read' => ['*'], - 'write' => ['user:'.$invitee->getId(), 'team:'.$team->getId().'/owner'], - ], + '$id' => $dbForInternal->getId(), + '$read' => ['*'], + '$write' => ['user:'.$invitee->getId(), 'team:'.$team->getId().'/owner'], 'userId' => $invitee->getId(), 'teamId' => $team->getId(), 'roles' => $roles, @@ -394,28 +339,18 @@ App::post('/v1/teams/:teamId/memberships') if ($isPrivilegedUser || $isAppUser) { // Allow admin to create membership Authorization::disable(); - $membership = $projectDB->createDocument($membership->getArrayCopy()); + $membership = $dbForInternal->createDocument('memberships', $membership); - $team = $projectDB->updateDocument(\array_merge($team->getArrayCopy(), [ - 'sum' => $team->getAttribute('sum', 0) + 1, - ])); + $team = $dbForInternal->updateDocument('teams', $team->getId(), $team->setAttribute('sum', $team->getAttribute('sum', 0) + 1)); // Attach user to team $invitee->setAttribute('memberships', $membership, Document::SET_TYPE_APPEND); - $invitee = $projectDB->updateDocument($invitee->getArrayCopy()); - - if (false === $invitee) { - throw new Exception('Failed saving user to DB', 500); - } + $invitee = $dbForInternal->updateDocument('users', $invitee->getId(), $invitee); Authorization::reset(); } else { - $membership = $projectDB->createDocument($membership->getArrayCopy()); - } - - if (false === $membership) { - throw new Exception('Failed saving membership to DB', 500); + $membership = $dbForInternal->createDocument('memberships', $membership); } $url = Template::parseURL($url); @@ -462,13 +397,11 @@ App::post('/v1/teams/:teamId/memberships') ->setParam('resource', 'teams/'.$teamId) ; - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic(new Document(\array_merge($membership->getArrayCopy(), [ - 'email' => $email, - 'name' => $name, - ])), Response::MODEL_MEMBERSHIP) - ; + $response->setStatusCode(Response::STATUS_CODE_CREATED); + $response->dynamic2($membership + ->setAttribute('email', $email) + ->setAttribute('name', $name) + , Response::MODEL_MEMBERSHIP); }); App::get('/v1/teams/:teamId/memberships') @@ -488,27 +421,19 @@ App::get('/v1/teams/:teamId/memberships') ->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true) ->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true) ->inject('response') - ->inject('projectDB') - ->action(function ($teamId, $search, $limit, $offset, $orderType, $response, $projectDB) { + ->inject('dbForInternal') + ->action(function ($teamId, $search, $limit, $offset, $orderType, $response, $dbForInternal) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Database $dbForInternal */ - $team = $projectDB->getDocument($teamId); + $team = $dbForInternal->getDocument('teams', $teamId); - if (empty($team->getId()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) { + if (empty($team->getId())) { throw new Exception('Team not found', 404); } - $memberships = $projectDB->getCollection([ - 'limit' => $limit, - 'offset' => $offset, - 'orderType' => $orderType, - 'search' => $search, - 'filters' => [ - '$collection='.Database::SYSTEM_COLLECTION_MEMBERSHIPS, - 'teamId='.$teamId, - ], - ]); + $memberships = $dbForInternal->find('memberships', [new Query('teamId', Query::TYPE_EQUAL, [$teamId])], $limit, $offset); + $sum = $dbForInternal->count('memberships', [new Query('teamId', Query::TYPE_EQUAL, [$teamId])], 5000); $users = []; foreach ($memberships as $membership) { @@ -516,12 +441,15 @@ App::get('/v1/teams/:teamId/memberships') continue; } - $temp = $projectDB->getDocument($membership->getAttribute('userId', null))->getArrayCopy(['email', 'name']); + $temp = $dbForInternal->getDocument('users', $membership->getAttribute('userId', null))->getArrayCopy(['email', 'name']); $users[] = new Document(\array_merge($temp, $membership->getArrayCopy())); } - $response->dynamic(new Document(['sum' => $projectDB->getSum(), 'memberships' => $users]), Response::MODEL_MEMBERSHIP_LIST); + $response->dynamic2(new Document([ + 'sum' => $sum, + 'memberships' => $users + ]), Response::MODEL_MEMBERSHIP_LIST); }); App::patch('/v1/teams/:teamId/memberships/:inviteId/status') @@ -543,21 +471,21 @@ App::patch('/v1/teams/:teamId/memberships/:inviteId/status') ->inject('request') ->inject('response') ->inject('user') - ->inject('projectDB') + ->inject('dbForInternal') ->inject('geodb') ->inject('audits') - ->action(function ($teamId, $inviteId, $userId, $secret, $request, $response, $user, $projectDB, $geodb, $audits) { + ->action(function ($teamId, $inviteId, $userId, $secret, $request, $response, $user, $dbForInternal, $geodb, $audits) { /** @var Utopia\Swoole\Request $request */ /** @var Appwrite\Utopia\Response $response */ /** @var Appwrite\Database\Document $user */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Database $dbForInternal */ /** @var MaxMind\Db\Reader $geodb */ /** @var Appwrite\Event\Event $audits */ $protocol = $request->getProtocol(); - $membership = $projectDB->getDocument($inviteId); + $membership = $dbForInternal->getDocument('memberships', $inviteId); - if (empty($membership->getId()) || Database::SYSTEM_COLLECTION_MEMBERSHIPS != $membership->getCollection()) { + if (empty($membership->getId())) { throw new Exception('Invite not found', 404); } @@ -567,11 +495,11 @@ App::patch('/v1/teams/:teamId/memberships/:inviteId/status') Authorization::disable(); - $team = $projectDB->getDocument($teamId); + $team = $dbForInternal->getDocument('teams', $teamId); Authorization::reset(); - if (empty($team->getId()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) { + if (empty($team->getId())) { throw new Exception('Team not found', 404); } @@ -584,13 +512,7 @@ App::patch('/v1/teams/:teamId/memberships/:inviteId/status') } if (empty($user->getId())) { - $user = $projectDB->getCollectionFirst([ // Get user - 'limit' => 1, - 'filters' => [ - '$collection='.Database::SYSTEM_COLLECTION_USERS, - '$id='.$userId, - ], - ]); + $user = $dbForInternal->getDocument('users', $userId); // Get user } if ($membership->getAttribute('userId') !== $user->getId()) { @@ -614,8 +536,7 @@ App::patch('/v1/teams/:teamId/memberships/:inviteId/status') $expiry = \time() + Auth::TOKEN_EXPIRATION_LOGIN_LONG; $secret = Auth::tokenGenerator(); $session = new Document(array_merge([ - '$collection' => Database::SYSTEM_COLLECTION_SESSIONS, - '$permissions' => ['read' => ['user:'.$user->getId()], 'write' => ['user:'.$user->getId()]], + '$id' => $dbForInternal->getId(), 'userId' => $user->getId(), 'provider' => Auth::SESSION_PROVIDER_EMAIL, 'providerUid' => $user->getAttribute('email'), @@ -630,24 +551,14 @@ App::patch('/v1/teams/:teamId/memberships/:inviteId/status') Authorization::setRole('user:'.$userId); - $user = $projectDB->updateDocument($user->getArrayCopy()); - - if (false === $user) { - throw new Exception('Failed saving user to DB', 500); - } + $user = $dbForInternal->updateDocument('users', $user->getId(), $user); Authorization::disable(); - $team = $projectDB->updateDocument(\array_merge($team->getArrayCopy(), [ - 'sum' => $team->getAttribute('sum', 0) + 1, - ])); + $team = $dbForInternal->updateDocument('teams', $team->getId(), $team->setAttribute('sum', $team->getAttribute('sum', 0) + 1)); Authorization::reset(); - if (false === $team) { - throw new Exception('Failed saving team to DB', 500); - } - $audits ->setParam('userId', $user->getId()) ->setParam('event', 'teams.membership.update') @@ -665,10 +576,10 @@ App::patch('/v1/teams/:teamId/memberships/:inviteId/status') ->addCookie(Auth::$cookieName, Auth::encodeSession($user->getId(), $secret), $expiry, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')) ; - $response->dynamic(new Document(\array_merge($membership->getArrayCopy(), [ - 'email' => $user->getAttribute('email'), - 'name' => $user->getAttribute('name'), - ])), Response::MODEL_MEMBERSHIP); + $response->dynamic2($membership + ->setAttribute('email', $user->getAttribute('email')) + ->setAttribute('name', $user->getAttribute('name')) + , Response::MODEL_MEMBERSHIP); }); App::delete('/v1/teams/:teamId/memberships/:inviteId') @@ -685,18 +596,18 @@ App::delete('/v1/teams/:teamId/memberships/:inviteId') ->param('teamId', '', new UID(), 'Team unique ID.') ->param('inviteId', '', new UID(), 'Invite unique ID.') ->inject('response') - ->inject('projectDB') + ->inject('dbForInternal') ->inject('audits') ->inject('events') - ->action(function ($teamId, $inviteId, $response, $projectDB, $audits, $events) { + ->action(function ($teamId, $inviteId, $response, $dbForInternal, $audits, $events) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Database $dbForInternal */ /** @var Appwrite\Event\Event $audits */ /** @var Appwrite\Event\Event $events */ - $membership = $projectDB->getDocument($inviteId); + $membership = $dbForInternal->getDocument('memberships', $inviteId); - if (empty($membership->getId()) || Database::SYSTEM_COLLECTION_MEMBERSHIPS != $membership->getCollection()) { + if (empty($membership->getId())) { throw new Exception('Invite not found', 404); } @@ -704,24 +615,18 @@ App::delete('/v1/teams/:teamId/memberships/:inviteId') throw new Exception('Team IDs don\'t match', 404); } - $team = $projectDB->getDocument($teamId); + $team = $dbForInternal->getDocument('teams', $teamId); - if (empty($team->getId()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) { + if (empty($team->getId())) { throw new Exception('Team not found', 404); } - if (!$projectDB->deleteDocument($membership->getId())) { + if (!$dbForInternal->deleteDocument('memberships', $membership->getId())) { throw new Exception('Failed to remove membership from DB', 500); } if ($membership->getAttribute('confirm')) { // Count only confirmed members - $team = $projectDB->updateDocument(\array_merge($team->getArrayCopy(), [ - 'sum' => $team->getAttribute('sum', 0) - 1, - ])); - } - - if (false === $team) { - throw new Exception('Failed saving team to DB', 500); + $team = $dbForInternal->updateDocument('teams', $team->getId(), $team->setAttribute('sum', $team->getAttribute('sum', 0) - 1)); } $audits @@ -731,7 +636,7 @@ App::delete('/v1/teams/:teamId/memberships/:inviteId') ; $events - ->setParam('eventData', $response->output($membership, Response::MODEL_MEMBERSHIP)) + ->setParam('eventData', $response->output2($membership, Response::MODEL_MEMBERSHIP)) ; $response->noContent(); diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 6b5bfbdbd..82386f44f 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -1,5 +1,8 @@ param('password', '', new Password(), 'User password. Must be between 6 to 32 chars.') ->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true) ->inject('response') - ->inject('projectDB') - ->action(function ($email, $password, $name, $response, $projectDB) { + ->inject('dbForInternal') + ->action(function ($email, $password, $name, $response, $dbForInternal) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Database $projectDB */ - - $profile = $projectDB->getCollectionFirst([ // Get user by email address - 'limit' => 1, - 'filters' => [ - '$collection='.Database::SYSTEM_COLLECTION_USERS, - 'email='.$email, - ], - ]); - - if (!empty($profile)) { - throw new Exception('User already registered', 409); - } + /** @var Utopia\Database\Database $dbForInternal */ try { - $user = $projectDB->createDocument([ - '$collection' => Database::SYSTEM_COLLECTION_USERS, - '$permissions' => [ - 'read' => ['*'], - 'write' => ['user:{self}'], - ], + $userId = $dbForInternal->getId(); + $user = $dbForInternal->createDocument('users', new Document([ + '$id' => $userId, + '$read' => ['*'], + '$write' => ['user:'.$userId], 'email' => $email, 'emailVerification' => false, 'status' => Auth::USER_STATUS_UNACTIVATED, @@ -66,15 +52,17 @@ App::post('/v1/users') 'registration' => \time(), 'reset' => false, 'name' => $name, - ], ['email' => $email]); + 'prefs' => [], + 'sessions' => [], + 'tokens' => [], + 'memberships' => [], + ])); } catch (Duplicate $th) { throw new Exception('Account already exists', 409); } - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($user, Response::MODEL_USER) - ; + $response->setStatusCode(Response::STATUS_CODE_CREATED); + $response->dynamic2($user, Response::MODEL_USER); }); App::get('/v1/users') @@ -93,23 +81,16 @@ App::get('/v1/users') ->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true) ->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true) ->inject('response') - ->inject('projectDB') - ->action(function ($search, $limit, $offset, $orderType, $response, $projectDB) { + ->inject('dbForInternal') + ->action(function ($search, $limit, $offset, $orderType, $response, $dbForInternal) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Database $dbForInternal */ - $results = $projectDB->getCollection([ - 'limit' => $limit, - 'offset' => $offset, - 'orderType' => $orderType, - 'search' => $search, - 'filters' => [ - '$collection='.Database::SYSTEM_COLLECTION_USERS, - ], - ]); + $results = $dbForInternal->find('users', [], $limit, $offset); + $sum = $dbForInternal->count('users', [], 5000); - $response->dynamic(new Document([ - 'sum' => $projectDB->getSum(), + $response->dynamic2(new Document([ + 'sum' => $sum, 'users' => $results ]), Response::MODEL_USER_LIST); }); @@ -127,18 +108,18 @@ App::get('/v1/users/:userId') ->label('sdk.response.model', Response::MODEL_USER) ->param('userId', '', new UID(), 'User unique ID.') ->inject('response') - ->inject('projectDB') - ->action(function ($userId, $response, $projectDB) { + ->inject('dbForInternal') + ->action(function ($userId, $response, $dbForInternal) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Database $dbForInternal */ - $user = $projectDB->getDocument($userId); + $user = $dbForInternal->getDocument('users', $userId); - if (empty($user->getId()) || Database::SYSTEM_COLLECTION_USERS != $user->getCollection()) { + if (empty($user->getId())) { throw new Exception('User not found', 404); } - $response->dynamic($user, Response::MODEL_USER); + $response->dynamic2($user, Response::MODEL_USER); }); App::get('/v1/users/:userId/prefs') @@ -154,20 +135,20 @@ App::get('/v1/users/:userId/prefs') ->label('sdk.response.model', Response::MODEL_PREFERENCES) ->param('userId', '', new UID(), 'User unique ID.') ->inject('response') - ->inject('projectDB') - ->action(function ($userId, $response, $projectDB) { + ->inject('dbForInternal') + ->action(function ($userId, $response, $dbForInternal) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Database $dbForInternal */ - $user = $projectDB->getDocument($userId); + $user = $dbForInternal->getDocument('users', $userId); - if (empty($user->getId()) || Database::SYSTEM_COLLECTION_USERS != $user->getCollection()) { + if (empty($user->getId())) { throw new Exception('User not found', 404); } $prefs = $user->getAttribute('prefs', new \stdClass()); - $response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES); + $response->dynamic2(new Document($prefs), Response::MODEL_PREFERENCES); }); App::get('/v1/users/:userId/sessions') @@ -183,16 +164,16 @@ App::get('/v1/users/:userId/sessions') ->label('sdk.response.model', Response::MODEL_SESSION_LIST) ->param('userId', '', new UID(), 'User unique ID.') ->inject('response') - ->inject('projectDB') + ->inject('dbForInternal') ->inject('locale') - ->action(function ($userId, $response, $projectDB, $locale) { + ->action(function ($userId, $response, $dbForInternal, $locale) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Database $dbForInternal */ /** @var Utopia\Locale\Locale $locale */ - $user = $projectDB->getDocument($userId); + $user = $dbForInternal->getDocument('users', $userId); - if (empty($user->getId()) || Database::SYSTEM_COLLECTION_USERS != $user->getCollection()) { + if (empty($user->getId())) { throw new Exception('User not found', 404); } @@ -210,11 +191,11 @@ App::get('/v1/users/:userId/sessions') $sessions[$key] = $session; } - $response->dynamic(new Document([ + $response->dynamic2(new Document([ 'sum' => count($sessions), 'sessions' => $sessions ]), Response::MODEL_SESSION_LIST); - }, ['response', 'projectDB', 'locale']); + }, ['response', 'dbForInternal', 'locale']); App::get('/v1/users/:userId/logs') ->desc('Get User Logs') @@ -231,20 +212,20 @@ App::get('/v1/users/:userId/logs') ->inject('response') ->inject('register') ->inject('project') - ->inject('projectDB') + ->inject('dbForInternal') ->inject('locale') ->inject('geodb') - ->action(function ($userId, $response, $register, $project, $projectDB, $locale, $geodb) { + ->action(function ($userId, $response, $register, $project, $dbForInternal, $locale, $geodb) { /** @var Appwrite\Utopia\Response $response */ /** @var Utopia\Registry\Registry $register */ /** @var Appwrite\Database\Document $project */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Database $dbForInternal */ /** @var Utopia\Locale\Locale $locale */ /** @var MaxMind\Db\Reader $geodb */ - $user = $projectDB->getDocument($userId); + $user = $dbForInternal->getDocument('users', $userId); - if (empty($user->getId()) || Database::SYSTEM_COLLECTION_USERS != $user->getCollection()) { + if (empty($user->getId())) { throw new Exception('User not found', 404); } @@ -327,7 +308,7 @@ App::get('/v1/users/:userId/logs') } } - $response->dynamic(new Document(['logs' => $output]), Response::MODEL_LOG_LIST); + $response->dynamic2(new Document(['logs' => $output]), Response::MODEL_LOG_LIST); }); App::patch('/v1/users/:userId/status') @@ -345,26 +326,20 @@ App::patch('/v1/users/:userId/status') ->param('userId', '', new UID(), 'User unique ID.') ->param('status', '', new WhiteList([Auth::USER_STATUS_ACTIVATED, Auth::USER_STATUS_BLOCKED, Auth::USER_STATUS_UNACTIVATED], true), 'User Status code. To activate the user pass '.Auth::USER_STATUS_ACTIVATED.', to block the user pass '.Auth::USER_STATUS_BLOCKED.' and for disabling the user pass '.Auth::USER_STATUS_UNACTIVATED) ->inject('response') - ->inject('projectDB') - ->action(function ($userId, $status, $response, $projectDB) { + ->inject('dbForInternal') + ->action(function ($userId, $status, $response, $dbForInternal) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Database $dbForInternal */ - $user = $projectDB->getDocument($userId); + $user = $dbForInternal->getDocument('users', $userId); - if (empty($user->getId()) || Database::SYSTEM_COLLECTION_USERS != $user->getCollection()) { + if (empty($user->getId())) { throw new Exception('User not found', 404); } - $user = $projectDB->updateDocument(\array_merge($user->getArrayCopy(), [ - 'status' => (int)$status, - ])); + $user = $dbForInternal->updateDocument('users', $user->getId(), $user->setAttribute('status', (int)$status)); - if (false === $user) { - throw new Exception('Failed saving user to DB', 500); - } - - $response->dynamic($user, Response::MODEL_USER); + $response->dynamic2($user, Response::MODEL_USER); }); App::patch('/v1/users/:userId/prefs') @@ -382,26 +357,20 @@ App::patch('/v1/users/:userId/prefs') ->param('userId', '', new UID(), 'User unique ID.') ->param('prefs', '', new Assoc(), 'Prefs key-value JSON object.') ->inject('response') - ->inject('projectDB') - ->action(function ($userId, $prefs, $response, $projectDB) { + ->inject('dbForInternal') + ->action(function ($userId, $prefs, $response, $dbForInternal) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Database $dbForInternal */ - $user = $projectDB->getDocument($userId); + $user = $dbForInternal->getDocument('users', $userId); - if (empty($user->getId()) || Database::SYSTEM_COLLECTION_USERS != $user->getCollection()) { + if ($user->isEmpty()) { throw new Exception('User not found', 404); } - $user = $projectDB->updateDocument(\array_merge($user->getArrayCopy(), [ - 'prefs' => $prefs, - ])); + $user = $dbForInternal->updateDocument('users', $user->getId(), $user->setAttribute('prefs', $prefs)); - if (false === $user) { - throw new Exception('Failed saving user to DB', 500); - } - - $response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES); + $response->dynamic2(new Document($prefs), Response::MODEL_PREFERENCES); }); App::delete('/v1/users/:userId/sessions/:sessionId') @@ -418,32 +387,34 @@ App::delete('/v1/users/:userId/sessions/:sessionId') ->param('userId', '', new UID(), 'User unique ID.') ->param('sessionId', null, new UID(), 'User unique session ID.') ->inject('response') - ->inject('projectDB') + ->inject('dbForInternal') ->inject('events') - ->action(function ($userId, $sessionId, $response, $projectDB, $events) { + ->action(function ($userId, $sessionId, $response, $dbForInternal, $events) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Database $dbForInternal */ /** @var Appwrite\Event\Event $events */ - $user = $projectDB->getDocument($userId); + $user = $dbForInternal->getDocument('users', $userId); - if (empty($user->getId()) || Database::SYSTEM_COLLECTION_USERS != $user->getCollection()) { + if (empty($user->getId())) { throw new Exception('User not found', 404); } $sessions = $user->getAttribute('sessions', []); - foreach ($sessions as $session) { + foreach ($sessions as $key => $session) { /** @var Document $session */ if ($sessionId == $session->getId()) { - if (!$projectDB->deleteDocument($session->getId())) { - throw new Exception('Failed to remove token from DB', 500); - } + unset($sessions[$key]); + $user->setAttribute('sessions', $sessions); + $events - ->setParam('eventData', $response->output($user, Response::MODEL_USER)) + ->setParam('eventData', $response->output2($user, Response::MODEL_USER)) ; + + $dbForInternal->updateDocument('users', $user->getId(), $user); } } @@ -464,31 +435,25 @@ App::delete('/v1/users/:userId/sessions') ->label('sdk.response.model', Response::MODEL_NONE) ->param('userId', '', new UID(), 'User unique ID.') ->inject('response') - ->inject('projectDB') + ->inject('dbForInternal') ->inject('events') - ->action(function ($userId, $response, $projectDB, $events) { + ->action(function ($userId, $response, $dbForInternal, $events) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Database $dbForInternal */ /** @var Appwrite\Event\Event $events */ - $user = $projectDB->getDocument($userId); + $user = $dbForInternal->getDocument('users', $userId); - if (empty($user->getId()) || Database::SYSTEM_COLLECTION_USERS != $user->getCollection()) { + if (empty($user->getId())) { throw new Exception('User not found', 404); } $sessions = $user->getAttribute('sessions', []); - - foreach ($sessions as $session) { - /** @var Document $session */ - - if (!$projectDB->deleteDocument($session->getId())) { - throw new Exception('Failed to remove token from DB', 500); - } - } + + $dbForInternal->updateDocument('users', $user->getId(), $user); $events - ->setParam('eventData', $response->output($user, Response::MODEL_USER)) + ->setParam('eventData', $response->output2($user, Response::MODEL_USER)) ; // TODO : Response filter implementation @@ -508,39 +473,29 @@ App::delete('/v1/users/:userId') ->label('sdk.response.model', Response::MODEL_NONE) ->param('userId', '', function () {return new UID();}, 'User unique ID.') ->inject('response') - ->inject('projectDB') + ->inject('dbForInternal') ->inject('events') ->inject('deletes') - ->action(function ($userId, $response, $projectDB, $events, $deletes) { + ->action(function ($userId, $response, $dbForInternal, $events, $deletes) { /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Database $dbForInternal */ /** @var Appwrite\Event\Event $events */ /** @var Appwrite\Event\Event $deletes */ - $user = $projectDB->getDocument($userId); + $user = $dbForInternal->getDocument('users', $userId); - if (empty($user->getId()) || Database::SYSTEM_COLLECTION_USERS != $user->getCollection()) { + if ($user->isEmpty()) { throw new Exception('User not found', 404); } - if (!$projectDB->deleteDocument($userId)) { + + if (!$dbForInternal->deleteDocument('users', $userId)) { throw new Exception('Failed to remove user from DB', 500); } - - if (!$projectDB->deleteUniqueKey(md5('users:email='.$user->getAttribute('email', null)))) { - throw new Exception('Failed to remove unique key from DB', 500); - } - $reservedId = $projectDB->createDocument([ - '$collection' => Database::SYSTEM_COLLECTION_RESERVED, - '$id' => $userId, - '$permissions' => [ - 'read' => ['*'], - ], - ]); - - if (false === $reservedId) { - throw new Exception('Failed saving reserved id to DB', 500); - } + // $dbForInternal->createDocument('users', new Document([ + // '$id' => $userId, + // '$read' => ['*'], + // ])); $deletes ->setParam('type', DELETE_TYPE_DOCUMENT) @@ -548,7 +503,7 @@ App::delete('/v1/users/:userId') ; $events - ->setParam('eventData', $response->output($user, Response::MODEL_USER)) + ->setParam('eventData', $response->output2($user, Response::MODEL_USER)) ; // TODO : Response filter implementation diff --git a/app/init.php b/app/init.php index 7a163a39c..4f599aa45 100644 --- a/app/init.php +++ b/app/init.php @@ -406,12 +406,12 @@ App::setResource('clients', function($request, $console, $project) { return $clients; }, ['request', 'console', 'project']); -App::setResource('user', function($mode, $project, $console, $request, $response, $projectDB, $consoleDB) { +App::setResource('user', function($mode, $project, $console, $request, $response, $dbForInternal, $dbForConsole) { /** @var Utopia\Swoole\Request $request */ /** @var Appwrite\Utopia\Response $response */ - /** @var Appwrite\Database\Document $project */ - /** @var Appwrite\Database\Database $consoleDB */ - /** @var Appwrite\Database\Database $projectDB */ + /** @var Utopia\Database\Document $project */ + /** @var Utopia\Database\Database $dbForInternal */ + /** @var Utopia\Database\Database $dbForConsole */ /** @var bool $mode */ Authorization::setDefaultStatus(true); @@ -437,14 +437,14 @@ App::setResource('user', function($mode, $project, $console, $request, $response $session = Auth::decodeSession(((isset($fallback[Auth::$cookieName])) ? $fallback[Auth::$cookieName] : '')); } - Auth::$unique = $session['id']; - Auth::$secret = $session['secret']; + Auth::$unique = $session['id'] ?? ''; + Auth::$secret = $session['secret'] ?? ''; if (APP_MODE_ADMIN !== $mode) { - $user = $projectDB->getDocument(Auth::$unique); + $user = $dbForInternal->getDocument('users', Auth::$unique); } else { - $user = $consoleDB->getDocument(Auth::$unique); + $user = $dbForConsole->getDocument('users', Auth::$unique); $user ->setAttribute('$id', 'admin-'.$user->getAttribute('$id')) @@ -481,7 +481,7 @@ App::setResource('user', function($mode, $project, $console, $request, $response $jwtSessionId = $payload['sessionId'] ?? ''; if($jwtUserId && $jwtSessionId) { - $user = $projectDB->getDocument($jwtUserId); + $user = $dbForInternal->getDocument('users', $jwtUserId); } if (empty($user->search('$id', $jwtSessionId, $user->getAttribute('tokens')))) { // Match JWT to active token @@ -490,7 +490,7 @@ App::setResource('user', function($mode, $project, $console, $request, $response } return $user; -}, ['mode', 'project', 'console', 'request', 'response', 'projectDB', 'consoleDB']); +}, ['mode', 'project', 'console', 'request', 'response', 'dbForInternal', 'dbForConsole']); App::setResource('project', function($consoleDB, $request) { /** @var Utopia\Swoole\Request $request */ @@ -500,7 +500,7 @@ App::setResource('project', function($consoleDB, $request) { Authorization2::disable(); $project = $consoleDB->getDocument($request->getParam('project', - $request->getHeader('x-appwrite-project', ''))); + $request->getHeader('x-appwrite-project', 'console'))); Authorization::reset(); Authorization2::reset();