1
0
Fork 0
mirror of synced 2024-06-26 18:20:43 +12:00

Merge branch 'feat-database-indexing' into feat-custom-id

This commit is contained in:
Damodar Lohani 2021-08-03 13:34:02 +05:45
commit 136681df27
274 changed files with 3534 additions and 1885 deletions

View file

@ -238,7 +238,6 @@ RUN chmod +x /usr/local/bin/doctor && \
chmod +x /usr/local/bin/worker-deletes && \
chmod +x /usr/local/bin/worker-functions && \
chmod +x /usr/local/bin/worker-mails && \
chmod +x /usr/local/bin/worker-tasks && \
chmod +x /usr/local/bin/worker-usage && \
chmod +x /usr/local/bin/worker-webhooks

View file

@ -807,16 +807,6 @@ $collections = [
'array' => true,
'list' => [Database::SYSTEM_COLLECTION_KEYS],
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'Tasks',
'key' => 'tasks',
'type' => Database::SYSTEM_VAR_TYPE_DOCUMENT,
'default' => [],
'required' => false,
'array' => true,
'list' => [Database::SYSTEM_COLLECTION_TASKS],
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'Platforms',
@ -939,160 +929,6 @@ $collections = [
],
],
],
Database::SYSTEM_COLLECTION_TASKS => [
'$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS,
'$id' => Database::SYSTEM_COLLECTION_TASKS,
'$permissions' => ['read' => ['role:all']],
'name' => 'Task',
'structure' => true,
'rules' => [
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'Name',
'key' => 'name',
'type' => Database::SYSTEM_VAR_TYPE_TEXT,
'default' => null,
'required' => true,
'array' => false,
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'Status',
'key' => 'status',
'type' => Database::SYSTEM_VAR_TYPE_TEXT,
'default' => '',
'required' => false,
'array' => false,
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'Updated',
'key' => 'updated',
'type' => Database::SYSTEM_VAR_TYPE_NUMERIC,
'default' => '',
'required' => false,
'array' => false,
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'Schedule',
'key' => 'schedule',
'type' => Database::SYSTEM_VAR_TYPE_TEXT,
'default' => '',
'required' => false,
'array' => false,
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'Previous',
'key' => 'previous',
'type' => Database::SYSTEM_VAR_TYPE_NUMERIC,
'default' => '',
'required' => false,
'array' => false,
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'Next',
'key' => 'next',
'type' => Database::SYSTEM_VAR_TYPE_NUMERIC,
'default' => '',
'required' => false,
'array' => false,
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'Duration',
'key' => 'duration',
'type' => Database::SYSTEM_VAR_TYPE_NUMERIC,
'default' => '',
'required' => false,
'array' => false,
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'Delay',
'key' => 'delay',
'type' => Database::SYSTEM_VAR_TYPE_NUMERIC,
'default' => '',
'required' => false,
'array' => false,
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'Security',
'key' => 'security',
'type' => Database::SYSTEM_VAR_TYPE_BOOLEAN,
'default' => '',
'required' => false,
'array' => false,
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'HTTP Method',
'key' => 'httpMethod',
'type' => Database::SYSTEM_VAR_TYPE_TEXT,
'default' => '',
'required' => false,
'array' => false,
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'HTTP URL',
'key' => 'httpUrl',
'type' => Database::SYSTEM_VAR_TYPE_TEXT,
'default' => '',
'required' => false,
'array' => false,
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'HTTP Headers',
'key' => 'httpHeaders',
'type' => Database::SYSTEM_VAR_TYPE_TEXT,
'default' => null,
'required' => false,
'array' => true,
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'HTTP User',
'key' => 'httpUser',
'type' => Database::SYSTEM_VAR_TYPE_TEXT,
'default' => '',
'required' => false,
'array' => false,
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'HTTP Password',
'key' => 'httpPass',
'type' => Database::SYSTEM_VAR_TYPE_TEXT,
'default' => '',
'required' => false,
'array' => false,
'filter' => ['encrypt'],
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'Log',
'key' => 'log',
'type' => Database::SYSTEM_VAR_TYPE_TEXT,
'default' => '',
'required' => false,
'array' => false,
],
[
'$collection' => Database::SYSTEM_COLLECTION_RULES,
'label' => 'Failures',
'key' => 'failures',
'type' => Database::SYSTEM_VAR_TYPE_NUMERIC,
'default' => '',
'required' => false,
'array' => false,
],
],
],
Database::SYSTEM_COLLECTION_PLATFORMS => [
'$collection' => Database::SYSTEM_COLLECTION_COLLECTIONS,
'$id' => Database::SYSTEM_COLLECTION_PLATFORMS,

View file

@ -155,6 +155,17 @@ $collections = [
'array' => false,
'filters' => [],
],
[
'$id' => 'services',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16384,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => ['json'],
],
[
'$id' => 'platforms',
'type' => Database::VAR_STRING,
@ -188,17 +199,6 @@ $collections = [
'array' => true,
'filters' => ['json'],
],
[
'$id' => 'tasks',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16384,
'signed' => true,
'required' => false,
'default' => null,
'array' => true,
'filters' => ['json'],
],
[
'$id' => 'domains',
'type' => Database::VAR_STRING,
@ -218,7 +218,7 @@ $collections = [
'attributes' => ['name'],
'lengths' => [1024],
'orders' => [Database::ORDER_ASC],
]
],
],
],
@ -291,7 +291,7 @@ $collections = [
'required' => false,
'default' => null,
'array' => false,
'filters' => ['json']
'filters' => ['json'],
],
[
'$id' => 'registration',
@ -367,7 +367,7 @@ $collections = [
'attributes' => ['email'],
'lengths' => [1024],
'orders' => [Database::ORDER_ASC],
]
],
],
],
@ -473,7 +473,7 @@ $collections = [
'required' => false,
'default' => null,
'array' => false,
'filters' => []
'filters' => [],
],
[
'$id' => 'osCode',
@ -484,7 +484,7 @@ $collections = [
'required' => false,
'default' => null,
'array' => false,
'filters' => []
'filters' => [],
],
[
'$id' => 'osName',
@ -495,7 +495,7 @@ $collections = [
'required' => false,
'default' => null,
'array' => false,
'filters' => []
'filters' => [],
],
[
'$id' => 'osVersion',
@ -506,7 +506,7 @@ $collections = [
'required' => false,
'default' => null,
'array' => false,
'filters' => []
'filters' => [],
],
[
'$id' => 'clientType',
@ -517,7 +517,7 @@ $collections = [
'required' => false,
'default' => null,
'array' => false,
'filters' => []
'filters' => [],
],
[
'$id' => 'clientCode',
@ -528,7 +528,7 @@ $collections = [
'required' => false,
'default' => null,
'array' => false,
'filters' => []
'filters' => [],
],
[
'$id' => 'clientName',
@ -539,7 +539,7 @@ $collections = [
'required' => false,
'default' => null,
'array' => false,
'filters' => []
'filters' => [],
],
[
'$id' => 'clientVersion',
@ -550,7 +550,7 @@ $collections = [
'required' => false,
'default' => null,
'array' => false,
'filters' => []
'filters' => [],
],
[
'$id' => 'clientEngine',
@ -561,7 +561,7 @@ $collections = [
'required' => false,
'default' => null,
'array' => false,
'filters' => []
'filters' => [],
],
[
'$id' => 'clientEngineVersion',
@ -572,7 +572,7 @@ $collections = [
'required' => false,
'default' => null,
'array' => false,
'filters' => []
'filters' => [],
],
[
'$id' => 'deviceName',
@ -583,7 +583,7 @@ $collections = [
'required' => false,
'default' => null,
'array' => false,
'filters' => []
'filters' => [],
],
[
'$id' => 'deviceBrand',
@ -594,7 +594,7 @@ $collections = [
'required' => false,
'default' => null,
'array' => false,
'filters' => []
'filters' => [],
],
[
'$id' => 'deviceModel',
@ -605,7 +605,7 @@ $collections = [
'required' => false,
'default' => null,
'array' => false,
'filters' => []
'filters' => [],
],
],
'indexes' => [
@ -615,7 +615,7 @@ $collections = [
'attributes' => ['provider', 'providerUid'],
'lengths' => [100, 100],
'orders' => [Database::ORDER_ASC, Database::ORDER_ASC],
]
],
],
],
@ -665,7 +665,7 @@ $collections = [
'attributes' => ['name'],
'lengths' => [1024],
'orders' => [Database::ORDER_ASC],
]
],
],
],
@ -773,10 +773,10 @@ $collections = [
'attributes' => ['userId'],
'lengths' => [Database::LENGTH_KEY],
'orders' => [Database::ORDER_ASC],
]
],
],
],
'files' => [
'$collection' => Database::COLLECTIONS,
'$id' => 'files',
@ -952,10 +952,10 @@ $collections = [
'attributes' => ['name'],
'lengths' => [1024],
'orders' => [Database::ORDER_ASC],
]
],
],
],
'functions' => [
'$collection' => Database::COLLECTIONS,
'$id' => 'functions',
@ -1113,10 +1113,10 @@ $collections = [
'attributes' => ['name'],
'lengths' => [1024],
'orders' => [Database::ORDER_ASC],
]
],
],
],
'tags' => [
'$collection' => Database::COLLECTIONS,
'$id' => 'tags',
@ -1186,7 +1186,7 @@ $collections = [
'attributes' => ['functionId'],
'lengths' => [Database::LENGTH_KEY],
'orders' => [Database::ORDER_ASC],
]
],
],
],
@ -1303,10 +1303,10 @@ $collections = [
'attributes' => ['functionId'],
'lengths' => [Database::LENGTH_KEY],
'orders' => [Database::ORDER_ASC],
]
],
],
],
'certificates' => [
'$collection' => Database::COLLECTIONS,
'$id' => 'certificates',
@ -1403,7 +1403,7 @@ foreach ($providers as $index => $provider) {
}
$collections['projects']['attributes'][] = [
'$id' => 'usersOauth2'.\ucfirst($index).'Appid',
'$id' => 'usersOauth2' . \ucfirst($index) . 'Appid',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16384,
@ -1415,7 +1415,7 @@ foreach ($providers as $index => $provider) {
];
$collections['projects']['attributes'][] = [
'$id' => 'usersOauth2'.\ucfirst($index).'Secret',
'$id' => 'usersOauth2' . \ucfirst($index) . 'Secret',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16384,
@ -1441,4 +1441,4 @@ foreach ($auth as $index => $method) {
];
}
return $collections;
return $collections;

View file

@ -152,7 +152,7 @@ return [
'name' => 'Console',
'enabled' => false,
'beta' => false,
'languages' => [ // TODO change key to 'sdks'
'languages' => [
[
'key' => 'web',
'name' => 'Console',
@ -179,7 +179,7 @@ return [
'description' => 'Libraries for integrating with Appwrite to build server side integrations. Read the [getting started for server](/docs/getting-started-for-server) tutorial to start building your first server integration.',
'enabled' => true,
'beta' => false,
'languages' => [ // TODO change key to 'sdks'
'languages' => [
[
'key' => 'nodejs',
'name' => 'Node.js',

View file

@ -40,8 +40,6 @@ $admins = [
'platforms.write',
'keys.read',
'keys.write',
'tasks.read',
'tasks.write',
'webhooks.read',
'webhooks.write',
'locale.read',

View file

@ -8,17 +8,23 @@ return [
'controller' => 'web/home.php',
'sdk' => false,
'docs' => false,
'docsUrl' => '',
'tests' => false,
'optional' => false,
'icon' => '',
],
'console/' => [
'console' => [
'key' => 'console',
'name' => 'Console',
'controller' => 'web/console.php',
'sdk' => false,
'docs' => false,
'docsUrl' => '',
'tests' => false,
'optional' => false,
'icon' => '',
],
'v1/account' => [
'account' => [
'key' => 'account',
'name' => 'Account',
'subtitle' => 'The Account service allows you to authenticate and manage a user account.',
@ -26,9 +32,12 @@ return [
'controller' => 'api/account.php',
'sdk' => true,
'docs' => true,
'docsUrl' => 'https://appwrite.io/docs/client/account',
'tests' => false,
'optional' => true,
'icon' => '/images/services/account.png',
],
'v1/avatars' => [
'avatars' => [
'key' => 'avatars',
'name' => 'Avatars',
'subtitle'=> 'The Avatars service aims to help you complete everyday tasks related to your app image, icons, and avatars.',
@ -36,9 +45,12 @@ return [
'controller' => 'api/avatars.php',
'sdk' => true,
'docs' => true,
'docsUrl' => 'https://appwrite.io/docs/client/avatars',
'tests' => false,
'optional' => true,
'icon' => '/images/services/avatars.png',
],
'v1/database' => [
'database' => [
'key' => 'database',
'name' => 'Database',
'subtitle' => 'The Database service allows you to create structured collections of documents, query and filter lists of documents',
@ -46,9 +58,12 @@ return [
'controller' => 'api/database.php',
'sdk' => true,
'docs' => true,
'docsUrl' => 'https://appwrite.io/docs/client/database',
'tests' => false,
'optional' => true,
'icon' => '/images/services/database.png',
],
'v1/locale' => [
'locale' => [
'key' => 'locale',
'name' => 'Locale',
'subtitle' => 'The Locale service allows you to customize your app based on your users\' location.',
@ -56,9 +71,12 @@ return [
'controller' => 'api/locale.php',
'sdk' => true,
'docs' => true,
'docsUrl' => 'https://appwrite.io/docs/client/locale',
'tests' => false,
'optional' => true,
'icon' => '/images/services/locale.png',
],
'v1/health' => [
'health' => [
'key' => 'health',
'name' => 'Health',
'subtitle' => 'The Health service allows you to both validate and monitor your Appwrite server\'s health.',
@ -66,18 +84,24 @@ return [
'controller' => 'api/health.php',
'sdk' => true,
'docs' => true,
'docsUrl' => 'https://appwrite.io/docs/server/health',
'tests' => false,
'optional' => true,
'icon' => '/images/services/health.png',
],
'v1/projects' => [
'projects' => [
'key' => 'projects',
'name' => 'Projects',
'subtitle' => 'The Project service allows you to manage all the projects in your Appwrite server.',
'controller' => 'api/projects.php',
'sdk' => true,
'docs' => true,
'docsUrl' => '',
'tests' => false,
'optional' => false,
'icon' => '',
],
'v1/storage' => [
'storage' => [
'key' => 'storage',
'name' => 'Storage',
'subtitle' => 'The Storage service allows you to manage your project files.',
@ -85,9 +109,12 @@ return [
'controller' => 'api/storage.php',
'sdk' => true,
'docs' => true,
'docsUrl' => 'https://appwrite.io/docs/client/storage',
'tests' => false,
'optional' => true,
'icon' => '/images/services/storage.png',
],
'v1/teams' => [
'teams' => [
'key' => 'teams',
'name' => 'Teams',
'subtitle' => 'The Teams service allows you to group users of your project and to enable them to share read and write access to your project resources',
@ -95,9 +122,12 @@ return [
'controller' => 'api/teams.php',
'sdk' => true,
'docs' => true,
'docsUrl' => 'https://appwrite.io/docs/client/teams',
'tests' => false,
'optional' => true,
'icon' => '/images/services/teams.png',
],
'v1/users' => [
'users' => [
'key' => 'users',
'name' => 'Users',
'subtitle' => 'The Users service allows you to manage your project users.',
@ -105,9 +135,12 @@ return [
'controller' => 'api/users.php',
'sdk' => true,
'docs' => true,
'docsUrl' => 'https://appwrite.io/docs/server/users',
'tests' => false,
'optional' => true,
'icon' => '/images/services/users.png',
],
'v1/functions' => [
'functions' => [
'key' => 'functions',
'name' => 'Functions',
'subtitle' => 'The Functions Service allows you view, create and manage your Cloud Functions.',
@ -115,9 +148,12 @@ return [
'controller' => 'api/functions.php',
'sdk' => true,
'docs' => true,
'docsUrl' => 'https://appwrite.io/docs/functions',
'tests' => false,
'optional' => true,
'icon' => '/images/services/functions.png',
],
'v1/mock' => [
'mock' => [
'key' => 'mock',
'name' => 'Mock',
'subtitle' => '',
@ -125,9 +161,12 @@ return [
'controller' => 'mock.php',
'sdk' => false,
'docs' => false,
'docsUrl' => '',
'tests' => true,
'optional' => false,
'icon' => '',
],
'v1/graphql' => [
'graphql' => [
'key' => 'graphql',
'name' => 'GraphQL',
'subtitle' => 'Appwrite\'s GraphQL Endpoint',
@ -135,6 +174,9 @@ return [
'controller' => 'api/graphql.php',
'sdk' => false,
'docs' => false,
'tests' => false,
'docsUrl' => '',
'tests' => true,
'optional' => false,
'icon' => '',
],
];

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

@ -1156,8 +1156,8 @@ App::delete('/v1/account')
$protocol = $request->getProtocol();
$user = $dbForInternal->updateDocument('users', $user->getId(), $user->setAttribute('status', false));
//TODO delete all tokens or only current session?
//TODO delete all user data according to GDPR. Make sure everything is backed up and backups are deleted later
// TODO delete all tokens or only current session?
// TODO delete all user data according to GDPR. Make sure everything is backed up and backups are deleted later
/*
* Data to delete
* * Tokens
@ -1550,7 +1550,7 @@ App::post('/v1/account/verification')
->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
->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'])
->inject('request')
->inject('response')
->inject('project')

View file

@ -29,8 +29,8 @@ App::post('/v1/database/collections')
->groups(['api', 'database'])
->label('event', 'database.collections.create')
->label('scope', 'collections.write')
->label('sdk.namespace', 'database')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'database')
->label('sdk.method', 'createCollection')
->label('sdk.description', '/docs/references/database/create-collection.md')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
@ -76,8 +76,8 @@ App::get('/v1/database/collections')
->desc('List Collections')
->groups(['api', 'database'])
->label('scope', 'collections.read')
->label('sdk.namespace', 'database')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'database')
->label('sdk.method', 'listCollections')
->label('sdk.description', '/docs/references/database/list-collections.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -105,8 +105,8 @@ App::get('/v1/database/collections/:collectionId')
->desc('Get Collection')
->groups(['api', 'database'])
->label('scope', 'collections.read')
->label('sdk.namespace', 'database')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'database')
->label('sdk.method', 'getCollection')
->label('sdk.description', '/docs/references/database/get-collection.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -133,8 +133,8 @@ App::put('/v1/database/collections/:collectionId')
->groups(['api', 'database'])
->label('scope', 'collections.write')
->label('event', 'database.collections.update')
->label('sdk.namespace', 'database')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'database')
->label('sdk.method', 'updateCollection')
->label('sdk.description', '/docs/references/database/update-collection.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -187,8 +187,8 @@ App::delete('/v1/database/collections/:collectionId')
->groups(['api', 'database'])
->label('scope', 'collections.write')
->label('event', 'database.collections.delete')
->label('sdk.namespace', 'database')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'database')
->label('sdk.method', 'deleteCollection')
->label('sdk.description', '/docs/references/database/delete-collection.md')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
@ -231,8 +231,8 @@ App::post('/v1/database/collections/:collectionId/attributes')
->groups(['api', 'database'])
->label('event', 'database.attributes.create')
->label('scope', 'attributes.write')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'database')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.method', 'createAttribute')
->label('sdk.description', '/docs/references/database/create-attribute.md')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
@ -305,8 +305,8 @@ App::get('/v1/database/collections/:collectionId/attributes')
->desc('List Attributes')
->groups(['api', 'database'])
->label('scope', 'attributes.read')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'database')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.method', 'listAttributes')
->label('sdk.description', '/docs/references/database/list-attributes.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -343,8 +343,8 @@ App::get('/v1/database/collections/:collectionId/attributes/:attributeId')
->desc('Get Attribute')
->groups(['api', 'database'])
->label('scope', 'attributes.read')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'database')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.method', 'getAttribute')
->label('sdk.description', '/docs/references/database/get-attribute.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -385,8 +385,8 @@ App::delete('/v1/database/collections/:collectionId/attributes/:attributeId')
->groups(['api', 'database'])
->label('scope', 'attributes.write')
->label('event', 'database.attributes.delete')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'database')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.method', 'deleteAttribute')
->label('sdk.description', '/docs/references/database/delete-attribute.md')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
@ -447,8 +447,8 @@ App::post('/v1/database/collections/:collectionId/indexes')
->groups(['api', 'database'])
->label('event', 'database.indexes.create')
->label('scope', 'indexes.write')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'database')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.method', 'createIndex')
->label('sdk.description', '/docs/references/database/create-index.md')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
@ -536,8 +536,8 @@ App::get('/v1/database/collections/:collectionId/indexes')
->desc('List Indexes')
->groups(['api', 'database'])
->label('scope', 'indexes.read')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'database')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.method', 'listIndexes')
->label('sdk.description', '/docs/references/database/list-indexes.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -574,8 +574,8 @@ App::get('/v1/database/collections/:collectionId/indexes/:indexId')
->desc('Get Index')
->groups(['api', 'database'])
->label('scope', 'indexes.read')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'database')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.method', 'getIndex')
->label('sdk.description', '/docs/references/database/get-index.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -616,8 +616,8 @@ App::delete('/v1/database/collections/:collectionId/indexes/:indexId')
->groups(['api', 'database'])
->label('scope', 'indexes.write')
->label('event', 'database.indexes.delete')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'database')
->label('sdk.platform', [APP_PLATFORM_SERVER])
->label('sdk.method', 'deleteIndex')
->label('sdk.description', '/docs/references/database/delete-index.md')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
@ -678,8 +678,8 @@ App::post('/v1/database/collections/:collectionId/documents')
->groups(['api', 'database'])
->label('event', 'database.documents.create')
->label('scope', 'documents.write')
->label('sdk.namespace', 'database')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'database')
->label('sdk.method', 'createDocument')
->label('sdk.description', '/docs/references/database/create-document.md')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
@ -741,8 +741,8 @@ App::get('/v1/database/collections/:collectionId/documents')
->desc('List Documents')
->groups(['api', 'database'])
->label('scope', 'documents.read')
->label('sdk.namespace', 'database')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'database')
->label('sdk.method', 'listDocuments')
->label('sdk.description', '/docs/references/database/list-documents.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -795,8 +795,8 @@ App::get('/v1/database/collections/:collectionId/documents/:documentId')
->desc('Get Document')
->groups(['api', 'database'])
->label('scope', 'documents.read')
->label('sdk.namespace', 'database')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'database')
->label('sdk.method', 'getDocument')
->label('sdk.description', '/docs/references/database/get-document.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -830,8 +830,8 @@ App::patch('/v1/database/collections/:collectionId/documents/:documentId')
->groups(['api', 'database'])
->label('event', 'database.documents.update')
->label('scope', 'documents.write')
->label('sdk.namespace', 'database')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'database')
->label('sdk.method', 'updateDocument')
->label('sdk.description', '/docs/references/database/update-document.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
@ -901,8 +901,8 @@ App::delete('/v1/database/collections/:collectionId/documents/:documentId')
->groups(['api', 'database'])
->label('scope', 'documents.write')
->label('event', 'database.documents.delete')
->label('sdk.namespace', 'database')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'database')
->label('sdk.method', 'deleteDocument')
->label('sdk.description', '/docs/references/database/delete-document.md')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)

View file

@ -133,21 +133,6 @@ App::get('/v1/health/queue/webhooks')
$response->json(['size' => Resque::size(Event::WEBHOOK_QUEUE_NAME)]);
}, ['response']);
App::get('/v1/health/queue/tasks')
->desc('Get Tasks Queue')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'health')
->label('sdk.method', 'getQueueTasks')
->label('sdk.description', '/docs/references/health/get-queue-tasks.md')
->inject('response')
->action(function ($response) {
/** @var Appwrite\Utopia\Response $response */
$response->json(['size' => Resque::size(Event::TASK_QUEUE_NAME)]);
}, ['response']);
App::get('/v1/health/queue/logs')
->desc('Get Logs Queue')
->groups(['api', 'health'])

View file

@ -24,6 +24,14 @@ use Utopia\Validator\WhiteList;
use Utopia\Audit\Audit;
use Utopia\Abuse\Adapters\TimeLimit;
App::init(function ($project) {
/** @var Utopia\Database\Document $project */
if($project->getId() !== 'console') {
throw new Exception('Access to this API is forbidden.', 401);
}
}, ['project'], 'projects');
App::post('/v1/projects')
->desc('Create Project')
->groups(['api', 'projects'])
@ -81,10 +89,10 @@ App::post('/v1/projects')
'legalCity' => $legalCity,
'legalAddress' => $legalAddress,
'legalTaxId' => $legalTaxId,
'services' => new stdClass(),
'platforms' => [],
'webhooks' => [],
'keys' => [],
'tasks' => [],
'domains' => [],
'usersAuthEmailPassword' => true,
'usersAuthAnonymous' => true,
@ -336,9 +344,6 @@ App::get('/v1/projects/:projectId/usage')
$documents[] = ['name' => $collection['name'], 'total' => $projectDB->getSum()];
}
// Tasks
$tasksTotal = \count($project->getAttribute('tasks', []));
$response->json([
'range' => $range,
'requests' => [
@ -373,10 +378,6 @@ App::get('/v1/projects/:projectId/usage')
'data' => [],
'total' => $usersTotal,
],
'tasks' => [
'data' => [],
'total' => $tasksTotal,
],
'storage' => [
'total' => $projectDB->getCount(
[
@ -447,6 +448,39 @@ App::patch('/v1/projects/:projectId')
$response->dynamic($project, Response::MODEL_PROJECT);
});
App::patch('/v1/projects/:projectId/service')
->desc('Update service status')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateServiceStatus')
->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('service', '', new WhiteList(array_keys(array_filter(Config::getParam('services'), function($element) {return $element['optional'];})), true), 'Service name.')
->param('status', null, new Boolean(), 'Service status.')
->inject('response')
->inject('dbForConsole')
->action(function ($projectId, $service, $status, $response, $dbForConsole) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForConsole */
$project = $dbForConsole->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception('Project not found', 404);
}
$services = $project->getAttribute('services', []);
$services[$service] = $status;
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('services', $services));
$response->dynamic($project, Response::MODEL_PROJECT);
});
App::patch('/v1/projects/:projectId/oauth2')
->desc('Update Project OAuth2')
->groups(['api', 'projects'])
@ -972,239 +1006,6 @@ App::delete('/v1/projects/:projectId/keys/:keyId')
$response->noContent();
});
// Tasks
App::post('/v1/projects/:projectId/tasks')
->desc('Create Task')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->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('taskId', '', new CustomId(), 'Unique Id. Choose your own unique ID or pass the string `unique()` to auto generate it. Valid chars are a-z, A-Z, 0-9, and underscore. Can\'t start with a leading underscore. Max length is 36 chars.')
->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.')
->param('schedule', null, new Cron(), 'Task schedule CRON syntax.')
->param('security', false, new Boolean(true), 'Certificate verification, false for disabled or true for enabled.')
->param('httpMethod', '', new WhiteList(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS', 'TRACE', 'CONNECT'], true), 'Task HTTP method.')
->param('httpUrl', '', new URL(), 'Task HTTP URL')
->param('httpHeaders', null, new ArrayList(new Text(256)), 'Task HTTP headers list.', true)
->param('httpUser', '', new Text(256), 'Task HTTP user. Max length: 256 chars.', true)
->param('httpPass', '', new Text(256), 'Task HTTP password. Max length: 256 chars.', true)
->inject('response')
->inject('dbForConsole')
->action(function ($taskId, $projectId, $name, $status, $schedule, $security, $httpMethod, $httpUrl, $httpHeaders, $httpUser, $httpPass, $response, $dbForConsole) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForConsole */
$project = $dbForConsole->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception('Project not found', 404);
}
$cron = new CronExpression($schedule);
$next = ($status == 'play') ? $cron->getNextRunDate()->format('U') : null;
$security = ($security === '1' || $security === 'true' || $security === 1 || $security === true);
$task = new Document([
'$id' => $taskId == 'unique()' ? $dbForConsole->getId() : $taskId,
'projectId' => $project->getId(),
'name' => $name,
'status' => $status,
'schedule' => $schedule,
'updated' => \time(),
'previous' => null,
'next' => $next,
'security' => $security,
'httpMethod' => $httpMethod,
'httpUrl' => $httpUrl,
'httpHeaders' => $httpHeaders,
'httpUser' => $httpUser,
'httpPass' => $httpPass,
'log' => '{}',
'failures' => 0,
]);
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project
->setAttribute('tasks', $task, Document::SET_TYPE_APPEND)
);
if ($next) {
ResqueScheduler::enqueueAt($next, 'v1-tasks', 'TasksV1', $task->getArrayCopy());
}
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic($task, Response::MODEL_TASK);
});
App::get('/v1/projects/:projectId/tasks')
->desc('List Tasks')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->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.')
->inject('response')
->inject('dbForConsole')
->action(function ($projectId, $response, $dbForConsole) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForConsole */
$project = $dbForConsole->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception('Project not found', 404);
}
$tasks = $project->getAttribute('tasks', []);
$response->dynamic(new Document([
'tasks' => $tasks,
'sum' => count($tasks),
]), Response::MODEL_TASK_LIST);
});
App::get('/v1/projects/:projectId/tasks/:taskId')
->desc('Get Task')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->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.')
->inject('response')
->inject('dbForConsole')
->action(function ($projectId, $taskId, $response, $dbForConsole) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForConsole */
$project = $dbForConsole->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception('Project not found', 404);
}
$task = $project->find('$id', $taskId, 'tasks');
if (empty($task) || !$task instanceof Document) {
throw new Exception('Task not found', 404);
}
$response->dynamic($task, Response::MODEL_TASK);
});
App::put('/v1/projects/:projectId/tasks/:taskId')
->desc('Update Task')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->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.')
->param('status', null, new WhiteList(['play', 'pause'], true), 'Task status.')
->param('schedule', null, new Cron(), 'Task schedule CRON syntax.')
->param('security', false, new Boolean(true), 'Certificate verification, false for disabled or true for enabled.')
->param('httpMethod', '', new WhiteList(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS', 'TRACE', 'CONNECT'], true), 'Task HTTP method.')
->param('httpUrl', '', new URL(), 'Task HTTP URL.')
->param('httpHeaders', null, new ArrayList(new Text(256)), 'Task HTTP headers list.', true)
->param('httpUser', '', new Text(256), 'Task HTTP user. Max length: 256 chars.', true)
->param('httpPass', '', new Text(256), 'Task HTTP password. Max length: 256 chars.', true)
->inject('response')
->inject('dbForConsole')
->action(function ($projectId, $taskId, $name, $status, $schedule, $security, $httpMethod, $httpUrl, $httpHeaders, $httpUser, $httpPass, $response, $dbForConsole) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForConsole */
$project = $dbForConsole->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception('Project not found', 404);
}
$task = $project->find('$id', $taskId, 'tasks');
if (empty($task) || !$task instanceof Document) {
throw new Exception('Task not found', 404);
}
$cron = new CronExpression($schedule);
$next = ($status == 'play') ? $cron->getNextRunDate()->format('U') : null;
$security = ($security === '1' || $security === 'true' || $security === 1 || $security === true);
$project->findAndReplace('$id', $task->getId(), $task
->setAttribute('name', $name)
->setAttribute('status', $status)
->setAttribute('schedule', $schedule)
->setAttribute('updated', \time())
->setAttribute('next', $next)
->setAttribute('security', $security)
->setAttribute('httpMethod', $httpMethod)
->setAttribute('httpUrl', $httpUrl)
->setAttribute('httpHeaders', $httpHeaders)
->setAttribute('httpUser', $httpUser)
->setAttribute('httpPass', $httpPass)
, 'tasks');
$dbForConsole->updateDocument('projects', $project->getId(), $project);
if ($next) {
ResqueScheduler::enqueueAt($next, 'v1-tasks', 'TasksV1', $task->getArrayCopy());
}
$response->dynamic($task, Response::MODEL_TASK);
});
App::delete('/v1/projects/:projectId/tasks/:taskId')
->desc('Delete Task')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'deleteTask')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.model', Response::MODEL_NONE)
->param('projectId', null, new UID(), 'Project unique ID.')
->param('taskId', null, new UID(), 'Task unique ID.')
->inject('response')
->inject('dbForConsole')
->action(function ($projectId, $taskId, $response, $dbForConsole) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForConsole */
$project = $dbForConsole->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception('Project not found', 404);
}
if (!$project->findAndRemove('$id', $taskId, 'tasks')) {
throw new Exception('Task not found', 404);
}
$dbForConsole->updateDocument('projects', $project->getId(), $project);
$response->noContent();
});
// Platforms
App::post('/v1/projects/:projectId/platforms')

View file

@ -249,7 +249,7 @@ App::post('/v1/teams/:teamId/memberships')
->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
->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'])
->inject('response')
->inject('project')
->inject('user')
@ -520,7 +520,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId')
$membership->setAttribute('roles', $roles);
$membership = $dbForInternal->updateDocument('memberships', $membership->getId(), $membership);
//TODO sync updated membership in the user $profile object using TYPE_REPLACE
// TODO sync updated membership in the user $profile object using TYPE_REPLACE
$audits
->setParam('userId', $user->getId())

View file

@ -5,7 +5,6 @@ use Appwrite\Auth\Validator\Password;
use Appwrite\Utopia\Response;
use Utopia\App;
use Utopia\Exception;
use Utopia\Validator;
use Utopia\Validator\Assoc;
use Utopia\Validator\WhiteList;
use Appwrite\Network\Validator\Email;
@ -449,7 +448,6 @@ App::delete('/v1/users/:userId/sessions/:sessionId')
}
}
// TODO : Response filter implementation
$response->noContent();
});
@ -540,6 +538,5 @@ App::delete('/v1/users/:userId')
->setParam('eventData', $response->output($user, Response::MODEL_USER))
;
// TODO : Response filter implementation
$response->noContent();
});

View file

@ -256,7 +256,14 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons
}
}, $user->getAttribute('memberships', []));
// TDOO Check if user is root
$service = $route->getLabel('sdk.namespace','');
if(!empty($service)) {
if(array_key_exists($service, $project->getAttribute('services',[]))
&& !$project->getAttribute('services',[])[$service]
&& !Auth::isPrivilegedUser(Authorization::$roles)) {
throw new Exception('Service is disabled', 503);
}
}
if (!\in_array($scope, $scopes)) {
if ($project->isEmpty()) { // Check if permission is denied because project is missing
@ -333,6 +340,7 @@ App::error(function ($error, $utopia, $request, $response, $layout, $project) {
case 412: // Error allowed publicly
case 429: // Error allowed publicly
case 501: // Error allowed publicly
case 503: // Error allowed publicly
$code = $error->getCode();
$message = $error->getMessage();
break;

View file

@ -44,7 +44,7 @@ App::init(function ($utopia, $request, $response, $project, $user, $register, $e
->setParam('{url}', $request->getHostname().$route->getURL())
;
//TODO make sure we get array here
// TODO make sure we get array here
foreach ($request->getParams() as $key => $value) { // Set request params as potential abuse keys
if(!empty($value)) {
@ -115,7 +115,6 @@ App::init(function ($utopia, $request, $response, $project, $user, $register, $e
;
}, ['utopia', 'request', 'response', 'project', 'user', 'register', 'events', 'audits', 'usage', 'deletes', 'database', 'dbForInternal'], 'api');
App::init(function ($utopia, $request, $response, $project, $user) {
/** @var Utopia\App $utopia */
/** @var Utopia\Swoole\Request $request */
@ -217,7 +216,7 @@ App::shutdown(function ($utopia, $request, $response, $project, $events, $audits
$route = $utopia->match($request);
if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled'
&& $project->getId()
&& $mode !== APP_MODE_ADMIN //TODO: add check to make sure user is admin
&& $mode !== APP_MODE_ADMIN // TODO: add check to make sure user is admin
&& !empty($route->getLabel('sdk.namespace', null))) { // Don't calculate console usage on admin mode
$usage

View file

@ -142,6 +142,7 @@ App::get('/console/settings')
$page = new View(__DIR__.'/../../views/console/settings/index.phtml');
$page
->setParam('services', array_filter(Config::getParam('services'), function($element) {return $element['optional'];}))
->setParam('customDomainsEnabled', ($target->isKnown() && !$target->isTest()))
->setParam('customDomainsTarget', $target->get())
->setParam('smtpEnabled', (!empty(App::getEnv('_APP_SMTP_HOST'))))
@ -189,21 +190,6 @@ App::get('/console/keys')
->setParam('body', $page);
});
App::get('/console/tasks')
->groups(['web', 'console'])
->label('permission', 'public')
->label('scope', 'console')
->inject('layout')
->action(function ($layout) {
/** @var Utopia\View $layout */
$page = new View(__DIR__.'/../../views/console/tasks/index.phtml');
$layout
->setParam('title', APP_NAME.' - Tasks')
->setParam('body', $page);
});
App::get('/console/database')
->groups(['web', 'console'])
->label('permission', 'public')

View file

@ -395,7 +395,7 @@ App::get('/specs/:format')
}
}
foreach (Config::getParam('services', []) as $key => $service) {
foreach (Config::getParam('services', []) as $service) {
if(!isset($service['docs']) // Skip service if not part of the public API
|| !isset($service['sdk'])
|| !$service['docs']

View file

@ -55,7 +55,7 @@ const APP_PAGING_LIMIT = 12;
const APP_LIMIT_COUNT = 5000;
const APP_LIMIT_USERS = 10000;
const APP_CACHE_BUSTER = 150;
const APP_VERSION_STABLE = '0.9.2';
const APP_VERSION_STABLE = '0.10.0';
const APP_STORAGE_UPLOADS = '/storage/uploads';
const APP_STORAGE_FUNCTIONS = '/storage/functions';
const APP_STORAGE_CACHE = '/storage/cache';

View file

@ -29,7 +29,7 @@ $cli
$production = ($git) ? (Console::confirm('Type "Appwrite" to push code to production git repos') == 'Appwrite') : false;
$message = ($git) ? Console::confirm('Please enter your commit message:') : '';
if(!in_array($version, ['0.6.x', '0.7.x', '0.8.x', '0.9.x'])) {
if(!in_array($version, ['0.6.x', '0.7.x', '0.8.x', '0.9.x', '0.10.x'])) {
throw new Exception('Unknown version given');
}

View file

@ -142,16 +142,6 @@
<b class="subtitle">MANAGE</b>
<ul class="links">
<li>
<a data-ls-attrs="href=/console/tasks?project={{router.params.project}}"
data-analytics
data-analytics-event="click"
data-analytics-category="console/navigation"
data-analytics-label="Tasks Link">
<i class="icon-clock"></i>
Tasks
</a>
</li>
<li>
<a data-ls-attrs="href=/console/webhooks?project={{router.params.project}}"
data-analytics

View file

@ -18,7 +18,6 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled',true);
<li class="pull-start margin-end margin-bottom-small"><a data-ls-attrs="href=/console/settings?project={{router.params.project}}" class="link-animation-enabled"><i class="icon-cog"></i> &nbsp;Settings</a> &nbsp;&nbsp;</li>
<li class="pull-start margin-end margin-bottom-small"><a data-ls-attrs="href=/console/keys?project={{router.params.project}}" class="link-animation-enabled"><i class="icon-key-inv"></i> &nbsp;API Keys</a> &nbsp;&nbsp;</li>
<li class="pull-start margin-end margin-bottom-small"><a data-ls-attrs="href=/console/webhooks?project={{router.params.project}}" class="link-animation-enabled"><i class="icon-link"></i> &nbsp;Webhooks</a> &nbsp;&nbsp;</li>
<li class="pull-start margin-end margin-bottom-small"><a data-ls-attrs="href=/console/tasks?project={{router.params.project}}" class="link-animation-enabled"><i class="icon-clock"></i> &nbsp;Tasks</a> &nbsp;&nbsp;</li>
</ul>
<div class="margin-bottom phones-only">&nbsp;</div>
@ -79,6 +78,7 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled',true);
<div
data-service="projects.getUsage"
data-event="load"
data-scope="console"
data-name="usage"
data-param-project-id="{{router.params.project}}"
data-param-range="30d">
@ -102,12 +102,6 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled',true);
<span data-ls-bind="{{usage.network.total|humanFileUnit}}" class="text-size-small unit"></span>
</div>
<div class="metric margin-bottom-small">Bandwidth</div>
<div class="margin-top-large value small">
<b class="text-size-small sum small" data-ls-bind="{{usage.functions.total|statsTotal}}" data-default="0"></b>
<br />
<b>Func. Executions</b>
</div>
</div>
</div>
</div>
@ -131,8 +125,8 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled',true);
<div class="margin-top-small"><b class="text-size-small unit">Users</b></div>
</div>
<div class="col span-3">
<div class="value"><span class="sum" data-ls-bind="{{usage.tasks.total}}" data-default="0">0</span></div>
<div class="margin-top-small"><b class="text-size-small unit">Tasks</b></div>
<div class="value"><span class="sum" data-ls-bind="{{usage.functions.total|statsTotal}}" data-default="0">0</span></div>
<div class="margin-top-small"><b class="text-size-small unit">Func. Executions</b></div>
</div>
</div>
</div>

View file

@ -1,5 +1,5 @@
<?php
$services = $this->getParam('services', []);
$customDomainsEnabled = $this->getParam('customDomainsEnabled', false);
$customDomainsTarget = $this->getParam('customDomainsTarget', false);
$smtpEnabled = $this->getParam('smtpEnabled', false);
@ -18,7 +18,7 @@ $smtpEnabled = $this->getParam('smtpEnabled', false);
data-service="projects.get"
data-scope="console"
data-name="console-project"
data-event="load"
data-event="load,projects.update"
data-param-project-id="{{router.params.project}}"
data-success="trigger"
data-success-param-trigger-events="projects.get">
@ -193,6 +193,62 @@ $smtpEnabled = $this->getParam('smtpEnabled', false);
</div>
</form>
</li> -->
<li data-state="/console/settings/services?project={{router.params.project}}">
<h2>Services</h2>
<p class="text-fade margin-bottom">Choose services you wish to enable or disable.</p>
<ul class="tiles cell-3 margin-bottom-small">
<?php foreach($services as $index => $service):
$key = $service['key'] ?? '';
$name = $service['name'] ?? '';
$icon = $service['icon'] ?? '';
$docs = $service['docsUrl'] ?? '';
?>
<li class="">
<div class="box padding-small margin-bottom clear">
<div class="clear">
<form
data-analytics
data-analytics-activity
data-analytics-event="submit"
data-analytics-category="console"
data-analytics-label="Update Project service Status (<?php echo $this->escape($name); ?>)"
data-service="projects.updateServiceStatus"
data-scope="console"
data-event="change"
data-confirm="Are you sure you want to change the status of the <?php echo $this->escape($name); ?> service?"
data-param-project-id="{{router.params.project}}"
data-success="alert,trigger"
data-success-param-alert-text="Updated project service status successfully"
data-success-param-trigger-events="projects.update"
data-failure="alert"
data-failure-param-alert-text="Failed to update project service status settings"
data-failure-param-alert-classname="error">
<input name="service" id="<?php echo $this->escape($key); ?>" type="hidden" autocomplete="off" value="<?php echo $this->escape($key); ?>">
<input name="status" type="hidden" data-forms-switch data-ls-bind="{{console-project.serviceStatusFor<?php echo ucFirst($this->escape($key)); ?>}}" data-cast-to="boolean" class="pull-end" />
</form>
<img src="<?php echo $this->escape($icon); ?>?buster=<?php echo APP_CACHE_BUSTER; ?>" alt="" class="pull-start provider margin-end" />
<span class="text-size-small text-bold"><?php echo $this->escape($name); ?></span>
<?php if($docs): ?>
<p class="margin-bottom-no text-one-liner text-size-small">
<a href="<?php echo $this->escape($docs); ?>" target="_blank" rel="noopener">Docs<i class="icon-link-ext"></i></a>
</p>
<?php endif; ?>
</div>
<hr />
<div class="text-align-center text-size-small text-bold text-success" data-ls-if="!!({{console-project.serviceStatusFor<?php echo ucFirst($this->escape($key)); ?>}})">Enabled</div>
<div class="text-align-center text-size-small text-bold text-danger" data-ls-if="(!{{console-project.serviceStatusFor<?php echo ucFirst($this->escape($key)); ?>}})">Disabled</div>
</div>
</li>
<?php endforeach; ?>
</ul>
</li>
<li data-state="/console/settings/domains?project={{router.params.project}}">
<?php if(!$customDomainsEnabled): ?>

View file

@ -1,365 +0,0 @@
<div class="cover margin-bottom-large">
<h1 class="zone xl margin-bottom-large">
<a data-ls-attrs="href=/console/home?project={{router.params.project}}" class="back text-size-small link-return-animation--start"><i class="icon-left-open"></i> Home</a>
<br />
<span>Tasks</span>
</h1>
</div>
<div class="zone xl"
data-service="projects.listTasks"
data-scope="console"
data-event="load,projects.createTask,projects.updateTask,projects.deleteTask"
data-name="console-tasks"
data-param-project-id="{{router.params.project}}"
data-success="trigger"
data-success-param-trigger-events="projects.listTasks">
<div data-ls-if="0 === {{console-tasks.sum}} || undefined === {{console-tasks.sum}}" class="box margin-top margin-bottom">
<h3 class="margin-bottom-small text-bold">No Tasks Found</h3>
<p class="margin-bottom-no">You haven't created any tasks for your project yet.</p>
</div>
<div class="box y-scroll margin-bottom" data-ls-if="0 != {{console-tasks.sum}}">
<table class="full vertical">
<thead>
<tr>
<th>Name</th>
<th width="140">Status</th>
<th width="180">Schedule</th>
<th width="140"></th>
</tr>
</thead>
<tbody data-ls-loop="console-tasks.tasks" data-ls-as="task" class="list">
<tr>
<td>
<div class="margin-bottom-tiny text-one-liner">
<span data-ls-attrs="title={{task.name}} ({{task.failures}} errors)" data-ls-bind="{{task.name}}"></span>
<span data-ls-if="false === {{task.security}}">
&nbsp; <span class="text-danger">SSL/TLS Disabled</span>
</span>
<span data-ls-if="0 !== {{task.failures}}">
&nbsp; <span class="text-danger" data-ls-bind="({{task.failures}} errors)"></span>
</span>
</div>
<a data-ls-attrs="href={{task.httpUrl}}" data-ls-bind="{{task.httpUrl}}" target="_blank" class="text-one-liner text-size-small"></a>
</td>
<td data-title="" style="vertical-align: middle">
<span data-ls-if="'play' === {{task.status}}">
<span class="tag green"><i class="icon-play"></i> Running &nbsp;</span>
</span>
<span data-ls-if="'play' !== {{task.status}}">
<span class="tag red"><i class="icon-pause"></i> Paused &nbsp;</span>
</span>
</td>
<td data-title="" style="vertical-align: middle" class="text-size-small text-fade">
<span data-ls-bind="Next: {{task.next|dateTime}}"></span>
<br />
<span data-ls-if="undefined !== {{task.previous}} && {{task.previous}}">
<span data-ls-bind="Prev: {{task.previous|dateTime}}"></span>
<!-- <span data-ls-if="undefined !== {{task.delay}} && 59 < {{task.delay}}" class="text-danger margin-top-tiny">
<small data-ls-bind="({{task.delay|ms2hum}} Delay)"></small>
</span> -->
</span>
<small data-ls-if="undefined === {{task.previous}}" class="text-size-small">
None.
</small>
</td>
<td data-title="">
<div data-ui-modal class="modal box sticky-footer close" data-button-alias="none" data-open-event="task-update-{{task.$id}}">
<button type="button" class="close pull-end" data-ui-modal-close=""><i class="icon-cancel"></i></button>
<h1>Update Task</h1>
<form
data-analytics
data-analytics-activity
data-analytics-event="submit"
data-analytics-category="console"
data-analytics-label="Update Project Task"
data-service="projects.updateTask"
data-scope="console"
data-event="submit"
data-success="alert,trigger"
data-success-param-alert-text="Updated task successfully"
data-success-param-trigger-events="projects.updateTask"
data-failure="alert"
data-failure-param-alert-text="Failed to update task"
data-failure-param-alert-classname="error">
<input type="hidden" name="projectId" data-ls-bind="{{router.params.project}}" />
<input type="hidden" name="taskId" data-ls-bind="{{task.$id}}" />
<label data-ls-attrs="for=name-{{task.$id}}">Name</label>
<input type="text" class="full-width" data-ls-attrs="id=name-{{task.$id}}" name="name" required autocomplete="off" data-ls-bind="{{task.name}}" maxlength="128" />
<label data-ls-attrs="for=status-{{task.$id}}" class="margin-bottom">Status
<div class="margin-top-small">
<input name="status" type="radio" checked="checked" required data-ls-bind="{{task.status}}" value="play" /> &nbsp; <span>Play</span> &nbsp;
<input name="status" type="radio" required data-ls-bind="{{task.status}}" value="pause" /> &nbsp; <span>Pause</span> &nbsp;
</div>
</label>
<label data-ls-attrs="for=schedule-{{task.$id}}">Schedule (CRON Syntax)</label>
<input type="text" class="full-width" data-ls-attrs="id=schedule-{{task.$id}}" name="schedule" required autocomplete="off" data-ls-bind="{{task.schedule}}" placeholder="* * * * *" />
<div class="row responsive thin">
<div class="col span-4">
<label data-ls-attrs="for=httpMethod-{{task.$id}}">HTTP Method</label>
<select data-ls-attrs="id=httpMethod-{{task.$id}}" name="httpMethod" required data-ls-bind="{{task.httpMethod}}">
<option value="POST">POST</option>
<option value="GET">GET</option>
<option value="PUT">PUT</option>
<option value="PATCH">PATCH</option>
<option value="DELETE">DELETE</option>
<option value="CONNECT">CONNECT</option>
<option value="HEAD">HEAD</option>
<option value="TRACE">TRACE</option>
<option value="OPTIONS">OPTIONS</option>
</select>
</div>
<div class="col span-8">
<label data-ls-attrs="for=httpUrl-{{task.$id}}">HTTP URL</label>
<input type="url" class="full-width" data-ls-attrs="id=httpUrl-{{task.$id}}" name="httpUrl" required autocomplete="off" placeholder="https://example.com/callback" data-ls-bind="{{task.httpUrl}}" />
</div>
</div>
<div class="margin-bottom toggle" data-ls-ui-open data-button-aria="Advanced Options">
<i class="icon-plus pull-end margin-top-tiny"></i>
<i class="icon-minus pull-end margin-top-tiny"></i>
<h2 class="margin-bottom">
Advanced Options
<small class="text-size-small">(optional)</small>
</h2>
<label for="httpHeaders" class="text-bold">HTTP Headers</label>
<input type="hidden" id="httpHeadersInit" name="httpHeaders" data-cast-to="array-empty">
<div class="margin-bottom-small">
<div data-ls-loop="task.httpHeaders" data-ls-as="header" style="overflow: hidden">
<div class="margin-bottom-small">
<div data-forms-remove class="row thin">
<div class="col span-10">
<input type="hidden" name="httpHeaders" data-forms-headers data-ls-bind="{{header}}" data-cast-to="array" />
</div>
<div class="col span-2">
<button type="button" data-remove class="reverse danger round pull-end"><i class="icon-cancel"></i></button>
</div>
</div>
</div>
</div>
<div data-forms-clone="" data-label="Add Header" data-first="0">
<div class="">
<div data-forms-remove class="row thin margin-bottom-small">
<div class="col span-10">
<input type="hidden" name="httpHeaders" data-forms-headers data-cast-to="array" />
</div>
<div class="col span-2">
<button type="button" data-remove class="reverse danger round pull-end"><i class="icon-cancel"></i></button>
</div>
</div>
</div>
</div>
</div>
<label data-ls-attrs="for=security-{{task.$id}}" class="margin-bottom">
<div class="margin-bottom-small text-bold">SSL / TLS (Certificate verification)</div>
<input name="security" type="radio" required data-ls-bind="{{task.security}}" value="true" data-cast-to="boolean" /> &nbsp; <span>Enabled</span>
<input name="security" type="radio" required data-ls-bind="{{task.security}}" value="false" data-cast-to="boolean" /> &nbsp; <span>Disabled</span>
</label>
<p class="margin-bottom text-size-small text-fade"><span class="text-red">Warning</span>: Untrusted or self-signed certificates may not be secure.
<a href="https://en.wikipedia.org/wiki/Self-signed_certificate" target="_blank" rel="noopener">Learn more<i class="icon-link-ext"></i></a>
</p>
<label class="text-bold">HTTP Authentication <span class="tooltip" data-tooltip="Use to secure your endpoint from untrusted sources"><i class="icon-question"></i></span> &nbsp;<small>(optional)</small></label>
<div class="row responsive thin">
<div class="col span-6 margin-bottom">
<label data-ls-attrs="for=httpUser-{{task.$id}}">User</label>
<input type="text" class="full-width margin-bottom-no" data-ls-attrs="id=httpUser-{{task.$id}}" name="httpUser" autocomplete="off" data-ls-bind="{{task.httpUser}}" />
</div>
<div class="col span-6 margin-bottom">
<label data-ls-attrs="for=httpPass-{{task.$id}}">Password</label>
<input data-forms-show-secret type="password" class="full-width margin-bottom-no" data-ls-attrs="id=httpPass-{{task.$id}}" name="httpPass" autocomplete="off" data-ls-bind="{{task.httpPass}}" />
</div>
</div>
</div>
<footer>
<button type="submit">Update</button> &nbsp; <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
</footer>
</form>
</div>
<form
data-analytics
data-analytics-activity
data-analytics-event="submit"
data-analytics-category="console"
data-analytics-label="Delete Project Task"
data-service="projects.deleteTask"
data-scope="console"
data-event="task-delete-{{task.$id}}"
data-confirm="Are you sure you want to delete this task?"
data-success="alert,trigger"
data-success-param-alert-text="Deleted task successfully"
data-success-param-trigger-events="projects.deleteTask"
data-failure="alert"
data-failure-param-alert-text="Failed to delete task"
data-failure-param-alert-classname="error">
<input type="hidden" name="projectId" data-ls-bind="{{router.params.project}}" />
<input type="hidden" name="taskId" data-ls-bind="{{task.$id}}" />
</form>
<button class="pull-end margin-start round desktops-only" data-ls-ui-trigger="task-update-{{task.$id}}"><i class="icon-cog"></i></button>
<button class="pull-end reverse danger round desktops-only" data-ls-ui-trigger="task-delete-{{task.$id}}"><i class="icon-trash"></i></button>
<button class="link pull-start margin-end-small tablets-only phones-only" data-ls-ui-trigger="task-update-{{task.$id}}">Update</button>
<button class="link pull-start margin-end text-danger tablets-only phones-only" data-ls-ui-trigger="task-delete-{{task.$id}}">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
<div class="clear">
<div data-ui-modal class="modal box close sticky-footer" data-button-text="Add Task">
<button type="button" class="close pull-end" data-ui-modal-close=""><i class="icon-cancel"></i></button>
<h1>Add Task</h1>
<form
data-analytics
data-analytics-activity
data-analytics-event="submit"
data-analytics-category="console"
data-analytics-label="Create Project Task"
data-service="projects.createTask"
data-scope="console"
data-event="submit"
data-success="alert,trigger,reset"
data-success-param-alert-text="Created task successfully"
data-success-param-trigger-events="projects.createTask"
data-failure="alert"
data-failure-param-alert-text="Failed to create task"
data-failure-param-alert-classname="error">
<input type="hidden" name="projectId" data-ls-bind="{{router.params.project}}" />
<label for="name">Name</label>
<input type="text" class="full-width" id="name" name="name" required autocomplete="off" maxlength="128" />
<label for="taskId">Task ID</label>
<input
type="hidden"
data-custom-id
id-type="auto"
required
maxlength="36"
id="taskId"
name="taskId" />
<label data-ls-attrs="for=status" class="margin-bottom">Status
<div class="margin-top-small">
<input name="status" type="radio" value="play" checked="checked" required /> &nbsp; <span>Play</span> &nbsp;
<input name="status" type="radio" value="pause" required /> &nbsp; <span>Pause</span> &nbsp;
</div>
</label>
<label for="schedule">Schedule (CRON Syntax)</label>
<input type="text" class="full-width" id="schedule" name="schedule" required autocomplete="off" placeholder="* * * * *" />
<div class="row responsive thin">
<div class="col span-4">
<label for="httpMethod">HTTP Method</label>
<select id="httpMethod" name="httpMethod" required>
<option value="POST">POST</option>
<option value="GET">GET</option>
<option value="PUT">PUT</option>
<option value="PATCH">PATCH</option>
<option value="DELETE">DELETE</option>
<option value="CONNECT">CONNECT</option>
<option value="HEAD">HEAD</option>
<option value="TRACE">TRACE</option>
<option value="OPTIONS">OPTIONS</option>
</select>
</div>
<div class="col span-8">
<label for="httpUrl">HTTP URL</label>
<input type="url" class="full-width" id="httpUrl" name="httpUrl" required autocomplete="off" placeholder="https://example.com/callback" />
</div>
</div>
<div class="margin-bottom toggle" data-ls-ui-open data-button-aria="Advanced Options">
<i class="icon-plus pull-end margin-top-tiny"></i>
<i class="icon-minus pull-end margin-top-tiny"></i>
<h2 class="margin-bottom">
Advanced Options
<small class="text-size-small">(optional)</small>
</h2>
<label for="httpHeaders" class="text-bold">HTTP Headers</label>
<input type="hidden" id="httpHeadersInitAdd" name="httpHeaders" data-cast-to="array-empty">
<div class="margin-bottom-small">
<div data-forms-clone="" data-label="Add Header" data-first="0">
<div class="">
<div data-forms-remove class="row thin margin-bottom-small">
<div class="col span-10">
<input type="hidden" name="httpHeaders" data-forms-headers data-cast-to="array" />
</div>
<div class="col span-2">
<button type="button" data-remove class="reverse danger round pull-end"><i class="icon-cancel"></i></button>
</div>
</div>
</div>
</div>
</div>
<label for="secure" class="margin-bottom-small">
<div class="margin-bottom-small text-bold">SSL / TLS (Certificate verification)</div>
<input name="security" data-ls-attrs="id=secure-yes" type="radio" value="1" checked="checked" required /> &nbsp; <span>Enabled</span>
<input name="security" data-ls-attrs="id=secure-no" type="radio" value="0" required /> &nbsp; <span>Disabled</span>
</label>
<p class="margin-bottom text-size-small text-fade"><span class="text-red">Warning</span>: Untrusted or self-signed certificates may not be secure.
<a href="https://en.wikipedia.org/wiki/Self-signed_certificate" target="_blank" rel="noopener">Learn more<i class="icon-link-ext"></i></a>
</p>
<label class="text-bold">HTTP Authentication <span class="tooltip" data-tooltip="Use to secure your endpoint from untrusted sources"><i class="icon-question"></i></span> &nbsp;<small>(optional)</small></label>
<div class="row responsive thin">
<div class="col span-6 margin-bottom">
<label for="httpUser">User</label>
<input type="text" class="full-width margin-bottom-no" id="httpUser" name="httpUser" autocomplete="off" />
</div>
<div class="col span-6 margin-bottom">
<label for="httpPass">Password</label>
<input type="password" data-forms-show-secret class="full-width margin-bottom-no" id="httpPass" name="httpPass" autocomplete="off" />
</div>
</div>
</div>
<footer>
<button type="submit">Create</button> &nbsp; <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
</footer>
</form>
</div>
</div>
</div>

View file

@ -397,9 +397,9 @@ $auth = $this->getParam('auth', []);
</form>
<?php endif; ?>
<img src="<?php echo $this->escape($icon); ?>?buster=<?php echo APP_CACHE_BUSTER; ?>" alt="Email/Password Logo" class="pull-start provider margin-end" />
<img src="<?php echo $this->escape($icon); ?>?buster=<?php echo APP_CACHE_BUSTER; ?>" alt="<?php echo $this->escape($name); ?> Logo" class="pull-start provider margin-end" />
<span class="text-size-small"><?php echo $this->escape($name); ?><?php if(!$enabled): ?> <spann class="text-fade text-size-xs">soon</span><?php endif; ?></span>
<span class="text-size-small"><?php echo $this->escape($name); ?><?php if(!$enabled): ?> <span class="text-fade text-size-xs">soon</span><?php endif; ?></span>
<?php if($docs): ?>
<p class="margin-bottom-no text-one-liner text-size-small">

View file

@ -158,30 +158,6 @@ services:
- _APP_REDIS_USER
- _APP_REDIS_PASS
appwrite-worker-tasks:
image: <?php echo $organization; ?>/<?php echo $image; ?>:<?php echo $version."\n"; ?>
entrypoint: worker-tasks
container_name: appwrite-worker-tasks
restart: unless-stopped
networks:
- appwrite
depends_on:
- redis
- mariadb
environment:
- _APP_ENV
- _APP_OPENSSL_KEY_V1
- _APP_SYSTEM_SECURITY_EMAIL_ADDRESS
- _APP_REDIS_HOST
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
appwrite-worker-deletes:
image: <?php echo $organization; ?>/<?php echo $image; ?>:<?php echo $version."\n"; ?>
entrypoint: worker-deletes

View file

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

View file

@ -1,214 +0,0 @@
<?php
use Appwrite\Resque\Worker;
use Cron\CronExpression;
use Utopia\App;
use Utopia\Cache\Adapter\Redis;
use Utopia\Cache\Cache;
use Utopia\CLI\Console;
use Utopia\Database\Database;
use Utopia\Database\Adapter\MariaDB;
use Utopia\Database\Validator\Authorization;
require_once __DIR__.'/../workers.php';
Console::title('Tasks V1 Worker');
Console::success(APP_NAME.' tasks worker v1 has started');
class TasksV1 extends Worker
{
/**
* @var array
*/
public $args = [];
public function init(): void
{
}
public function run(): void
{
$projectId = $this->args['projectId'] ?? null;
$taskId = $this->args['$id'] ?? null;
$updated = $this->args['updated'] ?? null;
$next = $this->args['next'] ?? null;
$delay = \time() - $next;
$errors = [];
$timeout = 60 * 5; // 5 minutes
$errorLimit = 5;
$logLimit = 5;
$alert = '';
$dbForConsole = $this->getConsoleDB();
/*
* 1. Get Original Task
* 2. Check for updates
* If has updates skip task and don't reschedule
* If status not equal to play skip task
* 3. Check next run date, update task and add new job at the given date
* 4. Execute task (set optional timeout)
* 5. Update task response to log
* On success reset error count
* On failure add error count
* If error count bigger than allowed change status to pause
*/
if (empty($taskId)) {
throw new Exception('Missing task $id');
}
Authorization::disable();
$project = $dbForConsole->getDocument('projects', $projectId);
Authorization::reset();
// Find the task in the $project->getAttribute('tasks') array
$taskIndex = array_search($taskId, array_column($project->getAttributes()['tasks'], '$id'));
if ($taskIndex === false) {
throw new Exception('Task Not Found');
}
$task = $project->getAttribute('tasks')[$taskIndex];
if ($task->getAttribute('updated') !== $updated) { // Task have already been rescheduled by owner
return;
}
if ($task->getAttribute('status') !== 'play') { // Skip task and don't schedule again
return;
}
// Reschedule
$cron = new CronExpression($task->getAttribute('schedule'));
$next = (int) $cron->getNextRunDate()->format('U');
$headers = (\is_array($task->getAttribute('httpHeaders', []))) ? $task->getAttribute('httpHeaders', []) : [];
$task
->setAttribute('next', $next)
->setAttribute('previous', \time())
;
ResqueScheduler::enqueueAt($next, 'v1-tasks', 'TasksV1', $task->getArrayCopy()); // Async task rescheduale
$startTime = \microtime(true);
// Execute Task
$ch = \curl_init($task->getAttribute('httpUrl'));
\curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $task->getAttribute('httpMethod'));
\curl_setopt($ch, CURLOPT_POSTFIELDS, '');
\curl_setopt($ch, CURLOPT_HEADER, 0);
\curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
\curl_setopt($ch, CURLOPT_USERAGENT, \sprintf(APP_USERAGENT,
App::getEnv('_APP_VERSION', 'UNKNOWN'),
App::getEnv('_APP_SYSTEM_SECURITY_EMAIL_ADDRESS', APP_EMAIL_SECURITY)
));
\curl_setopt(
$ch,
CURLOPT_HTTPHEADER,
\array_merge($headers, [
'X-'.APP_NAME.'-Task-ID: '.$task->getAttribute('$id', ''),
'X-'.APP_NAME.'-Task-Name: '.$task->getAttribute('name', ''),
])
);
\curl_setopt($ch, CURLOPT_HEADER, true); // we want headers
\curl_setopt($ch, CURLOPT_NOBODY, true);
\curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
if (!$task->getAttribute('security', true)) {
\curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
\curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
}
$httpUser = $task->getAttribute('httpUser');
$httpPass = $task->getAttribute('httpPass');
if (!empty($httpUser) && !empty($httpPass)) {
\curl_setopt($ch, CURLOPT_USERPWD, "$httpUser:$httpPass");
\curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
}
$response = \curl_exec($ch);
if (false === $response) {
$errors[] = \curl_error($ch).'Failed to execute task';
}
$code = \curl_getinfo($ch, CURLINFO_HTTP_CODE);
$codeFamily = \mb_substr($code, 0, 1);
$headersSize = \curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$headers = \substr($response, 0, $headersSize);
$body = \substr($response, $headersSize);
\curl_close($ch);
$totalTime = \round(\microtime(true) - $startTime, 2);
switch ($codeFamily) {
case '2':
case '3':
break;
default:
$errors[] = 'Request failed with status code '.$code;
}
if (empty($errors)) {
$task->setAttribute('failures', 0);
$alert = 'Task "'.$task->getAttribute('name').'" Executed Successfully';
} else {
$task
->setAttribute('failures', $task->getAttribute('failures', 0) + 1)
->setAttribute('status', ($task->getAttribute('failures') >= $errorLimit) ? 'pause' : 'play')
;
$alert = 'Task "'.$task->getAttribute('name').'" failed to execute with the following errors: '.\implode("\n", $errors);
}
$log = \json_decode($task->getAttribute('log', '{}'), true);
if (\count($log) >= $logLimit) {
\array_pop($log);
}
\array_unshift($log, [
'code' => $code,
'duration' => $totalTime,
'delay' => $delay,
'errors' => $errors,
'headers' => $headers,
'body' => $body,
]);
$task
->setAttribute('log', \json_encode($log))
->setAttribute('duration', $totalTime)
->setAttribute('delay', $delay)
;
$project->findAndReplace('$id', $task->getId(), $task);
Authorization::disable();
if (false === $dbForConsole->updateDocument('projects', $project->getId(), $project)) {
throw new Exception('Failed saving tasks to DB');
}
Authorization::reset();
// ResqueScheduler::enqueueAt($next, 'v1-tasks', 'TasksV1', $task->getArrayCopy()); // Sync task rescheduale
// Send alert if needed (use SMTP as default for now)
return;
}
public function shutdown(): void
{
}
}

View file

@ -1,10 +0,0 @@
#!/bin/sh
if [ -z "$_APP_REDIS_USER" ] && [ -z "$_APP_REDIS_PASS" ]
then
REDIS_BACKEND="${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
else
REDIS_BACKEND="redis://${_APP_REDIS_USER}:${_APP_REDIS_PASS}@${_APP_REDIS_HOST}:${_APP_REDIS_PORT}"
fi
INTERVAL=0.1 QUEUE='v1-tasks' APP_INCLUDE='/usr/src/code/app/workers/tasks.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php

View file

@ -39,9 +39,9 @@
"appwrite/php-runtimes": "0.4.*",
"utopia-php/framework": "0.16.*",
"utopia-php/abuse": "dev-feat-utopia-db-integration",
"utopia-php/abuse": "0.6.*",
"utopia-php/analytics": "0.2.*",
"utopia-php/audit": "dev-feat-utopia-db-integration",
"utopia-php/audit": "0.6.*",
"utopia-php/cache": "0.4.*",
"utopia-php/cli": "0.11.*",
"utopia-php/config": "0.2.*",
@ -62,18 +62,8 @@
"adhocore/jwt": "1.1.2",
"slickdeals/statsd": "3.1.0"
},
"repositories": [
{
"type": "git",
"url": "https://github.com/lohanidamodar/abuse"
},
{
"type": "git",
"url": "https://github.com/lohanidamodar/audit"
}
],
"require-dev": {
"appwrite/sdk-generator": "dev-fix-new-defaults",
"appwrite/sdk-generator": "0.13.0",
"swoole/ide-helper": "4.6.7",
"phpunit/phpunit": "9.5.6",
"vimeo/psalm": "4.7.2"

137
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": "0246a4d33ab36b0a2f2a93be15cb0bef",
"content-hash": "6e0b87a4505ba02e444efa70b6f68ace",
"packages": [
{
"name": "adhocore/jwt",
@ -1583,16 +1583,16 @@
},
{
"name": "symfony/polyfill-php80",
"version": "v1.23.0",
"version": "v1.23.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0"
"reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/eca0bf41ed421bed1b57c4958bab16aa86b757d0",
"reference": "eca0bf41ed421bed1b57c4958bab16aa86b757d0",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/1100343ed1a92e3a38f9ae122fc0eb21602547be",
"reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be",
"shasum": ""
},
"require": {
@ -1646,7 +1646,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.23.0"
"source": "https://github.com/symfony/polyfill-php80/tree/v1.23.1"
},
"funding": [
{
@ -1662,15 +1662,21 @@
"type": "tidelift"
}
],
"time": "2021-02-19T12:13:01+00:00"
"time": "2021-07-28T13:41:28+00:00"
},
{
"name": "utopia-php/abuse",
"version": "dev-feat-utopia-db-integration",
"version": "0.6.0",
"source": {
"type": "git",
"url": "https://github.com/lohanidamodar/abuse",
"reference": "9742a72dfecb27e74e2d8d8018b7bdbec6637de6"
"url": "https://github.com/utopia-php/abuse.git",
"reference": "f568f97467eca66450af6fba18038ddeb8e8d05a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/f568f97467eca66450af6fba18038ddeb8e8d05a",
"reference": "f568f97467eca66450af6fba18038ddeb8e8d05a",
"shasum": ""
},
"require": {
"ext-pdo": "*",
@ -1687,6 +1693,7 @@
"Utopia\\Abuse\\": "src/Abuse"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
@ -1698,13 +1705,17 @@
],
"description": "A simple abuse library to manage application usage limits",
"keywords": [
"abuse",
"Abuse",
"framework",
"php",
"upf",
"utopia"
],
"time": "2021-07-04T06:06:38+00:00"
"support": {
"issues": "https://github.com/utopia-php/abuse/issues",
"source": "https://github.com/utopia-php/abuse/tree/0.6.0"
},
"time": "2021-08-01T11:16:50+00:00"
},
{
"name": "utopia-php/analytics",
@ -1763,11 +1774,17 @@
},
{
"name": "utopia-php/audit",
"version": "dev-feat-utopia-db-integration",
"version": "0.6.0",
"source": {
"type": "git",
"url": "https://github.com/lohanidamodar/audit",
"reference": "e4b03bf3dd86fbde8608ae2b6774851bb66e665b"
"url": "https://github.com/utopia-php/audit.git",
"reference": "f81bbe0bf64d74c9668ca7ab90d0b6eb3df4d47e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/f81bbe0bf64d74c9668ca7ab90d0b6eb3df4d47e",
"reference": "f81bbe0bf64d74c9668ca7ab90d0b6eb3df4d47e",
"shasum": ""
},
"require": {
"ext-pdo": "*",
@ -1784,6 +1801,7 @@
"Utopia\\Audit\\": "src/Audit"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
@ -1795,13 +1813,17 @@
],
"description": "A simple audit library to manage application users logs",
"keywords": [
"audit",
"Audit",
"framework",
"php",
"upf",
"utopia"
],
"time": "2021-07-04T12:02:18+00:00"
"support": {
"issues": "https://github.com/utopia-php/audit/issues",
"source": "https://github.com/utopia-php/audit/tree/0.6.0"
},
"time": "2021-08-01T11:14:31+00:00"
},
{
"name": "utopia-php/cache",
@ -2726,16 +2748,16 @@
},
{
"name": "appwrite/sdk-generator",
"version": "dev-fix-new-defaults",
"version": "0.13.0",
"source": {
"type": "git",
"url": "https://github.com/appwrite/sdk-generator.git",
"reference": "87ae24ee9d79d38a0fb198e24189efe0ca74b8dc"
"reference": "ea867bf585b03d2e22315820bf7ebca59c4cbd61"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/87ae24ee9d79d38a0fb198e24189efe0ca74b8dc",
"reference": "87ae24ee9d79d38a0fb198e24189efe0ca74b8dc",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/ea867bf585b03d2e22315820bf7ebca59c4cbd61",
"reference": "ea867bf585b03d2e22315820bf7ebca59c4cbd61",
"shasum": ""
},
"require": {
@ -2769,9 +2791,9 @@
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
"support": {
"issues": "https://github.com/appwrite/sdk-generator/issues",
"source": "https://github.com/appwrite/sdk-generator/tree/fix-new-defaults"
"source": "https://github.com/appwrite/sdk-generator/tree/0.13.0"
},
"time": "2021-07-20T09:42:41+00:00"
"time": "2021-07-31T20:27:03+00:00"
},
{
"name": "composer/semver",
@ -2856,21 +2878,21 @@
},
{
"name": "composer/xdebug-handler",
"version": "2.0.1",
"version": "2.0.2",
"source": {
"type": "git",
"url": "https://github.com/composer/xdebug-handler.git",
"reference": "964adcdd3a28bf9ed5d9ac6450064e0d71ed7496"
"reference": "84674dd3a7575ba617f5a76d7e9e29a7d3891339"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/xdebug-handler/zipball/964adcdd3a28bf9ed5d9ac6450064e0d71ed7496",
"reference": "964adcdd3a28bf9ed5d9ac6450064e0d71ed7496",
"url": "https://api.github.com/repos/composer/xdebug-handler/zipball/84674dd3a7575ba617f5a76d7e9e29a7d3891339",
"reference": "84674dd3a7575ba617f5a76d7e9e29a7d3891339",
"shasum": ""
},
"require": {
"php": "^5.3.2 || ^7.0 || ^8.0",
"psr/log": "^1.0"
"psr/log": "^1 || ^2 || ^3"
},
"require-dev": {
"phpstan/phpstan": "^0.12.55",
@ -2900,7 +2922,7 @@
"support": {
"irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/xdebug-handler/issues",
"source": "https://github.com/composer/xdebug-handler/tree/2.0.1"
"source": "https://github.com/composer/xdebug-handler/tree/2.0.2"
},
"funding": [
{
@ -2916,7 +2938,7 @@
"type": "tidelift"
}
],
"time": "2021-05-05T19:37:51+00:00"
"time": "2021-07-31T17:03:58+00:00"
},
{
"name": "dnoegel/php-xdg-base-dir",
@ -5132,7 +5154,6 @@
"type": "github"
}
],
"abandoned": true,
"time": "2020-09-28T06:45:17+00:00"
},
{
@ -5298,16 +5319,16 @@
},
{
"name": "symfony/console",
"version": "v5.3.4",
"version": "v5.3.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "ebd610dacd40d75b6a12bf64b5ccd494fc7d6ab1"
"reference": "51b71afd6d2dc8f5063199357b9880cea8d8bfe2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/ebd610dacd40d75b6a12bf64b5ccd494fc7d6ab1",
"reference": "ebd610dacd40d75b6a12bf64b5ccd494fc7d6ab1",
"url": "https://api.github.com/repos/symfony/console/zipball/51b71afd6d2dc8f5063199357b9880cea8d8bfe2",
"reference": "51b71afd6d2dc8f5063199357b9880cea8d8bfe2",
"shasum": ""
},
"require": {
@ -5377,7 +5398,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v5.3.4"
"source": "https://github.com/symfony/console/tree/v5.3.6"
},
"funding": [
{
@ -5393,7 +5414,7 @@
"type": "tidelift"
}
],
"time": "2021-07-26T16:33:26+00:00"
"time": "2021-07-27T19:10:22+00:00"
},
{
"name": "symfony/deprecation-contracts",
@ -5464,16 +5485,16 @@
},
{
"name": "symfony/polyfill-intl-grapheme",
"version": "v1.23.0",
"version": "v1.23.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
"reference": "24b72c6baa32c746a4d0840147c9715e42bb68ab"
"reference": "16880ba9c5ebe3642d1995ab866db29270b36535"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/24b72c6baa32c746a4d0840147c9715e42bb68ab",
"reference": "24b72c6baa32c746a4d0840147c9715e42bb68ab",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/16880ba9c5ebe3642d1995ab866db29270b36535",
"reference": "16880ba9c5ebe3642d1995ab866db29270b36535",
"shasum": ""
},
"require": {
@ -5525,7 +5546,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.23.0"
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.23.1"
},
"funding": [
{
@ -5541,7 +5562,7 @@
"type": "tidelift"
}
],
"time": "2021-05-27T09:17:38+00:00"
"time": "2021-05-27T12:26:48+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
@ -5629,16 +5650,16 @@
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.23.0",
"version": "v1.23.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1"
"reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2df51500adbaebdc4c38dea4c89a2e131c45c8a1",
"reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9174a3d80210dca8daa7f31fec659150bbeabfc6",
"reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6",
"shasum": ""
},
"require": {
@ -5689,7 +5710,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.0"
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.1"
},
"funding": [
{
@ -5705,7 +5726,7 @@
"type": "tidelift"
}
],
"time": "2021-05-27T09:27:20+00:00"
"time": "2021-05-27T12:26:48+00:00"
},
{
"name": "symfony/polyfill-php73",
@ -5950,16 +5971,16 @@
},
{
"name": "theseer/tokenizer",
"version": "1.2.0",
"version": "1.2.1",
"source": {
"type": "git",
"url": "https://github.com/theseer/tokenizer.git",
"reference": "75a63c33a8577608444246075ea0af0d052e452a"
"reference": "34a41e998c2183e22995f158c581e7b5e755ab9e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/75a63c33a8577608444246075ea0af0d052e452a",
"reference": "75a63c33a8577608444246075ea0af0d052e452a",
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e",
"reference": "34a41e998c2183e22995f158c581e7b5e755ab9e",
"shasum": ""
},
"require": {
@ -5988,7 +6009,7 @@
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
"support": {
"issues": "https://github.com/theseer/tokenizer/issues",
"source": "https://github.com/theseer/tokenizer/tree/master"
"source": "https://github.com/theseer/tokenizer/tree/1.2.1"
},
"funding": [
{
@ -5996,7 +6017,7 @@
"type": "github"
}
],
"time": "2020-07-12T23:59:07+00:00"
"time": "2021-07-28T10:34:58+00:00"
},
{
"name": "twig/twig",
@ -6235,11 +6256,7 @@
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {
"utopia-php/abuse": 20,
"utopia-php/audit": 20,
"appwrite/sdk-generator": 20
},
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {

View file

@ -191,33 +191,6 @@ services:
- _APP_REDIS_USER
- _APP_REDIS_PASS
appwrite-worker-tasks:
entrypoint: worker-tasks
container_name: appwrite-worker-tasks
build:
context: .
networks:
- appwrite
volumes:
- ./app:/usr/src/code/app
- ./src:/usr/src/code/src
depends_on:
- redis
- mariadb
environment:
- _APP_ENV
- _APP_OPENSSL_KEY_V1
- _APP_SYSTEM_SECURITY_EMAIL_ADDRESS
- _APP_REDIS_HOST
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
appwrite-worker-deletes:
entrypoint: worker-deletes
container_name: appwrite-worker-deletes

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.account.createAnonymousSession();
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.account.createJWT();
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,10 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
// Go to OAuth provider login page
sdk.account.createOAuth2Session('amazon');

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.account.createRecovery('email@example.com', 'https://example.com');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.account.createSession('email@example.com', 'password');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.account.createVerification('https://example.com');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.account.create('email@example.com', 'password');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.account.deleteSession('[SESSION_ID]');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.account.deleteSessions();
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.account.delete();
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.account.getLogs();
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.account.getPrefs();
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.account.getSession('[SESSION_ID]');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.account.getSessions();
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.account.get();
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.account.updateEmail('email@example.com', 'password');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.account.updateName('[NAME]');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.account.updatePassword('password');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.account.updatePrefs({});
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.account.updateRecovery('[USER_ID]', '[SECRET]', 'password', 'password');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.account.updateVerification('[USER_ID]', '[SECRET]');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,10 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let result = sdk.avatars.getBrowser('aa');
console.log(result); // Resource URL

View file

@ -0,0 +1,10 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let result = sdk.avatars.getCreditCard('amex');
console.log(result); // Resource URL

View file

@ -0,0 +1,10 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let result = sdk.avatars.getFavicon('https://example.com');
console.log(result); // Resource URL

View file

@ -0,0 +1,10 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let result = sdk.avatars.getFlag('af');
console.log(result); // Resource URL

View file

@ -0,0 +1,10 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let result = sdk.avatars.getImage('https://example.com');
console.log(result); // Resource URL

View file

@ -0,0 +1,10 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let result = sdk.avatars.getInitials();
console.log(result); // Resource URL

View file

@ -0,0 +1,10 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let result = sdk.avatars.getQR('[TEXT]');
console.log(result); // Resource URL

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.database.createAttribute('[COLLECTION_ID]', '', '[TYPE]', null, false);
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.database.createDocument('[COLLECTION_ID]', {});
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.database.createIndex('[COLLECTION_ID]', '', 'text', []);
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.database.deleteAttribute('[COLLECTION_ID]', '');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.database.deleteDocument('[COLLECTION_ID]', '[DOCUMENT_ID]');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.database.deleteIndex('[COLLECTION_ID]', '');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.database.getAttribute('[COLLECTION_ID]', '');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.database.getDocument('[COLLECTION_ID]', '[DOCUMENT_ID]');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.database.getIndex('[COLLECTION_ID]', '');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.database.listAttributes('[COLLECTION_ID]');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.database.listDocuments('[COLLECTION_ID]');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.database.listIndexes('[COLLECTION_ID]');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.database.updateDocument('[COLLECTION_ID]', '[DOCUMENT_ID]', {});
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.functions.createExecution('[FUNCTION_ID]');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.functions.getExecution('[FUNCTION_ID]', '[EXECUTION_ID]');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.functions.listExecutions('[FUNCTION_ID]');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.locale.getContinents();
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.locale.getCountriesEU();
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.locale.getCountriesPhones();
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.locale.getCountries();
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.locale.getCurrencies();
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.locale.getLanguages();
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.locale.get();
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.storage.createFile(document.getElementById('uploader').files[0]);
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.storage.deleteFile('[FILE_ID]');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,10 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let result = sdk.storage.getFileDownload('[FILE_ID]');
console.log(result); // Resource URL

View file

@ -0,0 +1,10 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let result = sdk.storage.getFilePreview('[FILE_ID]');
console.log(result); // Resource URL

View file

@ -0,0 +1,10 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let result = sdk.storage.getFileView('[FILE_ID]');
console.log(result); // Resource URL

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.storage.getFile('[FILE_ID]');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.storage.listFiles();
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.storage.updateFile('[FILE_ID]', [], []);
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.teams.createMembership('[TEAM_ID]', 'email@example.com', [], 'https://example.com');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.teams.create('[NAME]');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.teams.deleteMembership('[TEAM_ID]', '[MEMBERSHIP_ID]');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.teams.delete('[TEAM_ID]');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.teams.getMemberships('[TEAM_ID]');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.teams.get('[TEAM_ID]');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.teams.list();
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

View file

@ -0,0 +1,14 @@
let sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.teams.updateMembershipRoles('[TEAM_ID]', '[MEMBERSHIP_ID]', []);
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});

Some files were not shown because too many files have changed in this diff Show more