From 8f5fa849962977349f438aede076244a3cca7505 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Thu, 24 Oct 2024 10:49:43 +0200 Subject: [PATCH 1/2] Add variable endpoints for sites --- app/init.php | 2 +- .../Modules/Sites/Http/Sites/DeleteSite.php | 69 ++++++++++++++ .../Sites/Http/Variables/CreateVariable.php | 91 +++++++++++++++++++ .../Sites/Http/Variables/DeleteVariable.php | 68 ++++++++++++++ .../Sites/Http/Variables/GetVariable.php | 68 ++++++++++++++ .../Sites/Http/Variables/ListVariables.php | 57 ++++++++++++ .../Sites/Http/Variables/UpdateVariable.php | 82 +++++++++++++++++ .../Platform/Modules/Sites/Services/Http.php | 12 +++ 8 files changed, 448 insertions(+), 1 deletion(-) create mode 100644 src/Appwrite/Platform/Modules/Sites/Http/Sites/DeleteSite.php create mode 100644 src/Appwrite/Platform/Modules/Sites/Http/Variables/CreateVariable.php create mode 100644 src/Appwrite/Platform/Modules/Sites/Http/Variables/DeleteVariable.php create mode 100644 src/Appwrite/Platform/Modules/Sites/Http/Variables/GetVariable.php create mode 100644 src/Appwrite/Platform/Modules/Sites/Http/Variables/ListVariables.php create mode 100644 src/Appwrite/Platform/Modules/Sites/Http/Variables/UpdateVariable.php diff --git a/app/init.php b/app/init.php index 078db328ca..1b9625175a 100644 --- a/app/init.php +++ b/app/init.php @@ -558,7 +558,7 @@ Database::addFilter( return $database ->find('variables', [ Query::equal('resourceInternalId', [$document->getInternalId()]), - Query::equal('resourceType', ['function']), + Query::equal('resourceType', ['function', 'site']), Query::limit(APP_LIMIT_SUBQUERY), ]); } diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Sites/DeleteSite.php b/src/Appwrite/Platform/Modules/Sites/Http/Sites/DeleteSite.php new file mode 100644 index 0000000000..c1ac277436 --- /dev/null +++ b/src/Appwrite/Platform/Modules/Sites/Http/Sites/DeleteSite.php @@ -0,0 +1,69 @@ +setHttpMethod(Action::HTTP_REQUEST_METHOD_DELETE) + ->setHttpPath('/v1/sites/:siteId') + ->desc('Delete site') + ->groups(['api', 'sites']) + ->label('scope', 'functions.write') // TODO: Update scope to sites.write + ->label('event', 'sites.[siteId].delete') + ->label('audits.event', 'site.delete') + ->label('audits.resource', 'site/{request.siteId}') + ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'sites') + ->label('sdk.method', 'delete') + ->label('sdk.description', '/docs/references/sites/delete-site.md') + ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) + ->label('sdk.response.model', Response::MODEL_NONE) + ->param('siteId', '', new UID(), 'Site ID.') + ->inject('response') + ->inject('dbForProject') + ->inject('queueForDeletes') + ->inject('queueForEvents') + ->callback([$this, 'action']); + } + + public function action(string $siteId, Response $response, Database $dbForProject, Delete $queueForDeletes, Event $queueForEvents) + { + $site = $dbForProject->getDocument('sites', $siteId); + + if ($site->isEmpty()) { + throw new Exception(Exception::SITE_NOT_FOUND); + } + + if (!$dbForProject->deleteDocument('sites', $site->getId())) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove site from DB'); + } + + $queueForDeletes + ->setType(DELETE_TYPE_DOCUMENT) + ->setDocument($site); + + $queueForEvents->setParam('siteId', $site->getId()); + + $response->noContent(); + } +} diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Variables/CreateVariable.php b/src/Appwrite/Platform/Modules/Sites/Http/Variables/CreateVariable.php new file mode 100644 index 0000000000..fab3a953a8 --- /dev/null +++ b/src/Appwrite/Platform/Modules/Sites/Http/Variables/CreateVariable.php @@ -0,0 +1,91 @@ +setHttpMethod(Action::HTTP_REQUEST_METHOD_POST) + ->setHttpPath('/v1/sites/:siteId/variables') + ->desc('Create variable') + ->groups(['api', 'sites']) + ->label('scope', 'functions.write') // TODO: Update scope to sites.write + ->label('audits.event', 'variable.create') + ->label('audits.resource', 'site/{request.siteId}') + ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'sites') + ->label('sdk.method', 'createVariable') + ->label('sdk.description', '/docs/references/sites/create-variable.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_VARIABLE) + ->param('siteId', '', new UID(), 'Site unique ID.', false) + ->param('key', null, new Text(Database::LENGTH_KEY), 'Variable key. Max length: ' . Database::LENGTH_KEY . ' chars.', false) + ->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', false) + ->inject('response') + ->inject('dbForProject') + ->inject('dbForConsole') + ->callback([$this, 'action']); + } + + public function action(string $siteId, string $key, string $value, Response $response, Database $dbForProject, Database $dbForConsole) + { + $site = $dbForProject->getDocument('sites', $siteId); + + if ($site->isEmpty()) { + throw new Exception(Exception::SITE_NOT_FOUND); + } + + $variableId = ID::unique(); + + $variable = new Document([ + '$id' => $variableId, + '$permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], + 'resourceInternalId' => $site->getInternalId(), + 'resourceId' => $site->getId(), + 'resourceType' => 'site', + 'key' => $key, + 'value' => $value, + 'search' => implode(' ', [$variableId, $site->getId(), $key, 'site']), + ]); + + try { + $variable = $dbForProject->createDocument('variables', $variable); + } catch (DuplicateException $th) { + throw new Exception(Exception::VARIABLE_ALREADY_EXISTS); + } + + $dbForProject->updateDocument('sites', $site->getId(), $site->setAttribute('live', false)); + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($variable, Response::MODEL_VARIABLE); + } +} diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Variables/DeleteVariable.php b/src/Appwrite/Platform/Modules/Sites/Http/Variables/DeleteVariable.php new file mode 100644 index 0000000000..45f6905763 --- /dev/null +++ b/src/Appwrite/Platform/Modules/Sites/Http/Variables/DeleteVariable.php @@ -0,0 +1,68 @@ +setHttpMethod(Action::HTTP_REQUEST_METHOD_DELETE) + ->setHttpPath('/v1/sites/:siteId/variables/:variableId') + ->desc('Delete variable') + ->groups(['api', 'sites']) + ->label('scope', 'functions.write') // TODO: Update scope to sites + ->label('audits.event', 'variable.delete') + ->label('audits.resource', 'site/{request.siteId}') + ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'sites') + ->label('sdk.method', 'deleteVariable') + ->label('sdk.description', '/docs/references/sites/delete-variable.md') + ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) + ->label('sdk.response.model', Response::MODEL_NONE) + ->param('siteId', '', new UID(), 'Site unique ID.', false) + ->param('variableId', '', new UID(), 'Variable unique ID.', false) + ->inject('response') + ->inject('dbForProject') + ->callback([$this, 'action']); + } + + public function action(string $siteId, string $variableId, Response $response, Database $dbForProject) + { + $site = $dbForProject->getDocument('sites', $siteId); + + if ($site->isEmpty()) { + throw new Exception(Exception::SITE_NOT_FOUND); + } + + $variable = $dbForProject->getDocument('variables', $variableId); + if ($variable === false || $variable->isEmpty() || $variable->getAttribute('resourceInternalId') !== $site->getInternalId() || $variable->getAttribute('resourceType') !== 'site') { + throw new Exception(Exception::VARIABLE_NOT_FOUND); + } + + if ($variable === false || $variable->isEmpty()) { + throw new Exception(Exception::VARIABLE_NOT_FOUND); + } + + $dbForProject->deleteDocument('variables', $variable->getId()); + + $dbForProject->updateDocument('sites', $site->getId(), $site->setAttribute('live', false)); + + $response->noContent(); + } +} diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Variables/GetVariable.php b/src/Appwrite/Platform/Modules/Sites/Http/Variables/GetVariable.php new file mode 100644 index 0000000000..cb9a57a2e8 --- /dev/null +++ b/src/Appwrite/Platform/Modules/Sites/Http/Variables/GetVariable.php @@ -0,0 +1,68 @@ +setHttpMethod(Action::HTTP_REQUEST_METHOD_GET) + ->setHttpPath('/v1/sites/:siteId/variables/:variableId') + ->desc('Get variable') + ->groups(['api', 'sites']) + ->label('scope', 'functions.read') // TODO: Update scope to sites + ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'sites') + ->label('sdk.method', 'getVariable') + ->label('sdk.description', '/docs/references/sites/get-variable.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_VARIABLE) + ->param('siteId', '', new UID(), 'Site unique ID.', false) + ->param('variableId', '', new UID(), 'Variable unique ID.', false) + ->inject('response') + ->inject('dbForProject') + ->callback([$this, 'action']); + } + + public function action(string $siteId, string $variableId, Response $response, Database $dbForProject) + { + $site = $dbForProject->getDocument('sites', $siteId); + + if ($site->isEmpty()) { + throw new Exception(Exception::SITE_NOT_FOUND); + } + + $variable = $dbForProject->getDocument('variables', $variableId); + if ( + $variable === false || + $variable->isEmpty() || + $variable->getAttribute('resourceInternalId') !== $site->getInternalId() || + $variable->getAttribute('resourceType') !== 'site' + ) { + throw new Exception(Exception::VARIABLE_NOT_FOUND); + } + + if ($variable === false || $variable->isEmpty()) { + throw new Exception(Exception::VARIABLE_NOT_FOUND); + } + + $response->dynamic($variable, Response::MODEL_VARIABLE); + } +} diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Variables/ListVariables.php b/src/Appwrite/Platform/Modules/Sites/Http/Variables/ListVariables.php new file mode 100644 index 0000000000..7233cb234b --- /dev/null +++ b/src/Appwrite/Platform/Modules/Sites/Http/Variables/ListVariables.php @@ -0,0 +1,57 @@ +setHttpMethod(Action::HTTP_REQUEST_METHOD_GET) + ->setHttpPath('/v1/sites/:siteId/variables') + ->desc('List variables') + ->groups(['api', 'sites']) + ->label('scope', 'functions.read') // TODO: Update scope to sites + ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'sites') + ->label('sdk.method', 'listVariables') + ->label('sdk.description', '/docs/references/sites/list-variables.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_VARIABLE_LIST) + ->param('siteId', '', new UID(), 'Site unique ID.', false) + ->inject('response') + ->inject('dbForProject') + ->callback([$this, 'action']); + } + + public function action(string $siteId, Response $response, Database $dbForProject) + { + $site = $dbForProject->getDocument('sites', $siteId); + + if ($site->isEmpty()) { + throw new Exception(Exception::SITE_NOT_FOUND); + } + + $response->dynamic(new Document([ + 'variables' => $site->getAttribute('vars', []), + 'total' => \count($site->getAttribute('vars', [])), + ]), Response::MODEL_VARIABLE_LIST); + } +} diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Variables/UpdateVariable.php b/src/Appwrite/Platform/Modules/Sites/Http/Variables/UpdateVariable.php new file mode 100644 index 0000000000..abd023e182 --- /dev/null +++ b/src/Appwrite/Platform/Modules/Sites/Http/Variables/UpdateVariable.php @@ -0,0 +1,82 @@ +setHttpMethod(Action::HTTP_REQUEST_METHOD_PUT) + ->setHttpPath('/v1/sites/:siteId/variables/:variableId') + ->desc('Update variable') + ->groups(['api', 'sites']) + ->label('scope', 'functions.write') // TODO: Update scope to sites + ->label('audits.event', 'variable.update') + ->label('audits.resource', 'site/{request.siteId}') + ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'sites') + ->label('sdk.method', 'updateVariable') + ->label('sdk.description', '/docs/references/sites/update-variable.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_VARIABLE) + ->param('siteId', '', new UID(), 'Site unique ID.', false) + ->param('variableId', '', new UID(), 'Variable unique ID.', false) + ->param('key', null, new Text(255), 'Variable key. Max length: 255 chars.', false) + ->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', true) + ->inject('response') + ->inject('dbForProject') + ->callback([$this, 'action']); + } + + public function action(string $siteId, string $variableId, string $key, ?string $value, Response $response, Database $dbForProject) + { + $site = $dbForProject->getDocument('sites', $siteId); + + if ($site->isEmpty()) { + throw new Exception(Exception::SITE_NOT_FOUND); + } + + $variable = $dbForProject->getDocument('variables', $variableId); + if ($variable === false || $variable->isEmpty() || $variable->getAttribute('resourceInternalId') !== $site->getInternalId() || $variable->getAttribute('resourceType') !== 'site') { + throw new Exception(Exception::VARIABLE_NOT_FOUND); + } + + if ($variable === false || $variable->isEmpty()) { + throw new Exception(Exception::VARIABLE_NOT_FOUND); + } + + $variable + ->setAttribute('key', $key) + ->setAttribute('value', $value ?? $variable->getAttribute('value')) + ->setAttribute('search', implode(' ', [$variableId, $site->getId(), $key, 'site'])); + + try { + $dbForProject->updateDocument('variables', $variable->getId(), $variable); + } catch (DuplicateException $th) { + throw new Exception(Exception::VARIABLE_ALREADY_EXISTS); + } + + $dbForProject->updateDocument('sites', $site->getId(), $site->setAttribute('live', false)); + + $response->dynamic($variable, Response::MODEL_VARIABLE); + } +} diff --git a/src/Appwrite/Platform/Modules/Sites/Services/Http.php b/src/Appwrite/Platform/Modules/Sites/Services/Http.php index 7a66646ab3..ee72d434f4 100644 --- a/src/Appwrite/Platform/Modules/Sites/Services/Http.php +++ b/src/Appwrite/Platform/Modules/Sites/Services/Http.php @@ -11,10 +11,16 @@ use Appwrite\Platform\Modules\Sites\Http\Deployments\ListDeployments; use Appwrite\Platform\Modules\Sites\Http\Deployments\RebuildDeployment; use Appwrite\Platform\Modules\Sites\Http\Deployments\UpdateDeployment; use Appwrite\Platform\Modules\Sites\Http\Sites\CreateSite; +use Appwrite\Platform\Modules\Sites\Http\Sites\DeleteSite; use Appwrite\Platform\Modules\Sites\Http\Sites\GetSite; use Appwrite\Platform\Modules\Sites\Http\Sites\ListFrameworks; use Appwrite\Platform\Modules\Sites\Http\Sites\ListSites; use Appwrite\Platform\Modules\Sites\Http\Sites\UpdateSite; +use Appwrite\Platform\Modules\Sites\Http\Variables\CreateVariable; +use Appwrite\Platform\Modules\Sites\Http\Variables\DeleteVariable; +use Appwrite\Platform\Modules\Sites\Http\Variables\GetVariable; +use Appwrite\Platform\Modules\Sites\Http\Variables\ListVariables; +use Appwrite\Platform\Modules\Sites\Http\Variables\UpdateVariable; use Utopia\Platform\Service; class Http extends Service @@ -26,6 +32,7 @@ class Http extends Service $this->addAction(GetSite::getName(), new GetSite()); $this->addAction(ListSites::getName(), new ListSites()); $this->addAction(UpdateSite::getName(), new UpdateSite()); + $this->addAction(DeleteSite::getName(), new DeleteSite()); $this->addAction(ListFrameworks::getName(), new ListFrameworks()); $this->addAction(CreateDeployment::getName(), new CreateDeployment()); $this->addAction(GetDeployment::getName(), new GetDeployment()); @@ -35,5 +42,10 @@ class Http extends Service $this->addAction(DownloadDeployment::getName(), new DownloadDeployment()); $this->addAction(RebuildDeployment::getName(), new RebuildDeployment()); $this->addAction(CancelDeployment::getName(), new CancelDeployment()); + $this->addAction(CreateVariable::getName(), new CreateVariable()); + $this->addAction(GetVariable::getName(), new GetVariable()); + $this->addAction(ListVariables::getName(), new ListVariables()); + $this->addAction(UpdateVariable::getName(), new UpdateVariable()); + $this->addAction(DeleteVariable::getName(), new DeleteVariable()); } } From 8bda7f1e1efe4ba959bb719e0567d0967c04b999 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Thu, 24 Oct 2024 11:47:09 +0200 Subject: [PATCH 2/2] Add listSiteTemplates endpoint and response models --- app/config/site-templates.php | 45 +++++++ app/controllers/api/functions.php | 2 +- app/init.php | 1 + .../Sites/Http/Sites/ListSiteTemplates.php | 71 +++++++++++ .../Platform/Modules/Sites/Services/Http.php | 2 + src/Appwrite/Utopia/Response.php | 8 ++ .../Response/Model/TemplateFramework.php | 70 +++++++++++ .../Utopia/Response/Model/TemplateSite.php | 116 ++++++++++++++++++ 8 files changed, 314 insertions(+), 1 deletion(-) create mode 100644 app/config/site-templates.php create mode 100644 src/Appwrite/Platform/Modules/Sites/Http/Sites/ListSiteTemplates.php create mode 100644 src/Appwrite/Utopia/Response/Model/TemplateFramework.php create mode 100644 src/Appwrite/Utopia/Response/Model/TemplateSite.php diff --git a/app/config/site-templates.php b/app/config/site-templates.php new file mode 100644 index 0000000000..baaf78469f --- /dev/null +++ b/app/config/site-templates.php @@ -0,0 +1,45 @@ + [ + 'name' => 'sveltekit' + ], + 'NEXTJS' => [ + 'name' => 'nextjs' + ], +]; + +function getFrameworks($framework, $installCommand, $buildCommand, $outputDirectory, $fallbackRedirect, $providerRootDirectory) +{ + return array_map(function ($version) use ($framework, $installCommand, $buildCommand, $outputDirectory, $fallbackRedirect, $providerRootDirectory) { + return [ + 'name' => $framework['name'], + 'installCommand' => $installCommand, + 'buildCommand' => $buildCommand, + 'outputDirectory' => $outputDirectory, + 'fallbackRedirect' => $fallbackRedirect, + 'providerRootDirectory' => $providerRootDirectory + ]; + }, $framework); +} + +return [ + [ + 'icon' => 'icon-lightning-bolt', + 'id' => 'starter', + 'name' => 'Starter site', + 'tagline' => + 'A simple site to get started. Edit this site to explore endless possibilities with Appwrite Sites.', + 'useCases' => ['starter'], + 'frameworks' => [ + ...getFrameworks(TEMPLATE_FRAMEWORKS['SVELTEKIT'], 'npm install', 'npm run build', 'build', 'index.html', 'node/starter') + ], + 'instructions' => 'For documentation and instructions check out file.', + 'vcsProvider' => 'github', + 'providerRepositoryId' => 'templates', + 'providerOwner' => 'appwrite', + 'providerVersion' => '0.2.*', + 'variables' => [], + 'scopes' => ['users.read'] + ] +]; diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index 444e05fb21..b581f3b5f1 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -2565,7 +2565,7 @@ App::get('/v1/functions/templates') ->desc('List function templates') ->label('scope', 'public') ->label('sdk.namespace', 'functions') - ->label('sdk.method', 'listTemplates') + ->label('sdk.method', 'listTemplates') // TODO: Change to listFunctionTemplates later ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.description', '/docs/references/functions/list-templates.md') ->label('sdk.response.code', Response::STATUS_CODE_OK) diff --git a/app/init.php b/app/init.php index 1b9625175a..05824389e5 100644 --- a/app/init.php +++ b/app/init.php @@ -336,6 +336,7 @@ Config::load('storage-inputs', __DIR__ . '/config/storage/inputs.php'); Config::load('storage-outputs', __DIR__ . '/config/storage/outputs.php'); Config::load('runtime-specifications', __DIR__ . '/config/runtimes/specifications.php'); Config::load('function-templates', __DIR__ . '/config/function-templates.php'); +Config::load('site-templates', __DIR__ . '/config/site-templates.php'); /** * New DB Filters diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Sites/ListSiteTemplates.php b/src/Appwrite/Platform/Modules/Sites/Http/Sites/ListSiteTemplates.php new file mode 100644 index 0000000000..38e907267a --- /dev/null +++ b/src/Appwrite/Platform/Modules/Sites/Http/Sites/ListSiteTemplates.php @@ -0,0 +1,71 @@ +setHttpMethod(Action::HTTP_REQUEST_METHOD_GET) + ->setHttpPath('/v1/sites/templates') + ->desc('List site templates') + ->groups(['api']) + ->label('scope', 'public') + ->label('sdk.namespace', 'sites') + ->label('sdk.method', 'listSiteTemplates') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.description', '/docs/references/sites/list-templates.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_TEMPLATE_SITE_LIST) + ->param('frameworks', [], new ArrayList(new WhiteList(array_keys(Config::getParam('frameworks')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'List of frameworks allowed for filtering site templates. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' frameworks are allowed.', true) + ->param('useCases', [], new ArrayList(new WhiteList(['dev-tools', 'starter', 'databases', 'ai', 'messaging', 'utilities']), APP_LIMIT_ARRAY_PARAMS_SIZE), 'List of use cases allowed for filtering site templates. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' use cases are allowed.', true) + ->param('limit', 25, new Range(1, 5000), 'Limit the number of templates returned in the response. Default limit is 25, and maximum limit is 5000.', true) + ->param('offset', 0, new Range(0, 5000), 'Offset the list of returned templates. Maximum offset is 5000.', true) + ->inject('response') + ->callback([$this, 'action']); + } + + public function action(array $frameworks, array $usecases, int $limit, int $offset, Response $response) + { + $templates = Config::getParam('site-templates', []); + + var_dump($templates); + + if (!empty($frameworks)) { + $templates = \array_filter($templates, function ($template) use ($frameworks) { + return \count(\array_intersect($frameworks, \array_column($template['frameworks'], 'name'))) > 0; + }); + } + + if (!empty($usecases)) { + $templates = \array_filter($templates, function ($template) use ($usecases) { + return \count(\array_intersect($usecases, $template['useCases'])) > 0; + }); + } + + $responseTemplates = \array_slice($templates, $offset, $limit); + $response->dynamic(new Document([ + 'templates' => $responseTemplates, + 'total' => \count($responseTemplates), + ]), Response::MODEL_TEMPLATE_SITE_LIST); + } +} diff --git a/src/Appwrite/Platform/Modules/Sites/Services/Http.php b/src/Appwrite/Platform/Modules/Sites/Services/Http.php index ee72d434f4..92fdc8d842 100644 --- a/src/Appwrite/Platform/Modules/Sites/Services/Http.php +++ b/src/Appwrite/Platform/Modules/Sites/Services/Http.php @@ -15,6 +15,7 @@ use Appwrite\Platform\Modules\Sites\Http\Sites\DeleteSite; use Appwrite\Platform\Modules\Sites\Http\Sites\GetSite; use Appwrite\Platform\Modules\Sites\Http\Sites\ListFrameworks; use Appwrite\Platform\Modules\Sites\Http\Sites\ListSites; +use Appwrite\Platform\Modules\Sites\Http\Sites\ListSiteTemplates; use Appwrite\Platform\Modules\Sites\Http\Sites\UpdateSite; use Appwrite\Platform\Modules\Sites\Http\Variables\CreateVariable; use Appwrite\Platform\Modules\Sites\Http\Variables\DeleteVariable; @@ -47,5 +48,6 @@ class Http extends Service $this->addAction(ListVariables::getName(), new ListVariables()); $this->addAction(UpdateVariable::getName(), new UpdateVariable()); $this->addAction(DeleteVariable::getName(), new DeleteVariable()); + $this->addAction(ListSiteTemplates::getName(), new ListSiteTemplates()); } } diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index 816d72392e..e94d53abbc 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -91,8 +91,10 @@ use Appwrite\Utopia\Response\Model\Subscriber; use Appwrite\Utopia\Response\Model\Target; use Appwrite\Utopia\Response\Model\Team; use Appwrite\Utopia\Response\Model\TemplateEmail; +use Appwrite\Utopia\Response\Model\TemplateFramework; use Appwrite\Utopia\Response\Model\TemplateFunction; use Appwrite\Utopia\Response\Model\TemplateRuntime; +use Appwrite\Utopia\Response\Model\TemplateSite; use Appwrite\Utopia\Response\Model\TemplateSMS; use Appwrite\Utopia\Response\Model\TemplateVariable; use Appwrite\Utopia\Response\Model\Token; @@ -251,6 +253,9 @@ class Response extends SwooleResponse public const MODEL_SITE_LIST = 'siteList'; public const MODEL_FRAMEWORK = 'framework'; public const MODEL_FRAMEWORK_LIST = 'frameworkList'; + public const MODEL_TEMPLATE_SITE = 'templateSite'; + public const MODEL_TEMPLATE_SITE_LIST = 'templateSiteList'; + public const MODEL_TEMPLATE_FRAMEWORK = 'templateFramework'; // Functions public const MODEL_FUNCTION = 'function'; @@ -360,6 +365,7 @@ class Response extends SwooleResponse ->setModel(new BaseList('Teams List', self::MODEL_TEAM_LIST, 'teams', self::MODEL_TEAM)) ->setModel(new BaseList('Memberships List', self::MODEL_MEMBERSHIP_LIST, 'memberships', self::MODEL_MEMBERSHIP)) ->setModel(new BaseList('Sites List', self::MODEL_SITE_LIST, 'sites', self::MODEL_SITE)) + ->setModel(new BaseList('Site Templates List', self::MODEL_TEMPLATE_SITE_LIST, 'templates', self::MODEL_TEMPLATE_SITE)) ->setModel(new BaseList('Functions List', self::MODEL_FUNCTION_LIST, 'functions', self::MODEL_FUNCTION)) ->setModel(new BaseList('Function Templates List', self::MODEL_TEMPLATE_FUNCTION_LIST, 'templates', self::MODEL_TEMPLATE_FUNCTION)) ->setModel(new BaseList('Installations List', self::MODEL_INSTALLATION_LIST, 'installations', self::MODEL_INSTALLATION)) @@ -433,6 +439,8 @@ class Response extends SwooleResponse ->setModel(new Team()) ->setModel(new Membership()) ->setModel(new Site()) + ->setModel(new TemplateSite()) + ->setModel(new TemplateFramework()) ->setModel(new Func()) ->setModel(new TemplateFunction()) ->setModel(new TemplateRuntime()) diff --git a/src/Appwrite/Utopia/Response/Model/TemplateFramework.php b/src/Appwrite/Utopia/Response/Model/TemplateFramework.php new file mode 100644 index 0000000000..8acfcf0017 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/TemplateFramework.php @@ -0,0 +1,70 @@ +addRule('name', [ + 'type' => self::TYPE_STRING, + 'description' => 'Framework Name.', + 'default' => '', + 'example' => 'sveltekit', + ]) + ->addRule('installCommand', [ + 'type' => self::TYPE_STRING, + 'description' => 'The install command used to install the dependencies.', + 'default' => '', + 'example' => 'npm install', + ]) + ->addRule('buildCommand', [ + 'type' => self::TYPE_STRING, + 'description' => 'The build command used to build the deployment.', + 'default' => '', + 'example' => 'npm run build', + ]) + ->addRule('outputDirectory', [ + 'type' => self::TYPE_STRING, + 'description' => 'The output directory to store the build output.', + 'default' => '', + 'example' => 'build', + ]) + ->addRule('fallbackRedirect', [ + 'type' => self::TYPE_STRING, + 'description' => 'The fallback redirect for the site when a route is not found.', + 'default' => '', + 'example' => 'index.html', + ]) + ->addRule('providerRootDirectory', [ + 'type' => self::TYPE_STRING, + 'description' => 'Path to site in VCS (Version Control System) repository', + 'default' => '', + 'example' => 'node/starter', + ]); + } + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'Template Framework'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_TEMPLATE_FRAMEWORK; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/TemplateSite.php b/src/Appwrite/Utopia/Response/Model/TemplateSite.php new file mode 100644 index 0000000000..7eeff22076 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/TemplateSite.php @@ -0,0 +1,116 @@ +addRule('icon', [ + 'type' => self::TYPE_STRING, + 'description' => 'Site Template Icon.', + 'default' => '', + 'example' => 'icon-lightning-bolt', + ]) + ->addRule('id', [ + 'type' => self::TYPE_STRING, + 'description' => 'Site Template ID.', + 'default' => '', + 'example' => 'starter', + ]) + ->addRule('name', [ + 'type' => self::TYPE_STRING, + 'description' => 'Site Template Name.', + 'default' => '', + 'example' => 'Starter site', + ]) + ->addRule('tagline', [ + 'type' => self::TYPE_STRING, + 'description' => 'Site Template Tagline.', + 'default' => '', + 'example' => 'A simple site to get started.', + ]) + ->addRule('useCases', [ + 'type' => self::TYPE_STRING, + 'description' => 'Site use cases.', + 'default' => [], + 'example' => 'Starter', + 'array' => true, + ]) + ->addRule('frameworks', [ + 'type' => Response::MODEL_TEMPLATE_FRAMEWORK, + 'description' => 'List of frameworks that can be used with this template.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('instructions', [ + 'type' => self::TYPE_STRING, + 'description' => 'Site Template Instructions.', + 'default' => '', + 'example' => 'For documentation and instructions check out .', + ]) + ->addRule('vcsProvider', [ + 'type' => self::TYPE_STRING, + 'description' => 'VCS (Version Control System) Provider.', + 'default' => '', + 'example' => 'github', + ]) + ->addRule('providerRepositoryId', [ + 'type' => self::TYPE_STRING, + 'description' => 'VCS (Version Control System) Repository ID', + 'default' => '', + 'example' => 'templates', + ]) + ->addRule('providerOwner', [ + 'type' => self::TYPE_STRING, + 'description' => 'VCS (Version Control System) Owner.', + 'default' => '', + 'example' => 'appwrite', + ]) + ->addRule('providerVersion', [ + 'type' => self::TYPE_STRING, + 'description' => 'VCS (Version Control System) branch version (tag).', + 'default' => '', + 'example' => 'main', + ]) + ->addRule('variables', [ + 'type' => Response::MODEL_TEMPLATE_VARIABLE, + 'description' => 'Site variables.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ->addRule('scopes', [ + 'type' => self::TYPE_STRING, + 'description' => 'Site scopes.', + 'default' => [], + 'example' => 'users.read', + 'array' => true, + ]); + } + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'Template Site'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_TEMPLATE_SITE; + } +}