Merge branch '1.5.x' of github.com:appwrite/appwrite into db-project-by-region
# Conflicts: # app/controllers/general.php # src/Appwrite/Platform/Tasks/Migrate.php
This commit is contained in:
commit
5276024077
11 changed files with 166 additions and 106 deletions
2
.gitmodules
vendored
2
.gitmodules
vendored
|
@ -1,4 +1,4 @@
|
||||||
[submodule "app/console"]
|
[submodule "app/console"]
|
||||||
path = app/console
|
path = app/console
|
||||||
url = https://github.com/appwrite/console
|
url = https://github.com/appwrite/console
|
||||||
branch = 4.3.23
|
branch = 4.3.27
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 112fccf5a044c9795b31b264f5974224a3545a17
|
Subproject commit e0828010f4c222bb99cf65ddfed288e60602666f
|
|
@ -669,6 +669,7 @@ App::post('/v1/teams/:teamId/memberships')
|
||||||
}
|
}
|
||||||
|
|
||||||
$queueForEvents
|
$queueForEvents
|
||||||
|
->setParam('userId', $invitee->getId())
|
||||||
->setParam('teamId', $team->getId())
|
->setParam('teamId', $team->getId())
|
||||||
->setParam('membershipId', $membership->getId())
|
->setParam('membershipId', $membership->getId())
|
||||||
;
|
;
|
||||||
|
@ -902,6 +903,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId')
|
||||||
$dbForProject->purgeCachedDocument('users', $profile->getId());
|
$dbForProject->purgeCachedDocument('users', $profile->getId());
|
||||||
|
|
||||||
$queueForEvents
|
$queueForEvents
|
||||||
|
->setParam('userId', $profile->getId())
|
||||||
->setParam('teamId', $team->getId())
|
->setParam('teamId', $team->getId())
|
||||||
->setParam('membershipId', $membership->getId());
|
->setParam('membershipId', $membership->getId());
|
||||||
|
|
||||||
|
@ -1027,6 +1029,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
||||||
Authorization::skip(fn () => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1));
|
Authorization::skip(fn () => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1));
|
||||||
|
|
||||||
$queueForEvents
|
$queueForEvents
|
||||||
|
->setParam('userId', $user->getId())
|
||||||
->setParam('teamId', $team->getId())
|
->setParam('teamId', $team->getId())
|
||||||
->setParam('membershipId', $membership->getId())
|
->setParam('membershipId', $membership->getId())
|
||||||
;
|
;
|
||||||
|
@ -1108,6 +1111,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId')
|
||||||
}
|
}
|
||||||
|
|
||||||
$queueForEvents
|
$queueForEvents
|
||||||
|
->setParam('userId', $user->getId())
|
||||||
->setParam('teamId', $team->getId())
|
->setParam('teamId', $team->getId())
|
||||||
->setParam('membershipId', $membership->getId())
|
->setParam('membershipId', $membership->getId())
|
||||||
->setPayload($response->output($membership, Response::MODEL_MEMBERSHIP))
|
->setPayload($response->output($membership, Response::MODEL_MEMBERSHIP))
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
require_once __DIR__.'/../init.php';
|
require_once __DIR__ . '/../init.php';
|
||||||
|
|
||||||
use Appwrite\Auth\Auth;
|
use Appwrite\Auth\Auth;
|
||||||
use Appwrite\Event\Certificate;
|
use Appwrite\Event\Certificate;
|
||||||
|
@ -42,14 +42,14 @@ Config::setParam('cookieSamesite', Response::COOKIE_SAMESITE_NONE);
|
||||||
|
|
||||||
function router(App $utopia, Database $dbForConsole, callable $getProjectDB, SwooleRequest $swooleRequest, Request $request, Response $response, Event $queueForEvents, Usage $queueForUsage, Reader $geodb)
|
function router(App $utopia, Database $dbForConsole, callable $getProjectDB, SwooleRequest $swooleRequest, Request $request, Response $response, Event $queueForEvents, Usage $queueForUsage, Reader $geodb)
|
||||||
{
|
{
|
||||||
$utopia->getRoute()?->label('error', __DIR__.'/../views/general/error.phtml');
|
$utopia->getRoute()?->label('error', __DIR__ . '/../views/general/error.phtml');
|
||||||
|
|
||||||
$host = $request->getHostname() ?? '';
|
$host = $request->getHostname() ?? '';
|
||||||
|
|
||||||
$route = Authorization::skip(
|
$route = Authorization::skip(
|
||||||
fn () => $dbForConsole->find('rules', [
|
fn () => $dbForConsole->find('rules', [
|
||||||
Query::equal('domain', [$host]),
|
Query::equal('domain', [$host]),
|
||||||
Query::limit(1),
|
Query::limit(1)
|
||||||
])
|
])
|
||||||
)[0] ?? null;
|
)[0] ?? null;
|
||||||
|
|
||||||
|
@ -70,7 +70,6 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo
|
||||||
|
|
||||||
// Act as API - no Proxy logic
|
// Act as API - no Proxy logic
|
||||||
$utopia->getRoute()?->label('error', '');
|
$utopia->getRoute()?->label('error', '');
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +79,7 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo
|
||||||
);
|
);
|
||||||
if (array_key_exists('proxy', $project->getAttribute('services', []))) {
|
if (array_key_exists('proxy', $project->getAttribute('services', []))) {
|
||||||
$status = $project->getAttribute('services', [])['proxy'];
|
$status = $project->getAttribute('services', [])['proxy'];
|
||||||
if (! $status) {
|
if (!$status) {
|
||||||
throw new AppwriteException(AppwriteException::GENERAL_SERVICE_DISABLED);
|
throw new AppwriteException(AppwriteException::GENERAL_SERVICE_DISABLED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,7 +99,7 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo
|
||||||
throw new AppwriteException(AppwriteException::GENERAL_PROTOCOL_UNSUPPORTED, 'Method unsupported over HTTP. Please use HTTPS instead.');
|
throw new AppwriteException(AppwriteException::GENERAL_PROTOCOL_UNSUPPORTED, 'Method unsupported over HTTP. Please use HTTPS instead.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $response->redirect('https://'.$request->getHostname().$request->getURI());
|
return $response->redirect('https://' . $request->getHostname() . $request->getURI());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,10 +108,11 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo
|
||||||
|
|
||||||
$path = ($swooleRequest->server['request_uri'] ?? '/');
|
$path = ($swooleRequest->server['request_uri'] ?? '/');
|
||||||
$query = ($swooleRequest->server['query_string'] ?? '');
|
$query = ($swooleRequest->server['query_string'] ?? '');
|
||||||
if (! empty($query)) {
|
if (!empty($query)) {
|
||||||
$path .= '?'.$query;
|
$path .= '?' . $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$body = $swooleRequest->getContent() ?? '';
|
$body = $swooleRequest->getContent() ?? '';
|
||||||
$method = $swooleRequest->server['request_method'];
|
$method = $swooleRequest->server['request_method'];
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo
|
||||||
|
|
||||||
$function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId));
|
$function = Authorization::skip(fn () => $dbForProject->getDocument('functions', $functionId));
|
||||||
|
|
||||||
if ($function->isEmpty() || ! $function->getAttribute('enabled')) {
|
if ($function->isEmpty() || !$function->getAttribute('enabled')) {
|
||||||
throw new AppwriteException(AppwriteException::FUNCTION_NOT_FOUND);
|
throw new AppwriteException(AppwriteException::FUNCTION_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo
|
||||||
$runtime = (isset($runtimes[$function->getAttribute('runtime', '')])) ? $runtimes[$function->getAttribute('runtime', '')] : null;
|
$runtime = (isset($runtimes[$function->getAttribute('runtime', '')])) ? $runtimes[$function->getAttribute('runtime', '')] : null;
|
||||||
|
|
||||||
if (\is_null($runtime)) {
|
if (\is_null($runtime)) {
|
||||||
throw new AppwriteException(AppwriteException::FUNCTION_RUNTIME_UNSUPPORTED, 'Runtime "'.$function->getAttribute('runtime', '').'" is not supported');
|
throw new AppwriteException(AppwriteException::FUNCTION_RUNTIME_UNSUPPORTED, 'Runtime "' . $function->getAttribute('runtime', '') . '" is not supported');
|
||||||
}
|
}
|
||||||
|
|
||||||
$deployment = Authorization::skip(fn () => $dbForProject->getDocument('deployments', $function->getAttribute('deployment', '')));
|
$deployment = Authorization::skip(fn () => $dbForProject->getDocument('deployments', $function->getAttribute('deployment', '')));
|
||||||
|
@ -159,7 +159,7 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo
|
||||||
|
|
||||||
$permissions = $function->getAttribute('execute');
|
$permissions = $function->getAttribute('execute');
|
||||||
|
|
||||||
if (! (\in_array('any', $permissions)) && ! (\in_array('guests', $permissions))) {
|
if (!(\in_array('any', $permissions)) && !(\in_array('guests', $permissions))) {
|
||||||
throw new AppwriteException(AppwriteException::USER_UNAUTHORIZED, 'To execute function using domain, execute permissions must include "any" or "guests"');
|
throw new AppwriteException(AppwriteException::USER_UNAUTHORIZED, 'To execute function using domain, execute permissions must include "any" or "guests"');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,7 +172,7 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo
|
||||||
$headers['x-appwrite-continent-eu'] = 'false';
|
$headers['x-appwrite-continent-eu'] = 'false';
|
||||||
|
|
||||||
$ip = $headers['x-real-ip'] ?? '';
|
$ip = $headers['x-real-ip'] ?? '';
|
||||||
if (! empty($ip)) {
|
if (!empty($ip)) {
|
||||||
$record = $geodb->get($ip);
|
$record = $geodb->get($ip);
|
||||||
|
|
||||||
if ($record) {
|
if ($record) {
|
||||||
|
@ -228,7 +228,7 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo
|
||||||
'APPWRITE_FUNCTION_TRIGGER' => $headers['x-appwrite-trigger'] ?? '',
|
'APPWRITE_FUNCTION_TRIGGER' => $headers['x-appwrite-trigger'] ?? '',
|
||||||
'APPWRITE_FUNCTION_DATA' => $body ?? '',
|
'APPWRITE_FUNCTION_DATA' => $body ?? '',
|
||||||
'APPWRITE_FUNCTION_USER_ID' => $headers['x-appwrite-user-id'] ?? '',
|
'APPWRITE_FUNCTION_USER_ID' => $headers['x-appwrite-user-id'] ?? '',
|
||||||
'APPWRITE_FUNCTION_JWT' => $headers['x-appwrite-user-jwt'] ?? '',
|
'APPWRITE_FUNCTION_JWT' => $headers['x-appwrite-user-jwt'] ?? ''
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,7 +257,7 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo
|
||||||
try {
|
try {
|
||||||
$version = $function->getAttribute('version', 'v2');
|
$version = $function->getAttribute('version', 'v2');
|
||||||
$command = $runtime['startCommand'];
|
$command = $runtime['startCommand'];
|
||||||
$command = $version === 'v2' ? '' : 'cp /tmp/code.tar.gz /mnt/code/code.tar.gz && nohup helpers/start.sh "'.$command.'"';
|
$command = $version === 'v2' ? '' : 'cp /tmp/code.tar.gz /mnt/code/code.tar.gz && nohup helpers/start.sh "' . $command . '"';
|
||||||
$executionResponse = $executor->createExecution(
|
$executionResponse = $executor->createExecution(
|
||||||
projectId: $project->getId(),
|
projectId: $project->getId(),
|
||||||
deploymentId: $deployment->getId(),
|
deploymentId: $deployment->getId(),
|
||||||
|
@ -298,7 +298,7 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo
|
||||||
->setAttribute('duration', $durationEnd - $durationStart)
|
->setAttribute('duration', $durationEnd - $durationStart)
|
||||||
->setAttribute('status', 'failed')
|
->setAttribute('status', 'failed')
|
||||||
->setAttribute('responseStatusCode', 500)
|
->setAttribute('responseStatusCode', 500)
|
||||||
->setAttribute('errors', $th->getMessage().'\nError Code: '.$th->getCode());
|
->setAttribute('errors', $th->getMessage() . '\nError Code: ' . $th->getCode());
|
||||||
Console::error($th->getMessage());
|
Console::error($th->getMessage());
|
||||||
|
|
||||||
if ($th instanceof AppwriteException) {
|
if ($th instanceof AppwriteException) {
|
||||||
|
@ -308,10 +308,13 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo
|
||||||
$queueForUsage
|
$queueForUsage
|
||||||
->addMetric(METRIC_EXECUTIONS, 1)
|
->addMetric(METRIC_EXECUTIONS, 1)
|
||||||
->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS), 1)
|
->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS), 1)
|
||||||
->addMetric(METRIC_EXECUTIONS_COMPUTE, (int) ($execution->getAttribute('duration') * 1000)) // per project
|
->addMetric(METRIC_EXECUTIONS_COMPUTE, (int)($execution->getAttribute('duration') * 1000)) // per project
|
||||||
->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE), (int) ($execution->getAttribute('duration') * 1000)) // per function
|
->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_COMPUTE), (int)($execution->getAttribute('duration') * 1000)) // per function
|
||||||
->addMetric(METRIC_EXECUTIONS_MB_SECONDS, (int) (512 * $execution->getAttribute('duration', 0)))
|
->addMetric(METRIC_EXECUTIONS_MB_SECONDS, (int)(512 * $execution->getAttribute('duration', 0)))
|
||||||
->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_MB_SECONDS), (int) (512 * $execution->getAttribute('duration', 0)));
|
->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_MB_SECONDS), (int)(512 * $execution->getAttribute('duration', 0)))
|
||||||
|
->setProject($project)
|
||||||
|
->trigger()
|
||||||
|
;
|
||||||
|
|
||||||
if ($function->getAttribute('logging')) {
|
if ($function->getAttribute('logging')) {
|
||||||
/** @var Document $execution */
|
/** @var Document $execution */
|
||||||
|
@ -356,14 +359,12 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo
|
||||||
return true;
|
return true;
|
||||||
} elseif ($type === 'api') {
|
} elseif ($type === 'api') {
|
||||||
$utopia->getRoute()?->label('error', '');
|
$utopia->getRoute()?->label('error', '');
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
throw new AppwriteException(AppwriteException::GENERAL_SERVER_ERROR, 'Unknown resource type '.$type);
|
throw new AppwriteException(AppwriteException::GENERAL_SERVER_ERROR, 'Unknown resource type ' . $type);
|
||||||
}
|
}
|
||||||
|
|
||||||
$utopia->getRoute()?->label('error', '');
|
$utopia->getRoute()?->label('error', '');
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -446,12 +447,12 @@ App::init()
|
||||||
|
|
||||||
$domain = $request->getHostname();
|
$domain = $request->getHostname();
|
||||||
$domains = Config::getParam('domains', []);
|
$domains = Config::getParam('domains', []);
|
||||||
if (! array_key_exists($domain, $domains)) {
|
if (!array_key_exists($domain, $domains)) {
|
||||||
$domain = new Domain(! empty($domain) ? $domain : '');
|
$domain = new Domain(!empty($domain) ? $domain : '');
|
||||||
|
|
||||||
if (empty($domain->get()) || ! $domain->isKnown() || $domain->isTest()) {
|
if (empty($domain->get()) || !$domain->isKnown() || $domain->isTest()) {
|
||||||
$domains[$domain->get()] = false;
|
$domains[$domain->get()] = false;
|
||||||
Console::warning($domain->get().' is not a publicly accessible domain. Skipping SSL certificate generation.');
|
Console::warning($domain->get() . ' is not a publicly accessible domain. Skipping SSL certificate generation.');
|
||||||
} elseif (str_starts_with($request->getURI(), '/.well-known/acme-challenge')) {
|
} elseif (str_starts_with($request->getURI(), '/.well-known/acme-challenge')) {
|
||||||
Console::warning('Skipping SSL certificates generation on ACME challenge.');
|
Console::warning('Skipping SSL certificates generation on ACME challenge.');
|
||||||
} else {
|
} else {
|
||||||
|
@ -459,7 +460,7 @@ App::init()
|
||||||
|
|
||||||
$envDomain = System::getEnv('_APP_DOMAIN', '');
|
$envDomain = System::getEnv('_APP_DOMAIN', '');
|
||||||
$mainDomain = null;
|
$mainDomain = null;
|
||||||
if (! empty($envDomain) && $envDomain !== 'localhost') {
|
if (!empty($envDomain) && $envDomain !== 'localhost') {
|
||||||
$mainDomain = $envDomain;
|
$mainDomain = $envDomain;
|
||||||
} else {
|
} else {
|
||||||
$domainDocument = $dbForConsole->findOne('rules', [Query::orderAsc('$id')]);
|
$domainDocument = $dbForConsole->findOne('rules', [Query::orderAsc('$id')]);
|
||||||
|
@ -467,24 +468,24 @@ App::init()
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($mainDomain !== $domain->get()) {
|
if ($mainDomain !== $domain->get()) {
|
||||||
Console::warning($domain->get().' is not a main domain. Skipping SSL certificate generation.');
|
Console::warning($domain->get() . ' is not a main domain. Skipping SSL certificate generation.');
|
||||||
} else {
|
} else {
|
||||||
$domainDocument = $dbForConsole->findOne('rules', [
|
$domainDocument = $dbForConsole->findOne('rules', [
|
||||||
Query::equal('domain', [$domain->get()]),
|
Query::equal('domain', [$domain->get()])
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (! $domainDocument) {
|
if (!$domainDocument) {
|
||||||
$domainDocument = new Document([
|
$domainDocument = new Document([
|
||||||
'domain' => $domain->get(),
|
'domain' => $domain->get(),
|
||||||
'resourceType' => 'api',
|
'resourceType' => 'api',
|
||||||
'status' => 'verifying',
|
'status' => 'verifying',
|
||||||
'projectId' => 'console',
|
'projectId' => 'console',
|
||||||
'projectInternalId' => 'console',
|
'projectInternalId' => 'console'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$domainDocument = $dbForConsole->createDocument('rules', $domainDocument);
|
$domainDocument = $dbForConsole->createDocument('rules', $domainDocument);
|
||||||
|
|
||||||
Console::info('Issuing a TLS certificate for the main domain ('.$domain->get().') in a few seconds...');
|
Console::info('Issuing a TLS certificate for the main domain (' . $domain->get() . ') in a few seconds...');
|
||||||
|
|
||||||
$queueForCertificates
|
$queueForCertificates
|
||||||
->setDomain($domainDocument)
|
->setDomain($domainDocument)
|
||||||
|
@ -515,14 +516,14 @@ App::init()
|
||||||
$refDomainOrigin = $origin;
|
$refDomainOrigin = $origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
$refDomain = (! empty($protocol) ? $protocol : $request->getProtocol()).'://'.$refDomainOrigin.(! empty($port) ? ':'.$port : '');
|
$refDomain = (!empty($protocol) ? $protocol : $request->getProtocol()) . '://' . $refDomainOrigin . (!empty($port) ? ':' . $port : '');
|
||||||
|
|
||||||
$refDomain = (! $route->getLabel('origin', false)) // This route is publicly accessible
|
$refDomain = (!$route->getLabel('origin', false)) // This route is publicly accessible
|
||||||
? $refDomain
|
? $refDomain
|
||||||
: (! empty($protocol) ? $protocol : $request->getProtocol()).'://'.$origin.(! empty($port) ? ':'.$port : '');
|
: (!empty($protocol) ? $protocol : $request->getProtocol()) . '://' . $origin . (!empty($port) ? ':' . $port : '');
|
||||||
|
|
||||||
$selfDomain = new Domain($request->getHostname());
|
$selfDomain = new Domain($request->getHostname());
|
||||||
$endDomain = new Domain((string) $origin);
|
$endDomain = new Domain((string)$origin);
|
||||||
|
|
||||||
Config::setParam(
|
Config::setParam(
|
||||||
'domainVerification',
|
'domainVerification',
|
||||||
|
@ -530,7 +531,7 @@ App::init()
|
||||||
$endDomain->getRegisterable() !== ''
|
$endDomain->getRegisterable() !== ''
|
||||||
);
|
);
|
||||||
|
|
||||||
$isLocalHost = $request->getHostname() === 'localhost' || $request->getHostname() === 'localhost:'.$request->getPort();
|
$isLocalHost = $request->getHostname() === 'localhost' || $request->getHostname() === 'localhost:' . $request->getPort();
|
||||||
$isIpAddress = filter_var($request->getHostname(), FILTER_VALIDATE_IP) !== false;
|
$isIpAddress = filter_var($request->getHostname(), FILTER_VALIDATE_IP) !== false;
|
||||||
|
|
||||||
$isConsoleProject = $project->getAttribute('$id', '') === 'console';
|
$isConsoleProject = $project->getAttribute('$id', '') === 'console';
|
||||||
|
@ -542,8 +543,8 @@ App::init()
|
||||||
? null
|
? null
|
||||||
: (
|
: (
|
||||||
$isConsoleProject && $isConsoleRootSession
|
$isConsoleProject && $isConsoleRootSession
|
||||||
? '.'.$selfDomain->getRegisterable()
|
? '.' . $selfDomain->getRegisterable()
|
||||||
: '.'.$request->getHostname()
|
: '.' . $request->getHostname()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -559,7 +560,7 @@ App::init()
|
||||||
$response->addFilter(new ResponseV17());
|
$response->addFilter(new ResponseV17());
|
||||||
}
|
}
|
||||||
if (version_compare($responseFormat, APP_VERSION_STABLE, '>')) {
|
if (version_compare($responseFormat, APP_VERSION_STABLE, '>')) {
|
||||||
$response->addHeader('X-Appwrite-Warning', 'The current SDK is built for Appwrite '.$responseFormat.'. However, the current Appwrite server version is '.APP_VERSION_STABLE.'. Please downgrade your SDK to match the Appwrite version: https://appwrite.io/docs/sdks');
|
$response->addHeader('X-Appwrite-Warning', "The current SDK is built for Appwrite " . $responseFormat . ". However, the current Appwrite server version is ". APP_VERSION_STABLE . ". Please downgrade your SDK to match the Appwrite version: https://appwrite.io/docs/sdks");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -575,12 +576,12 @@ App::init()
|
||||||
throw new AppwriteException(AppwriteException::GENERAL_PROTOCOL_UNSUPPORTED, 'Method unsupported over HTTP. Please use HTTPS instead.');
|
throw new AppwriteException(AppwriteException::GENERAL_PROTOCOL_UNSUPPORTED, 'Method unsupported over HTTP. Please use HTTPS instead.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $response->redirect('https://'.$request->getHostname().$request->getURI());
|
return $response->redirect('https://' . $request->getHostname() . $request->getURI());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->getProtocol() === 'https') {
|
if ($request->getProtocol() === 'https') {
|
||||||
$response->addHeader('Strict-Transport-Security', 'max-age='.(60 * 60 * 24 * 126)); // 126 days
|
$response->addHeader('Strict-Transport-Security', 'max-age=' . (60 * 60 * 24 * 126)); // 126 days
|
||||||
}
|
}
|
||||||
|
|
||||||
$response
|
$response
|
||||||
|
@ -601,7 +602,7 @@ App::init()
|
||||||
$originValidator = new Origin(\array_merge($project->getAttribute('platforms', []), $console->getAttribute('platforms', [])));
|
$originValidator = new Origin(\array_merge($project->getAttribute('platforms', []), $console->getAttribute('platforms', [])));
|
||||||
|
|
||||||
if (
|
if (
|
||||||
! $originValidator->isValid($origin)
|
!$originValidator->isValid($origin)
|
||||||
&& \in_array($request->getMethod(), [Request::METHOD_POST, Request::METHOD_PUT, Request::METHOD_PATCH, Request::METHOD_DELETE])
|
&& \in_array($request->getMethod(), [Request::METHOD_POST, Request::METHOD_PUT, Request::METHOD_PATCH, Request::METHOD_DELETE])
|
||||||
&& $route->getLabel('origin', false) !== '*'
|
&& $route->getLabel('origin', false) !== '*'
|
||||||
&& empty($request->getHeader('x-appwrite-key', ''))
|
&& empty($request->getHeader('x-appwrite-key', ''))
|
||||||
|
@ -665,17 +666,17 @@ App::error()
|
||||||
$trace = $error->getTrace();
|
$trace = $error->getTrace();
|
||||||
|
|
||||||
if (php_sapi_name() === 'cli') {
|
if (php_sapi_name() === 'cli') {
|
||||||
Console::error('[Error] Timestamp: '.date('c', time()));
|
Console::error('[Error] Timestamp: ' . date('c', time()));
|
||||||
|
|
||||||
if ($route) {
|
if ($route) {
|
||||||
Console::error('[Error] Method: '.$route->getMethod());
|
Console::error('[Error] Method: ' . $route->getMethod());
|
||||||
Console::error('[Error] URL: '.$route->getPath());
|
Console::error('[Error] URL: ' . $route->getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
Console::error('[Error] Type: '.get_class($error));
|
Console::error('[Error] Type: ' . get_class($error));
|
||||||
Console::error('[Error] Message: '.$message);
|
Console::error('[Error] Message: ' . $message);
|
||||||
Console::error('[Error] File: '.$file);
|
Console::error('[Error] File: ' . $file);
|
||||||
Console::error('[Error] Line: '.$line);
|
Console::error('[Error] Line: ' . $line);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ($class) {
|
switch ($class) {
|
||||||
|
@ -730,12 +731,12 @@ App::error()
|
||||||
$providerName = System::getEnv('_APP_EXPERIMENT_LOGGING_PROVIDER', '');
|
$providerName = System::getEnv('_APP_EXPERIMENT_LOGGING_PROVIDER', '');
|
||||||
$providerConfig = System::getEnv('_APP_EXPERIMENT_LOGGING_CONFIG', '');
|
$providerConfig = System::getEnv('_APP_EXPERIMENT_LOGGING_CONFIG', '');
|
||||||
|
|
||||||
if (! (empty($providerName) || empty($providerConfig))) {
|
if (!(empty($providerName) || empty($providerConfig))) {
|
||||||
if (! Logger::hasProvider($providerName)) {
|
if (!Logger::hasProvider($providerName)) {
|
||||||
throw new Exception('Logging provider not supported. Logging is disabled');
|
throw new Exception("Logging provider not supported. Logging is disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
$classname = '\\Utopia\\Logger\\Adapter\\'.\ucfirst($providerName);
|
$classname = '\\Utopia\\Logger\\Adapter\\' . \ucfirst($providerName);
|
||||||
$adapter = new $classname($providerConfig);
|
$adapter = new $classname($providerConfig);
|
||||||
$logger = new Logger($adapter);
|
$logger = new Logger($adapter);
|
||||||
$logger->setSample(0.04);
|
$logger->setSample(0.04);
|
||||||
|
@ -744,10 +745,10 @@ App::error()
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($publish && $project->getId() !== 'console') {
|
if ($publish && $project->getId() !== 'console') {
|
||||||
if (! Auth::isPrivilegedUser(Authorization::getRoles())) {
|
if (!Auth::isPrivilegedUser(Authorization::getRoles())) {
|
||||||
$fileSize = 0;
|
$fileSize = 0;
|
||||||
$file = $request->getFiles('file');
|
$file = $request->getFiles('file');
|
||||||
if (! empty($file)) {
|
if (!empty($file)) {
|
||||||
$fileSize = (\is_array($file['size']) && isset($file['size'][0])) ? $file['size'][0] : $file['size'];
|
$fileSize = (\is_array($file['size']) && isset($file['size'][0])) ? $file['size'][0] : $file['size'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -762,6 +763,7 @@ App::error()
|
||||||
->trigger();
|
->trigger();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ($logger && $publish) {
|
if ($logger && $publish) {
|
||||||
try {
|
try {
|
||||||
/** @var Utopia\Database\Document $user */
|
/** @var Utopia\Database\Document $user */
|
||||||
|
@ -770,7 +772,7 @@ App::error()
|
||||||
// All good, user is optional information for logger
|
// All good, user is optional information for logger
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($user) && ! $user->isEmpty()) {
|
if (isset($user) && !$user->isEmpty()) {
|
||||||
$log->setUser(new User($user->getId()));
|
$log->setUser(new User($user->getId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -778,10 +780,10 @@ App::error()
|
||||||
$dsn = new DSN($project->getAttribute('database', 'console'));
|
$dsn = new DSN($project->getAttribute('database', 'console'));
|
||||||
} catch (\InvalidArgumentException) {
|
} catch (\InvalidArgumentException) {
|
||||||
// TODO: Temporary until all projects are using shared tables
|
// TODO: Temporary until all projects are using shared tables
|
||||||
$dsn = new DSN('mysql://'.$project->getAttribute('database', 'console'));
|
$dsn = new DSN('mysql://' . $project->getAttribute('database', 'console'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$log->setNamespace('http');
|
$log->setNamespace("http");
|
||||||
$log->setServer(\gethostname());
|
$log->setServer(\gethostname());
|
||||||
$log->setVersion($version);
|
$log->setVersion($version);
|
||||||
$log->setType(Log::TYPE_ERROR);
|
$log->setType(Log::TYPE_ERROR);
|
||||||
|
@ -794,25 +796,25 @@ App::error()
|
||||||
$log->addTag('code', $error->getCode());
|
$log->addTag('code', $error->getCode());
|
||||||
$log->addTag('projectId', $project->getId());
|
$log->addTag('projectId', $project->getId());
|
||||||
$log->addTag('hostname', $request->getHostname());
|
$log->addTag('hostname', $request->getHostname());
|
||||||
$log->addTag('locale', (string) $request->getParam('locale', $request->getHeader('x-appwrite-locale', '')));
|
$log->addTag('locale', (string)$request->getParam('locale', $request->getHeader('x-appwrite-locale', '')));
|
||||||
|
|
||||||
$log->addExtra('file', $error->getFile());
|
$log->addExtra('file', $error->getFile());
|
||||||
$log->addExtra('line', $error->getLine());
|
$log->addExtra('line', $error->getLine());
|
||||||
$log->addExtra('trace', $error->getTraceAsString());
|
$log->addExtra('trace', $error->getTraceAsString());
|
||||||
$log->addExtra('roles', Authorization::getRoles());
|
$log->addExtra('roles', Authorization::getRoles());
|
||||||
|
|
||||||
$action = $route->getLabel('sdk.namespace', 'UNKNOWN_NAMESPACE').'.'.$route->getLabel('sdk.method', 'UNKNOWN_METHOD');
|
$action = $route->getLabel("sdk.namespace", "UNKNOWN_NAMESPACE") . '.' . $route->getLabel("sdk.method", "UNKNOWN_METHOD");
|
||||||
$log->setAction($action);
|
$log->setAction($action);
|
||||||
|
|
||||||
$isProduction = System::getEnv('_APP_ENV', 'development') === 'production';
|
$isProduction = System::getEnv('_APP_ENV', 'development') === 'production';
|
||||||
$log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING);
|
$log->setEnvironment($isProduction ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING);
|
||||||
|
|
||||||
$responseCode = $logger->addLog($log);
|
$responseCode = $logger->addLog($log);
|
||||||
Console::info('Log pushed with status code: '.$responseCode);
|
Console::info('Log pushed with status code: ' . $responseCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Wrap all exceptions inside Appwrite\Extend\Exception */
|
/** Wrap all exceptions inside Appwrite\Extend\Exception */
|
||||||
if (! ($error instanceof AppwriteException)) {
|
if (!($error instanceof AppwriteException)) {
|
||||||
$error = new AppwriteException(AppwriteException::GENERAL_UNKNOWN, $message, $code, $error);
|
$error = new AppwriteException(AppwriteException::GENERAL_UNKNOWN, $message, $code, $error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -867,7 +869,7 @@ App::error()
|
||||||
$layout = new View($template);
|
$layout = new View($template);
|
||||||
|
|
||||||
$layout
|
$layout
|
||||||
->setParam('title', $project->getAttribute('name').' - Error')
|
->setParam('title', $project->getAttribute('name') . ' - Error')
|
||||||
->setParam('development', App::isDevelopment())
|
->setParam('development', App::isDevelopment())
|
||||||
->setParam('projectName', $project->getAttribute('name'))
|
->setParam('projectName', $project->getAttribute('name'))
|
||||||
->setParam('projectURL', $project->getAttribute('url'))
|
->setParam('projectURL', $project->getAttribute('url'))
|
||||||
|
@ -903,7 +905,7 @@ App::get('/robots.txt')
|
||||||
$mainDomain = System::getEnv('_APP_DOMAIN', '');
|
$mainDomain = System::getEnv('_APP_DOMAIN', '');
|
||||||
|
|
||||||
if ($host === $mainDomain) {
|
if ($host === $mainDomain) {
|
||||||
$template = new View(__DIR__.'/../views/general/robots.phtml');
|
$template = new View(__DIR__ . '/../views/general/robots.phtml');
|
||||||
$response->text($template->render(false));
|
$response->text($template->render(false));
|
||||||
} else {
|
} else {
|
||||||
router($utopia, $dbForConsole, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForUsage, $geodb);
|
router($utopia, $dbForConsole, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForUsage, $geodb);
|
||||||
|
@ -928,7 +930,7 @@ App::get('/humans.txt')
|
||||||
$mainDomain = System::getEnv('_APP_DOMAIN', '');
|
$mainDomain = System::getEnv('_APP_DOMAIN', '');
|
||||||
|
|
||||||
if ($host === $mainDomain) {
|
if ($host === $mainDomain) {
|
||||||
$template = new View(__DIR__.'/../views/general/humans.phtml');
|
$template = new View(__DIR__ . '/../views/general/humans.phtml');
|
||||||
$response->text($template->render(false));
|
$response->text($template->render(false));
|
||||||
} else {
|
} else {
|
||||||
router($utopia, $dbForConsole, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForUsage, $geodb);
|
router($utopia, $dbForConsole, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForUsage, $geodb);
|
||||||
|
@ -950,43 +952,43 @@ App::get('/.well-known/acme-challenge/*')
|
||||||
...Text::ALPHABET_LOWER,
|
...Text::ALPHABET_LOWER,
|
||||||
...Text::ALPHABET_UPPER,
|
...Text::ALPHABET_UPPER,
|
||||||
'-',
|
'-',
|
||||||
'_',
|
'_'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (! $validator->isValid($token) || \count($uriChunks) !== 4) {
|
if (!$validator->isValid($token) || \count($uriChunks) !== 4) {
|
||||||
throw new AppwriteException(AppwriteException::GENERAL_ARGUMENT_INVALID, 'Invalid challenge token.');
|
throw new AppwriteException(AppwriteException::GENERAL_ARGUMENT_INVALID, 'Invalid challenge token.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$base = \realpath(APP_STORAGE_CERTIFICATES);
|
$base = \realpath(APP_STORAGE_CERTIFICATES);
|
||||||
$absolute = \realpath($base.'/.well-known/acme-challenge/'.$token);
|
$absolute = \realpath($base . '/.well-known/acme-challenge/' . $token);
|
||||||
|
|
||||||
if (! $base) {
|
if (!$base) {
|
||||||
throw new AppwriteException(AppwriteException::GENERAL_SERVER_ERROR, 'Storage error');
|
throw new AppwriteException(AppwriteException::GENERAL_SERVER_ERROR, 'Storage error');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $absolute) {
|
if (!$absolute) {
|
||||||
throw new AppwriteException(AppwriteException::GENERAL_ROUTE_NOT_FOUND, 'Unknown path');
|
throw new AppwriteException(AppwriteException::GENERAL_ROUTE_NOT_FOUND, 'Unknown path');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! \substr($absolute, 0, \strlen($base)) === $base) {
|
if (!\substr($absolute, 0, \strlen($base)) === $base) {
|
||||||
throw new AppwriteException(AppwriteException::GENERAL_UNAUTHORIZED_SCOPE, 'Invalid path');
|
throw new AppwriteException(AppwriteException::GENERAL_UNAUTHORIZED_SCOPE, 'Invalid path');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! \file_exists($absolute)) {
|
if (!\file_exists($absolute)) {
|
||||||
throw new AppwriteException(AppwriteException::GENERAL_ROUTE_NOT_FOUND, 'Unknown path');
|
throw new AppwriteException(AppwriteException::GENERAL_ROUTE_NOT_FOUND, 'Unknown path');
|
||||||
}
|
}
|
||||||
|
|
||||||
$content = @\file_get_contents($absolute);
|
$content = @\file_get_contents($absolute);
|
||||||
|
|
||||||
if (! $content) {
|
if (!$content) {
|
||||||
throw new AppwriteException(AppwriteException::GENERAL_SERVER_ERROR, 'Failed to get contents');
|
throw new AppwriteException(AppwriteException::GENERAL_SERVER_ERROR, 'Failed to get contents');
|
||||||
}
|
}
|
||||||
|
|
||||||
$response->text($content);
|
$response->text($content);
|
||||||
});
|
});
|
||||||
|
|
||||||
include_once __DIR__.'/shared/api.php';
|
include_once __DIR__ . '/shared/api.php';
|
||||||
include_once __DIR__.'/shared/api/auth.php';
|
include_once __DIR__ . '/shared/api/auth.php';
|
||||||
|
|
||||||
App::wildcard()
|
App::wildcard()
|
||||||
->groups(['api'])
|
->groups(['api'])
|
||||||
|
|
|
@ -110,7 +110,7 @@ const APP_LIMIT_LIST_DEFAULT = 25; // Default maximum number of items to return
|
||||||
const APP_KEY_ACCCESS = 24 * 60 * 60; // 24 hours
|
const APP_KEY_ACCCESS = 24 * 60 * 60; // 24 hours
|
||||||
const APP_USER_ACCCESS = 24 * 60 * 60; // 24 hours
|
const APP_USER_ACCCESS = 24 * 60 * 60; // 24 hours
|
||||||
const APP_CACHE_UPDATE = 24 * 60 * 60; // 24 hours
|
const APP_CACHE_UPDATE = 24 * 60 * 60; // 24 hours
|
||||||
const APP_CACHE_BUSTER = 4323;
|
const APP_CACHE_BUSTER = 4327;
|
||||||
const APP_VERSION_STABLE = '1.5.8';
|
const APP_VERSION_STABLE = '1.5.8';
|
||||||
const APP_DATABASE_ATTRIBUTE_EMAIL = 'email';
|
const APP_DATABASE_ATTRIBUTE_EMAIL = 'email';
|
||||||
const APP_DATABASE_ATTRIBUTE_ENUM = 'enum';
|
const APP_DATABASE_ATTRIBUTE_ENUM = 'enum';
|
||||||
|
|
|
@ -380,8 +380,10 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
|
||||||
$user = $database->getDocument('users', $userId);
|
$user = $database->getDocument('users', $userId);
|
||||||
|
|
||||||
$roles = Auth::getRoles($user);
|
$roles = Auth::getRoles($user);
|
||||||
|
$channels = $realtime->connections[$connection]['channels'];
|
||||||
|
|
||||||
$realtime->subscribe($projectId, $connection, $roles, $realtime->connections[$connection]['channels']);
|
$realtime->unsubscribe($connection);
|
||||||
|
$realtime->subscribe($projectId, $connection, $roles, $channels);
|
||||||
|
|
||||||
$register->get('pools')->reclaim();
|
$register->get('pools')->reclaim();
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@
|
||||||
"utopia-php/storage": "0.18.*",
|
"utopia-php/storage": "0.18.*",
|
||||||
"utopia-php/swoole": "0.8.*",
|
"utopia-php/swoole": "0.8.*",
|
||||||
"utopia-php/system": "0.8.*",
|
"utopia-php/system": "0.8.*",
|
||||||
"utopia-php/vcs": "0.6.*",
|
"utopia-php/vcs": "0.8.*",
|
||||||
"utopia-php/websocket": "0.1.*",
|
"utopia-php/websocket": "0.1.*",
|
||||||
"matomo/device-detector": "6.1.*",
|
"matomo/device-detector": "6.1.*",
|
||||||
"dragonmantank/cron-expression": "3.3.2",
|
"dragonmantank/cron-expression": "3.3.2",
|
||||||
|
|
14
composer.lock
generated
14
composer.lock
generated
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "7a9af1063aac524865d2479ce3957d0e",
|
"content-hash": "b5c0db330bf30bd1d240b96116d96baf",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "adhocore/jwt",
|
"name": "adhocore/jwt",
|
||||||
|
@ -2758,16 +2758,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "utopia-php/vcs",
|
"name": "utopia-php/vcs",
|
||||||
"version": "0.6.7",
|
"version": "0.8.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/utopia-php/vcs.git",
|
"url": "https://github.com/utopia-php/vcs.git",
|
||||||
"reference": "8d8ff1ac68e991b95adb6f91fcde8f9bb8f24974"
|
"reference": "3084aa93d24ed1e70f01e75f4318fc0d07f12596"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/8d8ff1ac68e991b95adb6f91fcde8f9bb8f24974",
|
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/3084aa93d24ed1e70f01e75f4318fc0d07f12596",
|
||||||
"reference": "8d8ff1ac68e991b95adb6f91fcde8f9bb8f24974",
|
"reference": "3084aa93d24ed1e70f01e75f4318fc0d07f12596",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -2801,9 +2801,9 @@
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/utopia-php/vcs/issues",
|
"issues": "https://github.com/utopia-php/vcs/issues",
|
||||||
"source": "https://github.com/utopia-php/vcs/tree/0.6.7"
|
"source": "https://github.com/utopia-php/vcs/tree/0.8.1"
|
||||||
},
|
},
|
||||||
"time": "2024-06-05T17:38:29+00:00"
|
"time": "2024-07-29T20:49:09+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "utopia-php/websocket",
|
"name": "utopia-php/websocket",
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
namespace Appwrite\Platform\Tasks;
|
namespace Appwrite\Platform\Tasks;
|
||||||
|
|
||||||
use Appwrite\Migration\Migration;
|
use Appwrite\Migration\Migration;
|
||||||
|
use Redis;
|
||||||
use Utopia\App;
|
use Utopia\App;
|
||||||
use Utopia\Cache\Cache;
|
|
||||||
use Utopia\CLI\Console;
|
use Utopia\CLI\Console;
|
||||||
use Utopia\Database\Database;
|
use Utopia\Database\Database;
|
||||||
use Utopia\Database\Document;
|
use Utopia\Database\Document;
|
||||||
|
@ -12,10 +12,13 @@ use Utopia\Database\Query;
|
||||||
use Utopia\Database\Validator\Authorization;
|
use Utopia\Database\Validator\Authorization;
|
||||||
use Utopia\Platform\Action;
|
use Utopia\Platform\Action;
|
||||||
use Utopia\Registry\Registry;
|
use Utopia\Registry\Registry;
|
||||||
|
use Utopia\System\System;
|
||||||
use Utopia\Validator\Text;
|
use Utopia\Validator\Text;
|
||||||
|
|
||||||
class Migrate extends Action
|
class Migrate extends Action
|
||||||
{
|
{
|
||||||
|
protected Redis $redis;
|
||||||
|
|
||||||
public static function getName(): string
|
public static function getName(): string
|
||||||
{
|
{
|
||||||
return 'migrate';
|
return 'migrate';
|
||||||
|
@ -27,34 +30,54 @@ class Migrate extends Action
|
||||||
->desc('Migrate Appwrite to new version')
|
->desc('Migrate Appwrite to new version')
|
||||||
/** @TODO APP_VERSION_STABLE needs to be defined */
|
/** @TODO APP_VERSION_STABLE needs to be defined */
|
||||||
->param('version', APP_VERSION_STABLE, new Text(8), 'Version to migrate to.', true)
|
->param('version', APP_VERSION_STABLE, new Text(8), 'Version to migrate to.', true)
|
||||||
->inject('cache')
|
|
||||||
->inject('dbForConsole')
|
->inject('dbForConsole')
|
||||||
->inject('getProjectDB')
|
->inject('getProjectDB')
|
||||||
->inject('register')
|
->inject('register')
|
||||||
->callback(fn ($version, $cache, $dbForConsole, $getProjectDB, Registry $register) => $this->action($version, $cache, $dbForConsole, $getProjectDB, $register));
|
->callback(fn ($version, $dbForConsole, $getProjectDB, Registry $register) => $this->action($version, $dbForConsole, $getProjectDB, $register));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function clearProjectsCache(Cache $cache, Document $project)
|
private function clearProjectsCache(Document $project)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$cache->purge("cache-_{$project->getInternalId()}:*");
|
do {
|
||||||
|
$iterator = null;
|
||||||
|
$pattern = "default-cache-_{$project->getInternalId()}:*";
|
||||||
|
$keys = $this->redis->scan($iterator, $pattern, 1000);
|
||||||
|
if ($keys !== false) {
|
||||||
|
foreach ($keys as $key) {
|
||||||
|
$this->redis->del($key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while ($iterator > 0);
|
||||||
|
|
||||||
} catch (\Throwable $th) {
|
} catch (\Throwable $th) {
|
||||||
Console::error('Failed to clear project ("' . $project->getId() . '") cache with error: ' . $th->getMessage());
|
Console::error('Failed to clear project ("'.$project->getId().'") cache with error: '.$th->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function action(string $version, Cache $cache, Database $dbForConsole, callable $getProjectDB, Registry $register)
|
public function action(string $version, Database $dbForConsole, callable $getProjectDB, Registry $register)
|
||||||
{
|
{
|
||||||
Authorization::disable();
|
Authorization::disable();
|
||||||
if (!array_key_exists($version, Migration::$versions)) {
|
if (! array_key_exists($version, Migration::$versions)) {
|
||||||
Console::error("Version {$version} not found.");
|
Console::error("Version {$version} not found.");
|
||||||
Console::exit(1);
|
Console::exit(1);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->redis = new Redis();
|
||||||
|
$this->redis->connect(
|
||||||
|
System::getEnv('_APP_REDIS_HOST', null),
|
||||||
|
System::getEnv('_APP_REDIS_PORT', 6379),
|
||||||
|
3,
|
||||||
|
null,
|
||||||
|
10
|
||||||
|
);
|
||||||
|
|
||||||
$app = new App('UTC');
|
$app = new App('UTC');
|
||||||
|
|
||||||
Console::success('Starting Data Migration to version ' . $version);
|
Console::success('Starting Data Migration to version '.$version);
|
||||||
|
|
||||||
$console = $app->getResource('console');
|
$console = $app->getResource('console');
|
||||||
|
|
||||||
|
@ -74,11 +97,11 @@ class Migrate extends Action
|
||||||
$totalProjects = $dbForConsole->count('projects') + 1;
|
$totalProjects = $dbForConsole->count('projects') + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$class = 'Appwrite\\Migration\\Version\\' . Migration::$versions[$version];
|
$class = 'Appwrite\\Migration\\Version\\'.Migration::$versions[$version];
|
||||||
/** @var Migration $migration */
|
/** @var Migration $migration */
|
||||||
$migration = new $class();
|
$migration = new $class();
|
||||||
|
|
||||||
while (!empty($projects)) {
|
while (! empty($projects)) {
|
||||||
foreach ($projects as $project) {
|
foreach ($projects as $project) {
|
||||||
/**
|
/**
|
||||||
* Skip user projects with id 'console'
|
* Skip user projects with id 'console'
|
||||||
|
@ -87,7 +110,7 @@ class Migrate extends Action
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->clearProjectsCache($cache, $project);
|
$this->clearProjectsCache($project);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// TODO: Iterate through all project DBs
|
// TODO: Iterate through all project DBs
|
||||||
|
@ -99,11 +122,11 @@ class Migrate extends Action
|
||||||
->setPDO($register->get('db', true))
|
->setPDO($register->get('db', true))
|
||||||
->execute();
|
->execute();
|
||||||
} catch (\Throwable $th) {
|
} catch (\Throwable $th) {
|
||||||
Console::error('Failed to update project ("' . $project->getId() . '") version with error: ' . $th->getMessage());
|
Console::error('Failed to update project ("'.$project->getId().'") version with error: '.$th->getMessage());
|
||||||
throw $th;
|
throw $th;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->clearProjectsCache($cache, $project);
|
$this->clearProjectsCache($project);
|
||||||
}
|
}
|
||||||
|
|
||||||
$sum = \count($projects);
|
$sum = \count($projects);
|
||||||
|
@ -112,7 +135,7 @@ class Migrate extends Action
|
||||||
$offset = $offset + $limit;
|
$offset = $offset + $limit;
|
||||||
$count = $count + $sum;
|
$count = $count + $sum;
|
||||||
|
|
||||||
Console::log('Migrated ' . $count . '/' . $totalProjects . ' projects...');
|
Console::log('Migrated '.$count.'/'.$totalProjects.' projects...');
|
||||||
}
|
}
|
||||||
|
|
||||||
Console::success('Data Migration Completed');
|
Console::success('Data Migration Completed');
|
||||||
|
|
|
@ -217,7 +217,15 @@ class Builds extends Action
|
||||||
|
|
||||||
$branchName = $deployment->getAttribute('providerBranch');
|
$branchName = $deployment->getAttribute('providerBranch');
|
||||||
$commitHash = $deployment->getAttribute('providerCommitHash', '');
|
$commitHash = $deployment->getAttribute('providerCommitHash', '');
|
||||||
$gitCloneCommand = $github->generateCloneCommand($cloneOwner, $cloneRepository, $branchName, $tmpDirectory, $rootDirectory, $commitHash);
|
|
||||||
|
$cloneVersion = $branchName;
|
||||||
|
$cloneType = GitHub::CLONE_TYPE_BRANCH;
|
||||||
|
if(!empty($commitHash)) {
|
||||||
|
$cloneVersion = $commitHash;
|
||||||
|
$cloneType = GitHub::CLONE_TYPE_COMMIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gitCloneCommand = $github->generateCloneCommand($cloneOwner, $cloneRepository, $cloneVersion, $cloneType, $tmpDirectory, $rootDirectory);
|
||||||
$stdout = '';
|
$stdout = '';
|
||||||
$stderr = '';
|
$stderr = '';
|
||||||
Console::execute('mkdir -p /tmp/builds/' . \escapeshellcmd($buildId), '', $stdout, $stderr);
|
Console::execute('mkdir -p /tmp/builds/' . \escapeshellcmd($buildId), '', $stdout, $stderr);
|
||||||
|
@ -240,7 +248,13 @@ class Builds extends Action
|
||||||
if (!empty($templateRepositoryName) && !empty($templateOwnerName) && !empty($templateBranch)) {
|
if (!empty($templateRepositoryName) && !empty($templateOwnerName) && !empty($templateBranch)) {
|
||||||
// Clone template repo
|
// Clone template repo
|
||||||
$tmpTemplateDirectory = '/tmp/builds/' . \escapeshellcmd($buildId) . '/template';
|
$tmpTemplateDirectory = '/tmp/builds/' . \escapeshellcmd($buildId) . '/template';
|
||||||
$gitCloneCommandForTemplate = $github->generateCloneCommand($templateOwnerName, $templateRepositoryName, $templateBranch, $tmpTemplateDirectory, $templateRootDirectory);
|
|
||||||
|
$cloneType = GitHub::CLONE_TYPE_BRANCH;
|
||||||
|
if(\str_starts_with($templateBranch, '0.1.')) { // Temporary fix for 1.5. In future versions this only support tag names
|
||||||
|
$cloneType = GitHub::CLONE_TYPE_TAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gitCloneCommandForTemplate = $github->generateCloneCommand($templateOwnerName, $templateRepositoryName, $templateBranch, $cloneType, $tmpTemplateDirectory, $templateRootDirectory);
|
||||||
$exit = Console::execute($gitCloneCommandForTemplate, '', $stdout, $stderr);
|
$exit = Console::execute($gitCloneCommandForTemplate, '', $stdout, $stderr);
|
||||||
|
|
||||||
if ($exit !== 0) {
|
if ($exit !== 0) {
|
||||||
|
|
|
@ -8,6 +8,7 @@ use Tests\E2E\Client;
|
||||||
use Tests\E2E\Scopes\ProjectCustom;
|
use Tests\E2E\Scopes\ProjectCustom;
|
||||||
use Tests\E2E\Scopes\Scope;
|
use Tests\E2E\Scopes\Scope;
|
||||||
use Tests\E2E\Scopes\SideServer;
|
use Tests\E2E\Scopes\SideServer;
|
||||||
|
use Utopia\App;
|
||||||
use Utopia\Database\Document;
|
use Utopia\Database\Document;
|
||||||
use Utopia\Database\Helpers\ID;
|
use Utopia\Database\Helpers\ID;
|
||||||
use Utopia\Database\Query;
|
use Utopia\Database\Query;
|
||||||
|
@ -1569,6 +1570,20 @@ class FunctionsCustomServerTest extends Scope
|
||||||
$this->assertEquals(200, $response['headers']['status-code']);
|
$this->assertEquals(200, $response['headers']['status-code']);
|
||||||
$this->assertEquals($cookie, $response['body']);
|
$this->assertEquals($cookie, $response['body']);
|
||||||
|
|
||||||
|
// Await Aggregation
|
||||||
|
sleep(App::getEnv('_APP_USAGE_AGGREGATION_INTERVAL', 30));
|
||||||
|
|
||||||
|
$response = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/usage', array_merge([
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $this->getProject()['$id']
|
||||||
|
], $this->getHeaders()), [
|
||||||
|
'range' => '24h'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals(200, $response['headers']['status-code']);
|
||||||
|
$this->assertEquals(19, count($response['body']));
|
||||||
|
$this->assertEquals('24h', $response['body']['range']);
|
||||||
|
|
||||||
// Cleanup : Delete function
|
// Cleanup : Delete function
|
||||||
$response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
|
$response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, [
|
||||||
'content-type' => 'application/json',
|
'content-type' => 'application/json',
|
||||||
|
|
Loading…
Reference in a new issue