mirror of
https://github.com/appwrite/appwrite
synced 2026-05-23 08:58:35 +00:00
Merge branch 'refactor-usage-sn' into remove-cloud-scripts
This commit is contained in:
commit
ac5d45d71c
32 changed files with 517 additions and 152 deletions
10
.github/workflows/publish.yml
vendored
10
.github/workflows/publish.yml
vendored
|
|
@ -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 }}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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'])
|
||||
|
|
|
|||
|
|
@ -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],
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
48
composer.lock
generated
|
|
@ -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",
|
||||
|
|
|
|||
1
docs/references/health/get-storage.md
Normal file
1
docs/references/health/get-storage.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
Check the Appwrite storage device is up and connection is successful.
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
```
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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'))) {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in a new issue