diff --git a/Dockerfile b/Dockerfile index 5d06d6c828..a264ac8795 100755 --- a/Dockerfile +++ b/Dockerfile @@ -98,24 +98,9 @@ RUN chmod +x /usr/local/bin/doctor && \ chmod +x /usr/local/bin/worker-messaging && \ chmod +x /usr/local/bin/worker-webhooks && \ chmod +x /usr/local/bin/worker-migrations && \ - chmod +x /usr/local/bin/worker-hamster && \ chmod +x /usr/local/bin/worker-usage && \ chmod +x /usr/local/bin/worker-usage-dump - -# Cloud Executabless -RUN chmod +x /usr/local/bin/hamster && \ - chmod +x /usr/local/bin/volume-sync && \ - chmod +x /usr/local/bin/patch-delete-schedule-updated-at-attribute && \ - chmod +x /usr/local/bin/patch-recreate-repositories-documents && \ - chmod +x /usr/local/bin/patch-delete-project-collections && \ - chmod +x /usr/local/bin/delete-orphaned-projects && \ - chmod +x /usr/local/bin/clear-card-cache && \ - chmod +x /usr/local/bin/calc-users-stats && \ - chmod +x /usr/local/bin/calc-tier-stats && \ - chmod +x /usr/local/bin/get-migration-stats && \ - chmod +x /usr/local/bin/create-inf-metric - # Letsencrypt Permissions RUN mkdir -p /etc/letsencrypt/live/ && chmod -Rf 755 /etc/letsencrypt/live/ diff --git a/README.md b/README.md index 62b084d320..88b4173f1d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -> Great news! Appwrite Cloud is now in public beta! Sign up at [cloud.appwrite.io](https://cloud.appwrite.io) for a hassle-free, hosted experience. Join us in the Cloud today! ☁️🎉 +> Our Appwrite Init event has concluded. You can check out all the new and upcoming features [on our Init website](https://appwrite.io/init) 🚀

diff --git a/app/cli.php b/app/cli.php index d7cc5fe414..4e1df30f9a 100644 --- a/app/cli.php +++ b/app/cli.php @@ -131,9 +131,6 @@ CLI::setResource('queue', function (Group $pools) { CLI::setResource('queueForFunctions', function (Connection $queue) { return new Func($queue); }, ['queue']); -CLI::setResource('queueForHamster', function (Connection $queue) { - return new Hamster($queue); -}, ['queue']); CLI::setResource('queueForDeletes', function (Connection $queue) { return new Delete($queue); }, ['queue']); diff --git a/app/config/errors.php b/app/config/errors.php index 1699157d8c..91698e1f78 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -639,7 +639,7 @@ return [ Exception::PROJECT_PROVIDER_UNSUPPORTED => [ 'name' => Exception::PROJECT_PROVIDER_UNSUPPORTED, 'description' => 'The chosen OAuth provider is unsupported. Please check the Create OAuth2 Session docs for the complete list of supported OAuth providers.', - 'code' => 501, + 'code' => 400, ], Exception::PROJECT_INVALID_SUCCESS_URL => [ 'name' => Exception::PROJECT_INVALID_SUCCESS_URL, diff --git a/app/controllers/api/health.php b/app/controllers/api/health.php index d9faf998e6..6a2c1b0bed 100644 --- a/app/controllers/api/health.php +++ b/app/controllers/api/health.php @@ -796,12 +796,12 @@ App::get('/v1/health/queue/failed/:name') Event::MAILS_QUEUE_NAME, Event::FUNCTIONS_QUEUE_NAME, Event::USAGE_QUEUE_NAME, + Event::USAGE_DUMP_QUEUE_NAME, Event::WEBHOOK_CLASS_NAME, Event::CERTIFICATES_QUEUE_NAME, Event::BUILDS_QUEUE_NAME, Event::MESSAGING_QUEUE_NAME, - Event::MIGRATIONS_QUEUE_NAME, - Event::HAMSTER_CLASS_NAME + Event::MIGRATIONS_QUEUE_NAME ]), 'The name of the queue') ->param('threshold', 5000, new Integer(true), 'Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.', true) ->label('sdk.description', '/docs/references/health/get-failed-queue-jobs.md') diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 9e08c3774a..0174d59d95 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -4,6 +4,7 @@ use Appwrite\Auth\Auth; use Appwrite\Event\Delete; use Appwrite\Event\Validator\Event; use Appwrite\Extend\Exception; +use Appwrite\Hooks\Hooks; use Appwrite\Network\Validator\Email; use Appwrite\Network\Validator\Origin; use Appwrite\Template\Template; @@ -75,7 +76,8 @@ App::post('/v1/projects') ->inject('dbForConsole') ->inject('cache') ->inject('pools') - ->action(function (string $projectId, string $name, string $teamId, string $region, string $description, string $logo, string $url, string $legalName, string $legalCountry, string $legalState, string $legalCity, string $legalAddress, string $legalTaxId, Response $response, Database $dbForConsole, Cache $cache, Group $pools) { + ->inject('hooks') + ->action(function (string $projectId, string $name, string $teamId, string $region, string $description, string $logo, string $url, string $legalName, string $legalCountry, string $legalState, string $legalCity, string $legalAddress, string $legalTaxId, Response $response, Database $dbForConsole, Cache $cache, Group $pools, Hooks $hooks) { $team = $dbForConsole->getDocument('teams', $teamId); @@ -217,6 +219,8 @@ App::post('/v1/projects') $dbForProject->createCollection($key, $attributes, $indexes); } + $hooks->trigger('afterProjectCreation', [ $project, $pools, $cache ]); + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($project, Response::MODEL_PROJECT); diff --git a/app/controllers/general.php b/app/controllers/general.php index 11fabe7550..01bc946add 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -167,7 +167,7 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo $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"'); } @@ -367,6 +367,18 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo return false; } +/* +App::init() + ->groups(['api']) + ->inject('project') + ->inject('mode') + ->action(function (Document $project, string $mode) { + if ($mode === APP_MODE_ADMIN && $project->getId() === 'console') { + throw new AppwriteException(AppwriteException::GENERAL_BAD_REQUEST, 'Admin mode is not allowed for console project'); + } + }); +*/ + App::init() ->groups(['api', 'web']) ->inject('utopia') @@ -630,7 +642,7 @@ App::init() : Role::users()->toString(); // Add user roles - $memberships = $user->find('teamId', $project->getAttribute('teamId'), 'memberships'); + $memberships = $user->find('teamInternalId', $project->getAttribute('teamInternalId'), 'memberships'); if ($memberships) { foreach ($memberships->getAttribute('roles', []) as $memberRole) { @@ -820,31 +832,24 @@ App::error() } break; case 'Utopia\Database\Exception\Conflict': - \var_dump('Wrapping conflict exception'); $error = new AppwriteException(AppwriteException::DOCUMENT_UPDATE_CONFLICT, previous: $error); break; case 'Utopia\Database\Exception\Timeout': - \var_dump('Wrapping timeout exception'); $error = new AppwriteException(AppwriteException::DATABASE_TIMEOUT, previous: $error); break; case 'Utopia\Database\Exception\Query': - \var_dump('Wrapping query exception'); $error = new AppwriteException(AppwriteException::GENERAL_QUERY_INVALID, $error->getMessage(), previous: $error); break; case 'Utopia\Database\Exception\Structure': - \var_dump('Wrapping structure exception'); $error = new AppwriteException(AppwriteException::DOCUMENT_INVALID_STRUCTURE, $error->getMessage(), previous: $error); break; case 'Utopia\Database\Exception\Duplicate': - \var_dump('Wrapping duplicate exception'); $error = new AppwriteException(AppwriteException::DOCUMENT_ALREADY_EXISTS); break; case 'Utopia\Database\Exception\Restricted': - \var_dump('Wrapping restricted exception'); $error = new AppwriteException(AppwriteException::DOCUMENT_DELETE_RESTRICTED); break; case 'Utopia\Database\Exception\Authorization': - \var_dump('Wrapping authorization exception'); $error = new AppwriteException(AppwriteException::USER_UNAUTHORIZED); break; } @@ -858,6 +863,7 @@ App::error() $publish = $error->getCode() === 0 || $error->getCode() >= 500; } + /* if ($error->getCode() >= 400 && $error->getCode() < 500) { // Register error logger $providerName = App::getEnv('_APP_EXPERIMENT_LOGGING_PROVIDER', ''); @@ -874,6 +880,7 @@ App::error() $publish = true; } } + */ if ($logger && $publish) { try { diff --git a/app/init.php b/app/init.php index ec7fa7163b..64d7998025 100644 --- a/app/init.php +++ b/app/init.php @@ -1266,7 +1266,9 @@ function getDevice($root): Device case Storage::DEVICE_S3: return new S3($root, $accessKey, $accessSecret, $bucket, $region, $acl); case STORAGE::DEVICE_DO_SPACES: - return new DOSpaces($root, $accessKey, $accessSecret, $bucket, $region, $acl); + $device = new DOSpaces($root, $accessKey, $accessSecret, $bucket, $region, $acl); + $device->setHttpVersion(S3::HTTP_VERSION_1_1); + return $device; case Storage::DEVICE_BACKBLAZE: return new Backblaze($root, $accessKey, $accessSecret, $bucket, $region, $acl); case Storage::DEVICE_LINODE: @@ -1295,7 +1297,9 @@ function getDevice($root): Device $doSpacesRegion = App::getEnv('_APP_STORAGE_DO_SPACES_REGION', ''); $doSpacesBucket = App::getEnv('_APP_STORAGE_DO_SPACES_BUCKET', ''); $doSpacesAcl = 'private'; - return new DOSpaces($root, $doSpacesAccessKey, $doSpacesSecretKey, $doSpacesBucket, $doSpacesRegion, $doSpacesAcl); + $device = new DOSpaces($root, $doSpacesAccessKey, $doSpacesSecretKey, $doSpacesBucket, $doSpacesRegion, $doSpacesAcl); + $device->setHttpVersion(S3::HTTP_VERSION_1_1); + return $device; case Storage::DEVICE_BACKBLAZE: $backblazeAccessKey = App::getEnv('_APP_STORAGE_BACKBLAZE_ACCESS_KEY', ''); $backblazeSecretKey = App::getEnv('_APP_STORAGE_BACKBLAZE_SECRET', ''); diff --git a/app/realtime.php b/app/realtime.php index f7fc7070a4..9c6ae850e4 100644 --- a/app/realtime.php +++ b/app/realtime.php @@ -36,74 +36,83 @@ require_once __DIR__ . '/init.php'; Runtime::enableCoroutine(SWOOLE_HOOK_ALL); -function getConsoleDB(): Database -{ - global $register; +// Allows overriding +if (!function_exists("getConsoleDB")) { + function getConsoleDB(): Database + { + global $register; - /** @var \Utopia\Pools\Group $pools */ - $pools = $register->get('pools'); + /** @var \Utopia\Pools\Group $pools */ + $pools = $register->get('pools'); - $dbAdapter = $pools - ->get('console') - ->pop() - ->getResource() - ; - - $database = new Database($dbAdapter, getCache()); - - $database - ->setNamespace('_console') - ->setMetadata('host', \gethostname()) - ->setMetadata('project', '_console'); - - return $database; -} - -function getProjectDB(Document $project): Database -{ - global $register; - - /** @var \Utopia\Pools\Group $pools */ - $pools = $register->get('pools'); - - if ($project->isEmpty() || $project->getId() === 'console') { - return getConsoleDB(); - } - - $dbAdapter = $pools - ->get($project->getAttribute('database')) - ->pop() - ->getResource() - ; - - $database = new Database($dbAdapter, getCache()); - - $database - ->setNamespace('_' . $project->getInternalId()) - ->setMetadata('host', \gethostname()) - ->setMetadata('project', $project->getId()); - - return $database; -} - -function getCache(): Cache -{ - global $register; - - $pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */ - - $list = Config::getParam('pools-cache', []); - $adapters = []; - - foreach ($list as $value) { - $adapters[] = $pools - ->get($value) + $dbAdapter = $pools + ->get('console') ->pop() ->getResource() ; - } - return new Cache(new Sharding($adapters)); + $database = new Database($dbAdapter, getCache()); + + $database + ->setNamespace('_console') + ->setMetadata('host', \gethostname()) + ->setMetadata('project', '_console'); + + return $database; + } +} + +// Allows overriding +if (!function_exists("getProjectDB")) { + function getProjectDB(Document $project): Database + { + global $register; + + /** @var \Utopia\Pools\Group $pools */ + $pools = $register->get('pools'); + + if ($project->isEmpty() || $project->getId() === 'console') { + return getConsoleDB(); + } + + $dbAdapter = $pools + ->get($project->getAttribute('database')) + ->pop() + ->getResource() + ; + + $database = new Database($dbAdapter, getCache()); + + $database + ->setNamespace('_' . $project->getInternalId()) + ->setMetadata('host', \gethostname()) + ->setMetadata('project', $project->getId()); + + return $database; + } +} + +// Allows overriding +if (!function_exists("getCache")) { + function getCache(): Cache + { + global $register; + + $pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */ + + $list = Config::getParam('pools-cache', []); + $adapters = []; + + foreach ($list as $value) { + $adapters[] = $pools + ->get($value) + ->pop() + ->getResource() + ; + } + + return new Cache(new Sharding($adapters)); + } } $realtime = new Realtime(); @@ -204,29 +213,29 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume /** * Save current connections to the Database every 5 seconds. */ - Timer::tick(5000, function () use ($register, $stats, &$statsDocument, $logError) { - $payload = []; - foreach ($stats as $projectId => $value) { - $payload[$projectId] = $stats->get($projectId, 'connectionsTotal'); - } - if (empty($payload) || empty($statsDocument)) { - return; - } + // Timer::tick(5000, function () use ($register, $stats, &$statsDocument, $logError) { + // $payload = []; + // foreach ($stats as $projectId => $value) { + // $payload[$projectId] = $stats->get($projectId, 'connectionsTotal'); + // } + // if (empty($payload) || empty($statsDocument)) { + // return; + // } - try { - $database = getConsoleDB(); + // try { + // $database = getConsoleDB(); - $statsDocument - ->setAttribute('timestamp', DateTime::now()) - ->setAttribute('value', json_encode($payload)); + // $statsDocument + // ->setAttribute('timestamp', DateTime::now()) + // ->setAttribute('value', json_encode($payload)); - Authorization::skip(fn () => $database->updateDocument('realtime', $statsDocument->getId(), $statsDocument)); - } catch (Throwable $th) { - call_user_func($logError, $th, "updateWorkerDocument"); - } finally { - $register->get('pools')->reclaim(); - } - }); + // Authorization::skip(fn () => $database->updateDocument('realtime', $statsDocument->getId(), $statsDocument)); + // } catch (Throwable $th) { + // call_user_func($logError, $th, "updateWorkerDocument"); + // } finally { + // $register->get('pools')->reclaim(); + // } + // }); }); $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, $realtime, $logError) { diff --git a/app/views/general/error.phtml b/app/views/general/error.phtml index 450dcf8973..a3715e0156 100644 --- a/app/views/general/error.phtml +++ b/app/views/general/error.phtml @@ -59,7 +59,7 @@ $title = $this->getParam('title', '') - <?php echo $this->print($title, self::FILTER_ESCAPE); ?> + <?php echo $this->print($title); ?>