1
0
Fork 0
mirror of synced 2024-06-13 00:04:47 +12:00

Init DB library

This commit is contained in:
Eldad Fux 2021-05-03 11:28:31 +03:00
parent 0aaf504549
commit 3739be31bb
10 changed files with 2158 additions and 314 deletions

2
.env
View file

@ -15,7 +15,7 @@ _APP_REDIS_PORT=6379
_APP_DB_HOST=mariadb
_APP_DB_PORT=3306
_APP_DB_SCHEMA=appwrite
_APP_DB_USER=user
_APP_DB_USER=root
_APP_DB_PASS=password
_APP_STORAGE_ANTIVIRUS=disabled
_APP_STORAGE_ANTIVIRUS_HOST=clamav

1581
app/config/collections2.php Normal file

File diff suppressed because it is too large Load diff

View file

@ -45,10 +45,14 @@ App::post('/v1/projects')
->inject('response')
->inject('consoleDB')
->inject('projectDB')
->action(function ($name, $teamId, $description, $logo, $url, $legalName, $legalCountry, $legalState, $legalCity, $legalAddress, $legalTaxId, $response, $consoleDB, $projectDB) {
->inject('dbForInternal')
->inject('dbForExternal')
->action(function ($name, $teamId, $description, $logo, $url, $legalName, $legalCountry, $legalState, $legalCity, $legalAddress, $legalTaxId, $response, $consoleDB, $projectDB, $dbForInternal, $dbForExternal) {
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Database $consoleDB */
/** @var Appwrite\Database\Database $projectDB */
/** @var Utopia\Database\Database $dbForInternal */
/** @var Utopia\Database\Database $dbForExternal */
$team = $projectDB->getDocument($teamId);
@ -88,6 +92,34 @@ App::post('/v1/projects')
$consoleDB->createNamespace($project->getId());
$collections = Config::getParam('collections2', []); /** @var array $collections */
$dbForInternal->setNamespace('project_internal_'.$project->getId());
$dbForInternal->create();
$dbForExternal->setNamespace('project_external_'.$project->getId());
$dbForExternal->create();
foreach ($collections as $key => $collection) {
$dbForInternal->createCollection($key);
foreach ($collection['attributes'] as $i => $attribute) {
$dbForInternal->createAttribute(
$key,
$attribute['$id'],
$attribute['type'],
$attribute['size'],
$attribute['required'],
$attribute['signed'],
$attribute['array'],
$attribute['filters'],
);
}
foreach ($collection['indexes'] as $i => $index) {
}
}
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($project, Response::MODEL_PROJECT)

View file

@ -10,8 +10,7 @@ use Utopia\Validator\HexColor;
use Utopia\Cache\Cache;
use Utopia\Cache\Adapter\Filesystem;
use Appwrite\ClamAV\Network;
use Appwrite\Database\Database;
use Appwrite\Database\Document;
use Utopia\Database\Document;
use Appwrite\Database\Validator\UID;
use Utopia\Storage\Storage;
use Utopia\Storage\Validator\File;
@ -42,14 +41,14 @@ App::post('/v1/storage/files')
->param('write', null, new ArrayList(new Text(64)), 'An array of strings with write permissions. By default only the current user is granted with write permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.', true)
->inject('request')
->inject('response')
->inject('projectDB')
->inject('dbForInternal')
->inject('user')
->inject('audits')
->inject('usage')
->action(function ($file, $read, $write, $request, $response, $projectDB, $user, $audits, $usage) {
->action(function ($file, $read, $write, $request, $response, $dbForInternal, $user, $audits, $usage) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
/** @var Utopia\Database\Database $dbForInternal */
/** @var Appwrite\Database\Document $user */
/** @var Appwrite\Event\Event $audits */
/** @var Appwrite\Event\Event $usage */
@ -121,14 +120,11 @@ App::post('/v1/storage/files')
$sizeActual = $device->getFileSize($path);
$file = $projectDB->createDocument([
'$collection' => Database::SYSTEM_COLLECTION_FILES,
'$permissions' => [
'read' => (is_null($read) && !$user->isEmpty()) ? ['user:'.$user->getId()] : $read ?? [], // By default set read permissions for user
'write' => (is_null($write) && !$user->isEmpty()) ? ['user:'.$user->getId()] : $write ?? [], // By default set write permissions for user
],
$file = $dbForInternal->createDocument('files', new Document([
'$read' => (is_null($read) && !$user->isEmpty()) ? ['user:'.$user->getId()] : $read ?? [], // By default set read permissions for user
'$write' => (is_null($write) && !$user->isEmpty()) ? ['user:'.$user->getId()] : $write ?? [], // By default set write permissions for user
'dateCreated' => \time(),
'folderId' => '',
'bucketId' => '',
'name' => $file['name'],
'path' => $path,
'signature' => $device->getFileHash($path),
@ -136,13 +132,12 @@ App::post('/v1/storage/files')
'sizeOriginal' => $size,
'sizeActual' => $sizeActual,
'algorithm' => $compressor->getName(),
'token' => \bin2hex(\random_bytes(64)),
'comment' => '',
'fileOpenSSLVersion' => '1',
'fileOpenSSLCipher' => OpenSSL::CIPHER_AES_128_GCM,
'fileOpenSSLTag' => \bin2hex($tag),
'fileOpenSSLIV' => \bin2hex($iv),
]);
'openSSLVersion' => '1',
'openSSLCipher' => OpenSSL::CIPHER_AES_128_GCM,
'openSSLTag' => \bin2hex($tag),
'openSSLIV' => \bin2hex($iv),
]));
if (false === $file) {
throw new Exception('Failed saving file to DB', 500);
@ -159,7 +154,7 @@ App::post('/v1/storage/files')
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($file, Response::MODEL_FILE)
->dynamic2($file, Response::MODEL_FILE)
;
});
@ -179,23 +174,15 @@ App::get('/v1/storage/files')
->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_FILES,
],
]);
$results = $dbForInternal->find('files', [], $limit, $offset);
$response->dynamic(new Document([
'sum' => $projectDB->getSum(),
$response->dynamic2(new Document([
'sum' => $limit,
'files' => $results
]), Response::MODEL_FILE_LIST);
});
@ -213,18 +200,18 @@ App::get('/v1/storage/files/:fileId')
->label('sdk.response.model', Response::MODEL_FILE)
->param('fileId', '', new UID(), 'File unique ID.')
->inject('response')
->inject('projectDB')
->action(function ($fileId, $response, $projectDB) {
->inject('dbForInternal')
->action(function ($fileId, $response, $dbForInternal) {
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
/** @var Utopia\Database\Database $dbForInternal */
$file = $projectDB->getDocument($fileId);
$file = $dbForInternal->getDocument('files', $fileId);
if (empty($file->getId()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
if (empty($file->getId())) {
throw new Exception('File not found', 404);
}
$response->dynamic($file, Response::MODEL_FILE);
$response->dynamic2($file, Response::MODEL_FILE);
});
App::get('/v1/storage/files/:fileId/preview')
@ -252,12 +239,12 @@ App::get('/v1/storage/files/:fileId/preview')
->inject('request')
->inject('response')
->inject('project')
->inject('projectDB')
->action(function ($fileId, $width, $height, $quality, $borderWidth, $borderColor, $borderRadius, $opacity, $rotation, $background, $output, $request, $response, $project, $projectDB) {
->inject('dbForInternal')
->action(function ($fileId, $width, $height, $quality, $borderWidth, $borderColor, $borderRadius, $opacity, $rotation, $background, $output, $request, $response, $project, $dbForInternal) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Document $project */
/** @var Appwrite\Database\Database $projectDB */
/** @var Utopia\Database\Document $project */
/** @var Utopia\Database\Database $dbForInternal */
$storage = 'files';
@ -280,16 +267,16 @@ App::get('/v1/storage/files/:fileId/preview')
$date = \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT'; // 45 days cache
$key = \md5($fileId.$width.$height.$quality.$borderWidth.$borderColor.$borderRadius.$opacity.$rotation.$background.$storage.$output);
$file = $projectDB->getDocument($fileId);
$file = $dbForInternal->getDocument('files', $fileId);
if (empty($file->getId()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
if (empty($file->getId())) {
throw new Exception('File not found', 404);
}
$path = $file->getAttribute('path');
$type = \strtolower(\pathinfo($path, PATHINFO_EXTENSION));
$algorithm = $file->getAttribute('algorithm');
$cipher = $file->getAttribute('fileOpenSSLCipher');
$cipher = $file->getAttribute('openSSLCipher');
$mime = $file->getAttribute('mimeType');
if (!\in_array($mime, $inputs)) {
@ -327,11 +314,11 @@ App::get('/v1/storage/files/:fileId/preview')
if (!empty($cipher)) { // Decrypt
$source = OpenSSL::decrypt(
$source,
$file->getAttribute('fileOpenSSLCipher'),
App::getEnv('_APP_OPENSSL_KEY_V'.$file->getAttribute('fileOpenSSLVersion')),
$file->getAttribute('openSSLCipher'),
App::getEnv('_APP_OPENSSL_KEY_V'.$file->getAttribute('openSSLVersion')),
0,
\hex2bin($file->getAttribute('fileOpenSSLIV')),
\hex2bin($file->getAttribute('fileOpenSSLTag'))
\hex2bin($file->getAttribute('openSSLIV')),
\hex2bin($file->getAttribute('openSSLTag'))
);
}
@ -393,14 +380,14 @@ App::get('/v1/storage/files/:fileId/download')
->label('sdk.methodType', 'location')
->param('fileId', '', new UID(), 'File unique ID.')
->inject('response')
->inject('projectDB')
->action(function ($fileId, $response, $projectDB) {
->inject('dbForInternal')
->action(function ($fileId, $response, $dbForInternal) {
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
/** @var Utopia\Database\Database $dbForInternal */
$file = $projectDB->getDocument($fileId);
$file = $dbForInternal->getDocument('files', $fileId);
if (empty($file->getId()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
if (empty($file->getId())) {
throw new Exception('File not found', 404);
}
@ -415,14 +402,14 @@ App::get('/v1/storage/files/:fileId/download')
$source = $device->read($path);
if (!empty($file->getAttribute('fileOpenSSLCipher'))) { // Decrypt
if (!empty($file->getAttribute('openSSLCipher'))) { // Decrypt
$source = OpenSSL::decrypt(
$source,
$file->getAttribute('fileOpenSSLCipher'),
App::getEnv('_APP_OPENSSL_KEY_V'.$file->getAttribute('fileOpenSSLVersion')),
$file->getAttribute('openSSLCipher'),
App::getEnv('_APP_OPENSSL_KEY_V'.$file->getAttribute('openSSLVersion')),
0,
\hex2bin($file->getAttribute('fileOpenSSLIV')),
\hex2bin($file->getAttribute('fileOpenSSLTag'))
\hex2bin($file->getAttribute('openSSLIV')),
\hex2bin($file->getAttribute('openSSLTag'))
);
}
@ -451,15 +438,15 @@ App::get('/v1/storage/files/:fileId/view')
->label('sdk.methodType', 'location')
->param('fileId', '', new UID(), 'File unique ID.')
->inject('response')
->inject('projectDB')
->inject('dbForInternal')
->action(function ($fileId, $response, $projectDB) {
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
/** @var Utopia\Database\Database $dbForInternal */
$file = $projectDB->getDocument($fileId);
$file = $projectDB->getDocument('files', $fileId);
$mimes = Config::getParam('storage-mimes');
if (empty($file->getId()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
if (empty($file->getId())) {
throw new Exception('File not found', 404);
}
@ -480,14 +467,14 @@ App::get('/v1/storage/files/:fileId/view')
$source = $device->read($path);
if (!empty($file->getAttribute('fileOpenSSLCipher'))) { // Decrypt
if (!empty($file->getAttribute('openSSLCipher'))) { // Decrypt
$source = OpenSSL::decrypt(
$source,
$file->getAttribute('fileOpenSSLCipher'),
App::getEnv('_APP_OPENSSL_KEY_V'.$file->getAttribute('fileOpenSSLVersion')),
$file->getAttribute('openSSLCipher'),
App::getEnv('_APP_OPENSSL_KEY_V'.$file->getAttribute('openSSLVersion')),
0,
\hex2bin($file->getAttribute('fileOpenSSLIV')),
\hex2bin($file->getAttribute('fileOpenSSLTag'))
\hex2bin($file->getAttribute('openSSLIV')),
\hex2bin($file->getAttribute('openSSLTag'))
);
}
@ -522,26 +509,24 @@ App::put('/v1/storage/files/:fileId')
->param('read', [], new ArrayList(new Text(64)), 'An array of strings with read permissions. By default no user is granted with any read permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->param('write', [], new ArrayList(new Text(64)), 'An array of strings with write permissions. By default no user is granted with any write permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->inject('response')
->inject('projectDB')
->inject('dbForInternal')
->inject('audits')
->action(function ($fileId, $read, $write, $response, $projectDB, $audits) {
->action(function ($fileId, $read, $write, $response, $dbForInternal, $audits) {
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
/** @var Utopia\Database\Database $dbForInternal */
/** @var Appwrite\Event\Event $audits */
$file = $projectDB->getDocument($fileId);
$file = $dbForInternal->getDocument('files', $fileId);
if (empty($file->getId()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
if (empty($file->getId())) {
throw new Exception('File not found', 404);
}
$file = $projectDB->updateDocument(\array_merge($file->getArrayCopy(), [
'$permissions' => [
'read' => $read,
'write' => $write,
],
'folderId' => '',
]));
$file = $dbForInternal->updateDocument('files', $fileId, new Document(\array_merge($file->getArrayCopy(), [
'$read' => $read,
'$write' => $write,
'bucketId' => '',
])));
if (false === $file) {
throw new Exception('Failed saving file to DB', 500);
@ -552,7 +537,7 @@ App::put('/v1/storage/files/:fileId')
->setParam('resource', 'storage/files/'.$file->getId())
;
$response->dynamic($file, Response::MODEL_FILE);
$response->dynamic2($file, Response::MODEL_FILE);
});
App::delete('/v1/storage/files/:fileId')
@ -568,27 +553,27 @@ App::delete('/v1/storage/files/:fileId')
->label('sdk.response.model', Response::MODEL_NONE)
->param('fileId', '', new UID(), 'File unique ID.')
->inject('response')
->inject('projectDB')
->inject('dbForInternal')
->inject('events')
->inject('audits')
->inject('usage')
->action(function ($fileId, $response, $projectDB, $events, $audits, $usage) {
->action(function ($fileId, $response, $dbForInternal, $events, $audits, $usage) {
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Database $projectDB */
/** @var Utopia\Database\Database $dbForInternal */
/** @var Appwrite\Event\Event $events */
/** @var Appwrite\Event\Event $audits */
/** @var Appwrite\Event\Event $usage */
$file = $projectDB->getDocument($fileId);
$file = $dbForInternal->getDocument('files', $fileId);
if (empty($file->getId()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
if (empty($file->getId())) {
throw new Exception('File not found', 404);
}
$device = Storage::getDevice('files');
if ($device->delete($file->getAttribute('path', ''))) {
if (!$projectDB->deleteDocument($fileId)) {
if (!$dbForInternal->deleteDocument('files', $fileId)) {
throw new Exception('Failed to remove file from DB', 500);
}
}
@ -603,59 +588,8 @@ App::delete('/v1/storage/files/:fileId')
;
$events
->setParam('eventData', $response->output($file, Response::MODEL_FILE))
->setParam('eventData', $response->output2($file, Response::MODEL_FILE))
;
$response->noContent();
});
// App::get('/v1/storage/files/:fileId/scan')
// ->desc('Scan Storage')
// ->groups(['api', 'storage'])
// ->label('scope', 'god')
// ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
// ->label('sdk.namespace', 'storage')
// ->label('sdk.method', 'getFileScan')
// ->label('sdk.hide', true)
// ->param('fileId', '', new UID(), 'File unique ID.')
// ->param('storage', 'files', new WhiteList(['files']);})
// ->action(
// function ($fileId, $storage) use ($response, $request, $projectDB) {
// $file = $projectDB->getDocument($fileId);
// if (empty($file->getId()) || Database::SYSTEM_COLLECTION_FILES != $file->getCollection()) {
// throw new Exception('File not found', 404);
// }
// $path = $file->getAttribute('path', '');
// if (!file_exists($path)) {
// throw new Exception('File not found in '.$path, 404);
// }
// $compressor = new GZIP();
// $device = Storage::getDevice($storage);
// $source = $device->read($path);
// if (!empty($file->getAttribute('fileOpenSSLCipher'))) { // Decrypt
// $source = OpenSSL::decrypt(
// $source,
// $file->getAttribute('fileOpenSSLCipher'),
// App::getEnv('_APP_OPENSSL_KEY_V'.$file->getAttribute('fileOpenSSLVersion')),
// 0,
// hex2bin($file->getAttribute('fileOpenSSLIV')),
// hex2bin($file->getAttribute('fileOpenSSLTag'))
// );
// }
// $source = $compressor->decompress($source);
// $antiVirus = new Network('clamav', 3310);
// //var_dump($antiVirus->ping());
// //var_dump($antiVirus->version());
// //var_dump($antiVirus->fileScan('/storage/uploads/app-1/5/9/f/e/59fecaed49645.pdf'));
// }
// );
});

View file

@ -18,6 +18,7 @@ use Utopia\Storage\Device\Local;
use Utopia\Storage\Storage;
use Appwrite\Utopia\Response\Filters\V06;
use Utopia\CLI\Console;
use Utopia\Database\Validator\Authorization as Authorization2;
Config::setParam('domainVerification', false);
Config::setParam('cookieDomain', 'localhost');
@ -189,21 +190,26 @@ App::init(function ($utopia, $request, $response, $console, $project, $user, $lo
$scopes = \array_merge($roles[$role]['scopes'], $key->getAttribute('scopes', []));
Authorization::setDefaultStatus(false); // Cancel security segmentation for API keys.
Authorization2::setDefaultStatus(false); // Cancel security segmentation for API keys.
}
}
if ($user->getId()) {
Authorization::setRole('user:'.$user->getId());
Authorization2::setRole('user:'.$user->getId());
}
Authorization::setRole('role:'.$role);
Authorization2::setRole('role:'.$role);
\array_map(function ($node) {
if (isset($node['teamId']) && isset($node['roles'])) {
Authorization::setRole('team:'.$node['teamId']);
Authorization2::setRole('team:'.$node['teamId']);
foreach ($node['roles'] as $nodeRole) { // Set all team roles
Authorization::setRole('team:'.$node['teamId'].'/'.$nodeRole);
Authorization2::setRole('team:'.$node['teamId'].'/'.$nodeRole);
}
}
}, $user->getAttribute('memberships', []));

View file

@ -12,6 +12,7 @@ use Swoole\Http\Request as SwooleRequest;
use Swoole\Http\Response as SwooleResponse;
use Utopia\App;
use Utopia\CLI\Console;
use Utopia\Database\Validator\Authorization as Authorization2;
// xdebug_start_trace('/tmp/trace');
@ -100,6 +101,9 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
Authorization::cleanRoles();
Authorization::setRole('*');
Authorization2::cleanRoles();
Authorization2::setRole('*');
$app->run($request, $response);
} catch (\Throwable $th) {
Console::error('[Error] Type: '.get_class($th));

View file

@ -30,6 +30,11 @@ use Utopia\Registry\Registry;
use MaxMind\Db\Reader;
use PHPMailer\PHPMailer\PHPMailer;
use PDO as PDONative;
use Utopia\Cache\Adapter\None;
use Utopia\Cache\Cache;
use Utopia\Database\Adapter\MariaDB;
use Utopia\Database\Database as DatabaseDatabase;
use Utopia\Database\Validator\Authorization as Authorization2;
const APP_NAME = 'Appwrite';
const APP_DOMAIN = 'appwrite.io';
@ -79,6 +84,7 @@ Config::load('auth', __DIR__.'/config/auth.php');
Config::load('providers', __DIR__.'/config/providers.php');
Config::load('platforms', __DIR__.'/config/platforms.php');
Config::load('collections', __DIR__.'/config/collections.php');
Config::load('collections2', __DIR__.'/config/collections2.php');
Config::load('runtimes', __DIR__.'/config/runtimes.php');
Config::load('roles', __DIR__.'/config/roles.php'); // User roles and scopes
Config::load('scopes', __DIR__.'/config/scopes.php'); // User roles and scopes
@ -388,6 +394,7 @@ App::setResource('user', function($mode, $project, $console, $request, $response
/** @var bool $mode */
Authorization::setDefaultStatus(true);
Authorization2::setDefaultStatus(true);
Auth::setCookieName('a_session_'.$project->getId());
@ -432,6 +439,7 @@ App::setResource('user', function($mode, $project, $console, $request, $response
if (APP_MODE_ADMIN === $mode) {
if (!empty($user->search('teamId', $project->getAttribute('teamId'), $user->getAttribute('memberships')))) {
Authorization::setDefaultStatus(false); // Cancel security segmentation for admin users.
Authorization2::setDefaultStatus(false); // Cancel security segmentation for admin users.
} else {
$user = new Document(['$id' => '', '$collection' => Database::SYSTEM_COLLECTION_USERS]);
}
@ -468,11 +476,13 @@ App::setResource('project', function($consoleDB, $request) {
/** @var Appwrite\Database\Database $consoleDB */
Authorization::disable();
Authorization2::disable();
$project = $consoleDB->getDocument($request->getParam('project',
$request->getHeader('x-appwrite-project', '')));
Authorization::reset();
Authorization2::reset();
return $project;
}, ['consoleDB', 'request']);
@ -499,6 +509,24 @@ App::setResource('projectDB', function($register, $project) {
return $projectDB;
}, ['register', 'project']);
App::setResource('dbForInternal', function($register, $project) {
$cache = new Cache(new None());
$database = new DatabaseDatabase(new MariaDB($register->get('db')), $cache);
$database->setNamespace('project_internal_'.$project->getId());
return $database;
}, ['register', 'project']);
App::setResource('dbForExternal', function($register, $project) {
$cache = new Cache(new None());
$database = new DatabaseDatabase(new MariaDB($register->get('db')), $cache);
$database->setNamespace('project_external_'.$project->getId());
return $database;
}, ['register', 'project']);
App::setResource('mode', function($request) {
/** @var Utopia\Swoole\Request $request */
return $request->getParam('mode', $request->getHeader('x-appwrite-mode', APP_MODE_DEFAULT));

View file

@ -42,9 +42,10 @@
"utopia-php/abuse": "0.4.*",
"utopia-php/analytics": "0.2.*",
"utopia-php/audit": "0.5.*",
"utopia-php/cache": "0.2.*",
"utopia-php/cache": "0.4.*",
"utopia-php/cli": "0.10.*",
"utopia-php/config": "0.2.*",
"utopia-php/database": "v0.x-dev",
"utopia-php/locale": "0.3.*",
"utopia-php/registry": "0.4.*",
"utopia-php/preloader": "0.2.*",
@ -71,6 +72,10 @@
{
"type": "git",
"url": "https://github.com/appwrite/sdk-generator"
},
{
"type": "git",
"url": "https://github.com/utopia-php/database"
}
],
"provide": {

520
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "32ceddda707fb8f625f84eec08dc3871",
"content-hash": "4c699b84f6d1e789c9a45788634a702d",
"packages": [
{
"name": "adhocore/jwt",
@ -353,6 +353,79 @@
},
"time": "2020-11-06T16:09:14+00:00"
},
{
"name": "composer/package-versions-deprecated",
"version": "1.11.99.1",
"source": {
"type": "git",
"url": "https://github.com/composer/package-versions-deprecated.git",
"reference": "7413f0b55a051e89485c5cb9f765fe24bb02a7b6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/7413f0b55a051e89485c5cb9f765fe24bb02a7b6",
"reference": "7413f0b55a051e89485c5cb9f765fe24bb02a7b6",
"shasum": ""
},
"require": {
"composer-plugin-api": "^1.1.0 || ^2.0",
"php": "^7 || ^8"
},
"replace": {
"ocramius/package-versions": "1.11.99"
},
"require-dev": {
"composer/composer": "^1.9.3 || ^2.0@dev",
"ext-zip": "^1.13",
"phpunit/phpunit": "^6.5 || ^7"
},
"type": "composer-plugin",
"extra": {
"class": "PackageVersions\\Installer",
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"PackageVersions\\": "src/PackageVersions"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Marco Pivetta",
"email": "ocramius@gmail.com"
},
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be"
}
],
"description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)",
"support": {
"issues": "https://github.com/composer/package-versions-deprecated/issues",
"source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.1"
},
"funding": [
{
"url": "https://packagist.com",
"type": "custom"
},
{
"url": "https://github.com/composer",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
"type": "tidelift"
}
],
"time": "2020-11-11T10:22:58+00:00"
},
{
"name": "dragonmantank/cron-expression",
"version": "v3.1.0",
@ -713,6 +786,61 @@
},
"time": "2020-12-26T17:45:17+00:00"
},
{
"name": "jean85/pretty-package-versions",
"version": "1.6.0",
"source": {
"type": "git",
"url": "https://github.com/Jean85/pretty-package-versions.git",
"reference": "1e0104b46f045868f11942aea058cd7186d6c303"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/1e0104b46f045868f11942aea058cd7186d6c303",
"reference": "1e0104b46f045868f11942aea058cd7186d6c303",
"shasum": ""
},
"require": {
"composer/package-versions-deprecated": "^1.8.0",
"php": "^7.0|^8.0"
},
"require-dev": {
"phpunit/phpunit": "^6.0|^8.5|^9.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Jean85\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Alessandro Lai",
"email": "alessandro.lai85@gmail.com"
}
],
"description": "A wrapper for ocramius/package-versions to get pretty versions strings",
"keywords": [
"composer",
"package",
"release",
"versions"
],
"support": {
"issues": "https://github.com/Jean85/pretty-package-versions/issues",
"source": "https://github.com/Jean85/pretty-package-versions/tree/1.6.0"
},
"time": "2021-02-04T16:20:16+00:00"
},
{
"name": "matomo/device-detector",
"version": "4.2.2",
@ -782,6 +910,74 @@
},
"time": "2021-02-26T07:31:42+00:00"
},
{
"name": "mongodb/mongodb",
"version": "1.8.0",
"source": {
"type": "git",
"url": "https://github.com/mongodb/mongo-php-library.git",
"reference": "953dbc19443aa9314c44b7217a16873347e6840d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mongodb/mongo-php-library/zipball/953dbc19443aa9314c44b7217a16873347e6840d",
"reference": "953dbc19443aa9314c44b7217a16873347e6840d",
"shasum": ""
},
"require": {
"ext-hash": "*",
"ext-json": "*",
"ext-mongodb": "^1.8.1",
"jean85/pretty-package-versions": "^1.2",
"php": "^7.0 || ^8.0",
"symfony/polyfill-php80": "^1.19"
},
"require-dev": {
"squizlabs/php_codesniffer": "^3.5, <3.5.5",
"symfony/phpunit-bridge": "5.x-dev"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.8.x-dev"
}
},
"autoload": {
"psr-4": {
"MongoDB\\": "src/"
},
"files": [
"src/functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Andreas Braun",
"email": "andreas.braun@mongodb.com"
},
{
"name": "Jeremy Mikola",
"email": "jmikola@gmail.com"
}
],
"description": "MongoDB driver library",
"homepage": "https://jira.mongodb.org/browse/PHPLIB",
"keywords": [
"database",
"driver",
"mongodb",
"persistence"
],
"support": {
"issues": "https://github.com/mongodb/mongo-php-library/issues",
"source": "https://github.com/mongodb/mongo-php-library/tree/1.8.0"
},
"time": "2020-11-25T12:26:02+00:00"
},
{
"name": "mustangostang/spyc",
"version": "0.6.3",
@ -1322,6 +1518,89 @@
],
"time": "2021-01-07T16:49:33+00:00"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.22.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dc3063ba22c2a1fd2f45ed856374d79114998f91",
"reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.22-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Php80\\": ""
},
"files": [
"bootstrap.php"
],
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ion Bazan",
"email": "ion.bazan@gmail.com"
},
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.22.1"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2021-01-07T16:49:33+00:00"
},
{
"name": "utopia-php/abuse",
"version": "0.4.0",
@ -1483,21 +1762,22 @@
},
{
"name": "utopia-php/cache",
"version": "0.2.3",
"version": "0.4.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/cache.git",
"reference": "a44b904127f88fa64673e402e5c0732ff6687d47"
"reference": "8c48eff73219c8c1ac2807909f0a38f3480c8938"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/cache/zipball/a44b904127f88fa64673e402e5c0732ff6687d47",
"reference": "a44b904127f88fa64673e402e5c0732ff6687d47",
"url": "https://api.github.com/repos/utopia-php/cache/zipball/8c48eff73219c8c1ac2807909f0a38f3480c8938",
"reference": "8c48eff73219c8c1ac2807909f0a38f3480c8938",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": ">=7.3"
"ext-redis": "*",
"php": ">=7.4"
},
"require-dev": {
"phpunit/phpunit": "^9.3",
@ -1529,9 +1809,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/cache/issues",
"source": "https://github.com/utopia-php/cache/tree/0.2.3"
"source": "https://github.com/utopia-php/cache/tree/0.4.1"
},
"time": "2020-10-24T10:11:01+00:00"
"time": "2021-04-29T18:41:43+00:00"
},
{
"name": "utopia-php/cli",
@ -1637,6 +1917,61 @@
},
"time": "2020-10-24T09:49:09+00:00"
},
{
"name": "utopia-php/database",
"version": "v0.x-dev",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/database",
"reference": "518265a14702f61a35b95d4ae25c8b23e7c2b478"
},
"require": {
"ext-mongodb": "*",
"ext-pdo": "*",
"ext-redis": "*",
"mongodb/mongodb": "1.8.0",
"php": ">=7.1",
"utopia-php/cache": "0.4.*",
"utopia-php/framework": "0.*.*"
},
"require-dev": {
"phpunit/phpunit": "^9.4",
"vimeo/psalm": "4.0.1"
},
"type": "library",
"autoload": {
"psr-4": {
"Utopia\\Database\\": "src/Database"
}
},
"autoload-dev": {
"psr-4": {
"Utopia\\Tests\\": "tests/Database"
}
},
"license": [
"MIT"
],
"authors": [
{
"name": "Eldad Fux",
"email": "eldad@appwrite.io"
},
{
"name": "Brandon Leckemby",
"email": "brandon@appwrite.io"
}
],
"description": "A simple library to manage application persistency using multiple database adapters",
"keywords": [
"database",
"framework",
"php",
"upf",
"utopia"
],
"time": "2021-05-02T18:26:42+00:00"
},
{
"name": "utopia-php/domains",
"version": "v1.1.0",
@ -2376,79 +2711,6 @@
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
"time": "2021-03-28T22:18:36+00:00"
},
{
"name": "composer/package-versions-deprecated",
"version": "1.11.99.1",
"source": {
"type": "git",
"url": "https://github.com/composer/package-versions-deprecated.git",
"reference": "7413f0b55a051e89485c5cb9f765fe24bb02a7b6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/7413f0b55a051e89485c5cb9f765fe24bb02a7b6",
"reference": "7413f0b55a051e89485c5cb9f765fe24bb02a7b6",
"shasum": ""
},
"require": {
"composer-plugin-api": "^1.1.0 || ^2.0",
"php": "^7 || ^8"
},
"replace": {
"ocramius/package-versions": "1.11.99"
},
"require-dev": {
"composer/composer": "^1.9.3 || ^2.0@dev",
"ext-zip": "^1.13",
"phpunit/phpunit": "^6.5 || ^7"
},
"type": "composer-plugin",
"extra": {
"class": "PackageVersions\\Installer",
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"PackageVersions\\": "src/PackageVersions"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Marco Pivetta",
"email": "ocramius@gmail.com"
},
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be"
}
],
"description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)",
"support": {
"issues": "https://github.com/composer/package-versions-deprecated/issues",
"source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.1"
},
"funding": [
{
"url": "https://packagist.com",
"type": "custom"
},
{
"url": "https://github.com/composer",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
"type": "tidelift"
}
],
"time": "2020-11-11T10:22:58+00:00"
},
{
"name": "composer/semver",
"version": "3.2.4",
@ -4973,16 +5235,16 @@
},
{
"name": "symfony/console",
"version": "v5.2.6",
"version": "v5.2.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "35f039df40a3b335ebf310f244cb242b3a83ac8d"
"reference": "90374b8ed059325b49a29b55b3f8bb4062c87629"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/35f039df40a3b335ebf310f244cb242b3a83ac8d",
"reference": "35f039df40a3b335ebf310f244cb242b3a83ac8d",
"url": "https://api.github.com/repos/symfony/console/zipball/90374b8ed059325b49a29b55b3f8bb4062c87629",
"reference": "90374b8ed059325b49a29b55b3f8bb4062c87629",
"shasum": ""
},
"require": {
@ -5050,7 +5312,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v5.2.6"
"source": "https://github.com/symfony/console/tree/v5.2.7"
},
"funding": [
{
@ -5066,7 +5328,7 @@
"type": "tidelift"
}
],
"time": "2021-03-28T09:42:18+00:00"
"time": "2021-04-19T14:07:32+00:00"
},
{
"name": "symfony/polyfill-intl-grapheme",
@ -5392,89 +5654,6 @@
],
"time": "2021-01-07T16:49:33+00:00"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.22.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dc3063ba22c2a1fd2f45ed856374d79114998f91",
"reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.22-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Php80\\": ""
},
"files": [
"bootstrap.php"
],
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ion Bazan",
"email": "ion.bazan@gmail.com"
},
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.22.1"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2021-01-07T16:49:33+00:00"
},
{
"name": "symfony/service-contracts",
"version": "v2.4.0",
@ -5925,6 +6104,7 @@
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {
"utopia-php/database": 20,
"appwrite/sdk-generator": 20
},
"prefer-stable": false,

View file

@ -43,6 +43,7 @@ use Appwrite\Utopia\Response\Model\Webhook;
use Appwrite\Utopia\Response\Model\Preferences;
use Appwrite\Utopia\Response\Model\Mock; // Keep last
use stdClass;
use Utopia\Database\Document as DatabaseDocument;
/**
* @method public function setStatusCode(int $code = 200): Response
@ -275,6 +276,27 @@ class Response extends SwooleResponse
$this->json(!empty($output) ? $output : new stdClass());
}
/**
* Validate response objects and outputs
* the response according to given format type
*
* @param DatabaseDocument $document
* @param string $model
*
* return void
*/
public function dynamic2(DatabaseDocument $document, string $model): void
{
$output = $this->output2($document, $model);
// If filter is set, parse the output
if(self::isFilter()){
$output = self::getFilter()->parse($output, $model);
}
$this->json(!empty($output) ? $output : new stdClass());
}
/**
* Generate valid response object from document data
*
@ -327,6 +349,58 @@ class Response extends SwooleResponse
return $this->payload;
}
/**
* Generate valid response object from document data
*
* @param DatabaseDocument $document
* @param string $model
*
* return array
*/
public function output2(DatabaseDocument $document, string $model): array
{
$data = $document;
$model = $this->getModel($model);
$output = [];
if ($model->isAny()) {
$this->payload = $document->getArrayCopy();
return $this->payload;
}
foreach ($model->getRules() as $key => $rule) {
if (!$document->isSet($key)) {
if (!is_null($rule['default'])) {
$document->setAttribute($key, $rule['default']);
} else {
throw new Exception('Model '.$model->getName().' is missing response key: '.$key);
}
}
if ($rule['array']) {
if (!is_array($data[$key])) {
throw new Exception($key.' must be an array of type '.$rule['type']);
}
foreach ($data[$key] as &$item) {
if ($item instanceof Document) {
if (!array_key_exists($rule['type'], $this->models)) {
throw new Exception('Missing model for rule: '. $rule['type']);
}
$item = $this->output($item, $rule['type']);
}
}
}
$output[$key] = $data[$key];
}
$this->payload = $output;
return $this->payload;
}
/**
* YAML
*