Merge remote-tracking branch 'origin/0.14.x' into fix-wildcard-hostname-new
This commit is contained in:
commit
17b2ab86d8
|
@ -12,7 +12,7 @@ RUN composer install --ignore-platform-reqs --optimize-autoloader \
|
||||||
--no-plugins --no-scripts --prefer-dist \
|
--no-plugins --no-scripts --prefer-dist \
|
||||||
`if [ "$TESTING" != "true" ]; then echo "--no-dev"; fi`
|
`if [ "$TESTING" != "true" ]; then echo "--no-dev"; fi`
|
||||||
|
|
||||||
FROM node:16.13.2-alpine3.15 as node
|
FROM node:16.14.2-alpine3.15 as node
|
||||||
|
|
||||||
WORKDIR /usr/local/src/
|
WORKDIR /usr/local/src/
|
||||||
|
|
||||||
|
@ -30,8 +30,8 @@ ARG DEBUG=false
|
||||||
ENV DEBUG=$DEBUG
|
ENV DEBUG=$DEBUG
|
||||||
|
|
||||||
ENV PHP_REDIS_VERSION=5.3.7 \
|
ENV PHP_REDIS_VERSION=5.3.7 \
|
||||||
PHP_MONGODB_VERSION=1.9.1 \
|
PHP_MONGODB_VERSION=1.13.0 \
|
||||||
PHP_SWOOLE_VERSION=v4.8.7 \
|
PHP_SWOOLE_VERSION=v4.8.9 \
|
||||||
PHP_IMAGICK_VERSION=3.7.0 \
|
PHP_IMAGICK_VERSION=3.7.0 \
|
||||||
PHP_YAML_VERSION=2.2.2 \
|
PHP_YAML_VERSION=2.2.2 \
|
||||||
PHP_MAXMINDDB_VERSION=v1.11.0
|
PHP_MAXMINDDB_VERSION=v1.11.0
|
||||||
|
|
|
@ -2121,7 +2121,7 @@ $collections = [
|
||||||
'filters' => [],
|
'filters' => [],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'$id' => 'stdout',
|
'$id' => 'response',
|
||||||
'type' => Database::VAR_STRING,
|
'type' => Database::VAR_STRING,
|
||||||
'format' => '',
|
'format' => '',
|
||||||
'size' => 16384,
|
'size' => 16384,
|
||||||
|
@ -2425,7 +2425,7 @@ $collections = [
|
||||||
'$id' => 'value',
|
'$id' => 'value',
|
||||||
'type' => Database::VAR_INTEGER,
|
'type' => Database::VAR_INTEGER,
|
||||||
'format' => '',
|
'format' => '',
|
||||||
'size' => 0,
|
'size' => 8,
|
||||||
'signed' => false,
|
'signed' => false,
|
||||||
'required' => true,
|
'required' => true,
|
||||||
'default' => null,
|
'default' => null,
|
||||||
|
|
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
|
@ -838,6 +838,7 @@ App::put('/v1/account/sessions/magic-url')
|
||||||
}
|
}
|
||||||
|
|
||||||
$user
|
$user
|
||||||
|
->setAttribute('emailVerification', true)
|
||||||
->setAttribute('sessions', $session, Document::SET_TYPE_APPEND)
|
->setAttribute('sessions', $session, Document::SET_TYPE_APPEND)
|
||||||
->setAttribute('tokens', $tokens);
|
->setAttribute('tokens', $tokens);
|
||||||
|
|
||||||
|
@ -868,9 +869,7 @@ App::put('/v1/account/sessions/magic-url')
|
||||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||||
;
|
;
|
||||||
|
|
||||||
$countryName = (isset($countries[strtoupper($session->getAttribute('countryCode'))]))
|
$countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'));
|
||||||
? $countries[strtoupper($session->getAttribute('countryCode'))]
|
|
||||||
: $locale->getText('locale.country.unknown');
|
|
||||||
|
|
||||||
$session
|
$session
|
||||||
->setAttribute('current', true)
|
->setAttribute('current', true)
|
||||||
|
@ -1013,9 +1012,7 @@ App::post('/v1/account/sessions/anonymous')
|
||||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||||
;
|
;
|
||||||
|
|
||||||
$countryName = (isset($countries[strtoupper($session->getAttribute('countryCode'))]))
|
$countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'));
|
||||||
? $countries[strtoupper($session->getAttribute('countryCode'))]
|
|
||||||
: $locale->getText('locale.country.unknown');
|
|
||||||
|
|
||||||
$session
|
$session
|
||||||
->setAttribute('current', true)
|
->setAttribute('current', true)
|
||||||
|
@ -1280,15 +1277,13 @@ App::get('/v1/account/sessions/:sessionId')
|
||||||
|
|
||||||
$sessions = $user->getAttribute('sessions', []);
|
$sessions = $user->getAttribute('sessions', []);
|
||||||
$sessionId = ($sessionId === 'current')
|
$sessionId = ($sessionId === 'current')
|
||||||
? Auth::sessionVerify($user->getAttribute('sessions'), Auth::$secret)
|
? Auth::sessionVerify($user->getAttribute('sessions'), Auth::$secret)
|
||||||
: $sessionId;
|
: $sessionId;
|
||||||
|
|
||||||
foreach ($sessions as $session) {/** @var Document $session */
|
foreach ($sessions as $session) {/** @var Document $session */
|
||||||
if ($sessionId == $session->getId()) {
|
if ($sessionId == $session->getId()) {
|
||||||
|
|
||||||
$countryName = (isset($countries[strtoupper($session->getAttribute('countryCode'))]))
|
$countryName = $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'));
|
||||||
? $countries[strtoupper($session->getAttribute('countryCode'))]
|
|
||||||
: $locale->getText('locale.country.unknown');
|
|
||||||
|
|
||||||
$session
|
$session
|
||||||
->setAttribute('current', ($session->getAttribute('secret') == Auth::hash(Auth::$secret)))
|
->setAttribute('current', ($session->getAttribute('secret') == Auth::hash(Auth::$secret)))
|
||||||
|
@ -1622,7 +1617,7 @@ App::delete('/v1/account/sessions/:sessionId')
|
||||||
if ($session->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete the cookies too
|
if ($session->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete the cookies too
|
||||||
$session
|
$session
|
||||||
->setAttribute('current', true)
|
->setAttribute('current', true)
|
||||||
->setAttribute('countryName', (isset($countries[strtoupper($session->getAttribute('countryCode'))])) ? $countries[strtoupper($session->getAttribute('countryCode'))] : $locale->getText('locale.country.unknown'))
|
->setAttribute('countryName', $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')))
|
||||||
;
|
;
|
||||||
|
|
||||||
if (!Config::getParam('domainVerification')) {
|
if (!Config::getParam('domainVerification')) {
|
||||||
|
@ -1806,7 +1801,7 @@ App::delete('/v1/account/sessions')
|
||||||
|
|
||||||
$session
|
$session
|
||||||
->setAttribute('current', false)
|
->setAttribute('current', false)
|
||||||
->setAttribute('countryName', (isset($countries[strtoupper($session->getAttribute('countryCode'))])) ? $countries[strtoupper($session->getAttribute('countryCode'))] : $locale->getText('locale.country.unknown'))
|
->setAttribute('countryName', $locale->getText('countries.'.strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')))
|
||||||
;
|
;
|
||||||
|
|
||||||
if ($session->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete the cookies too
|
if ($session->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete the cookies too
|
||||||
|
|
|
@ -145,8 +145,8 @@ App::get('/v1/avatars/image')
|
||||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||||
->label('sdk.response.type', Response::CONTENT_TYPE_IMAGE)
|
->label('sdk.response.type', Response::CONTENT_TYPE_IMAGE)
|
||||||
->param('url', '', new URL(['http', 'https']), 'Image URL which you want to crop.')
|
->param('url', '', new URL(['http', 'https']), 'Image URL which you want to crop.')
|
||||||
->param('width', 400, new Range(0, 2000), 'Resize preview image width, Pass an integer between 0 to 2000.', true)
|
->param('width', 400, new Range(0, 2000), 'Resize preview image width, Pass an integer between 0 to 2000. Defaults to 400.', true)
|
||||||
->param('height', 400, new Range(0, 2000), 'Resize preview image height, Pass an integer between 0 to 2000.', true)
|
->param('height', 400, new Range(0, 2000), 'Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.', true)
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->action(function ($url, $width, $height, $response) {
|
->action(function ($url, $width, $height, $response) {
|
||||||
/** @var Appwrite\Utopia\Response $response */
|
/** @var Appwrite\Utopia\Response $response */
|
||||||
|
@ -367,7 +367,7 @@ App::get('/v1/avatars/qr')
|
||||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||||
->label('sdk.response.type', Response::CONTENT_TYPE_IMAGE_PNG)
|
->label('sdk.response.type', Response::CONTENT_TYPE_IMAGE_PNG)
|
||||||
->param('text', '', new Text(512), 'Plain text to be converted to QR code image.')
|
->param('text', '', new Text(512), 'Plain text to be converted to QR code image.')
|
||||||
->param('size', 400, new Range(0, 1000), 'QR code size. Pass an integer between 0 to 1000. Defaults to 400.', true)
|
->param('size', 400, new Range(1, 1000), 'QR code size. Pass an integer between 1 to 1000. Defaults to 400.', true)
|
||||||
->param('margin', 1, new Range(0, 10), 'Margin from edge. Pass an integer between 0 to 10. Defaults to 1.', true)
|
->param('margin', 1, new Range(0, 10), 'Margin from edge. Pass an integer between 0 to 10. Defaults to 1.', true)
|
||||||
->param('download', false, new Boolean(true), 'Return resulting image with \'Content-Disposition: attachment \' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.', true)
|
->param('download', false, new Boolean(true), 'Return resulting image with \'Content-Disposition: attachment \' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.', true)
|
||||||
->inject('response')
|
->inject('response')
|
||||||
|
|
|
@ -19,7 +19,6 @@ use Utopia\Database\Validator\Authorization;
|
||||||
use Utopia\Database\Validator\Key;
|
use Utopia\Database\Validator\Key;
|
||||||
use Utopia\Database\Validator\Permissions;
|
use Utopia\Database\Validator\Permissions;
|
||||||
use Utopia\Database\Validator\QueryValidator;
|
use Utopia\Database\Validator\QueryValidator;
|
||||||
use Utopia\Database\Validator\Queries as QueriesValidator;
|
|
||||||
use Utopia\Database\Validator\Structure;
|
use Utopia\Database\Validator\Structure;
|
||||||
use Utopia\Database\Validator\UID;
|
use Utopia\Database\Validator\UID;
|
||||||
use Utopia\Database\Exception\Authorization as AuthorizationException;
|
use Utopia\Database\Exception\Authorization as AuthorizationException;
|
||||||
|
@ -31,6 +30,8 @@ use Appwrite\Network\Validator\Email;
|
||||||
use Appwrite\Network\Validator\IP;
|
use Appwrite\Network\Validator\IP;
|
||||||
use Appwrite\Network\Validator\URL;
|
use Appwrite\Network\Validator\URL;
|
||||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||||
|
use Appwrite\Utopia\Database\Validator\Queries as QueriesValidator;
|
||||||
|
use Appwrite\Utopia\Database\Validator\OrderAttributes as OrderAttributesValidator;
|
||||||
use Appwrite\Utopia\Response;
|
use Appwrite\Utopia\Response;
|
||||||
use Appwrite\Detector\Detector;
|
use Appwrite\Detector\Detector;
|
||||||
use Appwrite\Event\Event;
|
use Appwrite\Event\Event;
|
||||||
|
@ -1742,6 +1743,13 @@ App::get('/v1/database/collections/:collectionId/documents')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!empty($orderAttributes)) {
|
||||||
|
$validator = new OrderAttributesValidator($collection->getAttribute('attributes', []), $collection->getAttribute('indexes', []), true);
|
||||||
|
if (!$validator->isValid($orderAttributes)) {
|
||||||
|
throw new Exception($validator->getDescription(), 400, Exception::GENERAL_QUERY_INVALID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$cursorDocument = null;
|
$cursorDocument = null;
|
||||||
if (!empty($cursor)) {
|
if (!empty($cursor)) {
|
||||||
$cursorDocument = $collection->getAttribute('permission') === 'collection'
|
$cursorDocument = $collection->getAttribute('permission') === 'collection'
|
||||||
|
|
|
@ -880,7 +880,7 @@ App::post('/v1/functions/:functionId/executions')
|
||||||
'trigger' => 'http', // http / schedule / event
|
'trigger' => 'http', // http / schedule / event
|
||||||
'status' => 'waiting', // waiting / processing / completed / failed
|
'status' => 'waiting', // waiting / processing / completed / failed
|
||||||
'statusCode' => 0,
|
'statusCode' => 0,
|
||||||
'stdout' => '',
|
'response' => '',
|
||||||
'stderr' => '',
|
'stderr' => '',
|
||||||
'time' => 0.0,
|
'time' => 0.0,
|
||||||
'search' => implode(' ', [$functionId, $executionId]),
|
'search' => implode(' ', [$functionId, $executionId]),
|
||||||
|
@ -956,7 +956,7 @@ App::post('/v1/functions/:functionId/executions')
|
||||||
/** Update execution status */
|
/** Update execution status */
|
||||||
$execution->setAttribute('status', $executionResponse['status']);
|
$execution->setAttribute('status', $executionResponse['status']);
|
||||||
$execution->setAttribute('statusCode', $executionResponse['statusCode']);
|
$execution->setAttribute('statusCode', $executionResponse['statusCode']);
|
||||||
$execution->setAttribute('stdout', $executionResponse['stdout']);
|
$execution->setAttribute('response', $executionResponse['response']);
|
||||||
$execution->setAttribute('stderr', $executionResponse['stderr']);
|
$execution->setAttribute('stderr', $executionResponse['stderr']);
|
||||||
$execution->setAttribute('time', $executionResponse['time']);
|
$execution->setAttribute('time', $executionResponse['time']);
|
||||||
} catch (\Throwable $th) {
|
} catch (\Throwable $th) {
|
||||||
|
|
|
@ -214,24 +214,6 @@ App::get('/v1/health/queue/logs')
|
||||||
$response->dynamic(new Document([ 'size' => Resque::size(Event::AUDITS_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE);
|
$response->dynamic(new Document([ 'size' => Resque::size(Event::AUDITS_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE);
|
||||||
}, ['response']);
|
}, ['response']);
|
||||||
|
|
||||||
App::get('/v1/health/queue/usage')
|
|
||||||
->desc('Get Usage Queue')
|
|
||||||
->groups(['api', 'health'])
|
|
||||||
->label('scope', 'health.read')
|
|
||||||
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
|
|
||||||
->label('sdk.namespace', 'health')
|
|
||||||
->label('sdk.method', 'getQueueUsage')
|
|
||||||
->label('sdk.description', '/docs/references/health/get-queue-usage.md')
|
|
||||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
|
||||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
|
||||||
->label('sdk.response.model', Response::MODEL_HEALTH_QUEUE)
|
|
||||||
->inject('response')
|
|
||||||
->action(function ($response) {
|
|
||||||
/** @var Appwrite\Utopia\Response $response */
|
|
||||||
|
|
||||||
$response->dynamic(new Document([ 'size' => Resque::size(Event::USAGE_QUEUE_NAME) ]), Response::MODEL_HEALTH_QUEUE);
|
|
||||||
}, ['response']);
|
|
||||||
|
|
||||||
App::get('/v1/health/queue/certificates')
|
App::get('/v1/health/queue/certificates')
|
||||||
->desc('Get Certificates Queue')
|
->desc('Get Certificates Queue')
|
||||||
->groups(['api', 'health'])
|
->groups(['api', 'health'])
|
||||||
|
|
|
@ -77,6 +77,9 @@ App::post('/v1/projects')
|
||||||
}
|
}
|
||||||
|
|
||||||
$projectId = ($projectId == 'unique()') ? $dbForConsole->getId() : $projectId;
|
$projectId = ($projectId == 'unique()') ? $dbForConsole->getId() : $projectId;
|
||||||
|
if($projectId === 'console') {
|
||||||
|
throw new Exception("'console' is a reserved project.", 400, Exception::PROJECT_RESERVED_PROJECT);
|
||||||
|
}
|
||||||
$project = $dbForConsole->createDocument('projects', new Document([
|
$project = $dbForConsole->createDocument('projects', new Document([
|
||||||
'$id' => $projectId == 'unique()' ? $dbForConsole->getId() : $projectId,
|
'$id' => $projectId == 'unique()' ? $dbForConsole->getId() : $projectId,
|
||||||
'$read' => ['team:' . $teamId],
|
'$read' => ['team:' . $teamId],
|
||||||
|
|
|
@ -9,6 +9,7 @@ use Appwrite\Utopia\Database\Validator\CustomId;
|
||||||
use Appwrite\Utopia\Response;
|
use Appwrite\Utopia\Response;
|
||||||
use Utopia\App;
|
use Utopia\App;
|
||||||
use Appwrite\Extend\Exception;
|
use Appwrite\Extend\Exception;
|
||||||
|
use Utopia\Audit\Audit;
|
||||||
use Utopia\Config\Config;
|
use Utopia\Config\Config;
|
||||||
use Utopia\Database\Database;
|
use Utopia\Database\Database;
|
||||||
use Utopia\Database\Document;
|
use Utopia\Database\Document;
|
||||||
|
@ -42,11 +43,13 @@ App::post('/v1/teams')
|
||||||
->inject('user')
|
->inject('user')
|
||||||
->inject('dbForProject')
|
->inject('dbForProject')
|
||||||
->inject('events')
|
->inject('events')
|
||||||
->action(function ($teamId, $name, $roles, $response, $user, $dbForProject, $events) {
|
->inject('audits')
|
||||||
|
->action(function ($teamId, $name, $roles, $response, $user, $dbForProject, $events, $audits) {
|
||||||
/** @var Appwrite\Utopia\Response $response */
|
/** @var Appwrite\Utopia\Response $response */
|
||||||
/** @var Utopia\Database\Document $user */
|
/** @var Utopia\Database\Document $user */
|
||||||
/** @var Utopia\Database\Database $dbForProject */
|
/** @var Utopia\Database\Database $dbForProject */
|
||||||
/** @var Appwrite\Event\Event $events */
|
/** @var Appwrite\Event\Event $events */
|
||||||
|
/** @var Appwrite\Event\Event $audits */
|
||||||
|
|
||||||
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
|
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
|
||||||
$isAppUser = Auth::isAppUser(Authorization::getRoles());
|
$isAppUser = Auth::isAppUser(Authorization::getRoles());
|
||||||
|
@ -89,6 +92,12 @@ App::post('/v1/teams')
|
||||||
$events->setParam('userId', $user->getId());
|
$events->setParam('userId', $user->getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$audits
|
||||||
|
->setParam('event', 'teams.create')
|
||||||
|
->setParam('resource', 'team/'.$teamId)
|
||||||
|
->setParam('data', $team->getArrayCopy())
|
||||||
|
;
|
||||||
|
|
||||||
$response->setStatusCode(Response::STATUS_CODE_CREATED);
|
$response->setStatusCode(Response::STATUS_CODE_CREATED);
|
||||||
$response->dynamic($team, Response::MODEL_TEAM);
|
$response->dynamic($team, Response::MODEL_TEAM);
|
||||||
});
|
});
|
||||||
|
@ -182,9 +191,11 @@ App::put('/v1/teams/:teamId')
|
||||||
->param('name', null, new Text(128), 'New team name. Max length: 128 chars.')
|
->param('name', null, new Text(128), 'New team name. Max length: 128 chars.')
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->inject('dbForProject')
|
->inject('dbForProject')
|
||||||
->action(function ($teamId, $name, $response, $dbForProject) {
|
->inject('audits')
|
||||||
|
->action(function ($teamId, $name, $response, $dbForProject, $audits) {
|
||||||
/** @var Appwrite\Utopia\Response $response */
|
/** @var Appwrite\Utopia\Response $response */
|
||||||
/** @var Utopia\Database\Database $dbForProject */
|
/** @var Utopia\Database\Database $dbForProject */
|
||||||
|
/** @var Appwrite\Event\Event $audits */
|
||||||
|
|
||||||
$team = $dbForProject->getDocument('teams', $teamId);
|
$team = $dbForProject->getDocument('teams', $teamId);
|
||||||
|
|
||||||
|
@ -197,6 +208,12 @@ App::put('/v1/teams/:teamId')
|
||||||
->setAttribute('search', implode(' ', [$teamId, $name]))
|
->setAttribute('search', implode(' ', [$teamId, $name]))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$audits
|
||||||
|
->setParam('event', 'teams.update')
|
||||||
|
->setParam('resource', 'team/'.$teamId)
|
||||||
|
->setParam('data', $team->getArrayCopy())
|
||||||
|
;
|
||||||
|
|
||||||
$response->dynamic($team, Response::MODEL_TEAM);
|
$response->dynamic($team, Response::MODEL_TEAM);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -216,11 +233,13 @@ App::delete('/v1/teams/:teamId')
|
||||||
->inject('dbForProject')
|
->inject('dbForProject')
|
||||||
->inject('events')
|
->inject('events')
|
||||||
->inject('deletes')
|
->inject('deletes')
|
||||||
->action(function ($teamId, $response, $dbForProject, $events, $deletes) {
|
->inject('audits')
|
||||||
|
->action(function ($teamId, $response, $dbForProject, $events, $deletes, $audits) {
|
||||||
/** @var Appwrite\Utopia\Response $response */
|
/** @var Appwrite\Utopia\Response $response */
|
||||||
/** @var Utopia\Database\Database $dbForProject */
|
/** @var Utopia\Database\Database $dbForProject */
|
||||||
/** @var Appwrite\Event\Event $events */
|
/** @var Appwrite\Event\Event $events */
|
||||||
/** @var Appwrite\Event\Event $deletes */
|
/** @var Appwrite\Event\Event $deletes */
|
||||||
|
/** @var Appwrite\Event\Event $audits */
|
||||||
|
|
||||||
$team = $dbForProject->getDocument('teams', $teamId);
|
$team = $dbForProject->getDocument('teams', $teamId);
|
||||||
|
|
||||||
|
@ -252,6 +271,12 @@ App::delete('/v1/teams/:teamId')
|
||||||
->setParam('eventData', $response->output($team, Response::MODEL_TEAM))
|
->setParam('eventData', $response->output($team, Response::MODEL_TEAM))
|
||||||
;
|
;
|
||||||
|
|
||||||
|
$audits
|
||||||
|
->setParam('event', 'teams.delete')
|
||||||
|
->setParam('resource', 'team/'.$teamId)
|
||||||
|
->setParam('data', $team->getArrayCopy())
|
||||||
|
;
|
||||||
|
|
||||||
$response->noContent();
|
$response->noContent();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -845,3 +870,88 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId')
|
||||||
|
|
||||||
$response->noContent();
|
$response->noContent();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
App::get('/v1/teams/:teamId/logs')
|
||||||
|
->desc('List Team Logs')
|
||||||
|
->groups(['api', 'teams'])
|
||||||
|
->label('scope', 'teams.read')
|
||||||
|
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
||||||
|
->label('sdk.namespace', 'teams')
|
||||||
|
->label('sdk.method', 'listLogs')
|
||||||
|
->label('sdk.description', '/docs/references/teams/get-team-logs.md')
|
||||||
|
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||||
|
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||||
|
->label('sdk.response.model', Response::MODEL_LOG_LIST)
|
||||||
|
->param('teamId', null, new UID(), 'Team ID.')
|
||||||
|
->param('limit', 25, new Range(0, 100), 'Maximum number of logs to return in response. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
|
||||||
|
->param('offset', 0, new Range(0, APP_LIMIT_COUNT), 'Offset value. The default value is 0. Use this value to manage pagination. [learn more about pagination](https://appwrite.io/docs/pagination)', true)
|
||||||
|
->inject('response')
|
||||||
|
->inject('dbForProject')
|
||||||
|
->inject('locale')
|
||||||
|
->inject('geodb')
|
||||||
|
->action(function ($teamId, $limit, $offset, $response, $dbForProject, $locale, $geodb) {
|
||||||
|
/** @var Appwrite\Utopia\Response $response */
|
||||||
|
/** @var Utopia\Database\Document $project */
|
||||||
|
/** @var Utopia\Database\Database $dbForProject */
|
||||||
|
/** @var Utopia\Locale\Locale $locale */
|
||||||
|
/** @var MaxMind\Db\Reader $geodb */
|
||||||
|
|
||||||
|
$team = $dbForProject->getDocument('teams', $teamId);
|
||||||
|
|
||||||
|
if ($team->isEmpty()) {
|
||||||
|
throw new Exception('Team not found', 404, Exception::TEAM_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
$audit = new Audit($dbForProject);
|
||||||
|
$resource = 'team/'.$team->getId();
|
||||||
|
$logs = $audit->getLogsByResource($resource, $limit, $offset);
|
||||||
|
|
||||||
|
$output = [];
|
||||||
|
|
||||||
|
foreach ($logs as $i => &$log) {
|
||||||
|
$log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN';
|
||||||
|
|
||||||
|
$detector = new Detector($log['userAgent']);
|
||||||
|
$detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then)
|
||||||
|
|
||||||
|
$os = $detector->getOS();
|
||||||
|
$client = $detector->getClient();
|
||||||
|
$device = $detector->getDevice();
|
||||||
|
|
||||||
|
$output[$i] = new Document([
|
||||||
|
'event' => $log['event'],
|
||||||
|
'userId' => $log['userId'],
|
||||||
|
'userEmail' => $log['data']['userEmail'] ?? null,
|
||||||
|
'userName' => $log['data']['userName'] ?? null,
|
||||||
|
'mode' => $log['data']['mode'] ?? null,
|
||||||
|
'ip' => $log['ip'],
|
||||||
|
'time' => $log['time'],
|
||||||
|
'osCode' => $os['osCode'],
|
||||||
|
'osName' => $os['osName'],
|
||||||
|
'osVersion' => $os['osVersion'],
|
||||||
|
'clientType' => $client['clientType'],
|
||||||
|
'clientCode' => $client['clientCode'],
|
||||||
|
'clientName' => $client['clientName'],
|
||||||
|
'clientVersion' => $client['clientVersion'],
|
||||||
|
'clientEngine' => $client['clientEngine'],
|
||||||
|
'clientEngineVersion' => $client['clientEngineVersion'],
|
||||||
|
'deviceName' => $device['deviceName'],
|
||||||
|
'deviceBrand' => $device['deviceBrand'],
|
||||||
|
'deviceModel' => $device['deviceModel']
|
||||||
|
]);
|
||||||
|
|
||||||
|
$record = $geodb->get($log['ip']);
|
||||||
|
|
||||||
|
if ($record) {
|
||||||
|
$output[$i]['countryCode'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--';
|
||||||
|
$output[$i]['countryName'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown'));
|
||||||
|
} else {
|
||||||
|
$output[$i]['countryCode'] = '--';
|
||||||
|
$output[$i]['countryName'] = $locale->getText('locale.country.unknown');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$response->dynamic(new Document([
|
||||||
|
'total' => $audit->countLogsByResource($resource),
|
||||||
|
'logs' => $output,
|
||||||
|
]), Response::MODEL_LOG_LIST);
|
||||||
|
});
|
||||||
|
|
|
@ -453,7 +453,12 @@ App::patch('/v1/users/:userId/name')
|
||||||
throw new Exception('User not found', 404, Exception::USER_NOT_FOUND);
|
throw new Exception('User not found', 404, Exception::USER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('name', $name));
|
$user
|
||||||
|
->setAttribute('name', $name)
|
||||||
|
->setAttribute('search', \implode(' ', [$user->getId(), $user->getAttribute('email'), $name]));
|
||||||
|
;
|
||||||
|
|
||||||
|
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
|
||||||
|
|
||||||
$audits
|
$audits
|
||||||
->setParam('userId', $user->getId())
|
->setParam('userId', $user->getId())
|
||||||
|
@ -542,8 +547,13 @@ App::patch('/v1/users/:userId/email')
|
||||||
|
|
||||||
$email = \strtolower($email);
|
$email = \strtolower($email);
|
||||||
|
|
||||||
|
$user
|
||||||
|
->setAttribute('email', $email)
|
||||||
|
->setAttribute('search', \implode(' ', [$user->getId(), $email, $user->getAttribute('name')]))
|
||||||
|
;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('email', $email));
|
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
|
||||||
} catch(Duplicate $th) {
|
} catch(Duplicate $th) {
|
||||||
throw new Exception('Email already exists', 409, Exception::USER_EMAIL_ALREADY_EXISTS);
|
throw new Exception('Email already exists', 409, Exception::USER_EMAIL_ALREADY_EXISTS);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ use Appwrite\Extend\Exception;
|
||||||
use Utopia\Config\Config;
|
use Utopia\Config\Config;
|
||||||
use Utopia\Domains\Domain;
|
use Utopia\Domains\Domain;
|
||||||
use Appwrite\Auth\Auth;
|
use Appwrite\Auth\Auth;
|
||||||
|
use Appwrite\Event\Event;
|
||||||
use Appwrite\Network\Validator\Origin;
|
use Appwrite\Network\Validator\Origin;
|
||||||
use Appwrite\Utopia\Response\Filters\V11 as ResponseV11;
|
use Appwrite\Utopia\Response\Filters\V11 as ResponseV11;
|
||||||
use Appwrite\Utopia\Response\Filters\V12 as ResponseV12;
|
use Appwrite\Utopia\Response\Filters\V12 as ResponseV12;
|
||||||
|
@ -74,33 +75,44 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons
|
||||||
} else {
|
} else {
|
||||||
Authorization::disable();
|
Authorization::disable();
|
||||||
|
|
||||||
$domainDocument = $dbForConsole->findOne('domains', [
|
$mainDomain = null;
|
||||||
new Query('domain', QUERY::TYPE_EQUAL, [$domain->get()])
|
if(!empty(App::getEnv('_APP_DOMAIN', ''))) {
|
||||||
]);
|
$mainDomain = App::getEnv('_APP_DOMAIN', '');
|
||||||
|
} else {
|
||||||
|
$domainDocument = $dbForConsole->findOne('domains', [], 0, ['_id'], ['ASC']);
|
||||||
|
$mainDomain = $domainDocument ? $domainDocument->getAttribute('domain') : $domain->get();
|
||||||
|
}
|
||||||
|
|
||||||
if (!$domainDocument) {
|
if($mainDomain !== $domain->get()) {
|
||||||
$domainDocument = new Document([
|
Console::warning($domain->get() . ' is not a main domain. Skipping SSL certificate generation.');
|
||||||
'domain' => $domain->get(),
|
} else {
|
||||||
'tld' => $domain->getSuffix(),
|
$domainDocument = $dbForConsole->findOne('domains', [
|
||||||
'registerable' => $domain->getRegisterable(),
|
new Query('domain', QUERY::TYPE_EQUAL, [$domain->get()])
|
||||||
'verification' => false,
|
|
||||||
'certificateId' => null,
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$domainDocument = $dbForConsole->createDocument('domains', $domainDocument);
|
if (!$domainDocument) {
|
||||||
|
$domainDocument = new Document([
|
||||||
|
'domain' => $domain->get(),
|
||||||
|
'tld' => $domain->getSuffix(),
|
||||||
|
'registerable' => $domain->getRegisterable(),
|
||||||
|
'verification' => false,
|
||||||
|
'certificateId' => null,
|
||||||
|
]);
|
||||||
|
|
||||||
Console::info('Issuing a TLS certificate for the master domain (' . $domain->get() . ') in a few seconds...');
|
$domainDocument = $dbForConsole->createDocument('domains', $domainDocument);
|
||||||
|
|
||||||
Resque::enqueue('v1-certificates', 'CertificatesV1', [
|
Console::info('Issuing a TLS certificate for the main domain (' . $domain->get() . ') in a few seconds...');
|
||||||
'document' => $domainDocument,
|
|
||||||
'domain' => $domain->get(),
|
Resque::enqueue(Event::CERTIFICATES_QUEUE_NAME, Event::CERTIFICATES_CLASS_NAME, [
|
||||||
'validateTarget' => false,
|
'document' => $domainDocument,
|
||||||
'validateCNAME' => false,
|
'domain' => $domain->get(),
|
||||||
]);
|
'validateTarget' => false,
|
||||||
|
'validateCNAME' => false,
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$domains[$domain->get()] = true;
|
$domains[$domain->get()] = true;
|
||||||
|
|
||||||
Authorization::reset(); // ensure authorization is re-enabled
|
Authorization::reset(); // ensure authorization is re-enabled
|
||||||
}
|
}
|
||||||
Config::setParam('domains', $domains);
|
Config::setParam('domains', $domains);
|
||||||
|
|
|
@ -1,90 +0,0 @@
|
||||||
CREATE DATABASE IF NOT EXISTS `appwrite` /*!40100 DEFAULT CHARACTER SET utf8mb4 */;
|
|
||||||
|
|
||||||
USE `appwrite`;
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `template.abuse.abuse` (
|
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
||||||
`_key` varchar(255) NOT NULL,
|
|
||||||
`_time` int(11) NOT NULL,
|
|
||||||
`_count` int(11) NOT NULL DEFAULT '0',
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
UNIQUE KEY `unique1` (`_key`,`_time`),
|
|
||||||
KEY `index1` (`_key`,`_time`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `template.audit.audit` (
|
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
||||||
`userId` varchar(45) NOT NULL,
|
|
||||||
`event` varchar(45) NOT NULL,
|
|
||||||
`resource` varchar(45) DEFAULT NULL,
|
|
||||||
`userAgent` text NOT NULL,
|
|
||||||
`ip` varchar(45) NOT NULL,
|
|
||||||
`location` varchar(45) DEFAULT NULL,
|
|
||||||
`time` datetime NOT NULL,
|
|
||||||
`data` longtext DEFAULT NULL,
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
UNIQUE KEY `id_UNIQUE` (`id`),
|
|
||||||
KEY `index_1` (`userId`),
|
|
||||||
KEY `index_2` (`event`),
|
|
||||||
KEY `index_3` (`resource`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `template.database.documents` (
|
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Unique ID for each node',
|
|
||||||
`uid` varchar(45) DEFAULT NULL,
|
|
||||||
`status` int(11) NOT NULL DEFAULT 0,
|
|
||||||
`createdAt` datetime DEFAULT NULL,
|
|
||||||
`updatedAt` datetime DEFAULT NULL,
|
|
||||||
`signature` varchar(32) NOT NULL,
|
|
||||||
`revision` varchar(45) NOT NULL,
|
|
||||||
`permissions` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
UNIQUE KEY `id_UNIQUE` (`id`),
|
|
||||||
UNIQUE KEY `index2` (`uid`),
|
|
||||||
KEY `index3` (`signature`,`uid`,`revision`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `template.database.properties` (
|
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Primary Key',
|
|
||||||
`documentUid` varchar(45) NOT NULL COMMENT 'Unique UID foreign key',
|
|
||||||
`documentRevision` varchar(45) NOT NULL,
|
|
||||||
`key` varchar(32) NOT NULL COMMENT 'Property key name',
|
|
||||||
`value` text NOT NULL COMMENT 'Value of property',
|
|
||||||
`primitive` varchar(32) NOT NULL COMMENT 'Primitive type of property value',
|
|
||||||
`array` tinyint(4) NOT NULL DEFAULT 0,
|
|
||||||
`order` int(11) NOT NULL,
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
KEY `index1` (`documentUid`),
|
|
||||||
KEY `index2` (`key`,`value`(5)),
|
|
||||||
FULLTEXT KEY `index3` (`value`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `template.database.relationships` (
|
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
||||||
`revision` varchar(45) NOT NULL,
|
|
||||||
`start` varchar(45) NOT NULL COMMENT 'Unique UID foreign key',
|
|
||||||
`end` varchar(45) NOT NULL COMMENT 'Unique UID foreign key',
|
|
||||||
`key` varchar(256) NOT NULL,
|
|
||||||
`path` int(11) NOT NULL DEFAULT 0,
|
|
||||||
`array` tinyint(4) NOT NULL DEFAULT 0,
|
|
||||||
`order` int(11) NOT NULL DEFAULT 0,
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
KEY `relationships_start_nodes_id_idx` (`start`),
|
|
||||||
KEY `relationships_end_nodes_id_idx` (`end`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `template.database.unique` (
|
|
||||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
|
||||||
`key` varchar(128) DEFAULT NULL,
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
UNIQUE KEY `index1` (`key`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
||||||
|
|
||||||
/* Default App */
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `app_console.database.documents` LIKE `template.database.documents`;
|
|
||||||
CREATE TABLE IF NOT EXISTS `app_console.database.properties` LIKE `template.database.properties`;
|
|
||||||
CREATE TABLE IF NOT EXISTS `app_console.database.relationships` LIKE `template.database.relationships`;
|
|
||||||
CREATE TABLE IF NOT EXISTS `app_console.database.unique` LIKE `template.database.unique`;
|
|
||||||
CREATE TABLE IF NOT EXISTS `app_console.audit.audit` LIKE `template.audit.audit`;
|
|
||||||
CREATE TABLE IF NOT EXISTS `app_console.abuse.abuse` LIKE `template.abuse.abuse`;
|
|
|
@ -279,7 +279,7 @@ App::post('/v1/runtimes')
|
||||||
$endTime = \time();
|
$endTime = \time();
|
||||||
$container = array_merge($container, [
|
$container = array_merge($container, [
|
||||||
'status' => 'ready',
|
'status' => 'ready',
|
||||||
'stdout' => \utf8_encode($stdout),
|
'response' => \utf8_encode($stdout),
|
||||||
'stderr' => \utf8_encode($stderr),
|
'stderr' => \utf8_encode($stderr),
|
||||||
'startTime' => $startTime,
|
'startTime' => $startTime,
|
||||||
'endTime' => $endTime,
|
'endTime' => $endTime,
|
||||||
|
@ -408,7 +408,7 @@ App::post('/v1/execution')
|
||||||
->desc('Create an execution')
|
->desc('Create an execution')
|
||||||
->param('runtimeId', '', new Text(64), 'The runtimeID to execute')
|
->param('runtimeId', '', new Text(64), 'The runtimeID to execute')
|
||||||
->param('vars', [], new Assoc(), 'Environment variables required for the build')
|
->param('vars', [], new Assoc(), 'Environment variables required for the build')
|
||||||
->param('data', '{}', new Text(8192), 'Data to be forwarded to the function, this is user specified.', true)
|
->param('data', '', new Text(8192), 'Data to be forwarded to the function, this is user specified.', true)
|
||||||
->param('timeout', 15, new Range(1, (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)), 'Function maximum execution time in seconds.')
|
->param('timeout', 15, new Range(1, (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)), 'Function maximum execution time in seconds.')
|
||||||
->inject('activeRuntimes')
|
->inject('activeRuntimes')
|
||||||
->inject('response')
|
->inject('response')
|
||||||
|
@ -512,7 +512,7 @@ App::post('/v1/execution')
|
||||||
$execution = [
|
$execution = [
|
||||||
'status' => $functionStatus,
|
'status' => $functionStatus,
|
||||||
'statusCode' => $statusCode,
|
'statusCode' => $statusCode,
|
||||||
'stdout' => \utf8_encode(\mb_substr($stdout, -16384)),
|
'response' => \utf8_encode(\mb_substr($stdout, -16384)),
|
||||||
'stderr' => \utf8_encode(\mb_substr($stderr, -16384)),
|
'stderr' => \utf8_encode(\mb_substr($stderr, -16384)),
|
||||||
'time' => $executionTime,
|
'time' => $executionTime,
|
||||||
];
|
];
|
||||||
|
|
|
@ -181,7 +181,7 @@ if(!empty($user) || !empty($pass)) {
|
||||||
*/
|
*/
|
||||||
Database::addFilter('casting',
|
Database::addFilter('casting',
|
||||||
function($value) {
|
function($value) {
|
||||||
return json_encode(['value' => $value]);
|
return json_encode(['value' => $value], JSON_PRESERVE_ZERO_FRACTION);
|
||||||
},
|
},
|
||||||
function($value) {
|
function($value) {
|
||||||
if (is_null($value)) {
|
if (is_null($value)) {
|
||||||
|
|
|
@ -163,28 +163,6 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume
|
||||||
* Save current connections to the Database every 5 seconds.
|
* Save current connections to the Database every 5 seconds.
|
||||||
*/
|
*/
|
||||||
Timer::tick(5000, function () use ($register, $stats, &$statsDocument, $logError) {
|
Timer::tick(5000, function () use ($register, $stats, &$statsDocument, $logError) {
|
||||||
/** @var Document $statsDocument */
|
|
||||||
foreach ($stats as $projectId => $value) {
|
|
||||||
$connections = $stats->get($projectId, 'connections') ?? 0;
|
|
||||||
$messages = $stats->get($projectId, 'messages' ?? 0);
|
|
||||||
|
|
||||||
$usage = new Event('v1-usage', 'UsageV1');
|
|
||||||
$usage
|
|
||||||
->setParam('projectId', $projectId)
|
|
||||||
->setParam('realtimeConnections', $connections)
|
|
||||||
->setParam('realtimeMessages', $messages)
|
|
||||||
->setParam('networkRequestSize', 0)
|
|
||||||
->setParam('networkResponseSize', 0);
|
|
||||||
|
|
||||||
$stats->set($projectId, [
|
|
||||||
'messages' => 0,
|
|
||||||
'connections' => 0
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
|
|
||||||
$usage->trigger();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$payload = [];
|
$payload = [];
|
||||||
foreach ($stats as $projectId => $value) {
|
foreach ($stats as $projectId => $value) {
|
||||||
$payload[$projectId] = $stats->get($projectId, 'connectionsTotal');
|
$payload[$projectId] = $stats->get($projectId, 'connectionsTotal');
|
||||||
|
|
|
@ -418,7 +418,7 @@ $cli
|
||||||
|
|
||||||
// Get total storage
|
// Get total storage
|
||||||
$dbForProject->setNamespace('_' . $projectId);
|
$dbForProject->setNamespace('_' . $projectId);
|
||||||
$storageTotal = $dbForProject->sum('deployments', 'size');
|
$deploymentsTotal = $dbForProject->sum('deployments', 'size');
|
||||||
|
|
||||||
$time = (int) (floor(time() / 1800) * 1800); // Time rounded to nearest 30 minutes
|
$time = (int) (floor(time() / 1800) * 1800); // Time rounded to nearest 30 minutes
|
||||||
$id = \md5($time . '_30m_storage.deployments.total'); //Construct unique id for each metric using time, period and metric
|
$id = \md5($time . '_30m_storage.deployments.total'); //Construct unique id for each metric using time, period and metric
|
||||||
|
@ -431,14 +431,14 @@ $cli
|
||||||
'period' => '30m',
|
'period' => '30m',
|
||||||
'time' => $time,
|
'time' => $time,
|
||||||
'metric' => 'storage.deployments.total',
|
'metric' => 'storage.deployments.total',
|
||||||
'value' => $storageTotal,
|
'value' => $deploymentsTotal,
|
||||||
'type' => 1,
|
'type' => 1,
|
||||||
]));
|
]));
|
||||||
} else {
|
} else {
|
||||||
$dbForProject->updateDocument(
|
$dbForProject->updateDocument(
|
||||||
'stats',
|
'stats',
|
||||||
$document->getId(),
|
$document->getId(),
|
||||||
$document->setAttribute('value', $storageTotal)
|
$document->setAttribute('value', $deploymentsTotal)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$time = (int) (floor(time() / 86400) * 86400); // Time rounded to nearest day
|
$time = (int) (floor(time() / 86400) * 86400); // Time rounded to nearest day
|
||||||
|
@ -450,14 +450,14 @@ $cli
|
||||||
'period' => '1d',
|
'period' => '1d',
|
||||||
'time' => $time,
|
'time' => $time,
|
||||||
'metric' => 'storage.deployments.total',
|
'metric' => 'storage.deployments.total',
|
||||||
'value' => $storageTotal,
|
'value' => $deploymentsTotal,
|
||||||
'type' => 1,
|
'type' => 1,
|
||||||
]));
|
]));
|
||||||
} else {
|
} else {
|
||||||
$dbForProject->updateDocument(
|
$dbForProject->updateDocument(
|
||||||
'stats',
|
'stats',
|
||||||
$document->getId(),
|
$document->getId(),
|
||||||
$document->setAttribute('value', $storageTotal)
|
$document->setAttribute('value', $deploymentsTotal)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
|
@ -714,7 +714,7 @@ $cli
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserting project level sums for sub collections like storage.total
|
* Inserting project level sums for sub collections like storage.files.total
|
||||||
*/
|
*/
|
||||||
foreach ($subCollectionTotals as $subCollection => $count) {
|
foreach ($subCollectionTotals as $subCollection => $count) {
|
||||||
$dbForProject->setNamespace("_{$projectId}");
|
$dbForProject->setNamespace("_{$projectId}");
|
||||||
|
@ -754,6 +754,44 @@ $cli
|
||||||
$dbForProject->updateDocument('stats', $document->getId(),
|
$dbForProject->updateDocument('stats', $document->getId(),
|
||||||
$document->setAttribute('value', $count));
|
$document->setAttribute('value', $count));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// aggregate storage.total = storage.files.total + storage.deployments.total
|
||||||
|
if($metricPrefix === 'storage' && $subCollection === 'files') {
|
||||||
|
$metric = 'storage.total';
|
||||||
|
$time = (int) (floor(time() / 1800) * 1800); // Time rounded to nearest 30 minutes
|
||||||
|
$id = \md5($time . '_30m_' . $metric); //Construct unique id for each metric using time, period and metric
|
||||||
|
$document = $dbForProject->getDocument('stats', $id);
|
||||||
|
if ($document->isEmpty()) {
|
||||||
|
$dbForProject->createDocument('stats', new Document([
|
||||||
|
'$id' => $id,
|
||||||
|
'time' => $time,
|
||||||
|
'period' => '30m',
|
||||||
|
'metric' => $metric,
|
||||||
|
'value' => $count + $deploymentsTotal,
|
||||||
|
'type' => 1,
|
||||||
|
]));
|
||||||
|
} else {
|
||||||
|
$dbForProject->updateDocument('stats', $document->getId(),
|
||||||
|
$document->setAttribute('value', $count + $deploymentsTotal));
|
||||||
|
}
|
||||||
|
|
||||||
|
$time = (int) (floor(time() / 86400) * 86400); // Time rounded to nearest day
|
||||||
|
$id = \md5($time . '_1d_' . $metric); //Construct unique id for each metric using time, period and metric
|
||||||
|
$document = $dbForProject->getDocument('stats', $id);
|
||||||
|
if ($document->isEmpty()) {
|
||||||
|
$dbForProject->createDocument('stats', new Document([
|
||||||
|
'$id' => $id,
|
||||||
|
'time' => $time,
|
||||||
|
'period' => '1d',
|
||||||
|
'metric' => $metric,
|
||||||
|
'value' => $count + $deploymentsTotal,
|
||||||
|
'type' => 1,
|
||||||
|
]));
|
||||||
|
} else {
|
||||||
|
$dbForProject->updateDocument('stats', $document->getId(),
|
||||||
|
$document->setAttribute('value', $count + $deploymentsTotal));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (\Exception$e) {
|
} catch (\Exception$e) {
|
||||||
Console::warning("Failed to save database counters data for project {$collection}: {$e->getMessage()}");
|
Console::warning("Failed to save database counters data for project {$collection}: {$e->getMessage()}");
|
||||||
|
|
|
@ -621,7 +621,7 @@ $logs = $this->getParam('logs', null);
|
||||||
data-failure-param-alert-text="Failed to create attribute"
|
data-failure-param-alert-text="Failed to create attribute"
|
||||||
data-failure-param-alert-classname="error"
|
data-failure-param-alert-classname="error"
|
||||||
@reset="array = required = false"
|
@reset="array = required = false"
|
||||||
x-data="{ array: false, required: false }">
|
x-data="{ array: false, required: false, size: null }">
|
||||||
|
|
||||||
<input type="hidden" name="projectId" data-ls-bind="{{router.params.project}}" />
|
<input type="hidden" name="projectId" data-ls-bind="{{router.params.project}}" />
|
||||||
<input type="hidden" name="collectionId" data-ls-bind="{{router.params.id}}" />
|
<input type="hidden" name="collectionId" data-ls-bind="{{router.params.id}}" />
|
||||||
|
@ -631,7 +631,7 @@ $logs = $this->getParam('logs', null);
|
||||||
<div class="text-fade text-size-xs margin-top-negative-small margin-bottom">Allowed Characters A-Z, a-z, 0-9, and non-leading underscore, hyphen and dot</div>
|
<div class="text-fade text-size-xs margin-top-negative-small margin-bottom">Allowed Characters A-Z, a-z, 0-9, and non-leading underscore, hyphen and dot</div>
|
||||||
|
|
||||||
<label for="string-length">Size</label>
|
<label for="string-length">Size</label>
|
||||||
<input id="string-length" name="size" type="number" class="margin-bottom" autocomplete="off" required value="255" data-cast-to="integer" />
|
<input id="string-length" name="size" type="number" class="margin-bottom" autocomplete="off" required value="255" data-cast-to="integer" x-model="size" />
|
||||||
|
|
||||||
<div class="margin-bottom">
|
<div class="margin-bottom">
|
||||||
<input x-model="required" name="required" class="button switch" type="checkbox" /> Required <span class="tooltip" data-tooltip="Mark whether this is a required attribute"><i class="icon-info-circled"></i></span>
|
<input x-model="required" name="required" class="button switch" type="checkbox" /> Required <span class="tooltip" data-tooltip="Mark whether this is a required attribute"><i class="icon-info-circled"></i></span>
|
||||||
|
@ -643,7 +643,7 @@ $logs = $this->getParam('logs', null);
|
||||||
|
|
||||||
<label for="xdefault">Default Value</label>
|
<label for="xdefault">Default Value</label>
|
||||||
<template x-if="!(array || required)">
|
<template x-if="!(array || required)">
|
||||||
<input name="xdefault" type="text" class="margin-bottom-large" autocomplete="off">
|
<input name="xdefault" type="text" class="margin-bottom-large" autocomplete="off" :maxlength="size">
|
||||||
</template>
|
</template>
|
||||||
<template x-if="(array || required)">
|
<template x-if="(array || required)">
|
||||||
<input name="xdefault" type="text" class="margin-bottom-large" autocomplete="off" disabled value="">
|
<input name="xdefault" type="text" class="margin-bottom-large" autocomplete="off" disabled value="">
|
||||||
|
@ -677,7 +677,7 @@ $logs = $this->getParam('logs', null);
|
||||||
data-failure-param-alert-text="Failed to create attribute"
|
data-failure-param-alert-text="Failed to create attribute"
|
||||||
data-failure-param-alert-classname="error"
|
data-failure-param-alert-classname="error"
|
||||||
@reset="array = required = false"
|
@reset="array = required = false"
|
||||||
x-data="{ array: false, required: false }">
|
x-data="{ array: false, required: false, min: null, max: null }">
|
||||||
|
|
||||||
<input type="hidden" name="projectId" data-ls-bind="{{router.params.project}}" />
|
<input type="hidden" name="projectId" data-ls-bind="{{router.params.project}}" />
|
||||||
<input type="hidden" name="collectionId" data-ls-bind="{{router.params.id}}" />
|
<input type="hidden" name="collectionId" data-ls-bind="{{router.params.id}}" />
|
||||||
|
@ -697,18 +697,18 @@ $logs = $this->getParam('logs', null);
|
||||||
<div class="row responsive thin">
|
<div class="row responsive thin">
|
||||||
<div class="col span-6 margin-bottom-small">
|
<div class="col span-6 margin-bottom-small">
|
||||||
<label for="integer-min">Min</label>
|
<label for="integer-min">Min</label>
|
||||||
<input id="integer-min" type="number" step="1" class="full-width" name="min" autocomplete="off" data-cast-to="integer" />
|
<input id="integer-min" type="number" step="1" class="full-width" name="min" autocomplete="off" data-cast-to="integer" x-model="min" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col span-6 margin-bottom-small">
|
<div class="col span-6 margin-bottom-small">
|
||||||
<label for="integer-max">Max</label>
|
<label for="integer-max">Max</label>
|
||||||
<input id="integer-max" type="number" step="1" class="full-width" name="max" autocomplete="off" data-cast-to="integer" />
|
<input id="integer-max" type="number" step="1" class="full-width" name="max" autocomplete="off" data-cast-to="integer" x-model="max" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label for="integer-default">Default Value</label>
|
<label for="integer-default">Default Value</label>
|
||||||
|
|
||||||
<template x-if="!(array || required)">
|
<template x-if="!(array || required)">
|
||||||
<input name="xdefault" type="number" class="margin-bottom-large" autocomplete="off" data-cast-to="integer">
|
<input name="xdefault" type="number" class="margin-bottom-large" autocomplete="off" data-cast-to="integer" :min="min" :max="max">
|
||||||
</template>
|
</template>
|
||||||
<template x-if="(array || required)">
|
<template x-if="(array || required)">
|
||||||
<input name="xdefault" type="number" class="margin-bottom-large" autocomplete="off" data-cast-to="integer" disabled>
|
<input name="xdefault" type="number" class="margin-bottom-large" autocomplete="off" data-cast-to="integer" disabled>
|
||||||
|
@ -742,7 +742,7 @@ $logs = $this->getParam('logs', null);
|
||||||
data-failure-param-alert-text="Failed to create attribute"
|
data-failure-param-alert-text="Failed to create attribute"
|
||||||
data-failure-param-alert-classname="error"
|
data-failure-param-alert-classname="error"
|
||||||
@reset="array = required = false"
|
@reset="array = required = false"
|
||||||
x-data="{ array: false, required: false }">
|
x-data="{ array: false, required: false, min: null, max: null }">
|
||||||
|
|
||||||
<input type="hidden" name="projectId" data-ls-bind="{{router.params.project}}" />
|
<input type="hidden" name="projectId" data-ls-bind="{{router.params.project}}" />
|
||||||
<input type="hidden" name="collectionId" data-ls-bind="{{router.params.id}}" />
|
<input type="hidden" name="collectionId" data-ls-bind="{{router.params.id}}" />
|
||||||
|
@ -762,18 +762,18 @@ $logs = $this->getParam('logs', null);
|
||||||
<div class="row responsive thin">
|
<div class="row responsive thin">
|
||||||
<div class="col span-6 margin-bottom-small">
|
<div class="col span-6 margin-bottom-small">
|
||||||
<label for="float-min">Min</label>
|
<label for="float-min">Min</label>
|
||||||
<input id="float-min" type="number" class="full-width" name="min" step="any" autocomplete="off" data-cast-to="float" />
|
<input id="float-min" type="number" class="full-width" name="min" step="any" autocomplete="off" data-cast-to="float" x-model="min" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col span-6 margin-bottom-small">
|
<div class="col span-6 margin-bottom-small">
|
||||||
<label for="float-max">Max</label>
|
<label for="float-max">Max</label>
|
||||||
<input id="float-max" type="number" class="full-width" name="max" step="any" autocomplete="off" data-cast-to="float" />
|
<input id="float-max" type="number" class="full-width" name="max" step="any" autocomplete="off" data-cast-to="float" x-model="max" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label for="float-default">Default Value</label>
|
<label for="float-default">Default Value</label>
|
||||||
|
|
||||||
<template x-if="!(array || required)">
|
<template x-if="!(array || required)">
|
||||||
<input name="xdefault" type="number" step="any" class="margin-bottom-large" autocomplete="off" data-cast-to="float">
|
<input name="xdefault" type="number" step="any" class="margin-bottom-large" autocomplete="off" data-cast-to="float" :min="min" :max="max">
|
||||||
</template>
|
</template>
|
||||||
<template x-if="(array || required)">
|
<template x-if="(array || required)">
|
||||||
<input name="xdefault" type="number" step="any" class="margin-bottom-large" autocomplete="off" data-cast-to="float" disabled>
|
<input name="xdefault" type="number" step="any" class="margin-bottom-large" autocomplete="off" data-cast-to="float" disabled>
|
||||||
|
|
|
@ -55,17 +55,26 @@ $logs = $this->getParam('logs', null);
|
||||||
data-analytics-activity
|
data-analytics-activity
|
||||||
data-analytics-event="submit"
|
data-analytics-event="submit"
|
||||||
data-analytics-category="console"
|
data-analytics-category="console"
|
||||||
data-analytics-label="Update Database Document"
|
|
||||||
data-service="{{|documentAction}}"
|
data-service="{{|documentAction}}"
|
||||||
data-name="project-document"
|
data-name="project-document"
|
||||||
data-scope="sdk"
|
data-scope="sdk"
|
||||||
data-event="submit"
|
data-event="submit"
|
||||||
data-success="trigger,redirect"
|
|
||||||
data-success-param-trigger-events="database.updateDocument"
|
|
||||||
data-success-param-redirect-url="/console/database/document?id={{serviceData.$id}}&collection={{project-collection.$id}}&project={{router.params.project}}"
|
|
||||||
data-failure="alert"
|
data-failure="alert"
|
||||||
data-failure-param-alert-text="Failed to update document"
|
data-failure-param-alert-classname="error"
|
||||||
data-failure-param-alert-classname="error">
|
<?php if($new): ?>
|
||||||
|
data-analytics-label="Create Database Document"
|
||||||
|
data-success="trigger,redirect"
|
||||||
|
data-success-param-trigger-events="database.createDocument"
|
||||||
|
data-success-param-redirect-url="/console/database/collection?id={{project-collection.$id}}&project={{router.params.project}}"
|
||||||
|
data-failure-param-alert-text="Failed to create document"
|
||||||
|
<?php else: ?>
|
||||||
|
data-analytics-label="Update Database Document"
|
||||||
|
data-success="trigger,alert"
|
||||||
|
data-success-param-trigger-events="database.updateDocument"
|
||||||
|
data-success-param-alert-text="Your document was updated"
|
||||||
|
data-failure-param-alert-text="Failed to update document"
|
||||||
|
<?php endif; ?>
|
||||||
|
>
|
||||||
|
|
||||||
<input type="hidden" name="collectionId" data-ls-bind="{{project-collection.$id}}" />
|
<input type="hidden" name="collectionId" data-ls-bind="{{project-collection.$id}}" />
|
||||||
<?php if(!$new): ?><input type="hidden" name="documentId" data-ls-bind="{{project-document.$id}}" /><?php endif; ?>
|
<?php if(!$new): ?><input type="hidden" name="documentId" data-ls-bind="{{project-document.$id}}" /><?php endif; ?>
|
||||||
|
@ -104,6 +113,8 @@ $logs = $this->getParam('logs', null);
|
||||||
:placeholder="attr.default"
|
:placeholder="attr.default"
|
||||||
:name="attr.key"
|
:name="attr.key"
|
||||||
:required="attr.required"
|
:required="attr.required"
|
||||||
|
:min="attr.min"
|
||||||
|
:max="attr.max"
|
||||||
x-model="doc[attr.key]"
|
x-model="doc[attr.key]"
|
||||||
data-cast-to="integer" />
|
data-cast-to="integer" />
|
||||||
</template>
|
</template>
|
||||||
|
@ -114,6 +125,8 @@ $logs = $this->getParam('logs', null);
|
||||||
:placeholder="attr.default"
|
:placeholder="attr.default"
|
||||||
:name="attr.key"
|
:name="attr.key"
|
||||||
:required="attr.required"
|
:required="attr.required"
|
||||||
|
:min="attr.min"
|
||||||
|
:max="attr.max"
|
||||||
x-model="doc[attr.key]"
|
x-model="doc[attr.key]"
|
||||||
data-cast-to="float" />
|
data-cast-to="float" />
|
||||||
</template>
|
</template>
|
||||||
|
@ -131,6 +144,7 @@ $logs = $this->getParam('logs', null);
|
||||||
:placeholder="attr.default"
|
:placeholder="attr.default"
|
||||||
:name="attr.key"
|
:name="attr.key"
|
||||||
:required="attr.required"
|
:required="attr.required"
|
||||||
|
:maxlength="attr.size"
|
||||||
x-model="doc[attr.key]"
|
x-model="doc[attr.key]"
|
||||||
data-cast-to="string"></textarea>
|
data-cast-to="string"></textarea>
|
||||||
</template>
|
</template>
|
||||||
|
@ -197,6 +211,8 @@ $logs = $this->getParam('logs', null);
|
||||||
:placeholder="attr.default"
|
:placeholder="attr.default"
|
||||||
:name="attr.key"
|
:name="attr.key"
|
||||||
:required="attr.required"
|
:required="attr.required"
|
||||||
|
:min="attr.min"
|
||||||
|
:max="attr.max"
|
||||||
x-model="doc[attr.key][index]"
|
x-model="doc[attr.key][index]"
|
||||||
data-cast-to="integer" />
|
data-cast-to="integer" />
|
||||||
</template>
|
</template>
|
||||||
|
@ -207,6 +223,8 @@ $logs = $this->getParam('logs', null);
|
||||||
:placeholder="attr.default"
|
:placeholder="attr.default"
|
||||||
:name="attr.key"
|
:name="attr.key"
|
||||||
:required="attr.required"
|
:required="attr.required"
|
||||||
|
:min="attr.min"
|
||||||
|
:max="attr.max"
|
||||||
x-model="doc[attr.key][index]"
|
x-model="doc[attr.key][index]"
|
||||||
data-cast-to="float" />
|
data-cast-to="float" />
|
||||||
</template>
|
</template>
|
||||||
|
@ -226,6 +244,7 @@ $logs = $this->getParam('logs', null);
|
||||||
:placeholder="attr.default"
|
:placeholder="attr.default"
|
||||||
:name="attr.key"
|
:name="attr.key"
|
||||||
:required="attr.required"
|
:required="attr.required"
|
||||||
|
:maxlength="attr.size"
|
||||||
x-model="doc[attr.key][index]"
|
x-model="doc[attr.key][index]"
|
||||||
data-cast-to="string"></textarea>
|
data-cast-to="string"></textarea>
|
||||||
</template>
|
</template>
|
||||||
|
@ -267,9 +286,9 @@ $logs = $this->getParam('logs', null);
|
||||||
:required="attr.required"
|
:required="attr.required"
|
||||||
:name="attr.key"
|
:name="attr.key"
|
||||||
data-cast-to="string">
|
data-cast-to="string">
|
||||||
<template x-for="element in attr.elements">
|
<option :disabled="attr.required" selected label=" "></option>
|
||||||
<option :disabled="attr.required" selected label=" "></option>
|
|
||||||
|
|
||||||
|
<template x-for="element in attr.elements">
|
||||||
<option
|
<option
|
||||||
:value="element"
|
:value="element"
|
||||||
x-text="element"
|
x-text="element"
|
||||||
|
|
|
@ -233,7 +233,53 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
<li data-state="/console/users/teams/team/audit?id={{router.params.id}}&project={{router.params.project}}">
|
||||||
|
<h2>Activity</h2>
|
||||||
|
|
||||||
|
<div
|
||||||
|
data-service="teams.listLogs"
|
||||||
|
data-name="logs"
|
||||||
|
data-param-team-id="{{router.params.id}}"
|
||||||
|
data-event="load,logs-load">
|
||||||
|
|
||||||
|
<div class="box margin-top margin-bottom" data-ls-if="{{logs.logs.length}} === 0" style="display: none" class="margin-top-xxl margin-bottom-xxl text-align-center">
|
||||||
|
<h3 class="text-bold margin-bottom-no">No logs available.</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box" data-ls-if="{{logs.logs.length}} !== 0" style="display: none">
|
||||||
|
<table class="vertical small">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th width="140">Date</th>
|
||||||
|
<th width="175">Event</th>
|
||||||
|
<th>Client</th>
|
||||||
|
<th width="90">Location</th>
|
||||||
|
<th width="90">IP</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody data-ls-loop="logs.logs" data-ls-as="log">
|
||||||
|
<tr>
|
||||||
|
<td data-title="Date: "><span data-ls-bind="{{log.time|dateTime}}"></span></td>
|
||||||
|
<td data-title="Event: "><span data-ls-bind="{{log.event}}"></span></td>
|
||||||
|
<td data-title="Client: ">
|
||||||
|
<img onerror="this.onerror=null;this.className='avatar hide'" data-ls-if="{{log.clientCode|lowercase}} !== 'cli'" data-ls-attrs="src={{env.API}}/avatars/browsers/{{log.clientCode|lowercase}}?width=80&height=80&project={{env.PROJECT}},title={{log.clientName}},alt={{log.clientName}}" class="avatar xxs inline margin-end-small" />
|
||||||
|
|
||||||
|
<img onerror="this.onerror=null;this.className='avatar hide'" data-ls-if="{{log.clientCode|lowercase}} === 'cli'" data-ls-attrs="src=/images/clients/terminal.png?buster=<?php echo APP_CACHE_BUSTER; ?>,title={{log.clientName}},alt={{log.clientName}}" class="avatar xxs inline margin-end-small" />
|
||||||
|
|
||||||
|
<span data-ls-if="({{log.clientName}})" data-ls-bind="{{log.clientName}} {{log.clientVersion}} on {{log.model}} {{log.osName}} {{log.osVersion}}"></span>
|
||||||
|
<div data-ls-if="(!{{log.clientName}})" class="text-align-center text-fade">Unknown</div>
|
||||||
|
</td>
|
||||||
|
<td data-title="Location: ">
|
||||||
|
<img onerror="this.onerror=null;this.className='avatar hide'" data-ls-if="{{log.countryCode}} !== '--'" data-ls-attrs="src={{env.API}}/avatars/flags/{{log.countryCode}}?width=80&height=80&project={{env.PROJECT}}" class="avatar xxs inline margin-end-small" />
|
||||||
|
<span data-ls-bind="{{log.countryName}}"></span>
|
||||||
|
</td>
|
||||||
|
<td data-title="IP: "><span data-ls-bind="{{log.ip}}"></span></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -242,6 +242,52 @@
|
||||||
<li class="margin-bottom-small"><i class="icon-angle-circled-right margin-start-tiny margin-end-tiny"></i> <button data-ls-ui-trigger="open-json" class="link text-size-small">View as JSON</button></li>
|
<li class="margin-bottom-small"><i class="icon-angle-circled-right margin-start-tiny margin-end-tiny"></i> <button data-ls-ui-trigger="open-json" class="link text-size-small">View as JSON</button></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<div data-ls-if="{{user.emailVerification}} === false" style="display: none">
|
||||||
|
<form name="users.updateVerification" class="margin-bottom"
|
||||||
|
data-analytics
|
||||||
|
data-analytics-activity
|
||||||
|
data-analytics-event="submit"
|
||||||
|
data-analytics-category="console"
|
||||||
|
data-analytics-label="Update Verification Status"
|
||||||
|
data-service="users.updateVerification"
|
||||||
|
data-scope="sdk"
|
||||||
|
data-event="submit"
|
||||||
|
data-success="trigger,alert"
|
||||||
|
data-success-param-alert-text="User verification status was updated successfully"
|
||||||
|
data-success-param-trigger-events="users.update"
|
||||||
|
data-failure="alert"
|
||||||
|
data-failure-param-alert-text="Failed to update user verification status"
|
||||||
|
data-failure-param-alert-classname="error"
|
||||||
|
>
|
||||||
|
<input type="hidden" disabled name="userId" data-ls-bind="{{user.$id}}">
|
||||||
|
<input type="hidden" disabled name="emailVerification" value="true" data-cast-to="boolean">
|
||||||
|
<button type="submit" class="dark fill">Verify Account</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div data-ls-if="{{user.emailVerification}} === true" style="display: none">
|
||||||
|
<form name="users.updateVerification" class="margin-bottom"
|
||||||
|
data-analytics
|
||||||
|
data-analytics-activity
|
||||||
|
data-analytics-event="submit"
|
||||||
|
data-analytics-category="console"
|
||||||
|
data-analytics-label="Update Verification Status"
|
||||||
|
data-service="users.updateVerification"
|
||||||
|
data-scope="sdk"
|
||||||
|
data-event="submit"
|
||||||
|
data-success="trigger,alert"
|
||||||
|
data-success-param-alert-text="User verification status was updated successfully"
|
||||||
|
data-success-param-trigger-events="users.update"
|
||||||
|
data-failure="alert"
|
||||||
|
data-failure-param-alert-text="Failed to update user verification status"
|
||||||
|
data-failure-param-alert-classname="error"
|
||||||
|
>
|
||||||
|
<input type="hidden" disabled name="userId" data-ls-bind="{{user.$id}}">
|
||||||
|
<input type="hidden" disabled name="emailVerification" value="false" data-cast-to="boolean">
|
||||||
|
<button type="submit" class="dark fill">Unverify Account</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div data-ls-if="{{user.status}} === true" style="display: none">
|
<div data-ls-if="{{user.status}} === true" style="display: none">
|
||||||
<form name="users.updateStatus" class="margin-bottom"
|
<form name="users.updateStatus" class="margin-bottom"
|
||||||
data-analytics
|
data-analytics
|
||||||
|
|
|
@ -16,7 +16,7 @@ $image = $this->getParam('image', '');
|
||||||
|
|
||||||
services:
|
services:
|
||||||
traefik:
|
traefik:
|
||||||
image: traefik:2.5
|
image: traefik:2.7
|
||||||
container_name: appwrite-traefik
|
container_name: appwrite-traefik
|
||||||
command:
|
command:
|
||||||
- --providers.file.directory=/storage/config
|
- --providers.file.directory=/storage/config
|
||||||
|
|
|
@ -71,6 +71,11 @@ class DatabaseV1 extends Worker
|
||||||
$dbForConsole = $this->getConsoleDB();
|
$dbForConsole = $this->getConsoleDB();
|
||||||
$dbForProject = $this->getProjectDB($projectId);
|
$dbForProject = $this->getProjectDB($projectId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch attribute from the database, since with Resque float values are loosing informations.
|
||||||
|
*/
|
||||||
|
$attribute = $dbForProject->getDocument('attributes', $attribute->getId());
|
||||||
|
|
||||||
$event = 'database.attributes.update';
|
$event = 'database.attributes.update';
|
||||||
$collectionId = $collection->getId();
|
$collectionId = $collection->getId();
|
||||||
$key = $attribute->getAttribute('key', '');
|
$key = $attribute->getAttribute('key', '');
|
||||||
|
|
|
@ -254,7 +254,7 @@ class FunctionsV1 extends Worker
|
||||||
'trigger' => $trigger,
|
'trigger' => $trigger,
|
||||||
'status' => 'waiting',
|
'status' => 'waiting',
|
||||||
'statusCode' => 0,
|
'statusCode' => 0,
|
||||||
'stdout' => '',
|
'response' => '',
|
||||||
'stderr' => '',
|
'stderr' => '',
|
||||||
'time' => 0.0,
|
'time' => 0.0,
|
||||||
'search' => implode(' ', [$functionId, $executionId]),
|
'search' => implode(' ', [$functionId, $executionId]),
|
||||||
|
@ -303,7 +303,7 @@ class FunctionsV1 extends Worker
|
||||||
/** Update execution status */
|
/** Update execution status */
|
||||||
$execution->setAttribute('status', $executionResponse['status']);
|
$execution->setAttribute('status', $executionResponse['status']);
|
||||||
$execution->setAttribute('statusCode', $executionResponse['statusCode']);
|
$execution->setAttribute('statusCode', $executionResponse['statusCode']);
|
||||||
$execution->setAttribute('stdout', $executionResponse['stdout']);
|
$execution->setAttribute('response', $executionResponse['response']);
|
||||||
$execution->setAttribute('stderr', $executionResponse['stderr']);
|
$execution->setAttribute('stderr', $executionResponse['stderr']);
|
||||||
$execution->setAttribute('time', $executionResponse['time']);
|
$execution->setAttribute('time', $executionResponse['time']);
|
||||||
} catch (\Throwable $th) {
|
} catch (\Throwable $th) {
|
||||||
|
|
|
@ -56,7 +56,7 @@
|
||||||
"utopia-php/image": "0.5.*",
|
"utopia-php/image": "0.5.*",
|
||||||
"utopia-php/orchestration": "0.4.*",
|
"utopia-php/orchestration": "0.4.*",
|
||||||
"resque/php-resque": "1.3.6",
|
"resque/php-resque": "1.3.6",
|
||||||
"matomo/device-detector": "5.0.4",
|
"matomo/device-detector": "6.0.0",
|
||||||
"dragonmantank/cron-expression": "3.3.1",
|
"dragonmantank/cron-expression": "3.3.1",
|
||||||
"influxdb/influxdb-php": "1.15.2",
|
"influxdb/influxdb-php": "1.15.2",
|
||||||
"phpmailer/phpmailer": "6.6.0",
|
"phpmailer/phpmailer": "6.6.0",
|
||||||
|
@ -72,9 +72,9 @@
|
||||||
],
|
],
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"appwrite/sdk-generator": "0.18.3",
|
"appwrite/sdk-generator": "0.18.3",
|
||||||
"phpunit/phpunit": "9.5.10",
|
"phpunit/phpunit": "9.5.20",
|
||||||
"swoole/ide-helper": "4.8.5",
|
"swoole/ide-helper": "4.8.9",
|
||||||
"textalk/websocket": "1.5.5",
|
"textalk/websocket": "1.5.7",
|
||||||
"vimeo/psalm": "4.13.1"
|
"vimeo/psalm": "4.13.1"
|
||||||
},
|
},
|
||||||
"provide": {
|
"provide": {
|
||||||
|
|
70
composer.lock
generated
70
composer.lock
generated
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "e0de8d0bba618a46646cf3da1e06a652",
|
"content-hash": "78c5402d7bf745469d0063a9bc955df0",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "adhocore/jwt",
|
"name": "adhocore/jwt",
|
||||||
|
@ -925,16 +925,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "matomo/device-detector",
|
"name": "matomo/device-detector",
|
||||||
"version": "5.0.4",
|
"version": "6.0.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/matomo-org/device-detector.git",
|
"url": "https://github.com/matomo-org/device-detector.git",
|
||||||
"reference": "99ea1953fc7f23f785e593ce1499a00586645530"
|
"reference": "7fc2af3af62bd69e6e3404d561e371a83c112be9"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/matomo-org/device-detector/zipball/99ea1953fc7f23f785e593ce1499a00586645530",
|
"url": "https://api.github.com/repos/matomo-org/device-detector/zipball/7fc2af3af62bd69e6e3404d561e371a83c112be9",
|
||||||
"reference": "99ea1953fc7f23f785e593ce1499a00586645530",
|
"reference": "7fc2af3af62bd69e6e3404d561e371a83c112be9",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -990,7 +990,7 @@
|
||||||
"source": "https://github.com/matomo-org/matomo",
|
"source": "https://github.com/matomo-org/matomo",
|
||||||
"wiki": "https://dev.matomo.org/"
|
"wiki": "https://dev.matomo.org/"
|
||||||
},
|
},
|
||||||
"time": "2022-02-18T19:51:56+00:00"
|
"time": "2022-04-11T09:58:17+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "mongodb/mongodb",
|
"name": "mongodb/mongodb",
|
||||||
|
@ -4549,16 +4549,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/phpunit",
|
"name": "phpunit/phpunit",
|
||||||
"version": "9.5.10",
|
"version": "9.5.20",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||||
"reference": "c814a05837f2edb0d1471d6e3f4ab3501ca3899a"
|
"reference": "12bc8879fb65aef2138b26fc633cb1e3620cffba"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c814a05837f2edb0d1471d6e3f4ab3501ca3899a",
|
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/12bc8879fb65aef2138b26fc633cb1e3620cffba",
|
||||||
"reference": "c814a05837f2edb0d1471d6e3f4ab3501ca3899a",
|
"reference": "12bc8879fb65aef2138b26fc633cb1e3620cffba",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -4574,7 +4574,7 @@
|
||||||
"phar-io/version": "^3.0.2",
|
"phar-io/version": "^3.0.2",
|
||||||
"php": ">=7.3",
|
"php": ">=7.3",
|
||||||
"phpspec/prophecy": "^1.12.1",
|
"phpspec/prophecy": "^1.12.1",
|
||||||
"phpunit/php-code-coverage": "^9.2.7",
|
"phpunit/php-code-coverage": "^9.2.13",
|
||||||
"phpunit/php-file-iterator": "^3.0.5",
|
"phpunit/php-file-iterator": "^3.0.5",
|
||||||
"phpunit/php-invoker": "^3.1.1",
|
"phpunit/php-invoker": "^3.1.1",
|
||||||
"phpunit/php-text-template": "^2.0.3",
|
"phpunit/php-text-template": "^2.0.3",
|
||||||
|
@ -4588,7 +4588,7 @@
|
||||||
"sebastian/global-state": "^5.0.1",
|
"sebastian/global-state": "^5.0.1",
|
||||||
"sebastian/object-enumerator": "^4.0.3",
|
"sebastian/object-enumerator": "^4.0.3",
|
||||||
"sebastian/resource-operations": "^3.0.3",
|
"sebastian/resource-operations": "^3.0.3",
|
||||||
"sebastian/type": "^2.3.4",
|
"sebastian/type": "^3.0",
|
||||||
"sebastian/version": "^3.0.2"
|
"sebastian/version": "^3.0.2"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
@ -4636,11 +4636,11 @@
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.10"
|
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.20"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"url": "https://phpunit.de/donate.html",
|
"url": "https://phpunit.de/sponsors.html",
|
||||||
"type": "custom"
|
"type": "custom"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -4648,7 +4648,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-09-25T07:38:51+00:00"
|
"time": "2022-04-01T12:37:26+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "psr/container",
|
"name": "psr/container",
|
||||||
|
@ -5560,28 +5560,28 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/type",
|
"name": "sebastian/type",
|
||||||
"version": "2.3.4",
|
"version": "3.0.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/type.git",
|
"url": "https://github.com/sebastianbergmann/type.git",
|
||||||
"reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914"
|
"reference": "b233b84bc4465aff7b57cf1c4bc75c86d00d6dad"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b8cd8a1c753c90bc1a0f5372170e3e489136f914",
|
"url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b233b84bc4465aff7b57cf1c4bc75c86d00d6dad",
|
||||||
"reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914",
|
"reference": "b233b84bc4465aff7b57cf1c4bc75c86d00d6dad",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.3"
|
"php": ">=7.3"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^9.3"
|
"phpunit/phpunit": "^9.5"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "2.3-dev"
|
"dev-master": "3.0-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
@ -5604,7 +5604,7 @@
|
||||||
"homepage": "https://github.com/sebastianbergmann/type",
|
"homepage": "https://github.com/sebastianbergmann/type",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/type/issues",
|
"issues": "https://github.com/sebastianbergmann/type/issues",
|
||||||
"source": "https://github.com/sebastianbergmann/type/tree/2.3.4"
|
"source": "https://github.com/sebastianbergmann/type/tree/3.0.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -5612,7 +5612,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-06-15T12:49:02+00:00"
|
"time": "2022-03-15T09:54:48+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/version",
|
"name": "sebastian/version",
|
||||||
|
@ -5669,16 +5669,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "swoole/ide-helper",
|
"name": "swoole/ide-helper",
|
||||||
"version": "4.8.5",
|
"version": "4.8.9",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/swoole/ide-helper.git",
|
"url": "https://github.com/swoole/ide-helper.git",
|
||||||
"reference": "d03c707d4dc803228e93b4884c72949c4d28e8b8"
|
"reference": "8f82ba3b6af04a5bccb97c1654af992d1ee8b0fe"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/swoole/ide-helper/zipball/d03c707d4dc803228e93b4884c72949c4d28e8b8",
|
"url": "https://api.github.com/repos/swoole/ide-helper/zipball/8f82ba3b6af04a5bccb97c1654af992d1ee8b0fe",
|
||||||
"reference": "d03c707d4dc803228e93b4884c72949c4d28e8b8",
|
"reference": "8f82ba3b6af04a5bccb97c1654af992d1ee8b0fe",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
|
@ -5695,7 +5695,7 @@
|
||||||
"description": "IDE help files for Swoole.",
|
"description": "IDE help files for Swoole.",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/swoole/ide-helper/issues",
|
"issues": "https://github.com/swoole/ide-helper/issues",
|
||||||
"source": "https://github.com/swoole/ide-helper/tree/4.8.5"
|
"source": "https://github.com/swoole/ide-helper/tree/4.8.9"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -5707,7 +5707,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2021-12-24T22:44:20+00:00"
|
"time": "2022-04-18T20:38:04+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/console",
|
"name": "symfony/console",
|
||||||
|
@ -6221,16 +6221,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "textalk/websocket",
|
"name": "textalk/websocket",
|
||||||
"version": "1.5.5",
|
"version": "1.5.7",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/Textalk/websocket-php.git",
|
"url": "https://github.com/Textalk/websocket-php.git",
|
||||||
"reference": "846542f82658132cd36acb7a7e8ce0f03960c295"
|
"reference": "1712325e99b6bf869ccbf9bf41ab749e7328ea46"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/Textalk/websocket-php/zipball/846542f82658132cd36acb7a7e8ce0f03960c295",
|
"url": "https://api.github.com/repos/Textalk/websocket-php/zipball/1712325e99b6bf869ccbf9bf41ab749e7328ea46",
|
||||||
"reference": "846542f82658132cd36acb7a7e8ce0f03960c295",
|
"reference": "1712325e99b6bf869ccbf9bf41ab749e7328ea46",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -6264,9 +6264,9 @@
|
||||||
"description": "WebSocket client and server",
|
"description": "WebSocket client and server",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/Textalk/websocket-php/issues",
|
"issues": "https://github.com/Textalk/websocket-php/issues",
|
||||||
"source": "https://github.com/Textalk/websocket-php/tree/1.5.5"
|
"source": "https://github.com/Textalk/websocket-php/tree/1.5.7"
|
||||||
},
|
},
|
||||||
"time": "2021-08-07T10:21:40+00:00"
|
"time": "2022-03-29T09:46:59+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "theseer/tokenizer",
|
"name": "theseer/tokenizer",
|
||||||
|
|
|
@ -14,7 +14,7 @@ version: '3'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
traefik:
|
traefik:
|
||||||
image: traefik:2.5
|
image: traefik:2.7
|
||||||
<<: *x-logging
|
<<: *x-logging
|
||||||
container_name: appwrite-traefik
|
container_name: appwrite-traefik
|
||||||
command:
|
command:
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
You can use this endpoint to show different browser icons to your users. The code argument receives the browser code as it appears in your user /account/sessions endpoint. Use width, height and quality arguments to change the output settings.
|
You can use this endpoint to show different browser icons to your users. The code argument receives the browser code as it appears in your user [GET /account/sessions](/docs/client/account#accountGetSessions) endpoint. Use width, height and quality arguments to change the output settings.
|
||||||
|
|
||||||
|
When one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.
|
|
@ -1 +1,3 @@
|
||||||
The credit card endpoint will return you the icon of the credit card provider you need. Use width, height and quality arguments to change the output settings.
|
The credit card endpoint will return you the icon of the credit card provider you need. Use width, height and quality arguments to change the output settings.
|
||||||
|
|
||||||
|
When one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
You can use this endpoint to show different country flags icons to your users. The code argument receives the 2 letter country code. Use width, height and quality arguments to change the output settings.
|
You can use this endpoint to show different country flags icons to your users. The code argument receives the 2 letter country code. Use width, height and quality arguments to change the output settings.
|
||||||
|
|
||||||
|
When one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
Use this endpoint to fetch a remote image URL and crop it to any image size you want. This endpoint is very useful if you need to crop and display remote images in your app or in case you want to make sure a 3rd party image is properly served using a TLS protocol.
|
Use this endpoint to fetch a remote image URL and crop it to any image size you want. This endpoint is very useful if you need to crop and display remote images in your app or in case you want to make sure a 3rd party image is properly served using a TLS protocol.
|
||||||
|
|
||||||
|
When one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 400x400px.
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
Use this endpoint to show your user initials avatar icon on your website or app. By default, this route will try to print your logged-in user name or email initials. You can also overwrite the user name if you pass the 'name' parameter. If no name is given and no user is logged, an empty avatar will be returned.
|
Use this endpoint to show your user initials avatar icon on your website or app. By default, this route will try to print your logged-in user name or email initials. You can also overwrite the user name if you pass the 'name' parameter. If no name is given and no user is logged, an empty avatar will be returned.
|
||||||
|
|
||||||
You can use the color and background params to change the avatar colors. By default, a random theme will be selected. The random theme will persist for the user's initials when reloading the same theme will always return for the same initials.
|
You can use the color and background params to change the avatar colors. By default, a random theme will be selected. The random theme will persist for the user's initials when reloading the same theme will always return for the same initials.
|
||||||
|
|
||||||
|
When one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
Get the number of usage stats that are waiting to be processed in the Appwrite internal queue server.
|
|
1
docs/references/teams/get-team-logs.md
Normal file
1
docs/references/teams/get-team-logs.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Get the team activity logs list by its unique ID.
|
14
package-lock.json
generated
14
package-lock.json
generated
|
@ -12,7 +12,7 @@
|
||||||
"chart.js": "^3.7.1",
|
"chart.js": "^3.7.1",
|
||||||
"markdown-it": "^12.3.2",
|
"markdown-it": "^12.3.2",
|
||||||
"pell": "^1.0.6",
|
"pell": "^1.0.6",
|
||||||
"prismjs": "^1.27.0",
|
"prismjs": "^1.28.0",
|
||||||
"turndown": "^7.1.1"
|
"turndown": "^7.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -3566,9 +3566,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prismjs": {
|
"node_modules/prismjs": {
|
||||||
"version": "1.27.0",
|
"version": "1.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz",
|
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.28.0.tgz",
|
||||||
"integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==",
|
"integrity": "sha512-8aaXdYvl1F7iC7Xm1spqSaY/OJBpYW3v+KJ+F17iYxvdc8sfjW194COK5wVhMZX45tGteiBQgdvD/nhxcRwylw==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
|
@ -7981,9 +7981,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"prismjs": {
|
"prismjs": {
|
||||||
"version": "1.27.0",
|
"version": "1.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz",
|
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.28.0.tgz",
|
||||||
"integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA=="
|
"integrity": "sha512-8aaXdYvl1F7iC7Xm1spqSaY/OJBpYW3v+KJ+F17iYxvdc8sfjW194COK5wVhMZX45tGteiBQgdvD/nhxcRwylw=="
|
||||||
},
|
},
|
||||||
"process-nextick-args": {
|
"process-nextick-args": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
"chart.js": "^3.7.1",
|
"chart.js": "^3.7.1",
|
||||||
"markdown-it": "^12.3.2",
|
"markdown-it": "^12.3.2",
|
||||||
"pell": "^1.0.6",
|
"pell": "^1.0.6",
|
||||||
"prismjs": "^1.27.0",
|
"prismjs": "^1.28.0",
|
||||||
"turndown": "^7.1.1"
|
"turndown": "^7.1.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
17
public/dist/scripts/app-all.js
vendored
17
public/dist/scripts/app-all.js
vendored
File diff suppressed because one or more lines are too long
15
public/dist/scripts/app-dep.js
vendored
15
public/dist/scripts/app-dep.js
vendored
File diff suppressed because one or more lines are too long
2
public/dist/scripts/app.js
vendored
2
public/dist/scripts/app.js
vendored
|
@ -696,7 +696,7 @@ if(this.getFile(id)){this.updateFile(id,{name:file.name,completed:false,failed:f
|
||||||
target.reset();try{const response=await sdk.storage.createFile(bucketId,fileId,file,read,write,(progress)=>{this.updateFile(id,{id:progress.$id,progress:Math.round(progress.progress),error:"",});id=progress.$id;const file=this.getFile(id)??{};if(file.cancelled===true){throw'USER_CANCELLED';}});const existingFile=this.getFile(id)??{};if(existingFile.cancelled){this.updateFile(id,{id:response.$id,name:response.name,failed:false,});id=response.$id;throw'USER_CANCELLED'}else{this.updateFile(id,{id:response.$id,name:response.name,progress:100,completed:true,failed:false,});id=response.$id;}
|
target.reset();try{const response=await sdk.storage.createFile(bucketId,fileId,file,read,write,(progress)=>{this.updateFile(id,{id:progress.$id,progress:Math.round(progress.progress),error:"",});id=progress.$id;const file=this.getFile(id)??{};if(file.cancelled===true){throw'USER_CANCELLED';}});const existingFile=this.getFile(id)??{};if(existingFile.cancelled){this.updateFile(id,{id:response.$id,name:response.name,failed:false,});id=response.$id;throw'USER_CANCELLED'}else{this.updateFile(id,{id:response.$id,name:response.name,progress:100,completed:true,failed:false,});id=response.$id;}
|
||||||
document.dispatchEvent(new CustomEvent('storage.createFile'));}catch(error){if(error==='USER_CANCELLED'){await sdk.storage.deleteFile(bucketId,id);this.updateFile(id,{cancelled:false,failed:true,});this.removeFile(id);}else{this.updateFile(id,{id:id,failed:true,error:error.message??error});}
|
document.dispatchEvent(new CustomEvent('storage.createFile'));}catch(error){if(error==='USER_CANCELLED'){await sdk.storage.deleteFile(bucketId,id);this.updateFile(id,{cancelled:false,failed:true,});this.removeFile(id);}else{this.updateFile(id,{id:id,failed:true,error:error.message??error});}
|
||||||
document.dispatchEvent(new CustomEvent('storage.createFile'));}}});});})(window);(function(window){"use strict";window.ls.view.add({selector:"data-service",controller:function(element,view,container,form,alerts,expression,window){let action=element.dataset["service"];let service=element.dataset["name"]||null;let event=expression.parse(element.dataset["event"]);let confirm=element.dataset["confirm"]||"";let loading=element.dataset["loading"]||"";let loaderId=null;let scope=element.dataset["scope"]||"sdk";let success=element.dataset["success"]||"";let failure=element.dataset["failure"]||"";let running=false;let callbacks={hide:function(){return function(){return element.style.opacity='0';};},reset:function(){return function(){if("FORM"===element.tagName){return element.reset();}
|
document.dispatchEvent(new CustomEvent('storage.createFile'));}}});});})(window);(function(window){"use strict";window.ls.view.add({selector:"data-service",controller:function(element,view,container,form,alerts,expression,window){let action=element.dataset["service"];let service=element.dataset["name"]||null;let event=expression.parse(element.dataset["event"]);let confirm=element.dataset["confirm"]||"";let loading=element.dataset["loading"]||"";let loaderId=null;let scope=element.dataset["scope"]||"sdk";let success=element.dataset["success"]||"";let failure=element.dataset["failure"]||"";let running=false;let callbacks={hide:function(){return function(){return element.style.opacity='0';};},reset:function(){return function(){if("FORM"===element.tagName){return element.reset();}
|
||||||
throw new Error("This callback is only valid for forms");};},alert:function(text,classname){return function(alerts){alerts.add({text:text,class:classname||"success"},3000);};},redirect:function(url){return function(router){if(url==="/console"){window.location=url;return;}
|
throw new Error("This callback is only valid for forms");};},alert:function(text,classname){return function(alerts){alerts.add({text:text,class:classname||"success"},6000);};},redirect:function(url){return function(router){if(url==="/console"){window.location=url;return;}
|
||||||
router.change(url||"/");};},reload:function(){return function(router){router.reload();};},state:function(keys){let updateQueryString=function(key,value,url){var re=new RegExp("([?&])"+key+"=.*?(&|#|$)(.*)","gi"),hash;if(re.test(url)){if(typeof value!=="undefined"&&value!==null){return url.replace(re,"$1"+key+"="+value+"$2$3");}else{hash=url.split("#");url=hash[0].replace(re,"$1$3").replace(/(&|\?)$/,"");if(typeof hash[1]!=="undefined"&&hash[1]!==null){url+="#"+hash[1];}
|
router.change(url||"/");};},reload:function(){return function(router){router.reload();};},state:function(keys){let updateQueryString=function(key,value,url){var re=new RegExp("([?&])"+key+"=.*?(&|#|$)(.*)","gi"),hash;if(re.test(url)){if(typeof value!=="undefined"&&value!==null){return url.replace(re,"$1"+key+"="+value+"$2$3");}else{hash=url.split("#");url=hash[0].replace(re,"$1$3").replace(/(&|\?)$/,"");if(typeof hash[1]!=="undefined"&&hash[1]!==null){url+="#"+hash[1];}
|
||||||
return url;}}else{if(typeof value!=="undefined"&&value!==null){var separator=url.indexOf("?")!==-1?"&":"?";hash=url.split("#");url=hash[0]+separator+key+"="+value;if(typeof hash[1]!=="undefined"&&hash[1]!==null){url+="#"+hash[1];}
|
return url;}}else{if(typeof value!=="undefined"&&value!==null){var separator=url.indexOf("?")!==-1?"&":"?";hash=url.split("#");url=hash[0]+separator+key+"="+value;if(typeof hash[1]!=="undefined"&&hash[1]!==null){url+="#"+hash[1];}
|
||||||
return url;}else{return url;}}};keys=keys.split(",").map(element=>element.trim());return function(serviceForm,router,window){let url=window.location.href;keys.map(node=>{node=node.split("=");let key=node[0]||"";let name=node[1]||key;let value=getValue(key,"param",serviceForm);url=updateQueryString(name,value?value:null,url);});if(url!==window.location.href){window.history.pushState({},"",url);router.reset();}};},trigger:function(events){return function(document){events=events.trim().split(",");for(let i=0;i<events.length;i++){if(""===events[i]){continue;}
|
return url;}else{return url;}}};keys=keys.split(",").map(element=>element.trim());return function(serviceForm,router,window){let url=window.location.href;keys.map(node=>{node=node.split("=");let key=node[0]||"";let name=node[1]||key;let value=getValue(key,"param",serviceForm);url=updateQueryString(name,value?value:null,url);});if(url!==window.location.href){window.history.pushState({},"",url);router.reset();}};},trigger:function(events){return function(document){events=events.trim().split(",");for(let i=0;i<events.length;i++){if(""===events[i]){continue;}
|
||||||
|
|
2
public/dist/styles/default-ltr.css
vendored
2
public/dist/styles/default-ltr.css
vendored
File diff suppressed because one or more lines are too long
2
public/dist/styles/default-rtl.css
vendored
2
public/dist/styles/default-rtl.css
vendored
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 208 KiB After Width: | Height: | Size: 507 KiB |
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 250 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -48,7 +48,7 @@
|
||||||
mode: '',
|
mode: '',
|
||||||
};
|
};
|
||||||
this.headers = {
|
this.headers = {
|
||||||
'x-sdk-version': 'appwrite:web:4.0.4',
|
'x-sdk-version': 'appwrite:web:5.0.0',
|
||||||
'X-Appwrite-Response-Format': '0.13.0',
|
'X-Appwrite-Response-Format': '0.13.0',
|
||||||
};
|
};
|
||||||
this.realtime = {
|
this.realtime = {
|
||||||
|
@ -371,7 +371,7 @@
|
||||||
*
|
*
|
||||||
* Update currently logged in user password. For validation, user is required
|
* Update currently logged in user password. For validation, user is required
|
||||||
* to pass in the new password, and the old password. For users created with
|
* to pass in the new password, and the old password. For users created with
|
||||||
* OAuth and Team Invites, oldPassword is optional.
|
* OAuth, Team Invites and Magic URL, oldPassword is optional.
|
||||||
*
|
*
|
||||||
* @param {string} password
|
* @param {string} password
|
||||||
* @param {string} oldPassword
|
* @param {string} oldPassword
|
||||||
|
@ -768,6 +768,9 @@
|
||||||
/**
|
/**
|
||||||
* Update Session (Refresh Tokens)
|
* Update Session (Refresh Tokens)
|
||||||
*
|
*
|
||||||
|
* Access tokens have limited lifespan and expire to mitigate security risks.
|
||||||
|
* If session was created using an OAuth provider, this route can be used to
|
||||||
|
* "refresh" the access token.
|
||||||
*
|
*
|
||||||
* @param {string} sessionId
|
* @param {string} sessionId
|
||||||
* @throws {AppwriteException}
|
* @throws {AppwriteException}
|
||||||
|
@ -1923,9 +1926,7 @@
|
||||||
/**
|
/**
|
||||||
* Delete Document
|
* Delete Document
|
||||||
*
|
*
|
||||||
* Delete a document by its unique ID. This endpoint deletes only the parent
|
* Delete a document by its unique ID.
|
||||||
* documents, its attributes and relations to other documents. Child documents
|
|
||||||
* **will not** be deleted.
|
|
||||||
*
|
*
|
||||||
* @param {string} collectionId
|
* @param {string} collectionId
|
||||||
* @param {string} documentId
|
* @param {string} documentId
|
||||||
|
@ -2263,7 +2264,7 @@
|
||||||
}, payload);
|
}, payload);
|
||||||
}),
|
}),
|
||||||
/**
|
/**
|
||||||
* List the currently active function runtimes.
|
* List runtimes
|
||||||
*
|
*
|
||||||
* Get a list of all runtimes that are currently active on your instance.
|
* Get a list of all runtimes that are currently active on your instance.
|
||||||
*
|
*
|
||||||
|
@ -2488,8 +2489,8 @@
|
||||||
if (onProgress) {
|
if (onProgress) {
|
||||||
onProgress({
|
onProgress({
|
||||||
$id: response.$id,
|
$id: response.$id,
|
||||||
progress: Math.min((counter + 1) * Appwrite.CHUNK_SIZE, size) / size * 100,
|
progress: Math.min((counter + 1) * Appwrite.CHUNK_SIZE - 1, size) / size * 100,
|
||||||
sizeUploaded: end + 1,
|
sizeUploaded: end,
|
||||||
chunksTotal: response.chunksTotal,
|
chunksTotal: response.chunksTotal,
|
||||||
chunksUploaded: response.chunksUploaded
|
chunksUploaded: response.chunksUploaded
|
||||||
});
|
});
|
||||||
|
@ -4329,8 +4330,8 @@
|
||||||
if (onProgress) {
|
if (onProgress) {
|
||||||
onProgress({
|
onProgress({
|
||||||
$id: response.$id,
|
$id: response.$id,
|
||||||
progress: Math.min((counter + 1) * Appwrite.CHUNK_SIZE, size) / size * 100,
|
progress: Math.min((counter + 1) * Appwrite.CHUNK_SIZE - 1, size) / size * 100,
|
||||||
sizeUploaded: end + 1,
|
sizeUploaded: end,
|
||||||
chunksTotal: response.chunksTotal,
|
chunksTotal: response.chunksTotal,
|
||||||
chunksUploaded: response.chunksUploaded
|
chunksUploaded: response.chunksUploaded
|
||||||
});
|
});
|
||||||
|
@ -4744,6 +4745,34 @@
|
||||||
'content-type': 'application/json',
|
'content-type': 'application/json',
|
||||||
}, payload);
|
}, payload);
|
||||||
}),
|
}),
|
||||||
|
/**
|
||||||
|
* List Team Logs
|
||||||
|
*
|
||||||
|
* Get the team activity logs list by its unique ID.
|
||||||
|
*
|
||||||
|
* @param {string} teamId
|
||||||
|
* @param {number} limit
|
||||||
|
* @param {number} offset
|
||||||
|
* @throws {AppwriteException}
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
listLogs: (teamId, limit, offset) => __awaiter(this, void 0, void 0, function* () {
|
||||||
|
if (typeof teamId === 'undefined') {
|
||||||
|
throw new AppwriteException('Missing required parameter: "teamId"');
|
||||||
|
}
|
||||||
|
let path = '/teams/{teamId}/logs'.replace('{teamId}', teamId);
|
||||||
|
let payload = {};
|
||||||
|
if (typeof limit !== 'undefined') {
|
||||||
|
payload['limit'] = limit;
|
||||||
|
}
|
||||||
|
if (typeof offset !== 'undefined') {
|
||||||
|
payload['offset'] = offset;
|
||||||
|
}
|
||||||
|
const uri = new URL(this.config.endpoint + path);
|
||||||
|
return yield this.call('get', uri, {
|
||||||
|
'content-type': 'application/json',
|
||||||
|
}, payload);
|
||||||
|
}),
|
||||||
/**
|
/**
|
||||||
* Get Team Memberships
|
* Get Team Memberships
|
||||||
*
|
*
|
||||||
|
@ -5536,7 +5565,7 @@
|
||||||
var _a, _b;
|
var _a, _b;
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
method = method.toUpperCase();
|
method = method.toUpperCase();
|
||||||
headers = Object.assign(Object.assign({}, headers), this.headers);
|
headers = Object.assign({}, this.headers, headers);
|
||||||
let options = {
|
let options = {
|
||||||
method,
|
method,
|
||||||
headers,
|
headers,
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
|
|
||||||
alert: function(text, classname) {
|
alert: function(text, classname) {
|
||||||
return function(alerts) {
|
return function(alerts) {
|
||||||
alerts.add({ text: text, class: classname || "success" }, 3000);
|
alerts.add({ text: text, class: classname || "success" }, 6000);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
[data-views-current="1"] {
|
[data-views-current="1"] {
|
||||||
.scroll-to {
|
.scroll-to {
|
||||||
opacity: 0!important;
|
opacity: 0!important;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,6 +96,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[data-views-current]:not([data-views-current="0"]):not([data-views-current="1"]) .upload-box {
|
||||||
|
margin-right: 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
.icon-button {
|
.icon-button {
|
||||||
--p-icon-button-size:var(--icon-button-size, 20px);
|
--p-icon-button-size:var(--icon-button-size, 20px);
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
@font-face {font-family: "icon";
|
@font-face {font-family: "icon";
|
||||||
src: url('/fonts/icon.eot?t=1645269945236'); /* IE9*/
|
src: url('/fonts/icon.eot?t=1650537780691'); /* IE9*/
|
||||||
src: url('/fonts/icon.eot?t=1645269945236#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
src: url('/fonts/icon.eot?t=1650537780691#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||||
url("/fonts/icon.woff2?t=1645269945236") format("woff2"),
|
url("/fonts/icon.woff2?t=1650537780691") format("woff2"),
|
||||||
url("/fonts/icon.woff?t=1645269945236") format("woff"),
|
url("/fonts/icon.woff?t=1650537780691") format("woff"),
|
||||||
url('/fonts/icon.ttf?t=1645269945236') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
|
url('/fonts/icon.ttf?t=1650537780691') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
|
||||||
url('/fonts/icon.svg?t=1645269945236#icon') format('svg'); /* iOS 4.1- */
|
url('/fonts/icon.svg?t=1650537780691#icon') format('svg'); /* iOS 4.1- */
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
text-decoration: inherit;
|
text-decoration: inherit;
|
||||||
width: 1em;
|
|
||||||
margin-right: .2em;
|
margin-right: .2em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
/* opacity: .8; */
|
/* opacity: .8; */
|
||||||
|
@ -79,101 +78,101 @@
|
||||||
.icon-down-open:before { content: "\ea22"; }
|
.icon-down-open:before { content: "\ea22"; }
|
||||||
.icon-download:before { content: "\ea23"; }
|
.icon-download:before { content: "\ea23"; }
|
||||||
.icon-edit:before { content: "\ea24"; }
|
.icon-edit:before { content: "\ea24"; }
|
||||||
.icon-enum:before { content: "\ea25"; }
|
.icon-email:before { content: "\ea25"; }
|
||||||
.icon-export:before { content: "\ea26"; }
|
.icon-enum:before { content: "\ea26"; }
|
||||||
.icon-eye:before { content: "\ea27"; }
|
.icon-export:before { content: "\ea27"; }
|
||||||
.icon-facebook:before { content: "\ea28"; }
|
.icon-eye:before { content: "\ea28"; }
|
||||||
.icon-file:before { content: "\ea29"; }
|
.icon-facebook:before { content: "\ea29"; }
|
||||||
.icon-film:before { content: "\ea2a"; }
|
.icon-file:before { content: "\ea2a"; }
|
||||||
.icon-filter:before { content: "\ea2b"; }
|
.icon-film:before { content: "\ea2b"; }
|
||||||
.icon-fire:before { content: "\ea2c"; }
|
.icon-filter:before { content: "\ea2c"; }
|
||||||
.icon-float:before { content: "\ea2d"; }
|
.icon-fire:before { content: "\ea2d"; }
|
||||||
.icon-folder:before { content: "\ea2e"; }
|
.icon-float:before { content: "\ea2e"; }
|
||||||
.icon-github:before { content: "\ea2f"; }
|
.icon-folder:before { content: "\ea2f"; }
|
||||||
.icon-gitlab:before { content: "\ea30"; }
|
.icon-github:before { content: "\ea30"; }
|
||||||
.icon-glasses:before { content: "\ea31"; }
|
.icon-gitlab:before { content: "\ea31"; }
|
||||||
.icon-google:before { content: "\ea32"; }
|
.icon-glasses:before { content: "\ea32"; }
|
||||||
.icon-hackernews:before { content: "\ea33"; }
|
.icon-google:before { content: "\ea33"; }
|
||||||
.icon-header:before { content: "\ea34"; }
|
.icon-hackernews:before { content: "\ea34"; }
|
||||||
.icon-heart:before { content: "\ea35"; }
|
.icon-header:before { content: "\ea35"; }
|
||||||
.icon-home:before { content: "\ea36"; }
|
.icon-heart:before { content: "\ea36"; }
|
||||||
.icon-image:before { content: "\ea37"; }
|
.icon-home:before { content: "\ea37"; }
|
||||||
.icon-inbox:before { content: "\ea38"; }
|
.icon-image:before { content: "\ea38"; }
|
||||||
.icon-info-circled:before { content: "\ea39"; }
|
.icon-inbox:before { content: "\ea39"; }
|
||||||
.icon-instagram:before { content: "\ea3a"; }
|
.icon-info-circled:before { content: "\ea3a"; }
|
||||||
.icon-integer:before { content: "\ea3b"; }
|
.icon-instagram:before { content: "\ea3b"; }
|
||||||
.icon-ip:before { content: "\ea3c"; }
|
.icon-integer:before { content: "\ea3c"; }
|
||||||
.icon-italic:before { content: "\ea3d"; }
|
.icon-ip:before { content: "\ea3d"; }
|
||||||
.icon-key-inv:before { content: "\ea3e"; }
|
.icon-italic:before { content: "\ea3e"; }
|
||||||
.icon-key:before { content: "\ea3f"; }
|
.icon-key-inv:before { content: "\ea3f"; }
|
||||||
.icon-keyboard:before { content: "\ea40"; }
|
.icon-key:before { content: "\ea40"; }
|
||||||
.icon-lamp:before { content: "\ea41"; }
|
.icon-keyboard:before { content: "\ea41"; }
|
||||||
.icon-left-dir:before { content: "\ea42"; }
|
.icon-lamp:before { content: "\ea42"; }
|
||||||
.icon-left-open:before { content: "\ea43"; }
|
.icon-left-dir:before { content: "\ea43"; }
|
||||||
.icon-lifebuoy:before { content: "\ea44"; }
|
.icon-left-open:before { content: "\ea44"; }
|
||||||
.icon-lightning:before { content: "\ea45"; }
|
.icon-lifebuoy:before { content: "\ea45"; }
|
||||||
.icon-link-ext:before { content: "\ea46"; }
|
.icon-lightning:before { content: "\ea46"; }
|
||||||
.icon-link:before { content: "\ea47"; }
|
.icon-link-ext:before { content: "\ea47"; }
|
||||||
.icon-url:before { content: "\ea47"; }
|
.icon-link:before { content: "\ea48"; }
|
||||||
.icon-linkedin:before { content: "\ea48"; }
|
.icon-linkedin:before { content: "\ea49"; }
|
||||||
.icon-list-bullet:before { content: "\ea49"; }
|
.icon-list-bullet:before { content: "\ea4a"; }
|
||||||
.icon-list-numbered:before { content: "\ea4a"; }
|
.icon-list-numbered:before { content: "\ea4b"; }
|
||||||
.icon-list:before { content: "\ea4b"; }
|
.icon-list:before { content: "\ea4c"; }
|
||||||
.icon-location:before { content: "\ea4c"; }
|
.icon-location:before { content: "\ea4d"; }
|
||||||
.icon-lock:before { content: "\ea4d"; }
|
.icon-lock:before { content: "\ea4e"; }
|
||||||
.icon-login:before { content: "\ea4e"; }
|
.icon-login:before { content: "\ea4f"; }
|
||||||
.icon-mail:before { content: "\ea4f"; }
|
.icon-mail:before { content: "\ea50"; }
|
||||||
.icon-email:before { content: "\ea4f"; }
|
.icon-medium:before { content: "\ea51"; }
|
||||||
.icon-medium:before { content: "\ea50"; }
|
.icon-menu:before { content: "\ea52"; }
|
||||||
.icon-menu:before { content: "\ea51"; }
|
.icon-minus:before { content: "\ea53"; }
|
||||||
.icon-minus:before { content: "\ea52"; }
|
.icon-moon-inv:before { content: "\ea54"; }
|
||||||
.icon-moon-inv:before { content: "\ea53"; }
|
.icon-moon:before { content: "\ea55"; }
|
||||||
.icon-moon:before { content: "\ea54"; }
|
.icon-more:before { content: "\ea56"; }
|
||||||
.icon-more:before { content: "\ea55"; }
|
.icon-network:before { content: "\ea57"; }
|
||||||
.icon-network:before { content: "\ea56"; }
|
.icon-ok-circled:before { content: "\ea58"; }
|
||||||
.icon-ok-circled:before { content: "\ea57"; }
|
.icon-ok:before { content: "\ea59"; }
|
||||||
.icon-ok:before { content: "\ea58"; }
|
.icon-palette:before { content: "\ea5a"; }
|
||||||
.icon-palette:before { content: "\ea59"; }
|
.icon-pause:before { content: "\ea5b"; }
|
||||||
.icon-pause:before { content: "\ea5a"; }
|
.icon-phone:before { content: "\ea5c"; }
|
||||||
.icon-phone:before { content: "\ea5b"; }
|
.icon-photograph:before { content: "\ea5d"; }
|
||||||
.icon-photograph:before { content: "\ea5c"; }
|
.icon-picture:before { content: "\ea5e"; }
|
||||||
.icon-picture:before { content: "\ea5d"; }
|
.icon-pinterest:before { content: "\ea5f"; }
|
||||||
.icon-pinterest:before { content: "\ea5e"; }
|
.icon-play:before { content: "\ea60"; }
|
||||||
.icon-play:before { content: "\ea5f"; }
|
.icon-plus:before { content: "\ea61"; }
|
||||||
.icon-plus:before { content: "\ea60"; }
|
.icon-qrcode:before { content: "\ea62"; }
|
||||||
.icon-qrcode:before { content: "\ea61"; }
|
.icon-question:before { content: "\ea63"; }
|
||||||
.icon-question:before { content: "\ea62"; }
|
.icon-quote-right:before { content: "\ea64"; }
|
||||||
.icon-quote-right:before { content: "\ea63"; }
|
.icon-random:before { content: "\ea65"; }
|
||||||
.icon-random:before { content: "\ea64"; }
|
.icon-reddit:before { content: "\ea66"; }
|
||||||
.icon-reddit:before { content: "\ea65"; }
|
.icon-refresh:before { content: "\ea67"; }
|
||||||
.icon-refresh:before { content: "\ea66"; }
|
.icon-right-dir:before { content: "\ea68"; }
|
||||||
.icon-right-dir:before { content: "\ea67"; }
|
.icon-right-open:before { content: "\ea69"; }
|
||||||
.icon-right-open:before { content: "\ea68"; }
|
.icon-rocket:before { content: "\ea6a"; }
|
||||||
.icon-rocket:before { content: "\ea69"; }
|
.icon-search:before { content: "\ea6b"; }
|
||||||
.icon-search:before { content: "\ea6a"; }
|
.icon-shield:before { content: "\ea6c"; }
|
||||||
.icon-shield:before { content: "\ea6b"; }
|
.icon-shuffle:before { content: "\ea6d"; }
|
||||||
.icon-shuffle:before { content: "\ea6c"; }
|
.icon-smile-o:before { content: "\ea6e"; }
|
||||||
.icon-smile-o:before { content: "\ea6d"; }
|
.icon-sort:before { content: "\ea6f"; }
|
||||||
.icon-sort:before { content: "\ea6e"; }
|
.icon-stackoverflow:before { content: "\ea70"; }
|
||||||
.icon-stackoverflow:before { content: "\ea6f"; }
|
.icon-stopwatch:before { content: "\ea71"; }
|
||||||
.icon-stopwatch:before { content: "\ea70"; }
|
.icon-string:before { content: "\ea72"; }
|
||||||
.icon-string:before { content: "\ea71"; }
|
.icon-sun-inv:before { content: "\ea73"; }
|
||||||
.icon-sun-inv:before { content: "\ea72"; }
|
.icon-telegram:before { content: "\ea74"; }
|
||||||
.icon-telegram:before { content: "\ea73"; }
|
.icon-trash-2:before { content: "\ea75"; }
|
||||||
.icon-trash-2:before { content: "\ea74"; }
|
.icon-trash:before { content: "\ea76"; }
|
||||||
.icon-trash:before { content: "\ea75"; }
|
.icon-twitter:before { content: "\ea77"; }
|
||||||
.icon-twitter:before { content: "\ea76"; }
|
.icon-underline:before { content: "\ea78"; }
|
||||||
.icon-underline:before { content: "\ea77"; }
|
.icon-up-dir:before { content: "\ea79"; }
|
||||||
.icon-up-dir:before { content: "\ea78"; }
|
.icon-up-open:before { content: "\ea7a"; }
|
||||||
.icon-up-open:before { content: "\ea79"; }
|
.icon-upload:before { content: "\ea7b"; }
|
||||||
.icon-upload:before { content: "\ea7a"; }
|
.icon-url:before { content: "\ea7c"; }
|
||||||
.icon-user:before { content: "\ea7b"; }
|
.icon-user:before { content: "\ea7d"; }
|
||||||
.icon-users:before { content: "\ea7c"; }
|
.icon-users:before { content: "\ea7e"; }
|
||||||
.icon-videocam:before { content: "\ea7d"; }
|
.icon-videocam:before { content: "\ea7f"; }
|
||||||
.icon-warning:before { content: "\ea7e"; }
|
.icon-warning:before { content: "\ea80"; }
|
||||||
.icon-whatsapp:before { content: "\ea7f"; }
|
.icon-whatsapp:before { content: "\ea81"; }
|
||||||
.icon-wheelchair:before { content: "\ea80"; }
|
.icon-wheelchair:before { content: "\ea82"; }
|
||||||
.icon-windows:before { content: "\ea81"; }
|
.icon-windows:before { content: "\ea83"; }
|
||||||
.icon-wrench:before { content: "\ea82"; }
|
.icon-wrench:before { content: "\ea84"; }
|
||||||
.icon-x:before { content: "\ea83"; }
|
.icon-x:before { content: "\ea85"; }
|
||||||
.icon-youtube-play:before { content: "\ea84"; }
|
.icon-youtube-play:before { content: "\ea86"; }
|
||||||
|
|
|
@ -16,9 +16,6 @@ class Event
|
||||||
const AUDITS_QUEUE_NAME = 'v1-audits';
|
const AUDITS_QUEUE_NAME = 'v1-audits';
|
||||||
const AUDITS_CLASS_NAME = 'AuditsV1';
|
const AUDITS_CLASS_NAME = 'AuditsV1';
|
||||||
|
|
||||||
const USAGE_QUEUE_NAME = 'v1-usage';
|
|
||||||
const USAGE_CLASS_NAME = 'UsageV1';
|
|
||||||
|
|
||||||
const MAILS_QUEUE_NAME = 'v1-mails';
|
const MAILS_QUEUE_NAME = 'v1-mails';
|
||||||
const MAILS_CLASS_NAME = 'MailsV1';
|
const MAILS_CLASS_NAME = 'MailsV1';
|
||||||
|
|
||||||
|
|
|
@ -145,6 +145,7 @@ class Exception extends \Exception
|
||||||
const PROJECT_INVALID_SUCCESS_URL = 'project_invalid_success_url';
|
const PROJECT_INVALID_SUCCESS_URL = 'project_invalid_success_url';
|
||||||
const PROJECT_INVALID_FAILURE_URL = 'project_invalid_failure_url';
|
const PROJECT_INVALID_FAILURE_URL = 'project_invalid_failure_url';
|
||||||
const PROJECT_MISSING_USER_ID = 'project_missing_user_id';
|
const PROJECT_MISSING_USER_ID = 'project_missing_user_id';
|
||||||
|
const PROJECT_RESERVED_PROJECT = 'project_reserved_project';
|
||||||
|
|
||||||
/** Webhooks */
|
/** Webhooks */
|
||||||
const WEBHOOK_NOT_FOUND = 'webhook_not_found';
|
const WEBHOOK_NOT_FOUND = 'webhook_not_found';
|
||||||
|
|
25
src/Appwrite/Utopia/Database/Validator/OrderAttributes.php
Normal file
25
src/Appwrite/Utopia/Database/Validator/OrderAttributes.php
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
namespace Appwrite\Utopia\Database\Validator;
|
||||||
|
|
||||||
|
use Utopia\Database\Document;
|
||||||
|
use Utopia\Database\Validator\OrderAttributes as ValidatorOrderAttributes;
|
||||||
|
|
||||||
|
class OrderAttributes extends ValidatorOrderAttributes
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Expression constructor
|
||||||
|
*
|
||||||
|
* @param Document[] $attributes
|
||||||
|
* @param Document[] $indexes
|
||||||
|
* @param bool $strict
|
||||||
|
*/
|
||||||
|
public function __construct($attributes, $indexes, $strict)
|
||||||
|
{
|
||||||
|
// Remove failed/stuck/processing indexes
|
||||||
|
$indexes = \array_filter($indexes, function($index) {
|
||||||
|
return $index->getAttribute('status') === 'available';
|
||||||
|
});
|
||||||
|
|
||||||
|
parent::__construct($attributes, $indexes, $strict);
|
||||||
|
}
|
||||||
|
}
|
25
src/Appwrite/Utopia/Database/Validator/Queries.php
Normal file
25
src/Appwrite/Utopia/Database/Validator/Queries.php
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
namespace Appwrite\Utopia\Database\Validator;
|
||||||
|
|
||||||
|
use Utopia\Database\Document;
|
||||||
|
use Utopia\Database\Validator\Queries as ValidatorQueries;
|
||||||
|
|
||||||
|
class Queries extends ValidatorQueries
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Expression constructor
|
||||||
|
*
|
||||||
|
* @param Document[] $attributes
|
||||||
|
* @param Document[] $indexes
|
||||||
|
* @param bool $strict
|
||||||
|
*/
|
||||||
|
public function __construct($attributes, $indexes, $strict)
|
||||||
|
{
|
||||||
|
// Remove failed/stuck/processing indexes
|
||||||
|
$indexes = \array_filter($indexes, function($index) {
|
||||||
|
return $index->getAttribute('status') === 'available';
|
||||||
|
});
|
||||||
|
|
||||||
|
parent::__construct($attributes, $indexes, $strict);
|
||||||
|
}
|
||||||
|
}
|
|
@ -53,9 +53,9 @@ class Execution extends Model
|
||||||
'default' => 0,
|
'default' => 0,
|
||||||
'example' => 0,
|
'example' => 0,
|
||||||
])
|
])
|
||||||
->addRule('stdout', [
|
->addRule('response', [
|
||||||
'type' => self::TYPE_STRING,
|
'type' => self::TYPE_STRING,
|
||||||
'description' => 'The script stdout output string. Logs the last 4,000 characters of the execution stdout output.',
|
'description' => 'The script response output string. Logs the last 4,000 characters of the execution response output.',
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'example' => '',
|
'example' => '',
|
||||||
])
|
])
|
||||||
|
|
|
@ -445,7 +445,7 @@ trait AccountBase
|
||||||
{
|
{
|
||||||
$email = $data['email'] ?? '';
|
$email = $data['email'] ?? '';
|
||||||
$session = $data['session'] ?? '';
|
$session = $data['session'] ?? '';
|
||||||
$newName = 'New Name';
|
$newName = 'Lorem';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for SUCCESS
|
* Test for SUCCESS
|
||||||
|
@ -532,7 +532,6 @@ trait AccountBase
|
||||||
$this->assertNotEmpty($response['body']['$id']);
|
$this->assertNotEmpty($response['body']['$id']);
|
||||||
$this->assertIsNumeric($response['body']['registration']);
|
$this->assertIsNumeric($response['body']['registration']);
|
||||||
$this->assertEquals($response['body']['email'], $email);
|
$this->assertEquals($response['body']['email'], $email);
|
||||||
$this->assertEquals($response['body']['name'], 'New Name');
|
|
||||||
|
|
||||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions', array_merge([
|
$response = $this->client->call(Client::METHOD_POST, '/account/sessions', array_merge([
|
||||||
'origin' => 'http://localhost',
|
'origin' => 'http://localhost',
|
||||||
|
@ -625,7 +624,6 @@ trait AccountBase
|
||||||
$this->assertNotEmpty($response['body']['$id']);
|
$this->assertNotEmpty($response['body']['$id']);
|
||||||
$this->assertIsNumeric($response['body']['registration']);
|
$this->assertIsNumeric($response['body']['registration']);
|
||||||
$this->assertEquals($response['body']['email'], $newEmail);
|
$this->assertEquals($response['body']['email'], $newEmail);
|
||||||
$this->assertEquals($response['body']['name'], 'New Name');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for FAILURE
|
* Test for FAILURE
|
||||||
|
@ -1339,6 +1337,7 @@ trait AccountBase
|
||||||
{
|
{
|
||||||
$id = $data['id'] ?? '';
|
$id = $data['id'] ?? '';
|
||||||
$token = $data['token'] ?? '';
|
$token = $data['token'] ?? '';
|
||||||
|
$email = $data['email'] ?? '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for SUCCESS
|
* Test for SUCCESS
|
||||||
|
@ -1361,6 +1360,20 @@ trait AccountBase
|
||||||
$sessionId = $response['body']['$id'];
|
$sessionId = $response['body']['$id'];
|
||||||
$session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']];
|
$session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']];
|
||||||
|
|
||||||
|
$response = $this->client->call(Client::METHOD_GET, '/account', array_merge([
|
||||||
|
'origin' => 'http://localhost',
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
|
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
|
||||||
|
]));
|
||||||
|
|
||||||
|
$this->assertEquals($response['headers']['status-code'], 200);
|
||||||
|
$this->assertNotEmpty($response['body']);
|
||||||
|
$this->assertNotEmpty($response['body']['$id']);
|
||||||
|
$this->assertIsNumeric($response['body']['registration']);
|
||||||
|
$this->assertEquals($response['body']['email'], $email);
|
||||||
|
$this->assertTrue($response['body']['emailVerification']);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for FAILURE
|
* Test for FAILURE
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -510,4 +510,85 @@ class AccountCustomClientTest extends Scope
|
||||||
|
|
||||||
$this->assertEquals($response['headers']['status-code'], 404);
|
$this->assertEquals($response['headers']['status-code'], 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @depends testUpdateAccountName
|
||||||
|
*/
|
||||||
|
public function testUpdateAccountNameSearch($data): void
|
||||||
|
{
|
||||||
|
$id = $data['id'] ?? '';
|
||||||
|
$email = $data['email'] ?? '';
|
||||||
|
$newName = 'Lorem';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for SUCCESS
|
||||||
|
*/
|
||||||
|
$response = $this->client->call(Client::METHOD_GET, '/users', [
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
|
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||||
|
], [
|
||||||
|
'search' => $newName
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals($response['headers']['status-code'], 200);
|
||||||
|
$this->assertNotEmpty($response['body']);
|
||||||
|
$this->assertNotEmpty($response['body']['users']);
|
||||||
|
$this->assertCount(1, $response['body']['users']);
|
||||||
|
$this->assertEquals($response['body']['users'][0]['email'], $email);
|
||||||
|
|
||||||
|
$response = $this->client->call(Client::METHOD_GET, '/users', [
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
|
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||||
|
], [
|
||||||
|
'search' => $id
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals($response['headers']['status-code'], 200);
|
||||||
|
$this->assertNotEmpty($response['body']);
|
||||||
|
$this->assertNotEmpty($response['body']['users']);
|
||||||
|
$this->assertCount(1, $response['body']['users']);
|
||||||
|
$this->assertEquals($response['body']['users'][0]['email'], $email);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @depends testUpdateAccountEmail
|
||||||
|
*/
|
||||||
|
public function testUpdateAccountEmailSearch($data): void
|
||||||
|
{
|
||||||
|
$id = $data['id'] ?? '';
|
||||||
|
$email = $data['email'] ?? '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for SUCCESS
|
||||||
|
*/
|
||||||
|
$response = $this->client->call(Client::METHOD_GET, '/users', [
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
|
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||||
|
], [
|
||||||
|
'search' => '"' . $email . '"'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals($response['headers']['status-code'], 200);
|
||||||
|
$this->assertNotEmpty($response['body']);
|
||||||
|
$this->assertNotEmpty($response['body']['users']);
|
||||||
|
$this->assertCount(1, $response['body']['users']);
|
||||||
|
$this->assertEquals($response['body']['users'][0]['email'], $email);
|
||||||
|
|
||||||
|
$response = $this->client->call(Client::METHOD_GET, '/users', [
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
|
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||||
|
], [
|
||||||
|
'search' => $id
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals($response['headers']['status-code'], 200);
|
||||||
|
$this->assertNotEmpty($response['body']);
|
||||||
|
$this->assertNotEmpty($response['body']['users']);
|
||||||
|
$this->assertCount(1, $response['body']['users']);
|
||||||
|
$this->assertEquals($response['body']['users'][0]['email'], $email);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1428,6 +1428,7 @@ trait DatabaseBase
|
||||||
]), [
|
]), [
|
||||||
'key' => 'probability',
|
'key' => 'probability',
|
||||||
'required' => false,
|
'required' => false,
|
||||||
|
'default' => 0,
|
||||||
'min' => 0,
|
'min' => 0,
|
||||||
'max' => 1,
|
'max' => 1,
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -208,7 +208,7 @@ class FunctionsCustomClientTest extends Scope
|
||||||
'x-appwrite-key' => $apikey,
|
'x-appwrite-key' => $apikey,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$output = json_decode($executions['body']['stdout'], true);
|
$output = json_decode($executions['body']['response'], true);
|
||||||
$this->assertEquals(200, $executions['headers']['status-code']);
|
$this->assertEquals(200, $executions['headers']['status-code']);
|
||||||
$this->assertEquals('completed', $executions['body']['status']);
|
$this->assertEquals('completed', $executions['body']['status']);
|
||||||
$this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']);
|
$this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']);
|
||||||
|
@ -383,7 +383,7 @@ class FunctionsCustomClientTest extends Scope
|
||||||
'async' => false
|
'async' => false
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$output = json_decode($execution['body']['stdout'], true);
|
$output = json_decode($execution['body']['response'], true);
|
||||||
$this->assertEquals(201, $execution['headers']['status-code']);
|
$this->assertEquals(201, $execution['headers']['status-code']);
|
||||||
$this->assertEquals('completed', $execution['body']['status']);
|
$this->assertEquals('completed', $execution['body']['status']);
|
||||||
$this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']);
|
$this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']);
|
||||||
|
|
|
@ -490,7 +490,7 @@ class FunctionsCustomServerTest extends Scope
|
||||||
$this->assertEquals($data['functionId'], $execution['body']['functionId']);
|
$this->assertEquals($data['functionId'], $execution['body']['functionId']);
|
||||||
$this->assertEquals('waiting', $execution['body']['status']);
|
$this->assertEquals('waiting', $execution['body']['status']);
|
||||||
$this->assertEquals(0, $execution['body']['statusCode']);
|
$this->assertEquals(0, $execution['body']['statusCode']);
|
||||||
$this->assertEquals('', $execution['body']['stdout']);
|
$this->assertEquals('', $execution['body']['response']);
|
||||||
$this->assertEquals('', $execution['body']['stderr']);
|
$this->assertEquals('', $execution['body']['stderr']);
|
||||||
$this->assertEquals(0, $execution['body']['time']);
|
$this->assertEquals(0, $execution['body']['time']);
|
||||||
|
|
||||||
|
@ -507,13 +507,13 @@ class FunctionsCustomServerTest extends Scope
|
||||||
$this->assertEquals($data['functionId'], $execution['body']['functionId']);
|
$this->assertEquals($data['functionId'], $execution['body']['functionId']);
|
||||||
$this->assertEquals('completed', $execution['body']['status']);
|
$this->assertEquals('completed', $execution['body']['status']);
|
||||||
$this->assertEquals(200, $execution['body']['statusCode']);
|
$this->assertEquals(200, $execution['body']['statusCode']);
|
||||||
$this->assertStringContainsString($execution['body']['functionId'], $execution['body']['stdout']);
|
$this->assertStringContainsString($execution['body']['functionId'], $execution['body']['response']);
|
||||||
$this->assertStringContainsString($data['deploymentId'], $execution['body']['stdout']);
|
$this->assertStringContainsString($data['deploymentId'], $execution['body']['response']);
|
||||||
$this->assertStringContainsString('Test1', $execution['body']['stdout']);
|
$this->assertStringContainsString('Test1', $execution['body']['response']);
|
||||||
$this->assertStringContainsString('http', $execution['body']['stdout']);
|
$this->assertStringContainsString('http', $execution['body']['response']);
|
||||||
$this->assertStringContainsString('PHP', $execution['body']['stdout']);
|
$this->assertStringContainsString('PHP', $execution['body']['response']);
|
||||||
$this->assertStringContainsString('8.0', $execution['body']['stdout']);
|
$this->assertStringContainsString('8.0', $execution['body']['response']);
|
||||||
// $this->assertStringContainsString('êä', $execution['body']['stdout']); // tests unknown utf-8 chars
|
// $this->assertStringContainsString('êä', $execution['body']['response']); // tests unknown utf-8 chars
|
||||||
$this->assertEquals('', $execution['body']['stderr']);
|
$this->assertEquals('', $execution['body']['stderr']);
|
||||||
$this->assertLessThan(0.500, $execution['body']['time']);
|
$this->assertLessThan(0.500, $execution['body']['time']);
|
||||||
|
|
||||||
|
@ -596,11 +596,11 @@ class FunctionsCustomServerTest extends Scope
|
||||||
$this->assertEquals(201, $execution['headers']['status-code']);
|
$this->assertEquals(201, $execution['headers']['status-code']);
|
||||||
|
|
||||||
$this->assertEquals('completed', $execution['body']['status']);
|
$this->assertEquals('completed', $execution['body']['status']);
|
||||||
$this->assertStringContainsString($data['deploymentId'], $execution['body']['stdout']);
|
$this->assertStringContainsString($data['deploymentId'], $execution['body']['response']);
|
||||||
$this->assertStringContainsString('Test1', $execution['body']['stdout']);
|
$this->assertStringContainsString('Test1', $execution['body']['response']);
|
||||||
$this->assertStringContainsString('http', $execution['body']['stdout']);
|
$this->assertStringContainsString('http', $execution['body']['response']);
|
||||||
$this->assertStringContainsString('PHP', $execution['body']['stdout']);
|
$this->assertStringContainsString('PHP', $execution['body']['response']);
|
||||||
$this->assertStringContainsString('8.0', $execution['body']['stdout']);
|
$this->assertStringContainsString('8.0', $execution['body']['response']);
|
||||||
// $this->assertStringContainsString('êä', $execution['body']['sdtout']); // tests unknown utf-8 chars
|
// $this->assertStringContainsString('êä', $execution['body']['sdtout']); // tests unknown utf-8 chars
|
||||||
$this->assertLessThan(0.500, $execution['body']['time']);
|
$this->assertLessThan(0.500, $execution['body']['time']);
|
||||||
|
|
||||||
|
@ -764,7 +764,7 @@ class FunctionsCustomServerTest extends Scope
|
||||||
$this->assertEquals($executions['body']['executions'][0]['statusCode'], 124);
|
$this->assertEquals($executions['body']['executions'][0]['statusCode'], 124);
|
||||||
$this->assertGreaterThan(2, $executions['body']['executions'][0]['time']);
|
$this->assertGreaterThan(2, $executions['body']['executions'][0]['time']);
|
||||||
$this->assertLessThan(3, $executions['body']['executions'][0]['time']);
|
$this->assertLessThan(3, $executions['body']['executions'][0]['time']);
|
||||||
$this->assertEquals($executions['body']['executions'][0]['stdout'], '');
|
$this->assertEquals($executions['body']['executions'][0]['response'], '');
|
||||||
$this->assertEquals($executions['body']['executions'][0]['stderr'], 'Execution timed out.');
|
$this->assertEquals($executions['body']['executions'][0]['stderr'], 'Execution timed out.');
|
||||||
|
|
||||||
// Cleanup : Delete function
|
// Cleanup : Delete function
|
||||||
|
@ -847,7 +847,7 @@ class FunctionsCustomServerTest extends Scope
|
||||||
'x-appwrite-project' => $this->getProject()['$id'],
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
], $this->getHeaders()));
|
], $this->getHeaders()));
|
||||||
|
|
||||||
$output = json_decode($executions['body']['stdout'], true);
|
$output = json_decode($executions['body']['response'], true);
|
||||||
|
|
||||||
$this->assertEquals(200, $executions['headers']['status-code']);
|
$this->assertEquals(200, $executions['headers']['status-code']);
|
||||||
$this->assertEquals('completed', $executions['body']['status']);
|
$this->assertEquals('completed', $executions['body']['status']);
|
||||||
|
@ -875,7 +875,7 @@ class FunctionsCustomServerTest extends Scope
|
||||||
$this->assertCount(1, $executions['body']['executions']);
|
$this->assertCount(1, $executions['body']['executions']);
|
||||||
$this->assertEquals($executions['body']['executions'][0]['$id'], $executionId);
|
$this->assertEquals($executions['body']['executions'][0]['$id'], $executionId);
|
||||||
$this->assertEquals($executions['body']['executions'][0]['trigger'], 'http');
|
$this->assertEquals($executions['body']['executions'][0]['trigger'], 'http');
|
||||||
$this->assertStringContainsString('foobar', $executions['body']['executions'][0]['stdout']);
|
$this->assertStringContainsString('foobar', $executions['body']['executions'][0]['response']);
|
||||||
|
|
||||||
// Cleanup : Delete function
|
// Cleanup : Delete function
|
||||||
$response = $this->client->call(Client::METHOD_DELETE, '/functions/'. $functionId, [
|
$response = $this->client->call(Client::METHOD_DELETE, '/functions/'. $functionId, [
|
||||||
|
@ -952,7 +952,7 @@ class FunctionsCustomServerTest extends Scope
|
||||||
'x-appwrite-project' => $this->getProject()['$id'],
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
], $this->getHeaders()));
|
], $this->getHeaders()));
|
||||||
|
|
||||||
$output = json_decode($executions['body']['stdout'], true);
|
$output = json_decode($executions['body']['response'], true);
|
||||||
|
|
||||||
$this->assertEquals(200, $executions['headers']['status-code']);
|
$this->assertEquals(200, $executions['headers']['status-code']);
|
||||||
$this->assertEquals('completed', $executions['body']['status']);
|
$this->assertEquals('completed', $executions['body']['status']);
|
||||||
|
@ -981,7 +981,7 @@ class FunctionsCustomServerTest extends Scope
|
||||||
$this->assertCount(1, $executions['body']['executions']);
|
$this->assertCount(1, $executions['body']['executions']);
|
||||||
$this->assertEquals($executions['body']['executions'][0]['$id'], $executionId);
|
$this->assertEquals($executions['body']['executions'][0]['$id'], $executionId);
|
||||||
$this->assertEquals($executions['body']['executions'][0]['trigger'], 'http');
|
$this->assertEquals($executions['body']['executions'][0]['trigger'], 'http');
|
||||||
$this->assertStringContainsString('foobar', $executions['body']['executions'][0]['stdout']);
|
$this->assertStringContainsString('foobar', $executions['body']['executions'][0]['response']);
|
||||||
|
|
||||||
// Cleanup : Delete function
|
// Cleanup : Delete function
|
||||||
$response = $this->client->call(Client::METHOD_DELETE, '/functions/'. $functionId, [
|
$response = $this->client->call(Client::METHOD_DELETE, '/functions/'. $functionId, [
|
||||||
|
@ -1057,7 +1057,7 @@ class FunctionsCustomServerTest extends Scope
|
||||||
'x-appwrite-project' => $this->getProject()['$id'],
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
], $this->getHeaders()));
|
], $this->getHeaders()));
|
||||||
|
|
||||||
$output = json_decode($executions['body']['stdout'], true);
|
$output = json_decode($executions['body']['response'], true);
|
||||||
|
|
||||||
$this->assertEquals(200, $executions['headers']['status-code']);
|
$this->assertEquals(200, $executions['headers']['status-code']);
|
||||||
$this->assertEquals('completed', $executions['body']['status']);
|
$this->assertEquals('completed', $executions['body']['status']);
|
||||||
|
@ -1086,7 +1086,7 @@ class FunctionsCustomServerTest extends Scope
|
||||||
$this->assertCount(1, $executions['body']['executions']);
|
$this->assertCount(1, $executions['body']['executions']);
|
||||||
$this->assertEquals($executions['body']['executions'][0]['$id'], $executionId);
|
$this->assertEquals($executions['body']['executions'][0]['$id'], $executionId);
|
||||||
$this->assertEquals($executions['body']['executions'][0]['trigger'], 'http');
|
$this->assertEquals($executions['body']['executions'][0]['trigger'], 'http');
|
||||||
$this->assertStringContainsString('foobar', $executions['body']['executions'][0]['stdout']);
|
$this->assertStringContainsString('foobar', $executions['body']['executions'][0]['response']);
|
||||||
|
|
||||||
// Cleanup : Delete function
|
// Cleanup : Delete function
|
||||||
$response = $this->client->call(Client::METHOD_DELETE, '/functions/'. $functionId, [
|
$response = $this->client->call(Client::METHOD_DELETE, '/functions/'. $functionId, [
|
||||||
|
@ -1162,7 +1162,7 @@ class FunctionsCustomServerTest extends Scope
|
||||||
'x-appwrite-project' => $this->getProject()['$id'],
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
], $this->getHeaders()));
|
], $this->getHeaders()));
|
||||||
|
|
||||||
$output = json_decode($executions['body']['stdout'], true);
|
$output = json_decode($executions['body']['response'], true);
|
||||||
|
|
||||||
$this->assertEquals(200, $executions['headers']['status-code']);
|
$this->assertEquals(200, $executions['headers']['status-code']);
|
||||||
$this->assertEquals('completed', $executions['body']['status']);
|
$this->assertEquals('completed', $executions['body']['status']);
|
||||||
|
@ -1191,7 +1191,7 @@ class FunctionsCustomServerTest extends Scope
|
||||||
$this->assertCount(1, $executions['body']['executions']);
|
$this->assertCount(1, $executions['body']['executions']);
|
||||||
$this->assertEquals($executions['body']['executions'][0]['$id'], $executionId);
|
$this->assertEquals($executions['body']['executions'][0]['$id'], $executionId);
|
||||||
$this->assertEquals($executions['body']['executions'][0]['trigger'], 'http');
|
$this->assertEquals($executions['body']['executions'][0]['trigger'], 'http');
|
||||||
$this->assertStringContainsString('foobar', $executions['body']['executions'][0]['stdout']);
|
$this->assertStringContainsString('foobar', $executions['body']['executions'][0]['response']);
|
||||||
|
|
||||||
// Cleanup : Delete function
|
// Cleanup : Delete function
|
||||||
$response = $this->client->call(Client::METHOD_DELETE, '/functions/'. $functionId, [
|
$response = $this->client->call(Client::METHOD_DELETE, '/functions/'. $functionId, [
|
||||||
|
@ -1267,7 +1267,7 @@ class FunctionsCustomServerTest extends Scope
|
||||||
'x-appwrite-project' => $this->getProject()['$id'],
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
], $this->getHeaders()));
|
], $this->getHeaders()));
|
||||||
|
|
||||||
$output = json_decode($executions['body']['stdout'], true);
|
$output = json_decode($executions['body']['response'], true);
|
||||||
|
|
||||||
$this->assertEquals(200, $executions['headers']['status-code']);
|
$this->assertEquals(200, $executions['headers']['status-code']);
|
||||||
$this->assertEquals('completed', $executions['body']['status']);
|
$this->assertEquals('completed', $executions['body']['status']);
|
||||||
|
@ -1296,7 +1296,7 @@ class FunctionsCustomServerTest extends Scope
|
||||||
$this->assertCount(1, $executions['body']['executions']);
|
$this->assertCount(1, $executions['body']['executions']);
|
||||||
$this->assertEquals($executions['body']['executions'][0]['$id'], $executionId);
|
$this->assertEquals($executions['body']['executions'][0]['$id'], $executionId);
|
||||||
$this->assertEquals($executions['body']['executions'][0]['trigger'], 'http');
|
$this->assertEquals($executions['body']['executions'][0]['trigger'], 'http');
|
||||||
$this->assertStringContainsString('foobar', $executions['body']['executions'][0]['stdout']);
|
$this->assertStringContainsString('foobar', $executions['body']['executions'][0]['response']);
|
||||||
|
|
||||||
// Cleanup : Delete function
|
// Cleanup : Delete function
|
||||||
$response = $this->client->call(Client::METHOD_DELETE, '/functions/'. $functionId, [
|
$response = $this->client->call(Client::METHOD_DELETE, '/functions/'. $functionId, [
|
||||||
|
@ -1372,7 +1372,7 @@ class FunctionsCustomServerTest extends Scope
|
||||||
// 'x-appwrite-project' => $this->getProject()['$id'],
|
// 'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
// ], $this->getHeaders()));
|
// ], $this->getHeaders()));
|
||||||
|
|
||||||
// $output = json_decode($executions['body']['stdout'], true);
|
// $output = json_decode($executions['body']['response'], true);
|
||||||
|
|
||||||
// $this->assertEquals(200, $executions['headers']['status-code']);
|
// $this->assertEquals(200, $executions['headers']['status-code']);
|
||||||
// $this->assertEquals('completed', $executions['body']['status']);
|
// $this->assertEquals('completed', $executions['body']['status']);
|
||||||
|
@ -1401,7 +1401,7 @@ class FunctionsCustomServerTest extends Scope
|
||||||
// $this->assertCount(1, $executions['body']['executions']);
|
// $this->assertCount(1, $executions['body']['executions']);
|
||||||
// $this->assertEquals($executions['body']['executions'][0]['$id'], $executionId);
|
// $this->assertEquals($executions['body']['executions'][0]['$id'], $executionId);
|
||||||
// $this->assertEquals($executions['body']['executions'][0]['trigger'], 'http');
|
// $this->assertEquals($executions['body']['executions'][0]['trigger'], 'http');
|
||||||
// $this->assertStringContainsString('foobar', $executions['body']['executions'][0]['stdout']);
|
// $this->assertStringContainsString('foobar', $executions['body']['executions'][0]['response']);
|
||||||
|
|
||||||
// // Cleanup : Delete function
|
// // Cleanup : Delete function
|
||||||
// $response = $this->client->call(Client::METHOD_DELETE, '/functions/'. $functionId, [
|
// $response = $this->client->call(Client::METHOD_DELETE, '/functions/'. $functionId, [
|
||||||
|
|
|
@ -146,27 +146,6 @@ class HealthCustomServerTest extends Scope
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testUsageSuccess(): array
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Test for SUCCESS
|
|
||||||
*/
|
|
||||||
$response = $this->client->call(Client::METHOD_GET, '/health/queue/usage', array_merge([
|
|
||||||
'content-type' => 'application/json',
|
|
||||||
'x-appwrite-project' => $this->getProject()['$id'],
|
|
||||||
], $this->getHeaders()), []);
|
|
||||||
|
|
||||||
$this->assertEquals(200, $response['headers']['status-code']);
|
|
||||||
$this->assertIsInt($response['body']['size']);
|
|
||||||
$this->assertLessThan(200, $response['body']['size']);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test for FAILURE
|
|
||||||
*/
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testCertificatesSuccess(): array
|
public function testCertificatesSuccess(): array
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -281,6 +281,44 @@ trait UsersBase
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @depends testUpdateUserName
|
||||||
|
*/
|
||||||
|
public function testUpdateUserNameSearch($data): void
|
||||||
|
{
|
||||||
|
$id = $data['userId'] ?? '';
|
||||||
|
$newName = 'Updated name';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for SUCCESS
|
||||||
|
*/
|
||||||
|
$response = $this->client->call(Client::METHOD_GET, '/users', array_merge([
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
|
], $this->getHeaders()), [
|
||||||
|
'search' => $newName
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals($response['headers']['status-code'], 200);
|
||||||
|
$this->assertNotEmpty($response['body']);
|
||||||
|
$this->assertNotEmpty($response['body']['users']);
|
||||||
|
$this->assertCount(1, $response['body']['users']);
|
||||||
|
$this->assertEquals($response['body']['users'][0]['$id'], $id);
|
||||||
|
|
||||||
|
$response = $this->client->call(Client::METHOD_GET, '/users', array_merge([
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
|
], $this->getHeaders()), [
|
||||||
|
'search' => $id
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals($response['headers']['status-code'], 200);
|
||||||
|
$this->assertNotEmpty($response['body']);
|
||||||
|
$this->assertNotEmpty($response['body']['users']);
|
||||||
|
$this->assertCount(1, $response['body']['users']);
|
||||||
|
$this->assertEquals($response['body']['users'][0]['$id'], $id);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @depends testGetUser
|
* @depends testGetUser
|
||||||
*/
|
*/
|
||||||
|
@ -310,6 +348,44 @@ trait UsersBase
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @depends testUpdateUserEmail
|
||||||
|
*/
|
||||||
|
public function testUpdateUserEmailSearch($data): void
|
||||||
|
{
|
||||||
|
$id = $data['userId'] ?? '';
|
||||||
|
$newEmail = '"users.service@updated.com"';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for SUCCESS
|
||||||
|
*/
|
||||||
|
$response = $this->client->call(Client::METHOD_GET, '/users', array_merge([
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
|
], $this->getHeaders()), [
|
||||||
|
'search' => $newEmail
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals($response['headers']['status-code'], 200);
|
||||||
|
$this->assertNotEmpty($response['body']);
|
||||||
|
$this->assertNotEmpty($response['body']['users']);
|
||||||
|
$this->assertCount(1, $response['body']['users']);
|
||||||
|
$this->assertEquals($response['body']['users'][0]['$id'], $id);
|
||||||
|
|
||||||
|
$response = $this->client->call(Client::METHOD_GET, '/users', array_merge([
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
|
], $this->getHeaders()), [
|
||||||
|
'search' => $id
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals($response['headers']['status-code'], 200);
|
||||||
|
$this->assertNotEmpty($response['body']);
|
||||||
|
$this->assertNotEmpty($response['body']['users']);
|
||||||
|
$this->assertCount(1, $response['body']['users']);
|
||||||
|
$this->assertEquals($response['body']['users'][0]['$id'], $id);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @depends testUpdateUserEmail
|
* @depends testUpdateUserEmail
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in a new issue