mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Merge branch 'feat-database-indexing' into feat-storage-buckets
This commit is contained in:
@@ -18,7 +18,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
|
||||
|
||||
+2
-1
@@ -34,8 +34,9 @@ install:
|
||||
- sleep 10
|
||||
|
||||
script:
|
||||
- docker ps
|
||||
- docker ps -a
|
||||
- docker-compose logs appwrite
|
||||
- docker-compose logs mariadb
|
||||
- docker-compose logs appwrite-worker-functions
|
||||
- docker-compose exec appwrite doctor
|
||||
- docker-compose exec appwrite vars
|
||||
|
||||
+10
@@ -15,6 +15,7 @@ RUN composer update --ignore-platform-reqs --optimize-autoloader \
|
||||
FROM php:8.0-cli-alpine as step1
|
||||
|
||||
ENV PHP_REDIS_VERSION=5.3.4 \
|
||||
PHP_MONGODB_VERSION=1.9.1 \
|
||||
PHP_SWOOLE_VERSION=v4.6.6 \
|
||||
PHP_IMAGICK_VERSION=master \
|
||||
PHP_YAML_VERSION=2.2.1 \
|
||||
@@ -45,6 +46,14 @@ RUN \
|
||||
./configure && \
|
||||
make && make install && \
|
||||
cd .. && \
|
||||
# Mongodb Extension
|
||||
git clone --depth 1 --branch $PHP_MONGODB_VERSION https://github.com/mongodb/mongo-php-driver.git && \
|
||||
cd mongo-php-driver && \
|
||||
git submodule update --init && \
|
||||
phpize && \
|
||||
./configure && \
|
||||
make && make install && \
|
||||
cd .. && \
|
||||
## Swoole Extension
|
||||
git clone --depth 1 --branch $PHP_SWOOLE_VERSION https://github.com/swoole/swoole-src.git && \
|
||||
cd swoole-src && \
|
||||
@@ -165,6 +174,7 @@ WORKDIR /usr/src/code
|
||||
COPY --from=step0 /usr/local/src/vendor /usr/src/code/vendor
|
||||
COPY --from=step1 /usr/local/lib/php/extensions/no-debug-non-zts-20200930/swoole.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/
|
||||
COPY --from=step1 /usr/local/lib/php/extensions/no-debug-non-zts-20200930/redis.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/
|
||||
COPY --from=step1 /usr/local/lib/php/extensions/no-debug-non-zts-20200930/mongodb.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/
|
||||
COPY --from=step1 /usr/local/lib/php/extensions/no-debug-non-zts-20200930/imagick.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/
|
||||
COPY --from=step1 /usr/local/lib/php/extensions/no-debug-non-zts-20200930/yaml.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/
|
||||
COPY --from=step1 /usr/local/lib/php/extensions/no-debug-non-zts-20200930/maxminddb.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/
|
||||
|
||||
+20
-20
@@ -11,7 +11,7 @@ $collections = [
|
||||
'console' => [
|
||||
'$id' => 'console',
|
||||
'$collection' => 'projects',
|
||||
'$permissions' => ['read' => ['*']],
|
||||
'$permissions' => ['read' => ['role:all']],
|
||||
'name' => 'Appwrite',
|
||||
'description' => 'Appwrite core engine',
|
||||
'logo' => '',
|
||||
@@ -51,7 +51,7 @@ $collections = [
|
||||
Database::SYSTEM_COLLECTION_COLLECTIONS => [
|
||||
'$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS,
|
||||
'$id' => Database::SYSTEM_COLLECTION_COLLECTIONS,
|
||||
'$permissions' => ['read' => ['*']],
|
||||
'$permissions' => ['read' => ['role:all']],
|
||||
'name' => 'Collections',
|
||||
'structure' => true,
|
||||
'rules' => [
|
||||
@@ -106,7 +106,7 @@ $collections = [
|
||||
Database::SYSTEM_COLLECTION_RULES => [
|
||||
'$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS,
|
||||
'$id' => Database::SYSTEM_COLLECTION_RULES,
|
||||
'$permissions' => ['read' => ['*']],
|
||||
'$permissions' => ['read' => ['role:all']],
|
||||
'name' => 'Collections Rule',
|
||||
'structure' => true,
|
||||
'rules' => [
|
||||
@@ -186,7 +186,7 @@ $collections = [
|
||||
Database::SYSTEM_COLLECTION_USERS => [
|
||||
'$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS,
|
||||
'$id' => Database::SYSTEM_COLLECTION_USERS,
|
||||
'$permissions' => ['read' => ['*']],
|
||||
'$permissions' => ['read' => ['role:all']],
|
||||
'name' => 'User',
|
||||
'structure' => true,
|
||||
'rules' => [
|
||||
@@ -307,7 +307,7 @@ $collections = [
|
||||
Database::SYSTEM_COLLECTION_SESSIONS => [
|
||||
'$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS,
|
||||
'$id' => Database::SYSTEM_COLLECTION_SESSIONS,
|
||||
'$permissions' => ['read' => ['*']],
|
||||
'$permissions' => ['read' => ['role:all']],
|
||||
'name' => 'Session',
|
||||
'structure' => true,
|
||||
'rules' => [
|
||||
@@ -505,7 +505,7 @@ $collections = [
|
||||
Database::SYSTEM_COLLECTION_TOKENS => [
|
||||
'$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS,
|
||||
'$id' => Database::SYSTEM_COLLECTION_TOKENS,
|
||||
'$permissions' => ['read' => ['*']],
|
||||
'$permissions' => ['read' => ['role:all']],
|
||||
'name' => 'Token',
|
||||
'structure' => true,
|
||||
'rules' => [
|
||||
@@ -568,7 +568,7 @@ $collections = [
|
||||
Database::SYSTEM_COLLECTION_MEMBERSHIPS => [
|
||||
'$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS,
|
||||
'$id' => Database::SYSTEM_COLLECTION_MEMBERSHIPS,
|
||||
'$permissions' => ['read' => ['*']],
|
||||
'$permissions' => ['read' => ['role:all']],
|
||||
'name' => 'Membership',
|
||||
'structure' => true,
|
||||
'rules' => [
|
||||
@@ -640,7 +640,7 @@ $collections = [
|
||||
Database::SYSTEM_COLLECTION_TEAMS => [
|
||||
'$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS,
|
||||
'$id' => Database::SYSTEM_COLLECTION_TEAMS,
|
||||
'$permissions' => ['read' => ['*']],
|
||||
'$permissions' => ['read' => ['role:all']],
|
||||
'name' => 'Team',
|
||||
'structure' => true,
|
||||
'rules' => [
|
||||
@@ -676,7 +676,7 @@ $collections = [
|
||||
Database::SYSTEM_COLLECTION_PROJECTS => [
|
||||
'$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS,
|
||||
'$id' => Database::SYSTEM_COLLECTION_PROJECTS,
|
||||
'$permissions' => ['read' => ['*']],
|
||||
'$permissions' => ['read' => ['role:all']],
|
||||
'name' => 'Project',
|
||||
'structure' => true,
|
||||
'rules' => [
|
||||
@@ -834,7 +834,7 @@ $collections = [
|
||||
Database::SYSTEM_COLLECTION_WEBHOOKS => [
|
||||
'$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS,
|
||||
'$id' => Database::SYSTEM_COLLECTION_WEBHOOKS,
|
||||
'$permissions' => ['read' => ['*']],
|
||||
'$permissions' => ['read' => ['role:all']],
|
||||
'name' => 'Webhook',
|
||||
'structure' => true,
|
||||
'rules' => [
|
||||
@@ -898,7 +898,7 @@ $collections = [
|
||||
Database::SYSTEM_COLLECTION_KEYS => [
|
||||
'$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS,
|
||||
'$id' => Database::SYSTEM_COLLECTION_KEYS,
|
||||
'$permissions' => ['read' => ['*']],
|
||||
'$permissions' => ['read' => ['role:all']],
|
||||
'name' => 'Key',
|
||||
'structure' => true,
|
||||
'rules' => [
|
||||
@@ -934,7 +934,7 @@ $collections = [
|
||||
Database::SYSTEM_COLLECTION_TASKS => [
|
||||
'$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS,
|
||||
'$id' => Database::SYSTEM_COLLECTION_TASKS,
|
||||
'$permissions' => ['read' => ['*']],
|
||||
'$permissions' => ['read' => ['role:all']],
|
||||
'name' => 'Task',
|
||||
'structure' => true,
|
||||
'rules' => [
|
||||
@@ -1088,7 +1088,7 @@ $collections = [
|
||||
Database::SYSTEM_COLLECTION_PLATFORMS => [
|
||||
'$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS,
|
||||
'$id' => Database::SYSTEM_COLLECTION_PLATFORMS,
|
||||
'$permissions' => ['read' => ['*']],
|
||||
'$permissions' => ['read' => ['role:all']],
|
||||
'name' => 'Platform',
|
||||
'structure' => true,
|
||||
'rules' => [
|
||||
@@ -1160,7 +1160,7 @@ $collections = [
|
||||
Database::SYSTEM_COLLECTION_DOMAINS => [
|
||||
'$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS,
|
||||
'$id' => Database::SYSTEM_COLLECTION_DOMAINS,
|
||||
'$permissions' => ['read' => ['*']],
|
||||
'$permissions' => ['read' => ['role:all']],
|
||||
'name' => 'Domains',
|
||||
'structure' => true,
|
||||
'rules' => [
|
||||
@@ -1223,7 +1223,7 @@ $collections = [
|
||||
Database::SYSTEM_COLLECTION_CERTIFICATES => [
|
||||
'$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS,
|
||||
'$id' => Database::SYSTEM_COLLECTION_CERTIFICATES,
|
||||
'$permissions' => ['read' => ['*']],
|
||||
'$permissions' => ['read' => ['role:all']],
|
||||
'name' => 'Certificates',
|
||||
'structure' => true,
|
||||
'rules' => [
|
||||
@@ -1295,7 +1295,7 @@ $collections = [
|
||||
Database::SYSTEM_COLLECTION_FILES => [
|
||||
'$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS,
|
||||
'$id' => Database::SYSTEM_COLLECTION_FILES,
|
||||
'$permissions' => ['read' => ['*']],
|
||||
'$permissions' => ['read' => ['role:all']],
|
||||
'name' => 'File',
|
||||
'structure' => true,
|
||||
'rules' => [
|
||||
@@ -1530,7 +1530,7 @@ $collections = [
|
||||
Database::SYSTEM_COLLECTION_FUNCTIONS => [
|
||||
'$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS,
|
||||
'$id' => Database::SYSTEM_COLLECTION_FUNCTIONS,
|
||||
'$permissions' => ['read' => ['*']],
|
||||
'$permissions' => ['read' => ['role:all']],
|
||||
'name' => 'Functions',
|
||||
'structure' => true,
|
||||
'rules' => [
|
||||
@@ -1648,7 +1648,7 @@ $collections = [
|
||||
Database::SYSTEM_COLLECTION_TAGS => [
|
||||
'$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS,
|
||||
'$id' => Database::SYSTEM_COLLECTION_TAGS,
|
||||
'$permissions' => ['read' => ['*']],
|
||||
'$permissions' => ['read' => ['role:all']],
|
||||
'name' => 'Tags',
|
||||
'structure' => true,
|
||||
'rules' => [
|
||||
@@ -1702,7 +1702,7 @@ $collections = [
|
||||
Database::SYSTEM_COLLECTION_EXECUTIONS => [
|
||||
'$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS,
|
||||
'$id' => Database::SYSTEM_COLLECTION_EXECUTIONS,
|
||||
'$permissions' => ['read' => ['*']],
|
||||
'$permissions' => ['read' => ['role:all']],
|
||||
'name' => 'Executions',
|
||||
'structure' => true,
|
||||
'rules' => [
|
||||
@@ -1792,7 +1792,7 @@ $collections = [
|
||||
Database::SYSTEM_COLLECTION_RESERVED => [
|
||||
'$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS,
|
||||
'$id' => Database::SYSTEM_COLLECTION_RESERVED,
|
||||
'$permissions' => ['read' => ['*']],
|
||||
'$permissions' => ['read' => ['role:all']],
|
||||
'name' => 'Reserved',
|
||||
'structure' => true,
|
||||
],
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+252
-398
File diff suppressed because it is too large
Load Diff
@@ -85,10 +85,8 @@ App::post('/v1/database/collections')
|
||||
->setParam('data', $data->getArrayCopy())
|
||||
;
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($data, Response::MODEL_COLLECTION)
|
||||
;
|
||||
$response->setStatusCode(Response::STATUS_CODE_CREATED);
|
||||
$response->dynamic($data, Response::MODEL_COLLECTION);
|
||||
});
|
||||
|
||||
App::get('/v1/database/collections')
|
||||
@@ -123,8 +121,8 @@ App::get('/v1/database/collections')
|
||||
]);
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'collections' => $results,
|
||||
'sum' => $projectDB->getSum(),
|
||||
'collections' => $results
|
||||
]), Response::MODEL_COLLECTION_LIST);
|
||||
});
|
||||
|
||||
@@ -399,10 +397,8 @@ App::post('/v1/database/collections/:collectionId/documents')
|
||||
->setParam('data', $data->getArrayCopy())
|
||||
;
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($data, Response::MODEL_DOCUMENT)
|
||||
;
|
||||
$response->setStatusCode(Response::STATUS_CODE_CREATED);
|
||||
$response->dynamic($data, Response::MODEL_DOCUMENT);
|
||||
});
|
||||
|
||||
App::get('/v1/database/collections/:collectionId/documents')
|
||||
|
||||
+146
-204
@@ -2,9 +2,6 @@
|
||||
|
||||
use Ahc\Jwt\JWT;
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Database\Database;
|
||||
use Appwrite\Database\Document;
|
||||
use Appwrite\Database\Validator\Authorization;
|
||||
use Appwrite\Database\Validator\UID;
|
||||
use Utopia\Storage\Storage;
|
||||
use Utopia\Storage\Validator\File;
|
||||
@@ -14,6 +11,11 @@ use Utopia\Storage\Validator\Upload;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Task\Validator\Cron;
|
||||
use Utopia\App;
|
||||
use Utopia\Exception;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Assoc;
|
||||
use Utopia\Validator\Text;
|
||||
@@ -21,7 +23,6 @@ use Utopia\Validator\Range;
|
||||
use Utopia\Validator\WhiteList;
|
||||
use Utopia\Config\Config;
|
||||
use Cron\CronExpression;
|
||||
use Utopia\Exception;
|
||||
|
||||
include_once __DIR__ . '/../shared/api.php';
|
||||
|
||||
@@ -45,16 +46,13 @@ App::post('/v1/functions')
|
||||
->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true)
|
||||
->param('timeout', 15, new Range(1, 900), 'Function maximum execution time in seconds.', true)
|
||||
->inject('response')
|
||||
->inject('projectDB')
|
||||
->action(function ($name, $execute, $env, $vars, $events, $schedule, $timeout, $response, $projectDB) {
|
||||
->inject('dbForInternal')
|
||||
->action(function ($name, $execute, $env, $vars, $events, $schedule, $timeout, $response, $dbForInternal) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Appwrite\Database\Database $projectDB */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
|
||||
$function = $projectDB->createDocument([
|
||||
'$collection' => Database::SYSTEM_COLLECTION_FUNCTIONS,
|
||||
'$permissions' => [
|
||||
'execute' => $execute,
|
||||
],
|
||||
$function = $dbForInternal->createDocument('functions', new Document([
|
||||
'execute' => $execute,
|
||||
'dateCreated' => time(),
|
||||
'dateUpdated' => time(),
|
||||
'status' => 'disabled',
|
||||
@@ -64,19 +62,13 @@ App::post('/v1/functions')
|
||||
'vars' => $vars,
|
||||
'events' => $events,
|
||||
'schedule' => $schedule,
|
||||
'schedulePrevious' => null,
|
||||
'scheduleNext' => null,
|
||||
'schedulePrevious' => 0,
|
||||
'scheduleNext' => 0,
|
||||
'timeout' => $timeout,
|
||||
]);
|
||||
]));
|
||||
|
||||
if (false === $function) {
|
||||
throw new Exception('Failed saving function to DB', 500);
|
||||
}
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($function, Response::MODEL_FUNCTION)
|
||||
;
|
||||
$response->setStatusCode(Response::STATUS_CODE_CREATED);
|
||||
$response->dynamic2($function, Response::MODEL_FUNCTION);
|
||||
});
|
||||
|
||||
App::get('/v1/functions')
|
||||
@@ -95,24 +87,16 @@ App::get('/v1/functions')
|
||||
->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_FUNCTIONS,
|
||||
],
|
||||
]);
|
||||
$queries = ($search) ? [new Query('name', Query::TYPE_SEARCH, [$search])] : [];
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'sum' => $projectDB->getSum(),
|
||||
'functions' => $results
|
||||
$response->dynamic2(new Document([
|
||||
'functions' => $dbForInternal->find('functions', $queries, $limit, $offset, ['_id'], [$orderType]),
|
||||
'sum' => $dbForInternal->count('functions', $queries, APP_LIMIT_COUNT),
|
||||
]), Response::MODEL_FUNCTION_LIST);
|
||||
});
|
||||
|
||||
@@ -129,18 +113,18 @@ App::get('/v1/functions/:functionId')
|
||||
->label('sdk.response.model', Response::MODEL_FUNCTION)
|
||||
->param('functionId', '', new UID(), 'Function unique ID.')
|
||||
->inject('response')
|
||||
->inject('projectDB')
|
||||
->action(function ($functionId, $response, $projectDB) {
|
||||
->inject('dbForInternal')
|
||||
->action(function ($functionId, $response, $dbForInternal) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Appwrite\Database\Database $projectDB */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
|
||||
$function = $projectDB->getDocument($functionId);
|
||||
$function = $dbForInternal->getDocument('functions', $functionId);
|
||||
|
||||
if (empty($function->getId()) || Database::SYSTEM_COLLECTION_FUNCTIONS != $function->getCollection()) {
|
||||
if (empty($function->getId())) {
|
||||
throw new Exception('Function not found', 404);
|
||||
}
|
||||
|
||||
$response->dynamic($function, Response::MODEL_FUNCTION);
|
||||
$response->dynamic2($function, Response::MODEL_FUNCTION);
|
||||
});
|
||||
|
||||
App::get('/v1/functions/:functionId/usage')
|
||||
@@ -154,18 +138,18 @@ App::get('/v1/functions/:functionId/usage')
|
||||
->param('range', '30d', new WhiteList(['24h', '7d', '30d', '90d']), 'Date range.', true)
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
->inject('projectDB')
|
||||
->inject('dbForInternal')
|
||||
->inject('register')
|
||||
->action(function ($functionId, $range, $response, $project, $projectDB, $register) {
|
||||
->action(function ($functionId, $range, $response, $project, $dbForInternal, $register) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Appwrite\Database\Document $project */
|
||||
/** @var Appwrite\Database\Database $consoleDB */
|
||||
/** @var Appwrite\Database\Database $projectDB */
|
||||
/** @var Utopia\Database\Database $consoleDB */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Utopia\Registry\Registry $register */
|
||||
|
||||
$function = $projectDB->getDocument($functionId);
|
||||
$function = $dbForInternal->getDocument('functions', $functionId);
|
||||
|
||||
if (empty($function->getId()) || Database::SYSTEM_COLLECTION_FUNCTIONS != $function->getCollection()) {
|
||||
if (empty($function->getId())) {
|
||||
throw new Exception('Function not found', 404);
|
||||
}
|
||||
|
||||
@@ -284,39 +268,33 @@ App::put('/v1/functions/:functionId')
|
||||
->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true)
|
||||
->param('timeout', 15, new Range(1, 900), 'Function maximum execution time in seconds.', true)
|
||||
->inject('response')
|
||||
->inject('projectDB')
|
||||
->inject('dbForInternal')
|
||||
->inject('project')
|
||||
->action(function ($functionId, $name, $execute, $vars, $events, $schedule, $timeout, $response, $projectDB, $project) {
|
||||
->action(function ($functionId, $name, $execute, $vars, $events, $schedule, $timeout, $response, $dbForInternal, $project) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Appwrite\Database\Database $projectDB */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Database\Document $project */
|
||||
|
||||
$function = $projectDB->getDocument($functionId);
|
||||
$function = $dbForInternal->getDocument('functions', $functionId);
|
||||
|
||||
if (empty($function->getId()) || Database::SYSTEM_COLLECTION_FUNCTIONS != $function->getCollection()) {
|
||||
if (empty($function->getId())) {
|
||||
throw new Exception('Function not found', 404);
|
||||
}
|
||||
|
||||
$original = $function->getAttribute('schedule', '');
|
||||
$cron = (!empty($function->getAttribute('tag', null)) && !empty($schedule)) ? new CronExpression($schedule) : null;
|
||||
$next = (!empty($function->getAttribute('tag', null)) && !empty($schedule)) ? $cron->getNextRunDate()->format('U') : null;
|
||||
$next = (!empty($function->getAttribute('tag', null)) && !empty($schedule)) ? $cron->getNextRunDate()->format('U') : 0;
|
||||
|
||||
$function = $projectDB->updateDocument(array_merge($function->getArrayCopy(), [
|
||||
'$permissions' => [
|
||||
'execute' => $execute,
|
||||
],
|
||||
$function = $dbForInternal->updateDocument('functions', $function->getId(), new Document(array_merge($function->getArrayCopy(), [
|
||||
'execute' => $execute,
|
||||
'dateUpdated' => time(),
|
||||
'name' => $name,
|
||||
'vars' => $vars,
|
||||
'events' => $events,
|
||||
'schedule' => $schedule,
|
||||
'scheduleNext' => $next,
|
||||
'scheduleNext' => (int)$next,
|
||||
'timeout' => $timeout,
|
||||
]));
|
||||
|
||||
if (false === $function) {
|
||||
throw new Exception('Failed saving function to DB', 500);
|
||||
}
|
||||
])));
|
||||
|
||||
if ($next && $schedule !== $original) {
|
||||
ResqueScheduler::enqueueAt($next, 'v1-functions', 'FunctionsV1', [
|
||||
@@ -328,7 +306,7 @@ App::put('/v1/functions/:functionId')
|
||||
]); // Async task rescheduale
|
||||
}
|
||||
|
||||
$response->dynamic($function, Response::MODEL_FUNCTION);
|
||||
$response->dynamic2($function, Response::MODEL_FUNCTION);
|
||||
});
|
||||
|
||||
App::patch('/v1/functions/:functionId/tag')
|
||||
@@ -346,32 +324,32 @@ App::patch('/v1/functions/:functionId/tag')
|
||||
->param('functionId', '', new UID(), 'Function unique ID.')
|
||||
->param('tag', '', new UID(), 'Tag unique ID.')
|
||||
->inject('response')
|
||||
->inject('projectDB')
|
||||
->inject('dbForInternal')
|
||||
->inject('project')
|
||||
->action(function ($functionId, $tag, $response, $projectDB, $project) {
|
||||
->action(function ($functionId, $tag, $response, $dbForInternal, $project) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Appwrite\Database\Database $projectDB */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Database\Document $project */
|
||||
|
||||
$function = $projectDB->getDocument($functionId);
|
||||
$tag = $projectDB->getDocument($tag);
|
||||
$function = $dbForInternal->getDocument('functions', $functionId);
|
||||
$tag = $dbForInternal->getDocument('tags', $tag);
|
||||
|
||||
if (empty($function->getId()) || Database::SYSTEM_COLLECTION_FUNCTIONS != $function->getCollection()) {
|
||||
if (empty($function->getId())) {
|
||||
throw new Exception('Function not found', 404);
|
||||
}
|
||||
|
||||
if (empty($tag->getId()) || Database::SYSTEM_COLLECTION_TAGS != $tag->getCollection()) {
|
||||
if (empty($tag->getId())) {
|
||||
throw new Exception('Tag not found', 404);
|
||||
}
|
||||
|
||||
$schedule = $function->getAttribute('schedule', '');
|
||||
$cron = (empty($function->getAttribute('tag')) && !empty($schedule)) ? new CronExpression($schedule) : null;
|
||||
$next = (empty($function->getAttribute('tag')) && !empty($schedule)) ? $cron->getNextRunDate()->format('U') : null;
|
||||
$next = (empty($function->getAttribute('tag')) && !empty($schedule)) ? $cron->getNextRunDate()->format('U') : 0;
|
||||
|
||||
$function = $projectDB->updateDocument(array_merge($function->getArrayCopy(), [
|
||||
$function = $dbForInternal->updateDocument('functions', $function->getId(), new Document(array_merge($function->getArrayCopy(), [
|
||||
'tag' => $tag->getId(),
|
||||
'scheduleNext' => $next,
|
||||
]));
|
||||
'scheduleNext' => (int)$next,
|
||||
])));
|
||||
|
||||
if ($next) { // Init first schedule
|
||||
ResqueScheduler::enqueueAt($next, 'v1-functions', 'FunctionsV1', [
|
||||
@@ -383,11 +361,7 @@ App::patch('/v1/functions/:functionId/tag')
|
||||
]); // Async task rescheduale
|
||||
}
|
||||
|
||||
if (false === $function) {
|
||||
throw new Exception('Failed saving function to DB', 500);
|
||||
}
|
||||
|
||||
$response->dynamic($function, Response::MODEL_FUNCTION);
|
||||
$response->dynamic2($function, Response::MODEL_FUNCTION);
|
||||
});
|
||||
|
||||
App::delete('/v1/functions/:functionId')
|
||||
@@ -403,26 +377,26 @@ App::delete('/v1/functions/:functionId')
|
||||
->label('sdk.response.model', Response::MODEL_NONE)
|
||||
->param('functionId', '', new UID(), 'Function unique ID.')
|
||||
->inject('response')
|
||||
->inject('projectDB')
|
||||
->inject('dbForInternal')
|
||||
->inject('deletes')
|
||||
->action(function ($functionId, $response, $projectDB, $deletes) {
|
||||
->action(function ($functionId, $response, $dbForInternal, $deletes) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Appwrite\Database\Database $projectDB */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Event\Event $deletes */
|
||||
|
||||
$function = $projectDB->getDocument($functionId);
|
||||
$function = $dbForInternal->getDocument('functions', $functionId);
|
||||
|
||||
if (empty($function->getId()) || Database::SYSTEM_COLLECTION_FUNCTIONS != $function->getCollection()) {
|
||||
if (empty($function->getId())) {
|
||||
throw new Exception('Function not found', 404);
|
||||
}
|
||||
|
||||
if (!$projectDB->deleteDocument($function->getId())) {
|
||||
if (!$dbForInternal->deleteDocument('functions', $function->getId())) {
|
||||
throw new Exception('Failed to remove function from DB', 500);
|
||||
}
|
||||
|
||||
$deletes
|
||||
->setParam('type', DELETE_TYPE_DOCUMENT)
|
||||
->setParam('document', $function->getArrayCopy())
|
||||
->setParam('document', $function)
|
||||
;
|
||||
|
||||
$response->noContent();
|
||||
@@ -447,17 +421,17 @@ App::post('/v1/functions/:functionId/tags')
|
||||
->param('code', [], new File(), 'Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.', false)
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('projectDB')
|
||||
->inject('dbForInternal')
|
||||
->inject('usage')
|
||||
->action(function ($functionId, $command, $file, $request, $response, $projectDB, $usage) {
|
||||
->action(function ($functionId, $command, $file, $request, $response, $dbForInternal, $usage) {
|
||||
/** @var Utopia\Swoole\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Appwrite\Database\Database $projectDB */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Event\Event $usage */
|
||||
|
||||
$function = $projectDB->getDocument($functionId);
|
||||
$function = $dbForInternal->getDocument('functions', $functionId);
|
||||
|
||||
if (empty($function->getId()) || Database::SYSTEM_COLLECTION_FUNCTIONS != $function->getCollection()) {
|
||||
if (empty($function->getId())) {
|
||||
throw new Exception('Function not found', 404);
|
||||
}
|
||||
|
||||
@@ -496,31 +470,22 @@ App::post('/v1/functions/:functionId/tags')
|
||||
throw new Exception('Failed moving file', 500);
|
||||
}
|
||||
|
||||
$tag = $projectDB->createDocument([
|
||||
'$collection' => Database::SYSTEM_COLLECTION_TAGS,
|
||||
'$permissions' => [
|
||||
'read' => [],
|
||||
'write' => [],
|
||||
],
|
||||
$tag = $dbForInternal->createDocument('tags', new Document([
|
||||
'$read' => [],
|
||||
'$write' => [],
|
||||
'functionId' => $function->getId(),
|
||||
'dateCreated' => time(),
|
||||
'command' => $command,
|
||||
'path' => $path,
|
||||
'size' => $size,
|
||||
]);
|
||||
|
||||
if (false === $tag) {
|
||||
throw new Exception('Failed saving tag to DB', 500);
|
||||
}
|
||||
]));
|
||||
|
||||
$usage
|
||||
->setParam('storage', $tag->getAttribute('size', 0))
|
||||
;
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($tag, Response::MODEL_TAG)
|
||||
;
|
||||
$response->setStatusCode(Response::STATUS_CODE_CREATED);
|
||||
$response->dynamic2($tag, Response::MODEL_TAG);
|
||||
});
|
||||
|
||||
App::get('/v1/functions/:functionId/tags')
|
||||
@@ -540,31 +505,25 @@ App::get('/v1/functions/:functionId/tags')
|
||||
->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 ($functionId, $search, $limit, $offset, $orderType, $response, $projectDB) {
|
||||
->inject('dbForInternal')
|
||||
->action(function ($functionId, $search, $limit, $offset, $orderType, $response, $dbForInternal) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Appwrite\Database\Database $projectDB */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
|
||||
$function = $projectDB->getDocument($functionId);
|
||||
$function = $dbForInternal->getDocument('functions', $functionId);
|
||||
|
||||
if (empty($function->getId()) || Database::SYSTEM_COLLECTION_FUNCTIONS != $function->getCollection()) {
|
||||
if (empty($function->getId())) {
|
||||
throw new Exception('Function not found', 404);
|
||||
}
|
||||
|
||||
$results = $projectDB->getCollection([
|
||||
'limit' => $limit,
|
||||
'offset' => $offset,
|
||||
'orderType' => $orderType,
|
||||
'search' => $search,
|
||||
'filters' => [
|
||||
'$collection='.Database::SYSTEM_COLLECTION_TAGS,
|
||||
'functionId='.$function->getId(),
|
||||
],
|
||||
]);
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'sum' => $projectDB->getSum(),
|
||||
'tags' => $results
|
||||
$queries[] = new Query('functionId', Query::TYPE_EQUAL, [$function->getId()]);
|
||||
|
||||
$results = $dbForInternal->find('tags', $queries, $limit, $offset, ['_id'], [$orderType]);
|
||||
$sum = $dbForInternal->count('tags', $queries, APP_LIMIT_COUNT);
|
||||
|
||||
$response->dynamic2(new Document([
|
||||
'tags' => $results,
|
||||
'sum' => $sum,
|
||||
]), Response::MODEL_TAG_LIST);
|
||||
});
|
||||
|
||||
@@ -582,28 +541,28 @@ App::get('/v1/functions/:functionId/tags/:tagId')
|
||||
->param('functionId', '', new UID(), 'Function unique ID.')
|
||||
->param('tagId', '', new UID(), 'Tag unique ID.')
|
||||
->inject('response')
|
||||
->inject('projectDB')
|
||||
->action(function ($functionId, $tagId, $response, $projectDB) {
|
||||
->inject('dbForInternal')
|
||||
->action(function ($functionId, $tagId, $response, $dbForInternal) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Appwrite\Database\Database $projectDB */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
|
||||
$function = $projectDB->getDocument($functionId);
|
||||
$function = $dbForInternal->getDocument('functions', $functionId);
|
||||
|
||||
if (empty($function->getId()) || Database::SYSTEM_COLLECTION_FUNCTIONS != $function->getCollection()) {
|
||||
if (empty($function->getId())) {
|
||||
throw new Exception('Function not found', 404);
|
||||
}
|
||||
|
||||
$tag = $projectDB->getDocument($tagId);
|
||||
$tag = $dbForInternal->getDocument('tags', $tagId);
|
||||
|
||||
if ($tag->getAttribute('functionId') !== $function->getId()) {
|
||||
throw new Exception('Tag not found', 404);
|
||||
}
|
||||
|
||||
if (empty($tag->getId()) || Database::SYSTEM_COLLECTION_TAGS != $tag->getCollection()) {
|
||||
if (empty($tag->getId())) {
|
||||
throw new Exception('Tag not found', 404);
|
||||
}
|
||||
|
||||
$response->dynamic($tag, Response::MODEL_TAG);
|
||||
$response->dynamic2($tag, Response::MODEL_TAG);
|
||||
});
|
||||
|
||||
App::delete('/v1/functions/:functionId/tags/:tagId')
|
||||
@@ -620,45 +579,41 @@ App::delete('/v1/functions/:functionId/tags/:tagId')
|
||||
->param('functionId', '', new UID(), 'Function unique ID.')
|
||||
->param('tagId', '', new UID(), 'Tag unique ID.')
|
||||
->inject('response')
|
||||
->inject('projectDB')
|
||||
->inject('dbForInternal')
|
||||
->inject('usage')
|
||||
->action(function ($functionId, $tagId, $response, $projectDB, $usage) {
|
||||
->action(function ($functionId, $tagId, $response, $dbForInternal, $usage) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Appwrite\Database\Database $projectDB */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Event\Event $usage */
|
||||
|
||||
$function = $projectDB->getDocument($functionId);
|
||||
$function = $dbForInternal->getDocument('functions', $functionId);
|
||||
|
||||
if (empty($function->getId()) || Database::SYSTEM_COLLECTION_FUNCTIONS != $function->getCollection()) {
|
||||
if (empty($function->getId())) {
|
||||
throw new Exception('Function not found', 404);
|
||||
}
|
||||
|
||||
$tag = $projectDB->getDocument($tagId);
|
||||
$tag = $dbForInternal->getDocument('tags', $tagId);
|
||||
|
||||
if ($tag->getAttribute('functionId') !== $function->getId()) {
|
||||
throw new Exception('Tag not found', 404);
|
||||
}
|
||||
|
||||
if (empty($tag->getId()) || Database::SYSTEM_COLLECTION_TAGS != $tag->getCollection()) {
|
||||
if (empty($tag->getId())) {
|
||||
throw new Exception('Tag not found', 404);
|
||||
}
|
||||
|
||||
$device = Storage::getDevice('functions');
|
||||
|
||||
if ($device->delete($tag->getAttribute('path', ''))) {
|
||||
if (!$projectDB->deleteDocument($tag->getId())) {
|
||||
if (!$dbForInternal->deleteDocument('tags', $tag->getId())) {
|
||||
throw new Exception('Failed to remove tag from DB', 500);
|
||||
}
|
||||
}
|
||||
|
||||
if($function->getAttribute('tag') === $tag->getId()) { // Reset function tag
|
||||
$function = $projectDB->updateDocument(array_merge($function->getArrayCopy(), [
|
||||
$function = $dbForInternal->updateDocument('functions', $function->getId(), new Document(array_merge($function->getArrayCopy(), [
|
||||
'tag' => '',
|
||||
]));
|
||||
|
||||
if (false === $function) {
|
||||
throw new Exception('Failed saving function to DB', 500);
|
||||
}
|
||||
])));
|
||||
}
|
||||
|
||||
$usage
|
||||
@@ -687,29 +642,29 @@ App::post('/v1/functions/:functionId/executions')
|
||||
// ->param('async', 1, new Range(0, 1), 'Execute code asynchronously. Pass 1 for true, 0 for false. Default value is 1.', true)
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
->inject('projectDB')
|
||||
->inject('dbForInternal')
|
||||
->inject('user')
|
||||
->action(function ($functionId, $data, /*$async,*/ $response, $project, $projectDB, $user) {
|
||||
->action(function ($functionId, $data, /*$async,*/ $response, $project, $dbForInternal, $user) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Appwrite\Database\Document $project */
|
||||
/** @var Appwrite\Database\Database $projectDB */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Database\Document $user */
|
||||
|
||||
Authorization::disable();
|
||||
|
||||
$function = $projectDB->getDocument($functionId);
|
||||
$function = $dbForInternal->getDocument('functions', $functionId);
|
||||
|
||||
if (empty($function->getId()) || Database::SYSTEM_COLLECTION_FUNCTIONS != $function->getCollection()) {
|
||||
if (empty($function->getId())) {
|
||||
throw new Exception('Function not found', 404);
|
||||
}
|
||||
|
||||
$tag = $projectDB->getDocument($function->getAttribute('tag'));
|
||||
$tag = $dbForInternal->getDocument('tags', $function->getAttribute('tag'));
|
||||
|
||||
if ($tag->getAttribute('functionId') !== $function->getId()) {
|
||||
throw new Exception('Tag not found. Deploy tag before trying to execute a function', 404);
|
||||
}
|
||||
|
||||
if (empty($tag->getId()) || Database::SYSTEM_COLLECTION_TAGS != $tag->getCollection()) {
|
||||
if (empty($tag->getId())) {
|
||||
throw new Exception('Tag not found. Deploy tag before trying to execute a function', 404);
|
||||
}
|
||||
|
||||
@@ -717,33 +672,27 @@ App::post('/v1/functions/:functionId/executions')
|
||||
|
||||
$validator = new Authorization($function, 'execute');
|
||||
|
||||
if (!$validator->isValid($function->getPermissions())) { // Check if user has write access to execute function
|
||||
if (!$validator->isValid($function->getAttribute('execute'))) { // Check if user has write access to execute function
|
||||
throw new Exception($validator->getDescription(), 401);
|
||||
}
|
||||
|
||||
Authorization::disable();
|
||||
|
||||
$execution = $projectDB->createDocument([
|
||||
'$collection' => Database::SYSTEM_COLLECTION_EXECUTIONS,
|
||||
'$permissions' => [
|
||||
'read' => (!empty($user->getId())) ? ['user:' . $user->getId()] : [],
|
||||
'write' => [],
|
||||
],
|
||||
$execution = $dbForInternal->createDocument('executions', new Document([
|
||||
'$read' => (!empty($user->getId())) ? ['user:' . $user->getId()] : [],
|
||||
'$write' => [],
|
||||
'dateCreated' => time(),
|
||||
'functionId' => $function->getId(),
|
||||
'tagId' => $tag->getId(),
|
||||
'trigger' => 'http', // http / schedule / event
|
||||
'status' => 'waiting', // waiting / processing / completed / failed
|
||||
'exitCode' => 0,
|
||||
'stdout' => '',
|
||||
'stderr' => '',
|
||||
'time' => 0,
|
||||
]);
|
||||
'time' => 0.0,
|
||||
]));
|
||||
|
||||
Authorization::reset();
|
||||
|
||||
if (false === $execution) {
|
||||
throw new Exception('Failed saving execution to DB', 500);
|
||||
}
|
||||
|
||||
$jwt = ''; // initialize
|
||||
if (!empty($user->getId())) { // If userId exists, generate a JWT for function
|
||||
@@ -777,10 +726,8 @@ App::post('/v1/functions/:functionId/executions')
|
||||
'jwt' => $jwt,
|
||||
]);
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($execution, Response::MODEL_EXECUTION)
|
||||
;
|
||||
$response->setStatusCode(Response::STATUS_CODE_CREATED);
|
||||
$response->dynamic2($execution, Response::MODEL_EXECUTION);
|
||||
});
|
||||
|
||||
App::get('/v1/functions/:functionId/executions')
|
||||
@@ -795,38 +742,33 @@ App::get('/v1/functions/:functionId/executions')
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_EXECUTION_LIST)
|
||||
->param('functionId', '', new UID(), 'Function unique ID.')
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
|
||||
->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 ($functionId, $search, $limit, $offset, $orderType, $response, $projectDB) {
|
||||
->inject('dbForInternal')
|
||||
->action(function ($functionId, $limit, $offset, $response, $dbForInternal) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Appwrite\Database\Database $projectDB */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
|
||||
Authorization::disable();
|
||||
$function = $projectDB->getDocument($functionId);
|
||||
$function = $dbForInternal->getDocument('functions', $functionId);
|
||||
Authorization::reset();
|
||||
|
||||
if (empty($function->getId()) || Database::SYSTEM_COLLECTION_FUNCTIONS != $function->getCollection()) {
|
||||
if (empty($function->getId())) {
|
||||
throw new Exception('Function not found', 404);
|
||||
}
|
||||
|
||||
$results = $projectDB->getCollection([
|
||||
'limit' => $limit,
|
||||
'offset' => $offset,
|
||||
'orderType' => $orderType,
|
||||
'search' => $search,
|
||||
'filters' => [
|
||||
'$collection='.Database::SYSTEM_COLLECTION_EXECUTIONS,
|
||||
'functionId='.$function->getId(),
|
||||
],
|
||||
]);
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'sum' => $projectDB->getSum(),
|
||||
'executions' => $results
|
||||
$results = $dbForInternal->find('executions', [
|
||||
new Query('functionId', Query::TYPE_EQUAL, [$function->getId()]),
|
||||
], $limit, $offset, ['_id'], [Database::ORDER_DESC]);
|
||||
|
||||
$sum = $dbForInternal->count('executions', [
|
||||
new Query('functionId', Query::TYPE_EQUAL, [$function->getId()]),
|
||||
], APP_LIMIT_COUNT);
|
||||
|
||||
$response->dynamic2(new Document([
|
||||
'executions' => $results,
|
||||
'sum' => $sum,
|
||||
]), Response::MODEL_EXECUTION_LIST);
|
||||
});
|
||||
|
||||
@@ -844,28 +786,28 @@ App::get('/v1/functions/:functionId/executions/:executionId')
|
||||
->param('functionId', '', new UID(), 'Function unique ID.')
|
||||
->param('executionId', '', new UID(), 'Execution unique ID.')
|
||||
->inject('response')
|
||||
->inject('projectDB')
|
||||
->action(function ($functionId, $executionId, $response, $projectDB) {
|
||||
->inject('dbForInternal')
|
||||
->action(function ($functionId, $executionId, $response, $dbForInternal) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Appwrite\Database\Database $projectDB */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
|
||||
Authorization::disable();
|
||||
$function = $projectDB->getDocument($functionId);
|
||||
$function = $dbForInternal->getDocument('functions', $functionId);
|
||||
Authorization::reset();
|
||||
|
||||
if (empty($function->getId()) || Database::SYSTEM_COLLECTION_FUNCTIONS != $function->getCollection()) {
|
||||
if (empty($function->getId())) {
|
||||
throw new Exception('Function not found', 404);
|
||||
}
|
||||
|
||||
$execution = $projectDB->getDocument($executionId);
|
||||
$execution = $dbForInternal->getDocument('executions', $executionId);
|
||||
|
||||
if ($execution->getAttribute('functionId') !== $function->getId()) {
|
||||
throw new Exception('Execution not found', 404);
|
||||
}
|
||||
|
||||
if (empty($execution->getId()) || Database::SYSTEM_COLLECTION_EXECUTIONS != $execution->getCollection()) {
|
||||
if (empty($execution->getId())) {
|
||||
throw new Exception('Execution not found', 404);
|
||||
}
|
||||
|
||||
$response->dynamic($execution, Response::MODEL_EXECUTION);
|
||||
$response->dynamic2($execution, Response::MODEL_EXECUTION);
|
||||
});
|
||||
|
||||
@@ -267,7 +267,7 @@ App::get('/v1/health/anti-virus')
|
||||
'status' => (@$antiVirus->ping()) ? 'online' : 'offline',
|
||||
'version' => @$antiVirus->version(),
|
||||
]);
|
||||
} catch( \Exception $e) {
|
||||
} catch (Throwable $e) {
|
||||
$response->json([
|
||||
'status' => 'offline',
|
||||
'version' => '',
|
||||
|
||||
+443
-533
File diff suppressed because it is too large
Load Diff
+79
-153
@@ -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;
|
||||
@@ -22,6 +21,7 @@ use Utopia\Image\Image;
|
||||
use Appwrite\OpenSSL\OpenSSL;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Validator\Numeric;
|
||||
|
||||
App::post('/v1/storage/files')
|
||||
@@ -43,14 +43,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 */
|
||||
@@ -122,14 +122,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),
|
||||
@@ -137,17 +134,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),
|
||||
]);
|
||||
|
||||
if (false === $file) {
|
||||
throw new Exception('Failed saving file to DB', 500);
|
||||
}
|
||||
'openSSLVersion' => '1',
|
||||
'openSSLCipher' => OpenSSL::CIPHER_AES_128_GCM,
|
||||
'openSSLTag' => \bin2hex($tag),
|
||||
'openSSLIV' => \bin2hex($iv),
|
||||
]));
|
||||
|
||||
$audits
|
||||
->setParam('event', 'storage.files.create')
|
||||
@@ -158,9 +150,8 @@ App::post('/v1/storage/files')
|
||||
->setParam('storage', $sizeActual)
|
||||
;
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($file, Response::MODEL_FILE)
|
||||
$response->setStatusCode(Response::STATUS_CODE_CREATED);
|
||||
$response->dynamic2($file, Response::MODEL_FILE);
|
||||
;
|
||||
});
|
||||
|
||||
@@ -180,24 +171,16 @@ 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,
|
||||
],
|
||||
]);
|
||||
$queries = ($search) ? [new Query('name', Query::TYPE_SEARCH, $search)] : [];
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'sum' => $projectDB->getSum(),
|
||||
'files' => $results
|
||||
$response->dynamic2(new Document([
|
||||
'files' => $dbForInternal->find('files', $queries, $limit, $offset, ['_id'], [$orderType]),
|
||||
'sum' => $dbForInternal->count('files', $queries, APP_LIMIT_COUNT),
|
||||
]), Response::MODEL_FILE_LIST);
|
||||
});
|
||||
|
||||
@@ -214,18 +197,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')
|
||||
@@ -254,12 +237,12 @@ App::get('/v1/storage/files/:fileId/preview')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
->inject('projectDB')
|
||||
->action(function ($fileId, $width, $height, $gravity, $quality, $borderWidth, $borderColor, $borderRadius, $opacity, $rotation, $background, $output, $request, $response, $project, $projectDB) {
|
||||
->inject('dbForInternal')
|
||||
->action(function ($fileId, $width, $height, $gravity, $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';
|
||||
|
||||
@@ -282,16 +265,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)) {
|
||||
@@ -329,11 +312,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'))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -395,14 +378,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);
|
||||
}
|
||||
|
||||
@@ -417,14 +400,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'))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -453,15 +436,15 @@ App::get('/v1/storage/files/:fileId/view')
|
||||
->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);
|
||||
$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);
|
||||
}
|
||||
|
||||
@@ -482,14 +465,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'))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -524,37 +507,31 @@ 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' => '',
|
||||
]));
|
||||
|
||||
if (false === $file) {
|
||||
throw new Exception('Failed saving file to DB', 500);
|
||||
}
|
||||
$file = $dbForInternal->updateDocument('files', $fileId, new Document(\array_merge($file->getArrayCopy(), [
|
||||
'$read' => $read,
|
||||
'$write' => $write,
|
||||
'bucketId' => '',
|
||||
])));
|
||||
|
||||
$audits
|
||||
->setParam('event', 'storage.files.update')
|
||||
->setParam('resource', 'storage/files/'.$file->getId())
|
||||
;
|
||||
|
||||
$response->dynamic($file, Response::MODEL_FILE);
|
||||
$response->dynamic2($file, Response::MODEL_FILE);
|
||||
});
|
||||
|
||||
App::delete('/v1/storage/files/:fileId')
|
||||
@@ -570,27 +547,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);
|
||||
}
|
||||
}
|
||||
@@ -605,59 +582,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', 'root')
|
||||
// ->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'));
|
||||
|
||||
// }
|
||||
// );
|
||||
});
|
||||
+215
-284
@@ -1,24 +1,24 @@
|
||||
<?php
|
||||
|
||||
use Utopia\App;
|
||||
use Utopia\Exception;
|
||||
use Utopia\Config\Config;
|
||||
use Appwrite\Network\Validator\Email;
|
||||
use Utopia\Validator\Text;
|
||||
use Appwrite\Network\Validator\Host;
|
||||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\WhiteList;
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Database\Database;
|
||||
use Appwrite\Database\Document;
|
||||
use Appwrite\Database\Validator\UID;
|
||||
use Appwrite\Database\Validator\Authorization;
|
||||
use Appwrite\Database\Exception\Duplicate;
|
||||
use Appwrite\Database\Validator\Key;
|
||||
use Appwrite\Detector\Detector;
|
||||
use Appwrite\Template\Template;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Network\Validator\Email;
|
||||
use Appwrite\Network\Validator\Host;
|
||||
use Utopia\App;
|
||||
use Utopia\Exception;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\WhiteList;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Key;
|
||||
|
||||
App::post('/v1/teams')
|
||||
->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,15 @@ 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,24 +99,19 @@ 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,
|
||||
],
|
||||
]);
|
||||
$queries = ($search) ? [new Query('name', Query::TYPE_SEARCH, [$search])] : [];
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'sum' => $projectDB->getSum(),
|
||||
'teams' => $results
|
||||
$results = $dbForInternal->find('teams', $queries, $limit, $offset, ['_id'], [$orderType]);
|
||||
$sum = $dbForInternal->count('teams', $queries, APP_LIMIT_COUNT);
|
||||
|
||||
$response->dynamic2(new Document([
|
||||
'teams' => $results,
|
||||
'sum' => $sum,
|
||||
]), Response::MODEL_TEAM_LIST);
|
||||
});
|
||||
|
||||
@@ -146,18 +128,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 +157,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 +186,36 @@ 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
|
||||
|
||||
foreach ($memberships as $member) {
|
||||
if (!$projectDB->deleteDocument($member->getId())) {
|
||||
// TODO delete all members individually from the user object
|
||||
foreach ($memberships as $membership) {
|
||||
if (!$dbForInternal->deleteDocument('memberships', $membership->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 */
|
||||
|
||||
@@ -288,41 +260,20 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
|
||||
$email = \strtolower($email);
|
||||
$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' => 2000,
|
||||
'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,
|
||||
],
|
||||
]);
|
||||
$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', [], APP_LIMIT_USERS);
|
||||
|
||||
if($sum >= $limit) {
|
||||
throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501);
|
||||
@@ -332,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, 'role:all'],
|
||||
'$write' => ['user:'.$userId],
|
||||
'email' => $email,
|
||||
'emailVerification' => false,
|
||||
'status' => Auth::USER_STATUS_UNACTIVATED,
|
||||
@@ -351,31 +301,19 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
'registration' => \time(),
|
||||
'reset' => false,
|
||||
'name' => $name,
|
||||
'prefs' => [],
|
||||
'sessions' => [],
|
||||
'tokens' => [],
|
||||
], ['email' => $email]);
|
||||
'memberships' => [],
|
||||
]));
|
||||
} 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;
|
||||
|
||||
foreach ($memberships as $member) {
|
||||
if ($member->getAttribute('userId') == $invitee->getId()) {
|
||||
throw new Exception('User has already been invited or is already a member of this team', 409);
|
||||
}
|
||||
|
||||
if ($member->getAttribute('userId') == $user->getId() && \in_array('owner', $member->getAttribute('roles', []))) {
|
||||
$isOwner = true;
|
||||
}
|
||||
}
|
||||
$isOwner = Authorization::isRole('team:'.$team->getId().'/owner');;
|
||||
|
||||
if (!$isOwner && !$isPrivilegedUser && !$isAppUser) { // Not owner, not admin, not app (server)
|
||||
throw new Exception('User is not allowed to send invitations for this team', 401);
|
||||
@@ -384,11 +322,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' => ['role:all'],
|
||||
'$write' => ['user:'.$invitee->getId(), 'team:'.$team->getId().'/owner'],
|
||||
'userId' => $invitee->getId(),
|
||||
'teamId' => $team->getId(),
|
||||
'roles' => $roles,
|
||||
@@ -400,28 +336,26 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
|
||||
if ($isPrivilegedUser || $isAppUser) { // Allow admin to create membership
|
||||
Authorization::disable();
|
||||
$membership = $projectDB->createDocument($membership->getArrayCopy());
|
||||
try {
|
||||
$membership = $dbForInternal->createDocument('memberships', $membership);
|
||||
} catch (Duplicate $th) {
|
||||
throw new Exception('User has already been invited or is already a member of this team', 409);
|
||||
}
|
||||
|
||||
$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);
|
||||
try {
|
||||
$membership = $dbForInternal->createDocument('memberships', $membership);
|
||||
} catch (Duplicate $th) {
|
||||
throw new Exception('User has already been invited or is already a member of this team', 409);
|
||||
}
|
||||
}
|
||||
|
||||
$url = Template::parseURL($url);
|
||||
@@ -467,13 +401,59 @@ 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')
|
||||
->desc('Get Team Memberships')
|
||||
->groups(['api', 'teams'])
|
||||
->label('scope', 'teams.read')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
|
||||
->label('sdk.namespace', 'teams')
|
||||
->label('sdk.method', 'getMemberships')
|
||||
->label('sdk.description', '/docs/references/teams/get-team-members.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_MEMBERSHIP_LIST)
|
||||
->param('teamId', '', new UID(), 'Team unique ID.')
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
|
||||
->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('dbForInternal')
|
||||
->action(function ($teamId, $search, $limit, $offset, $orderType, $response, $dbForInternal) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
|
||||
$team = $dbForInternal->getDocument('teams', $teamId);
|
||||
|
||||
if (empty($team->getId())) {
|
||||
throw new Exception('Team not found', 404);
|
||||
}
|
||||
|
||||
$memberships = $dbForInternal->find('memberships', [new Query('teamId', Query::TYPE_EQUAL, [$teamId])], $limit, $offset, ['_id'], [$orderType]);
|
||||
$sum = $dbForInternal->count('memberships', [new Query('teamId', Query::TYPE_EQUAL, [$teamId])], APP_LIMIT_COUNT);
|
||||
$users = [];
|
||||
|
||||
foreach ($memberships as $membership) {
|
||||
if (empty($membership->getAttribute('userId', null))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$temp = $dbForInternal->getDocument('users', $membership->getAttribute('userId', null))->getArrayCopy(['email', 'name']);
|
||||
|
||||
$users[] = new Document(\array_merge($temp, $membership->getArrayCopy()));
|
||||
}
|
||||
|
||||
$response->dynamic2(new Document([
|
||||
'memberships' => $users,
|
||||
'sum' => $sum,
|
||||
]), Response::MODEL_MEMBERSHIP_LIST);
|
||||
});
|
||||
|
||||
App::patch('/v1/teams/:teamId/memberships/:membershipId')
|
||||
@@ -494,25 +474,29 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->inject('projectDB')
|
||||
->inject('dbForInternal')
|
||||
->inject('audits')
|
||||
->action(function ($teamId, $membershipId, $roles, $request, $response, $user, $projectDB,$audits) {
|
||||
->action(function ($teamId, $membershipId, $roles, $request, $response, $user, $dbForInternal, $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 Appwrite\Event\Event $audits */
|
||||
|
||||
$team = $projectDB->getDocument($teamId);
|
||||
if (empty($team->getId()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) {
|
||||
$team = $dbForInternal->getDocument('teams', $teamId);
|
||||
if ($team->isEmpty()) {
|
||||
throw new Exception('Team not found', 404);
|
||||
}
|
||||
|
||||
$membership = $projectDB->getDocument($membershipId);
|
||||
if (empty($membership->getId()) || Database::SYSTEM_COLLECTION_MEMBERSHIPS != $membership->getCollection()) {
|
||||
$membership = $dbForInternal->getDocument('memberships', $membershipId);
|
||||
if ($membership->isEmpty()) {
|
||||
throw new Exception('Membership not found', 404);
|
||||
}
|
||||
|
||||
$profile = $dbForInternal->getDocument('users', $membership->getAttribute('userId'));
|
||||
if ($profile->isEmpty()) {
|
||||
throw new Exception('User not found', 404);
|
||||
}
|
||||
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::$roles);
|
||||
$isAppUser = Auth::isAppUser(Authorization::$roles);
|
||||
@@ -524,11 +508,9 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId')
|
||||
|
||||
// Update the roles
|
||||
$membership->setAttribute('roles', $roles);
|
||||
$membership = $projectDB->updateDocument($membership->getArrayCopy());
|
||||
$membership = $dbForInternal->updateDocument('memberships', $membership->getId(), $membership);
|
||||
|
||||
if (false === $membership) {
|
||||
throw new Exception('Failed updating membership', 500);
|
||||
}
|
||||
//TODO sync updated membership in the user $profile object using TYPE_REPLACE
|
||||
|
||||
$audits
|
||||
->setParam('userId', $user->getId())
|
||||
@@ -536,60 +518,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId')
|
||||
->setParam('resource', 'teams/'.$teamId)
|
||||
;
|
||||
|
||||
$response->dynamic(new Document($membership->getArrayCopy()), Response::MODEL_MEMBERSHIP);
|
||||
});
|
||||
|
||||
App::get('/v1/teams/:teamId/memberships')
|
||||
->desc('Get Team Memberships')
|
||||
->groups(['api', 'teams'])
|
||||
->label('scope', 'teams.read')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
|
||||
->label('sdk.namespace', 'teams')
|
||||
->label('sdk.method', 'getMemberships')
|
||||
->label('sdk.description', '/docs/references/teams/get-team-members.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_MEMBERSHIP_LIST)
|
||||
->param('teamId', '', new UID(), 'Team unique ID.')
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
|
||||
->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) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Appwrite\Database\Database $projectDB */
|
||||
|
||||
$team = $projectDB->getDocument($teamId);
|
||||
|
||||
if (empty($team->getId()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) {
|
||||
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,
|
||||
],
|
||||
]);
|
||||
$users = [];
|
||||
|
||||
foreach ($memberships as $membership) {
|
||||
if (empty($membership->getAttribute('userId', null))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$temp = $projectDB->getDocument($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($membership, Response::MODEL_MEMBERSHIP);
|
||||
});
|
||||
|
||||
App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
||||
@@ -611,22 +540,23 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->inject('projectDB')
|
||||
->inject('dbForInternal')
|
||||
->inject('geodb')
|
||||
->inject('audits')
|
||||
->action(function ($teamId, $membershipId, $userId, $secret, $request, $response, $user, $projectDB, $geodb, $audits) {
|
||||
->action(function ($teamId, $membershipId, $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($membershipId);
|
||||
|
||||
if (empty($membership->getId()) || Database::SYSTEM_COLLECTION_MEMBERSHIPS != $membership->getCollection()) {
|
||||
throw new Exception('Invite not found', 404);
|
||||
$membership = $dbForInternal->getDocument('memberships', $membershipId);
|
||||
|
||||
if (empty($membership->getId())) {
|
||||
throw new Exception('Membership not found', 404);
|
||||
}
|
||||
|
||||
if ($membership->getAttribute('teamId') !== $teamId) {
|
||||
@@ -635,11 +565,11 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/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);
|
||||
}
|
||||
|
||||
@@ -652,13 +582,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/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()) {
|
||||
@@ -682,8 +606,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/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'),
|
||||
@@ -698,24 +621,15 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/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);
|
||||
$membership = $dbForInternal->updateDocument('memberships', $membership->getId(), $membership);
|
||||
|
||||
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.memberships.update.status')
|
||||
@@ -733,10 +647,10 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/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/:membershipId')
|
||||
@@ -753,18 +667,18 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId')
|
||||
->param('teamId', '', new UID(), 'Team unique ID.')
|
||||
->param('membershipId', '', new UID(), 'Membership ID.')
|
||||
->inject('response')
|
||||
->inject('projectDB')
|
||||
->inject('dbForInternal')
|
||||
->inject('audits')
|
||||
->inject('events')
|
||||
->action(function ($teamId, $membershipId, $response, $projectDB, $audits, $events) {
|
||||
->action(function ($teamId, $membershipId, $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($membershipId);
|
||||
$membership = $dbForInternal->getDocument('memberships', $membershipId);
|
||||
|
||||
if (empty($membership->getId()) || Database::SYSTEM_COLLECTION_MEMBERSHIPS != $membership->getCollection()) {
|
||||
if (empty($membership->getId())) {
|
||||
throw new Exception('Invite not found', 404);
|
||||
}
|
||||
|
||||
@@ -772,24 +686,41 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId')
|
||||
throw new Exception('Team IDs don\'t match', 404);
|
||||
}
|
||||
|
||||
$team = $projectDB->getDocument($teamId);
|
||||
$user = $dbForInternal->getDocument('users', $membership->getAttribute('userId'));
|
||||
|
||||
if (empty($team->getId()) || Database::SYSTEM_COLLECTION_TEAMS != $team->getCollection()) {
|
||||
if ($user->isEmpty()) {
|
||||
throw new Exception('User not found', 404);
|
||||
}
|
||||
|
||||
$team = $dbForInternal->getDocument('teams', $teamId);
|
||||
|
||||
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' => \max($team->getAttribute('sum', 0) - 1, 0), // Ensure that sum >= 0
|
||||
]));
|
||||
$memberships = $user->getAttribute('memberships', []);
|
||||
|
||||
foreach ($memberships as $key => $child) {
|
||||
/** @var Document $child */
|
||||
|
||||
if ($membershipId == $child->getId()) {
|
||||
unset($memberships[$key]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (false === $team) {
|
||||
throw new Exception('Failed saving team to DB', 500);
|
||||
Authorization::disable();
|
||||
|
||||
$dbForInternal->updateDocument('users', $user->getId(), $user->setAttribute('memberships', $memberships));
|
||||
|
||||
Authorization::reset();
|
||||
|
||||
if ($membership->getAttribute('confirm')) { // Count only confirmed members
|
||||
$team = $dbForInternal->updateDocument('teams', $team->getId(), $team->setAttribute('sum', \max($team->getAttribute('sum', 0) - 1, 0)));
|
||||
}
|
||||
|
||||
$audits
|
||||
@@ -799,7 +730,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId')
|
||||
;
|
||||
|
||||
$events
|
||||
->setParam('eventData', $response->output($membership, Response::MODEL_MEMBERSHIP))
|
||||
->setParam('eventData', $response->output2($membership, Response::MODEL_MEMBERSHIP))
|
||||
;
|
||||
|
||||
$response->noContent();
|
||||
|
||||
+109
-167
@@ -1,5 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Auth\Validator\Password;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\App;
|
||||
use Utopia\Exception;
|
||||
use Utopia\Validator;
|
||||
@@ -10,14 +13,9 @@ use Utopia\Validator\Text;
|
||||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\Audit\Adapters\MySQL as AuditAdapter;
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Auth\Validator\Password;
|
||||
use Appwrite\Database\Database;
|
||||
use Appwrite\Database\Document;
|
||||
use Appwrite\Database\Exception\Duplicate;
|
||||
use Appwrite\Database\Validator\UID;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use DeviceDetector\DeviceDetector;
|
||||
|
||||
App::post('/v1/users')
|
||||
@@ -36,31 +34,19 @@ App::post('/v1/users')
|
||||
->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 */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
|
||||
$email = \strtolower($email);
|
||||
$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);
|
||||
}
|
||||
|
||||
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' => ['role:all'],
|
||||
'$write' => ['user:'.$userId],
|
||||
'email' => $email,
|
||||
'emailVerification' => false,
|
||||
'status' => Auth::USER_STATUS_UNACTIVATED,
|
||||
@@ -69,15 +55,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')
|
||||
@@ -96,24 +84,17 @@ 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, ['_id'], [$orderType]);
|
||||
$sum = $dbForInternal->count('users', [], APP_LIMIT_COUNT);
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'sum' => $projectDB->getSum(),
|
||||
'users' => $results
|
||||
$response->dynamic2(new Document([
|
||||
'users' => $results,
|
||||
'sum' => $sum,
|
||||
]), Response::MODEL_USER_LIST);
|
||||
});
|
||||
|
||||
@@ -130,18 +111,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')
|
||||
@@ -157,20 +138,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')
|
||||
@@ -186,16 +167,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);
|
||||
}
|
||||
|
||||
@@ -213,11 +194,11 @@ App::get('/v1/users/:userId/sessions')
|
||||
$sessions[$key] = $session;
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
$response->dynamic2(new Document([
|
||||
'sessions' => $sessions,
|
||||
'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')
|
||||
@@ -232,29 +213,24 @@ App::get('/v1/users/:userId/logs')
|
||||
->label('sdk.response.model', Response::MODEL_LOG_LIST)
|
||||
->param('userId', '', new UID(), 'User unique ID.')
|
||||
->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, $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);
|
||||
}
|
||||
|
||||
$adapter = new AuditAdapter($register->get('db'));
|
||||
$adapter->setNamespace('app_'.$project->getId());
|
||||
|
||||
$audit = new Audit($adapter);
|
||||
$audit = new Audit($dbForInternal);
|
||||
|
||||
$countries = $locale->getText('countries');
|
||||
|
||||
@@ -303,7 +279,7 @@ App::get('/v1/users/:userId/logs')
|
||||
$output[$i] = new Document([
|
||||
'event' => $log['event'],
|
||||
'ip' => $log['ip'],
|
||||
'time' => \strtotime($log['time']),
|
||||
'time' => $log['time'],
|
||||
|
||||
'osCode' => $osCode,
|
||||
'osName' => $osName,
|
||||
@@ -330,7 +306,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')
|
||||
@@ -348,26 +324,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, Validator::TYPE_INTEGER), '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/verification')
|
||||
@@ -385,26 +355,20 @@ App::patch('/v1/users/:userId/verification')
|
||||
->param('userId', '', new UID(), 'User unique ID.')
|
||||
->param('emailVerification', false, new Boolean(), 'User Email Verification Status.')
|
||||
->inject('response')
|
||||
->inject('projectDB')
|
||||
->action(function ($userId, $emailVerification, $response, $projectDB) {
|
||||
->inject('dbForInternal')
|
||||
->action(function ($userId, $emailVerification, $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(), [
|
||||
'emailVerification' => $emailVerification,
|
||||
]));
|
||||
$user = $dbForInternal->updateDocument('users', $user->getId(), $user->setAttribute('emailVerification', $emailVerification));
|
||||
|
||||
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')
|
||||
@@ -422,26 +386,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')
|
||||
@@ -458,32 +416,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -504,31 +464,23 @@ 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->getAttribute('sessions', []));
|
||||
|
||||
$events
|
||||
->setParam('eventData', $response->output($user, Response::MODEL_USER))
|
||||
->setParam('eventData', $response->output2($user, Response::MODEL_USER))
|
||||
;
|
||||
|
||||
// TODO : Response filter implementation
|
||||
@@ -548,39 +500,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' => ['role:all'],
|
||||
// ]));
|
||||
|
||||
$deletes
|
||||
->setParam('type', DELETE_TYPE_DOCUMENT)
|
||||
@@ -588,7 +530,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
|
||||
|
||||
+24
-16
@@ -10,13 +10,13 @@ use Utopia\Exception;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Domains\Domain;
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Database\Database;
|
||||
use Appwrite\Database\Document;
|
||||
use Appwrite\Database\Validator\Authorization;
|
||||
use Appwrite\Network\Validator\Origin;
|
||||
use Appwrite\Utopia\Response\Filters\V06;
|
||||
use Appwrite\Utopia\Response\Filters\V07;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization as Authorization2;
|
||||
|
||||
Config::setParam('domainVerification', false);
|
||||
Config::setParam('cookieDomain', 'localhost');
|
||||
@@ -26,13 +26,12 @@ App::init(function ($utopia, $request, $response, $console, $project, $consoleDB
|
||||
/** @var Utopia\Swoole\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Appwrite\Database\Database $consoleDB */
|
||||
/** @var Appwrite\Database\Document $console */
|
||||
/** @var Appwrite\Database\Document $project */
|
||||
/** @var Appwrite\Database\Document $user */
|
||||
/** @var Utopia\Database\Document $console */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Locale\Locale $locale */
|
||||
/** @var bool $mode */
|
||||
/** @var array $clients */
|
||||
|
||||
|
||||
$domain = $request->getHostname();
|
||||
$domains = Config::getParam('domains', []);
|
||||
if (!array_key_exists($domain, $domains)) {
|
||||
@@ -86,7 +85,11 @@ App::init(function ($utopia, $request, $response, $console, $project, $consoleDB
|
||||
|
||||
$route = $utopia->match($request);
|
||||
|
||||
if (!empty($route->getLabel('sdk.auth', [])) && empty($project->getId()) && ($route->getLabel('scope', '') !== 'public')) {
|
||||
if ($project->isEmpty()) {
|
||||
throw new Exception('Project not found', 404);
|
||||
}
|
||||
|
||||
if (!empty($route->getLabel('sdk.auth', [])) && $project->isEmpty() && ($route->getLabel('scope', '') !== 'public')) {
|
||||
throw new Exception('Missing or unknown project ID', 400);
|
||||
}
|
||||
|
||||
@@ -129,8 +132,8 @@ App::init(function ($utopia, $request, $response, $console, $project, $consoleDB
|
||||
);
|
||||
|
||||
/*
|
||||
* Response format
|
||||
*/
|
||||
* Response format
|
||||
*/
|
||||
$responseFormat = $request->getHeader('x-appwrite-response-format', App::getEnv('_APP_SYSTEM_RESPONSE_FORMAT', ''));
|
||||
if ($responseFormat) {
|
||||
switch($responseFormat) {
|
||||
@@ -192,10 +195,10 @@ App::init(function ($utopia, $request, $response, $console, $project, $consoleDB
|
||||
$role = ($user->isEmpty()) ? Auth::USER_ROLE_GUEST : Auth::USER_ROLE_MEMBER;
|
||||
|
||||
// Add user roles
|
||||
$membership = $user->search('teamId', $project->getAttribute('teamId', null), $user->getAttribute('memberships', []));
|
||||
$memberships = $user->find('teamId', $project->getAttribute('teamId', null), 'memberships');
|
||||
|
||||
if ($membership) {
|
||||
foreach ($membership->getAttribute('roles', []) as $memberRole) {
|
||||
if ($memberships) {
|
||||
foreach ($memberships->getAttribute('roles', []) as $memberRole) {
|
||||
switch ($memberRole) {
|
||||
case 'owner':
|
||||
$role = Auth::USER_ROLE_OWNER;
|
||||
@@ -218,7 +221,7 @@ App::init(function ($utopia, $request, $response, $console, $project, $consoleDB
|
||||
|
||||
if (!empty($authKey)) { // API Key authentication
|
||||
// Check if given key match project API keys
|
||||
$key = $project->search('secret', $authKey, $project->getAttribute('keys', []));
|
||||
$key = $project->find('secret', $authKey, 'keys');
|
||||
|
||||
/*
|
||||
* Try app auth when we have project key and no user
|
||||
@@ -237,21 +240,26 @@ App::init(function ($utopia, $request, $response, $console, $project, $consoleDB
|
||||
$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', []));
|
||||
@@ -259,7 +267,7 @@ App::init(function ($utopia, $request, $response, $console, $project, $consoleDB
|
||||
// TDOO Check if user is root
|
||||
|
||||
if (!\in_array($scope, $scopes)) {
|
||||
if (empty($project->getId()) || Database::SYSTEM_COLLECTION_PROJECTS !== $project->getCollection()) { // Check if permission is denied because project is missing
|
||||
if ($project->isEmpty()) { // Check if permission is denied because project is missing
|
||||
throw new Exception('Project not found', 404);
|
||||
}
|
||||
|
||||
@@ -380,7 +388,7 @@ App::error(function ($error, $utopia, $request, $response, $layout, $project) {
|
||||
$response->html($layout->render());
|
||||
}
|
||||
|
||||
$response->dynamic(new Document($output),
|
||||
$response->dynamic2(new Document($output),
|
||||
$utopia->isDevelopment() ? Response::MODEL_ERROR_DEV : Response::MODEL_ERROR);
|
||||
}, ['error', 'utopia', 'request', 'response', 'layout', 'project']);
|
||||
|
||||
|
||||
@@ -9,18 +9,19 @@ use Utopia\Abuse\Adapters\TimeLimit;
|
||||
use Utopia\Storage\Device\Local;
|
||||
use Utopia\Storage\Storage;
|
||||
|
||||
App::init(function ($utopia, $request, $response, $project, $user, $register, $events, $audits, $usage, $deletes) {
|
||||
App::init(function ($utopia, $request, $response, $project, $user, $register, $events, $audits, $usage, $deletes, $dbForInternal) {
|
||||
/** @var Utopia\App $utopia */
|
||||
/** @var Utopia\Swoole\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Appwrite\Database\Document $project */
|
||||
/** @var Appwrite\Database\Document $user */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Registry\Registry $register */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Event\Event $usage */
|
||||
/** @var Appwrite\Event\Event $deletes */
|
||||
/** @var Appwrite\Event\Event $functions */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
|
||||
Storage::setDevice('files', new Local(APP_STORAGE_UPLOADS.'/app-'.$project->getId()));
|
||||
Storage::setDevice('functions', new Local(APP_STORAGE_FUNCTIONS.'/app-'.$project->getId()));
|
||||
@@ -34,10 +35,7 @@ App::init(function ($utopia, $request, $response, $project, $user, $register, $e
|
||||
/*
|
||||
* Abuse Check
|
||||
*/
|
||||
$timeLimit = new TimeLimit($route->getLabel('abuse-key', 'url:{url},ip:{ip}'), $route->getLabel('abuse-limit', 0), $route->getLabel('abuse-time', 3600), function () use ($register) {
|
||||
return $register->get('db');
|
||||
});
|
||||
$timeLimit->setNamespace('app_'.$project->getId());
|
||||
$timeLimit = new TimeLimit($route->getLabel('abuse-key', 'url:{url},ip:{ip}'), $route->getLabel('abuse-limit', 0), $route->getLabel('abuse-time', 3600), $dbForInternal);
|
||||
$timeLimit
|
||||
->setParam('{userId}', $user->getId())
|
||||
->setParam('{userAgent}', $request->getUserAgent(''))
|
||||
@@ -67,7 +65,7 @@ App::init(function ($utopia, $request, $response, $project, $user, $register, $e
|
||||
$isAppUser = Auth::isAppUser(Authorization::$roles);
|
||||
|
||||
if (($abuse->check() // Route is rate-limited
|
||||
&& App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') !== 'disabled') // Abuse is not diabled
|
||||
&& App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') !== 'disabled') // Abuse is not disabled
|
||||
&& (!$isAppUser && !$isPrivilegedUser)) // User is not an admin or API key
|
||||
{
|
||||
throw new Exception('Too many requests', 429);
|
||||
@@ -111,7 +109,7 @@ App::init(function ($utopia, $request, $response, $project, $user, $register, $e
|
||||
->setParam('projectId', $project->getId())
|
||||
;
|
||||
|
||||
}, ['utopia', 'request', 'response', 'project', 'user', 'register', 'events', 'audits', 'usage', 'deletes'], 'api');
|
||||
}, ['utopia', 'request', 'response', 'project', 'user', 'register', 'events', 'audits', 'usage', 'deletes', 'dbForInternal'], 'api');
|
||||
|
||||
|
||||
App::init(function ($utopia, $request, $response, $project, $user) {
|
||||
|
||||
@@ -44,12 +44,12 @@ App::get('/')
|
||||
->label('permission', 'public')
|
||||
->label('scope', 'home')
|
||||
->inject('response')
|
||||
->inject('consoleDB')
|
||||
->inject('dbForConsole')
|
||||
->inject('project')
|
||||
->action(function ($response, $consoleDB, $project) {
|
||||
->action(function ($response, $dbForConsole, $project) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Appwrite\Database\Database $consoleDB */
|
||||
/** @var Appwrite\Database\Document $project */
|
||||
/** @var Utopia\Database\Database $dbForConsole */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
|
||||
$response
|
||||
->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
|
||||
@@ -61,13 +61,7 @@ App::get('/')
|
||||
$whitlistRoot = App::getEnv('_APP_CONSOLE_WHITELIST_ROOT', 'enabled');
|
||||
|
||||
if($whitlistRoot !== 'disabled') {
|
||||
$consoleDB->getCollection([ // Count users
|
||||
'filters' => [
|
||||
'$collection='.Database::SYSTEM_COLLECTION_USERS,
|
||||
],
|
||||
]);
|
||||
|
||||
$sum = $consoleDB->getSum();
|
||||
$sum = $dbForConsole->count('users', [], APP_LIMIT_USERS);
|
||||
|
||||
if($sum !== 0) {
|
||||
return $response->redirect('/auth/signin');
|
||||
@@ -239,6 +233,7 @@ App::get('/specs/:format')
|
||||
->groups(['web', 'home'])
|
||||
->label('scope', 'public')
|
||||
->label('docs', false)
|
||||
->label('origin', '*')
|
||||
->param('format', 'swagger2', new WhiteList(['swagger2', 'open-api3'], true), 'Spec format.', true)
|
||||
->param('platform', APP_PLATFORM_CLIENT, new WhiteList([APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER, APP_PLATFORM_CONSOLE], true), 'Choose target platform.', true)
|
||||
->param('tests', 0, function () {return new Range(0, 1);}, 'Include only test services.', true)
|
||||
|
||||
+62
-9
@@ -3,8 +3,6 @@
|
||||
require_once __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
use Appwrite\Database\Validator\Authorization;
|
||||
use Utopia\Swoole\Files;
|
||||
use Utopia\Swoole\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Swoole\Process;
|
||||
use Swoole\Http\Server;
|
||||
@@ -13,7 +11,11 @@ use Swoole\Http\Response as SwooleResponse;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Domains\Domain;
|
||||
use Utopia\Database\Validator\Authorization as Authorization2;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\Abuse\Adapters\TimeLimit;
|
||||
use Utopia\Swoole\Files;
|
||||
use Utopia\Swoole\Request;
|
||||
|
||||
// xdebug_start_trace('/tmp/trace');
|
||||
|
||||
@@ -51,7 +53,59 @@ $http->on('AfterReload', function($serv, $workerId) {
|
||||
Console::success('Reload completed...');
|
||||
});
|
||||
|
||||
$http->on('start', function (Server $http) use ($payloadSize) {
|
||||
Files::load(__DIR__ . '/../public');
|
||||
|
||||
include __DIR__ . '/controllers/general.php';
|
||||
|
||||
$http->on('start', function (Server $http) use ($payloadSize, $register) {
|
||||
$app = new App('UTC');
|
||||
$dbForConsole = $app->getResource('dbForConsole'); /** @var Utopia\Database\Database $dbForConsole */
|
||||
|
||||
if(!$dbForConsole->exists()) {
|
||||
Console::success('[Setup] - Server database init started...');
|
||||
|
||||
$collections = Config::getParam('collections2', []); /** @var array $collections */
|
||||
|
||||
$register->get('cache')->flushAll();
|
||||
|
||||
$dbForConsole->create();
|
||||
|
||||
$audit = new Audit($dbForConsole);
|
||||
$audit->setup();
|
||||
|
||||
$adapter = new TimeLimit("", 0, 1, $dbForConsole);
|
||||
$adapter->setup();
|
||||
|
||||
foreach ($collections as $key => $collection) {
|
||||
$dbForConsole->createCollection($key);
|
||||
|
||||
foreach ($collection['attributes'] as $i => $attribute) {
|
||||
$dbForConsole->createAttribute(
|
||||
$key,
|
||||
$attribute['$id'],
|
||||
$attribute['type'],
|
||||
$attribute['size'],
|
||||
$attribute['required'],
|
||||
$attribute['signed'],
|
||||
$attribute['array'],
|
||||
$attribute['filters'],
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($collection['indexes'] as $i => $index) {
|
||||
$dbForConsole->createIndex(
|
||||
$key,
|
||||
$index['$id'],
|
||||
$index['type'],
|
||||
$index['attributes'],
|
||||
$index['lengths'],
|
||||
$index['orders'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Console::success('[Setup] - Server database init completed...');
|
||||
}
|
||||
|
||||
Console::success('Server started succefully (max payload is '.number_format($payloadSize).' bytes)');
|
||||
|
||||
@@ -64,10 +118,6 @@ $http->on('start', function (Server $http) use ($payloadSize) {
|
||||
});
|
||||
});
|
||||
|
||||
Files::load(__DIR__ . '/../public');
|
||||
|
||||
include __DIR__ . '/controllers/general.php';
|
||||
|
||||
$http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swooleResponse) {
|
||||
$request = new Request($swooleRequest);
|
||||
$response = new Response($swooleResponse);
|
||||
@@ -89,7 +139,10 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
||||
|
||||
try {
|
||||
Authorization::cleanRoles();
|
||||
Authorization::setRole('*');
|
||||
Authorization::setRole('role:all');
|
||||
|
||||
Authorization2::cleanRoles();
|
||||
Authorization2::setRole('role:all');
|
||||
|
||||
$app->run($request, $response);
|
||||
} catch (\Throwable $th) {
|
||||
|
||||
+136
-30
@@ -30,6 +30,12 @@ use Utopia\Registry\Registry;
|
||||
use MaxMind\Db\Reader;
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use PDO as PDONative;
|
||||
use Utopia\Cache\Adapter\Redis as RedisCache;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\Database\Adapter\MariaDB;
|
||||
use Utopia\Database\Document as Document2;
|
||||
use Utopia\Database\Database as Database2;
|
||||
use Utopia\Database\Validator\Authorization as Authorization2;
|
||||
|
||||
const APP_NAME = 'Appwrite';
|
||||
const APP_DOMAIN = 'appwrite.io';
|
||||
@@ -39,6 +45,8 @@ const APP_USERAGENT = APP_NAME.'-Server v%s. Please report abuse at %s';
|
||||
const APP_MODE_DEFAULT = 'default';
|
||||
const APP_MODE_ADMIN = 'admin';
|
||||
const APP_PAGING_LIMIT = 12;
|
||||
const APP_LIMIT_COUNT = 5000;
|
||||
const APP_LIMIT_USERS = 10000;
|
||||
const APP_CACHE_BUSTER = 148;
|
||||
const APP_VERSION_STABLE = '0.8.0';
|
||||
const APP_STORAGE_UPLOADS = '/storage/uploads';
|
||||
@@ -80,6 +88,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
|
||||
@@ -142,6 +151,27 @@ Database::addFilter('encrypt',
|
||||
}
|
||||
);
|
||||
|
||||
Database2::addFilter('encrypt',
|
||||
function($value) {
|
||||
$key = App::getEnv('_APP_OPENSSL_KEY_V1');
|
||||
$iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM));
|
||||
$tag = null;
|
||||
return json_encode([
|
||||
'data' => OpenSSL::encrypt($value, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag),
|
||||
'method' => OpenSSL::CIPHER_AES_128_GCM,
|
||||
'iv' => bin2hex($iv),
|
||||
'tag' => bin2hex($tag),
|
||||
'version' => '1',
|
||||
]);
|
||||
},
|
||||
function($value) {
|
||||
$value = json_decode($value, true);
|
||||
$key = App::getEnv('_APP_OPENSSL_KEY_V'.$value['version']);
|
||||
|
||||
return OpenSSL::decrypt($value['data'], $value['method'], $key, 0, hex2bin($value['iv']), hex2bin($value['tag']));
|
||||
}
|
||||
);
|
||||
|
||||
/*
|
||||
* Registry
|
||||
*/
|
||||
@@ -381,15 +411,16 @@ 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);
|
||||
Authorization2::setDefaultStatus(true);
|
||||
|
||||
Auth::setCookieName('a_session_'.$project->getId());
|
||||
|
||||
@@ -411,37 +442,38 @@ 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);
|
||||
if ($project->isEmpty()) {
|
||||
$user = new Document2(['$id' => '', '$collection' => 'users']);
|
||||
}
|
||||
else {
|
||||
$user = $dbForInternal->getDocument('users', Auth::$unique);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$user = $consoleDB->getDocument(Auth::$unique);
|
||||
|
||||
$user
|
||||
->setAttribute('$id', 'admin-'.$user->getAttribute('$id'))
|
||||
;
|
||||
$user = $dbForConsole->getDocument('users', Auth::$unique);
|
||||
}
|
||||
|
||||
if (empty($user->getId()) // Check a document has been found in the DB
|
||||
|| Database::SYSTEM_COLLECTION_USERS !== $user->getCollection() // Validate returned document is really a user document
|
||||
if ($user->isEmpty() // Check a document has been found in the DB
|
||||
|| !Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret)) { // Validate user has valid login token
|
||||
$user = new Document(['$id' => '', '$collection' => Database::SYSTEM_COLLECTION_USERS]);
|
||||
$user = new Document2(['$id' => '', '$collection' => 'users']);
|
||||
}
|
||||
|
||||
if (APP_MODE_ADMIN === $mode) {
|
||||
if (!empty($user->search('teamId', $project->getAttribute('teamId'), $user->getAttribute('memberships')))) {
|
||||
if ($user->find('teamId', $project->getAttribute('teamId'), '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]);
|
||||
$user = new Document2(['$id' => '', '$collection' => 'users']);
|
||||
}
|
||||
}
|
||||
|
||||
$authJWT = $request->getHeader('x-appwrite-jwt', '');
|
||||
|
||||
if (!empty($authJWT)) { // JWT authentication
|
||||
if (!empty($authJWT) && !$project->isEmpty()) { // JWT authentication
|
||||
$jwt = new JWT(App::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway.
|
||||
|
||||
try {
|
||||
@@ -454,34 +486,81 @@ 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
|
||||
$user = new Document(['$id' => '', '$collection' => Database::SYSTEM_COLLECTION_USERS]);
|
||||
if (empty($user->find('$id', $jwtSessionId, 'sessions'))) { // Match JWT to active token
|
||||
$user = new Document2(['$id' => '', '$collection' => 'users']);
|
||||
}
|
||||
}
|
||||
|
||||
return $user;
|
||||
}, ['mode', 'project', 'console', 'request', 'response', 'projectDB', 'consoleDB']);
|
||||
}, ['mode', 'project', 'console', 'request', 'response', 'dbForInternal', 'dbForConsole']);
|
||||
|
||||
App::setResource('project', function($consoleDB, $request) {
|
||||
App::setResource('project', function($dbForConsole, $request, $console) {
|
||||
/** @var Utopia\Swoole\Request $request */
|
||||
/** @var Appwrite\Database\Database $consoleDB */
|
||||
/** @var Utopia\Database\Database $dbForConsole */
|
||||
/** @var Utopia\Database\Document $console */
|
||||
|
||||
$projectId = $request->getParam('project',
|
||||
$request->getHeader('x-appwrite-project', 'console'));
|
||||
|
||||
if($projectId === 'console') {
|
||||
return $console;
|
||||
}
|
||||
|
||||
Authorization::disable();
|
||||
Authorization2::disable();
|
||||
|
||||
$project = $consoleDB->getDocument($request->getParam('project',
|
||||
$request->getHeader('x-appwrite-project', '')));
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
Authorization::reset();
|
||||
Authorization2::reset();
|
||||
|
||||
return $project;
|
||||
}, ['consoleDB', 'request']);
|
||||
}, ['dbForConsole', 'request', 'console']);
|
||||
|
||||
App::setResource('console', function($consoleDB) {
|
||||
return $consoleDB->getDocument('console');
|
||||
}, ['consoleDB']);
|
||||
App::setResource('console', function() {
|
||||
return new Document2([
|
||||
'$id' => 'console',
|
||||
'$collection' => 'projects',
|
||||
'name' => 'Appwrite',
|
||||
'description' => 'Appwrite core engine',
|
||||
'logo' => '',
|
||||
'teamId' => -1,
|
||||
'webhooks' => [],
|
||||
'keys' => [],
|
||||
'platforms' => [
|
||||
[
|
||||
'$collection' => Database::SYSTEM_COLLECTION_PLATFORMS,
|
||||
'name' => 'Production',
|
||||
'type' => 'web',
|
||||
'hostname' => 'appwrite.io',
|
||||
],
|
||||
[
|
||||
'$collection' => Database::SYSTEM_COLLECTION_PLATFORMS,
|
||||
'name' => 'Development',
|
||||
'type' => 'web',
|
||||
'hostname' => 'appwrite.test',
|
||||
],
|
||||
[
|
||||
'$collection' => Database::SYSTEM_COLLECTION_PLATFORMS,
|
||||
'name' => 'Localhost',
|
||||
'type' => 'web',
|
||||
'hostname' => 'localhost',
|
||||
], // Current host is added on app init
|
||||
],
|
||||
'legalName' => '',
|
||||
'legalCountry' => '',
|
||||
'legalState' => '',
|
||||
'legalCity' => '',
|
||||
'legalAddress' => '',
|
||||
'legalTaxId' => '',
|
||||
'authWhitelistEmails' => (!empty(App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null)) : [],
|
||||
'authWhitelistIPs' => (!empty(App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null))) ? \explode(',', App::getEnv('_APP_CONSOLE_WHITELIST_IPS', null)) : [],
|
||||
'usersAuthLimit' => (App::getEnv('_APP_CONSOLE_WHITELIST_ROOT', 'enabled') === 'enabled') ? 1 : 0, // limit signup to 1 user
|
||||
]);
|
||||
}, []);
|
||||
|
||||
App::setResource('consoleDB', function($register) {
|
||||
$consoleDB = new Database();
|
||||
@@ -501,6 +580,33 @@ App::setResource('projectDB', function($register, $project) {
|
||||
return $projectDB;
|
||||
}, ['register', 'project']);
|
||||
|
||||
App::setResource('dbForInternal', function($register, $project) {
|
||||
$cache = new Cache(new RedisCache($register->get('cache')));
|
||||
|
||||
$database = new Database2(new MariaDB($register->get('db')), $cache);
|
||||
$database->setNamespace('project_'.$project->getId().'_internal');
|
||||
|
||||
return $database;
|
||||
}, ['register', 'project']);
|
||||
|
||||
App::setResource('dbForExternal', function($register, $project) {
|
||||
$cache = new Cache(new RedisCache($register->get('cache')));
|
||||
|
||||
$database = new Database2(new MariaDB($register->get('db')), $cache);
|
||||
$database->setNamespace('project_'.$project->getId().'_external');
|
||||
|
||||
return $database;
|
||||
}, ['register', 'project']);
|
||||
|
||||
App::setResource('dbForConsole', function($register) {
|
||||
$cache = new Cache(new RedisCache($register->get('cache')));
|
||||
|
||||
$database = new Database2(new MariaDB($register->get('db')), $cache);
|
||||
$database->setNamespace('project_console_internal');
|
||||
|
||||
return $database;
|
||||
}, ['register']);
|
||||
|
||||
App::setResource('mode', function($request) {
|
||||
/** @var Utopia\Swoole\Request $request */
|
||||
return $request->getParam('mode', $request->getHeader('x-appwrite-mode', APP_MODE_DEFAULT));
|
||||
|
||||
@@ -32,6 +32,7 @@ foreach ([
|
||||
realpath(__DIR__ . '/../vendor/psr/log'),
|
||||
realpath(__DIR__ . '/../vendor/matomo'),
|
||||
realpath(__DIR__ . '/../vendor/symfony'),
|
||||
realpath(__DIR__ . '/../vendor/mongodb'),
|
||||
] as $key => $value) {
|
||||
if($value !== false) {
|
||||
$preloader->ignore($value);
|
||||
|
||||
@@ -58,7 +58,7 @@ $smtpEnabled = $this->getParam('smtpEnabled', false);
|
||||
<label for="logo">Project Logo</label>
|
||||
|
||||
<div class="text-align-center clear">
|
||||
<input type="hidden" name="logo" data-ls-bind="{{console-project.logo}}" data-read="<?php echo $this->escape(json_encode(['*'])); ?>" data-write="<?php echo $this->escape(json_encode(['team:{{console-project.teamId}}'])); ?>" data-accept="image/*" data-forms-upload="" data-label-button="Upload" data-preview-alt="Project Logo" data-scope="console" data-default="">
|
||||
<input type="hidden" name="logo" data-ls-bind="{{console-project.logo}}" data-read="<?php echo $this->escape(json_encode(['role:all'])); ?>" data-write="<?php echo $this->escape(json_encode(['team:{{console-project.teamId}}'])); ?>" data-accept="image/*" data-forms-upload="" data-label-button="Upload" data-preview-alt="Project Logo" data-scope="console" data-default="">
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
@@ -106,11 +106,11 @@ $fileLimitHuman = $this->getParam('fileLimitHuman', 0);
|
||||
<input type="hidden" data-ls-attrs="id=file-folderId-{{file.$id}}" name="folderId" data-cast-to="integer" value="1">
|
||||
|
||||
<label for="file-read">Read Access (<a data-ls-attrs="href={{env.HOME}}/docs/permissions" target="_blank" rel="noopener">Learn more</a>)</label>
|
||||
<input type="hidden" data-ls-attrs="id=file-read-{{file.$id}}" name="read" data-forms-tags data-cast-to="json" data-ls-bind="{{file.$permissions.read}}" placeholder="User ID, Team ID or Role" />
|
||||
<input type="hidden" data-ls-attrs="id=file-read-{{file.$id}}" name="read" data-forms-tags data-cast-to="json" data-ls-bind="{{file.$read}}" placeholder="User ID, Team ID or Role" />
|
||||
<div class="text-fade text-size-xs margin-top-negative-small margin-bottom">Add * for wildcard access</div>
|
||||
|
||||
<label for="file-write">Write Access (<a data-ls-attrs="href={{env.HOME}}/docs/permissions" target="_blank" rel="noopener">Learn more</a>)</label>
|
||||
<input type="hidden" data-ls-attrs="id=file-write-{{file.$id}}" name="write" data-forms-tags data-cast-to="json" data-ls-bind="{{file.$permissions.write}}" placeholder="User ID, Team ID or Role" />
|
||||
<input type="hidden" data-ls-attrs="id=file-write-{{file.$id}}" name="write" data-forms-tags data-cast-to="json" data-ls-bind="{{file.$write}}" placeholder="User ID, Team ID or Role" />
|
||||
<div class="text-fade text-size-xs margin-top-negative-small margin-bottom">Add * for wildcard access</div>
|
||||
</form>
|
||||
|
||||
@@ -243,7 +243,7 @@ $fileLimitHuman = $this->getParam('fileLimitHuman', 0);
|
||||
<div class="text-fade text-size-xs margin-top-negative-small margin-bottom">(Max file size allowed: <?php echo $fileLimitHuman; ?>)</div>
|
||||
|
||||
<label for="file-read">Read Access (<a data-ls-attrs="href={{env.HOME}}/docs/permissions" target="_blank" rel="noopener">Learn more</a>)</label>
|
||||
<input type="hidden" id="file-read" name="read" data-forms-tags data-cast-to="json" value="<?php echo htmlentities(json_encode(['*'])); ?>" placeholder="User ID, Team ID or Role" />
|
||||
<input type="hidden" id="file-read" name="read" data-forms-tags data-cast-to="json" value="<?php echo htmlentities(json_encode(['role:all'])); ?>" placeholder="User ID, Team ID or Role" />
|
||||
<div class="text-fade text-size-xs margin-top-negative-small margin-bottom">Add * for wildcard access</div>
|
||||
|
||||
<label for="file-write">Write Access (<a data-ls-attrs="href={{env.HOME}}/docs/permissions" target="_blank" rel="noopener">Learn more</a>)</label>
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
|
||||
use Appwrite\Resque\Worker;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\Audit\Adapters\MySQL as AuditAdapter;
|
||||
use Utopia\Cache\Adapter\Redis;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Adapter\MariaDB;
|
||||
use Utopia\Database\Database;
|
||||
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
@@ -31,10 +34,11 @@ class AuditsV1 extends Worker
|
||||
$data = $this->args['data'];
|
||||
$db = $register->get('db', true);
|
||||
|
||||
$adapter = new AuditAdapter($db);
|
||||
$adapter->setNamespace('app_'.$projectId);
|
||||
$cache = new Cache(new Redis($register->get('cache')));
|
||||
$dbForInternal = new Database(new MariaDB($db), $cache);
|
||||
$dbForInternal->setNamespace('project_'.$projectId.'_internal');
|
||||
|
||||
$audit = new Audit($adapter);
|
||||
$audit = new Audit($dbForInternal);
|
||||
|
||||
$audit->log($userId, $event, $resource, $userAgent, $ip, '', $data);
|
||||
}
|
||||
|
||||
+28
-16
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Appwrite\Database\Database;
|
||||
use Utopia\Database\Database as Database2;
|
||||
use Utopia\Cache\Adapter\Redis as RedisCache;
|
||||
use Appwrite\Database\Adapter\MySQL as MySQLAdapter;
|
||||
use Appwrite\Database\Adapter\Redis as RedisAdapter;
|
||||
use Appwrite\Database\Document;
|
||||
@@ -12,7 +14,8 @@ use Utopia\Abuse\Adapters\TimeLimit;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Audit\Audit;
|
||||
use Utopia\Audit\Adapters\MySQL as AuditAdapter;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\Database\Adapter\MariaDB;
|
||||
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
@@ -31,14 +34,15 @@ class DeletesV1 extends Worker
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
$projectId = isset($this->args['projectId']) ? $this->args['projectId'] : '';
|
||||
$type = $this->args['type'];
|
||||
$projectId = $this->args['projectId'] ?? '';
|
||||
$type = $this->args['type'] ?? '';
|
||||
|
||||
switch (strval($type)) {
|
||||
case DELETE_TYPE_DOCUMENT:
|
||||
$document = $this->args['document'];
|
||||
$document = $this->args['document'] ?? '';
|
||||
$document = new Document($document);
|
||||
switch (strval($document->getCollection())) {
|
||||
|
||||
switch ($document->getCollection()) {
|
||||
case Database::SYSTEM_COLLECTION_PROJECTS:
|
||||
$this->deleteProject($document);
|
||||
break;
|
||||
@@ -77,7 +81,6 @@ class DeletesV1 extends Worker
|
||||
default:
|
||||
Console::error('No delete operation for type: '.$type);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,12 +168,9 @@ class DeletesV1 extends Worker
|
||||
throw new Exception('Failed to delete audit logs. No timestamp provided');
|
||||
}
|
||||
|
||||
$timeLimit = new TimeLimit("", 0, 1, function () use ($register) {
|
||||
return $register->get('db');
|
||||
});
|
||||
|
||||
$this->deleteForProjectIds(function($projectId) use ($timeLimit, $timestamp){
|
||||
$timeLimit->setNamespace('app_'.$projectId);
|
||||
|
||||
$this->deleteForProjectIds(function($projectId) use ($timestamp){
|
||||
$timeLimit = new TimeLimit("", 0, 1, $this->getInternalDB($projectId));
|
||||
$abuse = new Abuse($timeLimit);
|
||||
|
||||
$status = $abuse->cleanup($timestamp);
|
||||
@@ -187,9 +187,7 @@ class DeletesV1 extends Worker
|
||||
throw new Exception('Failed to delete audit logs. No timestamp provided');
|
||||
}
|
||||
$this->deleteForProjectIds(function($projectId) use ($register, $timestamp){
|
||||
$adapter = new AuditAdapter($register->get('db'));
|
||||
$adapter->setNamespace('app_'.$projectId);
|
||||
$audit = new Audit($adapter);
|
||||
$audit = new Audit($this->getInternalDB($projectId));
|
||||
$status = $audit->cleanup($timestamp);
|
||||
if (!$status) {
|
||||
throw new Exception('Failed to delete Audit logs for project'.$projectId);
|
||||
@@ -373,4 +371,18 @@ class DeletesV1 extends Worker
|
||||
|
||||
return $projectDB;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Database2
|
||||
*/
|
||||
protected function getInternalDB($projectId): Database2
|
||||
{
|
||||
global $register;
|
||||
|
||||
$cache = new Cache(new RedisCache($register->get('cache')));
|
||||
$dbForInternal = new Database2(new MariaDB($register->get('db')), $cache);
|
||||
$dbForInternal->setNamespace('project_'.$projectId.'_internal'); // Main DB
|
||||
|
||||
return $dbForInternal;
|
||||
}
|
||||
}
|
||||
|
||||
+27
-43
@@ -1,17 +1,18 @@
|
||||
<?php
|
||||
|
||||
use Appwrite\Database\Database;
|
||||
use Appwrite\Database\Document;
|
||||
use Appwrite\Database\Adapter\MySQL as MySQLAdapter;
|
||||
use Appwrite\Database\Adapter\Redis as RedisAdapter;
|
||||
use Appwrite\Database\Validator\Authorization;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Resque\Worker;
|
||||
use Cron\CronExpression;
|
||||
use Swoole\Runtime;
|
||||
use Utopia\App;
|
||||
use Utopia\Cache\Adapter\Redis;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Adapter\MariaDB;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
|
||||
require_once __DIR__.'/../init.php';
|
||||
|
||||
@@ -152,10 +153,9 @@ class FunctionsV1 extends Worker
|
||||
$userId = $this->args['userId'] ?? '';
|
||||
$jwt = $this->args['jwt'] ?? '';
|
||||
|
||||
$database = new Database();
|
||||
$database->setAdapter(new RedisAdapter(new MySQLAdapter($register), $register));
|
||||
$database->setNamespace('app_'.$projectId);
|
||||
$database->setMocks(Config::getParam('collections', []));
|
||||
$cache = new Cache(new Redis($register->get('cache')));
|
||||
$database = new Database(new MariaDB($register->get('db')), $cache);
|
||||
$database->setNamespace('project_'.$projectId.'_internal');
|
||||
|
||||
switch ($trigger) {
|
||||
case 'event':
|
||||
@@ -168,16 +168,7 @@ class FunctionsV1 extends Worker
|
||||
|
||||
Authorization::disable();
|
||||
|
||||
$functions = $database->getCollection([
|
||||
'limit' => $limit,
|
||||
'offset' => $offset,
|
||||
'orderField' => 'name',
|
||||
'orderType' => 'ASC',
|
||||
'orderCast' => 'string',
|
||||
'filters' => [
|
||||
'$collection='.Database::SYSTEM_COLLECTION_FUNCTIONS,
|
||||
],
|
||||
]);
|
||||
$functions = $database->find('functions', [], $limit, $offset, ['name'], [Database::ORDER_ASC]);
|
||||
|
||||
Authorization::reset();
|
||||
|
||||
@@ -219,10 +210,10 @@ class FunctionsV1 extends Worker
|
||||
|
||||
// Reschedule
|
||||
Authorization::disable();
|
||||
$function = $database->getDocument($functionId);
|
||||
$function = $database->getDocument('functions', $functionId);
|
||||
Authorization::reset();
|
||||
|
||||
if (empty($function->getId()) || Database::SYSTEM_COLLECTION_FUNCTIONS != $function->getCollection()) {
|
||||
if (empty($function->getId())) {
|
||||
throw new Exception('Function not found ('.$functionId.')');
|
||||
}
|
||||
|
||||
@@ -240,9 +231,9 @@ class FunctionsV1 extends Worker
|
||||
|
||||
Authorization::disable();
|
||||
|
||||
$function = $database->updateDocument(array_merge($function->getArrayCopy(), [
|
||||
'scheduleNext' => $next,
|
||||
]));
|
||||
$function = $database->updateDocument('functions', $function->getId(), new Document(array_merge($function->getArrayCopy(), [
|
||||
'scheduleNext' => (int)$next,
|
||||
])));
|
||||
|
||||
Authorization::reset();
|
||||
|
||||
@@ -260,10 +251,10 @@ class FunctionsV1 extends Worker
|
||||
|
||||
case 'http':
|
||||
Authorization::disable();
|
||||
$function = $database->getDocument($functionId);
|
||||
$function = $database->getDocument('functions', $functionId);
|
||||
Authorization::reset();
|
||||
|
||||
if (empty($function->getId()) || Database::SYSTEM_COLLECTION_FUNCTIONS != $function->getCollection()) {
|
||||
if (empty($function->getId())) {
|
||||
throw new Exception('Function not found ('.$functionId.')');
|
||||
}
|
||||
|
||||
@@ -300,7 +291,7 @@ class FunctionsV1 extends Worker
|
||||
$runtimes = Config::getParam('runtimes');
|
||||
|
||||
Authorization::disable();
|
||||
$tag = $database->getDocument($function->getAttribute('tag', ''));
|
||||
$tag = $database->getDocument('tags', $function->getAttribute('tag', ''));
|
||||
Authorization::reset();
|
||||
|
||||
if($tag->getAttribute('functionId') !== $function->getId()) {
|
||||
@@ -309,12 +300,9 @@ class FunctionsV1 extends Worker
|
||||
|
||||
Authorization::disable();
|
||||
|
||||
$execution = (!empty($executionId)) ? $database->getDocument($executionId) : $database->createDocument([
|
||||
'$collection' => Database::SYSTEM_COLLECTION_EXECUTIONS,
|
||||
'$permissions' => [
|
||||
'read' => [],
|
||||
'write' => [],
|
||||
],
|
||||
$execution = (!empty($executionId)) ? $database->getDocument('executions', $executionId) : $database->createDocument('executions', new Document([
|
||||
'$read' => [],
|
||||
'$write' => [],
|
||||
'dateCreated' => time(),
|
||||
'functionId' => $function->getId(),
|
||||
'trigger' => $trigger, // http / schedule / event
|
||||
@@ -323,7 +311,7 @@ class FunctionsV1 extends Worker
|
||||
'stdout' => '',
|
||||
'stderr' => '',
|
||||
'time' => 0,
|
||||
]);
|
||||
]));
|
||||
|
||||
if(false === $execution || ($execution instanceof Document && $execution->isEmpty())) {
|
||||
throw new Exception('Failed to create or read execution');
|
||||
@@ -465,21 +453,17 @@ class FunctionsV1 extends Worker
|
||||
|
||||
Authorization::disable();
|
||||
|
||||
$execution = $database->updateDocument(array_merge($execution->getArrayCopy(), [
|
||||
$execution = $database->updateDocument('executions', $execution->getId(), new Document(array_merge($execution->getArrayCopy(), [
|
||||
'tagId' => $tag->getId(),
|
||||
'status' => $functionStatus,
|
||||
'exitCode' => $exitCode,
|
||||
'stdout' => \mb_substr($stdout, -4000), // log last 4000 chars output
|
||||
'stderr' => \mb_substr($stderr, -4000), // log last 4000 chars output
|
||||
'time' => $executionTime,
|
||||
]));
|
||||
'stdout' => \mb_substr($stdout, -8000), // log last 4000 chars output
|
||||
'stderr' => \mb_substr($stderr, -8000), // log last 4000 chars output
|
||||
'time' => (float)$executionTime,
|
||||
])));
|
||||
|
||||
Authorization::reset();
|
||||
|
||||
if (false === $function) {
|
||||
throw new Exception('Failed saving execution to DB', 500);
|
||||
}
|
||||
|
||||
$executionUpdate = new Event('v1-webhooks', 'WebhooksV1');
|
||||
|
||||
$executionUpdate
|
||||
|
||||
+14
-3
@@ -39,12 +39,13 @@
|
||||
"appwrite/php-runtimes": "0.2.*",
|
||||
|
||||
"utopia-php/framework": "0.14.*",
|
||||
"utopia-php/abuse": "0.4.*",
|
||||
"utopia-php/abuse": "dev-feat-utopia-db-integration",
|
||||
"utopia-php/analytics": "0.2.*",
|
||||
"utopia-php/audit": "0.5.*",
|
||||
"utopia-php/cache": "0.2.*",
|
||||
"utopia-php/audit": "dev-feat-utopia-db-integration",
|
||||
"utopia-php/cache": "0.4.*",
|
||||
"utopia-php/cli": "0.11.*",
|
||||
"utopia-php/config": "0.2.*",
|
||||
"utopia-php/database": "0.3.*",
|
||||
"utopia-php/locale": "0.3.*",
|
||||
"utopia-php/registry": "0.4.*",
|
||||
"utopia-php/preloader": "0.2.*",
|
||||
@@ -61,6 +62,16 @@
|
||||
"adhocore/jwt": "1.1.2",
|
||||
"slickdeals/statsd": "3.0.2"
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/lohanidamodar/audit"
|
||||
},
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/lohanidamodar/abuse"
|
||||
}
|
||||
],
|
||||
"require-dev": {
|
||||
"appwrite/sdk-generator": "0.10.11",
|
||||
"swoole/ide-helper": "4.6.6",
|
||||
|
||||
Generated
+388
-218
@@ -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": "399d2426ca92e04b6d6fb84a91c316c3",
|
||||
"content-hash": "bce8a47d7c5e94cc18bd05b1229ad1db",
|
||||
"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.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/package-versions-deprecated.git",
|
||||
"reference": "c6522afe5540d5fc46675043d3ed5a45a740b27c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/c6522afe5540d5fc46675043d3ed5a45a740b27c",
|
||||
"reference": "c6522afe5540d5fc46675043d3ed5a45a740b27c",
|
||||
"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.2"
|
||||
},
|
||||
"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": "2021-05-24T07:46:03+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",
|
||||
@@ -1323,22 +1519,100 @@
|
||||
"time": "2021-02-19T12:13:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/abuse",
|
||||
"version": "0.4.1",
|
||||
"name": "symfony/polyfill-php80",
|
||||
"version": "v1.23.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/abuse.git",
|
||||
"reference": "8b7973aae4b02489bd22ffea45b985608f13b6d9"
|
||||
"url": "https://github.com/symfony/polyfill-php80.git",
|
||||
"reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/8b7973aae4b02489bd22ffea45b985608f13b6d9",
|
||||
"reference": "8b7973aae4b02489bd22ffea45b985608f13b6d9",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/eca0bf41ed421bed1b57c4958bab16aa86b757d0",
|
||||
"reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.23-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.23.0"
|
||||
},
|
||||
"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-02-19T12:13:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/abuse",
|
||||
"version": "dev-feat-utopia-db-integration",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/lohanidamodar/abuse",
|
||||
"reference": "351dba60714321fabcd5028fdf7325f18f343018"
|
||||
},
|
||||
"require": {
|
||||
"ext-pdo": "*",
|
||||
"php": ">=7.4"
|
||||
"php": ">=7.4",
|
||||
"utopia-php/database": "0.3.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.4",
|
||||
@@ -1350,7 +1624,6 @@
|
||||
"Utopia\\Abuse\\": "src/Abuse"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
@@ -1362,17 +1635,13 @@
|
||||
],
|
||||
"description": "A simple abuse library to manage application usage limits",
|
||||
"keywords": [
|
||||
"Abuse",
|
||||
"abuse",
|
||||
"framework",
|
||||
"php",
|
||||
"upf",
|
||||
"utopia"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/abuse/issues",
|
||||
"source": "https://github.com/utopia-php/abuse/tree/0.4.1"
|
||||
},
|
||||
"time": "2021-06-05T14:31:33+00:00"
|
||||
"time": "2021-06-13T07:41:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/analytics",
|
||||
@@ -1431,21 +1700,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/audit",
|
||||
"version": "0.5.1",
|
||||
"version": "dev-feat-utopia-db-integration",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/audit.git",
|
||||
"reference": "154a850170a58667a15e4b65fbabb6cd0b709dd9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/audit/zipball/154a850170a58667a15e4b65fbabb6cd0b709dd9",
|
||||
"reference": "154a850170a58667a15e4b65fbabb6cd0b709dd9",
|
||||
"shasum": ""
|
||||
"url": "https://github.com/lohanidamodar/audit",
|
||||
"reference": "b3ca9fa928fdec8c966596cbd85ee1141c79b6eb"
|
||||
},
|
||||
"require": {
|
||||
"ext-pdo": "*",
|
||||
"php": ">=7.1"
|
||||
"php": ">=7.4",
|
||||
"utopia-php/database": "0.3.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.3",
|
||||
@@ -1457,7 +1721,6 @@
|
||||
"Utopia\\Audit\\": "src/Audit"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
@@ -1469,35 +1732,32 @@
|
||||
],
|
||||
"description": "A simple audit library to manage application users logs",
|
||||
"keywords": [
|
||||
"Audit",
|
||||
"audit",
|
||||
"framework",
|
||||
"php",
|
||||
"upf",
|
||||
"utopia"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/audit/issues",
|
||||
"source": "https://github.com/utopia-php/audit/tree/0.5.1"
|
||||
},
|
||||
"time": "2020-12-21T17:28:53+00:00"
|
||||
"time": "2021-06-13T07:41:15+00:00"
|
||||
},
|
||||
{
|
||||
"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 +1789,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 +1897,69 @@
|
||||
},
|
||||
"time": "2020-10-24T09:49:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/database",
|
||||
"version": "0.3.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/database.git",
|
||||
"reference": "8e56a2d399d17b2497c8ee0f8bf429ac2da90c56"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/8e56a2d399d17b2497c8ee0f8bf429ac2da90c56",
|
||||
"reference": "8e56a2d399d17b2497c8ee0f8bf429ac2da90c56",
|
||||
"shasum": ""
|
||||
},
|
||||
"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": {
|
||||
"fakerphp/faker": "^1.14",
|
||||
"phpunit/phpunit": "^9.4",
|
||||
"utopia-php/cli": "^0.11.0",
|
||||
"vimeo/psalm": "4.0.1"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Utopia\\Database\\": "src/Database"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"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"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/database/issues",
|
||||
"source": "https://github.com/utopia-php/database/tree/0.3.2"
|
||||
},
|
||||
"time": "2021-06-12T18:26:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/domains",
|
||||
"version": "v1.1.0",
|
||||
@@ -2387,79 +2710,6 @@
|
||||
},
|
||||
"time": "2021-06-07T11:37:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/package-versions-deprecated",
|
||||
"version": "1.11.99.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/package-versions-deprecated.git",
|
||||
"reference": "c6522afe5540d5fc46675043d3ed5a45a740b27c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/c6522afe5540d5fc46675043d3ed5a45a740b27c",
|
||||
"reference": "c6522afe5540d5fc46675043d3ed5a45a740b27c",
|
||||
"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.2"
|
||||
},
|
||||
"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": "2021-05-24T07:46:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/semver",
|
||||
"version": "3.2.5",
|
||||
@@ -2713,20 +2963,20 @@
|
||||
},
|
||||
{
|
||||
"name": "felixfbecker/advanced-json-rpc",
|
||||
"version": "v3.2.0",
|
||||
"version": "v3.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/felixfbecker/php-advanced-json-rpc.git",
|
||||
"reference": "06f0b06043c7438959dbdeed8bb3f699a19be22e"
|
||||
"reference": "b5f37dbff9a8ad360ca341f3240dc1c168b45447"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/06f0b06043c7438959dbdeed8bb3f699a19be22e",
|
||||
"reference": "06f0b06043c7438959dbdeed8bb3f699a19be22e",
|
||||
"url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/b5f37dbff9a8ad360ca341f3240dc1c168b45447",
|
||||
"reference": "b5f37dbff9a8ad360ca341f3240dc1c168b45447",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"netresearch/jsonmapper": "^1.0 || ^2.0",
|
||||
"netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0",
|
||||
"php": "^7.1 || ^8.0",
|
||||
"phpdocumentor/reflection-docblock": "^4.3.4 || ^5.0.0"
|
||||
},
|
||||
@@ -2752,9 +3002,9 @@
|
||||
"description": "A more advanced JSONRPC implementation",
|
||||
"support": {
|
||||
"issues": "https://github.com/felixfbecker/php-advanced-json-rpc/issues",
|
||||
"source": "https://github.com/felixfbecker/php-advanced-json-rpc/tree/v3.2.0"
|
||||
"source": "https://github.com/felixfbecker/php-advanced-json-rpc/tree/v3.2.1"
|
||||
},
|
||||
"time": "2021-01-10T17:48:47+00:00"
|
||||
"time": "2021-06-11T22:34:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "felixfbecker/language-server-protocol",
|
||||
@@ -3003,16 +3253,16 @@
|
||||
},
|
||||
{
|
||||
"name": "netresearch/jsonmapper",
|
||||
"version": "v2.1.0",
|
||||
"version": "v4.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/cweiske/jsonmapper.git",
|
||||
"reference": "e0f1e33a71587aca81be5cffbb9746510e1fe04e"
|
||||
"reference": "8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/e0f1e33a71587aca81be5cffbb9746510e1fe04e",
|
||||
"reference": "e0f1e33a71587aca81be5cffbb9746510e1fe04e",
|
||||
"url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d",
|
||||
"reference": "8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3020,10 +3270,10 @@
|
||||
"ext-pcre": "*",
|
||||
"ext-reflection": "*",
|
||||
"ext-spl": "*",
|
||||
"php": ">=5.6"
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.8.35 || ~5.7 || ~6.4 || ~7.0",
|
||||
"phpunit/phpunit": "~7.5 || ~8.0 || ~9.0",
|
||||
"squizlabs/php_codesniffer": "~3.5"
|
||||
},
|
||||
"type": "library",
|
||||
@@ -3048,9 +3298,9 @@
|
||||
"support": {
|
||||
"email": "cweiske@cweiske.de",
|
||||
"issues": "https://github.com/cweiske/jsonmapper/issues",
|
||||
"source": "https://github.com/cweiske/jsonmapper/tree/master"
|
||||
"source": "https://github.com/cweiske/jsonmapper/tree/v4.0.0"
|
||||
},
|
||||
"time": "2020-04-16T18:48:43+00:00"
|
||||
"time": "2020-12-01T19:48:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
@@ -4472,16 +4722,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/global-state",
|
||||
"version": "5.0.2",
|
||||
"version": "5.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/global-state.git",
|
||||
"reference": "a90ccbddffa067b51f574dea6eb25d5680839455"
|
||||
"reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/a90ccbddffa067b51f574dea6eb25d5680839455",
|
||||
"reference": "a90ccbddffa067b51f574dea6eb25d5680839455",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/23bd5951f7ff26f12d4e3242864df3e08dec4e49",
|
||||
"reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4524,7 +4774,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/global-state/issues",
|
||||
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.2"
|
||||
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -4532,7 +4782,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-10-26T15:55:19+00:00"
|
||||
"time": "2021-06-11T13:31:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/lines-of-code",
|
||||
@@ -5471,89 +5721,6 @@
|
||||
],
|
||||
"time": "2021-02-19T12:13:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php80",
|
||||
"version": "v1.23.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php80.git",
|
||||
"reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/eca0bf41ed421bed1b57c4958bab16aa86b757d0",
|
||||
"reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.23-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.23.0"
|
||||
},
|
||||
"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-02-19T12:13:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/service-contracts",
|
||||
"version": "v2.4.0",
|
||||
@@ -6003,7 +6170,10 @@
|
||||
],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"stability-flags": {
|
||||
"utopia-php/abuse": 20,
|
||||
"utopia-php/audit": 20
|
||||
},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
@@ -6025,5 +6195,5 @@
|
||||
"platform-overrides": {
|
||||
"php": "8.0"
|
||||
},
|
||||
"plugin-api-version": "2.1.0"
|
||||
"plugin-api-version": "2.0.0"
|
||||
}
|
||||
|
||||
+13
-2
@@ -62,7 +62,7 @@ services:
|
||||
- ./psalm.xml:/usr/src/code/psalm.xml
|
||||
- ./tests:/usr/src/code/tests
|
||||
- ./app:/usr/src/code/app
|
||||
# - ./vendor:/usr/src/code/vendor
|
||||
# - ./vendor/utopia-php/database:/usr/src/code/vendor/utopia-php/database
|
||||
- ./docs:/usr/src/code/docs
|
||||
- ./public:/usr/src/code/public
|
||||
- ./src:/usr/src/code/src
|
||||
@@ -388,7 +388,7 @@ services:
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=password
|
||||
- MYSQL_DATABASE=${_APP_DB_SCHEMA}
|
||||
- MYSQL_USER=${_APP_DB_USER}
|
||||
- MYSQL_USER=user
|
||||
- MYSQL_PASSWORD=${_APP_DB_PASS}
|
||||
command: 'mysqld --innodb-flush-method=fsync' # add ' --query_cache_size=0' for DB tests
|
||||
# command: mv /var/lib/mysql/ib_logfile0 /var/lib/mysql/ib_logfile0.bu && mv /var/lib/mysql/ib_logfile1 /var/lib/mysql/ib_logfile1.bu
|
||||
@@ -476,6 +476,17 @@ services:
|
||||
networks:
|
||||
- appwrite
|
||||
|
||||
swagger-validator:
|
||||
image: 'swaggerapi/swagger-validator-v2:v2.0.5'
|
||||
container_name: appwrite-swagger-validator
|
||||
ports:
|
||||
- '9506:8080'
|
||||
environment:
|
||||
- REJECT_LOCAL=false
|
||||
- REJECT_REDIRECT=false
|
||||
networks:
|
||||
- appwrite
|
||||
|
||||
# redis-commander:
|
||||
# image: rediscommander/redis-commander:latest
|
||||
# restart: unless-stopped
|
||||
|
||||
@@ -44,7 +44,7 @@ MultipartFile file = MultipartFile.fromFile('./path-to-file/image.jpg', filename
|
||||
|
||||
storage.createFile(
|
||||
file: file,
|
||||
read: ['*'],
|
||||
read: ['role:all'],
|
||||
write: []
|
||||
)
|
||||
.then((response) {
|
||||
|
||||
@@ -41,7 +41,7 @@ MultipartFile file = MultipartFile.fromFile('./path-to-file/image.jpg', filename
|
||||
|
||||
storage.createFile(
|
||||
file: file,
|
||||
read: ['*'],
|
||||
read: ['role:all'],
|
||||
write: []
|
||||
)
|
||||
.then((response) {
|
||||
|
||||
@@ -41,7 +41,7 @@ MultipartFile file = MultipartFile.fromFile('./path-to-file/image.jpg', filename
|
||||
|
||||
storage.createFile(
|
||||
file: file,
|
||||
read: ['*'],
|
||||
read: ['role:all'],
|
||||
write: []
|
||||
)
|
||||
.then((response) {
|
||||
|
||||
@@ -16,6 +16,7 @@ class Auth
|
||||
/**
|
||||
* User Roles.
|
||||
*/
|
||||
const USER_ROLE_ALL = 'all';
|
||||
const USER_ROLE_GUEST = 'guest';
|
||||
const USER_ROLE_MEMBER = 'member';
|
||||
const USER_ROLE_ADMIN = 'admin';
|
||||
@@ -23,7 +24,6 @@ class Auth
|
||||
const USER_ROLE_OWNER = 'owner';
|
||||
const USER_ROLE_APP = 'app';
|
||||
const USER_ROLE_SYSTEM = 'system';
|
||||
const USER_ROLE_ALL = '*';
|
||||
|
||||
/**
|
||||
* Token Types.
|
||||
|
||||
@@ -10,7 +10,7 @@ class Authorization extends Validator
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
static $roles = ['*' => true];
|
||||
static $roles = ['role:all' => true];
|
||||
|
||||
/**
|
||||
* @var Document
|
||||
|
||||
@@ -59,6 +59,42 @@ class PDO extends PDONative
|
||||
return $this->pdo->quote($string, $parameter_type);
|
||||
}
|
||||
|
||||
public function beginTransaction()
|
||||
{
|
||||
try {
|
||||
$result = $this->pdo->beginTransaction();
|
||||
} catch (\Throwable $th) {
|
||||
$this->pdo = $this->reconnect();
|
||||
$result = $this->pdo->beginTransaction();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function rollBack()
|
||||
{
|
||||
try {
|
||||
$result = $this->pdo->rollBack();
|
||||
} catch (\Throwable $th) {
|
||||
$this->pdo = $this->reconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function commit()
|
||||
{
|
||||
try {
|
||||
$result = $this->pdo->commit();
|
||||
} catch (\Throwable $th) {
|
||||
$this->pdo = $this->reconnect();
|
||||
$result = $this->pdo->commit();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function reconnect(): PDONative
|
||||
{
|
||||
$this->pdo = new PDONative($this->dsn, $this->username, $this->passwd, $this->options);
|
||||
|
||||
@@ -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 Response public function setStatusCode(int $code = 200)
|
||||
@@ -277,6 +278,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
|
||||
*
|
||||
@@ -329,6 +351,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
|
||||
*
|
||||
|
||||
@@ -16,12 +16,19 @@ class File extends Model
|
||||
'default' => '',
|
||||
'example' => '5e5ea5c16897e',
|
||||
])
|
||||
->addRule('$permissions', [
|
||||
'type' => Response::MODEL_PERMISSIONS,
|
||||
'description' => 'File permissions.',
|
||||
'default' => new \stdClass,
|
||||
'example' => new \stdClass,
|
||||
'array' => false,
|
||||
->addRule('$read', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'File read permissions.',
|
||||
'default' => [],
|
||||
'example' => ['role:all'],
|
||||
'array' => true,
|
||||
])
|
||||
->addRule('$write', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'File write permissions.',
|
||||
'default' => [],
|
||||
'example' => ['user:608f9da25e7e1'],
|
||||
'array' => true,
|
||||
])
|
||||
->addRule('name', [
|
||||
'type' => self::TYPE_STRING,
|
||||
|
||||
@@ -124,7 +124,7 @@ class HTTPTest extends Scope
|
||||
|
||||
public function testSpecOpenAPI3()
|
||||
{
|
||||
$response = $this->client->call(Client::METHOD_GET, '/specs/open-api3?platform=client', [
|
||||
$response = $this->client->call(Client::METHOD_GET, '/specs/open-api3?platform=console', [
|
||||
'content-type' => 'application/json',
|
||||
], []);
|
||||
|
||||
@@ -133,7 +133,7 @@ class HTTPTest extends Scope
|
||||
}
|
||||
|
||||
$client = new Client();
|
||||
$client->setEndpoint('https://validator.swagger.io');
|
||||
$client->setEndpoint('http://appwrite-swagger-validator:8080');
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
|
||||
@@ -243,7 +243,6 @@ class AccountCustomClientTest extends Scope
|
||||
$this->assertIsArray($response['body']);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
$this->assertNotEmpty($response['body']['userId']);
|
||||
|
||||
$session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']];
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ trait DatabaseBase
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'name' => 'Actors',
|
||||
'read' => ['*'],
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:member', 'role:admin'],
|
||||
'rules' => [
|
||||
[
|
||||
@@ -53,7 +53,7 @@ trait DatabaseBase
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'name' => 'Movies',
|
||||
'read' => ['*'],
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:member', 'role:admin'],
|
||||
'rules' => [
|
||||
[
|
||||
@@ -553,7 +553,7 @@ trait DatabaseBase
|
||||
'releaseYear' => 1945,
|
||||
'actors' => [],
|
||||
],
|
||||
'read' => ['*'],
|
||||
'read' => ['role:all'],
|
||||
]);
|
||||
|
||||
$this->assertEquals($document['headers']['status-code'], 200);
|
||||
@@ -563,14 +563,14 @@ trait DatabaseBase
|
||||
if($this->getSide() == 'client') {
|
||||
$this->assertCount(1, $document['body']['$permissions']['read']);
|
||||
$this->assertCount(1, $document['body']['$permissions']['write']);
|
||||
$this->assertEquals(['*'], $document['body']['$permissions']['read']);
|
||||
$this->assertEquals(['role:all'], $document['body']['$permissions']['read']);
|
||||
$this->assertEquals(['user:'.$this->getUser()['$id']], $document['body']['$permissions']['write']);
|
||||
}
|
||||
|
||||
if($this->getSide() == 'server') {
|
||||
$this->assertCount(1, $document['body']['$permissions']['read']);
|
||||
$this->assertCount(0, $document['body']['$permissions']['write']);
|
||||
$this->assertEquals(['*'], $document['body']['$permissions']['read']);
|
||||
$this->assertEquals(['role:all'], $document['body']['$permissions']['read']);
|
||||
$this->assertEquals([], $document['body']['$permissions']['write']);
|
||||
}
|
||||
|
||||
@@ -586,14 +586,14 @@ trait DatabaseBase
|
||||
if($this->getSide() == 'client') {
|
||||
$this->assertCount(1, $document['body']['$permissions']['read']);
|
||||
$this->assertCount(1, $document['body']['$permissions']['write']);
|
||||
$this->assertEquals(['*'], $document['body']['$permissions']['read']);
|
||||
$this->assertEquals(['role:all'], $document['body']['$permissions']['read']);
|
||||
$this->assertEquals(['user:'.$this->getUser()['$id']], $document['body']['$permissions']['write']);
|
||||
}
|
||||
|
||||
if($this->getSide() == 'server') {
|
||||
$this->assertCount(1, $document['body']['$permissions']['read']);
|
||||
$this->assertCount(0, $document['body']['$permissions']['write']);
|
||||
$this->assertEquals(['*'], $document['body']['$permissions']['read']);
|
||||
$this->assertEquals(['role:all'], $document['body']['$permissions']['read']);
|
||||
$this->assertEquals([], $document['body']['$permissions']['write']);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ class DatabaseCustomServerTest extends Scope
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'name' => 'Actors',
|
||||
'read' => ['*'],
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:member', 'role:admin'],
|
||||
'rules' => [
|
||||
[
|
||||
|
||||
@@ -139,7 +139,7 @@ class FunctionsCustomClientTest extends Scope
|
||||
'x-appwrite-key' => $apikey,
|
||||
], [
|
||||
'name' => 'Test',
|
||||
'execute' => ['*'],
|
||||
'execute' => ['role:all'],
|
||||
'env' => 'php-8.0',
|
||||
'vars' => [
|
||||
'funcKey1' => 'funcValue1',
|
||||
|
||||
@@ -18,9 +18,8 @@ trait StorageBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'),
|
||||
'read' => ['*'],
|
||||
'write' => ['*'],
|
||||
'folderId' => 'xyz',
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:all'],
|
||||
]);
|
||||
|
||||
$this->assertEquals($file['headers']['status-code'], 201);
|
||||
@@ -61,10 +60,10 @@ trait StorageBase
|
||||
//$this->assertEquals('aes-128-gcm', $file1['body']['fileOpenSSLCipher']);
|
||||
//$this->assertNotEmpty($file1['body']['fileOpenSSLTag']);
|
||||
//$this->assertNotEmpty($file1['body']['fileOpenSSLIV']);
|
||||
$this->assertIsArray($file1['body']['$permissions']['read']);
|
||||
$this->assertIsArray($file1['body']['$permissions']['write']);
|
||||
$this->assertCount(1, $file1['body']['$permissions']['read']);
|
||||
$this->assertCount(1, $file1['body']['$permissions']['write']);
|
||||
$this->assertIsArray($file1['body']['$read']);
|
||||
$this->assertIsArray($file1['body']['$write']);
|
||||
$this->assertCount(1, $file1['body']['$read']);
|
||||
$this->assertCount(1, $file1['body']['$write']);
|
||||
|
||||
$file2 = $this->client->call(Client::METHOD_GET, '/storage/files/' . $data['fileId'] . '/preview', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
@@ -101,7 +100,6 @@ trait StorageBase
|
||||
$this->assertEquals($image->getImageHeight(), $original->getImageHeight());
|
||||
$this->assertEquals('PNG', $image->getImageFormat());
|
||||
|
||||
|
||||
$file4 = $this->client->call(Client::METHOD_GET, '/storage/files/' . $data['fileId'] . '/preview', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
@@ -187,8 +185,8 @@ trait StorageBase
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'read' => ['*'],
|
||||
'write' => ['*'],
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:all'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $file['headers']['status-code']);
|
||||
@@ -203,10 +201,10 @@ trait StorageBase
|
||||
//$this->assertEquals('aes-128-gcm', $file['body']['fileOpenSSLCipher']);
|
||||
//$this->assertNotEmpty($file['body']['fileOpenSSLTag']);
|
||||
//$this->assertNotEmpty($file['body']['fileOpenSSLIV']);
|
||||
$this->assertIsArray($file['body']['$permissions']['read']);
|
||||
$this->assertIsArray($file['body']['$permissions']['write']);
|
||||
$this->assertCount(1, $file['body']['$permissions']['read']);
|
||||
$this->assertCount(1, $file['body']['$permissions']['write']);
|
||||
$this->assertIsArray($file['body']['$read']);
|
||||
$this->assertIsArray($file['body']['$write']);
|
||||
$this->assertCount(1, $file['body']['$read']);
|
||||
$this->assertCount(1, $file['body']['$write']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
|
||||
@@ -79,6 +79,19 @@ trait TeamsBaseClient
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'email' => $email,
|
||||
'name' => 'Friend User',
|
||||
'roles' => ['admin', 'editor'],
|
||||
'url' => 'http://localhost:5000/join-us#title'
|
||||
]);
|
||||
|
||||
$this->assertEquals(409, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
|
||||
@@ -79,6 +79,19 @@ trait TeamsBaseServer
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'email' => $email,
|
||||
'name' => 'Friend User',
|
||||
'roles' => ['admin', 'editor'],
|
||||
'url' => 'http://localhost:5000/join-us#title'
|
||||
]);
|
||||
|
||||
$this->assertEquals(409, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/teams/'.$teamUid.'/memberships', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
|
||||
@@ -18,8 +18,8 @@ trait WebhooksBase
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'name' => 'Actors',
|
||||
'read' => ['*'],
|
||||
'write' => ['*'],
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:all'],
|
||||
'rules' => [
|
||||
[
|
||||
'label' => 'First Name',
|
||||
@@ -56,10 +56,10 @@ trait WebhooksBase
|
||||
$this->assertNotEmpty($webhook['data']['$id']);
|
||||
$this->assertEquals($webhook['data']['name'], 'Actors');
|
||||
$this->assertIsArray($webhook['data']['$permissions']);
|
||||
$this->assertIsArray($webhook['data']['$permissions']['read']);
|
||||
$this->assertIsArray($webhook['data']['$permissions']['write']);
|
||||
$this->assertCount(1, $webhook['data']['$permissions']['read']);
|
||||
$this->assertCount(1, $webhook['data']['$permissions']['write']);
|
||||
$this->assertIsArray($webhook['data']['$read']);
|
||||
$this->assertIsArray($webhook['data']['$write']);
|
||||
$this->assertCount(1, $webhook['data']['$read']);
|
||||
$this->assertCount(1, $webhook['data']['$write']);
|
||||
$this->assertCount(2, $webhook['data']['rules']);
|
||||
|
||||
return array_merge(['actorsId' => $actors['body']['$id']]);
|
||||
@@ -79,8 +79,8 @@ trait WebhooksBase
|
||||
'lastName' => 'Evans',
|
||||
|
||||
],
|
||||
'read' => ['*'],
|
||||
'write' => ['*'],
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:all'],
|
||||
]);
|
||||
|
||||
$this->assertEquals($document['headers']['status-code'], 201);
|
||||
@@ -99,10 +99,10 @@ trait WebhooksBase
|
||||
$this->assertNotEmpty($webhook['data']['$id']);
|
||||
$this->assertEquals($webhook['data']['firstName'], 'Chris');
|
||||
$this->assertEquals($webhook['data']['lastName'], 'Evans');
|
||||
$this->assertIsArray($webhook['data']['$permissions']['read']);
|
||||
$this->assertIsArray($webhook['data']['$permissions']['write']);
|
||||
$this->assertCount(1, $webhook['data']['$permissions']['read']);
|
||||
$this->assertCount(1, $webhook['data']['$permissions']['write']);
|
||||
$this->assertIsArray($webhook['data']['$read']);
|
||||
$this->assertIsArray($webhook['data']['$write']);
|
||||
$this->assertCount(1, $webhook['data']['$read']);
|
||||
$this->assertCount(1, $webhook['data']['$write']);
|
||||
|
||||
$data['documentId'] = $document['body']['$id'];
|
||||
|
||||
@@ -122,8 +122,8 @@ trait WebhooksBase
|
||||
'firstName' => 'Chris1',
|
||||
'lastName' => 'Evans2',
|
||||
],
|
||||
'read' => ['*'],
|
||||
'write' => ['*'],
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:all'],
|
||||
]);
|
||||
|
||||
$this->assertEquals($document['headers']['status-code'], 200);
|
||||
@@ -142,10 +142,10 @@ trait WebhooksBase
|
||||
$this->assertNotEmpty($webhook['data']['$id']);
|
||||
$this->assertEquals($webhook['data']['firstName'], 'Chris1');
|
||||
$this->assertEquals($webhook['data']['lastName'], 'Evans2');
|
||||
$this->assertIsArray($webhook['data']['$permissions']['read']);
|
||||
$this->assertIsArray($webhook['data']['$permissions']['write']);
|
||||
$this->assertCount(1, $webhook['data']['$permissions']['read']);
|
||||
$this->assertCount(1, $webhook['data']['$permissions']['write']);
|
||||
$this->assertIsArray($webhook['data']['$read']);
|
||||
$this->assertIsArray($webhook['data']['$write']);
|
||||
$this->assertCount(1, $webhook['data']['$read']);
|
||||
$this->assertCount(1, $webhook['data']['$write']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
@@ -164,8 +164,8 @@ trait WebhooksBase
|
||||
'lastName' => 'Cooper',
|
||||
|
||||
],
|
||||
'read' => ['*'],
|
||||
'write' => ['*'],
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:all'],
|
||||
]);
|
||||
|
||||
$this->assertEquals($document['headers']['status-code'], 201);
|
||||
@@ -191,10 +191,10 @@ trait WebhooksBase
|
||||
$this->assertNotEmpty($webhook['data']['$id']);
|
||||
$this->assertEquals($webhook['data']['firstName'], 'Bradly');
|
||||
$this->assertEquals($webhook['data']['lastName'], 'Cooper');
|
||||
$this->assertIsArray($webhook['data']['$permissions']['read']);
|
||||
$this->assertIsArray($webhook['data']['$permissions']['write']);
|
||||
$this->assertCount(1, $webhook['data']['$permissions']['read']);
|
||||
$this->assertCount(1, $webhook['data']['$permissions']['write']);
|
||||
$this->assertIsArray($webhook['data']['$read']);
|
||||
$this->assertIsArray($webhook['data']['$write']);
|
||||
$this->assertCount(1, $webhook['data']['$read']);
|
||||
$this->assertCount(1, $webhook['data']['$write']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
@@ -209,8 +209,8 @@ trait WebhooksBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'),
|
||||
'read' => ['*'],
|
||||
'write' => ['*'],
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:all'],
|
||||
'folderId' => 'xyz',
|
||||
]);
|
||||
|
||||
@@ -228,7 +228,8 @@ trait WebhooksBase
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
|
||||
$this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), ('server' === $this->getSide()));
|
||||
$this->assertNotEmpty($webhook['data']['$id']);
|
||||
$this->assertIsArray($webhook['data']['$permissions']);
|
||||
$this->assertIsArray($webhook['data']['$read']);
|
||||
$this->assertIsArray($webhook['data']['$write']);
|
||||
$this->assertEquals($webhook['data']['name'], 'logo.png');
|
||||
$this->assertIsInt($webhook['data']['dateCreated'], 'logo.png');
|
||||
$this->assertNotEmpty($webhook['data']['signature']);
|
||||
@@ -253,8 +254,8 @@ trait WebhooksBase
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'read' => ['*'],
|
||||
'write' => ['*'],
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:all'],
|
||||
]);
|
||||
|
||||
$this->assertEquals($file['headers']['status-code'], 200);
|
||||
@@ -271,7 +272,8 @@ trait WebhooksBase
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
|
||||
$this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), ('server' === $this->getSide()));
|
||||
$this->assertNotEmpty($webhook['data']['$id']);
|
||||
$this->assertIsArray($webhook['data']['$permissions']);
|
||||
$this->assertIsArray($webhook['data']['$read']);
|
||||
$this->assertIsArray($webhook['data']['$write']);
|
||||
$this->assertEquals($webhook['data']['name'], 'logo.png');
|
||||
$this->assertIsInt($webhook['data']['dateCreated'], 'logo.png');
|
||||
$this->assertNotEmpty($webhook['data']['signature']);
|
||||
@@ -308,7 +310,8 @@ trait WebhooksBase
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
|
||||
$this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), ('server' === $this->getSide()));
|
||||
$this->assertNotEmpty($webhook['data']['$id']);
|
||||
$this->assertIsArray($webhook['data']['$permissions']);
|
||||
$this->assertIsArray($webhook['data']['$read']);
|
||||
$this->assertIsArray($webhook['data']['$write']);
|
||||
$this->assertEquals($webhook['data']['name'], 'logo.png');
|
||||
$this->assertIsInt($webhook['data']['dateCreated'], 'logo.png');
|
||||
$this->assertNotEmpty($webhook['data']['signature']);
|
||||
|
||||
@@ -28,8 +28,8 @@ class WebhooksCustomServerTest extends Scope
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'name' => 'Actors1',
|
||||
'read' => ['*'],
|
||||
'write' => ['*'],
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:all'],
|
||||
'rules' => [
|
||||
[
|
||||
'label' => 'First Name',
|
||||
@@ -86,8 +86,8 @@ class WebhooksCustomServerTest extends Scope
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'name' => 'Demo',
|
||||
'read' => ['*'],
|
||||
'write' => ['*'],
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:all'],
|
||||
'rules' => [
|
||||
[
|
||||
'label' => 'First Name',
|
||||
@@ -307,7 +307,7 @@ class WebhooksCustomServerTest extends Scope
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'Test',
|
||||
'env' => 'php-8.0',
|
||||
'execute' => ['*'],
|
||||
'execute' => ['role:all'],
|
||||
'timeout' => 10,
|
||||
]);
|
||||
|
||||
@@ -349,7 +349,7 @@ class WebhooksCustomServerTest extends Scope
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'Test',
|
||||
'env' => 'php-8.0',
|
||||
'execute' => ['*'],
|
||||
'execute' => ['role:all'],
|
||||
'vars' => [
|
||||
'key1' => 'value1',
|
||||
]
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
FROM mariadb:10.2
|
||||
|
||||
LABEL maintainer="team@appwrite.io"
|
||||
|
||||
# Add appwrite schema and tables
|
||||
ADD ./all.sql /docker-entrypoint-initdb.d/all.sql
|
||||
|
||||
RUN chown -R mysql:mysql /docker-entrypoint-initdb.d/
|
||||
@@ -1,83 +0,0 @@
|
||||
CREATE DATABASE IF NOT EXISTS `appwrite` /*!40100 DEFAULT CHARACTER SET utf8mb4 */;
|
||||
|
||||
USE `appwrite`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `template.abuse.abuse` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`_key` varchar(255) NOT NULL,
|
||||
`_time` varchar(45) NOT NULL,
|
||||
`_count` int(11) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `unique1` (`_key`,`_time`),
|
||||
KEY `index1` (`_key`,`_time`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `template.audit.audit` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`userId` varchar(45) NOT NULL,
|
||||
`userType` int(11) NOT NULL,
|
||||
`event` varchar(45) NOT NULL,
|
||||
`resource` varchar(45) DEFAULT NULL,
|
||||
`userAgent` text NOT NULL,
|
||||
`ip` varchar(45) NOT NULL,
|
||||
`location` varchar(45) DEFAULT NULL,
|
||||
`time` datetime NOT NULL,
|
||||
`data` longtext DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `id_UNIQUE` (`id`),
|
||||
KEY `index_1` (`userId`,`userType`),
|
||||
KEY `index_2` (`event`),
|
||||
KEY `index_3` (`resource`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `template.database.documents` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Unique ID for each node',
|
||||
`uid` varchar(45) DEFAULT NULL,
|
||||
`status` int(11) NOT NULL DEFAULT 0,
|
||||
`createdAt` datetime DEFAULT NULL,
|
||||
`updatedAt` datetime DEFAULT NULL,
|
||||
`signature` varchar(32) NOT NULL,
|
||||
`revision` varchar(45) NOT NULL,
|
||||
`permissions` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `id_UNIQUE` (`id`),
|
||||
UNIQUE KEY `index2` (`uid`),
|
||||
KEY `index3` (`signature`,`uid`,`revision`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `template.database.properties` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Primary Key',
|
||||
`documentUid` varchar(45) NOT NULL COMMENT 'Unique UID foreign key',
|
||||
`documentRevision` varchar(45) NOT NULL,
|
||||
`key` varchar(32) NOT NULL COMMENT 'Property key name',
|
||||
`value` text NOT NULL COMMENT 'Value of property',
|
||||
`primitive` varchar(32) NOT NULL COMMENT 'Primitive type of property value',
|
||||
`array` tinyint(4) NOT NULL DEFAULT 0,
|
||||
`order` int(11) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `index1` (`documentUid`),
|
||||
KEY `index2` (`key`,`value`(5)),
|
||||
FULLTEXT KEY `index3` (`value`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `template.database.relationships` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`revision` varchar(45) NOT NULL,
|
||||
`start` varchar(45) NOT NULL COMMENT 'Unique UID foreign key',
|
||||
`end` varchar(45) NOT NULL COMMENT 'Unique UID foreign key',
|
||||
`key` varchar(256) NOT NULL,
|
||||
`path` int(11) NOT NULL DEFAULT 0,
|
||||
`array` tinyint(4) NOT NULL DEFAULT 0,
|
||||
`order` int(11) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `relationships_start_nodes_id_idx` (`start`),
|
||||
KEY `relationships_end_nodes_id_idx` (`end`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
/* Default App */
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `app_console.database.documents` LIKE `template.database.documents`;
|
||||
CREATE TABLE IF NOT EXISTS `app_console.database.properties` LIKE `template.database.properties`;
|
||||
CREATE TABLE IF NOT EXISTS `app_console.database.relationships` LIKE `template.database.relationships`;
|
||||
CREATE TABLE IF NOT EXISTS `app_console.audit.audit` LIKE `template.audit.audit`;
|
||||
CREATE TABLE IF NOT EXISTS `app_console.abuse.abuse` LIKE `template.abuse.abuse`;
|
||||
File diff suppressed because one or more lines are too long
@@ -25,7 +25,7 @@ class AuthorizationTest extends TestCase
|
||||
'$collection' => uniqid(),
|
||||
'$permissions' => [
|
||||
'read' => ['user:123', 'team:123'],
|
||||
'write' => ['*'],
|
||||
'write' => ['role:all'],
|
||||
],
|
||||
]);
|
||||
$this->object = new Authorization($this->document, 'read');
|
||||
@@ -45,7 +45,7 @@ class AuthorizationTest extends TestCase
|
||||
$this->assertEquals(Authorization::isRole('user:456'), true);
|
||||
$this->assertEquals(Authorization::isRole('user:457'), false);
|
||||
$this->assertEquals(Authorization::isRole(''), false);
|
||||
$this->assertEquals(Authorization::isRole('*'), true);
|
||||
$this->assertEquals(Authorization::isRole('role:all'), true);
|
||||
|
||||
$this->assertEquals($this->object->isValid($this->document->getPermissions()), true);
|
||||
|
||||
|
||||
@@ -432,7 +432,7 @@ class V06Test extends TestCase
|
||||
{
|
||||
$content = [
|
||||
'$id' => '5e5ea5c16897e',
|
||||
'$permissions' => ['read' => ['*'], 'write' => ['*']],
|
||||
'$permissions' => ['read' => ['role:all'], 'write' => ['role:all']],
|
||||
'name' => 'Pink.png',
|
||||
'dateCreated' => 1592981250,
|
||||
'signature' => '5d529fd02b544198ae075bd57c1762bb',
|
||||
@@ -444,7 +444,7 @@ class V06Test extends TestCase
|
||||
$parsedResponse = $this->filter->parse($content, $model);
|
||||
|
||||
$this->assertEquals($parsedResponse['$id'], '5e5ea5c16897e');
|
||||
$this->assertEquals($parsedResponse['$permissions'], ['read' => ['*'], 'write' => ['*']]);
|
||||
$this->assertEquals($parsedResponse['$permissions'], ['read' => ['role:all'], 'write' => ['role:all']]);
|
||||
$this->assertEquals($parsedResponse['name'], 'Pink.png');
|
||||
$this->assertEquals($parsedResponse['dateCreated'], 1592981250);
|
||||
$this->assertEquals($parsedResponse['signature'], '5d529fd02b544198ae075bd57c1762bb');
|
||||
@@ -467,7 +467,7 @@ class V06Test extends TestCase
|
||||
{
|
||||
$content = [
|
||||
'$id' => '5e5ea5c16897e',
|
||||
'$permissions' => ['read' => ['*'], 'write' => ['*']],
|
||||
'$permissions' => ['read' => ['role:all'], 'write' => ['role:all']],
|
||||
'name' => 'Movies',
|
||||
'dateCreated' => 1592981250,
|
||||
'dateUpdated' => '5d529fd02b544198ae075bd57c1762bb',
|
||||
@@ -478,7 +478,7 @@ class V06Test extends TestCase
|
||||
$parsedResponse = $this->filter->parse($content, $model);
|
||||
|
||||
$this->assertEquals($parsedResponse['$id'], '5e5ea5c16897e');
|
||||
$this->assertEquals($parsedResponse['$permissions'], ['read' => ['*'], 'write' => ['*']]);
|
||||
$this->assertEquals($parsedResponse['$permissions'], ['read' => ['role:all'], 'write' => ['role:all']]);
|
||||
$this->assertEquals($parsedResponse['name'], 'Movies');
|
||||
$this->assertEquals($parsedResponse['dateCreated'], 1592981250);
|
||||
$this->assertEquals($parsedResponse['dateUpdated'], '5d529fd02b544198ae075bd57c1762bb');
|
||||
@@ -495,7 +495,7 @@ class V06Test extends TestCase
|
||||
'collections' => [
|
||||
0 => [
|
||||
'$id' => '5e5ea5c16897e',
|
||||
'$permissions' => ['read' => ['*'], 'write' => ['*']],
|
||||
'$permissions' => ['read' => ['role:all'], 'write' => ['role:all']],
|
||||
'name' => 'Movies',
|
||||
'dateCreated' => 1592981250,
|
||||
'dateUpdated' => '5d529fd02b544198ae075bd57c1762bb',
|
||||
@@ -509,7 +509,7 @@ class V06Test extends TestCase
|
||||
|
||||
$this->assertEquals($parsedResponse['sum'], 1);
|
||||
$this->assertEquals($parsedResponse['collections'][0]['$id'], '5e5ea5c16897e');
|
||||
$this->assertEquals($parsedResponse['collections'][0]['$permissions'], ['read' => ['*'], 'write' => ['*']]);
|
||||
$this->assertEquals($parsedResponse['collections'][0]['$permissions'], ['read' => ['role:all'], 'write' => ['role:all']]);
|
||||
$this->assertEquals($parsedResponse['collections'][0]['name'], 'Movies');
|
||||
$this->assertEquals($parsedResponse['collections'][0]['dateCreated'], 1592981250);
|
||||
$this->assertEquals($parsedResponse['collections'][0]['dateUpdated'], '5d529fd02b544198ae075bd57c1762bb');
|
||||
|
||||
Reference in New Issue
Block a user