diff --git a/src/Appwrite/Platform/Modules/Project/Http/Project/Platforms/App/Create.php b/src/Appwrite/Platform/Modules/Project/Http/Project/Platforms/App/Create.php index 7fdd8adcff..1c957f761c 100644 --- a/src/Appwrite/Platform/Modules/Project/Http/Project/Platforms/App/Create.php +++ b/src/Appwrite/Platform/Modules/Project/Http/Project/Platforms/App/Create.php @@ -6,10 +6,12 @@ use Appwrite\Event\Event as QueueEvent; use Appwrite\Extend\Exception; use Appwrite\Network\Platform; use Appwrite\Platform\Modules\Compute\Base; +use Appwrite\Platform\Modules\Project\Http\Project\Platforms\Web\Create as CreateWebPlatform; use Appwrite\SDK\AuthType; use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Database\Validator\CustomId; +use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Utopia\Database\Database; use Utopia\Database\Document; @@ -18,6 +20,7 @@ use Utopia\Database\Helpers\ID; use Utopia\Database\Validator\Authorization; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; +use Utopia\Validator\Hostname; use Utopia\Validator\Text; use Utopia\Validator\WhiteList; @@ -52,11 +55,23 @@ class Create extends Base ]; } + /** + * @return array + */ + public static function getAllSupportedTypes(): array + { + return [ + ...self::getSupportedTypes(), + ...CreateWebPlatform::getSupportedTypes(), + ]; + } + public function __construct() { $this ->setHttpMethod(Action::HTTP_REQUEST_METHOD_POST) ->setHttpPath('/v1/project/platforms/app') + ->httpAlias('/v1/projects/:projectId/platforms') ->desc('Create project app platform') ->groups(['api', 'project']) ->label('scope', 'project.write') @@ -83,10 +98,11 @@ class Create extends Base ->param( 'type', null, - new WhiteList($this->getSupportedTypes(), true), + new WhiteList($this->getAllSupportedTypes(), true), // We only support all here for backwards compatibility 'Platform type. Possible values are: ' . implode(', ', $this->getSupportedTypes()) ) - ->param('identifier', '', new Text(256), 'Package name for Android or bundle ID for iOS or macOS. Max length: 256 chars.') + ->param('identifier', '', new Text(256), 'Package name for Android or bundle ID for iOS or macOS. Max length: 256 chars.', true) // We only mark optional=true for backwards compatibility + ->inject('request') ->inject('response') ->inject('queueForEvents') ->inject('project') @@ -99,13 +115,31 @@ class Create extends Base string $platformId, string $name, string $type, - string $identifier, + ?string $identifier, // Only nullable for backwards compatibility + Request $request, Response $response, QueueEvent $queueForEvents, Document $project, Database $dbForPlatform, Authorization $authorization, ) { + $hostname = null; + + // Backwards compatibility + $isDeprecatedRequest = false; + if (!\in_array($type, self::getSupportedTypes())) { + $isDeprecatedRequest = true; + $hostname = $request->getParam('hostname', ''); + $hostnameValidator = new Hostname(); + if (!$hostnameValidator->isValid($hostname)) { + throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Param "hostname" is invalid: ' . $hostnameValidator->getDescription()); + } + } else { + if (empty($identifier)) { + throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Param "identifier" is not optional.'); + } + } + $platformId = ($platformId == 'unique()') ? ID::unique() : $platformId; $platform = new Document([ @@ -116,8 +150,8 @@ class Create extends Base 'type' => $type, 'name' => $name, 'key' => $identifier, - 'store' => null, // Unused at the moment - 'hostname' => null // Web platform attribute + 'hostname' => $hostname, // Web platform attribute; We fill only during backwards compatibility, otherwise null + 'store' => null, // Unused attribute ]); try { @@ -130,6 +164,10 @@ class Create extends Base $queueForEvents->setParam('platformId', $platform->getId()); + if (!$isDeprecatedRequest) { + $platform->setAttribute('hostname', ''); + } + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($platform, Response::MODEL_PLATFORM_APP); diff --git a/src/Appwrite/Platform/Modules/Project/Http/Project/Platforms/App/Update.php b/src/Appwrite/Platform/Modules/Project/Http/Project/Platforms/App/Update.php index 19a1b501aa..d32246abff 100644 --- a/src/Appwrite/Platform/Modules/Project/Http/Project/Platforms/App/Update.php +++ b/src/Appwrite/Platform/Modules/Project/Http/Project/Platforms/App/Update.php @@ -6,9 +6,11 @@ use Appwrite\Event\Event as QueueEvent; use Appwrite\Extend\Exception; use Appwrite\Platform\Modules\Compute\Base; use Appwrite\Platform\Modules\Project\Http\Project\Platforms\App\Create as AppPlatformCreate; +use Appwrite\Platform\Modules\Project\Http\Project\Platforms\Web\Create as WebPlatformCreate; use Appwrite\SDK\AuthType; use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; +use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Utopia\Database\Database; use Utopia\Database\Document; @@ -17,6 +19,7 @@ use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; +use Utopia\Validator\Hostname; use Utopia\Validator\Text; class Update extends Base @@ -32,6 +35,7 @@ class Update extends Base { $this->setHttpMethod(Action::HTTP_REQUEST_METHOD_PUT) ->setHttpPath('/v1/project/platforms/app/:platformId') + ->httpAlias('/v1/projects/:projectId/platforms/:platformId') ->desc('Update project app platform') ->groups(['api', 'project']) ->label('scope', 'project.write') @@ -55,7 +59,8 @@ class Update extends Base )) ->param('platformId', '', fn (Database $dbForPlatform) => new UID($dbForPlatform->getAdapter()->getMaxUIDLength()), 'Platform ID.', false, ['dbForPlatform']) ->param('name', null, new Text(128), 'Platform name. Max length: 128 chars.') - ->param('identifier', '', new Text(256), 'Package name for Android or bundle ID for iOS or macOS. Max length: 256 chars.') + ->param('identifier', '', new Text(256), 'Package name for Android or bundle ID for iOS or macOS. Max length: 256 chars.', true) // Only optional=true for backwards compatibility + ->inject('request') ->inject('response') ->inject('queueForEvents') ->inject('dbForPlatform') @@ -67,13 +72,29 @@ class Update extends Base public function action( string $platformId, string $name, - string $identifier, + ?string $identifier, // Only nullable for backwards compatibility + Request $request, Response $response, QueueEvent $queueForEvents, Database $dbForPlatform, Authorization $authorization, Document $project, ) { + // Backwards compatibility + $isDeprecatedRequest = false; + $hostname = $request->getParam('hostname', ''); + if (!empty($hostname)) { + $isDeprecatedRequest = true; + $hostnameValidator = new Hostname(); + if (!$hostnameValidator->isValid($hostname)) { + throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Param "hostname" is invalid: ' . $hostnameValidator->getDescription()); + } + } else { + if (empty($identifier)) { + throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Param "identifier" is not optional.'); + } + } + $platform = $authorization->skip(fn () => $dbForPlatform->getDocument('platforms', $platformId)); if ($platform->isEmpty() || $platform->getAttribute('projectInternalId', '') !== $project->getSequence()) { @@ -82,12 +103,22 @@ class Update extends Base $appPlatforms = AppPlatformCreate::getSupportedTypes(); if (!\in_array($platform->getAttribute('type', ''), $appPlatforms)) { - throw new Exception(Exception::PLATFORM_METHOD_UNSUPPORTED); + + if ($isDeprecatedRequest) { + // Bacwkards compatible check + $webPlatforms = WebPlatformCreate::getSupportedTypes(); + if (!\in_array($platform->getAttribute('type', ''), $webPlatforms)) { + throw new Exception(Exception::PLATFORM_METHOD_UNSUPPORTED); + } + } else { + throw new Exception(Exception::PLATFORM_METHOD_UNSUPPORTED); + } } $updates = new Document([ 'name' => $name, 'key' => $identifier, + 'hostname' => $hostname ?? $platform['hostname'] ?? '', // Backwards compatibility ]); try { @@ -100,6 +131,10 @@ class Update extends Base $queueForEvents->setParam('platformId', $platform->getId()); + if (!$isDeprecatedRequest) { + $platform->setAttribute('hostname', ''); + } + $response->dynamic($platform, Response::MODEL_PLATFORM_APP); } } diff --git a/src/Appwrite/Platform/Modules/Project/Http/Project/Platforms/Web/Create.php b/src/Appwrite/Platform/Modules/Project/Http/Project/Platforms/Web/Create.php index 851dfc5d19..a2f3bb11cb 100644 --- a/src/Appwrite/Platform/Modules/Project/Http/Project/Platforms/Web/Create.php +++ b/src/Appwrite/Platform/Modules/Project/Http/Project/Platforms/Web/Create.php @@ -107,7 +107,7 @@ class Create extends Base 'type' => $type, 'name' => $name, 'key' => null, // App platform attribute - 'store' => null, // App platform attribute + 'store' => null, // Unused attribute 'hostname' => $hostname ]); diff --git a/src/Appwrite/SDK/Specification/Format.php b/src/Appwrite/SDK/Specification/Format.php index 04ecafa8fc..b3a9473479 100644 --- a/src/Appwrite/SDK/Specification/Format.php +++ b/src/Appwrite/SDK/Specification/Format.php @@ -753,6 +753,9 @@ abstract class Format protected function getNestedModels(Model $model, array &$usedModels): void { foreach ($model->getRules() as $rule) { + if (($rule['hidden'] ?? false) === true) { + continue; + } if (!in_array($model->getType(), $usedModels)) { continue; } diff --git a/src/Appwrite/SDK/Specification/Format/OpenAPI3.php b/src/Appwrite/SDK/Specification/Format/OpenAPI3.php index 8c77da413f..675a592cc2 100644 --- a/src/Appwrite/SDK/Specification/Format/OpenAPI3.php +++ b/src/Appwrite/SDK/Specification/Format/OpenAPI3.php @@ -829,6 +829,10 @@ class OpenAPI3 extends Format } foreach ($model->getRules() as $name => $rule) { + if (($rule['hidden'] ?? false) === true) { + continue; + } + $type = ''; $format = null; $items = null; diff --git a/src/Appwrite/SDK/Specification/Format/Swagger2.php b/src/Appwrite/SDK/Specification/Format/Swagger2.php index d0815d8cad..aaca64771d 100644 --- a/src/Appwrite/SDK/Specification/Format/Swagger2.php +++ b/src/Appwrite/SDK/Specification/Format/Swagger2.php @@ -810,6 +810,10 @@ class Swagger2 extends Format } foreach ($model->getRules() as $name => $rule) { + if (($rule['hidden'] ?? false) === true) { + continue; + } + $type = ''; $format = null; $items = null; diff --git a/src/Appwrite/Utopia/Response/Model/PlatformApp.php b/src/Appwrite/Utopia/Response/Model/PlatformApp.php index 1b65b8a55c..f63833290c 100644 --- a/src/Appwrite/Utopia/Response/Model/PlatformApp.php +++ b/src/Appwrite/Utopia/Response/Model/PlatformApp.php @@ -52,6 +52,13 @@ class PlatformApp extends PlatformBase 'default' => '', 'example' => 'com.company.appname', ]) + ->addRule('hostname', [ // Backwards compatibility + 'type' => self::TYPE_STRING, + 'description' => 'Web app hostname. Empty string for other platforms.', + 'default' => '', + 'example' => 'app.example.com', + 'hidden' => true, + ]) ; }