1
0
Fork 0
mirror of synced 2024-06-27 02:31:04 +12:00

Merge branch 'master' into the-executor-poc

This commit is contained in:
Bradley Schofield 2022-01-18 15:24:33 +00:00
commit e79578570e
54 changed files with 1319 additions and 1110 deletions

View file

@ -37,6 +37,7 @@ body:
label: "🎲 Appwrite version"
description: "What version of Appwrite are you running?"
options:
- Version 0.12.x
- Version 0.11.x
- Version 0.10.x
- Version 0.9.x

View file

@ -1,6 +1,16 @@
# Unreleased Version 0.13.0
- Added ability to create syncronous function executions
- Introduced new execution model for functions
# Version 0.12.1
## Bugs
- Fixed some issues with the Migration
- Fixed the UI to add Variables to Functions
- Fixed wrong data type for String Attribute size
- Fixed Request stats on the console
- Fixed Realtime Connection stats with high number by abbreviation
- Fixed backward compatibility of account status attribute.
# Version 0.12.0
## Features

View file

@ -32,7 +32,7 @@ ENV DEBUG=$DEBUG
ENV PHP_REDIS_VERSION=5.3.5 \
PHP_MONGODB_VERSION=1.9.1 \
PHP_SWOOLE_VERSION=v4.8.5 \
PHP_IMAGICK_VERSION=3.5.1 \
PHP_IMAGICK_VERSION=3.7.0 \
PHP_YAML_VERSION=2.2.2 \
PHP_MAXMINDDB_VERSION=v1.11.0

View file

@ -40,6 +40,7 @@ Table of Contents:
- [Client](#client)
- [Server](#server)
- [Community](#community)
- [Architecture](#architecture)
- [Contributing](#contributing)
- [Security](#security)
- [Follow Us](#follow-us)
@ -58,7 +59,7 @@ docker run -it --rm \
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
--entrypoint="install" \
appwrite/appwrite:0.12.0
appwrite/appwrite:0.12.1
```
### Windows
@ -70,7 +71,7 @@ docker run -it --rm ^
--volume //var/run/docker.sock:/var/run/docker.sock ^
--volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^
--entrypoint="install" ^
appwrite/appwrite:0.12.0
appwrite/appwrite:0.12.1
```
#### PowerShell
@ -80,7 +81,7 @@ docker run -it --rm ,
--volume /var/run/docker.sock:/var/run/docker.sock ,
--volume ${pwd}/appwrite:/usr/src/code/appwrite:rw ,
--entrypoint="install" ,
appwrite/appwrite:0.12.0
appwrite/appwrite:0.12.1
```
Once the Docker installation completes, go to http://localhost to access the Appwrite console from your browser. Please note that on non-Linux native hosts, the server might take a few minutes to start after installation completes.
@ -143,6 +144,15 @@ Below is a list of currently supported platforms and languages. If you wish to h
Looking for more SDKs? - Help us by contributing a pull request to our [SDK Generator](https://github.com/appwrite/sdk-generator)!
## Architecture
![Appwrite Architecture](docs/specs/overview.drawio.svg)
Appwrite uses a microservices architecture that was designed for easy scaling and delegation of responsibilities. In addition, Appwrite supports multiple APIs (REST, WebSocket, and GraphQL-soon) to allow you to interact with your resources leveraging your existing knowledge and protocols of choice.
The Appwrite API layer was designed to be extremely fast by leveraging in-memory caching and delegating any heavy-lifting tasks to the Appwrite background workers. The background workers also allow you to precisely control your compute capacity and costs using a message queue to handle the load. You can learn more about our architecture in the [contribution guide](CONTRIBUTING.md#architecture-1).
## Contributing
All code contributions - including those of people having commit access - must go through a pull request and be approved by a core developer before being merged. This is to ensure a proper review of all the code.

View file

@ -19,18 +19,6 @@ $collections = [
'webhooks' => [],
'keys' => [],
'platforms' => [
[
'$collection' => Database::SYSTEM_COLLECTION_PLATFORMS,
'name' => 'Production',
'type' => 'web',
'hostname' => 'appwrite.io',
],
[
'$collection' => Database::SYSTEM_COLLECTION_PLATFORMS,
'name' => 'Development',
'type' => 'web',
'hostname' => 'appwrite.test',
],
[
'$collection' => Database::SYSTEM_COLLECTION_PLATFORMS,
'name' => 'Localhost',

View file

@ -2391,6 +2391,7 @@ $collections = [
],
],
],
'stats' => [
'$collection' => Database::METADATA,
'$id' => 'stats',
@ -2476,6 +2477,7 @@ $collections = [
],
],
],
'realtime' => [
'$collection' => Database::METADATA,
'$id' => 'realtime',

View file

@ -15,7 +15,7 @@ return [
[
'key' => 'web',
'name' => 'Web',
'version' => '6.0.0',
'version' => '6.0.1',
'url' => 'https://github.com/appwrite/sdk-for-web',
'package' => 'https://www.npmjs.com/package/appwrite',
'enabled' => true,
@ -63,7 +63,7 @@ return [
[
'key' => 'flutter',
'name' => 'Flutter',
'version' => '3.0.0',
'version' => '3.0.1',
'url' => 'https://github.com/appwrite/sdk-for-flutter',
'package' => 'https://pub.dev/packages/appwrite',
'enabled' => true,
@ -81,7 +81,7 @@ return [
[
'key' => 'apple',
'name' => 'Apple',
'version' => '0.2.0',
'version' => '0.2.1',
'url' => 'https://github.com/appwrite/sdk-for-apple',
'package' => 'https://github.com/appwrite/sdk-for-apple',
'enabled' => true,
@ -116,7 +116,7 @@ return [
[
'key' => 'android',
'name' => 'Android',
'version' => '0.3.0',
'version' => '0.3.1',
'url' => 'https://github.com/appwrite/sdk-for-android',
'package' => 'https://search.maven.org/artifact/io.appwrite/sdk-for-android',
'enabled' => true,
@ -152,7 +152,7 @@ return [
// ],
],
],
APP_PLATFORM_CONSOLE => [
'key' => APP_PLATFORM_CONSOLE,
'name' => 'Console',
@ -190,7 +190,7 @@ return [
[
'key' => 'nodejs',
'name' => 'Node.js',
'version' => '4.0.0',
'version' => '4.0.2',
'url' => 'https://github.com/appwrite/sdk-for-node',
'package' => 'https://www.npmjs.com/package/node-appwrite',
'enabled' => true,
@ -208,7 +208,7 @@ return [
[
'key' => 'deno',
'name' => 'Deno',
'version' => '2.0.0',
'version' => '2.0.2',
'url' => 'https://github.com/appwrite/sdk-for-deno',
'package' => 'https://deno.land/x/appwrite',
'enabled' => true,
@ -334,7 +334,7 @@ return [
[
'key' => 'dart',
'name' => 'Dart',
'version' => '3.0.0',
'version' => '3.0.2',
'url' => 'https://github.com/appwrite/sdk-for-dart',
'package' => 'https://pub.dev/packages/dart_appwrite',
'enabled' => true,
@ -370,7 +370,7 @@ return [
[
'key' => 'kotlin',
'name' => 'Kotlin',
'version' => '0.2.0',
'version' => '0.2.2',
'url' => 'https://github.com/appwrite/sdk-for-kotlin',
'package' => 'https://search.maven.org/artifact/io.appwrite/sdk-for-kotlin',
'enabled' => true,
@ -392,7 +392,7 @@ return [
[
'key' => 'swift',
'name' => 'Swift',
'version' => '0.2.0',
'version' => '0.2.1',
'url' => 'https://github.com/appwrite/sdk-for-swift',
'package' => 'https://github.com/appwrite/sdk-for-swift',
'enabled' => true,

View file

@ -131,6 +131,16 @@ return [ // Ordered by ABC.
'beta' => false,
'mock' => false,
],
'notion' => [
'name' => 'Notion',
'developers' => 'https://developers.notion.com/docs',
'icon' => 'icon-notion',
'enabled' => true,
'sandbox' => false,
'form' => false,
'beta' => false,
'mock' => false,
],
'paypal' => [
'name' => 'PayPal',
'developers' => 'https://developer.paypal.com/docs/api/overview/',

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -44,7 +44,7 @@ App::post('/v1/account')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER)
->label('abuse-limit', 10)
->param('userId', '', 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, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
->param('userId', '', 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, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
->param('email', '', new Email(), 'User email.')
->param('password', '', new Password(), 'User password. Must be at least 8 chars.')
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
@ -479,7 +479,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
$limit = $project->getAttribute('auths', [])['limit'] ?? 0;
if ($limit !== 0) {
$sum = $dbForProject->count('users', [ new Query('deleted', Query::TYPE_EQUAL, [false]),], APP_LIMIT_COUNT);
$sum = $dbForProject->count('users', [ new Query('deleted', Query::TYPE_EQUAL, [false]),], APP_LIMIT_USERS);
if ($sum >= $limit) {
throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501);
@ -615,7 +615,7 @@ App::post('/v1/account/sessions/magic-url')
->label('sdk.response.model', Response::MODEL_TOKEN)
->label('abuse-limit', 10)
->label('abuse-key', 'url:{url},email:{param-email}')
->param('userId', '', 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, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
->param('userId', '', 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, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
->param('email', '', new Email(), 'User email.')
->param('url', '', function ($clients) { return new Host($clients); }, 'URL to redirect the user back to your app from the magic URL login. 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.', true, ['clients'])
->inject('request')
@ -652,7 +652,7 @@ App::post('/v1/account/sessions/magic-url')
if ($limit !== 0) {
$sum = $dbForProject->count('users', [
new Query('deleted', Query::TYPE_EQUAL, [false]),
], APP_LIMIT_COUNT);
], APP_LIMIT_USERS);
if ($sum >= $limit) {
throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501);
@ -924,7 +924,7 @@ App::post('/v1/account/sessions/anonymous')
if ($limit !== 0) {
$sum = $dbForProject->count('users', [
new Query('deleted', Query::TYPE_EQUAL, [false]),
], APP_LIMIT_COUNT);
], APP_LIMIT_USERS);
if ($sum >= $limit) {
throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501);

View file

@ -148,7 +148,7 @@ App::post('/v1/database/collections')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_COLLECTION)
->param('collectionId', '', 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, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
->param('collectionId', '', 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, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
->param('name', '', new Text(128), 'Collection name. Max length: 128 chars.')
->param('permission', null, new WhiteList(['document', 'collection']), 'Permissions type model to use for reading documents in this collection. You can use collection-level permission set once on the collection using the `read` and `write` params, or you can set document-level permission where each document read and write params will decide who has access to read and write to each document individually. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.')
->param('read', null, new Permissions(), 'An array of strings with read permissions. By default no user is granted with any read permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.')
@ -1563,7 +1563,7 @@ App::post('/v1/database/collections/:collectionId/documents')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_DOCUMENT)
->param('documentId', '', new CustomId(), 'Document ID. Choose your own unique ID or pass the string `unique()` to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
->param('documentId', '', new CustomId(), 'Document ID. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
->param('collectionId', null, new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection). Make sure to define attributes before creating documents.')
->param('data', [], new JSON(), 'Document data as JSON object.')
->param('read', null, new Permissions(), 'An array of strings with read permissions. By default only the current user is granted with read permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.', true)
@ -1832,7 +1832,7 @@ App::get('/v1/database/collections/:collectionId/documents/:documentId')
$usage
->setParam('database.documents.read', 1)
->setParam('collectionId', $collectionId)
;
;
$response->dynamic($document, Response::MODEL_DOCUMENT);
});

View file

@ -41,7 +41,7 @@ App::post('/v1/functions')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_FUNCTION)
->param('functionId', '', new CustomId(), 'Function ID. Choose your own unique ID or pass the string `unique()` to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
->param('functionId', '', new CustomId(), 'Function ID. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
->param('name', '', new Text(128), 'Function name. Max length: 128 chars.')
->param('execute', [], new ArrayList(new Text(64)), 'An array of strings with execution permissions. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.')
->param('runtime', '', new WhiteList(array_keys(Config::getParam('runtimes')), true), 'Execution runtime.')

View file

@ -43,7 +43,7 @@ App::post('/v1/projects')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT)
->param('projectId', '', 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, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
->param('projectId', '', 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, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
->param('name', null, new Text(128), 'Project name. Max length: 128 chars.')
->param('teamId', '', new UID(), 'Team unique ID.')
->param('description', '', new Text(256), 'Project description. Max length: 256 chars.', true)
@ -461,7 +461,7 @@ App::patch('/v1/projects/:projectId/auth/limit')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT)
->param('projectId', '', new UID(), 'Project unique ID.')
->param('limit', false, new Integer(true), 'Set the max number of users allowed in this project. Use 0 for unlimited.')
->param('limit', false, new Range(0, APP_LIMIT_USERS), 'Set the max number of users allowed in this project. Use 0 for unlimited.')
->inject('response')
->inject('dbForConsole')
->action(function ($projectId, $limit, $response, $dbForConsole) {

View file

@ -41,7 +41,7 @@ App::post('/v1/storage/files')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_FILE)
->param('fileId', '', new CustomId(), 'File ID. Choose your own unique ID or pass the string `unique()` to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
->param('fileId', '', new CustomId(), 'File ID. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
->param('file', [], new File(), 'Binary file.', false)
->param('read', null, new ArrayList(new Text(64)), 'An array of strings with read permissions. By default only the current user is granted with read permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.', true)
->param('write', null, new ArrayList(new Text(64)), 'An array of strings with write permissions. By default only the current user is granted with write permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.', true)

View file

@ -34,7 +34,7 @@ App::post('/v1/teams')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_TEAM)
->param('teamId', '', new CustomId(), 'Team ID. Choose your own unique ID or pass the string `unique()` to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
->param('teamId', '', new CustomId(), 'Team ID. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
->param('name', null, new Text(128), 'Team name. Max length: 128 chars.')
->param('roles', ['owner'], new ArrayList(new Key()), 'Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](/docs/permissions). Max length for each role is 32 chars.', true)
->inject('response')

View file

@ -34,7 +34,7 @@ App::post('/v1/users')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER)
->param('userId', '', new CustomId(), 'User ID. Choose your own unique ID or pass the string `unique()` to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
->param('userId', '', new CustomId(), 'User ID. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
->param('email', '', new Email(), 'User email.')
->param('password', '', new Password(), 'User password. Must be at least 8 chars.')
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
@ -725,6 +725,11 @@ App::delete('/v1/users/:userId')
throw new Exception('User not found', 404);
}
/**
* DO NOT DELETE THE USER RECORD ITSELF.
* WE RETAIN THE USER RECORD TO RESERVE THE USER ID AND ENSURE THAT THE USER ID IS NOT REUSED.
*/
// clone user object to send to workers
$clone = clone $user;
@ -733,6 +738,8 @@ App::delete('/v1/users/:userId')
->setAttribute("email", null)
->setAttribute("password", null)
->setAttribute("deleted", true)
->setAttribute("tokens", [])
->setAttribute("search", null)
;
$dbForProject->updateDocument('users', $userId, $user);

View file

@ -167,6 +167,7 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons
break;
case version_compare ($responseFormat , '0.8.0', '<=') :
Response::setFilter(new V08());
break;
case version_compare ($responseFormat , '0.11.0', '<=') :
Response::setFilter(new V11());
break;

View file

@ -353,10 +353,12 @@ App::get('/v1/mock/tests/general/set-cookie')
->label('sdk.response.model', Response::MODEL_MOCK)
->label('sdk.mock', true)
->inject('response')
->action(function ($response) {
->inject('request')
->action(function ($response, $request) {
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Utopia\Request $request */
$response->addCookie('cookieName', 'cookieValue', \time() + 31536000, '/', 'localhost', true, true);
$response->addCookie('cookieName', 'cookieValue', \time() + 31536000, '/', $request->getHostname(), true, true);
});
App::get('/v1/mock/tests/general/get-cookie')

View file

@ -61,7 +61,7 @@ const APP_MODE_ADMIN = 'admin';
const APP_PAGING_LIMIT = 12;
const APP_LIMIT_COUNT = 5000;
const APP_LIMIT_USERS = 10000;
const APP_CACHE_BUSTER = 200;
const APP_CACHE_BUSTER = 201;
const APP_VERSION_STABLE = '0.13.0';
const APP_DATABASE_ATTRIBUTE_EMAIL = 'email';
const APP_DATABASE_ATTRIBUTE_ENUM = 'enum';
@ -775,18 +775,6 @@ App::setResource('console', function() {
'webhooks' => [],
'keys' => [],
'platforms' => [
[
'$collection' => 'platforms',
'name' => 'Production',
'type' => 'web',
'hostname' => 'appwrite.io',
],
[
'$collection' => 'platforms',
'name' => 'Development',
'type' => 'web',
'hostname' => 'appwrite.test',
],
[
'$collection' => 'platforms',
'name' => 'Localhost',

View file

@ -706,10 +706,10 @@ $logs = $this->getParam('logs', null);
<label for="integer-default">Default Value</label>
<template x-if="!(array || required)">
<input name="xdefault" type="number" class="margin-bottom-large" autocomplete="off">
<input name="xdefault" type="number" class="margin-bottom-large" autocomplete="off" data-cast-to="integer">
</template>
<template x-if="(array || required)">
<input name="xdefault" type="number" class="margin-bottom-large" autocomplete="off" disabled value="">
<input name="xdefault" type="number" class="margin-bottom-large" autocomplete="off" data-cast-to="integer" disabled>
</template>
<footer>
@ -770,10 +770,10 @@ $logs = $this->getParam('logs', null);
<label for="float-default">Default Value</label>
<template x-if="!(array || required)">
<input name="xdefault" type="number" step="0.01" class="margin-bottom-large" autocomplete="off">
<input name="xdefault" type="number" step="0.01" class="margin-bottom-large" autocomplete="off" data-cast-to="float">
</template>
<template x-if="(array || required)">
<input name="xdefault" type="number" step="0.01" class="margin-bottom-large" autocomplete="off" disabled value="">
<input name="xdefault" type="number" step="0.01" class="margin-bottom-large" autocomplete="off" data-cast-to="float" disabled>
</template>
<footer>

View file

@ -115,7 +115,7 @@ $logs = $this->getParam('logs', null);
:name="attr.key"
:required="attr.required"
x-model="doc[attr.key]"
data-cast-to="integer" />
data-cast-to="float" />
</template>
<template x-if="attr.type === 'boolean'">
<input
@ -205,7 +205,7 @@ $logs = $this->getParam('logs', null);
:name="attr.key"
:required="attr.required"
x-model="doc[attr.key][index]"
data-cast-to="integer" />
data-cast-to="float" />
</template>
<template x-if="attr.type === 'boolean'">
<input

View file

@ -528,7 +528,6 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
<div class="text-size-small text-fade margin-bottom margin-top-negative-small">Leave blank for no schedule</div>
<h3 class="margin-bottom-small">Variables <span class="tooltip small" data-tooltip="Set variables or secret keys that will be passed as env vars to your function at runtime."><i class="icon-info-circled"></i></span></h3>
<div data-ls-if="(!{{project-function.vars.length}})">
<hr class="margin-bottom margin-top-no" />
@ -548,9 +547,9 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
<div data-forms-clone="" data-target="project-vars" data-label="Add Variable" data-first="0">
<div class="margin-bottom-small">
<div data-forms-remove class="row thin margin-bottom-small">
<div data-forms-remove class="row thin">
<div class="col span-10">
<input type="hidden" name="" data-forms-key-value />
<input type="hidden" data-ls-attrs="data-forms-key-value"/>
</div>
<div class="col span-2">
<button type="button" data-remove class="reverse danger round pull-end"><i class="icon-cancel"></i></button>

View file

@ -97,13 +97,13 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
</div>
<div class="chart-metric">
<div class="value margin-bottom-small"><span class="sum" data-ls-bind="{{usage.requests|statsGetLast|statsTotal}}">N/A</span></div>
<div class="value margin-bottom-small"><span class="sum" data-ls-bind="{{usage.requests|statsGetSum|statsTotal}}">N/A</span></div>
<div class="unit margin-start-no margin-bottom-small">Requests</div>
</div>
</div>
<div class="col span-3">
<div class="value margin-bottom-small">
<span class="sum" data-ls-bind="{{realtime.current|accessProject}}" data-default="0">0</span>
<span class="sum" data-ls-bind="{{realtime.current|accessProject|statsTotal}}" data-default="0">0</span>
</div>
<div class="unit margin-start-no margin-bottom-small">Connections</div>
<div class="chart-bar margin-top-small margin-bottom-small" data-ls-attrs="data-history={{realtime.history|accessProject}}" data-forms-chart-bars="{{realtime.history|accessProject}}"></div>

View file

@ -453,7 +453,7 @@ $smtpEnabled = $this->getParam('smtpEnabled', false);
<div class="box margin-bottom">
<ul data-ls-loop="members.memberships" data-ls-as="member" class="list">
<li class="clear">
<form class="pull-end"
<form class="pull-end" data-ls-if="{{account.$id}} !== {{member.userId}}"
data-analytics
data-analytics-activity
data-analytics-event="submit"
@ -473,7 +473,33 @@ $smtpEnabled = $this->getParam('smtpEnabled', false);
<input name="teamId" data-ls-attrs="id=leave-teamId-{{member.$id}}" type="hidden" data-ls-bind="{{console-project.teamId}}">
<input name="membershipId" data-ls-attrs="id=leave-membershipId-{{member.$id}}" type="hidden" data-ls-bind="{{member.$id}}">
<button class="danger">Leave</button>
<button data-ls-if="1 === {{members.memberships.length}}" class="danger" disabled>Remove</button>
<button data-ls-if="1 < {{members.memberships.length}}" class="danger">Remove</button>
</form>
<form class="pull-end" data-ls-if="{{account.$id}} === {{member.userId}}"
data-analytics
data-analytics-activity
data-analytics-event="submit"
data-analytics-category="console"
data-analytics-label="Delete Project Membership"
data-service="teams.deleteMembership"
data-scope="console"
data-event="submit"
data-success="alert,trigger,redirect"
data-confirm="Are you sure you want to remove that user from the team?"
data-success-param-alert-text="Member Removed Successfully"
data-success-param-trigger-events="teams.deleteMembership"
data-success-param-redirect-url="/console"
data-failure="alert"
data-failure-param-alert-text="Failed to Remove Member"
data-failure-param-alert-classname="error">
<input name="teamId" data-ls-attrs="id=leave-teamId-{{member.$id}}" type="hidden" data-ls-bind="{{console-project.teamId}}">
<input name="membershipId" data-ls-attrs="id=leave-membershipId-{{member.$id}}" type="hidden" data-ls-bind="{{member.$id}}">
<button data-ls-if="1 === {{members.memberships.length}}" class="danger" disabled>Remove</button>
<button data-ls-if="1 < {{members.memberships.length}}" class="danger">Remove</button>
</form>
<div data-ls-if="false === {{member.confirm}}" class="pull-end margin-end">

View file

@ -353,13 +353,13 @@ $smtpEnabled = $this->getParam('smtpEnabled', false);
data-failure-param-alert-text="Failed to update project users limit"
data-failure-param-alert-classname="error">
<input name="limit" id="users-limit" type="number" data-ls-bind="{{console-project.authLimit}}" data-cast-to="numeric" min="0" />
<input name="limit" id="users-limit" type="number" data-ls-bind="{{console-project.authLimit}}" data-cast-to="numeric" min="0" max="<?php echo APP_LIMIT_USERS; ?>" />
<div class="info row thin margin-bottom margin-top">
<div class="col span-1">
<i class="icon-info-circled text-sign"></i>
</div>
<div class="col span-11">This limit will prevent new users from signing up for your project, no matter what auth method has been used. You will still be able to create users and team memberships from your Appwrite console. For an unlimited amount of users, set the limit to 0.</div>
<div class="col span-11">This limit will prevent new users from signing up for your project, no matter what auth method has been used. You will still be able to create users and team memberships from your Appwrite console. For an unlimited amount of users, set the limit to 0. Max limit is <?php echo number_format(APP_LIMIT_USERS); ?>.</div>
</div>
<button>Update</button> &nbsp; <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>

View file

@ -188,9 +188,22 @@ class DeletesV1 extends Worker
*/
protected function deleteUser(Document $document, string $projectId): void
{
/**
* DO NOT DELETE THE USER RECORD ITSELF.
* WE RETAIN THE USER RECORD TO RESERVE THE USER ID AND ENSURE THAT THE USER ID IS NOT REUSED.
*/
$userId = $document->getId();
$user = $this->getProjectDB($projectId)->getDocument('users', $userId);
// Delete all sessions of this user from the sessions table and update the sessions field of the user record
$this->deleteByGroup('sessions', [
new Query('userId', Query::TYPE_EQUAL, [$userId])
], $this->getProjectDB($projectId));
$user->setAttribute('sessions', []);
$updated = Authorization::skip(fn() => $this->getProjectDB($projectId)->updateDocument('users', $userId, $user));
// Tokens and Sessions removed with user document
// Delete Memberships and decrement team membership counts
$this->deleteByGroup('memberships', [
new Query('userId', Query::TYPE_EQUAL, [$userId])

View file

@ -40,10 +40,9 @@
"ext-openssl": "*",
"ext-zlib": "*",
"ext-sockets": "*",
"appwrite/php-clamav": "1.1.*",
"appwrite/php-runtimes": "dev-refactor",
"utopia-php/framework": "0.19.5",
"utopia-php/framework": "0.19.*",
"utopia-php/logger": "0.1.*",
"utopia-php/abuse": "0.7.*",
"utopia-php/analytics": "0.2.*",
@ -71,7 +70,7 @@
"slickdeals/statsd": "3.1.0"
},
"require-dev": {
"appwrite/sdk-generator": "0.17.0",
"appwrite/sdk-generator": "0.17.1",
"phpunit/phpunit": "9.5.10",
"swoole/ide-helper": "4.8.3",
"textalk/websocket": "1.5.5",

View file

@ -468,11 +468,7 @@ services:
- _APP_MAINTENANCE_RETENTION_AUDIT
appwrite-usage:
entrypoint:
- php
- -e
- /usr/src/code/app/cli.php
- usage
entrypoint: usage
container_name: appwrite-usage
build:
context: .

View file

@ -1 +1,3 @@
Use this endpoint to allow a user to accept an invitation to join a team after being redirected back to your app from the invitation email received by the user.
Use this endpoint to allow a user to accept an invitation to join a team after being redirected back to your app from the invitation email received by the user.
If the request is successful, a session for the user is automatically created.

View file

@ -1,3 +1,9 @@
## 3.0.2
- String Attribute Type got fixed
## 3.0.1
- Export Query Builder
## 3.0.0
- Support for Appwrite 0.12
- **BREAKING** Updated database service to adapt 0.12 API

View file

@ -1,3 +1,6 @@
## 3.0.1
- Export Query Builder
## 3.0.0
- Support for Appwrite 0.12
- **BREAKING** Updated database service to adapt 0.12 API

View file

@ -1,4 +1,4 @@
<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1108px" height="839px" viewBox="-0.5 -0.5 1108 839" content="&lt;mxfile host=&quot;612c770d-d23c-4897-ac0d-72478d1c5aef&quot; modified=&quot;2021-02-22T07:17:54.650Z&quot; agent=&quot;5.0 (Macintosh; Intel Mac OS X 11_2_1) AppleWebKit/537.36 (KHTML, like Gecko) Code/1.53.2 Chrome/87.0.4280.141 Electron/11.2.1 Safari/537.36&quot; etag=&quot;sAOb0L0gpVpMeEycjwCe&quot; version=&quot;14.2.4&quot; type=&quot;embed&quot;&gt;&lt;diagram id=&quot;WOshqXSVd2VkRfcggtcB&quot; name=&quot;Page-1&quot;&gt;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&lt;/diagram&gt;&lt;/mxfile&gt;">
<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1108px" height="839px" viewBox="-0.5 -0.5 1108 839" content="&lt;mxfile&gt;&lt;diagram id=&quot;WOshqXSVd2VkRfcggtcB&quot; name=&quot;Page-1&quot;&gt;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&lt;/diagram&gt;&lt;/mxfile&gt;">
<defs/>
<g>
<path d="M 77 40 L 77 80 L 397 80 L 397 113.63" fill="none" stroke="#23445d" stroke-miterlimit="10" pointer-events="stroke"/>
@ -201,13 +201,13 @@
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 520px; margin-left: 608px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
Pub/Sub (Redis)
Queue (Redis)
</div>
</div>
</div>
</foreignObject>
<text x="667" y="524" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
Pub/Sub (Redis)
Queue (Redis)
</text>
</switch>
</g>
@ -239,13 +239,13 @@
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 590px; margin-left: 468px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
Database (MariaDB)
Database
</div>
</div>
</div>
</foreignObject>
<text x="527" y="594" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
Database (MariaDB)
Database
</text>
</switch>
</g>
@ -404,22 +404,20 @@
</g>
<path d="M 437 720 L 437 820 L 297 820 L 297 590 L 460.63 590" fill="none" stroke="#d6b656" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 465.88 590 L 458.88 593.5 L 460.63 590 L 458.88 586.5 Z" fill="#d6b656" stroke="#d6b656" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 437 680 L 437 640 L 667 640 L 667 546.37" fill="none" stroke="#0e8088" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 667 541.12 L 670.5 548.12 L 667 546.37 L 663.5 548.12 Z" fill="#0e8088" stroke="#0e8088" stroke-miterlimit="10" pointer-events="all"/>
<rect x="397" y="680" width="80" height="40" fill="#b0e3e6" stroke="#0e8088" pointer-events="all"/>
<rect x="397" y="680" width="80" height="40" fill="#b1ddf0" stroke="#10739e" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 700px; margin-left: 398px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
Deletes
Maintenance
</div>
</div>
</div>
</foreignObject>
<text x="437" y="704" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
Deletes
Maintenance
</text>
</switch>
</g>
@ -450,9 +448,7 @@
<path d="M 347 541.12 L 350.5 548.12 L 347 546.37 L 343.5 548.12 Z" fill="#9673a6" stroke="#9673a6" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 347 720 L 347 740 L 207 740 L 207 546.37" fill="none" stroke="#9673a6" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 207 541.12 L 210.5 548.12 L 207 546.37 L 203.5 548.12 Z" fill="#9673a6" stroke="#9673a6" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 347 680 L 347 640 L 667 640 L 667 546.37" fill="none" stroke="#0e8088" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 667 541.12 L 670.5 548.12 L 667 546.37 L 663.5 548.12 Z" fill="#0e8088" stroke="#0e8088" stroke-miterlimit="10" pointer-events="all"/>
<rect x="307" y="680" width="80" height="40" fill="#b0e3e6" stroke="#0e8088" pointer-events="all"/>
<rect x="307" y="680" width="80" height="40" fill="#b1ddf0" stroke="#10739e" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
@ -530,8 +526,6 @@
</g>
<path d="M 707 720 L 707 820 L 297 820 L 297 590 L 460.63 590" fill="none" stroke="#d6b656" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 465.88 590 L 458.88 593.5 L 460.63 590 L 458.88 586.5 Z" fill="#d6b656" stroke="#d6b656" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 707 680 L 707 640 L 667 640 L 667 546.37" fill="none" stroke="#d4d4d4" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 667 541.12 L 670.5 548.12 L 667 546.37 L 663.5 548.12 Z" fill="#d4d4d4" stroke="#d4d4d4" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 707 680 L 707 640 L 667 640 L 667 546.37" fill="none" stroke="#0e8088" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 667 541.12 L 670.5 548.12 L 667 546.37 L 663.5 548.12 Z" fill="#0e8088" stroke="#0e8088" stroke-miterlimit="10" pointer-events="all"/>
<rect x="667" y="680" width="80" height="40" fill="#b0e3e6" stroke="#0e8088" pointer-events="all"/>
@ -541,13 +535,13 @@
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 700px; margin-left: 668px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
Tasks
Database
</div>
</div>
</div>
</foreignObject>
<text x="707" y="704" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
Tasks
Database
</text>
</switch>
</g>
@ -678,13 +672,13 @@
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 700px; margin-left: 1028px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
Scheduler
Deletes
</div>
</div>
</div>
</foreignObject>
<text x="1067" y="704" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
Scheduler
Deletes
</text>
</switch>
</g>
@ -714,13 +708,13 @@
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 520px; margin-left: 748px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
Antivirus (ClamAV)
AntiVirus (ClamAV)
</div>
</div>
</div>
</foreignObject>
<text x="807" y="524" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
Antivirus (ClamAV)
AntiVirus (ClamAV)
</text>
</switch>
</g>
@ -743,6 +737,23 @@
</text>
</switch>
</g>
<rect x="217" y="680" width="80" height="40" fill="#b1ddf0" stroke="#10739e" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 78px; height: 1px; padding-top: 700px; margin-left: 218px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
Scheduler
</div>
</div>
</div>
</foreignObject>
<text x="257" y="704" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
Scheduler
</text>
</switch>
</g>
</g>
<switch>
<g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/>

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

View file

@ -1,32 +1,32 @@
# Introducing new Environment Variable
This document is part of the Appwrite contributors' guide. Before you continue reading this document make sure you have read the [Code of Conduct](https://github.com/appwrite/appwrite/blob/master/CODE_OF_CONDUCT.md) and the [Contributing Guide](https://github.com/appwrite/appwrite/blob/master/CONTRIBUTING.md).
This document is part of the Appwrite contributors' guide. Before you continue reading this document, make sure you have read the [Code of Conduct](https://github.com/appwrite/appwrite/blob/master/CODE_OF_CONDUCT.md) and the [Contributing Guide](https://github.com/appwrite/appwrite/blob/master/CONTRIBUTING.md).
## Getting Started
### Agenda
Adding new features may require various configurations options to be set by the users. And for such options we use environment variables in Appwrite.
Adding new features may require various configurations options to be set by the users. And for such options, we use environment variables in Appwrite.
This tutorial will cover, how to properly add a new environment variable in Appwrite.
This tutorial will cover how to properly add a new environment variable in Appwrite.
### Naming environment variable
The environment variables in Appwrite are prefixed with `_APP_`. If it belongs to a specific category, the category name is appended as `_APP_REDIS` for the redis category. The available categories are General, Redis, MariaDB, InfluxDB, StatsD, SMTP, Storage and Functions. Finally a properly describing name is given to the variable. For example `_APP_REDIS_HOST` is an environment variable for redis connection host. You can find more information on available categories and existing environment variables in the [environment variables doc](https://appwrite.io/docs/environment-variables).
The environment variables in Appwrite are prefixed with `_APP_`. If it belongs to a specific category, the category name is appended as `_APP_REDIS` for the Redis category. The available categories are General, Redis, MariaDB, InfluxDB, StatsD, SMTP, Storage and Functions. Finally, a properly describing name is given to the variable. For example, `_APP_REDIS_HOST` is an environment variable for Redis connection host. You can find more information on available categories and existing environment variables in the [environment variables doc](https://appwrite.io/docs/environment-variables).
### Describe new environment variable
First of all, we add the new environment variable to `app/config/variables.php` in the designated category. If none of the categories fit, add it to the General category. Copy the existing variables description to create a new one, so that you will not miss any required fields.
First of all, we add the new environment variable to `app/config/variables.php` in the designated category. If none of the categories fit, add it to the General category. Copy the existing variable description to create a new one so that you will not miss any required fields.
This information is also used to generate the website documentation at https://appwrite.io/docs/environment-variables, so please use good descriptions that clearly define the purpose and other required info about the environment variable that you are adding.
### Add to .env and Dockerfile
If newly introduced environment variable has a default value, add it to the `.env` and `Dockerfile` along with other environment variables. `.env` file uses settings for Appwrite development environment.
If the newly introduced environment variable has a default value, add it to the `.env` and `Dockerfile` along with other environment variables. `.env` file uses settings for Appwrite development environment.
### Add to docker compose file and template
Add the new environment variables to the `docker-compose.yml` and `app/views/install/compose.phtml` for each docker services that require access to those environment variables.
### Add to Docker Compose file and template
Add the new environment variables to the `docker-compose.yml` and `app/views/install/compose.phtml` for each docker service that requires access to those environment variables.
The `docker-compose.yml` file is used by the Appwrite maintainers during development where as `app/views/install/compose.phtml` file is used by the Appwrite setup script.
The `docker-compose.yml` file is used by the Appwrite maintainers during development, whereas the `app/views/install/compose.phtml` file is used by the Appwrite setup script.
With these steps, your environment variable is properly added and can be accessed inside Appwrite code and any other containers where it is passed. You can access and use those variables to implement the features you are trying to achieve.
If everything went well, commit and initiate a PR and wait for the Appwrite team's approval.
Whooho! you have successfully added new environment variable to Appwrite. 🎉
Whooho! You have successfully added a new environment variable to Appwrite. 🎉

28
package-lock.json generated
View file

@ -9,8 +9,8 @@
"version": "0.1.0",
"license": "BSD-3-Clause",
"dependencies": {
"chart.js": "^3.6.2",
"markdown-it": "^12.3.0",
"chart.js": "^3.7.0",
"markdown-it": "^12.3.2",
"pell": "^1.0.6",
"prismjs": "^1.25.0",
"turndown": "^7.1.1"
@ -549,9 +549,9 @@
}
},
"node_modules/chart.js": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.6.2.tgz",
"integrity": "sha512-Xz7f/fgtVltfQYWq0zL1Xbv7N2inpG+B54p3D5FSvpCdy3sM+oZhbqa42eNuYXltaVvajgX5UpKCU2GeeJIgxg=="
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.7.0.tgz",
"integrity": "sha512-31gVuqqKp3lDIFmzpKIrBeum4OpZsQjSIAqlOpgjosHDJZlULtvwLEZKtEhIAZc7JMPaHlYMys40Qy9Mf+1AAg=="
},
"node_modules/chokidar": {
"version": "2.1.8",
@ -2862,9 +2862,9 @@
}
},
"node_modules/markdown-it": {
"version": "12.3.0",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.0.tgz",
"integrity": "sha512-T345UZZ6ejQWTjG6PSEHplzNy5m4kF6zvUpHVDv8Snl/pEU0OxIK0jGg8YLVNwJvT8E0YJC7/2UvssJDk/wQCQ==",
"version": "12.3.2",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
"integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
"dependencies": {
"argparse": "^2.0.1",
"entities": "~2.1.0",
@ -5484,9 +5484,9 @@
"dev": true
},
"chart.js": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.6.2.tgz",
"integrity": "sha512-Xz7f/fgtVltfQYWq0zL1Xbv7N2inpG+B54p3D5FSvpCdy3sM+oZhbqa42eNuYXltaVvajgX5UpKCU2GeeJIgxg=="
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.7.0.tgz",
"integrity": "sha512-31gVuqqKp3lDIFmzpKIrBeum4OpZsQjSIAqlOpgjosHDJZlULtvwLEZKtEhIAZc7JMPaHlYMys40Qy9Mf+1AAg=="
},
"chokidar": {
"version": "2.1.8",
@ -7413,9 +7413,9 @@
}
},
"markdown-it": {
"version": "12.3.0",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.0.tgz",
"integrity": "sha512-T345UZZ6ejQWTjG6PSEHplzNy5m4kF6zvUpHVDv8Snl/pEU0OxIK0jGg8YLVNwJvT8E0YJC7/2UvssJDk/wQCQ==",
"version": "12.3.2",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
"integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
"requires": {
"argparse": "^2.0.1",
"entities": "~2.1.0",

View file

@ -17,8 +17,8 @@
"gulp-less": "^5.0.0"
},
"dependencies": {
"chart.js": "^3.6.2",
"markdown-it": "^12.3.0",
"chart.js": "^3.7.0",
"markdown-it": "^12.3.2",
"pell": "^1.0.6",
"prismjs": "^1.25.0",
"turndown": "^7.1.1"

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -668,7 +668,8 @@ let units=["kB","MB","GB","TB","PB","EB","ZB","YB"];let u=-1;do{$value/=thresh;+
let thresh=1000;if(Math.abs($value)<thresh){return'B';}
let units=["kB","MB","GB","TB","PB","EB","ZB","YB"];let u=-1;do{$value/=thresh;++u;}while(Math.abs($value)>=thresh&&u<units.length-1);return units[u];}).add("statsTotal",function($value){if(!$value){return 0;}
$value=abbreviate($value,0,false,false);return $value??"N/A";}).add("statsGetLast",function($value){if(!$value||$value.length<1){return 0;}
return $value[$value.length-1].value;}).add("isEmpty",function($value){return(!!$value);}).add("isEmptyObject",function($value){return((Object.keys($value).length===0&&$value.constructor===Object)||$value.length===0)}).add("activeDomainsCount",function($value){let result=[];if(Array.isArray($value)){result=$value.filter(function(node){return(node.verification&&node.certificateId);});}
return $value[$value.length-1].value;}).add("statsGetSum",function($value){if(!$value||$value.length<1){return 0;}
return $value.reduce(function(value,object){return value+object.value},0);}).add("isEmpty",function($value){return(!!$value);}).add("isEmptyObject",function($value){return((Object.keys($value).length===0&&$value.constructor===Object)||$value.length===0)}).add("activeDomainsCount",function($value){let result=[];if(Array.isArray($value)){result=$value.filter(function(node){return(node.verification&&node.certificateId);});}
return result.length;}).add("documentAction",function(container){let collection=container.get('project-collection');let document=container.get('project-document');if(collection&&document&&!document.$id){return'database.createDocument';}
return'database.updateDocument';}).add("documentSuccess",function(container){let document=container.get('project-document');if(document&&!document.$id){return',redirect';}
return'';}).add("firstElement",function($value){if($value&&$value[0]){return $value[0];}
@ -811,7 +812,7 @@ position=direction;let current=Math.ceil(direction/window.innerHeight);element.s
else{element.classList.remove('scroll-end')}};window.addEventListener('scroll',check,false);window.addEventListener('resize',check,false);check();}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-setup",controller:function(element,console,form,alerts,router){element.addEventListener("submit",function(event){event.preventDefault();let loaderId=alerts.add({text:'Creating new project...',class:""},0);let formData=form.toJson(element);formData["name"]=formData["name"]||(element.dataset["defaultName"]||"");console.teams.create('unique()',formData["name"]||"").then(function(data){let team=data["$id"];formData=JSON.parse(JSON.stringify(formData).replace(new RegExp("{{teamId}}","g"),team));console.projects.create(formData["projectId"],formData["name"],team).then(function(project){alerts.remove(loaderId);window.location.href="/console/home?project="+project["$id"];},function(){throw new Error("Failed to setup project");});},function(){throw new Error("Setup failed creating project team");});});}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-switch",controller:function(element,router,document){let check=function(c){if(!element.value){return;}
if(element.value===router.params.project){return;}
return router.change("/console/home?project="+element.value);};element.addEventListener("change",function(){check();});}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-general-theme",controller:function(element,router,document){let toggle=function(c){if(document.body.classList.contains('theme-light')){document.body.classList.remove('theme-light');document.body.classList.add('theme-dark');window.localStorage.setItem('user-theme','theme-dark')}
else{document.body.classList.remove('theme-dark');document.body.classList.add('theme-light');window.localStorage.setItem('user-theme','theme-light')}};element.addEventListener("click",function(){toggle();});}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-version",controller:function(alerts,env,cookie){let cookieName="version-update-"+env.VERSION.replace(/\./g,"_");if(!cookie.get(cookieName)){var xhr=new XMLHttpRequest();xhr.open('GET','/console/version',true);xhr.onload=function(){if(this.readyState==4&&this.status==200){let data=JSON.parse(this.responseText);let text='Appwrite version '+data.version+' is available, check the';if(isNewerVersion(env.VERSION,data.version)){alerts.add({text:text,class:"success",link:"https://github.com/appwrite/appwrite/releases",label:'release notes',callback:function(){cookie.set(cookieName,"true",365*10);}},0);}}};xhr.send(null);function isNewerVersion(oldVer,newVer){const oldParts=oldVer.split('.')
else{document.body.classList.remove('theme-dark');document.body.classList.add('theme-light');window.localStorage.setItem('user-theme','theme-light')}};element.addEventListener("click",function(){toggle();});}});})(window);(function(window){window.ls.container.get("view").add({selector:"data-version",controller:function(alerts,env,cookie){let cookieName="version-update-"+env.VERSION.replace(/\./g,"_");if(!cookie.get(cookieName)){var xhr=new XMLHttpRequest();xhr.open('GET','https://appwrite.io/version',true);xhr.onload=function(){if(this.readyState==4&&this.status==200){let data=JSON.parse(this.responseText);let text='Appwrite version '+data.version+' is available, check the';if(isNewerVersion(env.VERSION,data.version)){alerts.add({text:text,class:"success",link:"https://github.com/appwrite/appwrite/releases",label:'release notes',callback:function(){cookie.set(cookieName,"true",365*10);}},0);}}};xhr.send(null);function isNewerVersion(oldVer,newVer){const oldParts=oldVer.split('.')
const newParts=newVer.split('.')
for(var i=0;i<newParts.length;i++){const a=parseInt(newParts[i])||0
const b=parseInt(oldParts[i])||0

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -183,6 +183,13 @@ window.ls.filter
return $value[$value.length - 1].value;
})
.add("statsGetSum", function ($value) {
if (!$value || $value.length < 1) {
return 0;
}
return $value.reduce(function(value, object) { return value + object.value }, 0);
})
.add("isEmpty", function ($value) {
return (!!$value);
})

View file

@ -7,7 +7,7 @@
if (!cookie.get(cookieName)) {
var xhr = new XMLHttpRequest();
xhr.open('GET', '/console/version', true);
xhr.open('GET', 'https://appwrite.io/version', true);
xhr.onload = function () {
if (this.readyState == 4 && this.status == 200) {

View file

@ -0,0 +1,148 @@
<?php
namespace Appwrite\Auth\OAuth2;
use Appwrite\Auth\OAuth2;
class Notion extends OAuth2
{
/**
* @var string
*/
private $endpoint = 'https://api.notion.com/v1';
/**
* @var string
*/
private $version = '2021-08-16';
/**
* @var array
*/
protected $user = [];
/**
* @var array
*/
protected $scopes = [];
/**
* @return string
*/
public function getName():string
{
return 'notion';
}
/**
* @return string
*/
public function getLoginURL():string
{
return $this->endpoint . '/oauth/authorize?'. \http_build_query([
'client_id' => $this->appID,
'redirect_uri' => $this->callback,
'response_type' => 'code',
'state' => \json_encode($this->state),
'owner' => 'user'
]);
}
/**
* @param string $code
*
* @return string
*/
public function getAccessToken(string $code):string
{
$headers = [
"Authorization: Basic " . \base64_encode($this->appID . ":" . $this->appSecret),
];
$response = $this->request(
'POST',
$this->endpoint . '/oauth/token',
$headers,
\http_build_query([
'grant_type' => 'authorization_code',
'redirect_uri' => $this->callback,
'code' => $code
])
);
$response = \json_decode($response, true);
if (isset($response['access_token'])) {
return $response['access_token'];
}
return '';
}
/**
* @param $accessToken
*
* @return string
*/
public function getUserID(string $accessToken):string
{
$response = $this->getUser($accessToken);
if (isset($response['bot']['owner']['user']['id'])) {
return $response['bot']['owner']['user']['id'];
}
return '';
}
/**
* @param $accessToken
*
* @return string
*/
public function getUserEmail(string $accessToken):string
{
$response = $this->getUser($accessToken);
if(isset($response['bot']['owner']['user']['person']['email'])){
return $response['bot']['owner']['user']['person']['email'];
}
return '';
}
/**
* @param $accessToken
*
* @return string
*/
public function getUserName(string $accessToken):string
{
$response = $this->getUser($accessToken);
if (isset($response['bot']['owner']['user']['name'])) {
return $response['bot']['owner']['user']['name'];
}
return '';
}
/**
* @param string $accessToken
*
* @return array
*/
protected function getUser(string $accessToken)
{
$headers = [
'Notion-Version: ' . $this->version,
'Authorization: Bearer '.\urlencode($accessToken)
];
if (empty($this->user)) {
$this->user = \json_decode($this->request('GET', $this->endpoint . '/users/me', $headers), true);
}
return $this->user;
}
}

View file

@ -66,6 +66,7 @@ abstract class Migration
'0.10.4' => 'V09',
'0.11.0' => 'V10',
'0.12.0' => 'V11',
'0.12.1' => 'V11',
];
/**

View file

@ -194,7 +194,7 @@ class V11 extends Migration
$new = $this->fixDocument($document);
if (empty($new->getId())) {
if (is_null($new) || empty($new->getId())) {
Console::warning('Skipped Document due to missing ID.');
continue;
}
@ -413,10 +413,10 @@ class V11 extends Migration
* Migrates single docuemnt.
*
* @param OldDocument $oldDocument
* @return Document
* @return Document|null
* @throws Exception
*/
protected function fixDocument(OldDocument $oldDocument): Document
protected function fixDocument(OldDocument $oldDocument): Document|null
{
$document = new Document($oldDocument->getArrayCopy());
$document = $this->migratePermissions($document);
@ -487,15 +487,20 @@ class V11 extends Migration
if (!empty($document->getAttribute('usersAuthLimit'))) {
$newAuths['limit'] = $document->getAttribute('usersAuthLimit');
$document->removeAttribute('usersAuthLimit');
}
$document->removeAttribute('usersAuthLimit');
$document->setAttribute('auths', $newProviders);
break;
case OldDatabase::SYSTEM_COLLECTION_PLATFORMS:
$projectId = $this->getProjectIdFromReadPermissions($document);
if (is_null($projectId)) {
return null;
}
/**
* Set Project ID
*/
@ -533,6 +538,10 @@ class V11 extends Migration
case OldDatabase::SYSTEM_COLLECTION_DOMAINS:
$projectId = $this->getProjectIdFromReadPermissions($document);
if (is_null($projectId)) {
return null;
}
/**
* Set Project ID
*/
@ -557,6 +566,10 @@ class V11 extends Migration
case OldDatabase::SYSTEM_COLLECTION_KEYS:
$projectId = $this->getProjectIdFromReadPermissions($document);
if (is_null($projectId)) {
return null;
}
/**
* Set Project ID
*/
@ -585,6 +598,10 @@ class V11 extends Migration
case OldDatabase::SYSTEM_COLLECTION_WEBHOOKS:
$projectId = $this->getProjectIdFromReadPermissions($document);
if (is_null($projectId)) {
return null;
}
/**
* Set Project ID
*/
@ -780,7 +797,7 @@ class V11 extends Migration
}
/**
* @param Document $document
* @param Document $document
* @return string|null
* @throws Exception
*/
@ -788,11 +805,17 @@ class V11 extends Migration
{
$readPermissions = $document->getRead();
$teamId = str_replace('team:', '', reset($readPermissions));
return $this->oldConsoleDB->getCollectionFirst([
$project = $this->oldConsoleDB->getCollectionFirst([
'filters' => [
'$collection=' . OldDatabase::SYSTEM_COLLECTION_PROJECTS,
'teamId=' . $teamId
]
])->getId();
]);
if (!$project) {
return null;
}
return $project->getId();
}
}

View file

@ -141,7 +141,13 @@ class V12 extends Filter
if(isset($usedOperator)) {
[ $attributeKey, $filterValue ] = \explode($usedOperator, $filter);
$filterValue = \is_numeric($filterValue) ? $filterValue : '"' . $filterValue . '"';
if($filterValue === 'true' || $filterValue === 'false') {
// Let's keep it at true and false string, but without "" around
// No action needed
} else {
$filterValue = \is_numeric($filterValue) ? $filterValue : '"' . $filterValue . '"';
}
$query = $attributeKey . '.' . $operators[$usedOperator] . '(' . $filterValue . ')';
\array_push($queries, $query);
}
@ -152,7 +158,6 @@ class V12 extends Filter
unset($content['search']);
unset($content['filters']);
unset($content['search']);
$content['queries'] = $queries;
return $content;

View file

@ -26,6 +26,7 @@ use Appwrite\Utopia\Response\Model\Continent;
use Appwrite\Utopia\Response\Model\Country;
use Appwrite\Utopia\Response\Model\Currency;
use Appwrite\Utopia\Response\Model\Document as ModelDocument;
use Appwrite\Utopia\Response\Model\DocumentList;
use Appwrite\Utopia\Response\Model\Domain;
use Appwrite\Utopia\Response\Model\Error;
use Appwrite\Utopia\Response\Model\ErrorDev;
@ -210,9 +211,9 @@ class Response extends SwooleResponse
->setModel(new Error())
->setModel(new ErrorDev())
// Lists
->setModel(new BaseList('Documents List', self::MODEL_DOCUMENT_LIST, 'documents', self::MODEL_DOCUMENT))
->setModel(new BaseList('Collections List', self::MODEL_COLLECTION_LIST, 'collections', self::MODEL_COLLECTION))
->setModel(new BaseList('Indexes List', self::MODEL_INDEX_LIST, 'indexes', self::MODEL_INDEX))
->setModel(new BaseList('Documents List', self::MODEL_DOCUMENT_LIST, 'documents', self::MODEL_DOCUMENT))
->setModel(new BaseList('Users List', self::MODEL_USER_LIST, 'users', self::MODEL_USER))
->setModel(new BaseList('Sessions List', self::MODEL_SESSION_LIST, 'sessions', self::MODEL_SESSION))
->setModel(new BaseList('Logs List', self::MODEL_LOG_LIST, 'logs', self::MODEL_LOG))
@ -378,13 +379,13 @@ class Response extends SwooleResponse
$model = $this->getModel($model);
$output = [];
$document = $model->filter($document);
if ($model->isAny()) {
$this->payload = $document->getArrayCopy();
return $this->payload;
}
$document = $model->filter($document);
foreach ($model->getRules() as $key => $rule) {
if (!$document->isSet($key) && $rule['require']) { // do not set attribute in response if not required
if (!is_null($rule['default'])) {

View file

@ -13,7 +13,7 @@ class AttributeString extends Attribute
$this
->addRule('size', [
'type' => self::TYPE_STRING,
'type' => self::TYPE_INTEGER,
'description' => 'Attribute size.',
'default' => 0,
'example' => 128,
@ -52,4 +52,4 @@ class AttributeString extends Attribute
{
return Response::MODEL_ATTRIBUTE_STRING;
}
}
}

View file

@ -3,6 +3,7 @@
namespace Appwrite\Utopia\Response\Model;
use Appwrite\Utopia\Response;
use Utopia\Database\Document as DatabaseDocument;
class Document extends Any
{
@ -57,4 +58,11 @@ class Document extends Any
])
;
}
public function filter(DatabaseDocument $document): DatabaseDocument
{
$document->removeAttribute('$internalId');
return $document;
}
}

View file

@ -825,6 +825,9 @@ trait DatabaseBase
$this->assertEquals(1944, $documents['body']['documents'][0]['releaseYear']);
$this->assertEquals(2017, $documents['body']['documents'][1]['releaseYear']);
$this->assertEquals(2019, $documents['body']['documents'][2]['releaseYear']);
$this->assertFalse(array_key_exists('$internalId', $documents['body']['documents'][0]));
$this->assertFalse(array_key_exists('$internalId', $documents['body']['documents'][1]));
$this->assertFalse(array_key_exists('$internalId', $documents['body']['documents'][2]));
$this->assertCount(3, $documents['body']['documents']);
foreach ($documents['body']['documents'] as $document) {
@ -866,6 +869,7 @@ trait DatabaseBase
$this->assertEquals($response['body']['releaseYear'], $document['releaseYear']);
$this->assertEquals($response['body']['$read'], $document['$read']);
$this->assertEquals($response['body']['$write'], $document['$write']);
$this->assertFalse(array_key_exists('$internalId', $response['body']));
}
}