Merge branch 'refactor-usage-sn' into remove-cloud-scripts

This commit is contained in:
Christy Jacob 2024-02-28 09:52:12 +05:30 committed by GitHub
commit ac5d45d71c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 517 additions and 152 deletions

View file

@ -17,6 +17,12 @@ jobs:
fetch-depth: 2
submodules: recursive
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
@ -35,11 +41,11 @@ jobs:
uses: docker/build-push-action@v4
with:
context: .
platforms: linux/amd64
platforms: linux/amd64,linux/arm64
build-args: |
VERSION=${{ steps.meta.outputs.version }}
VITE_APPWRITE_GROWTH_ENDPOINT=https://growth.appwrite.io/v1
VITE_GA_PROJECT=G-L7G2B6PLDS
VITE_CONSOLE_MODE=cloud
push: true
tags: ${{ steps.meta.outputs.tags }}
tags: ${{ steps.meta.outputs.tags }}

View file

@ -1791,7 +1791,7 @@ App::get('/v1/account/logs')
}
$response->dynamic(new Document([
'total' => $audit->countLogsByUser($user->getInternalId()),
'total' => $audit->countLogsByUser($user->getId()),
'logs' => $output,
]), Response::MODEL_LOG_LIST);
});
@ -2526,7 +2526,7 @@ App::post('/v1/account/recovery')
$queueForMails
->setRecipient($profile->getAttribute('email', ''))
->setName($profile->getAttribute('name'))
->setName($profile->getAttribute('name', ''))
->setBody($body)
->setVariables($emailVariables)
->setSubject($subject)

View file

@ -2997,6 +2997,33 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
$processDocument($collection, $document);
}
$select = \array_reduce($queries, function ($result, $query) {
return $result || ($query->getMethod() === Query::TYPE_SELECT);
}, false);
// Check if the SELECT query includes $databaseId and $collectionId
$hasDatabaseId = false;
$hasCollectionId = false;
if ($select) {
$hasDatabaseId = \array_reduce($queries, function ($result, $query) {
return $result || ($query->getMethod() === Query::TYPE_SELECT && \in_array('$databaseId', $query->getValues()));
}, false);
$hasCollectionId = \array_reduce($queries, function ($result, $query) {
return $result || ($query->getMethod() === Query::TYPE_SELECT && \in_array('$collectionId', $query->getValues()));
}, false);
}
if ($select) {
foreach ($documents as $document) {
if (!$hasDatabaseId) {
$document->removeAttribute('$databaseId');
}
if (!$hasCollectionId) {
$document->removeAttribute('$collectionId');
}
}
}
$response->dynamic(new Document([
'total' => $total,
'documents' => $documents,

View file

@ -702,6 +702,47 @@ App::get('/v1/health/storage/local')
$response->dynamic(new Document($output), Response::MODEL_HEALTH_STATUS);
});
App::get('/v1/health/storage')
->desc('Get storage')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'health')
->label('sdk.method', 'getStorage')
->label('sdk.description', '/docs/references/health/get-storage.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_HEALTH_STATUS)
->inject('response')
->inject('deviceFiles')
->inject('deviceFunctions')
->inject('deviceBuilds')
->action(function (Response $response, Device $deviceFiles, Device $deviceFunctions, Device $deviceBuilds) {
$devices = [$deviceFiles, $deviceFunctions, $deviceBuilds];
$checkStart = \microtime(true);
foreach ($devices as $device) {
if (!$device->write($device->getPath('health.txt'), 'test', 'text/plain')) {
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed writing test file to ' . $device->getRoot());
}
if ($device->read($device->getPath('health.txt')) !== 'test') {
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed reading test file from ' . $device->getRoot());
}
if (!$device->delete($device->getPath('health.txt'))) {
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed deleting test file from ' . $device->getRoot());
}
}
$output = [
'status' => 'pass',
'ping' => \round((\microtime(true) - $checkStart) / 1000)
];
$response->dynamic(new Document($output), Response::MODEL_HEALTH_STATUS);
});
App::get('/v1/health/anti-virus')
->desc('Get antivirus')
->groups(['api', 'health'])

View file

@ -144,9 +144,30 @@ App::get('/v1/project/usage')
];
}, $dbForProject->find('buckets'));
// merge network inbound + outbound
$projectBandwidth = [];
foreach ($usage[METRIC_NETWORK_INBOUND] as $item) {
$projectBandwidth[$item['date']] ??= 0;
$projectBandwidth[$item['date']] += $item['value'];
}
foreach ($usage[METRIC_NETWORK_OUTBOUND] as $item) {
$projectBandwidth[$item['date']] ??= 0;
$projectBandwidth[$item['date']] += $item['value'];
}
$network = [];
foreach ($projectBandwidth as $date => $value) {
$network[] = [
'date' => $date,
'value' => $value
];
}
$response->dynamic(new Document([
'requests' => ($usage[METRIC_NETWORK_REQUESTS]),
'network' => ($usage[METRIC_NETWORK_INBOUND] + $usage[METRIC_NETWORK_OUTBOUND]),
'network' => $network,
'users' => ($usage[METRIC_USERS]),
'executions' => ($usage[METRIC_EXECUTIONS]),
'executionsTotal' => $total[METRIC_EXECUTIONS],

View file

@ -615,9 +615,6 @@ App::get('/v1/users/:userId/logs')
$output[$i] = new Document([
'event' => $log['event'],
'userId' => ID::custom($log['data']['userId']),
'userEmail' => $log['data']['userEmail'] ?? null,
'userName' => $log['data']['userName'] ?? null,
'ip' => $log['ip'],
'time' => $log['time'],
'osCode' => $os['osCode'],
@ -646,7 +643,7 @@ App::get('/v1/users/:userId/logs')
}
$response->dynamic(new Document([
'total' => $audit->countLogsByUser($user->getInternalId()),
'total' => $audit->countLogsByUser($user->getId()),
'logs' => $output,
]), Response::MODEL_LOG_LIST);
});

View file

@ -9,9 +9,8 @@ use Utopia\Logger\Logger;
use Utopia\Logger\Log;
use Utopia\Logger\Log\User;
use Swoole\Http\Request as SwooleRequest;
use Utopia\Cache\Cache;
use Utopia\Pools\Group;
use Appwrite\Utopia\Request;
use MaxMind\Db\Reader;
use Appwrite\Utopia\Response;
use Appwrite\Utopia\View;
use Appwrite\Extend\Exception as AppwriteException;
@ -19,6 +18,8 @@ use Utopia\Config\Config;
use Utopia\Domains\Domain;
use Appwrite\Auth\Auth;
use Appwrite\Event\Certificate;
use Appwrite\Event\Event;
use Appwrite\Event\Usage;
use Appwrite\Network\Validator\Origin;
use Appwrite\Utopia\Response\Filters\V11 as ResponseV11;
use Appwrite\Utopia\Response\Filters\V12 as ResponseV12;
@ -31,6 +32,7 @@ use Utopia\Database\Database;
use Utopia\Database\DateTime;
use Utopia\Database\Document;
use Utopia\Database\Query;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Validator\Authorization;
use Utopia\Validator\Hostname;
use Appwrite\Utopia\Request\Filters\V12 as RequestV12;
@ -38,6 +40,7 @@ use Appwrite\Utopia\Request\Filters\V13 as RequestV13;
use Appwrite\Utopia\Request\Filters\V14 as RequestV14;
use Appwrite\Utopia\Request\Filters\V15 as RequestV15;
use Appwrite\Utopia\Request\Filters\V16 as RequestV16;
use Executor\Executor;
use Utopia\Validator\Text;
use Utopia\Validator\WhiteList;
@ -45,7 +48,7 @@ Config::setParam('domainVerification', false);
Config::setParam('cookieDomain', 'localhost');
Config::setParam('cookieSamesite', Response::COOKIE_SAMESITE_NONE);
function router(App $utopia, Database $dbForConsole, SwooleRequest $swooleRequest, Request $request, Response $response)
function router(App $utopia, Database $dbForConsole, callable $getProjectDB, SwooleRequest $swooleRequest, Request $request, Response $response, Event $queueForEvents, Usage $queueForUsage, Reader $geodb)
{
$utopia->getRoute()?->label('error', __DIR__ . '/../views/general/error.phtml');
@ -117,59 +120,218 @@ function router(App $utopia, Database $dbForConsole, SwooleRequest $swooleReques
$path .= '?' . $query;
}
$body = $swooleRequest->getContent() ?? '';
$method = $swooleRequest->server['request_method'];
$requestHeaders = $request->getHeaders();
$body = \json_encode([
'async' => false,
'body' => $swooleRequest->getContent() ?? '',
'method' => $swooleRequest->server['request_method'],
'path' => $path,
'headers' => $requestHeaders
$project = Authorization::skip(fn () => $dbForConsole->getDocument('projects', $projectId));
$dbForProject = $getProjectDB($project);
$function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId));
if ($function->isEmpty() || !$function->getAttribute('enabled')) {
throw new AppwriteException(AppwriteException::FUNCTION_NOT_FOUND);
}
$version = $function->getAttribute('version', 'v2');
$runtimes = Config::getParam($version === 'v2' ? 'runtimes-v2' : 'runtimes', []);
$runtime = (isset($runtimes[$function->getAttribute('runtime', '')])) ? $runtimes[$function->getAttribute('runtime', '')] : null;
if (\is_null($runtime)) {
throw new AppwriteException(AppwriteException::FUNCTION_RUNTIME_UNSUPPORTED, 'Runtime "' . $function->getAttribute('runtime', '') . '" is not supported');
}
$deployment = Authorization::skip(fn () => $dbForProject->getDocument('deployments', $function->getAttribute('deployment', '')));
if ($deployment->getAttribute('resourceId') !== $function->getId()) {
throw new AppwriteException(AppwriteException::DEPLOYMENT_NOT_FOUND, 'Deployment not found. Create a deployment before trying to execute a function');
}
if ($deployment->isEmpty()) {
throw new AppwriteException(AppwriteException::DEPLOYMENT_NOT_FOUND, 'Deployment not found. Create a deployment before trying to execute a function');
}
/** Check if build has completed */
$build = Authorization::skip(fn () => $dbForProject->getDocument('builds', $deployment->getAttribute('buildId', '')));
if ($build->isEmpty()) {
throw new AppwriteException(AppwriteException::BUILD_NOT_FOUND);
}
if ($build->getAttribute('status') !== 'ready') {
throw new AppwriteException(AppwriteException::BUILD_NOT_READY);
}
$permissions = $function->getAttribute('execute');
if (!(\in_array('any', $permissions)) && (\in_array('guests', $permissions))) {
throw new AppwriteException(AppwriteException::USER_UNAUTHORIZED, 'To execute function using domain, execute permissions must include "any" or "guests"');
}
$headers = \array_merge([], $requestHeaders);
$headers['x-appwrite-trigger'] = 'http';
$headers['x-appwrite-user-id'] = '';
$headers['x-appwrite-user-jwt'] = '';
$headers['x-appwrite-country-code'] = '';
$headers['x-appwrite-continent-code'] = '';
$headers['x-appwrite-continent-eu'] = 'false';
$ip = $headers['x-real-ip'] ?? '';
if (!empty($ip)) {
$record = $geodb->get($ip);
if ($record) {
$eu = Config::getParam('locale-eu');
$headers['x-appwrite-country-code'] = $record['country']['iso_code'] ?? '';
$headers['x-appwrite-continent-code'] = $record['continent']['code'] ?? '';
$headers['x-appwrite-continent-eu'] = (\in_array($record['country']['iso_code'], $eu)) ? 'true' : 'false';
}
}
$headersFiltered = [];
foreach ($headers as $key => $value) {
if (\in_array(\strtolower($key), FUNCTION_ALLOWLIST_HEADERS_REQUEST)) {
$headersFiltered[] = ['name' => $key, 'value' => $value];
}
}
$executionId = ID::unique();
$execution = new Document([
'$id' => $executionId,
'$permissions' => [],
'functionInternalId' => $function->getInternalId(),
'functionId' => $function->getId(),
'deploymentInternalId' => $deployment->getInternalId(),
'deploymentId' => $deployment->getId(),
'trigger' => 'http', // http / schedule / event
'status' => 'processing', // waiting / processing / completed / failed
'responseStatusCode' => 0,
'responseHeaders' => [],
'requestPath' => $path,
'requestMethod' => $method,
'requestHeaders' => $headersFiltered,
'errors' => '',
'logs' => '',
'duration' => 0.0,
'search' => implode(' ', [$functionId, $executionId]),
]);
$headers = [
'Content-Type: application/json',
'Content-Length: ' . \strlen($body),
'X-Appwrite-Project: ' . $projectId
];
$queueForEvents
->setParam('functionId', $function->getId())
->setParam('executionId', $execution->getId())
->setContext('function', $function);
$ch = \curl_init();
\curl_setopt($ch, CURLOPT_URL, "http://localhost/v1/functions/{$functionId}/executions");
\curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
\curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
\curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
\curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// \curl_setopt($ch, CURLOPT_HEADER, true);
\curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
\curl_setopt($ch, CURLOPT_TIMEOUT, 30);
$durationStart = \microtime(true);
$executionResponse = \curl_exec($ch);
$statusCode = \curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = \curl_error($ch);
$errNo = \curl_errno($ch);
$vars = [];
\curl_close($ch);
if ($errNo !== 0) {
throw new AppwriteException(AppwriteException::GENERAL_ARGUMENT_INVALID, "Internal error: " . $error);
// V2 vars
if ($version === 'v2') {
$vars = \array_merge($vars, [
'APPWRITE_FUNCTION_TRIGGER' => $headers['x-appwrite-trigger'] ?? '',
'APPWRITE_FUNCTION_DATA' => $body ?? '',
'APPWRITE_FUNCTION_USER_ID' => $headers['x-appwrite-user-id'] ?? '',
'APPWRITE_FUNCTION_JWT' => $headers['x-appwrite-user-jwt'] ?? ''
]);
}
if ($statusCode >= 400) {
$error = \json_decode($executionResponse, true)['message'];
throw new AppwriteException(AppwriteException::GENERAL_ARGUMENT_INVALID, "Execution error: " . $error);
// Shared vars
foreach ($function->getAttribute('varsProject', []) as $var) {
$vars[$var->getAttribute('key')] = $var->getAttribute('value', '');
}
$execution = \json_decode($executionResponse, true);
// Function vars
foreach ($function->getAttribute('vars', []) as $var) {
$vars[$var->getAttribute('key')] = $var->getAttribute('value', '');
}
$contentType = 'text/plain';
foreach ($execution['responseHeaders'] as $header) {
if (\strtolower($header['name']) === 'content-type') {
$contentType = $header['value'];
// Appwrite vars
$vars = \array_merge($vars, [
'APPWRITE_FUNCTION_ID' => $functionId,
'APPWRITE_FUNCTION_NAME' => $function->getAttribute('name'),
'APPWRITE_FUNCTION_DEPLOYMENT' => $deployment->getId(),
'APPWRITE_FUNCTION_PROJECT_ID' => $project->getId(),
'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'] ?? '',
'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'] ?? '',
]);
/** Execute function */
$executor = new Executor(App::getEnv('_APP_EXECUTOR_HOST'));
try {
$version = $function->getAttribute('version', 'v2');
$command = $runtime['startCommand'];
$command = $version === 'v2' ? '' : 'cp /tmp/code.tar.gz /mnt/code/code.tar.gz && nohup helpers/start.sh "' . $command . '"';
$executionResponse = $executor->createExecution(
projectId: $project->getId(),
deploymentId: $deployment->getId(),
body: \strlen($body) > 0 ? $body : null,
variables: $vars,
timeout: $function->getAttribute('timeout', 0),
image: $runtime['image'],
source: $build->getAttribute('path', ''),
entrypoint: $deployment->getAttribute('entrypoint', ''),
version: $version,
path: $path,
method: $method,
headers: $headers,
runtimeEntrypoint: $command,
requestTimeout: 30
);
$headersFiltered = [];
foreach ($executionResponse['headers'] as $key => $value) {
if (\in_array(\strtolower($key), FUNCTION_ALLOWLIST_HEADERS_RESPONSE)) {
$headersFiltered[] = ['name' => $key, 'value' => $value];
}
}
$response->setHeader($header['name'], $header['value']);
/** Update execution status */
$status = $executionResponse['statusCode'] >= 400 ? 'failed' : 'completed';
$execution->setAttribute('status', $status);
$execution->setAttribute('responseStatusCode', $executionResponse['statusCode']);
$execution->setAttribute('responseHeaders', $headersFiltered);
$execution->setAttribute('logs', $executionResponse['logs']);
$execution->setAttribute('errors', $executionResponse['errors']);
$execution->setAttribute('duration', $executionResponse['duration']);
} catch (\Throwable $th) {
$durationEnd = \microtime(true);
$execution
->setAttribute('duration', $durationEnd - $durationStart)
->setAttribute('status', 'failed')
->setAttribute('responseStatusCode', 500)
->setAttribute('errors', $th->getMessage() . '\nError Code: ' . $th->getCode());
Console::error($th->getMessage());
} finally {
$queueForUsage
->addMetric(METRIC_EXECUTIONS, 1)
->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS), 1)
->addMetric(METRIC_EXECUTIONS_COMPUTE, (int)($execution->getAttribute('duration') * 1000)) // per project
->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE), (int)($execution->getAttribute('duration') * 1000)) // per function
;
}
if ($function->getAttribute('logging')) {
/** @var Document $execution */
$execution = Authorization::skip(fn () => $dbForProject->createDocument('executions', $execution));
}
$execution->setAttribute('logs', '');
$execution->setAttribute('errors', '');
$headers = [];
foreach (($executionResponse['headers'] ?? []) as $key => $value) {
$headers[] = ['name' => $key, 'value' => $value];
}
$execution->setAttribute('responseBody', $executionResponse['body'] ?? '');
$execution->setAttribute('responseHeaders', $headers);
$body = $execution['responseBody'] ?? '';
$encodingKey = \array_search('x-open-runtimes-encoding', \array_column($execution['responseHeaders'], 'name'));
@ -179,6 +341,15 @@ function router(App $utopia, Database $dbForConsole, SwooleRequest $swooleReques
}
}
$contentType = 'text/plain';
foreach ($execution['responseHeaders'] as $header) {
if (\strtolower($header['name']) === 'content-type') {
$contentType = $header['value'];
}
$response->setHeader($header['name'], $header['value']);
}
$response
->setContentType($contentType)
->setStatusCode($execution['responseStatusCode'] ?? 200)
@ -205,13 +376,17 @@ App::init()
->inject('console')
->inject('project')
->inject('dbForConsole')
->inject('getProjectDB')
->inject('user')
->inject('locale')
->inject('localeCodes')
->inject('clients')
->inject('servers')
->inject('queueForCertificates')
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Document $console, Document $project, Database $dbForConsole, Document $user, Locale $locale, array $localeCodes, array $clients, array $servers, Certificate $queueForCertificates) {
->inject('queueForEvents')
->inject('queueForUsage')
->inject('geodb')
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Document $console, Document $project, Database $dbForConsole, callable $getProjectDB, Document $user, Locale $locale, array $localeCodes, array $clients, array $servers, Certificate $queueForCertificates, Event $queueForEvents, Usage $queueForUsage, Reader $geodb) {
/*
* Appwrite Router
*/
@ -220,7 +395,7 @@ App::init()
$mainDomain = App::getEnv('_APP_DOMAIN', '');
// Only run Router when external domain
if ($host !== $mainDomain) {
if (router($utopia, $dbForConsole, $swooleRequest, $request, $response)) {
if (router($utopia, $dbForConsole, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForUsage, $geodb)) {
return;
}
}
@ -571,7 +746,11 @@ App::options()
->inject('request')
->inject('response')
->inject('dbForConsole')
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForConsole) {
->inject('getProjectDB')
->inject('queueForEvents')
->inject('queueForUsage')
->inject('geodb')
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForConsole, callable $getProjectDB, Event $queueForEvents, Usage $queueForUsage, Reader $geodb) {
/*
* Appwrite Router
*/
@ -579,7 +758,7 @@ App::options()
$mainDomain = App::getEnv('_APP_DOMAIN', '');
// Only run Router when external domain
if ($host !== $mainDomain) {
if (router($utopia, $dbForConsole, $swooleRequest, $request, $response)) {
if (router($utopia, $dbForConsole, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForUsage, $geodb)) {
return;
}
}
@ -757,10 +936,10 @@ App::error()
->setParam('development', App::isDevelopment())
->setParam('projectName', $project->getAttribute('name'))
->setParam('projectURL', $project->getAttribute('url'))
->setParam('message', $error->getMessage())
->setParam('type', $type)
->setParam('code', $code)
->setParam('trace', $trace);
->setParam('message', $output['message'] ?? '')
->setParam('type', $output['type'] ?? '')
->setParam('code', $output['code'] ?? '')
->setParam('trace', $output['trace'] ?? []);
$response->html($layout->render());
}

View file

@ -56,7 +56,7 @@
"utopia-php/image": "0.5.*",
"utopia-php/locale": "0.4.*",
"utopia-php/logger": "0.3.*",
"utopia-php/messaging": "0.2.*",
"utopia-php/messaging": "0.3.*",
"utopia-php/migration": "0.3.*",
"utopia-php/orchestration": "0.9.*",
"utopia-php/platform": "0.5.*",

48
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "fd03f97115d752d1a94b533ccf570109",
"content-hash": "a8c299cb631eb98bbcf0a58a815f74ac",
"packages": [
{
"name": "adhocore/jwt",
@ -1551,16 +1551,16 @@
},
{
"name": "utopia-php/messaging",
"version": "0.2.0",
"version": "0.3.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/messaging.git",
"reference": "2d0f474a106bb1da285f85e105c29b46085d3a43"
"reference": "d488223876f88f97bb76fd6681fed0df80558f62"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/messaging/zipball/2d0f474a106bb1da285f85e105c29b46085d3a43",
"reference": "2d0f474a106bb1da285f85e105c29b46085d3a43",
"url": "https://api.github.com/repos/utopia-php/messaging/zipball/d488223876f88f97bb76fd6681fed0df80558f62",
"reference": "d488223876f88f97bb76fd6681fed0df80558f62",
"shasum": ""
},
"require": {
@ -1593,9 +1593,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/messaging/issues",
"source": "https://github.com/utopia-php/messaging/tree/0.2.0"
"source": "https://github.com/utopia-php/messaging/tree/0.3.0"
},
"time": "2023-09-14T20:48:42+00:00"
"time": "2023-11-14T21:02:37+00:00"
},
{
"name": "utopia-php/migration",
@ -2417,16 +2417,16 @@
"packages-dev": [
{
"name": "appwrite/sdk-generator",
"version": "0.36.2",
"version": "0.36.4",
"source": {
"type": "git",
"url": "https://github.com/appwrite/sdk-generator.git",
"reference": "0aa67479d75f0e0cb7b60454031534d7f0abaece"
"reference": "8d932098009d62d37dda73cfe4ebc11f83e21405"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/0aa67479d75f0e0cb7b60454031534d7f0abaece",
"reference": "0aa67479d75f0e0cb7b60454031534d7f0abaece",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/8d932098009d62d37dda73cfe4ebc11f83e21405",
"reference": "8d932098009d62d37dda73cfe4ebc11f83e21405",
"shasum": ""
},
"require": {
@ -2462,9 +2462,9 @@
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
"support": {
"issues": "https://github.com/appwrite/sdk-generator/issues",
"source": "https://github.com/appwrite/sdk-generator/tree/0.36.2"
"source": "https://github.com/appwrite/sdk-generator/tree/0.36.4"
},
"time": "2024-01-19T01:04:35+00:00"
"time": "2024-02-20T16:36:15+00:00"
},
{
"name": "doctrine/deprecations",
@ -3047,16 +3047,16 @@
},
{
"name": "phpdocumentor/type-resolver",
"version": "1.8.0",
"version": "1.8.1",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "fad452781b3d774e3337b0c0b245dd8e5a4455fc"
"reference": "bc3dc91a5e9b14aa06d1d9e90647c5c5a2cc5353"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/fad452781b3d774e3337b0c0b245dd8e5a4455fc",
"reference": "fad452781b3d774e3337b0c0b245dd8e5a4455fc",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/bc3dc91a5e9b14aa06d1d9e90647c5c5a2cc5353",
"reference": "bc3dc91a5e9b14aa06d1d9e90647c5c5a2cc5353",
"shasum": ""
},
"require": {
@ -3099,9 +3099,9 @@
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.8.0"
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.8.1"
},
"time": "2024-01-11T11:49:22+00:00"
"time": "2024-01-18T19:15:27+00:00"
},
{
"name": "phpspec/prophecy",
@ -4657,16 +4657,16 @@
},
{
"name": "squizlabs/php_codesniffer",
"version": "3.8.1",
"version": "3.9.0",
"source": {
"type": "git",
"url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git",
"reference": "14f5fff1e64118595db5408e946f3a22c75807f7"
"reference": "d63cee4890a8afaf86a22e51ad4d97c91dd4579b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/14f5fff1e64118595db5408e946f3a22c75807f7",
"reference": "14f5fff1e64118595db5408e946f3a22c75807f7",
"url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/d63cee4890a8afaf86a22e51ad4d97c91dd4579b",
"reference": "d63cee4890a8afaf86a22e51ad4d97c91dd4579b",
"shasum": ""
},
"require": {
@ -4733,7 +4733,7 @@
"type": "open_collective"
}
],
"time": "2024-01-11T20:47:48+00:00"
"time": "2024-02-16T15:06:51+00:00"
},
{
"name": "swoole/ide-helper",

View file

@ -0,0 +1 @@
Check the Appwrite storage device is up and connection is successful.

View file

@ -52,8 +52,9 @@ When trying to connect to Appwrite from an emulator or a mobile device, localhos
val account = Account(client)
val response = account.create(
ID.unique(),
"email@example.com",
"password"
"email@example.com",
"password",
"Walter O'Brien"
)
```
@ -72,8 +73,9 @@ val client = Client(context)
val account = Account(client)
val user = account.create(
ID.unique(),
"email@example.com",
"password"
"email@example.com",
"password",
"Walter O'Brien"
)
```
@ -82,7 +84,7 @@ The Appwrite Android SDK raises an `AppwriteException` object with `message`, `c
```kotlin
try {
var user = account.create(ID.unique(), "email@example.com", "password")
var user = account.create(ID.unique(),"email@example.com","password","Walter O'Brien")
Log.d("Appwrite user", user.toMap())
} catch(e : AppwriteException) {
e.printStackTrace()
@ -94,4 +96,4 @@ You can use the following resources to learn more and get help
- 🚀 [Getting Started Tutorial](https://appwrite.io/docs/getting-started-for-android)
- 📜 [Appwrite Docs](https://appwrite.io/docs)
- 💬 [Discord Community](https://appwrite.io/discord)
- 🚂 [Appwrite Android Playground](https://github.com/appwrite/playground-for-android)
- 🚂 [Appwrite Android Playground](https://github.com/appwrite/playground-for-android)

View file

@ -75,9 +75,10 @@ let account = Account(client)
do {
let user = try await account.create(
userId: ID.unique(),
email: "email@example.com",
password: "password"
userId: ID.unique(),
email: "email@example.com",
password: "password",
name: "Walter O'Brien"
)
print(String(describing: user.toMap()))
} catch {
@ -100,9 +101,10 @@ func main() {
do {
let user = try await account.create(
userId: ID.unique(),
email: "email@example.com",
password: "password"
userId: ID.unique(),
email: "email@example.com",
password: "password",
name: "Walter O'Brien"
)
print(String(describing: account.toMap()))
} catch {

View file

@ -18,9 +18,11 @@ Create a new user:
Users users = Users(client);
User result = await users.create(
userId: '[USER_ID]',
email: 'email@example.com',
password: 'password',
userId: ID.unique(),
email: "email@example.com",
phone: "+123456789",
password: "password",
name: "Walter O'Brien"
);
```
@ -57,4 +59,4 @@ storage.createFile(
});
```
All examples and API features are available at the [official Appwrite docs](https://appwrite.io/docs)
All examples and API features are available at the [official Appwrite docs](https://appwrite.io/docs)

View file

@ -16,7 +16,7 @@ void main() async {
Users users = Users(client);
try {
final user = await users.create(userId: ID.unique(), email: email@example.com,password: password, name: name);
final user = await users.create(userId: ID.unique(), email: "email@example.com", phone: "+123456789", password: "password", name: "Walter O'Brien");
print(user.toMap());
} on AppwriteException catch(e) {
print(e.message);
@ -31,7 +31,7 @@ The Appwrite Dart SDK raises `AppwriteException` object with `message`, `code` a
Users users = Users(client);
try {
final user = await users.create(userId: ID.unique(), email: email@example.com,password: password, name: name);
final user = await users.create(userId: ID.unique(), email: "email@example.com", phone: "+123456789", password: "password", name: "Walter O'Brien");
print(user.toMap());
} on AppwriteException catch(e) {
//show message to user or do other operation based on error as required

View file

@ -21,7 +21,7 @@ Once your SDK object is set, create any of the Appwrite service objects and choo
```typescript
let users = new sdk.Users(client);
let user = await users.create(ID.unique(), 'email@example.com', 'password');
let user = await users.create(ID.unique(), "email@example.com", "+123456789", "password", "Walter O'Brien");
console.log(user);
```
@ -39,7 +39,7 @@ client
.setSelfSigned() // Use only on dev mode with a self-signed SSL cert
;
let user = await users.create(ID.unique(), 'email@example.com', 'password');
let user = await users.create(ID.unique(), "email@example.com", "+123456789", "password", "Walter O'Brien");
console.log(user);
```
@ -50,7 +50,7 @@ The Appwrite Deno SDK raises `AppwriteException` object with `message`, `code` a
let users = new sdk.Users(client);
try {
let user = await users.create(ID.unique(), 'email@example.com', 'password');
let user = await users.create(ID.unique(), "email@example.com", "+123456789", "password", "Walter O'Brien");
} catch(e) {
console.log(e.message);
}

View file

@ -18,8 +18,9 @@ var users = new Users(client);
var user = await users.Create(
userId: ID.Unique(),
email: "email@example.com",
phone: "+123456789",
password: "password",
name: "name");
name: "Walter O'Brien");
Console.WriteLine(user.ToMap());
```
@ -35,8 +36,9 @@ try
var user = await users.Create(
userId: ID.Unique(),
email: "email@example.com",
phone: "+123456789",
password: "password",
name: "name");
name: "Walter O'Brien");
}
catch (AppwriteException e)
{

View file

@ -17,7 +17,7 @@ Create a new user and session:
```dart
Account account = Account(client);
final user = await account.create(userId: '[USER_ID]', email: 'me@appwrite.io', password: 'password', name: 'My Name');
final user = await account.create(userId: ID.unique(), email: "email@example.com", password: "password", name: "Walter O'Brien");
final session = await account.createEmailSession(email: 'me@appwrite.io', password: 'password');
@ -60,4 +60,4 @@ storage.createFile(
});
```
All examples and API features are available at the [official Appwrite docs](https://appwrite.io/docs)
All examples and API features are available at the [official Appwrite docs](https://appwrite.io/docs)

View file

@ -17,7 +17,7 @@ Create a new user and session:
```dart
Account account = Account(client);
final user = await account.create(userId: '[USER_ID]', email: 'me@appwrite.io', password: 'password', name: 'My Name');
final user = await account.create(userId: ID.unique(), email: "email@example.com", password: "password", name: "Walter O'Brien");
final session = await account.createEmailSession(email: 'me@appwrite.io', password: 'password');
@ -60,4 +60,4 @@ storage.createFile(
});
```
All examples and API features are available at the [official Appwrite docs](https://appwrite.io/docs)
All examples and API features are available at the [official Appwrite docs](https://appwrite.io/docs)

View file

@ -105,10 +105,7 @@ When trying to connect to Appwrite from an emulator or a mobile device, localhos
Account account = Account(client);
final user = await account
.create(
userId: ID.unique(),
email: 'me@appwrite.io',
password: 'password',
name: 'My Name'
userId: ID.unique(), email: "email@example.com", password: "password", name: "Walter O'Brien"
);
```
@ -133,10 +130,7 @@ void main() {
final user = await account
.create(
userId: ID.unique(),
email: 'me@appwrite.io',
password: 'password',
name: 'My Name'
userId: ID.unique(), email: "email@example.com", password: "password", name: "Walter O'Brien"
);
}
```
@ -148,7 +142,7 @@ The Appwrite Flutter SDK raises `AppwriteException` object with `message`, `type
Account account = Account(client);
try {
final user = await account.create(userId: ID.unique(), email: email@example.com,password: password, name: name);
final user = await account.create(userId: ID.unique(), email: "email@example.com", password: "password", name: "Walter O'Brien");
print(user.toMap());
} on AppwriteException catch(e) {
//show message to user or do other operation based on error as required

View file

@ -26,7 +26,9 @@ val users = Users(client)
val user = users.create(
user = ID.unique(),
email = "email@example.com",
phone = "+123456789",
password = "password",
name = "Walter O'Brien"
)
```
@ -48,7 +50,9 @@ suspend fun main() {
val user = users.create(
user = ID.unique(),
email = "email@example.com",
phone = "+123456789",
password = "password",
name = "Walter O'Brien"
)
}
```
@ -68,7 +72,9 @@ suspend fun main() {
val user = users.create(
user = ID.unique(),
email = "email@example.com",
phone = "+123456789",
password = "password",
name = "Walter O'Brien"
)
} catch (e: AppwriteException) {
e.printStackTrace()

View file

@ -22,7 +22,7 @@ Once your SDK object is set, create any of the Appwrite service objects and choo
```js
let users = new sdk.Users(client);
let promise = users.create(sdk.ID.unique(), 'email@example.com', undefined, 'password', 'Jane Doe');
let promise = users.create(sdk.ID.unique(), "email@example.com", "+123456789", "password", "Walter O'Brien");
promise.then(function (response) {
console.log(response);
@ -45,7 +45,7 @@ client
;
let users = new sdk.Users(client);
let promise = users.create(sdk.ID.unique(), 'email@example.com', undefined, 'password', 'Jane Doe');
let promise = users.create(sdk.ID.unique(), "email@example.com", "+123456789", "password", "Walter O'Brien");
promise.then(function (response) {
console.log(response);
@ -61,7 +61,7 @@ The Appwrite Node SDK raises `AppwriteException` object with `message`, `code` a
let users = new sdk.Users(client);
try {
let res = await users.create(sdk.ID.unique(), 'email@example.com', 'password');
let res = await users.create(sdk.ID.unique(), "email@example.com", "+123456789", "password", "Walter O'Brien");
} catch(e) {
console.log(e.message);
}

View file

@ -20,7 +20,7 @@ Once your SDK object is set, create any of the Appwrite service objects and choo
```php
$users = new Users($client);
$user = $users->create(ID::unique(), 'email@example.com', 'password');
$user = $users->create(ID::unique(), "email@example.com", "+123456789", "password", "Walter O'Brien");
```
### Full Example
@ -40,7 +40,7 @@ $client
$users = new Users($client);
$user = $users->create(ID::unique(), 'email@example.com', 'password');
$user = $users->create(ID::unique(), "email@example.com", "+123456789", "password", "Walter O'Brien");
```
### Error Handling
@ -49,7 +49,7 @@ The Appwrite PHP SDK raises `AppwriteException` object with `message`, `code` an
```php
$users = new Users($client);
try {
$user = $users->create(ID::unique(), 'email@example.com', 'password');
$user = $users->create(ID::unique(), "email@example.com", "+123456789", "password", "Walter O'Brien");
} catch(AppwriteException $error) {
echo $error->message;
}

View file

@ -23,7 +23,7 @@ Once your SDK object is set, create any of the Appwrite service objects and choo
```python
users = Users(client)
result = users.create('[USER_ID]', 'email@example.com', 'password')
result = users.create(ID.unique(), email = "email@example.com", phone = "+123456789", password = "password", name = "Walter O'Brien")
```
### Full Example
@ -43,7 +43,7 @@ client = Client()
users = Users(client)
result = users.create(ID.unique(), 'email@example.com', 'password')
result = users.create(ID.unique(), email = "email@example.com", phone = "+123456789", password = "password", name = "Walter O'Brien")
```
### Error Handling
@ -52,7 +52,7 @@ The Appwrite Python SDK raises `AppwriteException` object with `message`, `code`
```python
users = Users(client)
try:
result = users.create(ID.unique(), 'email@example.com', 'password')
result = users.create(ID.unique(), email = "email@example.com", phone = "+123456789", password = "password", name = "Walter O'Brien")
except AppwriteException as e:
print(e.message)
```

View file

@ -22,7 +22,7 @@ Once your SDK object is set, create any of the Appwrite service objects and choo
```ruby
users = Appwrite::Users.new(client);
user = users.create(userId: Appwrite::ID::unique(), email: 'email@example.com', password: 'password');
user = users.create(userId: Appwrite::ID::unique(), email: "email@example.com", phone: "+123456789", password: "password", name: "Walter O'Brien");
```
### Full Example
@ -40,7 +40,7 @@ client
users = Appwrite::Users.new(client);
user = users.create(userId: Appwrite::ID::unique(), email: 'email@example.com', password: 'password');
user = users.create(userId: Appwrite::ID::unique(), email: "email@example.com", phone: "+123456789", password: "password", name: "Walter O'Brien");
```
### Error Handling
@ -50,7 +50,7 @@ The Appwrite Ruby SDK raises `Appwrite::Exception` object with `message`, `code`
users = Appwrite::Users.new(client);
begin
user = users.create(userId: Appwrite::ID::unique(), email: 'email@example.com', password: 'password');
user = users.create(userId: Appwrite::ID::unique(), email: "email@example.com", phone: "+123456789", password: "password", name: "Walter O'Brien");
rescue Appwrite::Exception => error
puts error.message
end

View file

@ -25,9 +25,11 @@ let users = Users(client)
do {
let user = try await users.create(
userId: ID.unique(),
email: "email@example.com",
password: "password"
userId: ID.unique(),
email: "email@example.com",
phone: "+123456789",
password: "password",
name: "Walter O'Brien"
)
print(String(describing: user.toMap()))
} catch {
@ -51,9 +53,11 @@ func main() {
do {
let user = try await users.create(
userId: ID.unique(),
email: "email@example.com",
password: "password"
userId: ID.unique(),
email: "email@example.com",
phone: "+123456789",
password: "password",
name: "Walter O'Brien"
)
print(String(describing: user.toMap()))
} catch {

View file

@ -25,7 +25,7 @@ Once your SDK object is set, access any of the Appwrite services and choose any
const account = new Account(client);
// Register User
account.create(ID.unique(), 'me@example.com', 'password', 'Jane Doe')
account.create(ID.unique(), "email@example.com", "password", "Walter O'Brien")
.then(function (response) {
console.log(response);
}, function (error) {
@ -47,7 +47,7 @@ client
const account = new Account(client);
// Register User
account.create(ID.unique(), 'me@example.com', 'password', 'Jane Doe')
account.create(ID.unique(), "email@example.com", "password", "Walter O'Brien")
.then(function (response) {
console.log(response);
}, function (error) {

View file

@ -338,6 +338,14 @@ class Mail extends Event
return $this;
}
/**
* Set attachment
* @param string $content
* @param string $filename
* @param string $encoding
* @param string $type
* @return self
*/
public function setAttachment(string $content, string $filename, string $encoding = 'base64', string $type = 'plain/text')
{
$this->attachment = [
@ -349,11 +357,45 @@ class Mail extends Event
return $this;
}
/**
* Get attachment
*
* @return array
*/
public function getAttachment(): array
{
return $this->attachment;
}
/**
* Reset attachment
*
* @return self
*/
public function resetAttachment(): self
{
$this->attachment = [];
return $this;
}
/**
* Reset
*
* @return self
*/
public function reset(): self
{
$this->project = null;
$this->recipient = '';
$this->name = '';
$this->subject = '';
$this->body = '';
$this->variables = [];
$this->bodyTemplate = '';
$this->attachment = [];
return $this;
}
/**
* Executes the event and sends it to the mails worker.
*

View file

@ -88,14 +88,29 @@ class Messaging extends Action
return;
}
$sms = match ($this->dsn->getHost()) {
'mock' => new Mock($this->user, $this->secret), // used for tests
'twilio' => new Twilio($this->user, $this->secret),
'text-magic' => new TextMagic($this->user, $this->secret),
'telesign' => new Telesign($this->user, $this->secret),
'msg91' => new Msg91($this->user, $this->secret),
'vonage' => new Vonage($this->user, $this->secret),
default => null
switch ($this->dsn->getHost()) {
case 'mock':
$sms = new Mock($this->user, $this->secret); // used for tests
break;
case 'twilio':
$sms = new Twilio($this->user, $this->secret);
break;
case 'text-magic':
$sms = new TextMagic($this->user, $this->secret);
break;
case 'telesign':
$sms = new Telesign($this->user, $this->secret);
break;
case 'msg91':
$sms = new Msg91($this->user, $this->secret);
$sms->setTemplate($this->dsn->getParam('template'));
break;
case 'vonage':
$sms = new Vonage($this->user, $this->secret);
break;
default:
$sms = null;
};
if (empty(App::getEnv('_APP_SMS_PROVIDER'))) {

View file

@ -295,7 +295,7 @@ class OpenAPI3 extends Format
switch ((!empty($validator)) ? \get_class($validator) : '') {
case 'Utopia\Validator\Text':
$node['schema']['type'] = $validator->getType();
$node['schema']['x-example'] = '<' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . '>';
$node['schema']['x-example'] = '[' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . ']';
break;
case 'Utopia\Validator\Boolean':
$node['schema']['type'] = $validator->getType();
@ -303,14 +303,14 @@ class OpenAPI3 extends Format
break;
case 'Utopia\Database\Validator\UID':
$node['schema']['type'] = $validator->getType();
$node['schema']['x-example'] = '<' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . '>';
$node['schema']['x-example'] = '[' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . ']';
break;
case 'Appwrite\Utopia\Database\Validator\CustomId':
if ($route->getLabel('sdk.methodType', '') === 'upload') {
$node['schema']['x-upload-id'] = true;
}
$node['schema']['type'] = $validator->getType();
$node['schema']['x-example'] = '<' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . '>';
$node['schema']['x-example'] = '[' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . ']';
break;
case 'Utopia\Database\Validator\DatetimeValidator':
$node['schema']['type'] = $validator->getType();

View file

@ -297,7 +297,7 @@ class Swagger2 extends Format
switch ((!empty($validator)) ? \get_class($validator) : '') {
case 'Utopia\Validator\Text':
$node['type'] = $validator->getType();
$node['x-example'] = '<' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . '>';
$node['x-example'] = '[' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . ']';
break;
case 'Utopia\Validator\Boolean':
$node['type'] = $validator->getType();
@ -308,11 +308,11 @@ class Swagger2 extends Format
$node['x-upload-id'] = true;
}
$node['type'] = $validator->getType();
$node['x-example'] = '<' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . '>';
$node['x-example'] = '[' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . ']';
break;
case 'Utopia\Database\Validator\UID':
$node['type'] = $validator->getType();
$node['x-example'] = '<' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . '>';
$node['x-example'] = '[' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . ']';
break;
case 'Utopia\Database\Validator\DatetimeValidator':
$node['type'] = $validator->getType();

View file

@ -4068,6 +4068,8 @@ trait DatabasesBase
$this->assertEquals(2, count($response['body']['documents']));
$this->assertEquals(null, $response['body']['documents'][0]['fullName']);
$this->assertArrayNotHasKey("libraries", $response['body']['documents'][0]);
$this->assertArrayNotHasKey('$databaseId', $response['body']['documents'][0]);
$this->assertArrayNotHasKey('$collectionId', $response['body']['documents'][0]);
}
/**
@ -4087,6 +4089,8 @@ trait DatabasesBase
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertArrayNotHasKey('libraries', $response['body']['documents'][0]);
$this->assertArrayNotHasKey('$databaseId', $response['body']['documents'][0]);
$this->assertArrayNotHasKey('$collectionId', $response['body']['documents'][0]);
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['personCollection'] . '/documents', array_merge([
'content-type' => 'application/json',
@ -4099,6 +4103,8 @@ trait DatabasesBase
$document = $response['body']['documents'][0];
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertArrayHasKey('libraries', $document);
$this->assertArrayNotHasKey('$databaseId', $document);
$this->assertArrayNotHasKey('$collectionId', $document);
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['personCollection'] . '/documents/' . $document['$id'], array_merge([
'content-type' => 'application/json',

View file

@ -407,6 +407,24 @@ class HealthCustomServerTest extends Scope
return [];
}
public function testStorageSuccess(): array
{
/**
* Test for SUCCESS
*/
$response = $this->client->call(Client::METHOD_GET, '/health/storage', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals('pass', $response['body']['status']);
$this->assertIsInt($response['body']['ping']);
$this->assertLessThan(100, $response['body']['ping']);
return [];
}
public function testStorageAntiVirusSuccess(): array
{
/**