1
0
Fork 0
mirror of synced 2024-06-02 19:04:49 +12:00

Merge pull request #1412 from appwrite/feat-db-refactor-routes

Feat db refactor routes
This commit is contained in:
Eldad A. Fux 2021-07-19 22:18:28 +03:00 committed by GitHub
commit 48ad89ac27
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 350 additions and 32 deletions

View file

@ -371,6 +371,254 @@ $collections = [
],
],
'sessions' => [
'$collection' => Database::COLLECTIONS,
'$id' => 'sessions',
'name' => 'Sessions',
'attributes' => [
[
'$id' => 'userId',
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => 'provider',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 128,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => 'providerUid',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 2048,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => 'providerToken',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16384,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => 'secret',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 64, // https://www.tutorialspoint.com/how-long-is-the-sha256-hash-in-mysql
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => 'expire',
'type' => Database::VAR_INTEGER,
'format' => '',
'size' => 0,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => 'userAgent',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16384,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => 'ip',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 45, // https://stackoverflow.com/a/166157/2299554
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => 'countryCode',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 2,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => []
],
[
'$id' => 'osCode',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 256,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => []
],
[
'$id' => 'osName',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 256,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => []
],
[
'$id' => 'osVersion',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 256,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => []
],
[
'$id' => 'clientType',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 256,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => []
],
[
'$id' => 'clientCode',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 256,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => []
],
[
'$id' => 'clientName',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 256,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => []
],
[
'$id' => 'clientVersion',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 256,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => []
],
[
'$id' => 'clientEngine',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 256,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => []
],
[
'$id' => 'clientEngineVersion',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 256,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => []
],
[
'$id' => 'deviceName',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 256,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => []
],
[
'$id' => 'deviceBrand',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 256,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => []
],
[
'$id' => 'deviceModel',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 256,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => []
],
],
'indexes' => [
// [
// '$id' => '_key_provider_providerUid',
// 'type' => Database::INDEX_KEY,
// 'attributes' => ['provider', 'providerUid'],
// 'lengths' => [100, 100],
// 'orders' => [Database::ORDER_ASC, Database::ORDER_ASC],
// ]
],
],
'teams' => [
'$collection' => Database::COLLECTIONS,
'$id' => 'teams',
@ -1058,6 +1306,7 @@ $collections = [
]
],
],
'certificates' => [
'$collection' => Database::COLLECTIONS,
'$id' => 'certificates',

View file

@ -192,8 +192,12 @@ App::post('/v1/account/sessions')
Authorization::setRole('user:'.$profile->getId());
$profile->setAttribute('sessions', $session, Document::SET_TYPE_APPEND);
$session = $dbForInternal->createDocument('sessions', $session
->setAttribute('$read', ['user:'.$profile->getId()])
->setAttribute('$write', ['user:'.$profile->getId()])
);
$profile->setAttribute('sessions', $session, Document::SET_TYPE_APPEND);
$profile = $dbForInternal->updateDocument('users', $profile->getId(), $profile);
$audits
@ -428,35 +432,33 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
$current = Auth::sessionVerify($sessions, Auth::$secret);
if($current) { // Delete current session of new one.
foreach ($sessions as $key => $session) {
foreach ($sessions as $key => $session) { /** @var Document $session */
if ($current === $session['$id']) {
unset($sessions[$key]);
$dbForInternal->deleteDocument('sessions', $session->getId());
$dbForInternal->updateDocument('users', $user->getId(), $user->setAttribute('sessions', $sessions));
}
}
}
$user = (empty($user->getId())) ? $dbForInternal->getCollectionFirst([ // Get user by provider id
'limit' => 1,
'filters' => [
'$collection='.Database::SYSTEM_COLLECTION_USERS,
'sessions.provider='.$provider,
'sessions.providerUid='.$oauth2ID
],
]) : $user;
$user = ($user->isEmpty()) ? $dbForInternal->findFirst('sessions', [ // Get user by provider id
new Query('provider', QUERY::TYPE_EQUAL, [$provider]),
new Query('providerUid', QUERY::TYPE_EQUAL, [$oauth2ID]),
], 1) : $user;
if (empty($user)) { // No user logged in or with OAuth2 provider ID, create new one or connect with account with same email
if ($user === false || $user->isEmpty()) { // No user logged in or with OAuth2 provider ID, create new one or connect with account with same email
$name = $oauth2->getUserName($accessToken);
$email = $oauth2->getUserEmail($accessToken);
$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
if ($user === false || $user->isEmpty()) { // Last option -> create the user, generate random password
$limit = $project->getAttribute('usersAuthLimit', 0);
if ($limit !== 0) {
$sum = $dbForInternal->count('users', [], APP_LIMIT_COUNT);
if($sum >= $limit) {
throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501);
}
@ -530,6 +532,11 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
Authorization::setRole('user:'.$user->getId());
$session = $dbForInternal->createDocument('sessions', $session
->setAttribute('$read', ['user:'.$user->getId()])
->setAttribute('$write', ['user:'.$user->getId()])
);
$user = $dbForInternal->updateDocument('users', $user->getId(), $user);
$audits
@ -668,6 +675,11 @@ App::post('/v1/account/sessions/anonymous')
Authorization::setRole('user:'.$user->getId());
$session = $dbForInternal->createDocument('sessions', $session
->setAttribute('$read', ['user:'.$user->getId()])
->setAttribute('$write', ['user:'.$user->getId()])
);
$user = $dbForInternal->updateDocument('users', $user->getId(),
$user->setAttribute('sessions', $session, Document::SET_TYPE_APPEND));
@ -814,9 +826,7 @@ App::get('/v1/account/sessions')
$countries = $locale->getText('countries');
$current = Auth::sessionVerify($sessions, Auth::$secret);
foreach ($sessions as $key => $session) {
/** @var Document $session */
foreach ($sessions as $key => $session) { /** @var Document $session */
$countryName = (isset($countries[strtoupper($session->getAttribute('countryCode'))]))
? $countries[strtoupper($session->getAttribute('countryCode'))]
: $locale->getText('locale.country.unknown');
@ -1214,12 +1224,12 @@ App::delete('/v1/account/sessions/:sessionId')
$sessions = $user->getAttribute('sessions', []);
foreach ($sessions as $key => $session) {
/** @var Document $session */
foreach ($sessions as $key => $session) { /** @var Document $session */
if ($sessionId == $session->getId()) {
unset($sessions[$key]);
$dbForInternal->deleteDocument('sessions', $session->getId());
$audits
->setParam('userId', $user->getId())
->setParam('event', 'account.sessions.delete')
@ -1290,8 +1300,8 @@ App::delete('/v1/account/sessions')
$protocol = $request->getProtocol();
$sessions = $user->getAttribute('sessions', []);
foreach ($sessions as $session) {
/** @var Document $session */
foreach ($sessions as $session) { /** @var Document $session */
$dbForInternal->deleteDocument('sessions', $session->getId());
$audits
->setParam('userId', $user->getId())
@ -1372,7 +1382,7 @@ App::post('/v1/account/recovery')
$profile = $dbForInternal->findFirst('users', [new Query('email', Query::TYPE_EQUAL, [$email])], 1); // Get user by email address
if (!$profile) {
throw new Exception('User not found', 404); // TODO maybe hide this
throw new Exception('User not found', 404);
}
if (false === $profile->getAttribute('status')) { // Account is blocked
@ -1485,7 +1495,7 @@ App::put('/v1/account/recovery')
$profile = $dbForInternal->getDocument('users', $userId);
if ($profile->isEmpty()) {
throw new Exception('User not found', 404); // TODO maybe hide this
throw new Exception('User not found', 404);
}
$tokens = $profile->getAttribute('tokens', []);
@ -1667,7 +1677,7 @@ App::put('/v1/account/verification')
$profile = $dbForInternal->getDocument('users', $userId);
if ($profile->isEmpty()) {
throw new Exception('User not found', 404); // TODO maybe hide this
throw new Exception('User not found', 404);
}
$tokens = $profile->getAttribute('tokens', []);

View file

@ -143,7 +143,6 @@ App::get('/v1/functions/:functionId/usage')
->action(function ($functionId, $range, $response, $project, $dbForInternal, $register) {
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Document $project */
/** @var Utopia\Database\Database $consoleDB */
/** @var Utopia\Database\Database $dbForInternal */
/** @var Utopia\Registry\Registry $register */

View file

@ -608,6 +608,8 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
// Log user in
Authorization::setRole('user:'.$user->getId());
$detector = new Detector($request->getUserAgent('UNKNOWN'));
$record = $geodb->get($request->getIP());
$expiry = \time() + Auth::TOKEN_EXPIRATION_LOGIN_LONG;
@ -624,6 +626,11 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
'countryCode' => ($record) ? \strtolower($record['country']['iso_code']) : '--',
], $detector->getOS(), $detector->getClient(), $detector->getDevice()));
$session = $dbForInternal->createDocument('sessions', $session
->setAttribute('$read', ['user:'.$user->getId()])
->setAttribute('$write', ['user:'.$user->getId()])
);
$user->setAttribute('sessions', $session, Document::SET_TYPE_APPEND);
Authorization::setRole('user:'.$userId);

View file

@ -430,12 +430,13 @@ App::delete('/v1/users/:userId/sessions/:sessionId')
$sessions = $user->getAttribute('sessions', []);
foreach ($sessions as $key => $session) {
/** @var Document $session */
foreach ($sessions as $key => $session) { /** @var Document $session */
if ($sessionId == $session->getId()) {
unset($sessions[$key]);
$dbForInternal->deleteDocument('sessions', $session->getId());
$user->setAttribute('sessions', $sessions);
$events
@ -476,13 +477,18 @@ App::delete('/v1/users/:userId/sessions')
throw new Exception('User not found', 404);
}
$sessions = $user->getAttribute('sessions', []);
foreach ($sessions as $key => $session) { /** @var Document $session */
$dbForInternal->deleteDocument('sessions', $session->getId());
}
$dbForInternal->updateDocument('users', $user->getId(), $user->getAttribute('sessions', []));
$events
->setParam('eventData', $response->output2($user, Response::MODEL_USER))
;
// TODO : Response filter implementation
$response->noContent();
});

View file

@ -57,7 +57,7 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons
$certificate = $dbForConsole->createDocument('certificates', $certificate);
Authorization2::enable();
Console::info('Issuing a TLS certificate for the master domain (' . $domain->get() . ') in a few seconds...'); // TODO move this to installation script
Console::info('Issuing a TLS certificate for the master domain (' . $domain->get() . ') in a few seconds...');
Resque::enqueue('v1-certificates', 'CertificatesV1', [
'document' => $certificate,
@ -374,10 +374,12 @@ App::error(function ($error, $utopia, $request, $response, $layout, $project) {
$comp = new View($template);
$comp
->setParam('development', App::isDevelopment())
->setParam('projectName', $project->getAttribute('name'))
->setParam('projectURL', $project->getAttribute('url'))
->setParam('message', $error->getMessage())
->setParam('code', $code)
->setParam('trace', $error->getTrace())
;
$layout

View file

@ -1,7 +1,9 @@
<?php
$development = $this->getParam('development', false);
$code = $this->getParam('code', 500);
$errorID = $this->getParam('errorID', 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');
$message = $this->getParam('message', '');
$trace = $this->getParam('trace', []);
$projectName = $this->getParam('projectName', '');
$projectURL = $this->getParam('projectURL', '');
?>
@ -18,4 +20,30 @@ $projectURL = $this->getParam('projectURL', '');
<p><a href="<?php echo $this->escape($projectURL); ?>" rel="noopener">Back to <?php echo $projectName; ?></a></p>
<?php endif; ?>
<?php if ($development): ?>
<div class="margin-top-xl">
<h2 class="margin-bottom-large">Error Trace</h2>
<?php foreach($trace as $log): ?>
<table class="margin-bottom-xl">
<?php foreach($log as $key => $value): ?>
<tr>
<td style="width: 120px"><?php echo $key; ?></td>
<td>
<?php if (is_array($value)): ?>
<?php var_dump($value); ?>
<?php else: ?>
<?php echo $value; ?>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</table>
<?php endforeach; ?>
</div>
<?php endif; ?>
</section>

View file

@ -123,7 +123,7 @@ Console::info(count($list)." functions listed in " . ($executionEnd - $execution
* 7. Trigger usage log - DONE
*/
//TODO aviod scheduled execution if delay is bigger than X offest
//TODO avoid scheduled execution if delay is bigger than X offest
class FunctionsV1 extends Worker
{

View file

@ -96,7 +96,7 @@ class Task extends Model
])
->addRule('status', [
'type' => self::TYPE_STRING,
'description' => 'Task status. Possible values: play, pause', // TODO - change to enabled disabled
'description' => 'Task status. Possible values: play, pause',
'default' => '',
'example' => 'enabled',
])

View file

@ -28,7 +28,7 @@ class Team extends Model
'default' => 0,
'example' => 1592981250,
])
->addRule('sum', [ // TODO change key name?
->addRule('sum', [
'type' => self::TYPE_INTEGER,
'description' => 'Total sum of team members.',
'default' => 0,

View file

@ -14,6 +14,9 @@ class AccountCustomClientTest extends Scope
use ProjectCustom;
use SideClient;
/**
* @depends testCreateAccountSession
*/
public function testCreateOAuth2AccountSession():array
{
$provider = 'mock';
@ -384,6 +387,17 @@ class AccountCustomClientTest extends Scope
/**
* Test for SUCCESS
*/
$response = $this->client->call(Client::METHOD_GET, '/account', array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
]));
$this->assertEquals($response['headers']['status-code'], 200);
$userId = $response['body']['$id'] ?? '';
$response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$this->getProject()['$id'].'/oauth2', array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
@ -406,6 +420,8 @@ class AccountCustomClientTest extends Scope
'success' => 'http://localhost/v1/mock/tests/general/oauth2/success',
'failure' => 'http://localhost/v1/mock/tests/general/oauth2/failure',
]);
$session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']];
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals('success', $response['body']['result']);
@ -418,6 +434,7 @@ class AccountCustomClientTest extends Scope
]));
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertEquals($response['body']['$id'], $userId);
$this->assertEquals($response['body']['name'], 'User Name');
$this->assertEquals($response['body']['email'], 'user@localhost.test');