Merge branch '1.5.x' into feat-ssr-dx
This commit is contained in:
commit
f285173f4e
2
.env
2
.env
|
@ -79,7 +79,7 @@ _APP_MAINTENANCE_RETENTION_CACHE=2592000
|
|||
_APP_MAINTENANCE_RETENTION_EXECUTION=1209600
|
||||
_APP_MAINTENANCE_RETENTION_ABUSE=86400
|
||||
_APP_MAINTENANCE_RETENTION_AUDIT=1209600
|
||||
_APP_USAGE_AGGREGATION_INTERVAL=60000
|
||||
_APP_USAGE_AGGREGATION_INTERVAL=30
|
||||
_APP_MAINTENANCE_RETENTION_USAGE_HOURLY=8640000
|
||||
_APP_MAINTENANCE_RETENTION_SCHEDULES=86400
|
||||
_APP_USAGE_STATS=enabled
|
||||
|
|
|
@ -105,7 +105,8 @@ RUN chmod +x /usr/local/bin/doctor && \
|
|||
chmod +x /usr/local/bin/worker-migrations && \
|
||||
chmod +x /usr/local/bin/worker-webhooks && \
|
||||
chmod +x /usr/local/bin/worker-hamster && \
|
||||
chmod +x /usr/local/bin/worker-usage
|
||||
chmod +x /usr/local/bin/worker-usage && \
|
||||
chmod +x /usr/local/bin/worker-usage-dump
|
||||
|
||||
|
||||
# Cloud Executabless
|
||||
|
|
|
@ -34,6 +34,28 @@ $commonCollections = [
|
|||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'resourceType',
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 255,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('mimeType'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 255, // https://tools.ietf.org/html/rfc4288#section-4.2
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'accessedAt',
|
||||
'type' => Database::VAR_DATETIME,
|
||||
|
@ -2113,6 +2135,13 @@ $commonCollections = [
|
|||
'lengths' => [],
|
||||
'orders' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('_unique_target_topic'),
|
||||
'type' => Database::INDEX_UNIQUE,
|
||||
'attributes' => ['targetInternalId', 'topicInternalId'],
|
||||
'lengths' => [],
|
||||
'orders' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('_fulltext_search'),
|
||||
'type' => Database::INDEX_FULLTEXT,
|
||||
|
@ -4362,17 +4391,6 @@ $consoleCollections = array_merge([
|
|||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('resourceCollection'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => true,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('resourceInternalId'),
|
||||
'type' => Database::VAR_STRING,
|
||||
|
|
|
@ -272,6 +272,11 @@ return [
|
|||
'description' => 'User phone is already verified',
|
||||
'code' => 409
|
||||
],
|
||||
Exception::USER_DELETION_PROHIBITED => [
|
||||
'name' => Exception::USER_DELETION_PROHIBITED,
|
||||
'description' => 'User deletion is not allowed for users with active memberships. Please delete all confirmed memberships before deleting the account.',
|
||||
'code' => 400
|
||||
],
|
||||
Exception::USER_TARGET_NOT_FOUND => [
|
||||
'name' => Exception::USER_TARGET_NOT_FOUND,
|
||||
'description' => 'The target could not be found.',
|
||||
|
@ -425,6 +430,11 @@ return [
|
|||
'description' => 'The value for x-appwrite-id header is invalid. Please check the value of the x-appwrite-id header is a valid id and not unique().',
|
||||
'code' => 400,
|
||||
],
|
||||
Exception::STORAGE_FILE_NOT_PUBLIC => [
|
||||
'name' => Exception::STORAGE_FILE_NOT_PUBLIC,
|
||||
'description' => 'The requested file is not publicly readable.',
|
||||
'code' => 403,
|
||||
],
|
||||
|
||||
/** VCS */
|
||||
Exception::INSTALLATION_NOT_FOUND => [
|
||||
|
|
|
@ -303,7 +303,7 @@ return [
|
|||
[
|
||||
'key' => 'ruby',
|
||||
'name' => 'Ruby',
|
||||
'version' => '10.1.0',
|
||||
'version' => '10.1.1',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-ruby',
|
||||
'package' => 'https://rubygems.org/gems/appwrite',
|
||||
'enabled' => true,
|
||||
|
|
|
@ -266,7 +266,7 @@ App::post('/v1/account/sessions/email')
|
|||
'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak
|
||||
'userAgent' => $request->getUserAgent('UNKNOWN'),
|
||||
'ip' => $request->getIP(),
|
||||
'factors' => ['email'],
|
||||
'factors' => ['password'],
|
||||
'countryCode' => ($record) ? \strtolower($record['country']['iso_code']) : '--',
|
||||
'expire' => DateTime::addSeconds(new \DateTime(), $duration)
|
||||
],
|
||||
|
@ -1840,10 +1840,10 @@ App::post('/v1/account/tokens/phone')
|
|||
]);
|
||||
|
||||
$queueForMessaging
|
||||
->setType(MESSAGE_SEND_TYPE_INTERNAL)
|
||||
->setMessage($messageDoc)
|
||||
->setRecipients([$phone])
|
||||
->setProviderType(MESSAGE_TYPE_SMS)
|
||||
->trigger();
|
||||
->setProviderType(MESSAGE_TYPE_SMS);
|
||||
|
||||
$queueForEvents->setPayload(
|
||||
$response->output(
|
||||
|
@ -2191,7 +2191,7 @@ App::get('/v1/account/logs')
|
|||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => $audit->countLogsByUser($user->getId()),
|
||||
'total' => $audit->countLogsByUser($user->getInternalId()),
|
||||
'logs' => $output,
|
||||
]), Response::MODEL_LOG_LIST);
|
||||
});
|
||||
|
@ -3381,10 +3381,10 @@ App::post('/v1/account/verification/phone')
|
|||
]);
|
||||
|
||||
$queueForMessaging
|
||||
->setType(MESSAGE_SEND_TYPE_INTERNAL)
|
||||
->setMessage($messageDoc)
|
||||
->setRecipients([$user->getAttribute('phone')])
|
||||
->setProviderType(MESSAGE_TYPE_SMS)
|
||||
->trigger();
|
||||
->setProviderType(MESSAGE_TYPE_SMS);
|
||||
|
||||
$queueForEvents
|
||||
->setParam('userId', $user->getId())
|
||||
|
@ -3744,14 +3744,14 @@ App::post('/v1/account/mfa/challenge')
|
|||
}
|
||||
|
||||
$queueForMessaging
|
||||
->setType(MESSAGE_SEND_TYPE_INTERNAL)
|
||||
->setMessage(new Document([
|
||||
'$id' => $challenge->getId(),
|
||||
'data' => [
|
||||
'content' => $code,
|
||||
],
|
||||
]))
|
||||
->setRecipients([$user->getAttribute('phone')])
|
||||
->trigger();
|
||||
->setRecipients([$user->getAttribute('phone')]);
|
||||
break;
|
||||
case 'email':
|
||||
if (empty(App::getEnv('_APP_SMTP_HOST'))) {
|
||||
|
@ -3858,15 +3858,27 @@ App::delete('/v1/account')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
|
||||
->label('sdk.response.model', Response::MODEL_NONE)
|
||||
->inject('user')
|
||||
->inject('project')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForDeletes')
|
||||
->action(function (Document $user, Response $response, Database $dbForProject, Event $queueForEvents, Delete $queueForDeletes) {
|
||||
->action(function (Document $user, Document $project, Response $response, Database $dbForProject, Event $queueForEvents, Delete $queueForDeletes) {
|
||||
if ($user->isEmpty()) {
|
||||
throw new Exception(Exception::USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
if ($project->getId() === 'console') {
|
||||
// get all memberships
|
||||
$memberships = $user->getAttribute('memberships', []);
|
||||
foreach ($memberships as $membership) {
|
||||
// prevent deletion if at least one active membership
|
||||
if ($membership->getAttribute('confirm', false)) {
|
||||
throw new Exception(Exception::USER_DELETION_PROHIBITED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$dbForProject->deleteDocument('users', $user->getId());
|
||||
|
||||
$queueForDeletes
|
||||
|
|
|
@ -76,7 +76,7 @@ $getUserGitHub = function (string $userId, Document $project, Database $dbForPro
|
|||
}
|
||||
|
||||
if (empty($gitHubSession)) {
|
||||
throw new Exception(Exception::GENERAL_UNKNOWN, 'GitHub session not found.');
|
||||
throw new Exception(Exception::USER_SESSION_NOT_FOUND, 'GitHub session not found.');
|
||||
}
|
||||
|
||||
$provider = $gitHubSession->getAttribute('provider', '');
|
||||
|
|
|
@ -121,9 +121,7 @@ $redeployVcs = function (Request $request, Document $function, Document $project
|
|||
->setType(BUILD_TYPE_DEPLOYMENT)
|
||||
->setResource($function)
|
||||
->setDeployment($deployment)
|
||||
->setTemplate($template)
|
||||
->setProject($project)
|
||||
->trigger();
|
||||
->setTemplate($template);
|
||||
};
|
||||
|
||||
App::post('/v1/functions')
|
||||
|
@ -235,7 +233,6 @@ App::post('/v1/functions')
|
|||
fn () => $dbForConsole->createDocument('schedules', new Document([
|
||||
'region' => App::getEnv('_APP_REGION', 'default'), // Todo replace with projects region
|
||||
'resourceType' => 'function',
|
||||
'resourceCollection' => 'functions',
|
||||
'resourceId' => $function->getId(),
|
||||
'resourceInternalId' => $function->getInternalId(),
|
||||
'resourceUpdatedAt' => DateTime::now(),
|
||||
|
@ -847,8 +844,8 @@ App::get('/v1/functions/:functionId/deployments/:deploymentId/download')
|
|||
->inject('response')
|
||||
->inject('request')
|
||||
->inject('dbForProject')
|
||||
->inject('deviceFunctions')
|
||||
->action(function (string $functionId, string $deploymentId, Response $response, Request $request, Database $dbForProject, Device $deviceFunctions) {
|
||||
->inject('deviceForFunctions')
|
||||
->action(function (string $functionId, string $deploymentId, Response $response, Request $request, Database $dbForProject, Device $deviceForFunctions) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
if ($function->isEmpty()) {
|
||||
|
@ -865,7 +862,7 @@ App::get('/v1/functions/:functionId/deployments/:deploymentId/download')
|
|||
}
|
||||
|
||||
$path = $deployment->getAttribute('path', '');
|
||||
if (!$deviceFunctions->exists($path)) {
|
||||
if (!$deviceForFunctions->exists($path)) {
|
||||
throw new Exception(Exception::DEPLOYMENT_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
@ -875,7 +872,7 @@ App::get('/v1/functions/:functionId/deployments/:deploymentId/download')
|
|||
->addHeader('X-Peak', \memory_get_peak_usage())
|
||||
->addHeader('Content-Disposition', 'attachment; filename="' . $deploymentId . '.tar.gz"');
|
||||
|
||||
$size = $deviceFunctions->getFileSize($path);
|
||||
$size = $deviceForFunctions->getFileSize($path);
|
||||
$rangeHeader = $request->getHeader('range');
|
||||
|
||||
if (!empty($rangeHeader)) {
|
||||
|
@ -897,13 +894,13 @@ App::get('/v1/functions/:functionId/deployments/:deploymentId/download')
|
|||
->addHeader('Content-Length', $end - $start + 1)
|
||||
->setStatusCode(Response::STATUS_CODE_PARTIALCONTENT);
|
||||
|
||||
$response->send($deviceFunctions->read($path, $start, ($end - $start + 1)));
|
||||
$response->send($deviceForFunctions->read($path, $start, ($end - $start + 1)));
|
||||
}
|
||||
|
||||
if ($size > APP_STORAGE_READ_BUFFER) {
|
||||
for ($i = 0; $i < ceil($size / MAX_OUTPUT_CHUNK_SIZE); $i++) {
|
||||
$response->chunk(
|
||||
$deviceFunctions->read(
|
||||
$deviceForFunctions->read(
|
||||
$path,
|
||||
($i * MAX_OUTPUT_CHUNK_SIZE),
|
||||
min(MAX_OUTPUT_CHUNK_SIZE, $size - ($i * MAX_OUTPUT_CHUNK_SIZE))
|
||||
|
@ -912,7 +909,7 @@ App::get('/v1/functions/:functionId/deployments/:deploymentId/download')
|
|||
);
|
||||
}
|
||||
} else {
|
||||
$response->send($deviceFunctions->read($path));
|
||||
$response->send($deviceForFunctions->read($path));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1051,10 +1048,10 @@ App::post('/v1/functions/:functionId/deployments')
|
|||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
->inject('project')
|
||||
->inject('deviceFunctions')
|
||||
->inject('deviceLocal')
|
||||
->inject('deviceForFunctions')
|
||||
->inject('deviceForLocal')
|
||||
->inject('queueForBuilds')
|
||||
->action(function (string $functionId, ?string $entrypoint, ?string $commands, mixed $code, bool $activate, Request $request, Response $response, Database $dbForProject, Event $queueForEvents, Document $project, Device $deviceFunctions, Device $deviceLocal, Build $queueForBuilds) {
|
||||
->action(function (string $functionId, ?string $entrypoint, ?string $commands, mixed $code, bool $activate, Request $request, Response $response, Database $dbForProject, Event $queueForEvents, Document $project, Device $deviceForFunctions, Device $deviceForLocal, Build $queueForBuilds) {
|
||||
|
||||
$activate = filter_var($activate, FILTER_VALIDATE_BOOLEAN);
|
||||
|
||||
|
@ -1135,11 +1132,11 @@ App::post('/v1/functions/:functionId/deployments')
|
|||
}
|
||||
|
||||
// Save to storage
|
||||
$fileSize ??= $deviceLocal->getFileSize($fileTmpName);
|
||||
$path = $deviceFunctions->getPath($deploymentId . '.' . \pathinfo($fileName, PATHINFO_EXTENSION));
|
||||
$fileSize ??= $deviceForLocal->getFileSize($fileTmpName);
|
||||
$path = $deviceForFunctions->getPath($deploymentId . '.' . \pathinfo($fileName, PATHINFO_EXTENSION));
|
||||
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
|
||||
|
||||
$metadata = ['content_type' => $deviceLocal->getFileMimeType($fileTmpName)];
|
||||
$metadata = ['content_type' => $deviceForLocal->getFileMimeType($fileTmpName)];
|
||||
if (!$deployment->isEmpty()) {
|
||||
$chunks = $deployment->getAttribute('chunksTotal', 1);
|
||||
$metadata = $deployment->getAttribute('metadata', []);
|
||||
|
@ -1148,7 +1145,7 @@ App::post('/v1/functions/:functionId/deployments')
|
|||
}
|
||||
}
|
||||
|
||||
$chunksUploaded = $deviceFunctions->upload($fileTmpName, $path, $chunk, $chunks, $metadata);
|
||||
$chunksUploaded = $deviceForFunctions->upload($fileTmpName, $path, $chunk, $chunks, $metadata);
|
||||
|
||||
if (empty($chunksUploaded)) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed moving file');
|
||||
|
@ -1171,7 +1168,7 @@ App::post('/v1/functions/:functionId/deployments')
|
|||
}
|
||||
}
|
||||
|
||||
$fileSize = $deviceFunctions->getFileSize($path);
|
||||
$fileSize = $deviceForFunctions->getFileSize($path);
|
||||
|
||||
if ($deployment->isEmpty()) {
|
||||
$deployment = $dbForProject->createDocument('deployments', new Document([
|
||||
|
@ -1202,9 +1199,7 @@ App::post('/v1/functions/:functionId/deployments')
|
|||
$queueForBuilds
|
||||
->setType(BUILD_TYPE_DEPLOYMENT)
|
||||
->setResource($function)
|
||||
->setDeployment($deployment)
|
||||
->setProject($project)
|
||||
->trigger();
|
||||
->setDeployment($deployment);
|
||||
} else {
|
||||
if ($deployment->isEmpty()) {
|
||||
$deployment = $dbForProject->createDocument('deployments', new Document([
|
||||
|
@ -1382,8 +1377,8 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId')
|
|||
->inject('dbForProject')
|
||||
->inject('queueForDeletes')
|
||||
->inject('queueForEvents')
|
||||
->inject('deviceFunctions')
|
||||
->action(function (string $functionId, string $deploymentId, Response $response, Database $dbForProject, Delete $queueForDeletes, Event $queueForEvents, Device $deviceFunctions) {
|
||||
->inject('deviceForFunctions')
|
||||
->action(function (string $functionId, string $deploymentId, Response $response, Database $dbForProject, Delete $queueForDeletes, Event $queueForEvents, Device $deviceForFunctions) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
if ($function->isEmpty()) {
|
||||
|
@ -1404,7 +1399,7 @@ App::delete('/v1/functions/:functionId/deployments/:deploymentId')
|
|||
}
|
||||
|
||||
if (!empty($deployment->getAttribute('path', ''))) {
|
||||
if (!($deviceFunctions->delete($deployment->getAttribute('path', '')))) {
|
||||
if (!($deviceForFunctions->delete($deployment->getAttribute('path', '')))) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove deployment from storage');
|
||||
}
|
||||
}
|
||||
|
@ -1484,9 +1479,7 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId')
|
|||
$queueForBuilds
|
||||
->setType(BUILD_TYPE_DEPLOYMENT)
|
||||
->setResource($function)
|
||||
->setDeployment($deployment)
|
||||
->setProject($project)
|
||||
->trigger();
|
||||
->setDeployment($deployment);
|
||||
|
||||
$queueForEvents
|
||||
->setParam('functionId', $function->getId())
|
||||
|
|
|
@ -792,8 +792,8 @@ App::get('/v1/health/stats') // Currently only used internally
|
|||
->label('docs', false)
|
||||
->inject('response')
|
||||
->inject('register')
|
||||
->inject('deviceFiles')
|
||||
->action(function (Response $response, Registry $register, Device $deviceFiles) {
|
||||
->inject('deviceForFiles')
|
||||
->action(function (Response $response, Registry $register, Device $deviceForFiles) {
|
||||
|
||||
$cache = $register->get('cache');
|
||||
|
||||
|
@ -802,9 +802,9 @@ App::get('/v1/health/stats') // Currently only used internally
|
|||
$response
|
||||
->json([
|
||||
'storage' => [
|
||||
'used' => Storage::human($deviceFiles->getDirectorySize($deviceFiles->getRoot() . '/')),
|
||||
'partitionTotal' => Storage::human($deviceFiles->getPartitionTotalSpace()),
|
||||
'partitionFree' => Storage::human($deviceFiles->getPartitionFreeSpace()),
|
||||
'used' => Storage::human($deviceForFiles->getDirectorySize($deviceForFiles->getRoot() . '/')),
|
||||
'partitionTotal' => Storage::human($deviceForFiles->getPartitionTotalSpace()),
|
||||
'partitionFree' => Storage::human($deviceForFiles->getPartitionFreeSpace()),
|
||||
],
|
||||
'cache' => [
|
||||
'uptime' => $cacheStats['uptime_in_seconds'] ?? 0,
|
||||
|
|
|
@ -10,6 +10,7 @@ use Appwrite\Messaging\Status as MessageStatus;
|
|||
use Appwrite\Network\Validator\Email;
|
||||
use Appwrite\Permission;
|
||||
use Appwrite\Role;
|
||||
use Appwrite\Utopia\Database\Validator\CompoundUID;
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Messages;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Providers;
|
||||
|
@ -27,11 +28,13 @@ use Utopia\Database\Helpers\ID;
|
|||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Datetime as DatetimeValidator;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
use Utopia\Database\Validator\Query\Offset;
|
||||
use Utopia\Database\Validator\Roles;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Domains\Domain;
|
||||
use Utopia\Locale\Locale;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Boolean;
|
||||
|
@ -216,14 +219,14 @@ App::post('/v1/messaging/providers/smtp')
|
|||
->label('scope', 'providers.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'messaging')
|
||||
->label('sdk.method', 'createSMTPProvider')
|
||||
->label('sdk.method', 'createSmtpProvider')
|
||||
->label('sdk.description', '/docs/references/messaging/create-smtp-provider.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_PROVIDER)
|
||||
->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('name', '', new Text(128), 'Provider name.')
|
||||
->param('host', '', new Text(0), 'SMTP hosts. Either a single hostname or multiple semicolon-delimited hostnames. You can also specify a different port for each host by using this format: [hostname:port] (e.g. "smtp1.example.com:25;smtp2.example.com"). You can also specify encryption type, for example: (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465"). Hosts will be tried in order.')
|
||||
->param('host', '', new Text(0), 'SMTP hosts. Either a single hostname or multiple semicolon-delimited hostnames. You can also specify a different port for each host such as `smtp1.example.com:25;smtp2.example.com`. You can also specify encryption type, for example: `tls://smtp1.example.com:587;ssl://smtp2.example.com:465"`. Hosts will be tried in order.')
|
||||
->param('port', 587, new Range(1, 65535), 'The default SMTP server port.', true)
|
||||
->param('username', '', new Text(0), 'Authentication username.', true)
|
||||
->param('password', '', new Text(0), 'Authentication password.', true)
|
||||
|
@ -689,7 +692,7 @@ App::post('/v1/messaging/providers/fcm')
|
|||
->label('scope', 'providers.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'messaging')
|
||||
->label('sdk.method', 'createFCMProvider')
|
||||
->label('sdk.method', 'createFcmProvider')
|
||||
->label('sdk.description', '/docs/references/messaging/create-fcm-provider.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
|
@ -752,7 +755,7 @@ App::post('/v1/messaging/providers/apns')
|
|||
->label('scope', 'providers.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'messaging')
|
||||
->label('sdk.method', 'createAPNSProvider')
|
||||
->label('sdk.method', 'createApnsProvider')
|
||||
->label('sdk.description', '/docs/references/messaging/create-apns-provider.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
|
@ -881,7 +884,7 @@ App::get('/v1/messaging/providers/:providerId/logs')
|
|||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'messaging')
|
||||
->label('sdk.method', 'listProviderLogs')
|
||||
->label('sdk.description', '/docs/references/messaging/providers/get-logs.md')
|
||||
->label('sdk.description', '/docs/references/messaging/list-provider-logs.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_LOG_LIST)
|
||||
|
@ -1192,14 +1195,14 @@ App::patch('/v1/messaging/providers/smtp/:providerId')
|
|||
->label('scope', 'providers.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'messaging')
|
||||
->label('sdk.method', 'updateSMTPProvider')
|
||||
->label('sdk.method', 'updateSmtpProvider')
|
||||
->label('sdk.description', '/docs/references/messaging/update-smtp-provider.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_PROVIDER)
|
||||
->param('providerId', '', new UID(), 'Provider ID.')
|
||||
->param('name', '', new Text(128), 'Provider name.', true)
|
||||
->param('host', '', new Text(0), 'SMTP hosts. Either a single hostname or multiple semicolon-delimited hostnames. You can also specify a different port for each host by using this format: [hostname:port] (e.g. "smtp1.example.com:25;smtp2.example.com"). You can also specify encryption type, for example: (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465"). Hosts will be tried in order.', true)
|
||||
->param('host', '', new Text(0), 'SMTP hosts. Either a single hostname or multiple semicolon-delimited hostnames. You can also specify a different port for each host such as `smtp1.example.com:25;smtp2.example.com`. You can also specify encryption type, for example: `tls://smtp1.example.com:587;ssl://smtp2.example.com:465"`. Hosts will be tried in order.', true)
|
||||
->param('port', null, new Range(1, 65535), 'SMTP port.', true)
|
||||
->param('username', '', new Text(0), 'Authentication username.', true)
|
||||
->param('password', '', new Text(0), 'Authentication password.', true)
|
||||
|
@ -1724,7 +1727,7 @@ App::patch('/v1/messaging/providers/fcm/:providerId')
|
|||
->label('scope', 'providers.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'messaging')
|
||||
->label('sdk.method', 'updateFCMProvider')
|
||||
->label('sdk.method', 'updateFcmProvider')
|
||||
->label('sdk.description', '/docs/references/messaging/update-fcm-provider.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
|
@ -1793,7 +1796,7 @@ App::patch('/v1/messaging/providers/apns/:providerId')
|
|||
->label('scope', 'providers.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'messaging')
|
||||
->label('sdk.method', 'updateAPNSProvider')
|
||||
->label('sdk.method', 'updateApnsProvider')
|
||||
->label('sdk.description', '/docs/references/messaging/update-apns-provider.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
|
@ -1906,7 +1909,7 @@ App::delete('/v1/messaging/providers/:providerId')
|
|||
});
|
||||
|
||||
App::post('/v1/messaging/topics')
|
||||
->desc('Create a topic.')
|
||||
->desc('Create a topic')
|
||||
->groups(['api', 'messaging'])
|
||||
->label('audits.event', 'topic.create')
|
||||
->label('audits.resource', 'topic/{response.$id}')
|
||||
|
@ -1949,7 +1952,7 @@ App::post('/v1/messaging/topics')
|
|||
});
|
||||
|
||||
App::get('/v1/messaging/topics')
|
||||
->desc('List topics.')
|
||||
->desc('List topics')
|
||||
->groups(['api', 'messaging'])
|
||||
->label('scope', 'topics.read')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
|
||||
|
@ -2006,7 +2009,7 @@ App::get('/v1/messaging/topics/:topicId/logs')
|
|||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'messaging')
|
||||
->label('sdk.method', 'listTopicLogs')
|
||||
->label('sdk.description', '/docs/references/messaging/topics/get-logs.md')
|
||||
->label('sdk.description', '/docs/references/messaging/list-topic-logs.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_LOG_LIST)
|
||||
|
@ -2089,7 +2092,7 @@ App::get('/v1/messaging/topics/:topicId/logs')
|
|||
});
|
||||
|
||||
App::get('/v1/messaging/topics/:topicId')
|
||||
->desc('Get a topic.')
|
||||
->desc('Get a topic')
|
||||
->groups(['api', 'messaging'])
|
||||
->label('scope', 'topics.read')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
|
||||
|
@ -2116,7 +2119,7 @@ App::get('/v1/messaging/topics/:topicId')
|
|||
});
|
||||
|
||||
App::patch('/v1/messaging/topics/:topicId')
|
||||
->desc('Update a topic.')
|
||||
->desc('Update a topic')
|
||||
->groups(['api', 'messaging'])
|
||||
->label('audits.event', 'topic.update')
|
||||
->label('audits.resource', 'topic/{response.$id}')
|
||||
|
@ -2155,7 +2158,7 @@ App::patch('/v1/messaging/topics/:topicId')
|
|||
});
|
||||
|
||||
App::delete('/v1/messaging/topics/:topicId')
|
||||
->desc('Delete a topic.')
|
||||
->desc('Delete a topic')
|
||||
->groups(['api', 'messaging'])
|
||||
->label('audits.event', 'topic.delete')
|
||||
->label('audits.resource', 'topic/{request.$topicId}')
|
||||
|
@ -2195,7 +2198,7 @@ App::delete('/v1/messaging/topics/:topicId')
|
|||
});
|
||||
|
||||
App::post('/v1/messaging/topics/:topicId/subscribers')
|
||||
->desc('Create a subscriber.')
|
||||
->desc('Create a subscriber')
|
||||
->groups(['api', 'messaging'])
|
||||
->label('audits.event', 'subscriber.create')
|
||||
->label('audits.resource', 'subscriber/{response.$id}')
|
||||
|
@ -2291,7 +2294,7 @@ App::post('/v1/messaging/topics/:topicId/subscribers')
|
|||
});
|
||||
|
||||
App::get('/v1/messaging/topics/:topicId/subscribers')
|
||||
->desc('List subscribers.')
|
||||
->desc('List subscribers')
|
||||
->groups(['api', 'messaging'])
|
||||
->label('scope', 'subscribers.read')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
|
||||
|
@ -2371,7 +2374,7 @@ App::get('/v1/messaging/subscribers/:subscriberId/logs')
|
|||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'messaging')
|
||||
->label('sdk.method', 'listSubscriberLogs')
|
||||
->label('sdk.description', '/docs/references/messaging/subscribers/get-logs.md')
|
||||
->label('sdk.description', '/docs/references/messaging/list-subscriber-logs.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_LOG_LIST)
|
||||
|
@ -2454,7 +2457,7 @@ App::get('/v1/messaging/subscribers/:subscriberId/logs')
|
|||
});
|
||||
|
||||
App::get('/v1/messaging/topics/:topicId/subscribers/:subscriberId')
|
||||
->desc('Get a subscriber.')
|
||||
->desc('Get a subscriber')
|
||||
->groups(['api', 'messaging'])
|
||||
->label('scope', 'subscribers.read')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
|
||||
|
@ -2493,7 +2496,7 @@ App::get('/v1/messaging/topics/:topicId/subscribers/:subscriberId')
|
|||
});
|
||||
|
||||
App::delete('/v1/messaging/topics/:topicId/subscribers/:subscriberId')
|
||||
->desc('Delete a subscriber.')
|
||||
->desc('Delete a subscriber')
|
||||
->groups(['api', 'messaging'])
|
||||
->label('audits.event', 'subscriber.delete')
|
||||
->label('audits.resource', 'subscriber/{request.$subscriberId}')
|
||||
|
@ -2552,7 +2555,7 @@ App::delete('/v1/messaging/topics/:topicId/subscribers/:subscriberId')
|
|||
});
|
||||
|
||||
App::post('/v1/messaging/messages/email')
|
||||
->desc('Create an email.')
|
||||
->desc('Create an email')
|
||||
->groups(['api', 'messaging'])
|
||||
->label('audits.event', 'message.create')
|
||||
->label('audits.resource', 'message/{response.$id}')
|
||||
|
@ -2573,6 +2576,7 @@ App::post('/v1/messaging/messages/email')
|
|||
->param('targets', [], new ArrayList(new UID()), 'List of Targets IDs.', true)
|
||||
->param('cc', [], new ArrayList(new UID()), 'Array of target IDs to be added as CC.', true)
|
||||
->param('bcc', [], new ArrayList(new UID()), 'Array of target IDs to be added as BCC.', true)
|
||||
->param('attachments', [], new ArrayList(new CompoundUID()), 'Array of compound bucket IDs to file IDs to be attached to the email.', true)
|
||||
->param('status', MessageStatus::DRAFT, new WhiteList([MessageStatus::DRAFT, MessageStatus::SCHEDULED, MessageStatus::PROCESSING]), 'Message Status. Value must be one of: ' . implode(', ', [MessageStatus::DRAFT, MessageStatus::SCHEDULED, MessageStatus::PROCESSING]) . '.', true)
|
||||
->param('html', false, new Boolean(), 'Is content of type HTML', true)
|
||||
->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true)
|
||||
|
@ -2582,7 +2586,7 @@ App::post('/v1/messaging/messages/email')
|
|||
->inject('project')
|
||||
->inject('queueForMessaging')
|
||||
->inject('response')
|
||||
->action(function (string $messageId, string $subject, string $content, array $topics, array $users, array $targets, array $cc, array $bcc, string $status, bool $html, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
|
||||
->action(function (string $messageId, string $subject, string $content, array $topics, array $users, array $targets, array $cc, array $bcc, array $attachments, string $status, bool $html, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
|
||||
$messageId = $messageId == 'unique()'
|
||||
? ID::unique()
|
||||
: $messageId;
|
||||
|
@ -2615,6 +2619,29 @@ App::post('/v1/messaging/messages/email')
|
|||
}
|
||||
}
|
||||
|
||||
if (!empty($attachments)) {
|
||||
foreach ($attachments as &$attachment) {
|
||||
[$bucketId, $fileId] = CompoundUID::parse($attachment);
|
||||
|
||||
$bucket = $dbForProject->getDocument('buckets', $bucketId);
|
||||
|
||||
if ($bucket->isEmpty()) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
|
||||
if ($file->isEmpty()) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
$attachment = [
|
||||
'bucketId' => $bucketId,
|
||||
'fileId' => $fileId,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$message = $dbForProject->createDocument('messages', new Document([
|
||||
'$id' => $messageId,
|
||||
'providerType' => MESSAGE_TYPE_EMAIL,
|
||||
|
@ -2628,6 +2655,7 @@ App::post('/v1/messaging/messages/email')
|
|||
'html' => $html,
|
||||
'cc' => $cc,
|
||||
'bcc' => $bcc,
|
||||
'attachments' => $attachments,
|
||||
],
|
||||
'status' => $status,
|
||||
]));
|
||||
|
@ -2635,14 +2663,13 @@ App::post('/v1/messaging/messages/email')
|
|||
switch ($status) {
|
||||
case MessageStatus::PROCESSING:
|
||||
$queueForMessaging
|
||||
->setMessageId($message->getId())
|
||||
->trigger();
|
||||
->setType(MESSAGE_SEND_TYPE_EXTERNAL)
|
||||
->setMessageId($message->getId());
|
||||
break;
|
||||
case MessageStatus::SCHEDULED:
|
||||
$schedule = $dbForConsole->createDocument('schedules', new Document([
|
||||
'region' => App::getEnv('_APP_REGION', 'default'),
|
||||
'resourceType' => 'message',
|
||||
'resourceCollection' => 'messages',
|
||||
'resourceId' => $message->getId(),
|
||||
'resourceInternalId' => $message->getInternalId(),
|
||||
'resourceUpdatedAt' => DateTime::now(),
|
||||
|
@ -2672,7 +2699,7 @@ App::post('/v1/messaging/messages/email')
|
|||
});
|
||||
|
||||
App::post('/v1/messaging/messages/sms')
|
||||
->desc('Create an SMS.')
|
||||
->desc('Create an SMS')
|
||||
->groups(['api', 'messaging'])
|
||||
->label('audits.event', 'message.create')
|
||||
->label('audits.resource', 'message/{response.$id}')
|
||||
|
@ -2680,7 +2707,7 @@ App::post('/v1/messaging/messages/sms')
|
|||
->label('scope', 'messages.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'messaging')
|
||||
->label('sdk.method', 'createSMS')
|
||||
->label('sdk.method', 'createSms')
|
||||
->label('sdk.description', '/docs/references/messaging/create-sms.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
|
@ -2744,14 +2771,13 @@ App::post('/v1/messaging/messages/sms')
|
|||
switch ($status) {
|
||||
case MessageStatus::PROCESSING:
|
||||
$queueForMessaging
|
||||
->setMessageId($message->getId())
|
||||
->trigger();
|
||||
->setType(MESSAGE_SEND_TYPE_EXTERNAL)
|
||||
->setMessageId($message->getId());
|
||||
break;
|
||||
case MessageStatus::SCHEDULED:
|
||||
$schedule = $dbForConsole->createDocument('schedules', new Document([
|
||||
'region' => App::getEnv('_APP_REGION', 'default'),
|
||||
'resourceType' => 'message',
|
||||
'resourceCollection' => 'messages',
|
||||
'resourceId' => $message->getId(),
|
||||
'resourceInternalId' => $message->getInternalId(),
|
||||
'resourceUpdatedAt' => DateTime::now(),
|
||||
|
@ -2781,7 +2807,7 @@ App::post('/v1/messaging/messages/sms')
|
|||
});
|
||||
|
||||
App::post('/v1/messaging/messages/push')
|
||||
->desc('Create a push notification.')
|
||||
->desc('Create a push notification')
|
||||
->groups(['api', 'messaging'])
|
||||
->label('audits.event', 'message.create')
|
||||
->label('audits.resource', 'message/{response.$id}')
|
||||
|
@ -2790,7 +2816,7 @@ App::post('/v1/messaging/messages/push')
|
|||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'messaging')
|
||||
->label('sdk.method', 'createPush')
|
||||
->label('sdk.description', '/docs/references/messaging/create-push-notification.md')
|
||||
->label('sdk.description', '/docs/references/messaging/create-push.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_MESSAGE)
|
||||
|
@ -2802,6 +2828,7 @@ App::post('/v1/messaging/messages/push')
|
|||
->param('targets', [], new ArrayList(new UID()), 'List of Targets IDs.', true)
|
||||
->param('data', null, new JSON(), 'Additional Data for push notification.', true)
|
||||
->param('action', '', new Text(256), 'Action for push notification.', true)
|
||||
->param('image', '', new CompoundUID(), 'Image for push notification. Must be a compound bucket ID to file ID of a jpeg, png, or bmp image in Appwrite Storage.', true)
|
||||
->param('icon', '', new Text(256), 'Icon for push notification. Available only for Android and Web Platform.', true)
|
||||
->param('sound', '', new Text(256), 'Sound for push notification. Available only for Android and IOS Platform.', true)
|
||||
->param('color', '', new Text(256), 'Color for push notification. Available only for Android Platform.', true)
|
||||
|
@ -2815,7 +2842,7 @@ App::post('/v1/messaging/messages/push')
|
|||
->inject('project')
|
||||
->inject('queueForMessaging')
|
||||
->inject('response')
|
||||
->action(function (string $messageId, string $title, string $body, array $topics, array $users, array $targets, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
|
||||
->action(function (string $messageId, string $title, string $body, array $topics, array $users, array $targets, ?array $data, string $action, string $image, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
|
||||
$messageId = $messageId == 'unique()'
|
||||
? ID::unique()
|
||||
: $messageId;
|
||||
|
@ -2846,9 +2873,41 @@ App::post('/v1/messaging/messages/push')
|
|||
}
|
||||
}
|
||||
|
||||
if (!empty($image)) {
|
||||
[$bucketId, $fileId] = CompoundUID::parse($image);
|
||||
|
||||
$bucket = $dbForProject->getDocument('buckets', $bucketId);
|
||||
if ($bucket->isEmpty()) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
if ($file->isEmpty()) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (!\in_array(Permission::read(Role::any()), \array_merge($file->getRead(), $bucket->getRead()))) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_PUBLIC);
|
||||
}
|
||||
|
||||
if (!\in_array($file->getAttribute('mimeType'), ['image/png', 'image/jpeg'])) {
|
||||
throw new Exception(Exception::STORAGE_FILE_TYPE_UNSUPPORTED);
|
||||
}
|
||||
|
||||
$host = App::getEnv('_APP_DOMAIN', 'localhost');
|
||||
$domain = new Domain(\parse_url($host, PHP_URL_HOST));
|
||||
$protocol = App::getEnv('_APP_OPTIONS_FORCE_HTTPS') === 'disabled' ? 'http' : 'https';
|
||||
|
||||
if (!$domain->isKnown()) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_PUBLIC);
|
||||
}
|
||||
|
||||
$image = "{$protocol}://{$host}/v1/storage/buckets/{$bucket->getId()}/files/{$file->getId()}/view?project={$project->getId()}";
|
||||
}
|
||||
|
||||
$pushData = [];
|
||||
|
||||
$keys = ['title', 'body', 'data', 'action', 'icon', 'sound', 'color', 'tag', 'badge'];
|
||||
$keys = ['title', 'body', 'data', 'action', 'image', 'icon', 'sound', 'color', 'tag', 'badge'];
|
||||
|
||||
foreach ($keys as $key) {
|
||||
if (!empty($$key)) {
|
||||
|
@ -2870,14 +2929,13 @@ App::post('/v1/messaging/messages/push')
|
|||
switch ($status) {
|
||||
case MessageStatus::PROCESSING:
|
||||
$queueForMessaging
|
||||
->setMessageId($message->getId())
|
||||
->trigger();
|
||||
->setType(MESSAGE_SEND_TYPE_EXTERNAL)
|
||||
->setMessageId($message->getId());
|
||||
break;
|
||||
case MessageStatus::SCHEDULED:
|
||||
$schedule = $dbForConsole->createDocument('schedules', new Document([
|
||||
'region' => App::getEnv('_APP_REGION', 'default'),
|
||||
'resourceType' => 'message',
|
||||
'resourceCollection' => 'messages',
|
||||
'resourceId' => $message->getId(),
|
||||
'resourceInternalId' => $message->getInternalId(),
|
||||
'resourceUpdatedAt' => DateTime::now(),
|
||||
|
@ -2964,7 +3022,7 @@ App::get('/v1/messaging/messages/:messageId/logs')
|
|||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'messaging')
|
||||
->label('sdk.method', 'listMessageLogs')
|
||||
->label('sdk.description', '/docs/references/messaging/messages/get-logs.md')
|
||||
->label('sdk.description', '/docs/references/messaging/list-message-logs.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_LOG_LIST)
|
||||
|
@ -3136,7 +3194,7 @@ App::get('/v1/messaging/messages/:messageId')
|
|||
});
|
||||
|
||||
App::patch('/v1/messaging/messages/email/:messageId')
|
||||
->desc('Update an email.')
|
||||
->desc('Update an email')
|
||||
->groups(['api', 'messaging'])
|
||||
->label('audits.event', 'message.update')
|
||||
->label('audits.resource', 'message/{response.$id}')
|
||||
|
@ -3231,7 +3289,6 @@ App::patch('/v1/messaging/messages/email/:messageId')
|
|||
$schedule = $dbForConsole->createDocument('schedules', new Document([
|
||||
'region' => App::getEnv('_APP_REGION', 'default'),
|
||||
'resourceType' => 'message',
|
||||
'resourceCollection' => 'messages',
|
||||
'resourceId' => $message->getId(),
|
||||
'resourceInternalId' => $message->getInternalId(),
|
||||
'resourceUpdatedAt' => DateTime::now(),
|
||||
|
@ -3263,8 +3320,8 @@ App::patch('/v1/messaging/messages/email/:messageId')
|
|||
|
||||
if ($status === MessageStatus::PROCESSING) {
|
||||
$queueForMessaging
|
||||
->setMessageId($message->getId())
|
||||
->trigger();
|
||||
->setType(MESSAGE_SEND_TYPE_EXTERNAL)
|
||||
->setMessageId($message->getId());
|
||||
}
|
||||
|
||||
$queueForEvents
|
||||
|
@ -3275,7 +3332,7 @@ App::patch('/v1/messaging/messages/email/:messageId')
|
|||
});
|
||||
|
||||
App::patch('/v1/messaging/messages/sms/:messageId')
|
||||
->desc('Update an SMS.')
|
||||
->desc('Update an SMS')
|
||||
->groups(['api', 'messaging'])
|
||||
->label('audits.event', 'message.update')
|
||||
->label('audits.resource', 'message/{response.$id}')
|
||||
|
@ -3283,7 +3340,7 @@ App::patch('/v1/messaging/messages/sms/:messageId')
|
|||
->label('scope', 'messages.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'messaging')
|
||||
->label('sdk.method', 'updateSMS')
|
||||
->label('sdk.method', 'updateSms')
|
||||
->label('sdk.description', '/docs/references/messaging/update-email.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
|
@ -3350,7 +3407,6 @@ App::patch('/v1/messaging/messages/sms/:messageId')
|
|||
$schedule = $dbForConsole->createDocument('schedules', new Document([
|
||||
'region' => App::getEnv('_APP_REGION', 'default'),
|
||||
'resourceType' => 'message',
|
||||
'resourceCollection' => 'messages',
|
||||
'resourceId' => $message->getId(),
|
||||
'resourceInternalId' => $message->getInternalId(),
|
||||
'resourceUpdatedAt' => DateTime::now(),
|
||||
|
@ -3382,8 +3438,8 @@ App::patch('/v1/messaging/messages/sms/:messageId')
|
|||
|
||||
if ($status === MessageStatus::PROCESSING) {
|
||||
$queueForMessaging
|
||||
->setMessageId($message->getId())
|
||||
->trigger();
|
||||
->setType(MESSAGE_SEND_TYPE_EXTERNAL)
|
||||
->setMessageId($message->getId());
|
||||
}
|
||||
|
||||
$queueForEvents
|
||||
|
@ -3394,7 +3450,7 @@ App::patch('/v1/messaging/messages/sms/:messageId')
|
|||
});
|
||||
|
||||
App::patch('/v1/messaging/messages/push/:messageId')
|
||||
->desc('Update a push notification.')
|
||||
->desc('Update a push notification')
|
||||
->groups(['api', 'messaging'])
|
||||
->label('audits.event', 'message.update')
|
||||
->label('audits.resource', 'message/{response.$id}')
|
||||
|
@ -3403,7 +3459,7 @@ App::patch('/v1/messaging/messages/push/:messageId')
|
|||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'messaging')
|
||||
->label('sdk.method', 'updatePush')
|
||||
->label('sdk.description', '/docs/references/messaging/update-push-notification.md')
|
||||
->label('sdk.description', '/docs/references/messaging/update-push.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_MESSAGE)
|
||||
|
@ -3415,6 +3471,7 @@ App::patch('/v1/messaging/messages/push/:messageId')
|
|||
->param('body', null, new Text(64230), 'Body for push notification.', true)
|
||||
->param('data', null, new JSON(), 'Additional Data for push notification.', true)
|
||||
->param('action', null, new Text(256), 'Action for push notification.', true)
|
||||
->param('image', null, new CompoundUID(), 'Image for push notification. Must be a compound bucket ID to file ID of a jpeg, png, or bmp image in Appwrite Storage.', true)
|
||||
->param('icon', null, new Text(256), 'Icon for push notification. Available only for Android and Web platforms.', true)
|
||||
->param('sound', null, new Text(256), 'Sound for push notification. Available only for Android and iOS platforms.', true)
|
||||
->param('color', null, new Text(256), 'Color for push notification. Available only for Android platforms.', true)
|
||||
|
@ -3428,7 +3485,7 @@ App::patch('/v1/messaging/messages/push/:messageId')
|
|||
->inject('project')
|
||||
->inject('queueForMessaging')
|
||||
->inject('response')
|
||||
->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, ?string $title, ?string $body, ?array $data, ?string $action, ?string $icon, ?string $sound, ?string $color, ?string $tag, ?int $badge, ?string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
|
||||
->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, ?string $title, ?string $body, ?array $data, ?string $action, ?string $image, ?string $icon, ?string $sound, ?string $color, ?string $tag, ?int $badge, ?string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
|
||||
$message = $dbForProject->getDocument('messages', $messageId);
|
||||
|
||||
if ($message->isEmpty()) {
|
||||
|
@ -3498,6 +3555,38 @@ App::patch('/v1/messaging/messages/push/:messageId')
|
|||
$pushData['badge'] = $badge;
|
||||
}
|
||||
|
||||
if (!\is_null($image)) {
|
||||
[$bucketId, $fileId] = CompoundUID::parse($image);
|
||||
|
||||
$bucket = $dbForProject->getDocument('buckets', $bucketId);
|
||||
if ($bucket->isEmpty()) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
if ($file->isEmpty()) {
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (!\in_array(Permission::read(Role::any()), \array_merge($file->getRead(), $bucket->getRead()))) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_PUBLIC);
|
||||
}
|
||||
|
||||
if (!\in_array($file->getAttribute('mimeType'), ['image/png', 'image/jpeg'])) {
|
||||
throw new Exception(Exception::STORAGE_FILE_TYPE_UNSUPPORTED);
|
||||
}
|
||||
|
||||
$host = App::getEnv('_APP_DOMAIN', 'localhost');
|
||||
$domain = new Domain(\parse_url($host, PHP_URL_HOST));
|
||||
$protocol = App::getEnv('_APP_OPTIONS_FORCE_HTTPS') === 'disabled' ? 'http' : 'https';
|
||||
|
||||
if (!$domain->isKnown()) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_PUBLIC);
|
||||
}
|
||||
|
||||
$pushData['image'] = "{$protocol}://{$host}/v1/storage/buckets/{$bucket->getId()}/files/{$file->getId()}/view?project={$project->getId()}";
|
||||
}
|
||||
|
||||
$message->setAttribute('data', $pushData);
|
||||
|
||||
if (!\is_null($status)) {
|
||||
|
@ -3509,7 +3598,6 @@ App::patch('/v1/messaging/messages/push/:messageId')
|
|||
$schedule = $dbForConsole->createDocument('schedules', new Document([
|
||||
'region' => App::getEnv('_APP_REGION', 'default'),
|
||||
'resourceType' => 'message',
|
||||
'resourceCollection' => 'messages',
|
||||
'resourceId' => $message->getId(),
|
||||
'resourceInternalId' => $message->getInternalId(),
|
||||
'resourceUpdatedAt' => DateTime::now(),
|
||||
|
@ -3541,8 +3629,8 @@ App::patch('/v1/messaging/messages/push/:messageId')
|
|||
|
||||
if ($status === MessageStatus::PROCESSING) {
|
||||
$queueForMessaging
|
||||
->setMessageId($message->getId())
|
||||
->trigger();
|
||||
->setType(MESSAGE_SEND_TYPE_EXTERNAL)
|
||||
->setMessageId($message->getId());
|
||||
}
|
||||
|
||||
$queueForEvents
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -360,9 +360,9 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
|||
->inject('user')
|
||||
->inject('queueForEvents')
|
||||
->inject('mode')
|
||||
->inject('deviceFiles')
|
||||
->inject('deviceLocal')
|
||||
->action(function (string $bucketId, string $fileId, mixed $file, ?array $permissions, Request $request, Response $response, Database $dbForProject, Document $user, Event $queueForEvents, string $mode, Device $deviceFiles, Device $deviceLocal) {
|
||||
->inject('deviceForFiles')
|
||||
->inject('deviceForLocal')
|
||||
->action(function (string $bucketId, string $fileId, mixed $file, ?array $permissions, Request $request, Response $response, Database $dbForProject, Document $user, Event $queueForEvents, string $mode, Device $deviceForFiles, Device $deviceForLocal) {
|
||||
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
|
@ -493,13 +493,13 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
|||
}
|
||||
|
||||
// Save to storage
|
||||
$fileSize ??= $deviceLocal->getFileSize($fileTmpName);
|
||||
$path = $deviceFiles->getPath($fileId . '.' . \pathinfo($fileName, PATHINFO_EXTENSION));
|
||||
$path = str_ireplace($deviceFiles->getRoot(), $deviceFiles->getRoot() . DIRECTORY_SEPARATOR . $bucket->getId(), $path); // Add bucket id to path after root
|
||||
$fileSize ??= $deviceForLocal->getFileSize($fileTmpName);
|
||||
$path = $deviceForFiles->getPath($fileId . '.' . \pathinfo($fileName, PATHINFO_EXTENSION));
|
||||
$path = str_ireplace($deviceForFiles->getRoot(), $deviceForFiles->getRoot() . DIRECTORY_SEPARATOR . $bucket->getId(), $path); // Add bucket id to path after root
|
||||
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
|
||||
$metadata = ['content_type' => $deviceLocal->getFileMimeType($fileTmpName)];
|
||||
$metadata = ['content_type' => $deviceForLocal->getFileMimeType($fileTmpName)];
|
||||
if (!$file->isEmpty()) {
|
||||
$chunks = $file->getAttribute('chunksTotal', 1);
|
||||
$uploaded = $file->getAttribute('chunksUploaded', 0);
|
||||
|
@ -514,32 +514,32 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
|||
}
|
||||
}
|
||||
|
||||
$chunksUploaded = $deviceFiles->upload($fileTmpName, $path, $chunk, $chunks, $metadata);
|
||||
$chunksUploaded = $deviceForFiles->upload($fileTmpName, $path, $chunk, $chunks, $metadata);
|
||||
|
||||
if (empty($chunksUploaded)) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed uploading file');
|
||||
}
|
||||
|
||||
if ($chunksUploaded === $chunks) {
|
||||
if (App::getEnv('_APP_STORAGE_ANTIVIRUS') === 'enabled' && $bucket->getAttribute('antivirus', true) && $fileSize <= APP_LIMIT_ANTIVIRUS && $deviceFiles->getType() === Storage::DEVICE_LOCAL) {
|
||||
if (App::getEnv('_APP_STORAGE_ANTIVIRUS') === 'enabled' && $bucket->getAttribute('antivirus', true) && $fileSize <= APP_LIMIT_ANTIVIRUS && $deviceForFiles->getType() === Storage::DEVICE_LOCAL) {
|
||||
$antivirus = new Network(
|
||||
App::getEnv('_APP_STORAGE_ANTIVIRUS_HOST', 'clamav'),
|
||||
(int) App::getEnv('_APP_STORAGE_ANTIVIRUS_PORT', 3310)
|
||||
);
|
||||
|
||||
if (!$antivirus->fileScan($path)) {
|
||||
$deviceFiles->delete($path);
|
||||
$deviceForFiles->delete($path);
|
||||
throw new Exception(Exception::STORAGE_INVALID_FILE);
|
||||
}
|
||||
}
|
||||
|
||||
$mimeType = $deviceFiles->getFileMimeType($path); // Get mime-type before compression and encryption
|
||||
$fileHash = $deviceFiles->getFileHash($path); // Get file hash before compression and encryption
|
||||
$mimeType = $deviceForFiles->getFileMimeType($path); // Get mime-type before compression and encryption
|
||||
$fileHash = $deviceForFiles->getFileHash($path); // Get file hash before compression and encryption
|
||||
$data = '';
|
||||
// Compression
|
||||
$algorithm = $bucket->getAttribute('compression', Compression::NONE);
|
||||
if ($fileSize <= APP_STORAGE_READ_BUFFER && $algorithm != Compression::NONE) {
|
||||
$data = $deviceFiles->read($path);
|
||||
$data = $deviceForFiles->read($path);
|
||||
switch ($algorithm) {
|
||||
case Compression::ZSTD:
|
||||
$compressor = new Zstd();
|
||||
|
@ -559,7 +559,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
|||
|
||||
if ($bucket->getAttribute('encryption', true) && $fileSize <= APP_STORAGE_READ_BUFFER) {
|
||||
if (empty($data)) {
|
||||
$data = $deviceFiles->read($path);
|
||||
$data = $deviceForFiles->read($path);
|
||||
}
|
||||
$key = App::getEnv('_APP_OPENSSL_KEY_V1');
|
||||
$iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM));
|
||||
|
@ -567,12 +567,12 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
|||
}
|
||||
|
||||
if (!empty($data)) {
|
||||
if (!$deviceFiles->write($path, $data, $mimeType)) {
|
||||
if (!$deviceForFiles->write($path, $data, $mimeType)) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to save file');
|
||||
}
|
||||
}
|
||||
|
||||
$sizeActual = $deviceFiles->getFileSize($path);
|
||||
$sizeActual = $deviceForFiles->getFileSize($path);
|
||||
|
||||
$openSSLVersion = null;
|
||||
$openSSLCipher = null;
|
||||
|
@ -872,9 +872,9 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
|||
->inject('project')
|
||||
->inject('dbForProject')
|
||||
->inject('mode')
|
||||
->inject('deviceFiles')
|
||||
->inject('deviceLocal')
|
||||
->action(function (string $bucketId, string $fileId, int $width, int $height, string $gravity, int $quality, int $borderWidth, string $borderColor, int $borderRadius, float $opacity, int $rotation, string $background, string $output, Request $request, Response $response, Document $project, Database $dbForProject, string $mode, Device $deviceFiles, Device $deviceLocal) {
|
||||
->inject('deviceForFiles')
|
||||
->inject('deviceForLocal')
|
||||
->action(function (string $bucketId, string $fileId, int $width, int $height, string $gravity, int $quality, int $borderWidth, string $borderColor, int $borderRadius, float $opacity, int $rotation, string $background, string $output, Request $request, Response $response, Document $project, Database $dbForProject, string $mode, Device $deviceForFiles, Device $deviceForLocal) {
|
||||
|
||||
if (!\extension_loaded('imagick')) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Imagick extension is missing');
|
||||
|
@ -931,10 +931,10 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
|||
$cipher = null;
|
||||
$background = (empty($background)) ? 'eceff1' : $background;
|
||||
$type = \strtolower(\pathinfo($path, PATHINFO_EXTENSION));
|
||||
$deviceFiles = $deviceLocal;
|
||||
$deviceForFiles = $deviceForLocal;
|
||||
}
|
||||
|
||||
if (!$deviceFiles->exists($path)) {
|
||||
if (!$deviceForFiles->exists($path)) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
@ -950,7 +950,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
|||
$output = empty($type) ? (array_search($mime, $outputs) ?? 'jpg') : $type;
|
||||
}
|
||||
|
||||
$source = $deviceFiles->read($path);
|
||||
$source = $deviceForFiles->read($path);
|
||||
|
||||
if (!empty($cipher)) { // Decrypt
|
||||
$source = OpenSSL::decrypt(
|
||||
|
@ -1033,8 +1033,8 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
|||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('mode')
|
||||
->inject('deviceFiles')
|
||||
->action(function (string $bucketId, string $fileId, Request $request, Response $response, Database $dbForProject, string $mode, Device $deviceFiles) {
|
||||
->inject('deviceForFiles')
|
||||
->action(function (string $bucketId, string $fileId, Request $request, Response $response, Database $dbForProject, string $mode, Device $deviceForFiles) {
|
||||
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
|
@ -1064,7 +1064,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
|||
|
||||
$path = $file->getAttribute('path', '');
|
||||
|
||||
if (!$deviceFiles->exists($path)) {
|
||||
if (!$deviceForFiles->exists($path)) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND, 'File not found in ' . $path);
|
||||
}
|
||||
|
||||
|
@ -1100,7 +1100,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
|||
|
||||
$source = '';
|
||||
if (!empty($file->getAttribute('openSSLCipher'))) { // Decrypt
|
||||
$source = $deviceFiles->read($path);
|
||||
$source = $deviceForFiles->read($path);
|
||||
$source = OpenSSL::decrypt(
|
||||
$source,
|
||||
$file->getAttribute('openSSLCipher'),
|
||||
|
@ -1114,14 +1114,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
|||
switch ($file->getAttribute('algorithm', Compression::NONE)) {
|
||||
case Compression::ZSTD:
|
||||
if (empty($source)) {
|
||||
$source = $deviceFiles->read($path);
|
||||
$source = $deviceForFiles->read($path);
|
||||
}
|
||||
$compressor = new Zstd();
|
||||
$source = $compressor->decompress($source);
|
||||
break;
|
||||
case Compression::GZIP:
|
||||
if (empty($source)) {
|
||||
$source = $deviceFiles->read($path);
|
||||
$source = $deviceForFiles->read($path);
|
||||
}
|
||||
$compressor = new GZIP();
|
||||
$source = $compressor->decompress($source);
|
||||
|
@ -1136,13 +1136,13 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
|||
}
|
||||
|
||||
if (!empty($rangeHeader)) {
|
||||
$response->send($deviceFiles->read($path, $start, ($end - $start + 1)));
|
||||
$response->send($deviceForFiles->read($path, $start, ($end - $start + 1)));
|
||||
}
|
||||
|
||||
if ($size > APP_STORAGE_READ_BUFFER) {
|
||||
for ($i = 0; $i < ceil($size / MAX_OUTPUT_CHUNK_SIZE); $i++) {
|
||||
$response->chunk(
|
||||
$deviceFiles->read(
|
||||
$deviceForFiles->read(
|
||||
$path,
|
||||
($i * MAX_OUTPUT_CHUNK_SIZE),
|
||||
min(MAX_OUTPUT_CHUNK_SIZE, $size - ($i * MAX_OUTPUT_CHUNK_SIZE))
|
||||
|
@ -1151,7 +1151,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
|||
);
|
||||
}
|
||||
} else {
|
||||
$response->send($deviceFiles->read($path));
|
||||
$response->send($deviceForFiles->read($path));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1173,8 +1173,8 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
|||
->inject('request')
|
||||
->inject('dbForProject')
|
||||
->inject('mode')
|
||||
->inject('deviceFiles')
|
||||
->action(function (string $bucketId, string $fileId, Response $response, Request $request, Database $dbForProject, string $mode, Device $deviceFiles) {
|
||||
->inject('deviceForFiles')
|
||||
->action(function (string $bucketId, string $fileId, Response $response, Request $request, Database $dbForProject, string $mode, Device $deviceForFiles) {
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
|
||||
|
@ -1205,7 +1205,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
|||
|
||||
$path = $file->getAttribute('path', '');
|
||||
|
||||
if (!$deviceFiles->exists($path)) {
|
||||
if (!$deviceForFiles->exists($path)) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND, 'File not found in ' . $path);
|
||||
}
|
||||
|
||||
|
@ -1249,7 +1249,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
|||
|
||||
$source = '';
|
||||
if (!empty($file->getAttribute('openSSLCipher'))) { // Decrypt
|
||||
$source = $deviceFiles->read($path);
|
||||
$source = $deviceForFiles->read($path);
|
||||
$source = OpenSSL::decrypt(
|
||||
$source,
|
||||
$file->getAttribute('openSSLCipher'),
|
||||
|
@ -1263,14 +1263,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
|||
switch ($file->getAttribute('algorithm', Compression::NONE)) {
|
||||
case Compression::ZSTD:
|
||||
if (empty($source)) {
|
||||
$source = $deviceFiles->read($path);
|
||||
$source = $deviceForFiles->read($path);
|
||||
}
|
||||
$compressor = new Zstd();
|
||||
$source = $compressor->decompress($source);
|
||||
break;
|
||||
case Compression::GZIP:
|
||||
if (empty($source)) {
|
||||
$source = $deviceFiles->read($path);
|
||||
$source = $deviceForFiles->read($path);
|
||||
}
|
||||
$compressor = new GZIP();
|
||||
$source = $compressor->decompress($source);
|
||||
|
@ -1286,15 +1286,15 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
|||
}
|
||||
|
||||
if (!empty($rangeHeader)) {
|
||||
$response->send($deviceFiles->read($path, $start, ($end - $start + 1)));
|
||||
$response->send($deviceForFiles->read($path, $start, ($end - $start + 1)));
|
||||
return;
|
||||
}
|
||||
|
||||
$size = $deviceFiles->getFileSize($path);
|
||||
$size = $deviceForFiles->getFileSize($path);
|
||||
if ($size > APP_STORAGE_READ_BUFFER) {
|
||||
for ($i = 0; $i < ceil($size / MAX_OUTPUT_CHUNK_SIZE); $i++) {
|
||||
$response->chunk(
|
||||
$deviceFiles->read(
|
||||
$deviceForFiles->read(
|
||||
$path,
|
||||
($i * MAX_OUTPUT_CHUNK_SIZE),
|
||||
min(MAX_OUTPUT_CHUNK_SIZE, $size - ($i * MAX_OUTPUT_CHUNK_SIZE))
|
||||
|
@ -1303,7 +1303,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
|||
);
|
||||
}
|
||||
} else {
|
||||
$response->send($deviceFiles->read($path));
|
||||
$response->send($deviceForFiles->read($path));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1438,9 +1438,9 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
|
|||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
->inject('mode')
|
||||
->inject('deviceFiles')
|
||||
->inject('deviceForFiles')
|
||||
->inject('queueForDeletes')
|
||||
->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $queueForEvents, string $mode, Device $deviceFiles, Delete $queueForDeletes) {
|
||||
->action(function (string $bucketId, string $fileId, Response $response, Database $dbForProject, Event $queueForEvents, string $mode, Device $deviceForFiles, Delete $queueForDeletes) {
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
|
||||
|
@ -1471,17 +1471,18 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
|
|||
|
||||
$deviceDeleted = false;
|
||||
if ($file->getAttribute('chunksTotal') !== $file->getAttribute('chunksUploaded')) {
|
||||
$deviceDeleted = $deviceFiles->abort(
|
||||
$deviceDeleted = $deviceForFiles->abort(
|
||||
$file->getAttribute('path'),
|
||||
($file->getAttribute('metadata', [])['uploadId'] ?? '')
|
||||
);
|
||||
} else {
|
||||
$deviceDeleted = $deviceFiles->delete($file->getAttribute('path'));
|
||||
$deviceDeleted = $deviceForFiles->delete($file->getAttribute('path'));
|
||||
}
|
||||
|
||||
if ($deviceDeleted) {
|
||||
$queueForDeletes
|
||||
->setType(DELETE_TYPE_CACHE_BY_RESOURCE)
|
||||
->setResourceType('bucket/' . $bucket->getId())
|
||||
->setResource('file/' . $fileId)
|
||||
;
|
||||
|
||||
|
|
|
@ -658,10 +658,10 @@ App::post('/v1/teams/:teamId/memberships')
|
|||
]);
|
||||
|
||||
$queueForMessaging
|
||||
->setType(MESSAGE_SEND_TYPE_INTERNAL)
|
||||
->setMessage($messageDoc)
|
||||
->setRecipients([$phone])
|
||||
->setProviderType('SMS')
|
||||
->trigger();
|
||||
->setProviderType('SMS');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -995,7 +995,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
|||
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
|
||||
$team = Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team->setAttribute('total', $team->getAttribute('total', 0) + 1)));
|
||||
Authorization::skip(fn() => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1));
|
||||
|
||||
$queueForEvents
|
||||
->setParam('teamId', $team->getId())
|
||||
|
@ -1075,8 +1075,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId')
|
|||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
|
||||
if ($membership->getAttribute('confirm')) { // Count only confirmed members
|
||||
$team->setAttribute('total', \max($team->getAttribute('total', 0) - 1, 0));
|
||||
Authorization::skip(fn() => $dbForProject->updateDocument('teams', $team->getId(), $team));
|
||||
Authorization::skip(fn() => $dbForProject->decreaseDocumentAttribute('teams', $team->getId(), 'total', 1, 0));
|
||||
}
|
||||
|
||||
$queueForEvents
|
||||
|
|
|
@ -192,7 +192,6 @@ App::post('/v1/users')
|
|||
->inject('hooks')
|
||||
->action(function (string $userId, ?string $email, ?string $phone, ?string $password, string $name, Response $response, Document $project, Database $dbForProject, Event $queueForEvents, Hooks $hooks) {
|
||||
$user = createUser('plaintext', '{}', $userId, $email, $password, $phone, $name, $project, $dbForProject, $queueForEvents, $hooks);
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($user, Response::MODEL_USER);
|
||||
|
@ -806,6 +805,9 @@ 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'],
|
||||
|
@ -834,7 +836,7 @@ App::get('/v1/users/:userId/logs')
|
|||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => $audit->countLogsByUser($user->getId()),
|
||||
'total' => $audit->countLogsByUser($user->getInternalId()),
|
||||
'logs' => $output,
|
||||
]), Response::MODEL_LOG_LIST);
|
||||
});
|
||||
|
|
|
@ -238,9 +238,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
|
|||
$queueForBuilds
|
||||
->setType(BUILD_TYPE_DEPLOYMENT)
|
||||
->setResource($function)
|
||||
->setDeployment($deployment)
|
||||
->setProject($project)
|
||||
->trigger();
|
||||
->setDeployment($deployment);
|
||||
|
||||
//TODO: Add event?
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Event\Audit;
|
||||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Database as EventDatabase;
|
||||
use Appwrite\Event\Delete;
|
||||
use Appwrite\Event\Event;
|
||||
|
@ -305,10 +306,11 @@ App::init()
|
|||
->inject('queueForAudits')
|
||||
->inject('queueForDeletes')
|
||||
->inject('queueForDatabase')
|
||||
->inject('queueForBuilds')
|
||||
->inject('queueForUsage')
|
||||
->inject('dbForProject')
|
||||
->inject('mode')
|
||||
->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $queueForEvents, Messaging $queueForMessaging, Audit $queueForAudits, Delete $queueForDeletes, EventDatabase $queueForDatabase, Usage $queueForUsage, Database $dbForProject, string $mode) use ($databaseListener) {
|
||||
->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $queueForEvents, Messaging $queueForMessaging, Audit $queueForAudits, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, Usage $queueForUsage, Database $dbForProject, string $mode) use ($databaseListener) {
|
||||
|
||||
$route = $utopia->getRoute();
|
||||
|
||||
|
@ -382,9 +384,6 @@ App::init()
|
|||
->setProject($project)
|
||||
->setUser($user);
|
||||
|
||||
$queueForMessaging
|
||||
->setProject($project);
|
||||
|
||||
$queueForAudits
|
||||
->setMode($mode)
|
||||
->setUserAgent($request->getUserAgent(''))
|
||||
|
@ -393,9 +392,10 @@ App::init()
|
|||
->setProject($project)
|
||||
->setUser($user);
|
||||
|
||||
|
||||
$queueForDeletes->setProject($project);
|
||||
$queueForDatabase->setProject($project);
|
||||
$queueForBuilds->setProject($project);
|
||||
$queueForMessaging->setProject($project);
|
||||
|
||||
$dbForProject
|
||||
->on(Database::EVENT_DOCUMENT_CREATE, 'calculate-usage', fn ($event, $document) => $databaseListener($event, $document, $project, $queueForUsage, $dbForProject))
|
||||
|
@ -403,24 +403,22 @@ App::init()
|
|||
;
|
||||
|
||||
$useCache = $route->getLabel('cache', false);
|
||||
|
||||
if ($useCache) {
|
||||
$key = md5($request->getURI() . implode('*', $request->getParams()) . '*' . APP_CACHE_BUSTER);
|
||||
$cacheLog = Authorization::skip(fn () => $dbForProject->getDocument('cache', $key));
|
||||
$cache = new Cache(
|
||||
new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $project->getId())
|
||||
);
|
||||
$timestamp = 60 * 60 * 24 * 30;
|
||||
$data = $cache->load($key, $timestamp);
|
||||
|
||||
if (!empty($data)) {
|
||||
$data = json_decode($data, true);
|
||||
$parts = explode('/', $data['resourceType']);
|
||||
if (!empty($data) && !$cacheLog->isEmpty()) {
|
||||
$parts = explode('/', $cacheLog->getAttribute('resourceType'));
|
||||
$type = $parts[0] ?? null;
|
||||
|
||||
if ($type === 'bucket') {
|
||||
$bucketId = $parts[1] ?? null;
|
||||
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
|
||||
|
@ -432,11 +430,12 @@ App::init()
|
|||
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
|
||||
$validator = new Authorization(Database::PERMISSION_READ);
|
||||
$valid = $validator->isValid($bucket->getRead());
|
||||
|
||||
if (!$fileSecurity && !$valid) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
$parts = explode('/', $data['resource']);
|
||||
$parts = explode('/', $cacheLog->getAttribute('resource'));
|
||||
$fileId = $parts[1] ?? null;
|
||||
|
||||
if ($fileSecurity && !$valid) {
|
||||
|
@ -453,8 +452,8 @@ App::init()
|
|||
$response
|
||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $timestamp) . ' GMT')
|
||||
->addHeader('X-Appwrite-Cache', 'hit')
|
||||
->setContentType($data['contentType'])
|
||||
->send(base64_decode($data['payload']))
|
||||
->setContentType($cacheLog->getAttribute('mimeType'))
|
||||
->send($data)
|
||||
;
|
||||
} else {
|
||||
$response->addHeader('X-Appwrite-Cache', 'miss');
|
||||
|
@ -513,11 +512,13 @@ App::shutdown()
|
|||
->inject('queueForUsage')
|
||||
->inject('queueForDeletes')
|
||||
->inject('queueForDatabase')
|
||||
->inject('queueForBuilds')
|
||||
->inject('queueForMessaging')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForFunctions')
|
||||
->inject('mode')
|
||||
->inject('dbForConsole')
|
||||
->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $queueForEvents, Audit $queueForAudits, Usage $queueForUsage, Delete $queueForDeletes, EventDatabase $queueForDatabase, Database $dbForProject, Func $queueForFunctions, string $mode, Database $dbForConsole) use ($parseLabel) {
|
||||
->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $queueForEvents, Audit $queueForAudits, Usage $queueForUsage, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, Messaging $queueForMessaging, Database $dbForProject, Func $queueForFunctions, string $mode, Database $dbForConsole) use ($parseLabel) {
|
||||
|
||||
$responsePayload = $response->getPayload();
|
||||
|
||||
|
@ -618,6 +619,14 @@ App::shutdown()
|
|||
$queueForDatabase->trigger();
|
||||
}
|
||||
|
||||
if (!empty($queueForBuilds->getType())) {
|
||||
$queueForBuilds->trigger();
|
||||
}
|
||||
|
||||
if (!empty($queueForMessaging->getType())) {
|
||||
$queueForMessaging->trigger();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache label
|
||||
*/
|
||||
|
@ -625,7 +634,6 @@ App::shutdown()
|
|||
if ($useCache) {
|
||||
$resource = $resourceType = null;
|
||||
$data = $response->getPayload();
|
||||
|
||||
if (!empty($data['payload'])) {
|
||||
$pattern = $route->getLabel('cache.resource', null);
|
||||
if (!empty($pattern)) {
|
||||
|
@ -637,24 +645,19 @@ App::shutdown()
|
|||
$resourceType = $parseLabel($pattern, $responsePayload, $requestParams, $user);
|
||||
}
|
||||
|
||||
$key = md5($request->getURI() . implode('*', $request->getParams()) . '*' . APP_CACHE_BUSTER);
|
||||
$data = json_encode([
|
||||
'resourceType' => $resourceType,
|
||||
'resource' => $resource,
|
||||
'contentType' => $response->getContentType(),
|
||||
'payload' => base64_encode($data['payload']),
|
||||
]);
|
||||
|
||||
$signature = md5($data);
|
||||
$cacheLog = Authorization::skip(fn () => $dbForProject->getDocument('cache', $key));
|
||||
$key = md5($request->getURI() . '*' . implode('*', $request->getParams())) . '*' . APP_CACHE_BUSTER;
|
||||
$signature = md5($data['payload']);
|
||||
$cacheLog = Authorization::skip(fn () => $dbForProject->getDocument('cache', $key));
|
||||
$accessedAt = $cacheLog->getAttribute('accessedAt', '');
|
||||
$now = DateTime::now();
|
||||
if ($cacheLog->isEmpty()) {
|
||||
Authorization::skip(fn () => $dbForProject->createDocument('cache', new Document([
|
||||
'$id' => $key,
|
||||
'resource' => $resource,
|
||||
'accessedAt' => $now,
|
||||
'signature' => $signature,
|
||||
'$id' => $key,
|
||||
'resource' => $resource,
|
||||
'resourceType' => $resourceType,
|
||||
'mimeType' => $response->getContentType(),
|
||||
'accessedAt' => $now,
|
||||
'signature' => $signature,
|
||||
])));
|
||||
} elseif (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_CACHE_UPDATE)) > $accessedAt) {
|
||||
$cacheLog->setAttribute('accessedAt', $now);
|
||||
|
@ -665,7 +668,7 @@ App::shutdown()
|
|||
$cache = new Cache(
|
||||
new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $project->getId())
|
||||
);
|
||||
$cache->save($key, $data);
|
||||
$cache->save($key, $data['payload']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
16
app/init.php
16
app/init.php
|
@ -142,9 +142,11 @@ const APP_SOCIAL_DEV = 'https://dev.to/appwrite';
|
|||
const APP_SOCIAL_STACKSHARE = 'https://stackshare.io/appwrite';
|
||||
const APP_SOCIAL_YOUTUBE = 'https://www.youtube.com/c/appwrite?sub_confirmation=1';
|
||||
const APP_HOSTNAME_INTERNAL = 'appwrite';
|
||||
|
||||
// Database Reconnect
|
||||
const DATABASE_RECONNECT_SLEEP = 2;
|
||||
const DATABASE_RECONNECT_MAX_ATTEMPTS = 10;
|
||||
|
||||
// Database Worker Types
|
||||
const DATABASE_TYPE_CREATE_ATTRIBUTE = 'createAttribute';
|
||||
const DATABASE_TYPE_CREATE_INDEX = 'createIndex';
|
||||
|
@ -152,9 +154,11 @@ const DATABASE_TYPE_DELETE_ATTRIBUTE = 'deleteAttribute';
|
|||
const DATABASE_TYPE_DELETE_INDEX = 'deleteIndex';
|
||||
const DATABASE_TYPE_DELETE_COLLECTION = 'deleteCollection';
|
||||
const DATABASE_TYPE_DELETE_DATABASE = 'deleteDatabase';
|
||||
|
||||
// Build Worker Types
|
||||
const BUILD_TYPE_DEPLOYMENT = 'deployment';
|
||||
const BUILD_TYPE_RETRY = 'retry';
|
||||
|
||||
// Deletion Types
|
||||
const DELETE_TYPE_DATABASES = 'databases';
|
||||
const DELETE_TYPE_DOCUMENT = 'document';
|
||||
|
@ -180,6 +184,10 @@ const DELETE_TYPE_TOPIC = 'topic';
|
|||
const DELETE_TYPE_TARGET = 'target';
|
||||
const DELETE_TYPE_EXPIRED_TARGETS = 'invalid_targets';
|
||||
const DELETE_TYPE_SESSION_TARGETS = 'session_targets';
|
||||
|
||||
// Message types
|
||||
const MESSAGE_SEND_TYPE_INTERNAL = 'internal';
|
||||
const MESSAGE_SEND_TYPE_EXTERNAL = 'external';
|
||||
// Mail Types
|
||||
const MAIL_TYPE_VERIFICATION = 'verification';
|
||||
const MAIL_TYPE_MAGIC_SESSION = 'magicSession';
|
||||
|
@ -1375,19 +1383,19 @@ App::setResource('cache', function (Group $pools) {
|
|||
return new Cache(new Sharding($adapters));
|
||||
}, ['pools']);
|
||||
|
||||
App::setResource('deviceLocal', function () {
|
||||
App::setResource('deviceForLocal', function () {
|
||||
return new Local();
|
||||
});
|
||||
|
||||
App::setResource('deviceFiles', function ($project) {
|
||||
App::setResource('deviceForFiles', function ($project) {
|
||||
return getDevice(APP_STORAGE_UPLOADS . '/app-' . $project->getId());
|
||||
}, ['project']);
|
||||
|
||||
App::setResource('deviceFunctions', function ($project) {
|
||||
App::setResource('deviceForFunctions', function ($project) {
|
||||
return getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $project->getId());
|
||||
}, ['project']);
|
||||
|
||||
App::setResource('deviceBuilds', function ($project) {
|
||||
App::setResource('deviceForBuilds', function ($project) {
|
||||
return getDevice(APP_STORAGE_BUILDS . '/app-' . $project->getId());
|
||||
}, ['project']);
|
||||
|
||||
|
|
114
app/worker.php
114
app/worker.php
|
@ -15,6 +15,7 @@ use Appwrite\Event\Messaging;
|
|||
use Appwrite\Event\Migration;
|
||||
use Appwrite\Event\Phone;
|
||||
use Appwrite\Event\Usage;
|
||||
use Appwrite\Event\UsageDump;
|
||||
use Appwrite\Platform\Appwrite;
|
||||
use Swoole\Runtime;
|
||||
use Utopia\App;
|
||||
|
@ -34,6 +35,7 @@ use Utopia\Logger\Log;
|
|||
use Utopia\Logger\Logger;
|
||||
use Utopia\Pools\Group;
|
||||
use Utopia\Queue\Connection;
|
||||
use Utopia\Storage\Device\Local;
|
||||
|
||||
Authorization::disable();
|
||||
Runtime::enableCoroutine(SWOOLE_HOOK_ALL);
|
||||
|
@ -45,8 +47,7 @@ Server::setResource('dbForConsole', function (Cache $cache, Registry $register)
|
|||
$database = $pools
|
||||
->get('console')
|
||||
->pop()
|
||||
->getResource()
|
||||
;
|
||||
->getResource();
|
||||
|
||||
$adapter = new Database($database, $cache);
|
||||
$adapter->setNamespace('_console');
|
||||
|
@ -54,26 +55,6 @@ Server::setResource('dbForConsole', function (Cache $cache, Registry $register)
|
|||
return $adapter;
|
||||
}, ['cache', 'register']);
|
||||
|
||||
Server::setResource('dbForProject', function (Cache $cache, Registry $register, Message $message, Database $dbForConsole) {
|
||||
$payload = $message->getPayload() ?? [];
|
||||
$project = new Document($payload['project'] ?? []);
|
||||
|
||||
if ($project->isEmpty() || $project->getId() === 'console') {
|
||||
return $dbForConsole;
|
||||
}
|
||||
|
||||
$pools = $register->get('pools');
|
||||
$database = $pools
|
||||
->get($project->getAttribute('database'))
|
||||
->pop()
|
||||
->getResource()
|
||||
;
|
||||
|
||||
$adapter = new Database($database, $cache);
|
||||
$adapter->setNamespace('_' . $project->getInternalId());
|
||||
return $adapter;
|
||||
}, ['cache', 'register', 'message', 'dbForConsole']);
|
||||
|
||||
Server::setResource('project', function (Message $message, Database $dbForConsole) {
|
||||
$payload = $message->getPayload() ?? [];
|
||||
$project = new Document($payload['project'] ?? []);
|
||||
|
@ -81,10 +62,26 @@ Server::setResource('project', function (Message $message, Database $dbForConsol
|
|||
if ($project->getId() === 'console') {
|
||||
return $project;
|
||||
}
|
||||
|
||||
return $dbForConsole->getDocument('projects', $project->getId());
|
||||
;
|
||||
}, ['message', 'dbForConsole']);
|
||||
|
||||
Server::setResource('dbForProject', function (Cache $cache, Registry $register, Message $message, Document $project, Database $dbForConsole) {
|
||||
if ($project->isEmpty() || $project->getId() === 'console') {
|
||||
return $dbForConsole;
|
||||
}
|
||||
|
||||
$pools = $register->get('pools');
|
||||
$database = $pools
|
||||
->get($project->getAttribute('database'))
|
||||
->pop()
|
||||
->getResource();
|
||||
|
||||
$adapter = new Database($database, $cache);
|
||||
$adapter->setNamespace('_' . $project->getInternalId());
|
||||
return $adapter;
|
||||
}, ['cache', 'register', 'message', 'project', 'dbForConsole']);
|
||||
|
||||
Server::setResource('getProjectDB', function (Group $pools, Database $dbForConsole, $cache) {
|
||||
$databases = []; // TODO: @Meldiron This should probably be responsibility of utopia-php/pools
|
||||
|
||||
|
@ -143,72 +140,92 @@ Server::setResource('cache', function (Registry $register) {
|
|||
|
||||
return new Cache(new Sharding($adapters));
|
||||
}, ['register']);
|
||||
|
||||
Server::setResource('log', fn() => new Log());
|
||||
|
||||
Server::setResource('queueForUsage', function (Connection $queue) {
|
||||
return new Usage($queue);
|
||||
}, ['queue']);
|
||||
|
||||
Server::setResource('queueForUsageDump', function (Connection $queue) {
|
||||
return new UsageDump($queue);
|
||||
}, ['queue']);
|
||||
|
||||
Server::setResource('queue', function (Group $pools) {
|
||||
return $pools->get('queue')->pop()->getResource();
|
||||
}, ['pools']);
|
||||
|
||||
Server::setResource('queueForDatabase', function (Connection $queue) {
|
||||
return new EventDatabase($queue);
|
||||
}, ['queue']);
|
||||
|
||||
Server::setResource('queueForMessaging', function (Connection $queue) {
|
||||
return new Messaging($queue);
|
||||
}, ['queue']);
|
||||
|
||||
Server::setResource('queueForMails', function (Connection $queue) {
|
||||
return new Mail($queue);
|
||||
}, ['queue']);
|
||||
|
||||
Server::setResource('queueForBuilds', function (Connection $queue) {
|
||||
return new Build($queue);
|
||||
}, ['queue']);
|
||||
|
||||
Server::setResource('queueForDeletes', function (Connection $queue) {
|
||||
return new Delete($queue);
|
||||
}, ['queue']);
|
||||
|
||||
Server::setResource('queueForEvents', function (Connection $queue) {
|
||||
return new Event($queue);
|
||||
}, ['queue']);
|
||||
|
||||
Server::setResource('queueForAudits', function (Connection $queue) {
|
||||
return new Audit($queue);
|
||||
}, ['queue']);
|
||||
|
||||
Server::setResource('queueForFunctions', function (Connection $queue) {
|
||||
return new Func($queue);
|
||||
}, ['queue']);
|
||||
|
||||
Server::setResource('queueForCertificates', function (Connection $queue) {
|
||||
return new Certificate($queue);
|
||||
}, ['queue']);
|
||||
|
||||
Server::setResource('queueForMigrations', function (Connection $queue) {
|
||||
return new Migration($queue);
|
||||
}, ['queue']);
|
||||
|
||||
Server::setResource('queueForHamster', function (Connection $queue) {
|
||||
return new Hamster($queue);
|
||||
}, ['queue']);
|
||||
|
||||
Server::setResource('logger', function (Registry $register) {
|
||||
return $register->get('logger');
|
||||
}, ['register']);
|
||||
|
||||
Server::setResource('pools', function (Registry $register) {
|
||||
return $register->get('pools');
|
||||
}, ['register']);
|
||||
Server::setResource('getFunctionsDevice', function () {
|
||||
return function (string $projectId) {
|
||||
return getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $projectId);
|
||||
};
|
||||
});
|
||||
Server::setResource('getFilesDevice', function () {
|
||||
return function (string $projectId) {
|
||||
return getDevice(APP_STORAGE_UPLOADS . '/app-' . $projectId);
|
||||
};
|
||||
});
|
||||
Server::setResource('getBuildsDevice', function () {
|
||||
return function (string $projectId) {
|
||||
return getDevice(APP_STORAGE_BUILDS . '/app-' . $projectId);
|
||||
};
|
||||
});
|
||||
Server::setResource('getCacheDevice', function () {
|
||||
return function (string $projectId) {
|
||||
return getDevice(APP_STORAGE_CACHE . '/app-' . $projectId);
|
||||
};
|
||||
});
|
||||
|
||||
Server::setResource('deviceForFunctions', function (Document $project) {
|
||||
return getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $project->getId());
|
||||
}, ['project']);
|
||||
|
||||
Server::setResource('deviceForFiles', function (Document $project) {
|
||||
return getDevice(APP_STORAGE_UPLOADS . '/app-' . $project->getId());
|
||||
}, ['project']);
|
||||
|
||||
Server::setResource('deviceForBuilds', function (Document $project) {
|
||||
return getDevice(APP_STORAGE_BUILDS . '/app-' . $project->getId());
|
||||
}, ['project']);
|
||||
|
||||
Server::setResource('deviceForCache', function (Document $project) {
|
||||
return getDevice(APP_STORAGE_CACHE . '/app-' . $project->getId());
|
||||
}, ['project']);
|
||||
|
||||
Server::setResource('deviceForLocalFiles', function (Document $project) {
|
||||
return new Local(APP_STORAGE_UPLOADS . '/app-' . $project->getId());
|
||||
}, ['project']);
|
||||
|
||||
$pools = $register->get('pools');
|
||||
$platform = new Appwrite();
|
||||
|
@ -303,12 +320,9 @@ $worker
|
|||
Console::error('[Error] Line: ' . $error->getLine());
|
||||
});
|
||||
|
||||
try {
|
||||
$workerStart = $worker->getWorkerStart();
|
||||
} catch (\Throwable $error) {
|
||||
$worker->workerStart();
|
||||
} finally {
|
||||
Console::info("Worker $workerName started");
|
||||
}
|
||||
$worker->workerStart()
|
||||
->action(function () use ($workerName) {
|
||||
Console::info("Worker $workerName started");
|
||||
});
|
||||
|
||||
$worker->start();
|
||||
|
|
3
bin/worker-usage-dump
Normal file
3
bin/worker-usage-dump
Normal file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
|
||||
php /usr/src/code/app/worker.php usage-dump $@
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
|
||||
"name": "appwrite/server-ce",
|
||||
"description": "End to end backend server for frontend and mobile apps.",
|
||||
"type": "project",
|
||||
|
@ -56,7 +57,7 @@
|
|||
"utopia-php/image": "0.6.*",
|
||||
"utopia-php/locale": "0.4.*",
|
||||
"utopia-php/logger": "0.3.*",
|
||||
"utopia-php/messaging": "0.9.*",
|
||||
"utopia-php/messaging": "0.10.*",
|
||||
"utopia-php/migration": "0.3.*",
|
||||
"utopia-php/orchestration": "0.9.*",
|
||||
"utopia-php/platform": "0.5.*",
|
||||
|
@ -70,7 +71,7 @@
|
|||
"utopia-php/websocket": "0.1.*",
|
||||
"matomo/device-detector": "6.1.*",
|
||||
"dragonmantank/cron-expression": "3.3.2",
|
||||
"phpmailer/phpmailer": "6.8.0",
|
||||
"phpmailer/phpmailer": "6.9.1",
|
||||
"chillerlan/php-qrcode": "4.3.4",
|
||||
"adhocore/jwt": "1.1.2",
|
||||
"spomky-labs/otphp": "^10.0",
|
||||
|
|
89
composer.lock
generated
89
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": "609062319cc652e2760367f39604ac77",
|
||||
"content-hash": "a65e4309e3fd851aec97be2cf5b83cb4",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
|
@ -885,16 +885,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpmailer/phpmailer",
|
||||
"version": "v6.8.0",
|
||||
"version": "v6.9.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHPMailer/PHPMailer.git",
|
||||
"reference": "df16b615e371d81fb79e506277faea67a1be18f1"
|
||||
"reference": "039de174cd9c17a8389754d3b877a2ed22743e18"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/df16b615e371d81fb79e506277faea67a1be18f1",
|
||||
"reference": "df16b615e371d81fb79e506277faea67a1be18f1",
|
||||
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/039de174cd9c17a8389754d3b877a2ed22743e18",
|
||||
"reference": "039de174cd9c17a8389754d3b877a2ed22743e18",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -904,16 +904,17 @@
|
|||
"php": ">=5.5.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.2",
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^1.0",
|
||||
"doctrine/annotations": "^1.2.6 || ^1.13.3",
|
||||
"php-parallel-lint/php-console-highlighter": "^1.0.0",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.3.2",
|
||||
"phpcompatibility/php-compatibility": "^9.3.5",
|
||||
"roave/security-advisories": "dev-latest",
|
||||
"squizlabs/php_codesniffer": "^3.7.1",
|
||||
"squizlabs/php_codesniffer": "^3.7.2",
|
||||
"yoast/phpunit-polyfills": "^1.0.4"
|
||||
},
|
||||
"suggest": {
|
||||
"decomplexity/SendOauth2": "Adapter for using XOAUTH2 authentication",
|
||||
"ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
|
||||
"ext-openssl": "Needed for secure SMTP sending and DKIM signing",
|
||||
"greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication",
|
||||
|
@ -953,7 +954,7 @@
|
|||
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
|
||||
"support": {
|
||||
"issues": "https://github.com/PHPMailer/PHPMailer/issues",
|
||||
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.8.0"
|
||||
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.9.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -961,7 +962,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-03-06T14:43:22+00:00"
|
||||
"time": "2023-11-25T22:23:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spomky-labs/otphp",
|
||||
|
@ -1551,16 +1552,16 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/database",
|
||||
"version": "0.48.2",
|
||||
"version": "0.48.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/database.git",
|
||||
"reference": "0a231a2874fdbc0cf2ae2170b3f132fdee0ddfd4"
|
||||
"reference": "c7dd97d92f52a0aec9951e0b02309a100f3f24a9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/0a231a2874fdbc0cf2ae2170b3f132fdee0ddfd4",
|
||||
"reference": "0a231a2874fdbc0cf2ae2170b3f132fdee0ddfd4",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/c7dd97d92f52a0aec9951e0b02309a100f3f24a9",
|
||||
"reference": "c7dd97d92f52a0aec9951e0b02309a100f3f24a9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1568,7 +1569,7 @@
|
|||
"ext-pdo": "*",
|
||||
"php": ">=8.0",
|
||||
"utopia-php/cache": "0.9.*",
|
||||
"utopia-php/framework": "0.*.*",
|
||||
"utopia-php/framework": "0.33.*",
|
||||
"utopia-php/mongo": "0.3.*"
|
||||
},
|
||||
"require-dev": {
|
||||
|
@ -1601,9 +1602,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/database/issues",
|
||||
"source": "https://github.com/utopia-php/database/tree/0.48.2"
|
||||
"source": "https://github.com/utopia-php/database/tree/0.48.3"
|
||||
},
|
||||
"time": "2024-02-02T14:10:14+00:00"
|
||||
"time": "2024-02-21T08:32:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/domains",
|
||||
|
@ -1911,28 +1912,28 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/messaging",
|
||||
"version": "0.9.1",
|
||||
"version": "0.10.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/messaging.git",
|
||||
"reference": "7beec07684e9e1dfcf4ab5b1ba731fa396dccbdf"
|
||||
"reference": "71dce00ad43eb278a877cb2c329f7b8d677adfeb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/messaging/zipball/7beec07684e9e1dfcf4ab5b1ba731fa396dccbdf",
|
||||
"reference": "7beec07684e9e1dfcf4ab5b1ba731fa396dccbdf",
|
||||
"url": "https://api.github.com/repos/utopia-php/messaging/zipball/71dce00ad43eb278a877cb2c329f7b8d677adfeb",
|
||||
"reference": "71dce00ad43eb278a877cb2c329f7b8d677adfeb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-curl": "*",
|
||||
"ext-openssl": "*",
|
||||
"php": ">=8.0.0"
|
||||
"php": ">=8.0.0",
|
||||
"phpmailer/phpmailer": "6.9.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.13.*",
|
||||
"phpmailer/phpmailer": "6.8.*",
|
||||
"phpstan/phpstan": "1.10.*",
|
||||
"phpunit/phpunit": "9.6.10"
|
||||
"laravel/pint": "1.13.11",
|
||||
"phpstan/phpstan": "1.10.58",
|
||||
"phpunit/phpunit": "10.5.10"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
@ -1955,9 +1956,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/messaging/issues",
|
||||
"source": "https://github.com/utopia-php/messaging/tree/0.9.1"
|
||||
"source": "https://github.com/utopia-php/messaging/tree/0.10.0"
|
||||
},
|
||||
"time": "2024-02-15T03:44:44+00:00"
|
||||
"time": "2024-02-20T07:30:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/migration",
|
||||
|
@ -2779,16 +2780,16 @@
|
|||
"packages-dev": [
|
||||
{
|
||||
"name": "appwrite/sdk-generator",
|
||||
"version": "0.36.3",
|
||||
"version": "0.36.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appwrite/sdk-generator.git",
|
||||
"reference": "8d308f7f492545da3e51ea5b91c0778392c40b93"
|
||||
"reference": "8d932098009d62d37dda73cfe4ebc11f83e21405"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/8d308f7f492545da3e51ea5b91c0778392c40b93",
|
||||
"reference": "8d308f7f492545da3e51ea5b91c0778392c40b93",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/8d932098009d62d37dda73cfe4ebc11f83e21405",
|
||||
"reference": "8d932098009d62d37dda73cfe4ebc11f83e21405",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2824,9 +2825,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.3"
|
||||
"source": "https://github.com/appwrite/sdk-generator/tree/0.36.4"
|
||||
},
|
||||
"time": "2024-02-14T06:33:38+00:00"
|
||||
"time": "2024-02-20T16:36:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/deprecations",
|
||||
|
@ -3409,16 +3410,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": {
|
||||
|
@ -3461,9 +3462,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",
|
||||
|
@ -5019,16 +5020,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": {
|
||||
|
@ -5095,7 +5096,7 @@
|
|||
"type": "open_collective"
|
||||
}
|
||||
],
|
||||
"time": "2024-01-11T20:47:48+00:00"
|
||||
"time": "2024-02-16T15:06:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "swoole/ide-helper",
|
||||
|
|
|
@ -582,7 +582,6 @@ services:
|
|||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_SMS_PROJECTS_DENY_LIST
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
|
@ -592,6 +591,7 @@ services:
|
|||
- _APP_LOGGING_CONFIG
|
||||
- _APP_SMS_FROM
|
||||
- _APP_SMS_PROVIDER
|
||||
- _APP_SMS_PROJECTS_DENY_LIST
|
||||
|
||||
appwrite-worker-migrations:
|
||||
entrypoint: worker-migrations
|
||||
|
@ -696,6 +696,37 @@ services:
|
|||
- _APP_LOGGING_CONFIG
|
||||
- _APP_USAGE_AGGREGATION_INTERVAL
|
||||
|
||||
appwrite-worker-usage-dump:
|
||||
entrypoint: worker-usage-dump
|
||||
<<: *x-logging
|
||||
container_name: appwrite-worker-usage-dump
|
||||
image: appwrite-dev
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_USAGE_STATS
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_USAGE_AGGREGATION_INTERVAL
|
||||
|
||||
appwrite-scheduler-functions:
|
||||
entrypoint: schedule-functions
|
||||
<<: *x-logging
|
||||
|
@ -941,6 +972,7 @@ services:
|
|||
# - appwrite
|
||||
# volumes:
|
||||
# - appwrite-uploads:/storage/uploads
|
||||
|
||||
# Dev Tools Start ------------------------------------------------------------------------------------------
|
||||
#
|
||||
# The Appwrite Team uses the following tools to help debug, monitor and diagnose the Appwrite stack
|
||||
|
@ -949,8 +981,9 @@ services:
|
|||
#
|
||||
# MailCatcher - An SMTP server. Catches all system emails and displays them in a nice UI.
|
||||
# RequestCatcher - An HTTP server. Catches all system https calls and displays them using a simple HTTP API. Used to debug & tests webhooks and HTTP tasks
|
||||
# RedisCommander - A nice UI for exploring Redis data
|
||||
# Webgrind - A nice UI for exploring and debugging code-level stuff
|
||||
# Redis Insight - A nice UI for exploring Redis data
|
||||
# Adminer - A nice UI for exploring MariaDB data
|
||||
# GraphQl Explorer - A nice UI for exploring GraphQL API
|
||||
|
||||
maildev: # used mainly for dev tests
|
||||
image: appwrite/mailcatcher:1.0.0
|
||||
|
@ -980,21 +1013,15 @@ services:
|
|||
networks:
|
||||
- appwrite
|
||||
|
||||
# redis-commander:
|
||||
# image: rediscommander/redis-commander:latest
|
||||
# restart: unless-stopped
|
||||
# networks:
|
||||
# - appwrite
|
||||
# environment:
|
||||
# - REDIS_HOSTS=redis
|
||||
# ports:
|
||||
# - "8081:8081"
|
||||
# webgrind:
|
||||
# image: 'jokkedk/webgrind:latest'
|
||||
# volumes:
|
||||
# - './debug:/tmp'
|
||||
# ports:
|
||||
# - '3001:80'
|
||||
redis-insight:
|
||||
image: redis/redisinsight:latest
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
environment:
|
||||
- REDIS_HOSTS=redis
|
||||
ports:
|
||||
- "8081:5540"
|
||||
|
||||
graphql-explorer:
|
||||
container_name: appwrite-graphql-explorer
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ account = Account.new(client)
|
|||
|
||||
response = account.create_phone_verification()
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ account = Account.new(client)
|
|||
|
||||
response = account.create_recovery(email: 'email@example.com', url: 'https://example.com')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ account = Account.new(client)
|
|||
|
||||
response = account.create_verification(url: 'https://example.com')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ account = Account.new(client)
|
|||
|
||||
response = account.delete_identity(identity_id: '[IDENTITY_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ account = Account.new(client)
|
|||
|
||||
response = account.delete_session(session_id: '[SESSION_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ account = Account.new(client)
|
|||
|
||||
response = account.delete_sessions()
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ account = Account.new(client)
|
|||
|
||||
response = account.get_prefs()
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ account = Account.new(client)
|
|||
|
||||
response = account.get_session(session_id: '[SESSION_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ account = Account.new(client)
|
|||
|
||||
response = account.get()
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ account = Account.new(client)
|
|||
|
||||
response = account.list_identities()
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ account = Account.new(client)
|
|||
|
||||
response = account.list_logs()
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ account = Account.new(client)
|
|||
|
||||
response = account.list_sessions()
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ account = Account.new(client)
|
|||
|
||||
response = account.update_email(email: 'email@example.com', password: 'password')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ account = Account.new(client)
|
|||
|
||||
response = account.update_name(name: '[NAME]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ account = Account.new(client)
|
|||
|
||||
response = account.update_password(password: '')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ account = Account.new(client)
|
|||
|
||||
response = account.update_phone_verification(user_id: '[USER_ID]', secret: '[SECRET]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ account = Account.new(client)
|
|||
|
||||
response = account.update_phone(phone: '+12065550100', password: 'password')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ account = Account.new(client)
|
|||
|
||||
response = account.update_prefs(prefs: {})
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ account = Account.new(client)
|
|||
|
||||
response = account.update_recovery(user_id: '[USER_ID]', secret: '[SECRET]', password: 'password', password_again: 'password')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ account = Account.new(client)
|
|||
|
||||
response = account.update_session(session_id: '[SESSION_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ account = Account.new(client)
|
|||
|
||||
response = account.update_status()
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ account = Account.new(client)
|
|||
|
||||
response = account.update_verification(user_id: '[USER_ID]', secret: '[SECRET]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ avatars = Avatars.new(client)
|
|||
|
||||
response = avatars.get_browser(code: 'aa')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ avatars = Avatars.new(client)
|
|||
|
||||
response = avatars.get_credit_card(code: 'amex')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ avatars = Avatars.new(client)
|
|||
|
||||
response = avatars.get_favicon(url: 'https://example.com')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ avatars = Avatars.new(client)
|
|||
|
||||
response = avatars.get_flag(code: 'af')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ avatars = Avatars.new(client)
|
|||
|
||||
response = avatars.get_image(url: 'https://example.com')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ avatars = Avatars.new(client)
|
|||
|
||||
response = avatars.get_initials()
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ avatars = Avatars.new(client)
|
|||
|
||||
response = avatars.get_qr(text: '[TEXT]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.create_boolean_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false)
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.create_collection(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', name: '[NAME]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.create_datetime_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false)
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.create_document(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', document_id: '[DOCUMENT_ID]', data: {})
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.create_email_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false)
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.create_enum_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', elements: [], required: false)
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.create_float_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false)
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.create_index(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', type: 'key', attributes: [])
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.create_integer_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false)
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.create_ip_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false)
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.create_relationship_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', related_collection_id: '[RELATED_COLLECTION_ID]', type: 'oneToOne')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.create_string_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', size: 1, required: false)
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.create_url_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false)
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.create(database_id: '[DATABASE_ID]', name: '[NAME]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.delete_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.delete_collection(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.delete_document(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', document_id: '[DOCUMENT_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.delete_index(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.delete(database_id: '[DATABASE_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.get_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.get_collection(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.get_document(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', document_id: '[DOCUMENT_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.get_index(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.get(database_id: '[DATABASE_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.list_attributes(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.list_collections(database_id: '[DATABASE_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.list_documents(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.list_indexes(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.list()
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.update_boolean_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false, default: false)
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.update_collection(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', name: '[NAME]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.update_datetime_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false, default: '')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.update_document(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', document_id: '[DOCUMENT_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.update_email_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false, default: 'email@example.com')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.update_enum_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', elements: [], required: false, default: '[DEFAULT]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.update_float_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false, min: null, max: null, default: null)
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.update_integer_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false, min: null, max: null, default: null)
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.update_ip_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false, default: '')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.update_relationship_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.update_string_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false, default: '[DEFAULT]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.update_url_attribute(database_id: '[DATABASE_ID]', collection_id: '[COLLECTION_ID]', key: '', required: false, default: 'https://example.com')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ databases = Databases.new(client)
|
|||
|
||||
response = databases.update(database_id: '[DATABASE_ID]', name: '[NAME]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ functions = Functions.new(client)
|
|||
|
||||
response = functions.create_build(function_id: '[FUNCTION_ID]', deployment_id: '[DEPLOYMENT_ID]', build_id: '[BUILD_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ functions = Functions.new(client)
|
|||
|
||||
response = functions.create_deployment(function_id: '[FUNCTION_ID]', code: InputFile.from_path('dir/file.png'), activate: false)
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ functions = Functions.new(client)
|
|||
|
||||
response = functions.create_execution(function_id: '[FUNCTION_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ functions = Functions.new(client)
|
|||
|
||||
response = functions.create_variable(function_id: '[FUNCTION_ID]', key: '[KEY]', value: '[VALUE]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ functions = Functions.new(client)
|
|||
|
||||
response = functions.create(function_id: '[FUNCTION_ID]', name: '[NAME]', runtime: 'node-18.0')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ functions = Functions.new(client)
|
|||
|
||||
response = functions.delete_deployment(function_id: '[FUNCTION_ID]', deployment_id: '[DEPLOYMENT_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'Appwrite'
|
||||
require 'appwrite'
|
||||
|
||||
include Appwrite
|
||||
|
||||
|
@ -11,4 +11,4 @@ functions = Functions.new(client)
|
|||
|
||||
response = functions.delete_variable(function_id: '[FUNCTION_ID]', variable_id: '[VARIABLE_ID]')
|
||||
|
||||
puts response.inspect
|
||||
puts response.inspect
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue