1
0
Fork 0
mirror of synced 2024-06-02 02:44:47 +12:00

Merge branch '0.7.x' of github.com:appwrite/appwrite into feat-upgrade-php-version

This commit is contained in:
Eldad Fux 2020-11-21 08:17:53 +02:00
commit 1a2c3c1551
72 changed files with 2287 additions and 754 deletions

View file

@ -172,6 +172,14 @@ $collections = [
'required' => false,
'array' => true,
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'Filter',
'key' => 'filter',
'type' => Database::SYSTEM_VAR_TYPE_TEXT,
'required' => false,
'array' => true,
],
],
],
Database::SYSTEM_COLLECTION_USERS => [

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -37,6 +37,9 @@ App::post('/v1/account')
->label('sdk.namespace', 'account')
->label('sdk.method', 'create')
->label('sdk.description', '/docs/references/account/create.md')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER)
->label('abuse-limit', 10)
->param('email', '', new Email(), 'User email.')
->param('password', '', new Password(), 'User password. Must be between 6 to 32 chars.')
@ -131,6 +134,9 @@ App::post('/v1/account/sessions')
->label('sdk.namespace', 'account')
->label('sdk.method', 'createSession')
->label('sdk.description', '/docs/references/account/create-session.md')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_SESSION)
->label('abuse-limit', 10)
->label('abuse-key', 'url:{url},email:{param-email}')
->param('email', '', new Email(), 'User email.')
@ -185,7 +191,7 @@ App::post('/v1/account/sessions')
'$collection' => Database::SYSTEM_COLLECTION_TOKENS,
'$permissions' => ['read' => ['user:'.$profile->getId()], 'write' => ['user:'.$profile->getId()]],
'type' => Auth::TOKEN_TYPE_LOGIN,
'secret' => Auth::hash($secret), // On way hash encryption to protect DB leak
'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak
'expire' => $expiry,
'userAgent' => $request->getUserAgent('UNKNOWN'),
'ip' => $request->getIP(),
@ -523,7 +529,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
'$collection' => Database::SYSTEM_COLLECTION_TOKENS,
'$permissions' => ['read' => ['user:'.$user['$id']], 'write' => ['user:'.$user['$id']]],
'type' => Auth::TOKEN_TYPE_LOGIN,
'secret' => Auth::hash($secret), // On way hash encryption to protect DB leak
'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak
'expire' => $expiry,
'userAgent' => $request->getUserAgent('UNKNOWN'),
'ip' => $request->getIP(),
@ -611,7 +617,9 @@ App::get('/v1/account')
->label('sdk.namespace', 'account')
->label('sdk.method', 'get')
->label('sdk.description', '/docs/references/account/get.md')
->label('sdk.response', ['200' => 'user'])
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER)
->action(function ($response, $user) {
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Document $user */
@ -631,13 +639,16 @@ App::get('/v1/account/prefs')
->label('sdk.namespace', 'account')
->label('sdk.method', 'getPrefs')
->label('sdk.description', '/docs/references/account/get-prefs.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_ANY)
->action(function ($response, $user) {
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Document $user */
$prefs = $user->getAttribute('prefs', new \stdClass);
$response->json($prefs);
$response->dynamic(new Document($prefs), Response::MODEL_ANY);
}, ['response', 'user']);
App::get('/v1/account/sessions')
@ -648,6 +659,9 @@ App::get('/v1/account/sessions')
->label('sdk.namespace', 'account')
->label('sdk.method', 'getSessions')
->label('sdk.description', '/docs/references/account/get-sessions.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_SESSION_LIST)
->action(function ($response, $user, $locale) {
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Document $user */
@ -685,6 +699,9 @@ App::get('/v1/account/logs')
->label('sdk.namespace', 'account')
->label('sdk.method', 'getLogs')
->label('sdk.description', '/docs/references/account/get-logs.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_LOG_LIST)
->action(function ($response, $register, $project, $user, $locale, $geodb) {
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Document $project */
@ -783,6 +800,9 @@ App::patch('/v1/account/name')
->label('sdk.namespace', 'account')
->label('sdk.method', 'updateName')
->label('sdk.description', '/docs/references/account/update-name.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER)
->param('name', '', new Text(128), 'User name. Max length: 128 chars.')
->action(function ($name, $response, $user, $projectDB, $audits) {
/** @var Appwrite\Utopia\Response $response */
@ -818,6 +838,9 @@ App::patch('/v1/account/password')
->label('sdk.namespace', 'account')
->label('sdk.method', 'updatePassword')
->label('sdk.description', '/docs/references/account/update-password.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER)
->param('password', '', new Password(), 'New user password. Must be between 6 to 32 chars.')
->param('oldPassword', '', new Password(), 'Old user password. Must be between 6 to 32 chars.')
->action(function ($password, $oldPassword, $response, $user, $projectDB, $audits) {
@ -858,6 +881,9 @@ App::patch('/v1/account/email')
->label('sdk.namespace', 'account')
->label('sdk.method', 'updateEmail')
->label('sdk.description', '/docs/references/account/update-email.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER)
->param('email', '', new Email(), 'User email.')
->param('password', '', new Password(), 'User password. Must be between 6 to 32 chars.')
->action(function ($email, $password, $response, $user, $projectDB, $audits) {
@ -913,6 +939,9 @@ App::patch('/v1/account/prefs')
->label('sdk.namespace', 'account')
->label('sdk.method', 'updatePrefs')
->label('sdk.description', '/docs/references/account/update-prefs.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_ANY)
->param('prefs', [], new Assoc(), 'Prefs key-value JSON object.')
->action(function ($prefs, $response, $user, $projectDB, $audits) {
/** @var Appwrite\Utopia\Response $response */
@ -935,7 +964,7 @@ App::patch('/v1/account/prefs')
$prefs = $user->getAttribute('prefs', new \stdClass);
$response->json($prefs);
$response->dynamic(new Document($prefs), Response::MODEL_ANY);
}, ['response', 'user', 'projectDB', 'audits']);
App::delete('/v1/account')
@ -947,6 +976,9 @@ App::delete('/v1/account')
->label('sdk.namespace', 'account')
->label('sdk.method', 'delete')
->label('sdk.description', '/docs/references/account/delete.md')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_NONE)
->action(function ($request, $response, $user, $projectDB, $audits, $webhooks) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Response $response */
@ -1005,6 +1037,9 @@ App::delete('/v1/account/sessions/:sessionId')
->label('sdk.namespace', 'account')
->label('sdk.method', 'deleteSession')
->label('sdk.description', '/docs/references/account/delete-session.md')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_NONE)
->label('abuse-limit', 100)
->param('sessionId', null, new UID(), 'Session unique ID. Use the string \'current\' to delete the current device session.')
->action(function ($sessionId, $request, $response, $user, $projectDB, $audits, $webhooks) {
@ -1067,6 +1102,9 @@ App::delete('/v1/account/sessions')
->label('sdk.namespace', 'account')
->label('sdk.method', 'deleteSessions')
->label('sdk.description', '/docs/references/account/delete-sessions.md')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_NONE)
->label('abuse-limit', 100)
->action(function ($request, $response, $user, $projectDB, $audits, $webhooks) {
/** @var Utopia\Swoole\Request $request */
@ -1119,6 +1157,9 @@ App::post('/v1/account/recovery')
->label('sdk.namespace', 'account')
->label('sdk.method', 'createRecovery')
->label('sdk.description', '/docs/references/account/create-recovery.md')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_TOKEN)
->label('abuse-limit', 10)
->label('abuse-key', 'url:{url},email:{param-email}')
->param('email', '', new Email(), 'User email.')
@ -1149,7 +1190,7 @@ App::post('/v1/account/recovery')
'$collection' => Database::SYSTEM_COLLECTION_TOKENS,
'$permissions' => ['read' => ['user:'.$profile->getId()], 'write' => ['user:'.$profile->getId()]],
'type' => Auth::TOKEN_TYPE_RECOVERY,
'secret' => Auth::hash($secret), // On way hash encryption to protect DB leak
'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak
'expire' => \time() + Auth::TOKEN_EXPIRATION_RECOVERY,
'userAgent' => $request->getUserAgent('UNKNOWN'),
'ip' => $request->getIP(),
@ -1213,7 +1254,7 @@ App::post('/v1/account/recovery')
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->json($recovery->getArrayCopy(['$id', 'type', 'expire']))
->dynamic($recovery, Response::MODEL_TOKEN)
;
}, ['request', 'response', 'projectDB', 'project', 'locale', 'mails', 'audits']);
@ -1225,6 +1266,9 @@ App::put('/v1/account/recovery')
->label('sdk.namespace', 'account')
->label('sdk.method', 'updateRecovery')
->label('sdk.description', '/docs/references/account/update-recovery.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_TOKEN)
->label('abuse-limit', 10)
->label('abuse-key', 'url:{url},userId:{param-userId}')
->param('userId', '', new UID(), 'User account UID address.')
@ -1286,7 +1330,7 @@ App::put('/v1/account/recovery')
$recovery = $profile->search('$id', $recovery, $profile->getAttribute('tokens', []));
$response->json($recovery->getArrayCopy(['$id', 'type', 'expire']));
$response->dynamic($recovery, Response::MODEL_TOKEN);
}, ['response', 'projectDB', 'audits']);
App::post('/v1/account/verification')
@ -1297,6 +1341,9 @@ App::post('/v1/account/verification')
->label('sdk.namespace', 'account')
->label('sdk.method', 'createVerification')
->label('sdk.description', '/docs/references/account/create-verification.md')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_TOKEN)
->label('abuse-limit', 10)
->label('abuse-key', 'url:{url},email:{param-email}')
->param('url', '', function ($clients) { return new Host($clients); }, 'URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients']) // TODO add built-in confirm page
@ -1316,7 +1363,7 @@ App::post('/v1/account/verification')
'$collection' => Database::SYSTEM_COLLECTION_TOKENS,
'$permissions' => ['read' => ['user:'.$user->getId()], 'write' => ['user:'.$user->getId()]],
'type' => Auth::TOKEN_TYPE_VERIFICATION,
'secret' => Auth::hash($verificationSecret), // On way hash encryption to protect DB leak
'secret' => Auth::hash($verificationSecret), // One way hash encryption to protect DB leak
'expire' => \time() + Auth::TOKEN_EXPIRATION_CONFIRM,
'userAgent' => $request->getUserAgent('UNKNOWN'),
'ip' => $request->getIP(),
@ -1380,7 +1427,7 @@ App::post('/v1/account/verification')
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->json($verification->getArrayCopy(['$id', 'type', 'expire']))
->dynamic($verification, Response::MODEL_TOKEN)
;
}, ['request', 'response', 'project', 'user', 'projectDB', 'locale', 'audits', 'mails']);
@ -1392,6 +1439,9 @@ App::put('/v1/account/verification')
->label('sdk.namespace', 'account')
->label('sdk.method', 'updateVerification')
->label('sdk.description', '/docs/references/account/update-verification.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_TOKEN)
->label('abuse-limit', 10)
->label('abuse-key', 'url:{url},userId:{param-userId}')
->param('userId', '', new UID(), 'User unique ID.')
@ -1446,5 +1496,5 @@ App::put('/v1/account/verification')
$verification = $profile->search('$id', $verification, $profile->getAttribute('tokens', []));
$response->json($verification->getArrayCopy(['$id', 'type', 'expire']));
$response->dynamic($verification, Response::MODEL_TOKEN);
}, ['response', 'user', 'projectDB', 'audits']);

View file

@ -11,6 +11,7 @@ use Utopia\Cache\Cache;
use Utopia\Cache\Adapter\Filesystem;
use Appwrite\Resize\Resize;
use Appwrite\URL\URL as URLParse;
use Appwrite\Utopia\Response;
use Utopia\Config\Config;
use Utopia\Validator\HexColor;
use chillerlan\QRCode\QRCode;
@ -88,6 +89,8 @@ App::get('/v1/avatars/credit-cards/:code')
->label('sdk.method', 'getCreditCard')
->label('sdk.methodType', 'location')
->label('sdk.description', '/docs/references/avatars/get-credit-card.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_IMAGE_PNG)
->param('code', '', new WhiteList(\array_keys(Config::getParam('avatar-credit-cards'))), 'Credit Card Code. Possible values: '.\implode(', ', \array_keys(Config::getParam('avatar-credit-cards'))).'.')
->param('width', 100, new Range(0, 2000), 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('height', 100, new Range(0, 2000), 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true)
@ -105,6 +108,8 @@ App::get('/v1/avatars/browsers/:code')
->label('sdk.method', 'getBrowser')
->label('sdk.methodType', 'location')
->label('sdk.description', '/docs/references/avatars/get-browser.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_IMAGE_PNG)
->param('code', '', new WhiteList(\array_keys(Config::getParam('avatar-browsers'))), 'Browser Code.')
->param('width', 100, new Range(0, 2000), 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('height', 100, new Range(0, 2000), 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true)
@ -122,6 +127,8 @@ App::get('/v1/avatars/flags/:code')
->label('sdk.method', 'getFlag')
->label('sdk.methodType', 'location')
->label('sdk.description', '/docs/references/avatars/get-flag.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_IMAGE_PNG)
->param('code', '', new WhiteList(\array_keys(Config::getParam('avatar-flags'))), 'Country Code. ISO Alpha-2 country code format.')
->param('width', 100, new Range(0, 2000), 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('height', 100, new Range(0, 2000), 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true)
@ -139,6 +146,8 @@ App::get('/v1/avatars/image')
->label('sdk.method', 'getImage')
->label('sdk.methodType', 'location')
->label('sdk.description', '/docs/references/avatars/get-image.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_IMAGE)
->param('url', '', new URL(), 'Image URL which you want to crop.')
->param('width', 400, new Range(0, 2000), 'Resize preview image width, Pass an integer between 0 to 2000.', true)
->param('height', 400, new Range(0, 2000), 'Resize preview image height, Pass an integer between 0 to 2000.', true)
@ -205,6 +214,8 @@ App::get('/v1/avatars/favicon')
->label('sdk.method', 'getFavicon')
->label('sdk.methodType', 'location')
->label('sdk.description', '/docs/references/avatars/get-favicon.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_IMAGE)
->param('url', '', new URL(), 'Website URL which you want to fetch the favicon from.')
->action(function ($url, $response) {
/** @var Appwrite\Utopia\Response $response */
@ -355,6 +366,8 @@ App::get('/v1/avatars/qr')
->label('sdk.method', 'getQR')
->label('sdk.methodType', 'location')
->label('sdk.description', '/docs/references/avatars/get-qr.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_IMAGE_PNG)
->param('text', '', new Text(512), 'Plain text to be converted to QR code image.')
->param('size', 400, new Range(0, 1000), 'QR code size. Pass an integer between 0 to 1000. Defaults to 400.', true)
->param('margin', 1, new Range(0, 10), 'Margin from edge. Pass an integer between 0 to 10. Defaults to 1.', true)
@ -390,6 +403,8 @@ App::get('/v1/avatars/initials')
->label('sdk.method', 'getInitials')
->label('sdk.methodType', 'location')
->label('sdk.description', '/docs/references/avatars/get-initials.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_IMAGE_PNG)
->param('name', '', new Text(128), 'Full Name. When empty, current user name or email will be used. Max length: 128 chars.', true)
->param('width', 500, new Range(0, 2000), 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true)
->param('height', 500, new Range(0, 2000), 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true)

View file

@ -27,6 +27,9 @@ App::post('/v1/database/collections')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.method', 'createCollection')
->label('sdk.description', '/docs/references/database/create-collection.md')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_COLLECTION)
->param('name', '', new Text(128), 'Collection name. Max length: 128 chars.')
->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.')
@ -93,6 +96,9 @@ App::get('/v1/database/collections')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.method', 'listCollections')
->label('sdk.description', '/docs/references/database/list-collections.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_COLLECTION_LIST)
->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, 40000), 'Results offset. The default value is 0. Use this param to manage pagination.', true)
@ -127,6 +133,9 @@ App::get('/v1/database/collections/:collectionId')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.method', 'getCollection')
->label('sdk.description', '/docs/references/database/get-collection.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_COLLECTION)
->param('collectionId', '', new UID(), 'Collection unique ID.')
->action(function ($collectionId, $response, $projectDB) {
/** @var Appwrite\Utopia\Response $response */
@ -150,6 +159,9 @@ App::put('/v1/database/collections/:collectionId')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.method', 'updateCollection')
->label('sdk.description', '/docs/references/database/update-collection.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_COLLECTION)
->param('collectionId', '', new UID(), 'Collection unique ID.')
->param('name', null, new Text(128), 'Collection name. Max length: 128 chars.')
->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.')
@ -219,6 +231,9 @@ App::delete('/v1/database/collections/:collectionId')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.method', 'deleteCollection')
->label('sdk.description', '/docs/references/database/delete-collection.md')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_NONE)
->param('collectionId', '', new UID(), 'Collection unique ID.')
->action(function ($collectionId, $response, $projectDB, $webhooks, $audits) {
/** @var Appwrite\Utopia\Response $response */
@ -258,6 +273,9 @@ App::post('/v1/database/collections/:collectionId/documents')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.method', 'createDocument')
->label('sdk.description', '/docs/references/database/create-document.md')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_ANY)
->param('collectionId', null, new UID(), 'Collection unique ID. You can create a new collection with validation rules using the Database service [server integration](/docs/server/database#createCollection).')
->param('data', [], new JSON(), 'Document data as JSON object.')
->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.')
@ -371,6 +389,9 @@ App::get('/v1/database/collections/:collectionId/documents')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.method', 'listDocuments')
->label('sdk.description', '/docs/references/database/list-documents.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_DOCUMENT_LIST)
->param('collectionId', null, new UID(), 'Collection unique ID. You can create a new collection with validation rules using the Database service [server integration](/docs/server/database#createCollection).')
->param('filters', [], new ArrayList(new Text(128)), 'Array of filter strings. Each filter is constructed from a key name, comparison operator (=, !=, >, <, <=, >=) and a value. You can also use a dot (.) separator in attribute names to filter by child document attributes. Examples: \'name=John Doe\' or \'category.$id>=5bed2d152c362\'.', true)
->param('limit', 25, new Range(0, 100), 'Maximum number of documents to return in response. Use this value to manage pagination. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
@ -429,6 +450,9 @@ App::get('/v1/database/collections/:collectionId/documents/:documentId')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.method', 'getDocument')
->label('sdk.description', '/docs/references/database/get-document.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_ANY)
->param('collectionId', null, new UID(), 'Collection unique ID. You can create a new collection with validation rules using the Database service [server integration](/docs/server/database#createCollection).')
->param('documentId', null, new UID(), 'Document unique ID.')
->action(function ($collectionId, $documentId, $request, $response, $projectDB) {
@ -455,6 +479,9 @@ App::patch('/v1/database/collections/:collectionId/documents/:documentId')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.method', 'updateDocument')
->label('sdk.description', '/docs/references/database/update-document.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_ANY)
->param('collectionId', null, new UID(), 'Collection unique ID. You can create a new collection with validation rules using the Database service [server integration](/docs/server/database#createCollection).')
->param('documentId', null, new UID(), 'Document unique ID.')
->param('data', [], new JSON(), 'Document data as JSON object.')
@ -529,6 +556,9 @@ App::delete('/v1/database/collections/:collectionId/documents/:documentId')
->label('sdk.platform', [APP_PLATFORM_CLIENT, APP_PLATFORM_SERVER])
->label('sdk.method', 'deleteDocument')
->label('sdk.description', '/docs/references/database/delete-document.md')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_NONE)
->param('collectionId', null, new UID(), 'Collection unique ID. You can create a new collection with validation rules using the Database service [server integration](/docs/server/database#createCollection).')
->param('documentId', null, new UID(), 'Document unique ID.')
->action(function ($collectionId, $documentId, $response, $projectDB, $webhooks, $audits) {

View file

@ -29,6 +29,9 @@ App::post('/v1/functions')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'create')
->label('sdk.description', '/docs/references/functions/create-function.md')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_FUNCTION)
->param('name', '', new Text(128), 'Function name. Max length: 128 chars.')
->param('env', '', new WhiteList(array_keys(Config::getParam('environments')), true), 'Execution enviornment.')
->param('vars', [], new Assoc(), 'Key-value JSON object.', true)
@ -74,6 +77,9 @@ App::get('/v1/functions')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'list')
->label('sdk.description', '/docs/references/functions/list-functions.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_FUNCTION_LIST)
->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)
@ -105,6 +111,9 @@ App::get('/v1/functions/:functionId')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'get')
->label('sdk.description', '/docs/references/functions/get-function.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_FUNCTION)
->param('functionId', '', new UID(), 'Function unique ID.')
->action(function ($functionId, $response, $projectDB) {
$function = $projectDB->getDocument($functionId);
@ -237,6 +246,9 @@ App::put('/v1/functions/:functionId')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'update')
->label('sdk.description', '/docs/references/functions/update-function.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_FUNCTION)
->param('functionId', '', new UID(), 'Function unique ID.')
->param('name', '', new Text(128), 'Function name. Max length: 128 chars.')
->param('vars', [], new Assoc(), 'Key-value JSON object.', true)
@ -292,6 +304,9 @@ App::patch('/v1/functions/:functionId/tag')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'updateTag')
->label('sdk.description', '/docs/references/functions/update-tag.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_FUNCTION)
->param('functionId', '', new UID(), 'Function unique ID.')
->param('tag', '', new UID(), 'Tag unique ID.')
->action(function ($functionId, $tag, $response, $projectDB) {
@ -330,6 +345,9 @@ App::delete('/v1/functions/:functionId')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'delete')
->label('sdk.description', '/docs/references/functions/delete-function.md')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_NONE)
->param('functionId', '', new UID(), 'Function unique ID.')
->action(function ($functionId, $response, $projectDB, $deletes) {
/** @var Appwrite\Utopia\Response $response */
@ -361,6 +379,10 @@ App::post('/v1/functions/:functionId/tags')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'createTag')
->label('sdk.description', '/docs/references/functions/create-tag.md')
->label('sdk.request.type', 'multipart/form-data')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_TAG)
->param('functionId', '', new UID(), 'Function unique ID.')
->param('command', '', new Text('1028'), 'Code execution command.')
->param('code', [], new File(), 'Gzip file containing your code.', false)
@ -443,6 +465,9 @@ App::get('/v1/functions/:functionId/tags')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'listTags')
->label('sdk.description', '/docs/references/functions/list-tags.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_TAG_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)
@ -482,6 +507,9 @@ App::get('/v1/functions/:functionId/tags/:tagId')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'getTag')
->label('sdk.description', '/docs/references/functions/get-tag.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_TAG)
->param('functionId', '', new UID(), 'Function unique ID.')
->param('tagId', '', new UID(), 'Tag unique ID.')
->action(function ($functionId, $tagId, $response, $projectDB) {
@ -512,6 +540,9 @@ App::delete('/v1/functions/:functionId/tags/:tagId')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'deleteTag')
->label('sdk.description', '/docs/references/functions/delete-tag.md')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_NONE)
->param('functionId', '', new UID(), 'Function unique ID.')
->param('tagId', '', new UID(), 'Tag unique ID.')
->action(function ($functionId, $tagId, $response, $projectDB, $usage) {
@ -564,6 +595,9 @@ App::post('/v1/functions/:functionId/executions')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'createExecution')
->label('sdk.description', '/docs/references/functions/create-execution.md')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_EXECUTION)
->param('functionId', '', new UID(), 'Function unique ID.')
// ->param('async', 1, new Range(0, 1), 'Execute code asynchronously. Pass 1 for true, 0 for false. Default value is 1.', true)
->action(function ($functionId, /*$async,*/ $response, $project, $projectDB) {
@ -629,6 +663,9 @@ App::get('/v1/functions/:functionId/executions')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'listExecutions')
->label('sdk.description', '/docs/references/functions/list-executions.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->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)
@ -668,6 +705,9 @@ App::get('/v1/functions/:functionId/executions/:executionId')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'getExecution')
->label('sdk.description', '/docs/references/functions/get-execution.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_EXECUTION)
->param('functionId', '', new UID(), 'Function unique ID.')
->param('executionId', '', new UID(), 'Execution unique ID.')
->action(function ($functionId, $executionId, $response, $projectDB) {

View file

@ -13,6 +13,9 @@ App::get('/v1/locale')
->label('sdk.namespace', 'locale')
->label('sdk.method', 'get')
->label('sdk.description', '/docs/references/locale/get-locale.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_LOCALE)
->action(function ($request, $response, $locale, $geodb) {
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Response $response */
@ -71,6 +74,9 @@ App::get('/v1/locale/countries')
->label('sdk.namespace', 'locale')
->label('sdk.method', 'getCountries')
->label('sdk.description', '/docs/references/locale/get-countries.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_COUNTRY_LIST)
->action(function ($response, $locale) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Locale\Locale $locale */
@ -98,6 +104,9 @@ App::get('/v1/locale/countries/eu')
->label('sdk.namespace', 'locale')
->label('sdk.method', 'getCountriesEU')
->label('sdk.description', '/docs/references/locale/get-countries-eu.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_COUNTRY_LIST)
->action(function ($response, $locale) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Locale\Locale $locale */
@ -128,6 +137,9 @@ App::get('/v1/locale/countries/phones')
->label('sdk.namespace', 'locale')
->label('sdk.method', 'getCountriesPhones')
->label('sdk.description', '/docs/references/locale/get-countries-phones.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PHONE_LIST)
->action(function ($response, $locale) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Locale\Locale $locale */
@ -159,6 +171,9 @@ App::get('/v1/locale/continents')
->label('sdk.namespace', 'locale')
->label('sdk.method', 'getContinents')
->label('sdk.description', '/docs/references/locale/get-continents.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_CONTINENT_LIST)
->action(function ($response, $locale) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Locale\Locale $locale */
@ -185,6 +200,9 @@ App::get('/v1/locale/currencies')
->label('sdk.namespace', 'locale')
->label('sdk.method', 'getCurrencies')
->label('sdk.description', '/docs/references/locale/get-currencies.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_CURRENCY_LIST)
->action(function ($response) {
/** @var Appwrite\Utopia\Response $response */
@ -206,6 +224,9 @@ App::get('/v1/locale/languages')
->label('sdk.namespace', 'locale')
->label('sdk.method', 'getLanguages')
->label('sdk.description', '/docs/references/locale/get-languages.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_LANGUAGE_LIST)
->action(function ($response) {
/** @var Appwrite\Utopia\Response $response */

View file

@ -26,6 +26,9 @@ App::post('/v1/projects')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'create')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT)
->param('name', null, new Text(128), 'Project name. Max length: 128 chars.')
->param('teamId', '', new UID(), 'Team unique ID.')
->param('description', '', new Text(256), 'Project description. Max length: 256 chars.', true)
@ -92,6 +95,9 @@ App::get('/v1/projects')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'list')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT_LIST)
->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)
@ -124,6 +130,9 @@ App::get('/v1/projects/:projectId')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'get')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT)
->param('projectId', '', new UID(), 'Project unique ID.')
->action(function ($projectId, $response, $consoleDB) {
/** @var Appwrite\Utopia\Response $response */
@ -314,6 +323,9 @@ App::patch('/v1/projects/:projectId')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'update')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT)
->param('projectId', '', new UID(), 'Project unique ID.')
->param('name', null, new Text(128), 'Project name. Max length: 128 chars.')
->param('description', '', new Text(256), 'Project description. Max length: 256 chars.', true)
@ -361,6 +373,9 @@ App::patch('/v1/projects/:projectId/oauth2')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateOAuth2')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT)
->param('projectId', '', new UID(), 'Project unique ID.')
->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'Provider Name', false)
->param('appId', '', new Text(256), 'Provider app ID. Max length: 256 chars.', true)
@ -393,6 +408,9 @@ App::delete('/v1/projects/:projectId')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'delete')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_NONE)
->param('projectId', '', new UID(), 'Project unique ID.')
->param('password', '', new UID(), 'Your user password for confirmation. Must be between 6 to 32 chars.')
->action(function ($projectId, $password, $response, $user, $consoleDB, $deletes) {
@ -442,6 +460,9 @@ App::post('/v1/projects/:projectId/webhooks')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'createWebhook')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_WEBHOOK)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('name', null, new Text(128), 'Webhook name. Max length: 128 chars.')
->param('events', null, new ArrayList(new WhiteList(array_keys(Config::getParam('events'), true), true)), 'Events list.')
@ -499,6 +520,9 @@ App::get('/v1/projects/:projectId/webhooks')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'listWebhooks')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_WEBHOOK_LIST)
->param('projectId', '', new UID(), 'Project unique ID.')
->action(function ($projectId, $response, $consoleDB) {
/** @var Appwrite\Utopia\Response $response */
@ -524,6 +548,9 @@ App::get('/v1/projects/:projectId/webhooks/:webhookId')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getWebhook')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_WEBHOOK)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('webhookId', null, new UID(), 'Webhook unique ID.')
->action(function ($projectId, $webhookId, $response, $consoleDB) {
@ -551,6 +578,9 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateWebhook')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_WEBHOOK)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('webhookId', null, new UID(), 'Webhook unique ID.')
->param('name', null, new Text(128), 'Webhook name. Max length: 128 chars.')
@ -599,6 +629,9 @@ App::delete('/v1/projects/:projectId/webhooks/:webhookId')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'deleteWebhook')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_NONE)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('webhookId', null, new UID(), 'Webhook unique ID.')
->action(function ($projectId, $webhookId, $response, $consoleDB) {
@ -632,6 +665,9 @@ App::post('/v1/projects/:projectId/keys')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'createKey')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_KEY)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('name', null, new Text(128), 'Key name. Max length: 128 chars.')
->param('scopes', null, new ArrayList(new WhiteList(Config::getParam('scopes'), true)), 'Key scopes list.')
@ -680,6 +716,9 @@ App::get('/v1/projects/:projectId/keys')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'listKeys')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_KEY_LIST)
->param('projectId', null, new UID(), 'Project unique ID.')
->action(function ($projectId, $response, $consoleDB) {
/** @var Appwrite\Utopia\Response $response */
@ -705,6 +744,9 @@ App::get('/v1/projects/:projectId/keys/:keyId')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getKey')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_KEY)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('keyId', null, new UID(), 'Key unique ID.')
->action(function ($projectId, $keyId, $response, $consoleDB) {
@ -729,6 +771,9 @@ App::put('/v1/projects/:projectId/keys/:keyId')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateKey')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_KEY)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('keyId', null, new UID(), 'Key unique ID.')
->param('name', null, new Text(128), 'Key name. Max length: 128 chars.')
@ -767,6 +812,9 @@ App::delete('/v1/projects/:projectId/keys/:keyId')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'deleteKey')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_NONE)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('keyId', null, new UID(), 'Key unique ID.')
->action(function ($projectId, $keyId, $response, $consoleDB) {
@ -800,6 +848,9 @@ App::post('/v1/projects/:projectId/tasks')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'createTask')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_TASK)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('name', null, new Text(128), 'Task name. Max length: 128 chars.')
->param('status', null, new WhiteList(['play', 'pause'], true), 'Task status.')
@ -875,6 +926,9 @@ App::get('/v1/projects/:projectId/tasks')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'listTasks')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_TASK_LIST)
->param('projectId', '', new UID(), 'Project unique ID.')
->action(function ($projectId, $response, $consoleDB) {
/** @var Appwrite\Utopia\Response $response */
@ -901,6 +955,9 @@ App::get('/v1/projects/:projectId/tasks/:taskId')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getTask')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_TASK)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('taskId', null, new UID(), 'Task unique ID.')
->action(function ($projectId, $taskId, $response, $consoleDB) {
@ -928,6 +985,9 @@ App::put('/v1/projects/:projectId/tasks/:taskId')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateTask')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_TASK)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('taskId', null, new UID(), 'Task unique ID.')
->param('name', null, new Text(128), 'Task name. Max length: 128 chars.')
@ -991,6 +1051,9 @@ App::delete('/v1/projects/:projectId/tasks/:taskId')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'deleteTask')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_NONE)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('taskId', null, new UID(), 'Task unique ID.')
->action(function ($projectId, $taskId, $response, $consoleDB) {
@ -1024,6 +1087,9 @@ App::post('/v1/projects/:projectId/platforms')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'createPlatform')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PLATFORM)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('type', null, new WhiteList(['web', 'flutter-ios', 'flutter-android', 'ios', 'android', 'unity'], true), 'Platform type.')
->param('name', null, new Text(128), 'Platform name. Max length: 128 chars.')
@ -1079,6 +1145,9 @@ App::get('/v1/projects/:projectId/platforms')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'listPlatforms')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PLATFORM_LIST)
->param('projectId', '', new UID(), 'Project unique ID.')
->action(function ($projectId, $response, $consoleDB) {
/** @var Appwrite\Utopia\Response $response */
@ -1104,6 +1173,9 @@ App::get('/v1/projects/:projectId/platforms/:platformId')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getPlatform')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PLATFORM)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('platformId', null, new UID(), 'Platform unique ID.')
->action(function ($projectId, $platformId, $response, $consoleDB) {
@ -1131,6 +1203,9 @@ App::put('/v1/projects/:projectId/platforms/:platformId')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updatePlatform')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PLATFORM)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('platformId', null, new UID(), 'Platform unique ID.')
->param('name', null, new Text(128), 'Platform name. Max length: 128 chars.')
@ -1174,6 +1249,9 @@ App::delete('/v1/projects/:projectId/platforms/:platformId')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'deletePlatform')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_NONE)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('platformId', null, new UID(), 'Platform unique ID.')
->action(function ($projectId, $platformId, $response, $consoleDB) {
@ -1207,6 +1285,9 @@ App::post('/v1/projects/:projectId/domains')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'createDomain')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_DOMAIN)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('domain', null, new DomainValidator(), 'Domain name.')
->action(function ($projectId, $domain, $response, $consoleDB) {
@ -1271,6 +1352,9 @@ App::get('/v1/projects/:projectId/domains')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'listDomains')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_DOMAIN_LIST)
->param('projectId', '', new UID(), 'Project unique ID.')
->action(function ($projectId, $response, $consoleDB) {
/** @var Appwrite\Utopia\Response $response */
@ -1296,6 +1380,9 @@ App::get('/v1/projects/:projectId/domains/:domainId')
->label('scope', 'projects.read')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'getDomain')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_DOMAIN)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('domainId', null, new UID(), 'Domain unique ID.')
->action(function ($projectId, $domainId, $response, $consoleDB) {
@ -1323,6 +1410,9 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateDomainVerification')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_DOMAIN)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('domainId', null, new UID(), 'Domain unique ID.')
->action(function ($projectId, $domainId, $response, $consoleDB) {
@ -1381,6 +1471,9 @@ App::delete('/v1/projects/:projectId/domains/:domainId')
->label('scope', 'projects.write')
->label('sdk.namespace', 'projects')
->label('sdk.method', 'deleteDomain')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_NONE)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('domainId', null, new UID(), 'Domain unique ID.')
->action(function ($projectId, $domainId, $response, $consoleDB) {

View file

@ -32,8 +32,11 @@ App::post('/v1/storage/files')
->label('sdk.namespace', 'storage')
->label('sdk.method', 'createFile')
->label('sdk.description', '/docs/references/storage/create-file.md')
->label('sdk.consumes', 'multipart/form-data')
->label('sdk.request.type', 'multipart/form-data')
->label('sdk.methodType', 'upload')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_FILE)
->param('file', [], new File(), 'Binary file.', false)
->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.')
@ -46,12 +49,10 @@ App::post('/v1/storage/files')
/** @var Appwrite\Event\Event $usage */
$file = $request->getFiles('file');
$read = (empty($read)) ? ['user:'.$user->getId()] : $read;
$write = (empty($write)) ? ['user:'.$user->getId()] : $write;
/*
* Validators
*/
* Validators
*/
//$fileType = new FileType(array(FileType::FILE_TYPE_PNG, FileType::FILE_TYPE_GIF, FileType::FILE_TYPE_JPEG));
$fileSize = new FileSize(App::getEnv('_APP_STORAGE_LIMIT', 0));
$upload = new Upload();
@ -163,6 +164,9 @@ App::get('/v1/storage/files')
->label('sdk.namespace', 'storage')
->label('sdk.method', 'listFiles')
->label('sdk.description', '/docs/references/storage/list-files.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_FILE_LIST)
->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)
@ -197,6 +201,9 @@ App::get('/v1/storage/files/:fileId')
->label('sdk.namespace', 'storage')
->label('sdk.method', 'getFile')
->label('sdk.description', '/docs/references/storage/get-file.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_FILE)
->param('fileId', '', new UID(), 'File unique ID.')
->action(function ($fileId, $response, $projectDB) {
/** @var Appwrite\Utopia\Response $response */
@ -219,7 +226,8 @@ App::get('/v1/storage/files/:fileId/preview')
->label('sdk.namespace', 'storage')
->label('sdk.method', 'getFilePreview')
->label('sdk.description', '/docs/references/storage/get-file-preview.md')
->label('sdk.response.type', 'image/*')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_IMAGE)
->label('sdk.methodType', 'location')
->param('fileId', '', new UID(), 'File unique ID')
->param('width', 0, new Range(0, 4000), 'Resize preview image width, Pass an integer between 0 to 4000.', true)
@ -345,7 +353,8 @@ App::get('/v1/storage/files/:fileId/download')
->label('sdk.namespace', 'storage')
->label('sdk.method', 'getFileDownload')
->label('sdk.description', '/docs/references/storage/get-file-download.md')
->label('sdk.response.type', '*')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', '*/*')
->label('sdk.methodType', 'location')
->param('fileId', '', new UID(), 'File unique ID.')
->action(function ($fileId, $response, $projectDB) {
@ -400,7 +409,8 @@ App::get('/v1/storage/files/:fileId/view')
->label('sdk.namespace', 'storage')
->label('sdk.method', 'getFileView')
->label('sdk.description', '/docs/references/storage/get-file-view.md')
->label('sdk.response.type', '*')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', '*/*')
->label('sdk.methodType', 'location')
->param('fileId', '', new UID(), 'File unique ID.')
->param('as', '', new WhiteList(['pdf', /*'html',*/ 'text'], true), 'Choose a file format to convert your file to. Currently you can only convert word and pdf files to pdf or txt. This option is currently experimental only, use at your own risk.', true)
@ -474,6 +484,9 @@ App::put('/v1/storage/files/:fileId')
->label('sdk.namespace', 'storage')
->label('sdk.method', 'updateFile')
->label('sdk.description', '/docs/references/storage/update-file.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_FILE)
->param('fileId', '', new UID(), 'File unique ID.')
->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.')
@ -517,6 +530,9 @@ App::delete('/v1/storage/files/:fileId')
->label('sdk.namespace', 'storage')
->label('sdk.method', 'deleteFile')
->label('sdk.description', '/docs/references/storage/delete-file.md')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_NONE)
->param('fileId', '', new UID(), 'File unique ID.')
->action(function ($fileId, $response, $projectDB, $webhooks, $audits, $usage) {
/** @var Appwrite\Utopia\Response $response */

View file

@ -28,16 +28,21 @@ App::post('/v1/teams')
->label('sdk.namespace', 'teams')
->label('sdk.method', 'create')
->label('sdk.description', '/docs/references/teams/create-team.md')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_TEAM)
->param('name', null, new Text(128), 'Team name. Max length: 128 chars.')
->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)
->action(function ($name, $roles, $response, $user, $projectDB, $mode) {
->action(function ($name, $roles, $response, $user, $projectDB) {
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Document $user */
/** @var Appwrite\Database\Database $projectDB */
/** @var bool $mode */
Authorization::disable();
$isPreviliggedUser = Auth::isPreviliggedUser(Authorization::$roles);
$isAppUser = Auth::isAppUser(Authorization::$roles);
$team = $projectDB->createDocument([
'$collection' => Database::SYSTEM_COLLECTION_TEAMS,
'$permissions' => [
@ -45,7 +50,7 @@ App::post('/v1/teams')
'write' => ['team:{self}/owner'],
],
'name' => $name,
'sum' => ($mode !== APP_MODE_ADMIN && $user->getId()) ? 1 : 0,
'sum' => ($isPreviliggedUser || $isAppUser) ? 0 : 1,
'dateCreated' => \time(),
]);
@ -55,7 +60,7 @@ App::post('/v1/teams')
throw new Exception('Failed saving team to DB', 500);
}
if ($mode !== APP_MODE_ADMIN && $user->getId()) { // Don't add user on server mode
if (!$isPreviliggedUser && !$isAppUser) { // Don't add user on server mode
$membership = new Document([
'$collection' => Database::SYSTEM_COLLECTION_MEMBERSHIPS,
'$permissions' => [
@ -85,7 +90,7 @@ App::post('/v1/teams')
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($team, Response::MODEL_TEAM)
;
}, ['response', 'user', 'projectDB', 'mode']);
}, ['response', 'user', 'projectDB']);
App::get('/v1/teams')
->desc('List Teams')
@ -95,6 +100,9 @@ App::get('/v1/teams')
->label('sdk.namespace', 'teams')
->label('sdk.method', 'list')
->label('sdk.description', '/docs/references/teams/list-teams.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_TEAM_LIST)
->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)
@ -129,6 +137,9 @@ App::get('/v1/teams/:teamId')
->label('sdk.namespace', 'teams')
->label('sdk.method', 'get')
->label('sdk.description', '/docs/references/teams/get-team.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_TEAM)
->param('teamId', '', new UID(), 'Team unique ID.')
->action(function ($teamId, $response, $projectDB) {
/** @var Appwrite\Utopia\Response $response */
@ -151,6 +162,9 @@ App::put('/v1/teams/:teamId')
->label('sdk.namespace', 'teams')
->label('sdk.method', 'update')
->label('sdk.description', '/docs/references/teams/update-team.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_TEAM)
->param('teamId', '', new UID(), 'Team unique ID.')
->param('name', null, new Text(128), 'Team name. Max length: 128 chars.')
->action(function ($teamId, $name, $response, $projectDB) {
@ -182,6 +196,9 @@ App::delete('/v1/teams/:teamId')
->label('sdk.namespace', 'teams')
->label('sdk.method', 'delete')
->label('sdk.description', '/docs/references/teams/delete-team.md')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_NONE)
->param('teamId', '', new UID(), 'Team unique ID.')
->action(function ($teamId, $response, $projectDB) {
/** @var Appwrite\Utopia\Response $response */
@ -223,19 +240,24 @@ App::post('/v1/teams/:teamId/memberships')
->label('sdk.namespace', 'teams')
->label('sdk.method', 'createMembership')
->label('sdk.description', '/docs/references/teams/create-team-membership.md')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_MEMBERSHIP)
->param('teamId', '', new UID(), 'Team unique ID.')
->param('email', '', new Email(), 'New team member email.')
->param('name', '', new Text(128), 'New team member name. Max length: 128 chars.', true)
->param('roles', [], new ArrayList(new Key()), 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](/docs/permissions). Max length for each role is 32 chars.')
->param('url', '', function ($clients) { return new Host($clients); }, 'URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients']) // TODO add our own built-in confirm page
->action(function ($teamId, $email, $name, $roles, $url, $response, $project, $user, $projectDB, $locale, $audits, $mails, $mode) {
->action(function ($teamId, $email, $name, $roles, $url, $response, $project, $user, $projectDB, $locale, $audits, $mails) {
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Document $project */
/** @var Appwrite\Database\Document $user */
/** @var Appwrite\Database\Database $projectDB */
/** @var Appwrite\Event\Event $audits */
/** @var Appwrite\Event\Event $mails */
/** @var bool $mode */
$isPreviliggedUser = Auth::isPreviliggedUser(Authorization::$roles);
$isAppUser = Auth::isAppUser(Authorization::$roles);
$name = (empty($name)) ? $email : $name;
$team = $projectDB->getDocument($teamId);
@ -305,7 +327,7 @@ App::post('/v1/teams/:teamId/memberships')
}
}
if (!$isOwner && APP_MODE_ADMIN !== $mode && $user->getId()) { // Not owner, not admin, not app (server)
if (!$isOwner && !$isPreviliggedUser && !$isAppUser) { // Not owner, not admin, not app (server)
throw new Exception('User is not allowed to send invitations for this team', 401);
}
@ -321,12 +343,12 @@ App::post('/v1/teams/:teamId/memberships')
'teamId' => $team->getId(),
'roles' => $roles,
'invited' => \time(),
'joined' => (APP_MODE_ADMIN === $mode || !$user->getId()) ? \time() : 0,
'confirm' => (APP_MODE_ADMIN === $mode || !$user->getId()),
'joined' => ($isPreviliggedUser || $isAppUser) ? \time() : 0,
'confirm' => ($isPreviliggedUser || $isAppUser),
'secret' => Auth::hash($secret),
]);
if (APP_MODE_ADMIN === $mode || !$user->getId()) { // Allow admin to create membership
if ($isPreviliggedUser || $isAppUser) { // Allow admin to create membership
Authorization::disable();
$membership = $projectDB->createDocument($membership->getArrayCopy());
@ -377,7 +399,7 @@ App::post('/v1/teams/:teamId/memberships')
->setParam('{{text-cta}}', '#ffffff')
;
if (APP_MODE_ADMIN !== $mode && $user->getId()) { // No need in comfirmation when in admin or app mode
if (!$isPreviliggedUser && !$isAppUser) { // No need in comfirmation when in admin or app mode
$mails
->setParam('event', 'teams.membership.create')
->setParam('from', ($project->getId() === 'console') ? '' : \sprintf($locale->getText('account.emails.team'), $project->getAttribute('name')))
@ -402,7 +424,7 @@ App::post('/v1/teams/:teamId/memberships')
'name' => $name,
])), Response::MODEL_MEMBERSHIP)
;
}, ['response', 'project', 'user', 'projectDB', 'locale', 'audits', 'mails', 'mode']);
}, ['response', 'project', 'user', 'projectDB', 'locale', 'audits', 'mails']);
App::get('/v1/teams/:teamId/memberships')
->desc('Get Team Memberships')
@ -412,6 +434,9 @@ App::get('/v1/teams/:teamId/memberships')
->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)
@ -463,6 +488,9 @@ App::patch('/v1/teams/:teamId/memberships/:inviteId/status')
->label('sdk.namespace', 'teams')
->label('sdk.method', 'updateMembershipStatus')
->label('sdk.description', '/docs/references/teams/update-team-membership-status.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_MEMBERSHIP)
->param('teamId', '', new UID(), 'Team unique ID.')
->param('inviteId', '', new UID(), 'Invite unique ID.')
->param('userId', '', new UID(), 'User unique ID.')
@ -554,7 +582,7 @@ App::patch('/v1/teams/:teamId/memberships/:inviteId/status')
'$collection' => Database::SYSTEM_COLLECTION_TOKENS,
'$permissions' => ['read' => ['user:'.$user->getId()], 'write' => ['user:'.$user->getId()]],
'type' => Auth::TOKEN_TYPE_LOGIN,
'secret' => Auth::hash($secret), // On way hash encryption to protect DB leak
'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak
'expire' => $expiry,
'userAgent' => $request->getUserAgent('UNKNOWN'),
'ip' => $request->getIP(),
@ -638,6 +666,9 @@ App::delete('/v1/teams/:teamId/memberships/:inviteId')
->label('sdk.namespace', 'teams')
->label('sdk.method', 'deleteMembership')
->label('sdk.description', '/docs/references/teams/delete-team-membership.md')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_NONE)
->param('teamId', '', new UID(), 'Team unique ID.')
->param('inviteId', '', new UID(), 'Invite unique ID.')
->action(function ($teamId, $inviteId, $response, $projectDB, $audits) {

View file

@ -27,6 +27,9 @@ App::post('/v1/users')
->label('sdk.namespace', 'users')
->label('sdk.method', 'create')
->label('sdk.description', '/docs/references/users/create-user.md')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER)
->param('email', '', new Email(), 'User email.')
->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)
@ -80,6 +83,9 @@ App::get('/v1/users')
->label('sdk.namespace', 'users')
->label('sdk.method', 'list')
->label('sdk.description', '/docs/references/users/list-users.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER_LIST)
->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)
@ -114,6 +120,9 @@ App::get('/v1/users/:userId')
->label('sdk.namespace', 'users')
->label('sdk.method', 'get')
->label('sdk.description', '/docs/references/users/get-user.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER)
->param('userId', '', new UID(), 'User unique ID.')
->action(function ($userId, $response, $projectDB) {
/** @var Appwrite\Utopia\Response $response */
@ -136,6 +145,9 @@ App::get('/v1/users/:userId/prefs')
->label('sdk.namespace', 'users')
->label('sdk.method', 'getPrefs')
->label('sdk.description', '/docs/references/users/get-user-prefs.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_ANY)
->param('userId', '', new UID(), 'User unique ID.')
->action(function ($userId, $response, $projectDB) {
/** @var Appwrite\Utopia\Response $response */
@ -149,7 +161,7 @@ App::get('/v1/users/:userId/prefs')
$prefs = $user->getAttribute('prefs', '');
$response->json($prefs);
$response->dynamic(new Document($prefs), Response::MODEL_ANY);
}, ['response', 'projectDB']);
App::get('/v1/users/:userId/sessions')
@ -160,6 +172,9 @@ App::get('/v1/users/:userId/sessions')
->label('sdk.namespace', 'users')
->label('sdk.method', 'getSessions')
->label('sdk.description', '/docs/references/users/get-user-sessions.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_SESSION_LIST)
->param('userId', '', new UID(), 'User unique ID.')
->action(function ($userId, $response, $projectDB, $locale) {
/** @var Appwrite\Utopia\Response $response */
@ -203,6 +218,9 @@ App::get('/v1/users/:userId/logs')
->label('sdk.namespace', 'users')
->label('sdk.method', 'getLogs')
->label('sdk.description', '/docs/references/users/get-user-logs.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_LOG_LIST)
->param('userId', '', new UID(), 'User unique ID.')
->action(function ($userId, $response, $register, $project, $projectDB, $locale, $geodb) {
/** @var Appwrite\Utopia\Response $response */
@ -309,6 +327,9 @@ App::patch('/v1/users/:userId/status')
->label('sdk.namespace', 'users')
->label('sdk.method', 'updateStatus')
->label('sdk.description', '/docs/references/users/update-user-status.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER)
->param('userId', '', new UID(), 'User unique ID.')
->param('status', '', new WhiteList([Auth::USER_STATUS_ACTIVATED, Auth::USER_STATUS_BLOCKED, Auth::USER_STATUS_UNACTIVATED], true), 'User Status code. To activate the user pass '.Auth::USER_STATUS_ACTIVATED.', to block the user pass '.Auth::USER_STATUS_BLOCKED.' and for disabling the user pass '.Auth::USER_STATUS_UNACTIVATED)
->action(function ($userId, $status, $response, $projectDB) {
@ -340,6 +361,9 @@ App::patch('/v1/users/:userId/prefs')
->label('sdk.namespace', 'users')
->label('sdk.method', 'updatePrefs')
->label('sdk.description', '/docs/references/users/update-user-prefs.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_ANY)
->param('userId', '', new UID(), 'User unique ID.')
->param('prefs', '', new Assoc(), 'Prefs key-value JSON object.')
->action(function ($userId, $prefs, $response, $projectDB) {
@ -360,7 +384,7 @@ App::patch('/v1/users/:userId/prefs')
throw new Exception('Failed saving user to DB', 500);
}
$response->json($prefs);
$response->dynamic(new Document($prefs), Response::MODEL_ANY);
}, ['response', 'projectDB']);
App::delete('/v1/users/:userId/sessions/:sessionId')
@ -372,6 +396,9 @@ App::delete('/v1/users/:userId/sessions/:sessionId')
->label('sdk.namespace', 'users')
->label('sdk.method', 'deleteSession')
->label('sdk.description', '/docs/references/users/delete-user-session.md')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_NONE)
->label('abuse-limit', 100)
->param('userId', '', new UID(), 'User unique ID.')
->param('sessionId', null, new UID(), 'User unique session ID.')
@ -412,6 +439,9 @@ App::delete('/v1/users/:userId/sessions')
->label('sdk.namespace', 'users')
->label('sdk.method', 'deleteSessions')
->label('sdk.description', '/docs/references/users/delete-user-sessions.md')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_NONE)
->label('abuse-limit', 100)
->param('userId', '', new UID(), 'User unique ID.')
->action(function ($userId, $response, $projectDB, $webhooks) {
@ -449,6 +479,9 @@ App::delete('/v1/users/:userId')
->label('sdk.namespace', 'users')
->label('sdk.method', 'deleteUser')
->label('sdk.description', '/docs/references/users/delete-user.md')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_NONE)
->label('abuse-limit', 100)
->param('userId', '', function () {return new UID();}, 'User unique ID.')
->action(function ($userId, $response, $projectDB, $webhooks, $deletes) {

View file

@ -35,8 +35,6 @@ App::init(function ($utopia, $request, $response, $console, $project, $user, $lo
/** @var Appwrite\Event\Event $deletes */
/** @var bool $mode */
/** @var array $clients */
Authorization::$roles = ['*'];
$localeParam = (string)$request->getParam('locale', $request->getHeader('x-appwrite-locale', ''));

View file

@ -157,7 +157,7 @@ App::post('/v1/mock/tests/general/upload')
->label('sdk.namespace', 'general')
->label('sdk.method', 'upload')
->label('sdk.description', 'Mock a delete request for SDK tests')
->label('sdk.consumes', 'multipart/form-data')
->label('sdk.request.type', 'multipart/form-data')
->label('sdk.mock', true)
->param('x', '', new Text(100), 'Sample string param')
->param('y', '', new Numeric(), 'Sample numeric param')

View file

@ -1,11 +1,13 @@
<?php
use Appwrite\Template\Template;
use Appwrite\Specification\Format\OpenAPI3;
use Appwrite\Specification\Format\Swagger2;
use Appwrite\Specification\Specification;
use Utopia\App;
use Utopia\View;
use Utopia\Config\Config;
use Utopia\Exception;
use Utopia\Validator\WhiteList;
use Utopia\Validator\Range;
App::init(function ($layout) {
/** @var Utopia\View $layout */
@ -180,30 +182,26 @@ App::get('/error/:code')
->setParam('body', $page);
}, ['layout']);
App::get('/open-api-2.json')
App::get('/specs/:format')
->groups(['web', 'home'])
->label('scope', 'public')
->label('docs', false)
->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('extensions', 0, new Range(0, 1), 'Show extra data.', true)
->param('tests', 0, new Range(0, 1), 'Include only test services.', true)
->action(function ($platform, $extensions, $tests, $utopia, $request, $response) {
->action(function ($format, $platform, $utopia, $request, $response) {
/** @var Utopia\App $utopia */
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Response $response */
$security = [
APP_PLATFORM_CLIENT => ['Project' => []],
APP_PLATFORM_SERVER => ['Project' => [], 'Key' => []],
APP_PLATFORM_CONSOLE => ['Project' => [], 'Key' => []],
];
$platforms = [
'client' => APP_PLATFORM_CLIENT,
'server' => APP_PLATFORM_SERVER,
'all' => APP_PLATFORM_CONSOLE,
'console' => APP_PLATFORM_CONSOLE,
];
$routes = [];
$models = [];
$keys = [
APP_PLATFORM_CLIENT => [
'Project' => [
@ -267,98 +265,14 @@ App::get('/open-api-2.json')
],
];
/*
* Specifications (v3.0.0):
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md
*/
$output = [
'swagger' => '2.0',
'info' => [
'version' => APP_VERSION_STABLE,
'title' => APP_NAME,
'description' => 'Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs)',
'termsOfService' => 'https://appwrite.io/policy/terms',
'contact' => [
'name' => 'Appwrite Team',
'url' => 'https://appwrite.io/support',
'email' => App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM),
],
'license' => [
'name' => 'BSD-3-Clause',
'url' => 'https://raw.githubusercontent.com/appwrite/appwrite/master/LICENSE',
],
],
'host' => \parse_url(App::getEnv('_APP_HOME', $request->getHostname()), PHP_URL_HOST),
'basePath' => '/v1',
'schemes' => ['https'],
'consumes' => ['application/json', 'multipart/form-data'],
'produces' => ['application/json'],
'securityDefinitions' => $keys[$platform],
'paths' => [],
'definitions' => [
// 'Pet' => [
// 'required' => ['id', 'name'],
// 'properties' => [
// 'id' => [
// 'type' => 'integer',
// 'format' => 'int64',
// ],
// 'name' => [
// 'type' => 'string',
// ],
// 'tag' => [
// 'type' => 'string',
// ],
// ],
// ],
// 'Pets' => array(
// 'type' => 'array',
// 'items' => array(
// '$ref' => '#/definitions/Pet',
// ),
// ),
'Error' => array(
'required' => array(
0 => 'code',
1 => 'message',
),
'properties' => array(
'code' => array(
'type' => 'integer',
'format' => 'int32',
),
'message' => array(
'type' => 'string',
),
),
),
],
'externalDocs' => [
'description' => 'Full API docs, specs and tutorials',
'url' => $request->getProtocol().'://'.$request->getHostname().'/docs',
],
$security = [
APP_PLATFORM_CLIENT => ['Project' => []],
APP_PLATFORM_SERVER => ['Project' => [], 'Key' => []],
APP_PLATFORM_CONSOLE => ['Project' => [], 'Key' => []],
];
if ($extensions) {
if (isset($output['securityDefinitions']['Project'])) {
$output['securityDefinitions']['Project']['extensions'] = ['demo' => '5df5acd0d48c2'];
}
if (isset($output['securityDefinitions']['Key'])) {
$output['securityDefinitions']['Key']['extensions'] = ['demo' => '919c2d18fb5d4...a2ae413da83346ad2'];
}
if (isset($output['securityDefinitions']['Locale'])) {
$output['securityDefinitions']['Locale']['extensions'] = ['demo' => 'en'];
}
if (isset($output['securityDefinitions']['Mode'])) {
$output['securityDefinitions']['Mode']['extensions'] = ['demo' => ''];
}
}
foreach ($utopia->getRoutes() as $key => $method) {
foreach ($method as $route) { /* @var $route \Utopia\Route */
foreach ($method as $route) { /** @var \Utopia\Route $route */
if (!$route->getLabel('docs', true)) {
continue;
}
@ -375,184 +289,56 @@ App::get('/open-api-2.json')
continue;
}
$url = \str_replace('/v1', '', $route->getURL());
$scope = $route->getLabel('scope', '');
$hide = $route->getLabel('sdk.hide', false);
$consumes = ['application/json'];
if ($hide) {
continue;
$routes[] = $route;
$model = $response->getModel($route->getLabel('sdk.response.model', 'none'));
if($model) {
$models[$model->getType()] = $model;
}
$desc = (!empty($route->getLabel('sdk.description', ''))) ? \realpath(__DIR__.'/../../../'.$route->getLabel('sdk.description', '')) : null;
$temp = [
'summary' => $route->getDesc(),
'operationId' => $route->getLabel('sdk.method', \uniqid()),
'consumes' => [],
'tags' => [$route->getLabel('sdk.namespace', 'default')],
'description' => ($desc) ? \file_get_contents($desc) : '',
// 'responses' => [
// 200 => [
// 'description' => 'An paged array of pets',
// 'schema' => [
// '$ref' => '#/definitions/Pet',
// ],
// ],
// ],
];
if ($extensions) {
$platformList = $route->getLabel('sdk.platform', []);
$temp['extensions'] = [
'weight' => $route->getOrder(),
'cookies' => $route->getLabel('sdk.cookies', false),
'type' => $route->getLabel('sdk.methodType', ''),
'demo' => 'docs/examples/'. Template::fromCamelCaseToDash($route->getLabel('sdk.namespace', 'default')).'/'.Template::fromCamelCaseToDash($temp['operationId']).'.md',
'edit' => 'https://github.com/appwrite/appwrite/edit/master' . $route->getLabel('sdk.description', ''),
'rate-limit' => $route->getLabel('abuse-limit', 0),
'rate-time' => $route->getLabel('abuse-time', 3600),
'rate-key' => $route->getLabel('abuse-key', 'url:{url},ip:{ip}'),
'scope' => $route->getLabel('scope', ''),
'platforms' => $platformList,
];
}
if ((!empty($scope))) { // && 'public' != $scope
$temp['security'][] = $route->getLabel('sdk.security', $security[$platform]);
}
$requestBody = [
'content' => [
'application/x-www-form-urlencoded' => [
'schema' => [
'type' => 'object',
'properties' => [],
],
'required' => [],
],
],
];
foreach ($route->getParams() as $name => $param) {
$validator = (\is_callable($param['validator'])) ? call_user_func_array($param['validator'], $utopia->getResources($param['resources'])) : $param['validator']; /* @var $validator \Utopia\Validator */
$node = [
'name' => $name,
'description' => $param['description'],
'required' => !$param['optional'],
];
switch ((!empty($validator)) ? \get_class($validator) : '') {
case 'Utopia\Validator\Text':
$node['type'] = 'string';
$node['x-example'] = '['.\strtoupper(Template::fromCamelCaseToSnake($node['name'])).']';
break;
case 'Utopia\Validator\Boolean':
$node['type'] = 'boolean';
$node['x-example'] = false;
break;
case 'Appwrite\Database\Validator\UID':
$node['type'] = 'string';
$node['x-example'] = '['.\strtoupper(Template::fromCamelCaseToSnake($node['name'])).']';
break;
case 'Utopia\Validator\Email':
$node['type'] = 'string';
$node['format'] = 'email';
$node['x-example'] = 'email@example.com';
break;
case 'Utopia\Validator\URL':
$node['type'] = 'string';
$node['format'] = 'url';
$node['x-example'] = 'https://example.com';
break;
case 'Utopia\Validator\JSON':
case 'Utopia\Validator\Mock':
case 'Utopia\Validator\Assoc':
$node['type'] = 'object';
$node['type'] = 'object';
$node['x-example'] = '{}';
//$node['format'] = 'json';
break;
case 'Appwrite\Storage\Validator\File':
$consumes = ['multipart/form-data'];
$node['type'] = 'file';
break;
case 'Utopia\Validator\ArrayList':
$node['type'] = 'array';
$node['collectionFormat'] = 'multi';
$node['items'] = [
'type' => 'string',
];
break;
case 'Appwrite\Auth\Validator\Password':
$node['type'] = 'string';
$node['format'] = 'format';
$node['x-example'] = 'password';
break;
case 'Utopia\Validator\Range': /* @var $validator \Utopia\Validator\Range */
$node['type'] = 'integer';
$node['format'] = 'int32';
$node['x-example'] = $validator->getMin();
break;
case 'Utopia\Validator\Numeric':
$node['type'] = 'integer';
$node['format'] = 'int32';
break;
case 'Utopia\Validator\Length':
$node['type'] = 'string';
break;
case 'Utopia\Validator\Host':
$node['type'] = 'string';
$node['format'] = 'url';
$node['x-example'] = 'https://example.com';
break;
case 'Utopia\Validator\WhiteList': /* @var $validator \Utopia\Validator\WhiteList */
$node['type'] = 'string';
$node['x-example'] = $validator->getList()[0];
break;
default:
$node['type'] = 'string';
break;
}
if ($param['optional'] && !\is_null($param['default'])) { // Param has default value
$node['default'] = $param['default'];
}
if (false !== \strpos($url, ':'.$name)) { // Param is in URL path
$node['in'] = 'path';
$temp['parameters'][] = $node;
} elseif ($key == 'GET') { // Param is in query
$node['in'] = 'query';
$temp['parameters'][] = $node;
} else { // Param is in payload
$node['in'] = 'formData';
$temp['parameters'][] = $node;
$requestBody['content']['application/x-www-form-urlencoded']['schema']['properties'][] = $node;
if (!$param['optional']) {
$requestBody['content']['application/x-www-form-urlencoded']['required'][] = $name;
}
}
$url = \str_replace(':'.$name, '{'.$name.'}', $url);
}
$temp['consumes'] = $consumes;
$output['paths'][$url][\strtolower($route->getMethod())] = $temp;
}
}
/*foreach ($consoleDB->getMocks() as $mock) {
var_dump($mock['name']);
}*/
$models = $response->getModels();
\ksort($output['paths']);
foreach ($models as $key => $value) {
if($platform !== APP_PLATFORM_CONSOLE && !$value->isPublic()) {
unset($models[$key]);
}
}
switch ($format) {
case 'swagger2':
$format = new Swagger2($utopia, $routes, $models, $keys[$platform], $security[$platform]);
break;
case 'open-api3':
$format = new OpenAPI3($utopia, $routes, $models, $keys[$platform], $security[$platform]);
break;
default:
throw new Exception('Format not found', 404);
break;
}
$specs = new Specification($format);
$format
->setParam('name', APP_NAME)
->setParam('description', 'Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs)')
->setParam('endpoint', App::getEnv('_APP_HOME', $request->getProtocol().'://'.$request->getHostname()).'/v1')
->setParam('version', APP_VERSION_STABLE)
->setParam('terms', App::getEnv('_APP_HOME', $request->getProtocol().'://'.$request->getHostname()).'/policy/terms')
->setParam('support.email', App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM))
->setParam('support.url', App::getEnv('_APP_HOME', $request->getProtocol().'://'.$request->getHostname()).'/support')
->setParam('contact.name', APP_NAME.' Team')
->setParam('contact.email', App::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM))
->setParam('contact.url', App::getEnv('_APP_HOME', $request->getProtocol().'://'.$request->getHostname()).'/support')
->setParam('license.name', 'BSD-3-Clause')
->setParam('license.url', 'https://raw.githubusercontent.com/appwrite/appwrite/master/LICENSE')
->setParam('docs.description', 'Full API docs, specs and tutorials')
->setParam('docs.url', App::getEnv('_APP_HOME', $request->getProtocol().'://'.$request->getHostname()).'/docs')
;
$response
->json($output);
->json($specs->parse());
}, ['utopia', 'request', 'response']);

View file

@ -2,6 +2,7 @@
require_once __DIR__.'/../vendor/autoload.php';
use Appwrite\Database\Validator\Authorization;
use Utopia\Swoole\Files;
use Utopia\Swoole\Request;
use Appwrite\Utopia\Response;
@ -19,8 +20,6 @@ ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
sleep(2);
$http = new Server("0.0.0.0", 80);
$payloadSize = max(4000000 /* 4mb */, App::getEnv('_APP_STORAGE_LIMIT', 10000000 /* 10mb */));
@ -96,6 +95,9 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
$app = new App('America/New_York');
try {
Authorization::cleanRoles();
Authorization::setRole('*');
$app->run($request, $response);
} catch (\Throwable $th) {
Console::error('[Error] Type: '.get_class($th));

View file

@ -34,9 +34,10 @@ const APP_DOMAIN = 'appwrite.io';
const APP_EMAIL_TEAM = 'team@localhost.test'; // Default email address
const APP_EMAIL_SECURITY = 'security@localhost.test'; // Default security email address
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_CACHE_BUSTER = 139;
const APP_CACHE_BUSTER = 140;
const APP_VERSION_STABLE = '0.7.0';
const APP_STORAGE_UPLOADS = '/storage/uploads';
const APP_STORAGE_FUNCTIONS = '/storage/functions';
@ -381,8 +382,7 @@ App::setResource('user', function($mode, $project, $console, $request, $response
$session = Auth::decodeSession(
$request->getCookie(Auth::$cookieName, // Get sessions
$request->getCookie(Auth::$cookieName.'_legacy', // Get fallback session from old clients (no SameSite support)
$request->getHeader('x-appwrite-key', '')))); // Get API Key
$request->getCookie(Auth::$cookieName.'_legacy', '')));// Get fallback session from old clients (no SameSite support)
// Get fallback session from clients who block 3rd-party cookies
$response->addHeader('X-Debug-Fallback', 'false');
@ -463,7 +463,7 @@ App::setResource('projectDB', function($register, $project) {
App::setResource('mode', function($request) {
/** @var Utopia\Swoole\Request $request */
return $request->getParam('mode', $request->getHeader('x-appwrite-mode', 'default'));
return $request->getParam('mode', $request->getHeader('x-appwrite-mode', APP_MODE_DEFAULT));
}, ['request']);
App::setResource('geodb', function($register) {

View file

@ -21,41 +21,41 @@ $cli
Console::log("\n".'👩‍⚕️ Running '.APP_NAME.' Doctor for version '.App::getEnv('_APP_VERSION', 'UNKNOWN').' ...'."\n");
Console::log('Checking for production best practices...');
$domain = new Domain(App::getEnv('_APP_DOMAIN'));
if(!$domain->isKnown() || $domain->isTest()) {
Console::log('🔴 Hostname has a public suffix ('.$domain->get().')');
Console::log('🔴 Hostname has no public suffix ('.$domain->get().')');
}
else {
Console::log('🟢 Hostname has a public suffix ('.$domain->get().')');
}
$domain = new Domain(App::getEnv('_APP_DOMAIN_TARGET'));
if(!$domain->isKnown() || $domain->isTest()) {
Console::log('🔴 CNAME target has a public suffix ('.$domain->get().')');
Console::log('🔴 CNAME target has no public suffix ('.$domain->get().')');
}
else {
Console::log('🟢 CNAME target has a public suffix ('.$domain->get().')');
}
if(App::getEnv('_APP_OPENSSL_KEY_V1') === 'your-secret-key' || empty(App::getEnv('_APP_OPENSSL_KEY_V1'))) {
Console::log('🔴 Using a unique secret key for encryption');
Console::log('🔴 Not using a unique secret key for encryption');
}
else {
Console::log('🟢 Using a unique secret key for encryption');
}
if(App::getEnv('_APP_ENV', 'development') !== 'production') {
Console::log('🔴 App enviornment is set for production');
Console::log('🔴 App environment is set for development');
}
else {
Console::log('🟢 App enviornment is set for production');
Console::log('🟢 App environment is set for production');
}
if('enabled' !== App::getEnv('_APP_OPTIONS_ABUSE', 'disabled')) {
Console::log('🔴 Abuse protection is enabled');
Console::log('🔴 Abuse protection is disabled');
}
else {
Console::log('🟢 Abuse protection is enabled');
@ -74,7 +74,7 @@ $cli
else {
Console::log('🟢 Console access limits are enabled');
}
if('enabled' !== App::getEnv('_APP_OPTIONS_FORCE_HTTPS', 'disabled')) {
Console::log('🔴 HTTPS force option is disabled');
}
@ -133,17 +133,18 @@ $cli
$mail->Subject = 'Test SMTP Connection';
$mail->Body = 'Hello World';
$mail->AltBody = 'Hello World';
$mail->send();
Console::success('SMTP................connected 👍');
} catch (\Throwable $th) {
Console::error('SMTP.............disconnected 👎');
var_dump($th);
}
$host = App::getEnv('_APP_STATSD_HOST', 'telegraf');
$port = App::getEnv('_APP_STATSD_PORT', 8125);
if($fp = @\fsockopen('udp://'.$host, $port, $errCode, $errStr, 2)){
if($fp = @\fsockopen('udp://'.$host, $port, $errCode, $errStr, 2)){
Console::success('StatsD..............connected 👍');
\fclose($fp);
} else {
@ -153,7 +154,7 @@ $cli
$host = App::getEnv('_APP_INFLUXDB_HOST', '');
$port = App::getEnv('_APP_INFLUXDB_PORT', '');
if($fp = @\fsockopen($host, $port, $errCode, $errStr, 2)){
if($fp = @\fsockopen($host, $port, $errCode, $errStr, 2)){
Console::success('InfluxDB............connected 👍');
\fclose($fp);
} else {
@ -179,7 +180,7 @@ $cli
else {
Console::error('🔴 '.$key.' Volume is unreadable');
}
if (\is_writable($device->getRoot())) {
Console::success('🟢 '.$key.' Volume is writeable');
}
@ -203,9 +204,9 @@ $cli
$percentage = (($device->getPartitionTotalSpace() - $device->getPartitionFreeSpace())
/ $device->getPartitionTotalSpace()) * 100;
$message = $key.' Volume has '.Storage::human($device->getPartitionFreeSpace()) . ' free space ('.\round($percentage, 2).'% used)';
if ($percentage < 80) {
Console::success('🟢 ' . $message);
}
@ -213,12 +214,12 @@ $cli
Console::error('🔴 ' . $message);
}
}
try {
if(App::isProduction()) {
Console::log('');
$version = \json_decode(@\file_get_contents(App::getEnv('_APP_HOME', 'http://localhost').'/v1/health/version'), true);
if ($version && isset($version['version'])) {
if(\version_compare($version['version'], App::getEnv('_APP_VERSION', 'UNKNOWN')) === 0) {
Console::info('You are running the latest version of '.APP_NAME.'! 🥳');

View file

@ -67,6 +67,11 @@ services:
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
- _APP_SMTP_HOST
- _APP_SMTP_PORT
- _APP_SMTP_SECURE
- _APP_SMTP_USERNAME
- _APP_SMTP_PASSWORD
- _APP_INFLUXDB_HOST
- _APP_INFLUXDB_PORT
- _APP_STORAGE_LIMIT

View file

@ -34,7 +34,7 @@
"appwrite/php-clamav": "1.0.*",
"utopia-php/framework": "0.9.6",
"utopia-php/framework": "0.9.8",
"utopia-php/abuse": "0.2.*",
"utopia-php/audit": "0.3.*",
"utopia-php/cache": "0.2.*",
@ -47,7 +47,7 @@
"utopia-php/swoole": "0.2.*",
"resque/php-resque": "1.3.6",
"piwik/device-detector": "3.13.0",
"matomo/device-detector": "3.13.0",
"dragonmantank/cron-expression": "3.0.1",
"domnikl/statsd": "3.0.2",
"influxdb/influxdb-php": "1.15.1",

340
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "122d4aeabf81f6dd67b2d65041dd836e",
"content-hash": "18cec0afcb76ef57fa38386fe04fd87b",
"packages": [
{
"name": "appwrite/php-clamav",
@ -178,16 +178,16 @@
},
{
"name": "colinmollenhour/credis",
"version": "v1.12.0",
"version": "v1.12.1",
"source": {
"type": "git",
"url": "https://github.com/colinmollenhour/credis.git",
"reference": "efdf60db997e8f4330b24cfb7e5c5dc0bd612a48"
"reference": "c27faa11724229986335c23f4b6d0f1d8d6547fb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/colinmollenhour/credis/zipball/efdf60db997e8f4330b24cfb7e5c5dc0bd612a48",
"reference": "efdf60db997e8f4330b24cfb7e5c5dc0bd612a48",
"url": "https://api.github.com/repos/colinmollenhour/credis/zipball/c27faa11724229986335c23f4b6d0f1d8d6547fb",
"reference": "c27faa11724229986335c23f4b6d0f1d8d6547fb",
"shasum": ""
},
"require": {
@ -214,7 +214,7 @@
],
"description": "Credis is a lightweight interface to the Redis key-value store which wraps the phpredis library when available for better performance.",
"homepage": "https://github.com/colinmollenhour/credis",
"time": "2020-11-02T17:20:09+00:00"
"time": "2020-11-06T16:09:14+00:00"
},
{
"name": "domnikl/statsd",
@ -601,6 +601,61 @@
],
"time": "2020-09-18T13:24:03+00:00"
},
{
"name": "matomo/device-detector",
"version": "3.13.0",
"source": {
"type": "git",
"url": "https://github.com/matomo-org/device-detector.git",
"reference": "75ca5b690e38c40d199ade93e677bc5d7c3bc498"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/matomo-org/device-detector/zipball/75ca5b690e38c40d199ade93e677bc5d7c3bc498",
"reference": "75ca5b690e38c40d199ade93e677bc5d7c3bc498",
"shasum": ""
},
"require": {
"mustangostang/spyc": "*",
"php": ">=5.5"
},
"require-dev": {
"fabpot/php-cs-fixer": "~1.7",
"matthiasmullie/scrapbook": "@stable",
"phpunit/phpunit": "^4.8.36",
"psr/cache": "^1.0",
"psr/simple-cache": "^1.0"
},
"suggest": {
"doctrine/cache": "Can directly be used for caching purpose",
"ext-yaml": "Necessary for using the Pecl YAML parser"
},
"type": "library",
"autoload": {
"psr-4": {
"DeviceDetector\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-3.0-or-later"
],
"authors": [
{
"name": "The Matomo Team",
"email": "hello@matomo.org",
"homepage": "https://matomo.org/team/"
}
],
"description": "The Universal Device Detection library, that parses User Agents and detects devices (desktop, tablet, mobile, tv, cars, console, etc.), clients (browsers, media players, mobile apps, feed readers, libraries, etc), operating systems, devices, brands and models.",
"homepage": "https://matomo.org",
"keywords": [
"devicedetection",
"parser",
"useragent"
],
"time": "2020-08-17T07:37:33+00:00"
},
{
"name": "mustangostang/spyc",
"version": "dev-master",
@ -719,62 +774,6 @@
],
"time": "2020-07-14T18:50:27+00:00"
},
{
"name": "piwik/device-detector",
"version": "3.13.0",
"source": {
"type": "git",
"url": "https://github.com/matomo-org/device-detector.git",
"reference": "75ca5b690e38c40d199ade93e677bc5d7c3bc498"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/matomo-org/device-detector/zipball/75ca5b690e38c40d199ade93e677bc5d7c3bc498",
"reference": "75ca5b690e38c40d199ade93e677bc5d7c3bc498",
"shasum": ""
},
"require": {
"mustangostang/spyc": "*",
"php": ">=5.5"
},
"require-dev": {
"fabpot/php-cs-fixer": "~1.7",
"matthiasmullie/scrapbook": "@stable",
"phpunit/phpunit": "^4.8.36",
"psr/cache": "^1.0",
"psr/simple-cache": "^1.0"
},
"suggest": {
"doctrine/cache": "Can directly be used for caching purpose",
"ext-yaml": "Necessary for using the Pecl YAML parser"
},
"type": "library",
"autoload": {
"psr-4": {
"DeviceDetector\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-3.0-or-later"
],
"authors": [
{
"name": "The Matomo Team",
"email": "hello@matomo.org",
"homepage": "https://matomo.org/team/"
}
],
"description": "The Universal Device Detection library, that parses User Agents and detects devices (desktop, tablet, mobile, tv, cars, console, etc.), clients (browsers, media players, mobile apps, feed readers, libraries, etc), operating systems, devices, brands and models.",
"homepage": "https://matomo.org",
"keywords": [
"devicedetection",
"parser",
"useragent"
],
"abandoned": "matomo/device-detector",
"time": "2020-08-17T07:37:33+00:00"
},
{
"name": "psr/http-client",
"version": "dev-master",
@ -1333,16 +1332,16 @@
},
{
"name": "utopia-php/framework",
"version": "0.9.6",
"version": "0.9.8",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/framework.git",
"reference": "959767e401c0497f0ddf31446d8d4dfa125aa5dc"
"reference": "4caec144554f028b3ec710a0cdd4f75193f01285"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/framework/zipball/959767e401c0497f0ddf31446d8d4dfa125aa5dc",
"reference": "959767e401c0497f0ddf31446d8d4dfa125aa5dc",
"url": "https://api.github.com/repos/utopia-php/framework/zipball/4caec144554f028b3ec710a0cdd4f75193f01285",
"reference": "4caec144554f028b3ec710a0cdd4f75193f01285",
"shasum": ""
},
"require": {
@ -1374,7 +1373,7 @@
"php",
"upf"
],
"time": "2020-10-26T00:20:11+00:00"
"time": "2020-11-11T20:34:58+00:00"
},
{
"name": "utopia-php/locale",
@ -1736,7 +1735,7 @@
"source": {
"type": "git",
"url": "https://github.com/appwrite/sdk-generator",
"reference": "11789d2169109f182dbc9d7cca91aba925582cf3"
"reference": "e78d94eb1bc538e988d7e45afca7304a98ffc3f1"
},
"require": {
"ext-curl": "*",
@ -1766,7 +1765,7 @@
}
],
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
"time": "2020-10-31T19:31:23+00:00"
"time": "2020-11-11T09:53:31+00:00"
},
{
"name": "composer/package-versions-deprecated",
@ -1774,12 +1773,12 @@
"source": {
"type": "git",
"url": "https://github.com/composer/package-versions-deprecated.git",
"reference": "c8c9aa8a14cc3d3bec86d0a8c3fa52ea79936855"
"reference": "7413f0b55a051e89485c5cb9f765fe24bb02a7b6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/c8c9aa8a14cc3d3bec86d0a8c3fa52ea79936855",
"reference": "c8c9aa8a14cc3d3bec86d0a8c3fa52ea79936855",
"url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/7413f0b55a051e89485c5cb9f765fe24bb02a7b6",
"reference": "7413f0b55a051e89485c5cb9f765fe24bb02a7b6",
"shasum": ""
},
"require": {
@ -1835,7 +1834,7 @@
"type": "tidelift"
}
],
"time": "2020-08-25T05:50:16+00:00"
"time": "2020-11-11T10:22:58+00:00"
},
{
"name": "composer/semver",
@ -2006,36 +2005,31 @@
},
{
"name": "doctrine/instantiator",
"version": "dev-master",
"version": "1.5.x-dev",
"source": {
"type": "git",
"url": "https://github.com/doctrine/instantiator.git",
"reference": "3e7a22aed197e9333cc929e7f6b4300bdae91fcc"
"reference": "6410c4b8352cb64218641457cef64997e6b784fb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/3e7a22aed197e9333cc929e7f6b4300bdae91fcc",
"reference": "3e7a22aed197e9333cc929e7f6b4300bdae91fcc",
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/6410c4b8352cb64218641457cef64997e6b784fb",
"reference": "6410c4b8352cb64218641457cef64997e6b784fb",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^6.0",
"doctrine/coding-standard": "^8.0",
"ext-pdo": "*",
"ext-phar": "*",
"phpbench/phpbench": "^0.13",
"phpstan/phpstan-phpunit": "^0.11",
"phpstan/phpstan-shim": "^0.11",
"phpunit/phpunit": "^7.0"
"phpbench/phpbench": "^0.13 || 1.0.0-alpha2",
"phpstan/phpstan": "^0.12",
"phpstan/phpstan-phpunit": "^0.12",
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
@ -2049,7 +2043,7 @@
{
"name": "Marco Pivetta",
"email": "ocramius@gmail.com",
"homepage": "http://ocramius.github.com/"
"homepage": "https://ocramius.github.io/"
}
],
"description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
@ -2072,7 +2066,7 @@
"type": "tidelift"
}
],
"time": "2020-06-15T18:51:04+00:00"
"time": "2020-11-10T19:05:51+00:00"
},
{
"name": "felixfbecker/advanced-json-rpc",
@ -2795,12 +2789,12 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "6bec8dd32e06d100f90184458c5d8c8772e4ce98"
"reference": "5d66bde3afba51e21c6eb7d1a3776bd3b88dfafc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6bec8dd32e06d100f90184458c5d8c8772e4ce98",
"reference": "6bec8dd32e06d100f90184458c5d8c8772e4ce98",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/5d66bde3afba51e21c6eb7d1a3776bd3b88dfafc",
"reference": "5d66bde3afba51e21c6eb7d1a3776bd3b88dfafc",
"shasum": ""
},
"require": {
@ -2860,7 +2854,7 @@
"type": "github"
}
],
"time": "2020-11-04T07:06:06+00:00"
"time": "2020-11-09T10:25:30+00:00"
},
{
"name": "phpunit/php-file-iterator",
@ -2868,12 +2862,12 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
"reference": "32c4a908cc6fd6dc3a440f273d5ec5a50775de69"
"reference": "854c530d02bcc6b5b96942e6e4cfeead11b35aad"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/32c4a908cc6fd6dc3a440f273d5ec5a50775de69",
"reference": "32c4a908cc6fd6dc3a440f273d5ec5a50775de69",
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/854c530d02bcc6b5b96942e6e4cfeead11b35aad",
"reference": "854c530d02bcc6b5b96942e6e4cfeead11b35aad",
"shasum": ""
},
"require": {
@ -2916,7 +2910,7 @@
"type": "github"
}
],
"time": "2020-11-04T07:07:41+00:00"
"time": "2020-11-09T10:26:59+00:00"
},
{
"name": "phpunit/php-invoker",
@ -2924,12 +2918,12 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-invoker.git",
"reference": "188ae6dbe02d5b9d131d993b09854ecf96fce8a8"
"reference": "0cd572c9935a3a8373416e733ad1566d7c602ff1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/188ae6dbe02d5b9d131d993b09854ecf96fce8a8",
"reference": "188ae6dbe02d5b9d131d993b09854ecf96fce8a8",
"url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/0cd572c9935a3a8373416e733ad1566d7c602ff1",
"reference": "0cd572c9935a3a8373416e733ad1566d7c602ff1",
"shasum": ""
},
"require": {
@ -2975,7 +2969,7 @@
"type": "github"
}
],
"time": "2020-11-04T07:07:50+00:00"
"time": "2020-11-09T10:27:08+00:00"
},
{
"name": "phpunit/php-text-template",
@ -2983,12 +2977,12 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-text-template.git",
"reference": "c0bd1e74a1545f27146946930b41d94d2f682f66"
"reference": "0d0bdf563575ba6715c5a6754541c80a9aa6dde2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/c0bd1e74a1545f27146946930b41d94d2f682f66",
"reference": "c0bd1e74a1545f27146946930b41d94d2f682f66",
"url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0d0bdf563575ba6715c5a6754541c80a9aa6dde2",
"reference": "0d0bdf563575ba6715c5a6754541c80a9aa6dde2",
"shasum": ""
},
"require": {
@ -3030,7 +3024,7 @@
"type": "github"
}
],
"time": "2020-11-04T07:08:26+00:00"
"time": "2020-11-09T10:27:42+00:00"
},
{
"name": "phpunit/php-timer",
@ -3038,12 +3032,12 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-timer.git",
"reference": "2777aa95ed5e04753031e17ce2e3dcdee6026873"
"reference": "16bcf8ca6821c270f22794c02e50b8107cb375d8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/2777aa95ed5e04753031e17ce2e3dcdee6026873",
"reference": "2777aa95ed5e04753031e17ce2e3dcdee6026873",
"url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/16bcf8ca6821c270f22794c02e50b8107cb375d8",
"reference": "16bcf8ca6821c270f22794c02e50b8107cb375d8",
"shasum": ""
},
"require": {
@ -3085,7 +3079,7 @@
"type": "github"
}
],
"time": "2020-11-04T07:07:59+00:00"
"time": "2020-11-09T10:27:16+00:00"
},
{
"name": "phpunit/phpunit",
@ -3241,12 +3235,12 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/cli-parser.git",
"reference": "acc73ecb14ee96d072a410fe9662c44ae2fecffa"
"reference": "0810c53718aa9ea7e42f2de2865a049ce3f5122f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/acc73ecb14ee96d072a410fe9662c44ae2fecffa",
"reference": "acc73ecb14ee96d072a410fe9662c44ae2fecffa",
"url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/0810c53718aa9ea7e42f2de2865a049ce3f5122f",
"reference": "0810c53718aa9ea7e42f2de2865a049ce3f5122f",
"shasum": ""
},
"require": {
@ -3285,7 +3279,7 @@
"type": "github"
}
],
"time": "2020-11-04T07:08:55+00:00"
"time": "2020-11-09T10:28:10+00:00"
},
{
"name": "sebastian/code-unit",
@ -3293,12 +3287,12 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/code-unit.git",
"reference": "5421f8651a026ec69a5c0bb2024f2489f1fcb1d9"
"reference": "2af9894d3d514c2ee6d6ad03cc23bb4625050649"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/5421f8651a026ec69a5c0bb2024f2489f1fcb1d9",
"reference": "5421f8651a026ec69a5c0bb2024f2489f1fcb1d9",
"url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/2af9894d3d514c2ee6d6ad03cc23bb4625050649",
"reference": "2af9894d3d514c2ee6d6ad03cc23bb4625050649",
"shasum": ""
},
"require": {
@ -3337,7 +3331,7 @@
"type": "github"
}
],
"time": "2020-11-04T07:06:19+00:00"
"time": "2020-11-09T10:25:39+00:00"
},
{
"name": "sebastian/code-unit-reverse-lookup",
@ -3345,12 +3339,12 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
"reference": "491730172c42d29eec9bff865a6200c054a4bd19"
"reference": "2f9aa793a37d4f39b5cf5ee3c9a1bd506885d60c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/491730172c42d29eec9bff865a6200c054a4bd19",
"reference": "491730172c42d29eec9bff865a6200c054a4bd19",
"url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/2f9aa793a37d4f39b5cf5ee3c9a1bd506885d60c",
"reference": "2f9aa793a37d4f39b5cf5ee3c9a1bd506885d60c",
"shasum": ""
},
"require": {
@ -3388,7 +3382,7 @@
"type": "github"
}
],
"time": "2020-11-04T07:06:30+00:00"
"time": "2020-11-09T10:25:48+00:00"
},
{
"name": "sebastian/comparator",
@ -3396,12 +3390,12 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
"reference": "1dbf10c8cd661b5246794360572a3014f562f24c"
"reference": "6d3dc38d8631941ca18c76cac3d7a15838071693"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1dbf10c8cd661b5246794360572a3014f562f24c",
"reference": "1dbf10c8cd661b5246794360572a3014f562f24c",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/6d3dc38d8631941ca18c76cac3d7a15838071693",
"reference": "6d3dc38d8631941ca18c76cac3d7a15838071693",
"shasum": ""
},
"require": {
@ -3458,7 +3452,7 @@
"type": "github"
}
],
"time": "2020-11-04T07:06:39+00:00"
"time": "2020-11-09T10:25:57+00:00"
},
{
"name": "sebastian/complexity",
@ -3466,12 +3460,12 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/complexity.git",
"reference": "72f372239d9e83a9e76567172963ae539d0e680b"
"reference": "cf04d6dfa8f99e37a677bf67195c43fc30024282"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/72f372239d9e83a9e76567172963ae539d0e680b",
"reference": "72f372239d9e83a9e76567172963ae539d0e680b",
"url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/cf04d6dfa8f99e37a677bf67195c43fc30024282",
"reference": "cf04d6dfa8f99e37a677bf67195c43fc30024282",
"shasum": ""
},
"require": {
@ -3511,7 +3505,7 @@
"type": "github"
}
],
"time": "2020-11-04T07:08:35+00:00"
"time": "2020-11-09T10:27:51+00:00"
},
{
"name": "sebastian/diff",
@ -3519,12 +3513,12 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/diff.git",
"reference": "f2594561b644d70389fce186f1c862d65299ceaf"
"reference": "2c921642f8495dbf50fdcb920c425f9ccbb6a843"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/f2594561b644d70389fce186f1c862d65299ceaf",
"reference": "f2594561b644d70389fce186f1c862d65299ceaf",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/2c921642f8495dbf50fdcb920c425f9ccbb6a843",
"reference": "2c921642f8495dbf50fdcb920c425f9ccbb6a843",
"shasum": ""
},
"require": {
@ -3573,7 +3567,7 @@
"type": "github"
}
],
"time": "2020-11-04T07:06:48+00:00"
"time": "2020-11-09T10:26:06+00:00"
},
{
"name": "sebastian/environment",
@ -3581,12 +3575,12 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/environment.git",
"reference": "ff8eb08d4de421b3935a9f19adfd1e532221a868"
"reference": "6fe240eca4c1230f6442747269ff94234674f30e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/ff8eb08d4de421b3935a9f19adfd1e532221a868",
"reference": "ff8eb08d4de421b3935a9f19adfd1e532221a868",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6fe240eca4c1230f6442747269ff94234674f30e",
"reference": "6fe240eca4c1230f6442747269ff94234674f30e",
"shasum": ""
},
"require": {
@ -3632,7 +3626,7 @@
"type": "github"
}
],
"time": "2020-11-04T07:06:57+00:00"
"time": "2020-11-09T10:26:15+00:00"
},
{
"name": "sebastian/exporter",
@ -3640,12 +3634,12 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
"reference": "0b7afec9ebe89e21157ad0a0c9e569d25420c698"
"reference": "04229817d2bb369fa6b25229316e7bbc53baece2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/0b7afec9ebe89e21157ad0a0c9e569d25420c698",
"reference": "0b7afec9ebe89e21157ad0a0c9e569d25420c698",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/04229817d2bb369fa6b25229316e7bbc53baece2",
"reference": "04229817d2bb369fa6b25229316e7bbc53baece2",
"shasum": ""
},
"require": {
@ -3705,7 +3699,7 @@
"type": "github"
}
],
"time": "2020-11-04T07:07:06+00:00"
"time": "2020-11-09T10:26:24+00:00"
},
{
"name": "sebastian/global-state",
@ -3713,12 +3707,12 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git",
"reference": "6c76da2f16ba20a01b22cf6b2fafcfb9798fa4a1"
"reference": "bae2a2a7c5dac8eb4ab11e178fcd88242c1f8b17"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/6c76da2f16ba20a01b22cf6b2fafcfb9798fa4a1",
"reference": "6c76da2f16ba20a01b22cf6b2fafcfb9798fa4a1",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bae2a2a7c5dac8eb4ab11e178fcd88242c1f8b17",
"reference": "bae2a2a7c5dac8eb4ab11e178fcd88242c1f8b17",
"shasum": ""
},
"require": {
@ -3765,7 +3759,7 @@
"type": "github"
}
],
"time": "2020-11-04T07:07:15+00:00"
"time": "2020-11-09T10:26:33+00:00"
},
{
"name": "sebastian/lines-of-code",
@ -3773,12 +3767,12 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/lines-of-code.git",
"reference": "b7bcbd22e841edf65622aca6531129cf9c046a93"
"reference": "62f65495957a0d4b39045a059bbf8d6d74db06f5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/b7bcbd22e841edf65622aca6531129cf9c046a93",
"reference": "b7bcbd22e841edf65622aca6531129cf9c046a93",
"url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/62f65495957a0d4b39045a059bbf8d6d74db06f5",
"reference": "62f65495957a0d4b39045a059bbf8d6d74db06f5",
"shasum": ""
},
"require": {
@ -3818,7 +3812,7 @@
"type": "github"
}
],
"time": "2020-11-04T07:08:46+00:00"
"time": "2020-11-09T10:28:00+00:00"
},
{
"name": "sebastian/object-enumerator",
@ -3826,12 +3820,12 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/object-enumerator.git",
"reference": "4eb189f7ec118d4fc77a726a7c96a6322cee53c6"
"reference": "bd926d4c9372e89f8eeff4d3e1d46886b3647959"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/4eb189f7ec118d4fc77a726a7c96a6322cee53c6",
"reference": "4eb189f7ec118d4fc77a726a7c96a6322cee53c6",
"url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/bd926d4c9372e89f8eeff4d3e1d46886b3647959",
"reference": "bd926d4c9372e89f8eeff4d3e1d46886b3647959",
"shasum": ""
},
"require": {
@ -3871,7 +3865,7 @@
"type": "github"
}
],
"time": "2020-11-04T07:07:23+00:00"
"time": "2020-11-09T10:26:42+00:00"
},
{
"name": "sebastian/object-reflector",
@ -3879,12 +3873,12 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/object-reflector.git",
"reference": "482f5ff626f4c3ddd76743ea538eca30b2204bcc"
"reference": "2ae863c8667f2c149b20d13782d11ce23ab995f8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/482f5ff626f4c3ddd76743ea538eca30b2204bcc",
"reference": "482f5ff626f4c3ddd76743ea538eca30b2204bcc",
"url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/2ae863c8667f2c149b20d13782d11ce23ab995f8",
"reference": "2ae863c8667f2c149b20d13782d11ce23ab995f8",
"shasum": ""
},
"require": {
@ -3922,7 +3916,7 @@
"type": "github"
}
],
"time": "2020-11-04T07:07:32+00:00"
"time": "2020-11-09T10:26:50+00:00"
},
{
"name": "sebastian/recursion-context",
@ -3930,12 +3924,12 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/recursion-context.git",
"reference": "a164356d8bfb5bfb1f6e7334809fea30050d1e72"
"reference": "4c073073e68e3d2d5dd7a50ebfc53a912116b498"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/a164356d8bfb5bfb1f6e7334809fea30050d1e72",
"reference": "a164356d8bfb5bfb1f6e7334809fea30050d1e72",
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/4c073073e68e3d2d5dd7a50ebfc53a912116b498",
"reference": "4c073073e68e3d2d5dd7a50ebfc53a912116b498",
"shasum": ""
},
"require": {
@ -3981,7 +3975,7 @@
"type": "github"
}
],
"time": "2020-11-04T07:08:08+00:00"
"time": "2020-11-09T10:27:25+00:00"
},
{
"name": "sebastian/resource-operations",
@ -4040,12 +4034,12 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/type.git",
"reference": "714b5529326dd8101ba50ea70bd8f5f812bffe05"
"reference": "dcac0d6b8489ed9975d01303f0903958ebad0ce4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/type/zipball/714b5529326dd8101ba50ea70bd8f5f812bffe05",
"reference": "714b5529326dd8101ba50ea70bd8f5f812bffe05",
"url": "https://api.github.com/repos/sebastianbergmann/type/zipball/dcac0d6b8489ed9975d01303f0903958ebad0ce4",
"reference": "dcac0d6b8489ed9975d01303f0903958ebad0ce4",
"shasum": ""
},
"require": {
@ -4084,7 +4078,7 @@
"type": "github"
}
],
"time": "2020-11-04T07:08:17+00:00"
"time": "2020-11-09T10:27:33+00:00"
},
{
"name": "sebastian/version",
@ -4175,12 +4169,12 @@
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "5164210f240d580ce0f490a7f24827c6fbc7bc36"
"reference": "d1d8b8fd9b605630aa73b1b384e246fee54e8ffa"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/5164210f240d580ce0f490a7f24827c6fbc7bc36",
"reference": "5164210f240d580ce0f490a7f24827c6fbc7bc36",
"url": "https://api.github.com/repos/symfony/console/zipball/d1d8b8fd9b605630aa73b1b384e246fee54e8ffa",
"reference": "d1d8b8fd9b605630aa73b1b384e246fee54e8ffa",
"shasum": ""
},
"require": {
@ -4261,7 +4255,7 @@
"type": "tidelift"
}
],
"time": "2020-11-01T17:40:07+00:00"
"time": "2020-11-05T20:05:54+00:00"
},
{
"name": "symfony/polyfill-ctype",
@ -4940,12 +4934,12 @@
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "7685eb905a49056b9507fce0d70d3d7e02b78b20"
"reference": "e133d1fd8c9f22dd9bc43d1b7fc46e0f35692226"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/7685eb905a49056b9507fce0d70d3d7e02b78b20",
"reference": "7685eb905a49056b9507fce0d70d3d7e02b78b20",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/e133d1fd8c9f22dd9bc43d1b7fc46e0f35692226",
"reference": "e133d1fd8c9f22dd9bc43d1b7fc46e0f35692226",
"shasum": ""
},
"require": {
@ -5007,7 +5001,7 @@
"type": "tidelift"
}
],
"time": "2020-11-05T13:12:46+00:00"
"time": "2020-11-09T13:33:24+00:00"
},
{
"name": "vimeo/psalm",

View file

@ -82,6 +82,11 @@ services:
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
- _APP_SMTP_HOST
- _APP_SMTP_PORT
- _APP_SMTP_SECURE
- _APP_SMTP_USERNAME
- _APP_SMTP_PASSWORD
- _APP_INFLUXDB_HOST
- _APP_INFLUXDB_PORT
- _APP_STORAGE_LIMIT

View file

@ -23,7 +23,6 @@ class Auth
const USER_ROLE_OWNER = 4;
const USER_ROLE_APP = 5;
const USER_ROLE_SYSTEM = 6;
const USER_ROLE_ALL = '*';
/**
* Token Types.
@ -49,9 +48,9 @@ class Auth
/**
* User Unique ID.
*
* @var int
* @var string
*/
public static $unique = 0;
public static $unique = '';
/**
* User Secret Key.
@ -75,7 +74,7 @@ class Auth
/**
* Encode Session.
*
* @param int $id
* @param string $id
* @param string $secret
*
* @return string
@ -206,4 +205,40 @@ class Auth
return false;
}
/**
* Is Previligged User?
*
* @param array $roles
*
* @return bool
*/
public static function isPreviliggedUser(array $roles): bool
{
if(
array_key_exists('role:'.self::USER_ROLE_OWNER, $roles) ||
array_key_exists('role:'.self::USER_ROLE_DEVELOPER, $roles) ||
array_key_exists('role:'.self::USER_ROLE_ADMIN, $roles)
) {
return true;
}
return false;
}
/**
* Is App User?
*
* @param array $roles
*
* @return bool
*/
public static function isAppUser(array $roles): bool
{
if(array_key_exists('role:'.self::USER_ROLE_APP, $roles)) {
return true;
}
return false;
}
}

View file

@ -455,13 +455,28 @@ class Database
foreach ($rules as $key => $rule) {
$key = $rule->getAttribute('key', null);
$filters = $rule->getAttribute('filter', null);
$type = $rule->getAttribute('type', null);
$array = $rule->getAttribute('array', false);
$filters = $rule->getAttribute('filter', []);
$value = $document->getAttribute($key, null);
if (($value !== null) && is_array($filters)) {
foreach ($filters as $filter) {
$value = $this->encodeAttribute($filter, $value);
$document->setAttribute($key, $value);
if (($value !== null)) {
if ($type === self::SYSTEM_VAR_TYPE_DOCUMENT) {
if($array) {
$list = [];
foreach ($value as $child) {
$list[] = $this->encode($child);
}
$document->setAttribute($key, $list);
} else {
$document->setAttribute($key, $this->encode($value));
}
} else {
foreach ($filters as $filter) {
$value = $this->encodeAttribute($filter, $value);
$document->setAttribute($key, $value);
}
}
}
}
@ -476,13 +491,28 @@ class Database
foreach ($rules as $key => $rule) {
$key = $rule->getAttribute('key', null);
$filters = $rule->getAttribute('filter', null);
$type = $rule->getAttribute('type', null);
$array = $rule->getAttribute('array', false);
$filters = $rule->getAttribute('filter', []);
$value = $document->getAttribute($key, null);
if (($value !== null) && is_array($filters)) {
foreach (array_reverse($filters) as $filter) {
$value = $this->decodeAttribute($filter, $value);
$document->setAttribute($key, $value);
if (($value !== null)) {
if ($type === self::SYSTEM_VAR_TYPE_DOCUMENT) {
if($array) {
$list = [];
foreach ($value as $child) {
$list[] = $this->decode($child);
}
$document->setAttribute($key, $list);
} else {
$document->setAttribute($key, $this->decode($value));
}
} else {
foreach (array_reverse($filters) as $filter) {
$value = $this->decodeAttribute($filter, $value);
$document->setAttribute($key, $value);
}
}
}
}
@ -499,6 +529,7 @@ class Database
static protected function encodeAttribute(string $name, $value)
{
if (!isset(self::$filters[$name])) {
return $value;
throw new Exception('Filter not found');
}
@ -520,6 +551,7 @@ class Database
static protected function decodeAttribute(string $name, $value)
{
if (!isset(self::$filters[$name])) {
return $value;
throw new Exception('Filter not found');
}

View file

@ -10,7 +10,7 @@ class Authorization extends Validator
/**
* @var array
*/
static $roles = ['*'];
static $roles = ['*' => true];
/**
* @var Document
@ -77,7 +77,7 @@ class Authorization extends Validator
foreach ($permissions[$this->action] as $permission) {
$permission = \str_replace(':{self}', ':'.$this->document->getId(), $permission);
if (\in_array($permission, self::getRoles())) {
if (\array_key_exists($permission, self::$roles)) {
return true;
}
}
@ -92,17 +92,35 @@ class Authorization extends Validator
*
* @return void
*/
public static function setRole($role): void
public static function setRole(string $role): void
{
self::$roles[] = $role;
self::$roles[$role] = true;
}
/**
* @return array
*/
public static function getRoles()
public static function getRoles(): array
{
return self::$roles;
return \array_keys(self::$roles);
}
/**
* @return void
*/
public static function cleanRoles(): void
{
self::$roles = [];
}
/**
* @param string $role
*
* @return bool
*/
public static function isRole(string $role): bool
{
return (\array_key_exists($role, self::$roles));
}
/**

View file

@ -0,0 +1,124 @@
<?php
namespace Appwrite\Specification;
use Utopia\App;
use Utopia\Route;
use Appwrite\Utopia\Response\Model;
abstract class Format
{
/**
* @var App
*/
protected $app;
/**
* @var Route[]
*/
protected $routes;
/**
* @var Model[]
*/
protected $models;
/**
* @var array
*/
protected $keys;
/**
* @var array
*/
protected $security;
/**
* @var array
*/
protected $params = [
'name' => '',
'description' => '',
'endpoint' => 'https://localhost',
'version' => '1.0.0',
'terms' => '',
'support.email' => '',
'support.url' => '',
'contact.name' => '',
'contact.email' => '',
'contact.url' => '',
'license.name' => '',
'license.url' => '',
];
/**
* @param App $app
* @param Route[] $routes
* @param Model[] $models
* @param array $keys
* @param array $security
*/
public function __construct(App $app, array $routes, array $models, array $keys, array $security)
{
$this->app = $app;
$this->routes = $routes;
$this->models = $models;
$this->keys = $keys;
$this->security = $security;
}
/**
* Get Name.
*
* Get format name
*
* @return string
*/
abstract public function getName(): string;
/**
* Parse
*
* Parses Appwrite App to given format
*
* @return array
*/
abstract public function parse(): array;
/**
* Set Param.
*
* Set param value
*
* @param string $key
* @param string $value
*
* @return self
*/
public function setParam(string $key, string $value): self
{
$this->params[$key] = $value;
return $this;
}
/**
* Get Param.
*
* Get param value
*
* @param string $key
* @param string $default
*
* @return string
*/
public function getParam(string $key, string $default = ''): string
{
if(!isset($this->params[$key])) {
return $default;
}
return $this->params[$key];
}
}

View file

@ -0,0 +1,403 @@
<?php
namespace Appwrite\Specification\Format;
use Appwrite\Specification\Format;
use Appwrite\Template\Template;
class OpenAPI3 extends Format
{
/**
* Get Name.
*
* Get format name
*
* @return string
*/
public function getName():string
{
return 'Open API 3';
}
/**
* Parse
*
* Parses Appwrite App to given format
*
* @return array
*/
public function parse(): array
{
/*
* Specifications (v3.0.0):
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md
*/
$output = [
'openapi' => '3.0.0',
'info' => [
'version' => $this->getParam('version'),
'title' => $this->getParam('name'),
'description' => $this->getParam('description'),
'termsOfService' => $this->getParam('terms'),
'contact' => [
'name' => $this->getParam('contact.name'),
'url' => $this->getParam('contact.url'),
'email' => $this->getParam('contact.email'),
],
'license' => [
'name' => 'BSD-3-Clause',
'url' => 'https://raw.githubusercontent.com/appwrite/appwrite/master/LICENSE',
],
],
'servers' => [
[
'url' => $this->getParam('endpoint', ''),
],
],
'paths' => [],
'components' => [
'schemas' => [],
'securitySchemes' => $this->keys,
],
'externalDocs' => [
'description' => $this->getParam('docs.description'),
'url' => $this->getParam('docs.url'),
],
];
if (isset($output['components']['securitySchemes']['Project'])) {
$output['components']['securitySchemes']['Project']['x-appwrite'] = ['demo' => '5df5acd0d48c2'];
}
if (isset($output['components']['securitySchemes']['Key'])) {
$output['components']['securitySchemes']['Key']['x-appwrite'] = ['demo' => '919c2d18fb5d4...a2ae413da83346ad2'];
}
if (isset($output['components']['securitySchemes']['Locale'])) {
$output['components']['securitySchemes']['Locale']['x-appwrite'] = ['demo' => 'en'];
}
if (isset($output['components']['securitySchemes']['Mode'])) {
$output['components']['securitySchemes']['Mode']['x-appwrite'] = ['demo' => ''];
}
foreach ($this->routes as $route) { /* @var $route \Utopia\Route */
$url = \str_replace('/v1', '', $route->getURL());
$scope = $route->getLabel('scope', '');
$hide = $route->getLabel('sdk.hide', false);
$consumes = [$route->getLabel('sdk.request.type', 'application/json')];
if ($hide) {
continue;
}
$id = $route->getLabel('sdk.method', \uniqid());
$desc = (!empty($route->getLabel('sdk.description', ''))) ? \realpath(__DIR__.'/../../../../'.$route->getLabel('sdk.description', '')) : null;
$produces = $route->getLabel('sdk.response.type', 'application/json');
$model = $route->getLabel('sdk.response.model', 'none');
$temp = [
'summary' => $route->getDesc(),
'operationId' => $route->getLabel('sdk.namespace', 'default').ucfirst($id),
// 'consumes' => [],
// 'produces' => [$produces],
'tags' => [$route->getLabel('sdk.namespace', 'default')],
'description' => ($desc) ? \file_get_contents($desc) : '',
'responses' => [],
'x-appwrite' => [ // Appwrite related metadata
'method' => $route->getLabel('sdk.method', \uniqid()),
'weight' => $route->getOrder(),
'cookies' => $route->getLabel('sdk.cookies', false),
'type' => $route->getLabel('sdk.methodType', ''),
'demo' => 'docs/examples/'. Template::fromCamelCaseToDash($route->getLabel('sdk.namespace', 'default')).'/'.Template::fromCamelCaseToDash($id).'.md',
'edit' => 'https://github.com/appwrite/appwrite/edit/master' . $route->getLabel('sdk.description', ''),
'rate-limit' => $route->getLabel('abuse-limit', 0),
'rate-time' => $route->getLabel('abuse-time', 3600),
'rate-key' => $route->getLabel('abuse-key', 'url:{url},ip:{ip}'),
'scope' => $route->getLabel('scope', ''),
'platforms' => $route->getLabel('sdk.platform', []),
],
];
foreach ($this->models as $key => $value) {
if($value->getType() === $model) {
$model = $value;
break;
}
}
if($model->isNone()) {
$temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [
'description' => (in_array($produces, [
'image/*',
'image/jpeg',
'image/gif',
'image/png',
'image/webp',
'image/svg-x',
'image/x-icon',
'image/bmp',
])) ? 'Image' : 'File',
// 'schema' => [
// 'type' => 'file'
// ],
];
} else {
$temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [
'description' => $model->getName(),
'content' => [
$produces => [
'schema' => [
'$ref' => '#/components/schemas/'.$model->getType(),
],
],
],
];
}
if($route->getLabel('sdk.response.code', 500) === 204) {
$temp['responses'][(string)$route->getLabel('sdk.response.code', '500')]['description'] = 'No content';
unset($temp['responses'][(string)$route->getLabel('sdk.response.code', '500')]['schema']);
}
if ((!empty($scope))) { // && 'public' != $scope
$temp['security'][] = $route->getLabel('sdk.security', $this->security);
}
$body = [
'content' => [
$consumes[0] => [
'schema' => [
'type' => 'object',
'properties' => [],
],
],
],
];
$bodyRequired = [];
foreach ($route->getParams() as $name => $param) { // Set params
$validator = (\is_callable($param['validator'])) ? call_user_func_array($param['validator'], $this->app->getResources($param['resources'])) : $param['validator']; /* @var $validator \Utopia\Validator */
$node = [
'name' => $name,
'description' => $param['description'],
'required' => !$param['optional'],
];
switch ((!empty($validator)) ? \get_class($validator) : '') {
case 'Utopia\Validator\Text':
$node['schema']['type'] = 'string';
$node['schema']['x-example'] = '['.\strtoupper(Template::fromCamelCaseToSnake($node['name'])).']';
break;
case 'Utopia\Validator\Boolean':
$node['schema']['type'] = 'boolean';
$node['schema']['x-example'] = false;
break;
case 'Appwrite\Database\Validator\UID':
$node['schema']['type'] = 'string';
$node['schema']['x-example'] = '['.\strtoupper(Template::fromCamelCaseToSnake($node['name'])).']';
break;
case 'Utopia\Validator\Email':
$node['schema']['type'] = 'string';
$node['schema']['format'] = 'email';
$node['schema']['x-example'] = 'email@example.com';
break;
case 'Utopia\Validator\URL':
$node['schema']['type'] = 'string';
$node['schema']['format'] = 'url';
$node['schema']['x-example'] = 'https://example.com';
break;
case 'Utopia\Validator\JSON':
case 'Utopia\Validator\Mock':
case 'Utopia\Validator\Assoc':
$node['schema']['type'] = 'object';
$node['schema']['type'] = 'object';
$node['schema']['x-example'] = '{}';
//$node['schema']['format'] = 'json';
break;
case 'Appwrite\Storage\Validator\File':
$consumes = ['multipart/form-data'];
$node['schema']['type'] = 'string';
$node['schema']['format'] = 'binary';
break;
case 'Utopia\Validator\ArrayList':
$node['schema']['type'] = 'array';
$node['schema']['items'] = [
'type' => 'string',
];
break;
case 'Appwrite\Auth\Validator\Password':
$node['schema']['type'] = 'string';
$node['schema']['format'] = 'format';
$node['schema']['x-example'] = 'password';
break;
case 'Utopia\Validator\Range': /* @var $validator \Utopia\Validator\Range */
$node['schema']['type'] = 'integer';
$node['schema']['format'] = 'int32';
$node['schema']['x-example'] = $validator->getMin();
break;
case 'Utopia\Validator\Numeric':
$node['schema']['type'] = 'integer';
$node['schema']['format'] = 'int32';
break;
case 'Utopia\Validator\Length':
$node['schema']['type'] = 'string';
break;
case 'Utopia\Validator\Host':
$node['schema']['type'] = 'string';
$node['schema']['format'] = 'url';
$node['schema']['x-example'] = 'https://example.com';
break;
case 'Utopia\Validator\WhiteList': /* @var $validator \Utopia\Validator\WhiteList */
$node['schema']['type'] = 'string';
$node['schema']['x-example'] = $validator->getList()[0];
break;
default:
$node['schema']['type'] = 'string';
break;
}
if ($param['optional'] && !\is_null($param['default'])) { // Param has default value
$node['schema']['default'] = $param['default'];
}
if (false !== \strpos($url, ':'.$name)) { // Param is in URL path
$node['in'] = 'path';
$temp['parameters'][] = $node;
} elseif ($route->getMethod() == 'GET') { // Param is in query
$node['in'] = 'query';
$temp['parameters'][] = $node;
} else { // Param is in payload
if(!$param['optional']) {
$bodyRequired[] = $name;
}
$body['content'][$consumes[0]]['schema']['properties'][$name] = [
'type' => $node['schema']['type'],
'description' => $node['description'],
'x-example' => $node['x-example'] ?? null,
];
if(isset($node['default'])) {
$body['content'][$consumes[0]]['schema']['properties'][$name]['default'] = $node['default'];
}
if(\array_key_exists('items', $node['schema'])) {
$body['content'][$consumes[0]]['schema']['properties'][$name]['items'] = $node['schema']['items'];
}
}
$url = \str_replace(':'.$name, '{'.$name.'}', $url);
}
if(!empty($bodyRequired)) {
$body['content'][$consumes[0]]['schema']['required'] = $bodyRequired;
}
if(!empty($body['content'][$consumes[0]]['schema']['properties'])) {
$temp['requestBody'] = $body;
}
//$temp['consumes'] = $consumes;
$output['paths'][$url][\strtolower($route->getMethod())] = $temp;
}
foreach ($this->models as $model) {
$required = $model->getRequired();
$rules = $model->getRules();
$output['components']['schemas'][$model->getType()] = [
'description' => $model->getName(),
'type' => 'object',
];
if(!empty($rules)) {
$output['components']['schemas'][$model->getType()]['properties'] = [];
}
if($model->isAny()) {
$output['components']['schemas'][$model->getType()]['additionalProperties'] = true;
}
if(!empty($required)) {
$output['components']['schemas'][$model->getType()]['required'] = $required;
}
foreach($model->getRules() as $name => $rule) {
$type = '';
$format = null;
$items = null;
switch ($rule['type']) {
case 'string':
case 'json':
$type = 'string';
break;
case 'integer':
$type = 'integer';
$format = 'int32';
break;
case 'float':
$type = 'number';
$format = 'float';
break;
case 'boolean':
$type = 'boolean';
break;
default:
$type = 'object';
$rule['type'] = ($rule['type']) ? $rule['type'] : 'none';
$items = [
'$ref' => '#/components/schemas/'.$rule['type'],
];
break;
}
if($rule['array']) {
$output['components']['schemas'][$model->getType()]['properties'][$name] = [
'type' => 'array',
'description' => $rule['description'] ?? '',
'items' => [
'type' => $type,
]
];
if($format) {
$output['components']['schemas'][$model->getType()]['properties'][$name]['items']['format'] = $format;
}
if($items) {
$output['components']['schemas'][$model->getType()]['properties'][$name]['items'] = $items;
}
} else {
$output['components']['schemas'][$model->getType()]['properties'][$name] = [
'type' => $type,
'description' => $rule['description'] ?? '',
//'default' => $rule['default'] ?? null,
'x-example' => $rule['example'] ?? null,
];
if($format) {
$output['components']['schemas'][$model->getType()]['properties'][$name]['format'] = $format;
}
if($items) {
$output['components']['schemas'][$model->getType()]['properties'][$name]['items'] = $items;
}
}
}
}
\ksort($output['paths']);
return $output;
}
}

View file

@ -0,0 +1,401 @@
<?php
namespace Appwrite\Specification\Format;
use Appwrite\Specification\Format;
use Appwrite\Template\Template;
class Swagger2 extends Format
{
/**
* Get Name.
*
* Get format name
*
* @return string
*/
public function getName():string
{
return 'Swagger 2';
}
/**
* Parse
*
* Parses Appwrite App to given format
*
* @return array
*/
public function parse(): array
{
/*
* Specifications (v3.0.0):
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md
*/
$output = [
'swagger' => '2.0',
'info' => [
'version' => $this->getParam('version'),
'title' => $this->getParam('name'),
'description' => $this->getParam('description'),
'termsOfService' => $this->getParam('terms'),
'contact' => [
'name' => $this->getParam('contact.name'),
'url' => $this->getParam('contact.url'),
'email' => $this->getParam('contact.email'),
],
'license' => [
'name' => 'BSD-3-Clause',
'url' => 'https://raw.githubusercontent.com/appwrite/appwrite/master/LICENSE',
],
],
'host' => \parse_url($this->getParam('endpoint', ''), PHP_URL_HOST),
'basePath' => \parse_url($this->getParam('endpoint', ''), PHP_URL_PATH),
'schemes' => [\parse_url($this->getParam('endpoint', ''), PHP_URL_SCHEME)],
'consumes' => ['application/json', 'multipart/form-data'],
'produces' => ['application/json'],
'securityDefinitions' => $this->keys,
'paths' => [],
'definitions' => [],
'externalDocs' => [
'description' => $this->getParam('docs.description'),
'url' => $this->getParam('docs.url'),
],
];
if (isset($output['securityDefinitions']['Project'])) {
$output['securityDefinitions']['Project']['x-appwrite'] = ['demo' => '5df5acd0d48c2'];
}
if (isset($output['securityDefinitions']['Key'])) {
$output['securityDefinitions']['Key']['x-appwrite'] = ['demo' => '919c2d18fb5d4...a2ae413da83346ad2'];
}
if (isset($output['securityDefinitions']['Locale'])) {
$output['securityDefinitions']['Locale']['x-appwrite'] = ['demo' => 'en'];
}
if (isset($output['securityDefinitions']['Mode'])) {
$output['securityDefinitions']['Mode']['x-appwrite'] = ['demo' => ''];
}
foreach ($this->routes as $route) { /* @var $route \Utopia\Route */
$url = \str_replace('/v1', '', $route->getURL());
$scope = $route->getLabel('scope', '');
$hide = $route->getLabel('sdk.hide', false);
$consumes = [$route->getLabel('sdk.request.type', 'application/json')];
if ($hide) {
continue;
}
$id = $route->getLabel('sdk.method', \uniqid());
$desc = (!empty($route->getLabel('sdk.description', ''))) ? \realpath(__DIR__.'/../../../../'.$route->getLabel('sdk.description', '')) : null;
$produces = $route->getLabel('sdk.response.type', 'application/json');
$model = $route->getLabel('sdk.response.model', 'none');
$temp = [
'summary' => $route->getDesc(),
'operationId' => $route->getLabel('sdk.namespace', 'default').ucfirst($id),
'consumes' => [],
'produces' => [$produces],
'tags' => [$route->getLabel('sdk.namespace', 'default')],
'description' => ($desc) ? \file_get_contents($desc) : '',
'responses' => [],
'x-appwrite' => [ // Appwrite related metadata
'method' => $route->getLabel('sdk.method', \uniqid()),
'weight' => $route->getOrder(),
'cookies' => $route->getLabel('sdk.cookies', false),
'type' => $route->getLabel('sdk.methodType', ''),
'demo' => 'docs/examples/'. Template::fromCamelCaseToDash($route->getLabel('sdk.namespace', 'default')).'/'.Template::fromCamelCaseToDash($id).'.md',
'edit' => 'https://github.com/appwrite/appwrite/edit/master' . $route->getLabel('sdk.description', ''),
'rate-limit' => $route->getLabel('abuse-limit', 0),
'rate-time' => $route->getLabel('abuse-time', 3600),
'rate-key' => $route->getLabel('abuse-key', 'url:{url},ip:{ip}'),
'scope' => $route->getLabel('scope', ''),
'platforms' => $route->getLabel('sdk.platform', []),
],
];
foreach ($this->models as $key => $value) {
if($value->getType() === $model) {
$model = $value;
break;
}
}
if($model->isNone()) {
$temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [
'description' => (in_array($produces, [
'image/*',
'image/jpeg',
'image/gif',
'image/png',
'image/webp',
'image/svg-x',
'image/x-icon',
'image/bmp',
])) ? 'Image' : 'File',
'schema' => [
'type' => 'file'
],
];
} else {
$temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [
'description' => $model->getName(),
'schema' => [
'$ref' => '#/definitions/'.$model->getType(),
],
];
}
if($route->getLabel('sdk.response.code', 500) === 204) {
$temp['responses'][(string)$route->getLabel('sdk.response.code', '500')]['description'] = 'No content';
unset($temp['responses'][(string)$route->getLabel('sdk.response.code', '500')]['schema']);
}
if ((!empty($scope))) { // && 'public' != $scope
$temp['security'][] = $route->getLabel('sdk.security', $this->security);
}
$body = [
'name' => 'payload',
'in' => 'body',
'schema' => [
'type' => 'object',
'properties' => [],
],
];
$bodyRequired = [];
foreach ($route->getParams() as $name => $param) { // Set params
$validator = (\is_callable($param['validator'])) ? call_user_func_array($param['validator'], $this->app->getResources($param['resources'])) : $param['validator']; /* @var $validator \Utopia\Validator */
$node = [
'name' => $name,
'description' => $param['description'],
'required' => !$param['optional'],
];
switch ((!empty($validator)) ? \get_class($validator) : '') {
case 'Utopia\Validator\Text':
$node['type'] = 'string';
$node['x-example'] = '['.\strtoupper(Template::fromCamelCaseToSnake($node['name'])).']';
break;
case 'Utopia\Validator\Boolean':
$node['type'] = 'boolean';
$node['x-example'] = false;
break;
case 'Appwrite\Database\Validator\UID':
$node['type'] = 'string';
$node['x-example'] = '['.\strtoupper(Template::fromCamelCaseToSnake($node['name'])).']';
break;
case 'Utopia\Validator\Email':
$node['type'] = 'string';
$node['format'] = 'email';
$node['x-example'] = 'email@example.com';
break;
case 'Utopia\Validator\URL':
$node['type'] = 'string';
$node['format'] = 'url';
$node['x-example'] = 'https://example.com';
break;
case 'Utopia\Validator\JSON':
case 'Utopia\Validator\Mock':
case 'Utopia\Validator\Assoc':
$node['type'] = 'object';
$node['type'] = 'object';
$node['x-example'] = '{}';
//$node['format'] = 'json';
break;
case 'Appwrite\Storage\Validator\File':
$consumes = ['multipart/form-data'];
$node['type'] = 'file';
break;
case 'Utopia\Validator\ArrayList':
$node['type'] = 'array';
$node['collectionFormat'] = 'multi';
$node['items'] = [
'type' => 'string',
];
break;
case 'Appwrite\Auth\Validator\Password':
$node['type'] = 'string';
$node['format'] = 'format';
$node['x-example'] = 'password';
break;
case 'Utopia\Validator\Range': /* @var $validator \Utopia\Validator\Range */
$node['type'] = 'integer';
$node['format'] = 'int32';
$node['x-example'] = $validator->getMin();
break;
case 'Utopia\Validator\Numeric':
$node['type'] = 'integer';
$node['format'] = 'int32';
break;
case 'Utopia\Validator\Length':
$node['type'] = 'string';
break;
case 'Utopia\Validator\Host':
$node['type'] = 'string';
$node['format'] = 'url';
$node['x-example'] = 'https://example.com';
break;
case 'Utopia\Validator\WhiteList': /* @var $validator \Utopia\Validator\WhiteList */
$node['type'] = 'string';
$node['x-example'] = $validator->getList()[0];
break;
default:
$node['type'] = 'string';
break;
}
if ($param['optional'] && !\is_null($param['default'])) { // Param has default value
$node['default'] = $param['default'];
}
if (false !== \strpos($url, ':'.$name)) { // Param is in URL path
$node['in'] = 'path';
$temp['parameters'][] = $node;
} elseif ($route->getMethod() == 'GET') { // Param is in query
$node['in'] = 'query';
$temp['parameters'][] = $node;
} else { // Param is in payload
if(\in_array('multipart/form-data', $consumes)) {
$node['in'] = 'formData';
$temp['parameters'][] = $node;
continue;
}
if(!$param['optional']) {
$bodyRequired[] = $name;
}
$body['schema']['properties'][$name] = [
'type' => $node['type'],
'description' => $node['description'],
'default' => $node['default'] ?? null,
'x-example' => $node['x-example'] ?? null,
];
if(\array_key_exists('items', $node)) {
$body['schema']['properties'][$name]['items'] = $node['items'];
}
}
$url = \str_replace(':'.$name, '{'.$name.'}', $url);
}
if(!empty($bodyRequired)) {
$body['schema']['required'] = $bodyRequired;
}
if(!empty($body['schema']['properties'])) {
$temp['parameters'][] = $body;
}
$temp['consumes'] = $consumes;
$output['paths'][$url][\strtolower($route->getMethod())] = $temp;
}
foreach ($this->models as $model) {
$required = $model->getRequired();
$rules = $model->getRules();
$output['definitions'][$model->getType()] = [
'description' => $model->getName(),
'type' => 'object',
];
if(!empty($rules)) {
$output['definitions'][$model->getType()]['properties'] = [];
}
if($model->isAny()) {
$output['definitions'][$model->getType()]['additionalProperties'] = true;
}
if(!empty($required)) {
$output['definitions'][$model->getType()]['required'] = $required;
}
foreach($model->getRules() as $name => $rule) {
$type = '';
$format = null;
$items = null;
switch ($rule['type']) {
case 'string':
case 'json':
$type = 'string';
break;
case 'integer':
$type = 'integer';
$format = 'int32';
break;
case 'float':
$type = 'number';
$format = 'float';
break;
case 'boolean':
$type = 'boolean';
break;
default:
$type = 'object';
$rule['type'] = ($rule['type']) ? $rule['type'] : 'none';
$items = [
'type' => $type,
'$ref' => '#/definitions/'.$rule['type'],
];
break;
}
if($rule['array']) {
$output['definitions'][$model->getType()]['properties'][$name] = [
'type' => 'array',
'description' => $rule['description'] ?? '',
'items' => [
'type' => $type,
]
];
if($format) {
$output['definitions'][$model->getType()]['properties'][$name]['items']['format'] = $format;
}
if($items) {
$output['definitions'][$model->getType()]['properties'][$name]['items'] = $items;
}
} else {
$output['definitions'][$model->getType()]['properties'][$name] = [
'type' => $type,
'description' => $rule['description'] ?? '',
//'default' => $rule['default'] ?? null,
'x-example' => $rule['example'] ?? null,
];
if($format) {
$output['definitions'][$model->getType()]['properties'][$name]['format'] = $format;
}
if($items) {
$output['definitions'][$model->getType()]['properties'][$name]['items'] = $items;
}
}
}
}
\ksort($output['paths']);
return $output;
}
}

View file

@ -0,0 +1,43 @@
<?php
namespace Appwrite\Specification;
class Specification
{
/**
* @var Format
*/
protected $format;
/**
* @param Format $format
*/
public function __construct(Format $format)
{
$this->format = $format;
}
/**
* Get Name.
*
* Get format name
*
* @return string
*/
public function getName():string
{
return $this->format->getName();
}
/**
* Parse
*
* Parses Appwrite App to given format
*
* @return array
*/
public function parse(): array
{
return $this->format->parse();
}
}

View file

@ -7,6 +7,7 @@ use Utopia\Swoole\Response as SwooleResponse;
use Swoole\Http\Response as SwooleHTTPResponse;
use Appwrite\Database\Document;
use Appwrite\Utopia\Response\Model;
use Appwrite\Utopia\Response\Model\None;
use Appwrite\Utopia\Response\Model\Any;
use Appwrite\Utopia\Response\Model\BaseList;
use Appwrite\Utopia\Response\Model\Collection;
@ -27,12 +28,14 @@ use Appwrite\Utopia\Response\Model\Team;
use Appwrite\Utopia\Response\Model\Locale;
use Appwrite\Utopia\Response\Model\Log;
use Appwrite\Utopia\Response\Model\Membership;
use Appwrite\Utopia\Response\Model\Permissions;
use Appwrite\Utopia\Response\Model\Phone;
use Appwrite\Utopia\Response\Model\Platform;
use Appwrite\Utopia\Response\Model\Project;
use Appwrite\Utopia\Response\Model\Rule;
use Appwrite\Utopia\Response\Model\Tag;
use Appwrite\Utopia\Response\Model\Task;
use Appwrite\Utopia\Response\Model\Token;
use Appwrite\Utopia\Response\Model\Webhook;
/**
@ -41,6 +44,7 @@ use Appwrite\Utopia\Response\Model\Webhook;
class Response extends SwooleResponse
{
// General
const MODEL_NONE = 'none';
const MODEL_ANY = 'any';
const MODEL_LOG = 'log';
const MODEL_LOG_LIST = 'logList';
@ -122,6 +126,8 @@ class Response extends SwooleResponse
{
$this
// General
->setModel(new None())
->setModel(new Any())
->setModel(new Error())
->setModel(new ErrorDev())
// Lists
@ -136,24 +142,25 @@ class Response extends SwooleResponse
->setModel(new BaseList('Functions List', self::MODEL_FUNCTION_LIST, 'functions', self::MODEL_FUNCTION))
->setModel(new BaseList('Tags List', self::MODEL_TAG_LIST, 'tags', self::MODEL_TAG))
->setModel(new BaseList('Executions List', self::MODEL_EXECUTION_LIST, 'executions', self::MODEL_EXECUTION))
->setModel(new BaseList('Projects List', self::MODEL_PROJECT_LIST, 'projects', self::MODEL_PROJECT))
->setModel(new BaseList('Webhooks List', self::MODEL_WEBHOOK_LIST, 'webhooks', self::MODEL_WEBHOOK))
->setModel(new BaseList('API Keys List', self::MODEL_KEY_LIST, 'keys', self::MODEL_KEY))
->setModel(new BaseList('Tasks List', self::MODEL_TASK_LIST, 'tasks', self::MODEL_TASK))
->setModel(new BaseList('Platforms List', self::MODEL_PLATFORM_LIST, 'platforms', self::MODEL_PLATFORM))
->setModel(new BaseList('Domains List', self::MODEL_DOMAIN_LIST, 'domains', self::MODEL_DOMAIN))
->setModel(new BaseList('Projects List', self::MODEL_PROJECT_LIST, 'projects', self::MODEL_PROJECT, true, false))
->setModel(new BaseList('Webhooks List', self::MODEL_WEBHOOK_LIST, 'webhooks', self::MODEL_WEBHOOK, true, false))
->setModel(new BaseList('API Keys List', self::MODEL_KEY_LIST, 'keys', self::MODEL_KEY, true, false))
->setModel(new BaseList('Tasks List', self::MODEL_TASK_LIST, 'tasks', self::MODEL_TASK, true, false))
->setModel(new BaseList('Platforms List', self::MODEL_PLATFORM_LIST, 'platforms', self::MODEL_PLATFORM, true, false))
->setModel(new BaseList('Domains List', self::MODEL_DOMAIN_LIST, 'domains', self::MODEL_DOMAIN, true, false))
->setModel(new BaseList('Countries List', self::MODEL_COUNTRY_LIST, 'countries', self::MODEL_COUNTRY))
->setModel(new BaseList('Continents List', self::MODEL_CONTINENT_LIST, 'continents', self::MODEL_CONTINENT))
->setModel(new BaseList('Languages List', self::MODEL_LANGUAGE_LIST, 'languages', self::MODEL_LANGUAGE))
->setModel(new BaseList('Currencies List', self::MODEL_CURRENCY_LIST, 'currencies', self::MODEL_CURRENCY))
->setModel(new BaseList('Phones List', self::MODEL_PHONE_LIST, 'phones', self::MODEL_PHONE))
// Entities
->setModel(new Any())
->setModel(new Permissions())
->setModel(new Collection())
->setModel(new Rule())
->setModel(new Log())
->setModel(new User())
->setModel(new Session())
->setModel(new Token())
->setModel(new Locale())
->setModel(new File())
->setModel(new Team())
@ -215,6 +222,16 @@ class Response extends SwooleResponse
return $this->models[$key];
}
/**
* Get Models List
*
* @return Model[]
*/
public function getModels(): array
{
return $this->models;
}
/**
* Validate response objects and outputs
* the response according to given format type

View file

@ -4,11 +4,27 @@ namespace Appwrite\Utopia\Response;
abstract class Model
{
const TYPE_STRING = 'string';
const TYPE_INTEGER = 'integer';
const TYPE_FLOAT = 'float';
const TYPE_BOOLEAN = 'boolean';
const TYPE_JSON = 'json';
/**
* @var bool
*/
protected $none = false;
/**
* @var bool
*/
protected $any = false;
/**
* @var bool
*/
protected $public = true;
/**
* @var array
*/
@ -44,6 +60,7 @@ abstract class Model
protected function addRule(string $key, array $options): self
{
$this->rules[$key] = array_merge([
'require' => true,
'type' => '',
'description' => '',
'default' => null,
@ -54,8 +71,52 @@ abstract class Model
return $this;
}
public function getRequired()
{
$list = [];
foreach($this->rules as $key => $rule) {
if(isset($rule['require']) || $rule['require']) {
$list[] = $key;
}
}
return $list;
}
/**
* Is None
*
* Use to check if response is empty
*
* @return bool
*/
public function isNone(): bool
{
return $this->none;
}
/**
* Is Any
*
* Use to check if response is a wildcard
*
* @return bool
*/
public function isAny(): bool
{
return $this->any;
}
/**
* Is Public
*
* Should this model be publicly available in docs and spec files?
*
* @return bool
*/
public function isPublic(): bool
{
return $this->public;
}
}

View file

@ -17,22 +17,32 @@ class BaseList extends Model
*/
protected $type = '';
public function __construct(string $name, string $type, string $key, string $model, bool $paging = true)
/**
* @param string $name
* @param string $type
* @param string $key
* @param string $model
* @param bool $paging
* @param bool $public
*/
public function __construct(string $name, string $type, string $key, string $model, bool $paging = true, bool $public = true)
{
$this->name = $name;
$this->type = $type;
$this->public = $public;
if ($paging) {
$this->addRule('sum', [
'type' => 'integer',
'type' => self::TYPE_INTEGER,
'description' => 'Total sum of items in the list.',
'example' => '5',
'default' => 0,
'example' => 5,
]);
}
$this->addRule($key, [
'type' => $model,
'description' => 'List of '.$key.'.',
'example' => [],
'default' => [],
'array' => true,
]);
}

View file

@ -11,7 +11,7 @@ class Collection extends Model
{
$this
->addRule('$id', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Collection ID.',
'example' => '5e5ea5c16897e',
])
@ -22,24 +22,23 @@ class Collection extends Model
'array' => false,
])
->addRule('name', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Collection name.',
'example' => 'Movies',
])
->addRule('dateCreated', [
'type' => 'integer',
'type' => self::TYPE_INTEGER,
'description' => 'Collection creation date in Unix timestamp.',
'example' => 1592981250,
])
->addRule('dateUpdated', [
'type' => 'integer',
'type' => self::TYPE_INTEGER,
'description' => 'Collection creation date in Unix timestamp.',
'example' => 1592981550,
])
->addRule('rules', [
'type' => Response::MODEL_RULE,
'description' => 'Collection rules.',
'example' => [],
'default' => [],
'array' => true,
])

View file

@ -11,12 +11,12 @@ class Continent extends Model
{
$this
->addRule('name', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Continent name.',
'example' => 'Europe',
])
->addRule('code', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Continent two letter code.',
'example' => 'EU',
])

View file

@ -11,12 +11,12 @@ class Country extends Model
{
$this
->addRule('name', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Country name.',
'example' => 'United States',
])
->addRule('code', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Country two-character ISO 3166-1 alpha code.',
'example' => 'US',
])

View file

@ -11,42 +11,42 @@ class Currency extends Model
{
$this
->addRule('symbol', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Currency symbol.',
'example' => '$',
])
->addRule('name', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Currency name.',
'example' => 'US dollar',
])
->addRule('symbolNative', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Currency native symbol.',
'example' => '$',
])
->addRule('decimalDigits', [
'type' => 'integer',
'type' => self::TYPE_INTEGER,
'description' => 'Number of decimal digits.',
'example' => 2,
])
->addRule('rounding', [
'type' => 'float',
'type' => self::TYPE_FLOAT,
'description' => 'Currency digit rounding.',
'example' => 0,
])
->addRule('code', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Currency code in [ISO 4217-1](http://en.wikipedia.org/wiki/ISO_4217) three-character format.',
'example' => 'USD',
])
->addRule('namePlural', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Currency plural name',
'example' => 'US dollars',
])
// ->addRule('locations', [
// 'type' => 'string',
// 'type' => self::TYPE_STRING,
// 'description' => 'Currency locations list. List of location in two-character ISO 3166-1 alpha code.',
// 'example' => ['US'],
// 'array' => true,

View file

@ -7,31 +7,36 @@ use Appwrite\Utopia\Response\Model;
class Domain extends Model
{
/**
* @var bool
*/
protected $public = false;
public function __construct()
{
$this
->addRule('$id', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Domain ID.',
'example' => '5e5ea5c16897e',
])
->addRule('domain', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Domain name.',
'example' => 'appwrite.company.com',
])
->addRule('registerable', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Registerable domain name.',
'example' => 'company.com',
])
->addRule('tld', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'TLD name.',
'example' => 'com',
])
->addRule('verification', [
'type' => 'boolean',
'type' => self::TYPE_BOOLEAN,
'description' => 'Verification process status.',
'example' => true,
])

View file

@ -11,17 +11,17 @@ class Error extends Model
{
$this
->addRule('message', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Error message.',
'example' => 'Not found',
])
->addRule('code', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Error code.',
'example' => '404',
])
->addRule('version', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Server version number.',
'example' => '1.0',
])

View file

@ -6,23 +6,28 @@ use Appwrite\Utopia\Response;
class ErrorDev extends Error
{
/**
* @var bool
*/
protected $public = false;
public function __construct()
{
parent::__construct();
$this
->addRule('file', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'File path.',
'example' => '/usr/code/vendor/utopia-php/framework/src/App.php',
])
->addRule('line', [
'type' => 'integer',
'type' => self::TYPE_INTEGER,
'description' => 'Line number.',
'example' => 209,
])
->addRule('trace', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Error trace.',
'example' => [
''

View file

@ -11,47 +11,47 @@ class Execution extends Model
{
$this
->addRule('$id', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Execution ID.',
'example' => '5e5ea5c16897e',
])
->addRule('functionId', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Function ID.',
'example' => '5e5ea6g16897e',
])
->addRule('dateCreated', [
'type' => 'integer',
'type' => self::TYPE_INTEGER,
'description' => 'The execution creation date in Unix timestamp.',
'example' => 1592981250,
])
->addRule('trigger', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'The trigger that caused the function to execute. Possible values can be: `http`, `schedule`, or `event`.',
'example' => 'http',
])
->addRule('status', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'The status of the function execution. Possible values can be: `waiting`, `processing`, `completed`, or `failed`.',
'example' => 'processing',
])
->addRule('exitCode', [
'type' => 'integer',
'type' => self::TYPE_INTEGER,
'description' => 'The script exit code.',
'example' => 0,
])
->addRule('stdout', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'The script stdout output string.',
'example' => '',
])
->addRule('stderr', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'The script stderr output string.',
'example' => '',
])
->addRule('time', [
'type' => 'float',
'type' => self::TYPE_FLOAT,
'description' => 'The script execution time in seconds.',
'example' => 0.400,
])

View file

@ -11,7 +11,7 @@ class File extends Model
{
$this
->addRule('$id', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'File ID.',
'example' => '5e5ea5c16897e',
])
@ -22,27 +22,27 @@ class File extends Model
'array' => false,
])
->addRule('name', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'File name.',
'example' => 'Pink.png',
])
->addRule('dateCreated', [
'type' => 'integer',
'type' => self::TYPE_INTEGER,
'description' => 'File creation date in Unix timestamp.',
'example' => 1592981250,
])
->addRule('signature', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'File MD5 signature.',
'example' => '5d529fd02b544198ae075bd57c1762bb',
])
->addRule('mimeType', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'File mime type.',
'example' => 'image/png',
])
->addRule('sizeOriginal', [
'type' => 'integer',
'type' => self::TYPE_INTEGER,
'description' => 'File original size in bytes.',
'example' => 17890,
])

View file

@ -11,74 +11,74 @@ class Func extends Model
{
$this
->addRule('$id', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Function ID.',
'example' => '5e5ea5c16897e',
])
->addRule('name', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Function name.',
'example' => 'My Function',
])
->addRule('dateCreated', [
'type' => 'integer',
'type' => self::TYPE_INTEGER,
'description' => 'Function creation date in Unix timestamp.',
'example' => 1592981250,
])
->addRule('dateUpdated', [
'type' => 'integer',
'type' => self::TYPE_INTEGER,
'description' => 'Function update date in Unix timestamp.',
'example' => 1592981257,
])
->addRule('status', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Function status. Possible values: disabled, enabled',
'example' => 'enabled',
])
->addRule('env', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Function execution environment.',
'example' => 'python-3.8',
])
->addRule('tag', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Function active tag ID.',
'default' => '',
'example' => '5e5ea5c16897e',
])
->addRule('vars', [
'type' => 'json',
'type' => self::TYPE_JSON,
'description' => 'Function environment variables.',
'default' => new \stdClass,
'example' => ['key' => 'value'],
])
->addRule('events', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Function trigger events.',
'default' => [],
'example' => ['account.create'],
'array' => true,
])
->addRule('schedule', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Function execution schedult in CRON format.',
'default' => '',
'example' => '5 4 * * *',
])
->addRule('scheduleNext', [
'type' => 'integer',
'type' => self::TYPE_INTEGER,
'description' => 'Function next scheduled execution date in Unix timestamp.',
'example' => 1592981292,
'default' => 0,
])
->addRule('schedulePrevious', [
'type' => 'integer',
'type' => self::TYPE_INTEGER,
'description' => 'Function next scheduled execution date in Unix timestamp.',
'example' => 1592981237,
'default' => 0,
])
->addRule('timeout', [
'type' => 'integer',
'type' => self::TYPE_INTEGER,
'description' => 'Function execution timeout in seconds.',
'default' => 15,
'example' => 1592981237,

View file

@ -7,28 +7,33 @@ use Appwrite\Utopia\Response\Model;
class Key extends Model
{
/**
* @var bool
*/
protected $public = false;
public function __construct()
{
$this
->addRule('$id', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Key ID.',
'example' => '5e5ea5c16897e',
])
->addRule('name', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Key name.',
'example' => 'My API Key',
])
->addRule('scopes', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Allowed permission scopes.',
'default' => [],
'example' => ['users.read', 'documents.write'],
'array' => true,
])
->addRule('secret', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Secret key.',
'example' => '919c2d18fb5d4...a2ae413da83346ad2',
])

View file

@ -11,17 +11,17 @@ class Language extends Model
{
$this
->addRule('name', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Language name.',
'example' => 'Italian',
])
->addRule('code', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Language two-character ISO 639-1 codes.',
'example' => 'it',
])
->addRule('nativeName', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Language native name.',
'example' => 'Italiano',
])

View file

@ -11,38 +11,38 @@ class Locale extends Model
{
$this
->addRule('ip', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'User IP address.',
'example' => '127.0.0.1',
])
->addRule('countryCode', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Country code in [ISO 3166-1](http://en.wikipedia.org/wiki/ISO_3166-1) two-character format',
'example' => 'US',
])
->addRule('country', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Country name. This field support localization.',
'example' => 'United States',
])
->addRule('continentCode', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Continent code. A two character continent code "AF" for Africa, "AN" for Antarctica, "AS" for Asia, "EU" for Europe, "NA" for North America, "OC" for Oceania, and "SA" for South America.',
'example' => 'NA',
])
->addRule('continent', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Continent name. This field support localization.',
'example' => 'North America',
])
->addRule('eu', [
'type' => 'Boolean',
'type' => self::TYPE_BOOLEAN,
'description' => 'True if country is part of the Europian Union.',
'default' => false,
'example' => false,
])
->addRule('currency', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Currency code in [ISO 4217-1](http://en.wikipedia.org/wiki/ISO_4217) three-character format',
'example' => 'USD',
])

View file

@ -11,100 +11,100 @@ class Log extends Model
{
$this
->addRule('event', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Event name.',
'example' => 'account.sessions.create',
])
->addRule('ip', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'IP session in use when the session was created.',
'example' => '127.0.0.1',
])
->addRule('time', [
'type' => 'integer',
'type' => self::TYPE_INTEGER,
'description' => 'Log creation time in Unix timestamp.',
'example' => 1592981250,
])
->addRule('osCode', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Operating system code name. View list of [available options](https://github.com/appwrite/appwrite/blob/master/docs/lists/os.json).',
'default' => '',
'example' => 'Mac',
])
->addRule('osName', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Operating system name.',
'default' => '',
'example' => 'Mac',
])
->addRule('osVersion', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Operating system version.',
'default' => '',
'example' => 'Mac',
])
->addRule('clientType', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Client type.',
'default' => '',
'example' => 'browser',
])
->addRule('clientCode', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Client code name. View list of [available options](https://github.com/appwrite/appwrite/blob/master/docs/lists/clients.json).',
'default' => '',
'example' => 'CM',
])
->addRule('clientName', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Client name.',
'default' => '',
'example' => 'Chrome Mobile iOS',
])
->addRule('clientVersion', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Client version.',
'default' => '',
'example' => '84.0',
])
->addRule('clientEngine', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Client engine name.',
'default' => '',
'example' => 'WebKit',
])
->addRule('clientEngineVersion', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Client engine name.',
'default' => '',
'example' => '605.1.15',
])
->addRule('deviceName', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Device name.',
'default' => '',
'example' => 'smartphone',
])
->addRule('deviceBrand', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Device brand name.',
'default' => '',
'example' => 'Google',
])
->addRule('deviceModel', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Device model name.',
'default' => '',
'example' => 'Nexus 5',
])
->addRule('countryCode', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Country two-character ISO 3166-1 alpha code.',
'default' => '',
'example' => 'US',
])
->addRule('countryName', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Country name.',
'default' => '',
'example' => 'United States',

View file

@ -11,49 +11,49 @@ class Membership extends Model
{
$this
->addRule('$id', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Membership ID.',
'example' => '5e5ea5c16897e',
])
->addRule('userId', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'User ID.',
'example' => '5e5ea5c16897e',
])
->addRule('teamId', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Team ID.',
'example' => '5e5ea5c16897e',
])
->addRule('name', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'User name.',
'default' => '',
'example' => 'VIP',
])
->addRule('email', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'User email address.',
'default' => '',
'example' => 'john@appwrite.io',
])
->addRule('invited', [
'type' => 'integer',
'type' => self::TYPE_INTEGER,
'description' => 'Date, the user has been invited to join the team in Unix timestamp.',
'example' => 1592981250,
])
->addRule('joined', [
'type' => 'integer',
'type' => self::TYPE_INTEGER,
'description' => 'Date, the user has accepted the invitation to join the team in Unix timestamp.',
'example' => 1592981250,
])
->addRule('confirm', [
'type' => 'boolean',
'type' => self::TYPE_BOOLEAN,
'description' => 'User confirmation status, true if the user has joined the team or false otherwise.',
'example' => false,
])
->addRule('roles', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'User list of roles',
'default' => [],
'example' => [],

View file

@ -0,0 +1,34 @@
<?php
namespace Appwrite\Utopia\Response\Model;
use Appwrite\Utopia\Response;
use Appwrite\Utopia\Response\Model;
class None extends Model
{
/**
* @var bool
*/
protected $none = true;
/**
* Get Name
*
* @return string
*/
public function getName():string
{
return 'None';
}
/**
* Get Collection
*
* @return string
*/
public function getType():string
{
return Response::MODEL_NONE;
}
}

View file

@ -11,13 +11,13 @@ class Permissions extends Model
{
$this
->addRule('read', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Read permissions.',
'example' => ['*', 'user:5e5ea5c16897e'],
'array' => true,
])
->addRule('write', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Write permissions.',
'example' => ['*', 'user:5e5ea5c16897e'],
'array' => true,

View file

@ -11,17 +11,17 @@ class Phone extends Model
{
$this
->addRule('code', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Phone code.',
'example' => '+1',
])
->addRule('countryCode', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Country two-character ISO 3166-1 alpha code.',
'example' => 'US',
])
->addRule('countryName', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Country name.',
'example' => 'United States',
])

View file

@ -7,47 +7,52 @@ use Appwrite\Utopia\Response\Model;
class Platform extends Model
{
/**
* @var bool
*/
protected $public = false;
public function __construct()
{
$this
->addRule('$id', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Platform ID.',
'example' => '5e5ea5c16897e',
])
->addRule('name', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Platform name.',
'example' => 'My Web App',
])
->addRule('type', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Platform type. Possible values are: web, flutter-ios, flutter-android, ios, android, and unity.',
'example' => 'My Web App',
])
->addRule('key', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Platform Key. iOS bundle ID or Android package name. Empty string for other platforms.',
'example' => 'com.company.appname',
])
// ->addRule('store', [
// 'type' => 'string',
// 'type' => self::TYPE_STRING,
// 'description' => 'Link to platform store.',
// 'example' => '',
// ])
->addRule('hostname', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Web app hostname. Empty string for other platforms.',
'example' => true,
])
->addRule('httpUser', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'HTTP basic authentication username.',
'default' => '',
'example' => 'username',
])
->addRule('httpPass', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'HTTP basic authentication password.',
'default' => '',
'example' => 'password',

View file

@ -8,75 +8,80 @@ use Utopia\Config\Config;
class Project extends Model
{
/**
* @var bool
*/
protected $public = false;
public function __construct()
{
$this
->addRule('$id', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Project ID.',
'example' => '5e5ea5c16897e',
])
->addRule('name', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Project name.',
'default' => '',
'example' => 'New Project',
])
->addRule('description', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Project description.',
'default' => '',
'example' => 'This is a new project.',
])
->addRule('teamId', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Project team ID.',
'example' => '1592981250',
])
->addRule('logo', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Project logo file ID.',
'default' => '',
'example' => '5f5c451b403cb',
])
->addRule('url', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Project website URL.',
'default' => '',
'example' => '5f5c451b403cb',
])
->addRule('legalName', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Company legal name.',
'default' => '',
'example' => 'Company LTD.',
])
->addRule('legalCountry', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Country code in [ISO 3166-1](http://en.wikipedia.org/wiki/ISO_3166-1) two-character format.',
'default' => '',
'example' => 'US',
])
->addRule('legalState', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'State name.',
'default' => '',
'example' => 'New York',
])
->addRule('legalCity', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'City name.',
'default' => '',
'example' => 'New York City.',
])
->addRule('legalAddress', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Company Address.',
'default' => '',
'example' => '620 Eighth Avenue, New York, NY 10018',
])
->addRule('legalTaxId', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Company Tax ID.',
'default' => '',
'example' => '131102020',
@ -129,13 +134,13 @@ class Project extends Model
$this
->addRule('usersOauth2'.\ucfirst($index).'Appid', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => $name.' OAuth app ID.',
'example' => '123247283472834787438',
'default' => '',
])
->addRule('usersOauth2'.\ucfirst($index).'Secret', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => $name.' OAuth secret ID.',
'example' => 'djsgudsdsewe43434343dd34...',
'default' => '',

View file

@ -11,48 +11,48 @@ class Rule extends Model
{
$this
->addRule('$id', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Rule ID.',
'example' => '5e5ea5c16897e',
])
->addRule('$collection', [ // TODO remove this from public response
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Rule Collection.',
'example' => '5e5e66c16897e',
])
->addRule('type', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Rule type. Possible values: ',
'example' => 'title',
])
->addRule('key', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Rule key.',
'example' => 'title',
])
->addRule('label', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Rule label.',
'example' => 'Title',
])
->addRule('default', [ // TODO should be of mixed types
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Rule default value.',
'example' => 'Movie Name',
'default' => '',
])
->addRule('array', [
'type' => 'boolean',
'type' => self::TYPE_BOOLEAN,
'description' => 'Is array?',
'example' => false,
])
->addRule('required', [
'type' => 'boolean',
'type' => self::TYPE_BOOLEAN,
'description' => 'Is required?',
'example' => true,
])
->addRule('list', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'List of allowed values',
'array' => true,
'default' => [],

View file

@ -11,108 +11,108 @@ class Session extends Model
{
$this
->addRule('$id', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Session ID.',
'example' => '5e5ea5c16897e',
])
->addRule('expire', [
'type' => 'integer',
'type' => self::TYPE_INTEGER,
'description' => 'Session expiration date in Unix timestamp.',
'default' => 0,
'example' => 1592981250,
])
->addRule('ip', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'IP in use when the session was created.',
'default' => '',
'example' => '127.0.0.1',
])
->addRule('osCode', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Operating system code name. View list of [available options](https://github.com/appwrite/appwrite/blob/master/docs/lists/os.json).',
'default' => '',
'example' => 'Mac',
])
->addRule('osName', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Operating system name.',
'default' => '',
'example' => 'Mac',
])
->addRule('osVersion', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Operating system version.',
'default' => '',
'example' => 'Mac',
])
->addRule('clientType', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Client type.',
'default' => '',
'example' => 'browser',
])
->addRule('clientCode', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Client code name. View list of [available options](https://github.com/appwrite/appwrite/blob/master/docs/lists/clients.json).',
'default' => '',
'example' => 'CM',
])
->addRule('clientName', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Client name.',
'default' => '',
'example' => 'Chrome Mobile iOS',
])
->addRule('clientVersion', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Client version.',
'default' => '',
'example' => '84.0',
])
->addRule('clientEngine', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Client engine name.',
'default' => '',
'example' => 'WebKit',
])
->addRule('clientEngineVersion', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Client engine name.',
'default' => '',
'example' => '605.1.15',
])
->addRule('deviceName', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Device name.',
'default' => '',
'example' => 'smartphone',
])
->addRule('deviceBrand', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Device brand name.',
'default' => '',
'example' => 'Google',
])
->addRule('deviceModel', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Device model name.',
'default' => '',
'example' => 'Nexus 5',
])
->addRule('countryCode', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Country two-character ISO 3166-1 alpha code.',
'default' => '',
'example' => 'US',
])
->addRule('countryName', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Country name.',
'default' => '',
'example' => 'United States',
])
->addRule('current', [
'type' => 'boolean',
'type' => self::TYPE_BOOLEAN,
'description' => 'Returns true if this the current user session.',
'default' => '',
'example' => true,

View file

@ -11,27 +11,27 @@ class Tag extends Model
{
$this
->addRule('$id', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Tag ID.',
'example' => '5e5ea5c16897e',
])
->addRule('functionId', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Function ID.',
'example' => '5e5ea6g16897e',
])
->addRule('dateCreated', [
'type' => 'integer',
'type' => self::TYPE_INTEGER,
'description' => 'The tag creation date in Unix timestamp.',
'example' => 1592981250,
])
->addRule('command', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'The entrypoint command in use to execute the tag code.',
'example' => 'enabled',
])
->addRule('size', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'The code size in bytes.',
'example' => 'python-3.8',
])

View file

@ -7,95 +7,100 @@ use Appwrite\Utopia\Response\Model;
class Task extends Model
{
/**
* @var bool
*/
protected $public = false;
public function __construct()
{
$this
->addRule('$id', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Task ID.',
'example' => '5e5ea5c16897e',
])
->addRule('name', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Task name.',
'example' => 'My Task',
])
->addRule('security', [
'type' => 'boolean',
'type' => self::TYPE_BOOLEAN,
'description' => 'Indicated if SSL / TLS Certificate verification is enabled.',
'example' => true,
])
->addRule('httpMethod', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Task HTTP Method.',
'example' => 'POST',
])
->addRule('httpUrl', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Task HTTP URL.',
'example' => 'https://example.com/task',
])
->addRule('httpHeaders', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Task HTTP headers.',
'default' => [],
'example' => ['key:value'],
'array' => true,
])
->addRule('httpUser', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'HTTP basic authentication username.',
'default' => '',
'example' => 'username',
])
->addRule('httpPass', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'HTTP basic authentication password.',
'default' => '',
'example' => 'password',
])
->addRule('duration', [
'type' => 'float',
'type' => self::TYPE_FLOAT,
'description' => 'Task duration in seconds.',
'default' => 0,
'example' => 1.2,
])
->addRule('delay', [
'type' => 'float',
'type' => self::TYPE_FLOAT,
'description' => 'Task delay time in seconds.',
'default' => 0,
'example' => 1.2,
])
->addRule('failures', [
'type' => 'integer',
'type' => self::TYPE_INTEGER,
'description' => 'Number of recurring task failures.',
'default' => 0,
'example' => 0,
])
->addRule('schedule', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Task schedule in CRON syntax.',
'example' => '* * * * *',
])
->addRule('status', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Task status. Possible values: play, pause', // TODO - change to enabled disabled
'example' => 'enabled',
])
->addRule('updated', [
'type' => 'integer',
'type' => self::TYPE_INTEGER,
'description' => 'Task last updated time in Unix timestamp.',
'default' => 0,
'example' => 1592981250,
])
->addRule('previous', [
'type' => 'integer',
'type' => self::TYPE_INTEGER,
'description' => 'Task previous run time in Unix timestamp.',
'default' => 0,
'example' => 1592981250,
])
->addRule('next', [
'type' => 'integer',
'type' => self::TYPE_INTEGER,
'description' => 'Task next run time in Unix timestamp.',
'default' => 0,
'example' => 1592981650,

View file

@ -11,23 +11,23 @@ class Team extends Model
{
$this
->addRule('$id', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Team ID.',
'example' => '5e5ea5c16897e',
])
->addRule('name', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Team name.',
'default' => '',
'example' => 'VIP',
])
->addRule('dateCreated', [
'type' => 'integer',
'type' => self::TYPE_INTEGER,
'description' => 'Team creation date in Unix timestamp.',
'example' => 1592981250,
])
->addRule('sum', [ // TODO change key name?
'type' => 'integer',
'type' => self::TYPE_INTEGER,
'description' => 'Total sum of team members.',
'example' => 7,
])

View file

@ -9,6 +9,25 @@ class Token extends Model
{
public function __construct()
{
$this
->addRule('$id', [
'type' => self::TYPE_STRING,
'description' => 'Token ID.',
'example' => '5e5ea5c16897e',
])
// ->addRule('type', [ TODO: use this when token types will be strings
// 'type' => self::TYPE_STRING,
// 'description' => 'Token type. Possible values: play, pause',
// 'default' => '',
// 'example' => '127.0.0.1',
// ])
->addRule('expire', [
'type' => self::TYPE_INTEGER,
'description' => 'Token expiration date in Unix timestamp.',
'default' => 0,
'example' => 1592981250,
])
;
}
/**
@ -18,7 +37,7 @@ class Token extends Model
*/
public function getName():string
{
return 'User';
return 'Token';
}
/**
@ -28,6 +47,6 @@ class Token extends Model
*/
public function getType():string
{
return Response::MODEL_LOCALE;
return Response::MODEL_TOKEN;
}
}

View file

@ -11,47 +11,47 @@ class User extends Model
{
$this
->addRule('$id', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'User ID.',
'example' => '5e5ea5c16897e',
])
->addRule('name', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'User name.',
'example' => 'John Doe',
])
->addRule('registration', [
'type' => 'integer',
'type' => self::TYPE_INTEGER,
'description' => 'User registration date in Unix timestamp.',
'example' => 1592981250,
])
->addRule('status', [
'type' => 'integer',
'type' => self::TYPE_INTEGER,
'description' => 'User status. 0 for Unavtivated, 1 for active and 2 is blocked.',
'example' => 0,
])
->addRule('email', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'User email address.',
'example' => 'john@appwrite.io',
])
->addRule('emailVerification', [
'type' => 'boolean',
'type' => self::TYPE_BOOLEAN,
'description' => 'Email verification status.',
'default' => false,
'example' => true,
])
->addRule('prefs', [
'type' => 'json',
'type' => self::TYPE_JSON,
'description' => 'User preferences as a key-value object',
'default' => new \stdClass,
'example' => ['theme' => 'pink', 'timezone' => 'UTC'],
])
->addRule('roles', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'User list of roles',
'default' => [],
'example' => [],
'example' => '*',
'array' => true,
])
;

View file

@ -7,44 +7,49 @@ use Appwrite\Utopia\Response\Model;
class Webhook extends Model
{
/**
* @var bool
*/
protected $public = false;
public function __construct()
{
$this
->addRule('$id', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Webhook ID.',
'example' => '5e5ea5c16897e',
])
->addRule('name', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Webhook name.',
'example' => 'My Webhook',
])
->addRule('url', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Webhook URL endpoint.',
'example' => 'https://example.com/webhook',
])
->addRule('events', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'Webhook trigger events.',
'default' => [],
'example' => ['database.collections.update', 'database.collections.delete'],
'array' => true,
])
->addRule('security', [
'type' => 'boolean',
'type' => self::TYPE_BOOLEAN,
'description' => 'Indicated if SSL / TLS Certificate verification is enabled.',
'example' => true,
])
->addRule('httpUser', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'HTTP basic authentication username.',
'default' => '',
'example' => 'username',
])
->addRule('httpPass', [
'type' => 'string',
'type' => self::TYPE_STRING,
'description' => 'HTTP basic authentication password.',
'default' => '',
'example' => 'password',

View file

@ -2,10 +2,13 @@
namespace Tests\E2E\Services\Account;
use CURLFile;
use Exception;
use Tests\E2E\Client;
use Tests\E2E\Scopes\ProjectNone;
use Tests\E2E\Scopes\Scope;
use Tests\E2E\Scopes\SideNone;
use Utopia\CLI\Console;
class HTTPTest extends Scope
{
@ -92,4 +95,60 @@ class HTTPTest extends Scope
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertStringContainsString('# robotstxt.org/', $response['body']);
}
public function testSpecSwagger2()
{
$response = $this->client->call(Client::METHOD_GET, '/specs/swagger2?platform=client', [
'content-type' => 'application/json',
], []);
if(!file_put_contents(__DIR__ . '/../../resources/swagger2.json', json_encode($response['body']))) {
throw new Exception('Failed to save spec file');
}
$client = new Client();
$client->setEndpoint('https://validator.swagger.io');
/**
* Test for SUCCESS
*/
$response = $client->call(Client::METHOD_POST, '/validator/debug', [
'content-type' => 'application/json',
], json_decode(file_get_contents(realpath(__DIR__ . '/../../resources/swagger2.json')), true));
$response['body'] = json_decode($response['body'], true);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertFalse(isset($response['body']['messages']));
unlink(realpath(__DIR__ . '/../../resources/swagger2.json'));
}
public function testSpecOpenAPI3()
{
$response = $this->client->call(Client::METHOD_GET, '/specs/open-api3?platform=client', [
'content-type' => 'application/json',
], []);
if(!file_put_contents(__DIR__ . '/../../resources/open-api3.json', json_encode($response['body']))) {
throw new Exception('Failed to save spec file');
}
$client = new Client();
$client->setEndpoint('https://validator.swagger.io');
/**
* Test for SUCCESS
*/
$response = $client->call(Client::METHOD_POST, '/validator/debug', [
'content-type' => 'application/json',
], json_decode(file_get_contents(realpath(__DIR__ . '/../../resources/open-api3.json')), true));
$response['body'] = json_decode($response['body'], true);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertFalse(isset($response['body']['messages']));
unlink(realpath(__DIR__ . '/../../resources/open-api3.json'));
}
}

View file

@ -648,7 +648,6 @@ trait AccountBase
$this->assertEquals(201, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
$this->assertEquals(2, $response['body']['type']);
$this->assertIsNumeric($response['body']['expire']);
$lastEmail = $this->getLastEmail();
@ -940,7 +939,6 @@ trait AccountBase
$this->assertEquals(201, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
$this->assertEquals(3, $response['body']['type']);
$this->assertIsNumeric($response['body']['expire']);
$lastEmail = $this->getLastEmail();

View file

@ -221,10 +221,10 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
$this->assertEquals('Project Test 2', $response['body']['name']);
// $this->assertArrayHasKey('platforms', $response['body']); // TODO enable when response model is enabled
// $this->assertArrayHasKey('webhooks', $response['body']); // TODO enable when response model is enabled
// $this->assertArrayHasKey('keys', $response['body']); // TODO enable when response model is enabled
// $this->assertArrayHasKey('tasks', $response['body']); // TODO enable when response model is enabled
$this->assertArrayHasKey('platforms', $response['body']);
$this->assertArrayHasKey('webhooks', $response['body']);
$this->assertArrayHasKey('keys', $response['body']);
$this->assertArrayHasKey('tasks', $response['body']);
$projectId = $response['body']['$id'];
@ -443,7 +443,7 @@ class ProjectsConsoleClientTest extends Scope
$this->assertIsBool($response['body']['security']);
$this->assertEquals(false, $response['body']['security']);
$this->assertEquals('', $response['body']['httpUser']);
// $this->assertEquals('', $response['body']['httpPass']); // TODO add after encrypt refactor
$this->assertEquals('', $response['body']['httpPass']);
$response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/webhooks/'.$webhookId, array_merge([
'content-type' => 'application/json',
@ -462,7 +462,7 @@ class ProjectsConsoleClientTest extends Scope
$this->assertIsBool($response['body']['security']);
$this->assertEquals(false, $response['body']['security']);
$this->assertEquals('', $response['body']['httpUser']);
// $this->assertEquals('', $response['body']['httpPass']); // TODO add after encrypt refactor
$this->assertEquals('', $response['body']['httpPass']);
/**
* Test for FAILURE
@ -759,7 +759,7 @@ class ProjectsConsoleClientTest extends Scope
$this->assertContains('demo:value', $response['body']['httpHeaders']);
$this->assertCount(1, $response['body']['httpHeaders']);
$this->assertEquals('username', $response['body']['httpUser']);
// $this->assertEquals('password', $response['body']['httpPass']); // TODO add after encrypt refactor
$this->assertEquals('password', $response['body']['httpPass']);
$data = array_merge($data, ['taskId' => $response['body']['$id']]);
@ -901,7 +901,7 @@ class ProjectsConsoleClientTest extends Scope
$this->assertContains('demo:value', $response['body']['httpHeaders']);
$this->assertCount(1, $response['body']['httpHeaders']);
$this->assertEquals('username', $response['body']['httpUser']);
// $this->assertEquals('password', $response['body']['httpPass']); // TODO add after encrypt refactor
$this->assertEquals('password', $response['body']['httpPass']);
/**
* Test for FAILURE
@ -952,7 +952,7 @@ class ProjectsConsoleClientTest extends Scope
$this->assertContains('demo2:value2', $response['body']['httpHeaders']);
$this->assertCount(2, $response['body']['httpHeaders']);
$this->assertEquals('username1', $response['body']['httpUser']);
// $this->assertEquals('password1', $response['body']['httpPass']); // TODO add after encrypt refactor
$this->assertEquals('password1', $response['body']['httpPass']);
$response = $this->client->call(Client::METHOD_GET, '/projects/'.$id.'/tasks/'.$taskId, array_merge([
'content-type' => 'application/json',
@ -972,7 +972,7 @@ class ProjectsConsoleClientTest extends Scope
$this->assertContains('demo2:value2', $response['body']['httpHeaders']);
$this->assertCount(2, $response['body']['httpHeaders']);
$this->assertEquals('username1', $response['body']['httpUser']);
// $this->assertEquals('password1', $response['body']['httpPass']); // TODO add after encrypt refactor
$this->assertEquals('password1', $response['body']['httpPass']);
/**
* Test for FAILURE

View file

@ -118,4 +118,38 @@ class AuthTest extends TestCase
$this->assertEquals(Auth::tokenVerify($tokens3, Auth::TOKEN_TYPE_LOGIN, $secret), false);
$this->assertEquals(Auth::tokenVerify($tokens3, Auth::TOKEN_TYPE_LOGIN, 'false-secret'), false);
}
public function testIsPreviliggedUser()
{
$this->assertEquals(false, Auth::isPreviliggedUser([]));
$this->assertEquals(false, Auth::isPreviliggedUser(['role:'.Auth::USER_ROLE_GUEST => true]));
$this->assertEquals(false, Auth::isPreviliggedUser(['role:'.Auth::USER_ROLE_MEMBER => true]));
$this->assertEquals(true, Auth::isPreviliggedUser(['role:'.Auth::USER_ROLE_ADMIN => true]));
$this->assertEquals(true, Auth::isPreviliggedUser(['role:'.Auth::USER_ROLE_DEVELOPER => true]));
$this->assertEquals(true, Auth::isPreviliggedUser(['role:'.Auth::USER_ROLE_OWNER => true]));
$this->assertEquals(false, Auth::isPreviliggedUser(['role:'.Auth::USER_ROLE_APP => true]));
$this->assertEquals(false, Auth::isPreviliggedUser(['role:'.Auth::USER_ROLE_SYSTEM => true]));
$this->assertEquals(false, Auth::isPreviliggedUser(['role:'.Auth::USER_ROLE_APP => true, 'role:'.Auth::USER_ROLE_APP => true]));
$this->assertEquals(false, Auth::isPreviliggedUser(['role:'.Auth::USER_ROLE_APP => true, 'role:'.Auth::USER_ROLE_GUEST => true]));
$this->assertEquals(true, Auth::isPreviliggedUser(['role:'.Auth::USER_ROLE_OWNER => true, 'role:'.Auth::USER_ROLE_GUEST => true]));
$this->assertEquals(true, Auth::isPreviliggedUser(['role:'.Auth::USER_ROLE_OWNER => true, 'role:'.Auth::USER_ROLE_ADMIN => true, 'role:'.Auth::USER_ROLE_DEVELOPER => true]));
}
public function testIsAppUser()
{
$this->assertEquals(false, Auth::isAppUser([]));
$this->assertEquals(false, Auth::isAppUser(['role:'.Auth::USER_ROLE_GUEST => true]));
$this->assertEquals(false, Auth::isAppUser(['role:'.Auth::USER_ROLE_MEMBER => true]));
$this->assertEquals(false, Auth::isAppUser(['role:'.Auth::USER_ROLE_ADMIN => true]));
$this->assertEquals(false, Auth::isAppUser(['role:'.Auth::USER_ROLE_DEVELOPER => true]));
$this->assertEquals(false, Auth::isAppUser(['role:'.Auth::USER_ROLE_OWNER => true]));
$this->assertEquals(true, Auth::isAppUser(['role:'.Auth::USER_ROLE_APP => true]));
$this->assertEquals(false, Auth::isAppUser(['role:'.Auth::USER_ROLE_SYSTEM => true]));
$this->assertEquals(true, Auth::isAppUser(['role:'.Auth::USER_ROLE_APP => true, 'role:'.Auth::USER_ROLE_APP => true]));
$this->assertEquals(true, Auth::isAppUser(['role:'.Auth::USER_ROLE_APP => true, 'role:'.Auth::USER_ROLE_GUEST => true]));
$this->assertEquals(false, Auth::isAppUser(['role:'.Auth::USER_ROLE_OWNER => true, 'role:'.Auth::USER_ROLE_GUEST => true]));
$this->assertEquals(false, Auth::isAppUser(['role:'.Auth::USER_ROLE_OWNER => true, 'role:'.Auth::USER_ROLE_ADMIN => true, 'role:'.Auth::USER_ROLE_DEVELOPER => true]));
}
}

View file

@ -0,0 +1,83 @@
<?php
namespace Appwrite\Tests;
use Appwrite\Database\Document;
use Appwrite\Database\Validator\Authorization;
use PHPUnit\Framework\TestCase;
class AuthorizationTest extends TestCase
{
/**
* @var Authorization
*/
protected $object = null;
/**
* @var Document
*/
protected $document = null;
public function setUp(): void
{
$this->document = new Document([
'$id' => uniqid(),
'$collection' => uniqid(),
'$permissions' => [
'read' => ['user:123', 'team:123'],
'write' => ['*'],
],
]);
$this->object = new Authorization($this->document, 'read');
}
public function tearDown(): void
{
}
public function testValues()
{
$this->assertEquals($this->object->isValid($this->document->getPermissions()), false);
Authorization::setRole('user:456');
Authorization::setRole('user:123');
$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($this->object->isValid($this->document->getPermissions()), true);
Authorization::cleanRoles();
$this->assertEquals($this->object->isValid($this->document->getPermissions()), false);
Authorization::setRole('team:123');
$this->assertEquals($this->object->isValid($this->document->getPermissions()), true);
Authorization::cleanRoles();
Authorization::disable();
$this->assertEquals($this->object->isValid($this->document->getPermissions()), true);
Authorization::reset();
$this->assertEquals($this->object->isValid($this->document->getPermissions()), false);
Authorization::setDefaultStatus(false);
Authorization::disable();
$this->assertEquals($this->object->isValid($this->document->getPermissions()), true);
Authorization::reset();
$this->assertEquals($this->object->isValid($this->document->getPermissions()), true);
Authorization::enable();
$this->assertEquals($this->object->isValid($this->document->getPermissions()), false);
}
}