From 3172f3073c27050d2226df6c7feabaf9cf212567 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Fri, 13 Aug 2021 16:57:08 -0400 Subject: [PATCH 01/58] Split attribute model into primitive types --- .../Utopia/Response/Model/Attribute.php | 21 -------- .../Utopia/Response/Model/AttributeFloat.php | 51 +++++++++++++++++++ .../Response/Model/AttributeInteger.php | 51 +++++++++++++++++++ .../Utopia/Response/Model/AttributeString.php | 41 +++++++++++++++ 4 files changed, 143 insertions(+), 21 deletions(-) create mode 100644 src/Appwrite/Utopia/Response/Model/AttributeFloat.php create mode 100644 src/Appwrite/Utopia/Response/Model/AttributeInteger.php create mode 100644 src/Appwrite/Utopia/Response/Model/AttributeString.php diff --git a/src/Appwrite/Utopia/Response/Model/Attribute.php b/src/Appwrite/Utopia/Response/Model/Attribute.php index b8763be6f..c25b21da5 100644 --- a/src/Appwrite/Utopia/Response/Model/Attribute.php +++ b/src/Appwrite/Utopia/Response/Model/Attribute.php @@ -28,25 +28,12 @@ class Attribute extends Model 'default' => '', 'example' => 'string', ]) - ->addRule('size', [ - 'type' => self::TYPE_STRING, - 'description' => 'Attribute size.', - 'default' => 0, - 'example' => 128, - ]) ->addRule('required', [ 'type' => self::TYPE_BOOLEAN, 'description' => 'Is attribute required?', 'default' => false, 'example' => true, ]) - ->addRule('signed', [ - 'type' => self::TYPE_BOOLEAN, - 'description' => 'Is attribute signed?', - 'default' => true, - 'example' => true, - 'required' => false, - ]) ->addRule('array', [ 'type' => self::TYPE_BOOLEAN, 'description' => 'Is attribute an array?', @@ -54,14 +41,6 @@ class Attribute extends Model 'example' => false, 'required' => false ]) - ->addRule('filters', [ - 'type' => self::TYPE_STRING, - 'description' => 'Attribute filters.', - 'default' => [], - 'example' => [], - 'array' => true, - 'required' => false, - ]) ; } diff --git a/src/Appwrite/Utopia/Response/Model/AttributeFloat.php b/src/Appwrite/Utopia/Response/Model/AttributeFloat.php new file mode 100644 index 000000000..bf9ca0f10 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/AttributeFloat.php @@ -0,0 +1,51 @@ +addRule('min', [ + 'type' => self::TYPE_FLOAT, + 'description' => 'Minimum value to enforce on new documents.', + 'default' => null, + 'example' => 0.5, + 'array' => false, + 'required' => false, + ]) + ->addRule('max', [ + 'type' => self::TYPE_FLOAT, + 'description' => 'Minimum value to enforce on new documents.', + 'default' => null, + 'example' => 2.5, + 'array' => false, + 'required' => false, + ]) + ; + } + + /** + * Get Name + * + * @return string + */ + public function getName():string + { + return 'Float'; + } + + /** + * Get Collection + * + * @return string + */ + public function getType():string + { + return Response::MODEL_FLOAT; + } +} \ No newline at end of file diff --git a/src/Appwrite/Utopia/Response/Model/AttributeInteger.php b/src/Appwrite/Utopia/Response/Model/AttributeInteger.php new file mode 100644 index 000000000..5a5ec896c --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/AttributeInteger.php @@ -0,0 +1,51 @@ +addRule('min', [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Minimum value to enforce on new documents.', + 'default' => null, + 'example' => 0, + 'array' => false, + 'required' => false, + ]) + ->addRule('max', [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Minimum value to enforce on new documents.', + 'default' => null, + 'example' => 10, + 'array' => false, + 'required' => false, + ]) + ; + } + + /** + * Get Name + * + * @return string + */ + public function getName():string + { + return 'Integer'; + } + + /** + * Get Collection + * + * @return string + */ + public function getType():string + { + return Response::MODEL_INTEGER; + } +} \ No newline at end of file diff --git a/src/Appwrite/Utopia/Response/Model/AttributeString.php b/src/Appwrite/Utopia/Response/Model/AttributeString.php new file mode 100644 index 000000000..c12de4395 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/AttributeString.php @@ -0,0 +1,41 @@ +addRule('size', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute size.', + 'default' => 0, + 'example' => 128, + ]) + ; + } + + /** + * Get Name + * + * @return string + */ + public function getName():string + { + return 'String'; + } + + /** + * Get Collection + * + * @return string + */ + public function getType():string + { + return Response::MODEL_ATTRIBUTE_STRING; + } +} \ No newline at end of file From 20f5f03173ae67a05bc96bebdcabbc4ea888b038 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Fri, 13 Aug 2021 16:58:36 -0400 Subject: [PATCH 02/58] Create formatted string attribute models --- src/Appwrite/Utopia/Response/Model/Email.php | 43 ++++++++++++++++++++ src/Appwrite/Utopia/Response/Model/IP.php | 43 ++++++++++++++++++++ src/Appwrite/Utopia/Response/Model/URL.php | 43 ++++++++++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 src/Appwrite/Utopia/Response/Model/Email.php create mode 100644 src/Appwrite/Utopia/Response/Model/IP.php create mode 100644 src/Appwrite/Utopia/Response/Model/URL.php diff --git a/src/Appwrite/Utopia/Response/Model/Email.php b/src/Appwrite/Utopia/Response/Model/Email.php new file mode 100644 index 000000000..e876019f8 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/Email.php @@ -0,0 +1,43 @@ +addRule('format', [ + 'type' => self::TYPE_STRING, + 'description' => 'String format.', + 'default' => 'email', + 'example' => 'email', + 'array' => false, + 'required' => true, + ]) + ; + } + + /** + * Get Name + * + * @return string + */ + public function getName():string + { + return 'Email'; + } + + /** + * Get Collection + * + * @return string + */ + public function getType():string + { + return Response::MODEL_EMAIL; + } +} \ No newline at end of file diff --git a/src/Appwrite/Utopia/Response/Model/IP.php b/src/Appwrite/Utopia/Response/Model/IP.php new file mode 100644 index 000000000..e81805550 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/IP.php @@ -0,0 +1,43 @@ +addRule('format', [ + 'type' => self::TYPE_STRING, + 'description' => 'String format.', + 'default' => 'ip', + 'example' => 'ip', + 'array' => false, + 'required' => true, + ]) + ; + } + + /** + * Get Name + * + * @return string + */ + public function getName():string + { + return 'IP'; + } + + /** + * Get Collection + * + * @return string + */ + public function getType():string + { + return Response::MODEL_IP; + } +} \ No newline at end of file diff --git a/src/Appwrite/Utopia/Response/Model/URL.php b/src/Appwrite/Utopia/Response/Model/URL.php new file mode 100644 index 000000000..37340ab61 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/URL.php @@ -0,0 +1,43 @@ +addRule('format', [ + 'type' => self::TYPE_STRING, + 'description' => 'String format.', + 'default' => 'url', + 'example' => 'url', + 'array' => false, + 'required' => true, + ]) + ; + } + + /** + * Get Name + * + * @return string + */ + public function getName():string + { + return 'URL'; + } + + /** + * Get Collection + * + * @return string + */ + public function getType():string + { + return Response::MODEL_URL; + } +} \ No newline at end of file From 9c3f1988bbcbf8c46783e77c64fd2efa03387c6c Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Fri, 13 Aug 2021 16:58:54 -0400 Subject: [PATCH 03/58] Instantiate new attribute models, constants, and lists --- src/Appwrite/Utopia/Response.php | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index 3cd25b603..b31297262 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -11,6 +11,9 @@ use Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response\Model\None; use Appwrite\Utopia\Response\Model\Any; use Appwrite\Utopia\Response\Model\Attribute; +use Appwrite\Utopia\Response\Model\AttributeString; +use Appwrite\Utopia\Response\Model\AttributeInteger; +use Appwrite\Utopia\Response\Model\AttributeFloat; use Appwrite\Utopia\Response\Model\BaseList; use Appwrite\Utopia\Response\Model\Collection; use Appwrite\Utopia\Response\Model\Continent; @@ -18,12 +21,14 @@ use Appwrite\Utopia\Response\Model\Country; use Appwrite\Utopia\Response\Model\Currency; use Appwrite\Utopia\Response\Model\Document as ModelDocument; use Appwrite\Utopia\Response\Model\Domain; +use Appwrite\Utopia\Response\Model\Email; use Appwrite\Utopia\Response\Model\Error; use Appwrite\Utopia\Response\Model\ErrorDev; use Appwrite\Utopia\Response\Model\Execution; use Appwrite\Utopia\Response\Model\File; use Appwrite\Utopia\Response\Model\Func; use Appwrite\Utopia\Response\Model\Index; +use Appwrite\Utopia\Response\Model\IP; use Appwrite\Utopia\Response\Model\JWT; use Appwrite\Utopia\Response\Model\Key; use Appwrite\Utopia\Response\Model\Language; @@ -40,6 +45,7 @@ use Appwrite\Utopia\Response\Model\Project; use Appwrite\Utopia\Response\Model\Rule; use Appwrite\Utopia\Response\Model\Tag; use Appwrite\Utopia\Response\Model\Token; +use Appwrite\Utopia\Response\Model\URL; use Appwrite\Utopia\Response\Model\Webhook; use Appwrite\Utopia\Response\Model\Preferences; use Appwrite\Utopia\Response\Model\Mock; // Keep last @@ -62,13 +68,27 @@ class Response extends SwooleResponse // Database const MODEL_COLLECTION = 'collection'; const MODEL_COLLECTION_LIST = 'collectionList'; - const MODEL_ATTRIBUTE = 'attribute'; - const MODEL_ATTRIBUTE_LIST = 'attributeList'; const MODEL_INDEX = 'index'; const MODEL_INDEX_LIST = 'indexList'; const MODEL_DOCUMENT = 'document'; const MODEL_DOCUMENT_LIST = 'documentList'; + // Database Attributes + const MODEL_ATTRIBUTE = 'attribute'; + const MODEL_ATTRIBUTE_LIST = 'attributeList'; + const MODEL_ATTRIBUTE_STRING = 'attributeString'; + const MODEL_ATTRIBUTE_STRING_LIST = 'attributeStringList'; + const MODEL_INTEGER= 'integer'; + const MODEL_INTEGER_LIST= 'integerList'; + const MODEL_FLOAT= 'float'; + const MODEL_FLOAT_LIST= 'floatList'; + const MODEL_EMAIL= 'email'; + const MODEL_EMAIL_LIST= 'emailList'; + const MODEL_IP= 'ip'; + const MODEL_IP_LIST= 'ipList'; + const MODEL_URL= 'url'; + const MODEL_URL_LIST= 'urlList'; + // Users const MODEL_USER = 'user'; const MODEL_USER_LIST = 'userList'; @@ -179,6 +199,12 @@ class Response extends SwooleResponse // Entities ->setModel(new Collection()) ->setModel(new Attribute()) + ->setModel(new AttributeString()) + ->setModel(new AttributeInteger()) + ->setModel(new AttributeFloat()) + ->setModel(new Email()) + ->setModel(new IP()) + ->setModel(new URL()) ->setModel(new Index()) ->setModel(new ModelDocument()) ->setModel(new Log()) From 6948a75133b136cbd07733b0aa3bd361431ac727 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Mon, 16 Aug 2021 15:54:25 -0400 Subject: [PATCH 04/58] Prefix custom string models with Attribute --- src/Appwrite/Utopia/Response.php | 18 +++++++++--------- .../Model/{Email.php => AttributeEmail.php} | 6 +++--- .../Response/Model/{IP.php => AttributeIP.php} | 6 +++--- .../Model/{URL.php => AttributeURL.php} | 6 +++--- 4 files changed, 18 insertions(+), 18 deletions(-) rename src/Appwrite/Utopia/Response/Model/{Email.php => AttributeEmail.php} (85%) rename src/Appwrite/Utopia/Response/Model/{IP.php => AttributeIP.php} (86%) rename src/Appwrite/Utopia/Response/Model/{URL.php => AttributeURL.php} (85%) diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index b31297262..297b9f530 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -14,6 +14,9 @@ use Appwrite\Utopia\Response\Model\Attribute; use Appwrite\Utopia\Response\Model\AttributeString; use Appwrite\Utopia\Response\Model\AttributeInteger; use Appwrite\Utopia\Response\Model\AttributeFloat; +use Appwrite\Utopia\Response\Model\AttributeEmail; +use Appwrite\Utopia\Response\Model\AttributeIP; +use Appwrite\Utopia\Response\Model\AttributeURL; use Appwrite\Utopia\Response\Model\BaseList; use Appwrite\Utopia\Response\Model\Collection; use Appwrite\Utopia\Response\Model\Continent; @@ -21,14 +24,12 @@ use Appwrite\Utopia\Response\Model\Country; use Appwrite\Utopia\Response\Model\Currency; use Appwrite\Utopia\Response\Model\Document as ModelDocument; use Appwrite\Utopia\Response\Model\Domain; -use Appwrite\Utopia\Response\Model\Email; use Appwrite\Utopia\Response\Model\Error; use Appwrite\Utopia\Response\Model\ErrorDev; use Appwrite\Utopia\Response\Model\Execution; use Appwrite\Utopia\Response\Model\File; use Appwrite\Utopia\Response\Model\Func; use Appwrite\Utopia\Response\Model\Index; -use Appwrite\Utopia\Response\Model\IP; use Appwrite\Utopia\Response\Model\JWT; use Appwrite\Utopia\Response\Model\Key; use Appwrite\Utopia\Response\Model\Language; @@ -45,7 +46,6 @@ use Appwrite\Utopia\Response\Model\Project; use Appwrite\Utopia\Response\Model\Rule; use Appwrite\Utopia\Response\Model\Tag; use Appwrite\Utopia\Response\Model\Token; -use Appwrite\Utopia\Response\Model\URL; use Appwrite\Utopia\Response\Model\Webhook; use Appwrite\Utopia\Response\Model\Preferences; use Appwrite\Utopia\Response\Model\Mock; // Keep last @@ -82,11 +82,11 @@ class Response extends SwooleResponse const MODEL_INTEGER_LIST= 'integerList'; const MODEL_FLOAT= 'float'; const MODEL_FLOAT_LIST= 'floatList'; - const MODEL_EMAIL= 'email'; + const MODEL_ATTRIBUTE_EMAIL= 'email'; const MODEL_EMAIL_LIST= 'emailList'; - const MODEL_IP= 'ip'; + const MODEL_ATTRIBUTE_IP= 'ip'; const MODEL_IP_LIST= 'ipList'; - const MODEL_URL= 'url'; + const MODEL_ATTRIBUTE_URL= 'url'; const MODEL_URL_LIST= 'urlList'; // Users @@ -202,9 +202,9 @@ class Response extends SwooleResponse ->setModel(new AttributeString()) ->setModel(new AttributeInteger()) ->setModel(new AttributeFloat()) - ->setModel(new Email()) - ->setModel(new IP()) - ->setModel(new URL()) + ->setModel(new AttributeEmail()) + ->setModel(new AttributeIP()) + ->setModel(new AttributeURL()) ->setModel(new Index()) ->setModel(new ModelDocument()) ->setModel(new Log()) diff --git a/src/Appwrite/Utopia/Response/Model/Email.php b/src/Appwrite/Utopia/Response/Model/AttributeEmail.php similarity index 85% rename from src/Appwrite/Utopia/Response/Model/Email.php rename to src/Appwrite/Utopia/Response/Model/AttributeEmail.php index e876019f8..b0ea0d730 100644 --- a/src/Appwrite/Utopia/Response/Model/Email.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeEmail.php @@ -5,7 +5,7 @@ namespace Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Model\AttributeString; -class Email extends AttributeString +class AttributeEmail extends AttributeString { public function __construct() { @@ -28,7 +28,7 @@ class Email extends AttributeString */ public function getName():string { - return 'Email'; + return 'AttributeEmail'; } /** @@ -38,6 +38,6 @@ class Email extends AttributeString */ public function getType():string { - return Response::MODEL_EMAIL; + return Response::MODEL_ATTRIBUTE_EMAIL; } } \ No newline at end of file diff --git a/src/Appwrite/Utopia/Response/Model/IP.php b/src/Appwrite/Utopia/Response/Model/AttributeIP.php similarity index 86% rename from src/Appwrite/Utopia/Response/Model/IP.php rename to src/Appwrite/Utopia/Response/Model/AttributeIP.php index e81805550..19147ce00 100644 --- a/src/Appwrite/Utopia/Response/Model/IP.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeIP.php @@ -5,7 +5,7 @@ namespace Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Model\AttributeString; -class IP extends AttributeString +class AttributeIP extends AttributeString { public function __construct() { @@ -28,7 +28,7 @@ class IP extends AttributeString */ public function getName():string { - return 'IP'; + return 'AttributeIP'; } /** @@ -38,6 +38,6 @@ class IP extends AttributeString */ public function getType():string { - return Response::MODEL_IP; + return Response::MODEL_ATTRIBUTE_IP; } } \ No newline at end of file diff --git a/src/Appwrite/Utopia/Response/Model/URL.php b/src/Appwrite/Utopia/Response/Model/AttributeURL.php similarity index 85% rename from src/Appwrite/Utopia/Response/Model/URL.php rename to src/Appwrite/Utopia/Response/Model/AttributeURL.php index 37340ab61..d310af131 100644 --- a/src/Appwrite/Utopia/Response/Model/URL.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeURL.php @@ -5,7 +5,7 @@ namespace Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Model\AttributeString; -class URL extends AttributeString +class AttributeURL extends AttributeString { public function __construct() { @@ -28,7 +28,7 @@ class URL extends AttributeString */ public function getName():string { - return 'URL'; + return 'AttributeURL'; } /** @@ -38,6 +38,6 @@ class URL extends AttributeString */ public function getType():string { - return Response::MODEL_URL; + return Response::MODEL_ATTRIBUTE_URL; } } \ No newline at end of file From 78d013c10958de7c9ac1ede4b909f3f286ca9772 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Mon, 16 Aug 2021 15:59:58 -0400 Subject: [PATCH 05/58] Prefix all attribute models with Attribute --- src/Appwrite/Utopia/Response.php | 16 +++++----------- .../Utopia/Response/Model/AttributeFloat.php | 4 ++-- .../Utopia/Response/Model/AttributeInteger.php | 4 ++-- .../Utopia/Response/Model/AttributeString.php | 2 +- 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index 297b9f530..06c9375d0 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -77,17 +77,11 @@ class Response extends SwooleResponse const MODEL_ATTRIBUTE = 'attribute'; const MODEL_ATTRIBUTE_LIST = 'attributeList'; const MODEL_ATTRIBUTE_STRING = 'attributeString'; - const MODEL_ATTRIBUTE_STRING_LIST = 'attributeStringList'; - const MODEL_INTEGER= 'integer'; - const MODEL_INTEGER_LIST= 'integerList'; - const MODEL_FLOAT= 'float'; - const MODEL_FLOAT_LIST= 'floatList'; - const MODEL_ATTRIBUTE_EMAIL= 'email'; - const MODEL_EMAIL_LIST= 'emailList'; - const MODEL_ATTRIBUTE_IP= 'ip'; - const MODEL_IP_LIST= 'ipList'; - const MODEL_ATTRIBUTE_URL= 'url'; - const MODEL_URL_LIST= 'urlList'; + const MODEL_ATTRIBUTE_INTEGER= 'attributeInteger'; + const MODEL_ATTRIBUTE_FLOAT= 'attributeFloat'; + const MODEL_ATTRIBUTE_EMAIL= 'attributeEmail'; + const MODEL_ATTRIBUTE_IP= 'attributeIp'; + const MODEL_ATTRIBUTE_URL= 'attributeUrl'; // Users const MODEL_USER = 'user'; diff --git a/src/Appwrite/Utopia/Response/Model/AttributeFloat.php b/src/Appwrite/Utopia/Response/Model/AttributeFloat.php index bf9ca0f10..3320582b5 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeFloat.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeFloat.php @@ -36,7 +36,7 @@ class AttributeFloat extends Attribute */ public function getName():string { - return 'Float'; + return 'AttributeFloat'; } /** @@ -46,6 +46,6 @@ class AttributeFloat extends Attribute */ public function getType():string { - return Response::MODEL_FLOAT; + return Response::MODEL_ATTRIBUTE_FLOAT; } } \ No newline at end of file diff --git a/src/Appwrite/Utopia/Response/Model/AttributeInteger.php b/src/Appwrite/Utopia/Response/Model/AttributeInteger.php index 5a5ec896c..ee65d3a39 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeInteger.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeInteger.php @@ -36,7 +36,7 @@ class AttributeInteger extends Attribute */ public function getName():string { - return 'Integer'; + return 'AttributeInteger'; } /** @@ -46,6 +46,6 @@ class AttributeInteger extends Attribute */ public function getType():string { - return Response::MODEL_INTEGER; + return Response::MODEL_ATTRIBUTE_INTEGER; } } \ No newline at end of file diff --git a/src/Appwrite/Utopia/Response/Model/AttributeString.php b/src/Appwrite/Utopia/Response/Model/AttributeString.php index c12de4395..e7eb558b6 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeString.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeString.php @@ -26,7 +26,7 @@ class AttributeString extends Attribute */ public function getName():string { - return 'String'; + return 'AttributeString'; } /** From d2ad1a899e06440de991c4adb572a6aa6843d3d0 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Mon, 16 Aug 2021 16:01:20 -0400 Subject: [PATCH 06/58] Add response model for boolean attribute --- src/Appwrite/Utopia/Response.php | 1 + .../Response/Model/AttributeBoolean.php | 35 +++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 src/Appwrite/Utopia/Response/Model/AttributeBoolean.php diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index 06c9375d0..3a890f9a5 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -79,6 +79,7 @@ class Response extends SwooleResponse const MODEL_ATTRIBUTE_STRING = 'attributeString'; const MODEL_ATTRIBUTE_INTEGER= 'attributeInteger'; const MODEL_ATTRIBUTE_FLOAT= 'attributeFloat'; + const MODEL_ATTRIBUTE_BOOLEAN= 'attributeBoolean'; const MODEL_ATTRIBUTE_EMAIL= 'attributeEmail'; const MODEL_ATTRIBUTE_IP= 'attributeIp'; const MODEL_ATTRIBUTE_URL= 'attributeUrl'; diff --git a/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php b/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php new file mode 100644 index 000000000..70c089e51 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php @@ -0,0 +1,35 @@ + Date: Mon, 16 Aug 2021 16:06:27 -0400 Subject: [PATCH 07/58] Add default param to attribute response models --- src/Appwrite/Utopia/Response/Model/AttributeBoolean.php | 8 ++++++++ src/Appwrite/Utopia/Response/Model/AttributeEmail.php | 8 ++++++++ src/Appwrite/Utopia/Response/Model/AttributeFloat.php | 8 ++++++++ src/Appwrite/Utopia/Response/Model/AttributeIP.php | 8 ++++++++ src/Appwrite/Utopia/Response/Model/AttributeInteger.php | 8 ++++++++ src/Appwrite/Utopia/Response/Model/AttributeString.php | 8 ++++++++ src/Appwrite/Utopia/Response/Model/AttributeURL.php | 8 ++++++++ 7 files changed, 56 insertions(+) diff --git a/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php b/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php index 70c089e51..93979288e 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php @@ -10,6 +10,14 @@ class AttributeBoolean extends Model public function __construct() { $this + ->addRule('default', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.', + 'default' => null, + 'example' => false, + 'array' => false, + 'required' => false, + ]) ; } diff --git a/src/Appwrite/Utopia/Response/Model/AttributeEmail.php b/src/Appwrite/Utopia/Response/Model/AttributeEmail.php index b0ea0d730..11d068e8f 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeEmail.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeEmail.php @@ -18,6 +18,14 @@ class AttributeEmail extends AttributeString 'array' => false, 'required' => true, ]) + ->addRule('default', [ + 'type' => self::TYPE_STRING, + 'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.', + 'default' => null, + 'example' => 'default@example.com', + 'array' => false, + 'required' => false, + ]) ; } diff --git a/src/Appwrite/Utopia/Response/Model/AttributeFloat.php b/src/Appwrite/Utopia/Response/Model/AttributeFloat.php index 3320582b5..66259cfdb 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeFloat.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeFloat.php @@ -26,6 +26,14 @@ class AttributeFloat extends Attribute 'array' => false, 'required' => false, ]) + ->addRule('default', [ + 'type' => self::TYPE_FLOAT, + 'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.', + 'default' => null, + 'example' => 2.5, + 'array' => false, + 'required' => false, + ]) ; } diff --git a/src/Appwrite/Utopia/Response/Model/AttributeIP.php b/src/Appwrite/Utopia/Response/Model/AttributeIP.php index 19147ce00..a380e6e4d 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeIP.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeIP.php @@ -18,6 +18,14 @@ class AttributeIP extends AttributeString 'array' => false, 'required' => true, ]) + ->addRule('default', [ + 'type' => self::TYPE_STRING, + 'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.', + 'default' => null, + 'example' => '192.0.2.0', + 'array' => false, + 'required' => false, + ]) ; } diff --git a/src/Appwrite/Utopia/Response/Model/AttributeInteger.php b/src/Appwrite/Utopia/Response/Model/AttributeInteger.php index ee65d3a39..3092a7145 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeInteger.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeInteger.php @@ -26,6 +26,14 @@ class AttributeInteger extends Attribute 'array' => false, 'required' => false, ]) + ->addRule('default', [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.', + 'default' => null, + 'example' => 10, + 'array' => false, + 'required' => false, + ]) ; } diff --git a/src/Appwrite/Utopia/Response/Model/AttributeString.php b/src/Appwrite/Utopia/Response/Model/AttributeString.php index e7eb558b6..29a86a4b2 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeString.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeString.php @@ -16,6 +16,14 @@ class AttributeString extends Attribute 'default' => 0, 'example' => 128, ]) + ->addRule('default', [ + 'type' => self::TYPE_STRING, + 'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.', + 'default' => null, + 'example' => 'default', + 'array' => false, + 'required' => false, + ]) ; } diff --git a/src/Appwrite/Utopia/Response/Model/AttributeURL.php b/src/Appwrite/Utopia/Response/Model/AttributeURL.php index d310af131..52a549e2a 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeURL.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeURL.php @@ -18,6 +18,14 @@ class AttributeURL extends AttributeString 'array' => false, 'required' => true, ]) + ->addRule('default', [ + 'type' => self::TYPE_STRING, + 'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.', + 'default' => null, + 'example' => 'http://example.com', + 'array' => false, + 'required' => false, + ]) ; } From 328358654a8691fec9e36c66dfc5306ffebebddc Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Mon, 16 Aug 2021 16:08:18 -0400 Subject: [PATCH 08/58] Instantiate boolean attribute response model --- src/Appwrite/Utopia/Response.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index 3a890f9a5..53d574f47 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -14,6 +14,7 @@ use Appwrite\Utopia\Response\Model\Attribute; use Appwrite\Utopia\Response\Model\AttributeString; use Appwrite\Utopia\Response\Model\AttributeInteger; use Appwrite\Utopia\Response\Model\AttributeFloat; +use Appwrite\Utopia\Response\Model\AttributeBoolean; use Appwrite\Utopia\Response\Model\AttributeEmail; use Appwrite\Utopia\Response\Model\AttributeIP; use Appwrite\Utopia\Response\Model\AttributeURL; @@ -197,6 +198,7 @@ class Response extends SwooleResponse ->setModel(new AttributeString()) ->setModel(new AttributeInteger()) ->setModel(new AttributeFloat()) + ->setModel(new AttributeBoolean()) ->setModel(new AttributeEmail()) ->setModel(new AttributeIP()) ->setModel(new AttributeURL()) From 4c794623139c7cbbb4ab09a8756f5481ae853a56 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Mon, 16 Aug 2021 18:05:52 -0400 Subject: [PATCH 09/58] Create constants for attribute formats --- app/init.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/app/init.php b/app/init.php index 46dafebac..f80606f4c 100644 --- a/app/init.php +++ b/app/init.php @@ -62,6 +62,11 @@ const APP_LIMIT_COUNT = 5000; const APP_LIMIT_USERS = 10000; const APP_CACHE_BUSTER = 151; const APP_VERSION_STABLE = '0.10.0'; +const APP_DATABASE_ATTRIBUTE_EMAIL = 'email'; +const APP_DATABASE_ATTRIBUTE_IP = 'ip'; +const APP_DATABASE_ATTRIBUTE_URL = 'url'; +const APP_DATABASE_ATTRIBUTE_INT_RANGE = 'intRange'; +const APP_DATABASE_ATTRIBUTE_FLOAT_RANGE = 'floatRange'; const APP_STORAGE_UPLOADS = '/storage/uploads'; const APP_STORAGE_FUNCTIONS = '/storage/functions'; const APP_STORAGE_CACHE = '/storage/cache'; @@ -196,19 +201,19 @@ Database2::addFilter('encrypt', } ); -Structure::addFormat('email', function() { +Structure::addFormat(APP_DATABASE_ATTRIBUTE_EMAIL, function() { return new Email(); }, Database2::VAR_STRING); -Structure::addFormat('ip', function() { +Structure::addFormat(APP_DATABASE_ATTRIBUTE_IP, function() { return new IP(); }, Database2::VAR_STRING); -Structure::addFormat('url', function() { +Structure::addFormat(APP_DATABASE_ATTRIBUTE_URL, function() { return new URL(); }, Database2::VAR_STRING); -Structure::addFormat('int-range', function($attribute) { +Structure::addFormat(APP_DATABASE_ATTRIBUTE_INT_RANGE, function($attribute) { // Format encoded as json string containing name and relevant options // E.g. Range: $format = json_encode(['name'=>$name, 'min'=>$min, 'max'=>$max]); $format = json_decode($attribute['format'], true); @@ -218,7 +223,7 @@ Structure::addFormat('int-range', function($attribute) { return new Range($min, $max, $type); }, Database2::VAR_INTEGER); -Structure::addFormat('float-range', function($attribute) { +Structure::addFormat(APP_DATABASE_ATTRIBUTE_FLOAT_RANGE, function($attribute) { // Format encoded as json string containing name and relevant options // E.g. Range: $format = json_encode(['name'=>$name, 'min'=>$min, 'max'=>$max]); $format = json_decode($attribute['format'], true); From 10e42976522cfe721d6511a8c40e88b9bd1c398c Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Mon, 16 Aug 2021 18:59:33 -0400 Subject: [PATCH 10/58] Update attribute response models --- src/Appwrite/Utopia/Response/Model.php | 2 +- .../Utopia/Response/Model/Attribute.php | 2 +- .../Response/Model/AttributeBoolean.php | 2 +- .../Utopia/Response/Model/AttributeEmail.php | 8 +++---- .../Utopia/Response/Model/AttributeFloat.php | 22 +++++++---------- .../Utopia/Response/Model/AttributeIP.php | 8 +++---- .../Response/Model/AttributeInteger.php | 24 ++++++++----------- .../Utopia/Response/Model/AttributeString.php | 2 +- .../Utopia/Response/Model/AttributeURL.php | 6 ++--- 9 files changed, 34 insertions(+), 42 deletions(-) diff --git a/src/Appwrite/Utopia/Response/Model.php b/src/Appwrite/Utopia/Response/Model.php index 7c6aafdbd..73b660963 100644 --- a/src/Appwrite/Utopia/Response/Model.php +++ b/src/Appwrite/Utopia/Response/Model.php @@ -35,7 +35,7 @@ abstract class Model /** * Filter Document Structure * - * @return string + * @return Document */ public function filter(Document $document): Document { diff --git a/src/Appwrite/Utopia/Response/Model/Attribute.php b/src/Appwrite/Utopia/Response/Model/Attribute.php index c25b21da5..33df056a2 100644 --- a/src/Appwrite/Utopia/Response/Model/Attribute.php +++ b/src/Appwrite/Utopia/Response/Model/Attribute.php @@ -39,7 +39,7 @@ class Attribute extends Model 'description' => 'Is attribute an array?', 'default' => false, 'example' => false, - 'required' => false + 'require' => false ]) ; } diff --git a/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php b/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php index 93979288e..17c2e8960 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php @@ -16,7 +16,7 @@ class AttributeBoolean extends Model 'default' => null, 'example' => false, 'array' => false, - 'required' => false, + 'require' => false, ]) ; } diff --git a/src/Appwrite/Utopia/Response/Model/AttributeEmail.php b/src/Appwrite/Utopia/Response/Model/AttributeEmail.php index 11d068e8f..af090b77f 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeEmail.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeEmail.php @@ -13,10 +13,10 @@ class AttributeEmail extends AttributeString ->addRule('format', [ 'type' => self::TYPE_STRING, 'description' => 'String format.', - 'default' => 'email', - 'example' => 'email', + 'default' => \json_encode(['name'=>APP_DATABASE_ATTRIBUTE_EMAIL]), + 'example' => \json_encode(['name'=>APP_DATABASE_ATTRIBUTE_EMAIL]), 'array' => false, - 'required' => true, + 'require' => true, ]) ->addRule('default', [ 'type' => self::TYPE_STRING, @@ -24,7 +24,7 @@ class AttributeEmail extends AttributeString 'default' => null, 'example' => 'default@example.com', 'array' => false, - 'required' => false, + 'require' => false, ]) ; } diff --git a/src/Appwrite/Utopia/Response/Model/AttributeFloat.php b/src/Appwrite/Utopia/Response/Model/AttributeFloat.php index 66259cfdb..ec90cc7ed 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeFloat.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeFloat.php @@ -10,21 +10,17 @@ class AttributeFloat extends Attribute public function __construct() { $this - ->addRule('min', [ + ->addRule('format', [ 'type' => self::TYPE_FLOAT, - 'description' => 'Minimum value to enforce on new documents.', + 'description' => 'Float format.', 'default' => null, - 'example' => 0.5, + 'example' => \json_encode([ + 'name' => APP_DATABASE_ATTRIBUTE_FLOAT_RANGE, + 'min' => 1.5, + 'max' => 2.5, + ]), 'array' => false, - 'required' => false, - ]) - ->addRule('max', [ - 'type' => self::TYPE_FLOAT, - 'description' => 'Minimum value to enforce on new documents.', - 'default' => null, - 'example' => 2.5, - 'array' => false, - 'required' => false, + 'require' => false, ]) ->addRule('default', [ 'type' => self::TYPE_FLOAT, @@ -32,7 +28,7 @@ class AttributeFloat extends Attribute 'default' => null, 'example' => 2.5, 'array' => false, - 'required' => false, + 'require' => false, ]) ; } diff --git a/src/Appwrite/Utopia/Response/Model/AttributeIP.php b/src/Appwrite/Utopia/Response/Model/AttributeIP.php index a380e6e4d..ef6f5b4db 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeIP.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeIP.php @@ -13,10 +13,10 @@ class AttributeIP extends AttributeString ->addRule('format', [ 'type' => self::TYPE_STRING, 'description' => 'String format.', - 'default' => 'ip', - 'example' => 'ip', + 'default' => \json_encode(['name'=>APP_DATABASE_ATTRIBUTE_IP]), + 'example' => \json_encode(['name'=>APP_DATABASE_ATTRIBUTE_IP]), 'array' => false, - 'required' => true, + 'require' => true, ]) ->addRule('default', [ 'type' => self::TYPE_STRING, @@ -24,7 +24,7 @@ class AttributeIP extends AttributeString 'default' => null, 'example' => '192.0.2.0', 'array' => false, - 'required' => false, + 'require' => false, ]) ; } diff --git a/src/Appwrite/Utopia/Response/Model/AttributeInteger.php b/src/Appwrite/Utopia/Response/Model/AttributeInteger.php index 3092a7145..161a9cb9b 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeInteger.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeInteger.php @@ -10,21 +10,17 @@ class AttributeInteger extends Attribute public function __construct() { $this - ->addRule('min', [ - 'type' => self::TYPE_INTEGER, - 'description' => 'Minimum value to enforce on new documents.', + ->addRule('format', [ + 'type' => self::TYPE_STRING, + 'description' => 'Integer format.', 'default' => null, - 'example' => 0, + 'example' => \json_encode([ + 'name' => APP_DATABASE_ATTRIBUTE_INT_RANGE, + 'min' => 0, + 'max' => 10, + ]), 'array' => false, - 'required' => false, - ]) - ->addRule('max', [ - 'type' => self::TYPE_INTEGER, - 'description' => 'Minimum value to enforce on new documents.', - 'default' => null, - 'example' => 10, - 'array' => false, - 'required' => false, + 'require' => false, ]) ->addRule('default', [ 'type' => self::TYPE_INTEGER, @@ -32,7 +28,7 @@ class AttributeInteger extends Attribute 'default' => null, 'example' => 10, 'array' => false, - 'required' => false, + 'require' => false, ]) ; } diff --git a/src/Appwrite/Utopia/Response/Model/AttributeString.php b/src/Appwrite/Utopia/Response/Model/AttributeString.php index 29a86a4b2..9dd4b1829 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeString.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeString.php @@ -22,7 +22,7 @@ class AttributeString extends Attribute 'default' => null, 'example' => 'default', 'array' => false, - 'required' => false, + 'require' => false, ]) ; } diff --git a/src/Appwrite/Utopia/Response/Model/AttributeURL.php b/src/Appwrite/Utopia/Response/Model/AttributeURL.php index 52a549e2a..20e7f09fa 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeURL.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeURL.php @@ -13,8 +13,8 @@ class AttributeURL extends AttributeString ->addRule('format', [ 'type' => self::TYPE_STRING, 'description' => 'String format.', - 'default' => 'url', - 'example' => 'url', + 'default' => \json_encode(['name'=>APP_DATABASE_ATTRIBUTE_URL]), + 'example' => \json_encode(['name'=>APP_DATABASE_ATTRIBUTE_URL]), 'array' => false, 'required' => true, ]) @@ -24,7 +24,7 @@ class AttributeURL extends AttributeString 'default' => null, 'example' => 'http://example.com', 'array' => false, - 'required' => false, + 'require' => false, ]) ; } From 8f24d121f5752abebf4e5a097a0be19dc7385495 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Mon, 16 Aug 2021 19:21:00 -0400 Subject: [PATCH 11/58] Validate attributes and responses --- app/controllers/api/database.php | 186 ++++++++++++++++++++----------- 1 file changed, 120 insertions(+), 66 deletions(-) diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index 75eab3714..f3e766341 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -1,6 +1,5 @@ getCollection(); $attributeId = $attribute->getId(); $type = $attribute->getAttribute('type', ''); $size = $attribute->getAttribute('size', 0); $required = $attribute->getAttribute('required', true); $default = $attribute->getAttribute('default', null); - $min = $attribute->getAttribute('min', null); - $max = $attribute->getAttribute('max', null); $signed = $attribute->getAttribute('signed', true); // integers are signed by default $array = $attribute->getAttribute('array', false); $format = $attribute->getAttribute('format', null); @@ -51,15 +58,6 @@ $attributesCallback = function ($attribute, $response, $dbForExternal, $database throw new Exception('Collection not found', 404); } - // TODO@kodumbeats how to depend on $size for Text validator length - // Ensure attribute default is within required size - if ($size > 0 && !\is_null($default)) { - $validator = new Text($size); - if (!$validator->isValid($default)) { - throw new Exception('Length of default attribute exceeds attribute size', 400); - } - } - if (!\is_null($format)) { $name = \json_decode($format, true)['name']; if (!Structure::hasFormat($name, $type)) { @@ -67,23 +65,6 @@ $attributesCallback = function ($attribute, $response, $dbForExternal, $database } } - if (!is_null($min) || !is_null($max)) { // Add range validator if either $min or $max is provided - switch ($type) { - case Database::VAR_INTEGER: - $min = (is_null($min)) ? -INF : \intval($min); - $max = (is_null($max)) ? INF : \intval($max); - $format = 'int-range'; - break; - case Database::VAR_FLOAT: - $min = (is_null($min)) ? -INF : \floatval($min); - $max = (is_null($max)) ? INF : \floatval($max); - $format = 'float-range'; - break; - default: - throw new Exception("Format range not available for {$type} attributes.", 400); - } - } - $success = $dbForExternal->addAttributeInQueue($collectionId, $attributeId, $type, $size, $required, $default, $signed, $array, $format, $filters); // Database->addAttributeInQueue() does not return a document @@ -97,8 +78,6 @@ $attributesCallback = function ($attribute, $response, $dbForExternal, $database 'size' => $size, 'required' => $required, 'default' => $default, - 'min' => $min, - 'max' => $max, 'signed' => $signed, 'array' => $array, 'format' => $format, @@ -117,7 +96,8 @@ $attributesCallback = function ($attribute, $response, $dbForExternal, $database ; $response->setStatusCode(Response::STATUS_CODE_CREATED); - $response->dynamic($attribute, Response::MODEL_ATTRIBUTE); + + return $attribute; }; App::post('/v1/database/collections') @@ -344,13 +324,19 @@ App::post('/v1/database/collections/:collectionId/attributes/string') ->inject('dbForExternal') ->inject('database') ->inject('audits') - ->action(function ($collectionId, $attributeId, $size, $required, $default, $array, $response, $dbForExternal, $database, $audits) use ($attributesCallback) { + ->action(function ($collectionId, $attributeId, $size, $required, $default, $array, $response, $dbForExternal, $database, $audits) { /** @var Appwrite\Utopia\Response $response */ /** @var Utopia\Database\Database $dbForExternal*/ /** @var Appwrite\Event\Event $database */ /** @var Appwrite\Event\Event $audits */ - return $attributesCallback(new Document([ + // Ensure attribute default is within required size + $validator = new Text($size); + if (!is_null($default) && !$validator->isValid($default)) { + throw new Exception($validator->getDescription(), 400); + } + + $attribute = attributesCallback(new Document([ '$collection' => $collectionId, '$id' => $attributeId, 'type' => Database::VAR_STRING, @@ -359,6 +345,8 @@ App::post('/v1/database/collections/:collectionId/attributes/string') 'default' => $default, 'array' => $array, ]), $response, $dbForExternal, $database, $audits); + + $response->dynamic($attribute, Response::MODEL_ATTRIBUTE_STRING); }); App::post('/v1/database/collections/:collectionId/attributes/email') @@ -382,13 +370,19 @@ App::post('/v1/database/collections/:collectionId/attributes/email') ->inject('dbForExternal') ->inject('database') ->inject('audits') - ->action(function ($collectionId, $attributeId, $required, $default, $array, $response, $dbForExternal, $database, $audits) use ($attributesCallback) { + ->action(function ($collectionId, $attributeId, $required, $default, $array, $response, $dbForExternal, $database, $audits) { /** @var Appwrite\Utopia\Response $response */ /** @var Utopia\Database\Database $dbForExternal*/ /** @var Appwrite\Event\Event $database */ /** @var Appwrite\Event\Event $audits */ - return $attributesCallback(new Document([ + // Ensure attribute default is valid email + $validator = new Email(); + if (!is_null($default) && !$validator->isValid($default)) { + throw new Exception($validator->getDescription(), 400); + } + + $attribute = attributesCallback(new Document([ '$collection' => $collectionId, '$id' => $attributeId, 'type' => Database::VAR_STRING, @@ -396,8 +390,10 @@ App::post('/v1/database/collections/:collectionId/attributes/email') 'required' => $required, 'default' => $default, 'array' => $array, - 'format' => \json_encode(['name'=>'email']), + 'format' => \json_encode(['name'=> APP_DATABASE_ATTRIBUTE_EMAIL]), ]), $response, $dbForExternal, $database, $audits); + + $response->dynamic($attribute, Response::MODEL_ATTRIBUTE_EMAIL); }); App::post('/v1/database/collections/:collectionId/attributes/ip') @@ -421,13 +417,19 @@ App::post('/v1/database/collections/:collectionId/attributes/ip') ->inject('dbForExternal') ->inject('database') ->inject('audits') - ->action(function ($collectionId, $attributeId, $required, $default, $array, $response, $dbForExternal, $database, $audits) use ($attributesCallback) { + ->action(function ($collectionId, $attributeId, $required, $default, $array, $response, $dbForExternal, $database, $audits) { /** @var Appwrite\Utopia\Response $response */ /** @var Utopia\Database\Database $dbForExternal*/ /** @var Appwrite\Event\Event $database */ /** @var Appwrite\Event\Event $audits */ - return $attributesCallback(new Document([ + // Ensure attribute default is valid IP address + $validator = new IP(); + if (!is_null($default) && !$validator->isValid($default)) { + throw new Exception($validator->getDescription(), 400); + } + + $attribute = attributesCallback(new Document([ '$collection' => $collectionId, '$id' => $attributeId, 'type' => Database::VAR_STRING, @@ -435,8 +437,10 @@ App::post('/v1/database/collections/:collectionId/attributes/ip') 'required' => $required, 'default' => $default, 'array' => $array, - 'format' => \json_encode(['name'=>'ip']), + 'format' => \json_encode(['name'=> APP_DATABASE_ATTRIBUTE_IP]), ]), $response, $dbForExternal, $database, $audits); + + $response->dynamic($attribute, Response::MODEL_ATTRIBUTE_IP); }); App::post('/v1/database/collections/:collectionId/attributes/url') @@ -461,13 +465,19 @@ App::post('/v1/database/collections/:collectionId/attributes/url') ->inject('dbForExternal') ->inject('database') ->inject('audits') - ->action(function ($collectionId, $attributeId, $size, $required, $default, $array, $response, $dbForExternal, $database, $audits) use ($attributesCallback) { + ->action(function ($collectionId, $attributeId, $size, $required, $default, $array, $response, $dbForExternal, $database, $audits) { /** @var Appwrite\Utopia\Response $response */ /** @var Utopia\Database\Database $dbForExternal*/ /** @var Appwrite\Event\Event $database */ /** @var Appwrite\Event\Event $audits */ - return $attributesCallback(new Document([ + // Ensure attribute default is valid URL + $validator = new URL(); + if (!is_null($default) && !$validator->isValid($default)) { + throw new Exception($validator->getDescription(), 400); + } + + $attribute = attributesCallback(new Document([ '$collection' => $collectionId, '$id' => $attributeId, 'type' => Database::VAR_STRING, @@ -475,8 +485,10 @@ App::post('/v1/database/collections/:collectionId/attributes/url') 'required' => $required, 'default' => $default, 'array' => $array, - 'format' => \json_encode(['name'=>'url']), + 'format' => \json_encode(['name'=> APP_DATABASE_ATTRIBUTE_URL]), ]), $response, $dbForExternal, $database, $audits); + + $response->dynamic($attribute, Response::MODEL_ATTRIBUTE_URL); }); App::post('/v1/database/collections/:collectionId/attributes/integer') @@ -502,13 +514,23 @@ App::post('/v1/database/collections/:collectionId/attributes/integer') ->inject('dbForExternal') ->inject('database') ->inject('audits') - ->action(function ($collectionId, $attributeId, $required, $min, $max, $default, $array, $response, $dbForExternal, $database, $audits) use ($attributesCallback) { + ->action(function ($collectionId, $attributeId, $required, $min, $max, $default, $array, $response, $dbForExternal, $database, $audits) { /** @var Appwrite\Utopia\Response $response */ /** @var Utopia\Database\Database $dbForExternal*/ /** @var Appwrite\Event\Event $database */ /** @var Appwrite\Event\Event $audits */ - return $attributesCallback(new Document([ + // Ensure attribute default is within range + $format = (\is_null($min) || \is_null($max)); // whether to apply range format + $min = \is_null($min) ? -INF : \intval($min); + $max = \is_null($max) ? INF : \intval($max); + $validator = new Range($min, $max, Database::VAR_INTEGER); + + if (!is_null($default) && !$validator->isValid($default)) { + throw new Exception($validator->getDescription(), 400); + } + + $attribute = attributesCallback(new Document([ '$collection' => $collectionId, '$id' => $attributeId, 'type' => Database::VAR_INTEGER, @@ -516,12 +538,14 @@ App::post('/v1/database/collections/:collectionId/attributes/integer') 'required' => $required, 'default' => $default, 'array' => $array, - 'format' => \json_encode([ - 'name'=>'int-range', + 'format' => ($format) ? \json_encode([ + 'name'=> APP_DATABASE_ATTRIBUTE_INT_RANGE, 'min' => $min, 'max' => $max, - ]), + ]) : null, ]), $response, $dbForExternal, $database, $audits); + + $response->dynamic($attribute, Response::MODEL_ATTRIBUTE_INTEGER); }); App::post('/v1/database/collections/:collectionId/attributes/float') @@ -547,13 +571,23 @@ App::post('/v1/database/collections/:collectionId/attributes/float') ->inject('dbForExternal') ->inject('database') ->inject('audits') - ->action(function ($collectionId, $attributeId, $required, $min, $max, $default, $array, $response, $dbForExternal, $database, $audits) use ($attributesCallback) { + ->action(function ($collectionId, $attributeId, $required, $min, $max, $default, $array, $response, $dbForExternal, $database, $audits) { /** @var Appwrite\Utopia\Response $response */ /** @var Utopia\Database\Database $dbForExternal*/ /** @var Appwrite\Event\Event $database */ /** @var Appwrite\Event\Event $audits */ - return $attributesCallback(new Document([ + // Ensure attribute default is within range + $format = (\is_null($min) || \is_null($max)); // whether to apply range format + $min = \is_null($min) ? -INF : \floatval($min); + $max = \is_null($max) ? INF : \floatval($max); + $validator = new Range($min, $max, Database::VAR_FLOAT); + + if (!is_null($default) && !$validator->isValid($default)) { + throw new Exception($validator->getDescription(), 400); + } + + $attribute = attributesCallback(new Document([ '$collection' => $collectionId, '$id' => $attributeId, 'type' => Database::VAR_FLOAT, @@ -561,12 +595,14 @@ App::post('/v1/database/collections/:collectionId/attributes/float') 'size' => 0, 'default' => $default, 'array' => $array, - 'format' => \json_encode([ - 'name'=>'float-range', + 'format' => ($format) ? \json_encode([ + 'name'=> APP_DATABASE_ATTRIBUTE_FLOAT_RANGE, 'min' => $min, 'max' => $max, - ]), + ]) : null, ]), $response, $dbForExternal, $database, $audits); + + $response->dynamic($attribute, Response::MODEL_ATTRIBUTE_FLOAT); }); App::post('/v1/database/collections/:collectionId/attributes/boolean') @@ -590,13 +626,13 @@ App::post('/v1/database/collections/:collectionId/attributes/boolean') ->inject('dbForExternal') ->inject('database') ->inject('audits') - ->action(function ($collectionId, $attributeId, $required, $default, $array, $response, $dbForExternal, $database, $audits) use ($attributesCallback) { + ->action(function ($collectionId, $attributeId, $required, $default, $array, $response, $dbForExternal, $database, $audits) { /** @var Appwrite\Utopia\Response $response */ /** @var Utopia\Database\Database $dbForExternal*/ /** @var Appwrite\Event\Event $database */ /** @var Appwrite\Event\Event $audits */ - return $attributesCallback(new Document([ + $attribute = attributesCallback(new Document([ '$collection' => $collectionId, '$id' => $attributeId, 'type' => Database::VAR_BOOLEAN, @@ -605,6 +641,8 @@ App::post('/v1/database/collections/:collectionId/attributes/boolean') 'default' => $default, 'array' => $array, ]), $response, $dbForExternal, $database, $audits); + + $response->dynamic($attribute, Response::MODEL_ATTRIBUTE_BOOLEAN); }); App::get('/v1/database/collections/:collectionId/attributes') @@ -682,8 +720,24 @@ App::get('/v1/database/collections/:collectionId/attributes/:attributeId') $attribute = new Document([\array_merge($attributes[$attributeIndex], [ 'collectionId' => $collectionId, ])]); + + $type = $attribute->getAttribute('type'); + $format = json_decode($attribute->getAttribute('format'), true); + + $model = match($type) { + Database::VAR_BOOLEAN => Response::MODEL_ATTRIBUTE_BOOLEAN, + Database::VAR_INTEGER => Response::MODEL_ATTRIBUTE_INTEGER, + Database::VAR_FLOAT => Response::MODEL_ATTRIBUTE_FLOAT, + Database::VAR_STRING => match($format['name']) { + APP_DATABASE_ATTRIBUTE_URL => Response::MODEL_ATTRIBUTE_EMAIL, + APP_DATABASE_ATTRIBUTE_IP => Response::MODEL_ATTRIBUTE_IP, + APP_DATABASE_ATTRIBUTE_URL => Response::MODEL_ATTRIBUTE_URL, + default => Response::MODEL_ATTRIBUTE_STRING, + }, + default => Response::MODEL_ATTRIBUTE, + }; - $response->dynamic($attribute, Response::MODEL_ATTRIBUTE); + $response->dynamic($attribute, $model); }); App::delete('/v1/database/collections/:collectionId/attributes/:attributeId') From 19e144346986b82a4160f627e7541227abde5cd8 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Mon, 23 Aug 2021 15:06:47 -0400 Subject: [PATCH 12/58] Fix breaking bugs introduced in merge conflict resolution --- app/init.php | 1 - src/Appwrite/Utopia/Response/Model/Attribute.php | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/app/init.php b/app/init.php index e84317b6c..4d999b7a4 100644 --- a/app/init.php +++ b/app/init.php @@ -230,7 +230,6 @@ Database::addFilter('encrypt', * DB Formats */ Structure::addFormat(APP_DATABASE_ATTRIBUTE_EMAIL, function() { -Structure::addFormat('email', function() { return new Email(); }, Database::VAR_STRING); diff --git a/src/Appwrite/Utopia/Response/Model/Attribute.php b/src/Appwrite/Utopia/Response/Model/Attribute.php index f88b5ac4e..cc5c2a7f8 100644 --- a/src/Appwrite/Utopia/Response/Model/Attribute.php +++ b/src/Appwrite/Utopia/Response/Model/Attribute.php @@ -63,3 +63,4 @@ class Attribute extends Model { return Response::MODEL_ATTRIBUTE; } +} From 0eb0ceb6d593ef3d1529ee6ab708ee9f880f0710 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Mon, 23 Aug 2021 17:25:32 -0400 Subject: [PATCH 13/58] Explicitly add attribute model rules --- .../Response/Model/AttributeBoolean.php | 31 ++++++++++++++++ .../Utopia/Response/Model/AttributeEmail.php | 35 +++++++++++++++++-- .../Utopia/Response/Model/AttributeFloat.php | 31 ++++++++++++++++ .../Utopia/Response/Model/AttributeIP.php | 35 +++++++++++++++++-- .../Response/Model/AttributeInteger.php | 31 ++++++++++++++++ .../Utopia/Response/Model/AttributeString.php | 31 ++++++++++++++++ .../Utopia/Response/Model/AttributeURL.php | 35 +++++++++++++++++-- 7 files changed, 223 insertions(+), 6 deletions(-) diff --git a/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php b/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php index 17c2e8960..93dbe5725 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php @@ -10,6 +10,37 @@ class AttributeBoolean extends Model public function __construct() { $this + ->addRule('key', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute Key.', + 'default' => '', + 'example' => 'fullName', + ]) + ->addRule('type', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute type.', + 'default' => '', + 'example' => 'string', + ]) + ->addRule('status', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute status. Possible values: `available`, `processing`, `deleting`, or `failed`', + 'default' => '', + 'example' => 'string', + ]) + ->addRule('required', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Is attribute required?', + 'default' => false, + 'example' => true, + ]) + ->addRule('array', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Is attribute an array?', + 'default' => false, + 'example' => false, + 'require' => false + ]) ->addRule('default', [ 'type' => self::TYPE_BOOLEAN, 'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.', diff --git a/src/Appwrite/Utopia/Response/Model/AttributeEmail.php b/src/Appwrite/Utopia/Response/Model/AttributeEmail.php index af090b77f..861356df3 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeEmail.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeEmail.php @@ -10,11 +10,42 @@ class AttributeEmail extends AttributeString public function __construct() { $this + ->addRule('key', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute Key.', + 'default' => '', + 'example' => 'fullName', + ]) + ->addRule('type', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute type.', + 'default' => '', + 'example' => 'string', + ]) + ->addRule('status', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute status. Possible values: `available`, `processing`, `deleting`, or `failed`', + 'default' => '', + 'example' => 'string', + ]) + ->addRule('required', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Is attribute required?', + 'default' => false, + 'example' => true, + ]) + ->addRule('array', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Is attribute an array?', + 'default' => false, + 'example' => false, + 'require' => false + ]) ->addRule('format', [ 'type' => self::TYPE_STRING, 'description' => 'String format.', - 'default' => \json_encode(['name'=>APP_DATABASE_ATTRIBUTE_EMAIL]), - 'example' => \json_encode(['name'=>APP_DATABASE_ATTRIBUTE_EMAIL]), + 'default' => APP_DATABASE_ATTRIBUTE_EMAIL, + 'example' => APP_DATABASE_ATTRIBUTE_EMAIL, 'array' => false, 'require' => true, ]) diff --git a/src/Appwrite/Utopia/Response/Model/AttributeFloat.php b/src/Appwrite/Utopia/Response/Model/AttributeFloat.php index ec90cc7ed..85adbe285 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeFloat.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeFloat.php @@ -10,6 +10,37 @@ class AttributeFloat extends Attribute public function __construct() { $this + ->addRule('key', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute Key.', + 'default' => '', + 'example' => 'fullName', + ]) + ->addRule('type', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute type.', + 'default' => '', + 'example' => 'string', + ]) + ->addRule('status', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute status. Possible values: `available`, `processing`, `deleting`, or `failed`', + 'default' => '', + 'example' => 'string', + ]) + ->addRule('required', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Is attribute required?', + 'default' => false, + 'example' => true, + ]) + ->addRule('array', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Is attribute an array?', + 'default' => false, + 'example' => false, + 'require' => false + ]) ->addRule('format', [ 'type' => self::TYPE_FLOAT, 'description' => 'Float format.', diff --git a/src/Appwrite/Utopia/Response/Model/AttributeIP.php b/src/Appwrite/Utopia/Response/Model/AttributeIP.php index ef6f5b4db..36e000e15 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeIP.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeIP.php @@ -10,11 +10,42 @@ class AttributeIP extends AttributeString public function __construct() { $this + ->addRule('key', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute Key.', + 'default' => '', + 'example' => 'fullName', + ]) + ->addRule('type', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute type.', + 'default' => '', + 'example' => 'string', + ]) + ->addRule('status', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute status. Possible values: `available`, `processing`, `deleting`, or `failed`', + 'default' => '', + 'example' => 'string', + ]) + ->addRule('required', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Is attribute required?', + 'default' => false, + 'example' => true, + ]) + ->addRule('array', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Is attribute an array?', + 'default' => false, + 'example' => false, + 'require' => false + ]) ->addRule('format', [ 'type' => self::TYPE_STRING, 'description' => 'String format.', - 'default' => \json_encode(['name'=>APP_DATABASE_ATTRIBUTE_IP]), - 'example' => \json_encode(['name'=>APP_DATABASE_ATTRIBUTE_IP]), + 'default' => APP_DATABASE_ATTRIBUTE_IP, + 'example' => APP_DATABASE_ATTRIBUTE_IP, 'array' => false, 'require' => true, ]) diff --git a/src/Appwrite/Utopia/Response/Model/AttributeInteger.php b/src/Appwrite/Utopia/Response/Model/AttributeInteger.php index 161a9cb9b..366ecd556 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeInteger.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeInteger.php @@ -10,6 +10,37 @@ class AttributeInteger extends Attribute public function __construct() { $this + ->addRule('key', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute Key.', + 'default' => '', + 'example' => 'fullName', + ]) + ->addRule('type', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute type.', + 'default' => '', + 'example' => 'string', + ]) + ->addRule('status', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute status. Possible values: `available`, `processing`, `deleting`, or `failed`', + 'default' => '', + 'example' => 'string', + ]) + ->addRule('required', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Is attribute required?', + 'default' => false, + 'example' => true, + ]) + ->addRule('array', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Is attribute an array?', + 'default' => false, + 'example' => false, + 'require' => false + ]) ->addRule('format', [ 'type' => self::TYPE_STRING, 'description' => 'Integer format.', diff --git a/src/Appwrite/Utopia/Response/Model/AttributeString.php b/src/Appwrite/Utopia/Response/Model/AttributeString.php index 9dd4b1829..e8d156039 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeString.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeString.php @@ -10,6 +10,37 @@ class AttributeString extends Attribute public function __construct() { $this + ->addRule('key', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute Key.', + 'default' => '', + 'example' => 'fullName', + ]) + ->addRule('type', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute type.', + 'default' => '', + 'example' => 'string', + ]) + ->addRule('status', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute status. Possible values: `available`, `processing`, `deleting`, or `failed`', + 'default' => '', + 'example' => 'string', + ]) + ->addRule('required', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Is attribute required?', + 'default' => false, + 'example' => true, + ]) + ->addRule('array', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Is attribute an array?', + 'default' => false, + 'example' => false, + 'require' => false + ]) ->addRule('size', [ 'type' => self::TYPE_STRING, 'description' => 'Attribute size.', diff --git a/src/Appwrite/Utopia/Response/Model/AttributeURL.php b/src/Appwrite/Utopia/Response/Model/AttributeURL.php index 20e7f09fa..0d3365f3a 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeURL.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeURL.php @@ -10,11 +10,42 @@ class AttributeURL extends AttributeString public function __construct() { $this + ->addRule('key', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute Key.', + 'default' => '', + 'example' => 'fullName', + ]) + ->addRule('type', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute type.', + 'default' => '', + 'example' => 'string', + ]) + ->addRule('status', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute status. Possible values: `available`, `processing`, `deleting`, or `failed`', + 'default' => '', + 'example' => 'string', + ]) + ->addRule('required', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Is attribute required?', + 'default' => false, + 'example' => true, + ]) + ->addRule('array', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Is attribute an array?', + 'default' => false, + 'example' => false, + 'require' => false + ]) ->addRule('format', [ 'type' => self::TYPE_STRING, 'description' => 'String format.', - 'default' => \json_encode(['name'=>APP_DATABASE_ATTRIBUTE_URL]), - 'example' => \json_encode(['name'=>APP_DATABASE_ATTRIBUTE_URL]), + 'default' => APP_DATABASE_ATTRIBUTE_URL, + 'example' => APP_DATABASE_ATTRIBUTE_URL, 'array' => false, 'required' => true, ]) From ebcd1b23b6ad063a6dfab2da4a120b5bd49828ed Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Mon, 23 Aug 2021 17:29:05 -0400 Subject: [PATCH 14/58] Size not returned for integer attributes --- tests/e2e/Services/Database/DatabaseBase.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/e2e/Services/Database/DatabaseBase.php b/tests/e2e/Services/Database/DatabaseBase.php index 3e109ca33..a097777f5 100644 --- a/tests/e2e/Services/Database/DatabaseBase.php +++ b/tests/e2e/Services/Database/DatabaseBase.php @@ -73,7 +73,6 @@ trait DatabaseBase $this->assertEquals($releaseYear['headers']['status-code'], 201); $this->assertEquals($releaseYear['body']['key'], 'releaseYear'); $this->assertEquals($releaseYear['body']['type'], 'integer'); - $this->assertEquals($releaseYear['body']['size'], 0); $this->assertEquals($releaseYear['body']['required'], true); $this->assertEquals($actors['headers']['status-code'], 201); From 741779cdb88c0feaf38bd03773424aae8f27f4cf Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Mon, 23 Aug 2021 17:33:57 -0400 Subject: [PATCH 15/58] Do not throw exception if rule default is null but not required --- src/Appwrite/Utopia/Response.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index 53d574f47..1c73ac14c 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -325,7 +325,7 @@ class Response extends SwooleResponse $document = $model->filter($document); foreach ($model->getRules() as $key => $rule) { - if (!$document->isSet($key)) { + if (!$document->isSet($key) && $rule['require']) { // do not set attribute in response if not required if (!is_null($rule['default'])) { $document->setAttribute($key, $rule['default']); } else { From 4b0dc9dab31808462dbaac0453c533a738c56d4d Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Tue, 24 Aug 2021 09:46:41 -0400 Subject: [PATCH 16/58] Use param validation from framework --- app/controllers/api/database.php | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index e15b472b1..317528733 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -500,7 +500,7 @@ App::post('/v1/database/collections/:collectionId/attributes/email') ->param('collectionId', '', new UID(), 'Collection unique ID. You can create a new collection using the Database service [server integration](/docs/server/database#createCollection).') ->param('attributeId', '', new Key(), 'Attribute ID.') ->param('required', null, new Boolean(), 'Is attribute required?') - ->param('default', null, new Text(0), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true) + ->param('default', null, new Email(), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true) ->param('array', false, new Boolean(), 'Is attribute an array?', true) ->inject('response') ->inject('dbForInternal') @@ -512,12 +512,6 @@ App::post('/v1/database/collections/:collectionId/attributes/email') /** @var Appwrite\Event\Event $database */ /** @var Appwrite\Event\Event $audits */ - // Ensure attribute default is valid email - $validator = new Email(); - if (!is_null($default) && !$validator->isValid($default)) { - throw new Exception($validator->getDescription(), 400); - } - $attribute = attributesCallback($collectionId, new Document([ '$id' => $attributeId, 'type' => Database::VAR_STRING, @@ -546,7 +540,7 @@ App::post('/v1/database/collections/:collectionId/attributes/ip') ->param('collectionId', '', new UID(), 'Collection unique ID. You can create a new collection using the Database service [server integration](/docs/server/database#createCollection).') ->param('attributeId', '', new Key(), 'Attribute ID.') ->param('required', null, new Boolean(), 'Is attribute required?') - ->param('default', null, new Text(0), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true) + ->param('default', null, new IP(), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true) ->param('array', false, new Boolean(), 'Is attribute an array?', true) ->inject('response') ->inject('dbForInternal') @@ -558,12 +552,6 @@ App::post('/v1/database/collections/:collectionId/attributes/ip') /** @var Appwrite\Event\Event $database */ /** @var Appwrite\Event\Event $audits */ - // Ensure attribute default is valid IP address - $validator = new IP(); - if (!is_null($default) && !$validator->isValid($default)) { - throw new Exception($validator->getDescription(), 400); - } - $attribute = attributesCallback($collectionId, new Document([ '$id' => $attributeId, 'type' => Database::VAR_STRING, @@ -592,7 +580,7 @@ App::post('/v1/database/collections/:collectionId/attributes/url') ->param('collectionId', '', new UID(), 'Collection unique ID. You can create a new collection using the Database service [server integration](/docs/server/database#createCollection).') ->param('attributeId', '', new Key(), 'Attribute ID.') ->param('required', null, new Boolean(), 'Is attribute required?') - ->param('default', null, new Text(0), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true) + ->param('default', null, new URL(), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true) ->param('array', false, new Boolean(), 'Is attribute an array?', true) ->inject('response') ->inject('dbForInternal') @@ -604,12 +592,6 @@ App::post('/v1/database/collections/:collectionId/attributes/url') /** @var Appwrite\Event\Event $database */ /** @var Appwrite\Event\Event $audits */ - // Ensure attribute default is valid URL - $validator = new URL(); - if (!is_null($default) && !$validator->isValid($default)) { - throw new Exception($validator->getDescription(), 400); - } - $attribute = attributesCallback($collectionId, new Document([ '$id' => $attributeId, 'type' => Database::VAR_STRING, From c4cb72731e8cf0eadce93df13bd593bf7c6db92a Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Tue, 24 Aug 2021 09:49:58 -0400 Subject: [PATCH 17/58] Refactor attributeCallback to function createAttribute --- app/controllers/api/database.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index 317528733..2dd5c3f0e 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -42,7 +42,7 @@ use DeviceDetector\DeviceDetector; * * @return Document Newly created attribute document */ -function attributesCallback($collectionId, $attribute, $response, $dbForInternal, $database, $audits): Document +function createAttribute($collectionId, $attribute, $response, $dbForInternal, $database, $audits): Document { $attributeId = $attribute->getId(); @@ -473,7 +473,7 @@ App::post('/v1/database/collections/:collectionId/attributes/string') throw new Exception($validator->getDescription(), 400); } - $attribute = attributesCallback($collectionId, new Document([ + $attribute = createAttribute($collectionId, new Document([ '$id' => $attributeId, 'type' => Database::VAR_STRING, 'size' => $size, @@ -512,7 +512,7 @@ App::post('/v1/database/collections/:collectionId/attributes/email') /** @var Appwrite\Event\Event $database */ /** @var Appwrite\Event\Event $audits */ - $attribute = attributesCallback($collectionId, new Document([ + $attribute = createAttribute($collectionId, new Document([ '$id' => $attributeId, 'type' => Database::VAR_STRING, 'size' => 254, @@ -552,7 +552,7 @@ App::post('/v1/database/collections/:collectionId/attributes/ip') /** @var Appwrite\Event\Event $database */ /** @var Appwrite\Event\Event $audits */ - $attribute = attributesCallback($collectionId, new Document([ + $attribute = createAttribute($collectionId, new Document([ '$id' => $attributeId, 'type' => Database::VAR_STRING, 'size' => 39, @@ -592,7 +592,7 @@ App::post('/v1/database/collections/:collectionId/attributes/url') /** @var Appwrite\Event\Event $database */ /** @var Appwrite\Event\Event $audits */ - $attribute = attributesCallback($collectionId, new Document([ + $attribute = createAttribute($collectionId, new Document([ '$id' => $attributeId, 'type' => Database::VAR_STRING, 'size' => 2000, @@ -643,7 +643,7 @@ App::post('/v1/database/collections/:collectionId/attributes/integer') throw new Exception($validator->getDescription(), 400); } - $attribute = attributesCallback($collectionId, new Document([ + $attribute = createAttribute($collectionId, new Document([ '$id' => $attributeId, 'type' => Database::VAR_INTEGER, 'size' => 0, @@ -698,7 +698,7 @@ App::post('/v1/database/collections/:collectionId/attributes/float') throw new Exception($validator->getDescription(), 400); } - $attribute = attributesCallback($collectionId, new Document([ + $attribute = createAttribute($collectionId, new Document([ '$id' => $attributeId, 'type' => Database::VAR_FLOAT, 'required' => $required, @@ -742,7 +742,7 @@ App::post('/v1/database/collections/:collectionId/attributes/boolean') /** @var Appwrite\Event\Event $database */ /** @var Appwrite\Event\Event $audits */ - $attribute = attributesCallback($collectionId, new Document([ + $attribute = createAttribute($collectionId, new Document([ '$id' => $attributeId, 'type' => Database::VAR_BOOLEAN, 'size' => 0, From af2e64ef7b65b7852b3be8bc83135c57d9c2713a Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Tue, 24 Aug 2021 10:31:02 -0400 Subject: [PATCH 18/58] Construct parent models to properly inherit rules --- .../Response/Model/AttributeBoolean.php | 37 ++----------------- .../Utopia/Response/Model/AttributeEmail.php | 33 +---------------- .../Utopia/Response/Model/AttributeFloat.php | 33 +---------------- .../Utopia/Response/Model/AttributeIP.php | 33 +---------------- .../Response/Model/AttributeInteger.php | 36 ++---------------- .../Utopia/Response/Model/AttributeString.php | 33 +---------------- .../Utopia/Response/Model/AttributeURL.php | 33 +---------------- 7 files changed, 17 insertions(+), 221 deletions(-) diff --git a/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php b/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php index 93dbe5725..4076bc9eb 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php @@ -3,44 +3,15 @@ namespace Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response; -use Appwrite\Utopia\Response\Model; +use Appwrite\Utopia\Response\Model\Attribute; -class AttributeBoolean extends Model +class AttributeBoolean extends Attribute { public function __construct() { + parent::__construct(); + $this - ->addRule('key', [ - 'type' => self::TYPE_STRING, - 'description' => 'Attribute Key.', - 'default' => '', - 'example' => 'fullName', - ]) - ->addRule('type', [ - 'type' => self::TYPE_STRING, - 'description' => 'Attribute type.', - 'default' => '', - 'example' => 'string', - ]) - ->addRule('status', [ - 'type' => self::TYPE_STRING, - 'description' => 'Attribute status. Possible values: `available`, `processing`, `deleting`, or `failed`', - 'default' => '', - 'example' => 'string', - ]) - ->addRule('required', [ - 'type' => self::TYPE_BOOLEAN, - 'description' => 'Is attribute required?', - 'default' => false, - 'example' => true, - ]) - ->addRule('array', [ - 'type' => self::TYPE_BOOLEAN, - 'description' => 'Is attribute an array?', - 'default' => false, - 'example' => false, - 'require' => false - ]) ->addRule('default', [ 'type' => self::TYPE_BOOLEAN, 'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.', diff --git a/src/Appwrite/Utopia/Response/Model/AttributeEmail.php b/src/Appwrite/Utopia/Response/Model/AttributeEmail.php index 861356df3..1c058e6b0 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeEmail.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeEmail.php @@ -9,38 +9,9 @@ class AttributeEmail extends AttributeString { public function __construct() { + parent::__construct(); + $this - ->addRule('key', [ - 'type' => self::TYPE_STRING, - 'description' => 'Attribute Key.', - 'default' => '', - 'example' => 'fullName', - ]) - ->addRule('type', [ - 'type' => self::TYPE_STRING, - 'description' => 'Attribute type.', - 'default' => '', - 'example' => 'string', - ]) - ->addRule('status', [ - 'type' => self::TYPE_STRING, - 'description' => 'Attribute status. Possible values: `available`, `processing`, `deleting`, or `failed`', - 'default' => '', - 'example' => 'string', - ]) - ->addRule('required', [ - 'type' => self::TYPE_BOOLEAN, - 'description' => 'Is attribute required?', - 'default' => false, - 'example' => true, - ]) - ->addRule('array', [ - 'type' => self::TYPE_BOOLEAN, - 'description' => 'Is attribute an array?', - 'default' => false, - 'example' => false, - 'require' => false - ]) ->addRule('format', [ 'type' => self::TYPE_STRING, 'description' => 'String format.', diff --git a/src/Appwrite/Utopia/Response/Model/AttributeFloat.php b/src/Appwrite/Utopia/Response/Model/AttributeFloat.php index 85adbe285..669aa4dd7 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeFloat.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeFloat.php @@ -9,38 +9,9 @@ class AttributeFloat extends Attribute { public function __construct() { + parent::__construct(); + $this - ->addRule('key', [ - 'type' => self::TYPE_STRING, - 'description' => 'Attribute Key.', - 'default' => '', - 'example' => 'fullName', - ]) - ->addRule('type', [ - 'type' => self::TYPE_STRING, - 'description' => 'Attribute type.', - 'default' => '', - 'example' => 'string', - ]) - ->addRule('status', [ - 'type' => self::TYPE_STRING, - 'description' => 'Attribute status. Possible values: `available`, `processing`, `deleting`, or `failed`', - 'default' => '', - 'example' => 'string', - ]) - ->addRule('required', [ - 'type' => self::TYPE_BOOLEAN, - 'description' => 'Is attribute required?', - 'default' => false, - 'example' => true, - ]) - ->addRule('array', [ - 'type' => self::TYPE_BOOLEAN, - 'description' => 'Is attribute an array?', - 'default' => false, - 'example' => false, - 'require' => false - ]) ->addRule('format', [ 'type' => self::TYPE_FLOAT, 'description' => 'Float format.', diff --git a/src/Appwrite/Utopia/Response/Model/AttributeIP.php b/src/Appwrite/Utopia/Response/Model/AttributeIP.php index 36e000e15..8272c2760 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeIP.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeIP.php @@ -9,38 +9,9 @@ class AttributeIP extends AttributeString { public function __construct() { + parent::__construct(); + $this - ->addRule('key', [ - 'type' => self::TYPE_STRING, - 'description' => 'Attribute Key.', - 'default' => '', - 'example' => 'fullName', - ]) - ->addRule('type', [ - 'type' => self::TYPE_STRING, - 'description' => 'Attribute type.', - 'default' => '', - 'example' => 'string', - ]) - ->addRule('status', [ - 'type' => self::TYPE_STRING, - 'description' => 'Attribute status. Possible values: `available`, `processing`, `deleting`, or `failed`', - 'default' => '', - 'example' => 'string', - ]) - ->addRule('required', [ - 'type' => self::TYPE_BOOLEAN, - 'description' => 'Is attribute required?', - 'default' => false, - 'example' => true, - ]) - ->addRule('array', [ - 'type' => self::TYPE_BOOLEAN, - 'description' => 'Is attribute an array?', - 'default' => false, - 'example' => false, - 'require' => false - ]) ->addRule('format', [ 'type' => self::TYPE_STRING, 'description' => 'String format.', diff --git a/src/Appwrite/Utopia/Response/Model/AttributeInteger.php b/src/Appwrite/Utopia/Response/Model/AttributeInteger.php index 366ecd556..d1ff6346f 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeInteger.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeInteger.php @@ -9,38 +9,9 @@ class AttributeInteger extends Attribute { public function __construct() { + parent::__construct(); + $this - ->addRule('key', [ - 'type' => self::TYPE_STRING, - 'description' => 'Attribute Key.', - 'default' => '', - 'example' => 'fullName', - ]) - ->addRule('type', [ - 'type' => self::TYPE_STRING, - 'description' => 'Attribute type.', - 'default' => '', - 'example' => 'string', - ]) - ->addRule('status', [ - 'type' => self::TYPE_STRING, - 'description' => 'Attribute status. Possible values: `available`, `processing`, `deleting`, or `failed`', - 'default' => '', - 'example' => 'string', - ]) - ->addRule('required', [ - 'type' => self::TYPE_BOOLEAN, - 'description' => 'Is attribute required?', - 'default' => false, - 'example' => true, - ]) - ->addRule('array', [ - 'type' => self::TYPE_BOOLEAN, - 'description' => 'Is attribute an array?', - 'default' => false, - 'example' => false, - 'require' => false - ]) ->addRule('format', [ 'type' => self::TYPE_STRING, 'description' => 'Integer format.', @@ -65,8 +36,7 @@ class AttributeInteger extends Attribute } /** - * Get Name - * + * Get Name * * @return string */ public function getName():string diff --git a/src/Appwrite/Utopia/Response/Model/AttributeString.php b/src/Appwrite/Utopia/Response/Model/AttributeString.php index e8d156039..22f7e52a3 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeString.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeString.php @@ -9,38 +9,9 @@ class AttributeString extends Attribute { public function __construct() { + parent::__construct(); + $this - ->addRule('key', [ - 'type' => self::TYPE_STRING, - 'description' => 'Attribute Key.', - 'default' => '', - 'example' => 'fullName', - ]) - ->addRule('type', [ - 'type' => self::TYPE_STRING, - 'description' => 'Attribute type.', - 'default' => '', - 'example' => 'string', - ]) - ->addRule('status', [ - 'type' => self::TYPE_STRING, - 'description' => 'Attribute status. Possible values: `available`, `processing`, `deleting`, or `failed`', - 'default' => '', - 'example' => 'string', - ]) - ->addRule('required', [ - 'type' => self::TYPE_BOOLEAN, - 'description' => 'Is attribute required?', - 'default' => false, - 'example' => true, - ]) - ->addRule('array', [ - 'type' => self::TYPE_BOOLEAN, - 'description' => 'Is attribute an array?', - 'default' => false, - 'example' => false, - 'require' => false - ]) ->addRule('size', [ 'type' => self::TYPE_STRING, 'description' => 'Attribute size.', diff --git a/src/Appwrite/Utopia/Response/Model/AttributeURL.php b/src/Appwrite/Utopia/Response/Model/AttributeURL.php index 0d3365f3a..3bb05f4fa 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeURL.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeURL.php @@ -9,38 +9,9 @@ class AttributeURL extends AttributeString { public function __construct() { + parent::__construct(); + $this - ->addRule('key', [ - 'type' => self::TYPE_STRING, - 'description' => 'Attribute Key.', - 'default' => '', - 'example' => 'fullName', - ]) - ->addRule('type', [ - 'type' => self::TYPE_STRING, - 'description' => 'Attribute type.', - 'default' => '', - 'example' => 'string', - ]) - ->addRule('status', [ - 'type' => self::TYPE_STRING, - 'description' => 'Attribute status. Possible values: `available`, `processing`, `deleting`, or `failed`', - 'default' => '', - 'example' => 'string', - ]) - ->addRule('required', [ - 'type' => self::TYPE_BOOLEAN, - 'description' => 'Is attribute required?', - 'default' => false, - 'example' => true, - ]) - ->addRule('array', [ - 'type' => self::TYPE_BOOLEAN, - 'description' => 'Is attribute an array?', - 'default' => false, - 'example' => false, - 'require' => false - ]) ->addRule('format', [ 'type' => self::TYPE_STRING, 'description' => 'String format.', From 7506142ab91f1a3457eda35274dd251df2e215dd Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Tue, 24 Aug 2021 14:01:53 -0400 Subject: [PATCH 19/58] Parse min and max from formatOptions for response model --- app/controllers/api/database.php | 17 ++++++++++++++-- .../Utopia/Response/Model/AttributeFloat.php | 20 +++++++++++-------- .../Response/Model/AttributeInteger.php | 20 +++++++++++-------- 3 files changed, 39 insertions(+), 18 deletions(-) diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index 2dd5c3f0e..0490712e1 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -831,13 +831,14 @@ App::get('/v1/database/collections/:collectionId/attributes/:attributeId') ])]); $type = $attribute->getAttribute('type'); - $format = json_decode($attribute->getAttribute('format'), true); + $format = $attribute->getAttribute('format'); + $formatOptions = $attribute->getAttribute('formatOptions'); $model = match($type) { Database::VAR_BOOLEAN => Response::MODEL_ATTRIBUTE_BOOLEAN, Database::VAR_INTEGER => Response::MODEL_ATTRIBUTE_INTEGER, Database::VAR_FLOAT => Response::MODEL_ATTRIBUTE_FLOAT, - Database::VAR_STRING => match($format['name']) { + Database::VAR_STRING => match($format) { APP_DATABASE_ATTRIBUTE_URL => Response::MODEL_ATTRIBUTE_EMAIL, APP_DATABASE_ATTRIBUTE_IP => Response::MODEL_ATTRIBUTE_IP, APP_DATABASE_ATTRIBUTE_URL => Response::MODEL_ATTRIBUTE_URL, @@ -845,6 +846,18 @@ App::get('/v1/database/collections/:collectionId/attributes/:attributeId') }, default => Response::MODEL_ATTRIBUTE, }; + + // Format response if options are provided + // And response model needs to be modified + if (!empty($formatOptions) && + ($type === Response::MODEL_ATTRIBUTE_INTEGER || + $type === Response::MODEL_ATTRIBUTE_FLOAT)) + { + $attribute->setAttribute('min', $formatOptions['min'], $type); + $attribute->setAttribute('max', $formatOptions['max'], $type); + // unset($attribute['format']); + // unset($attribute['formatOptions']); + } $response->dynamic($attribute, $model); }); diff --git a/src/Appwrite/Utopia/Response/Model/AttributeFloat.php b/src/Appwrite/Utopia/Response/Model/AttributeFloat.php index 669aa4dd7..a0f68ec6a 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeFloat.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeFloat.php @@ -12,15 +12,19 @@ class AttributeFloat extends Attribute parent::__construct(); $this - ->addRule('format', [ - 'type' => self::TYPE_FLOAT, - 'description' => 'Float format.', + ->addRule('min', [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Minimum value to enforce for new documents.', 'default' => null, - 'example' => \json_encode([ - 'name' => APP_DATABASE_ATTRIBUTE_FLOAT_RANGE, - 'min' => 1.5, - 'max' => 2.5, - ]), + 'example' => 1, + 'array' => false, + 'require' => false, + ]) + ->addRule('max', [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Maximum value to enforce for new documents.', + 'default' => null, + 'example' => 10, 'array' => false, 'require' => false, ]) diff --git a/src/Appwrite/Utopia/Response/Model/AttributeInteger.php b/src/Appwrite/Utopia/Response/Model/AttributeInteger.php index d1ff6346f..f11344d79 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeInteger.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeInteger.php @@ -12,15 +12,19 @@ class AttributeInteger extends Attribute parent::__construct(); $this - ->addRule('format', [ - 'type' => self::TYPE_STRING, - 'description' => 'Integer format.', + ->addRule('min', [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Minimum value to enforce for new documents.', 'default' => null, - 'example' => \json_encode([ - 'name' => APP_DATABASE_ATTRIBUTE_INT_RANGE, - 'min' => 0, - 'max' => 10, - ]), + 'example' => 1, + 'array' => false, + 'require' => false, + ]) + ->addRule('max', [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Maximum value to enforce for new documents.', + 'default' => null, + 'example' => 10, 'array' => false, 'require' => false, ]) From 247c3adb48776a6b7c2ea4b3ac5f8bedcf529cf4 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Tue, 24 Aug 2021 14:02:33 -0400 Subject: [PATCH 20/58] Test for attribute response models --- tests/e2e/Services/Database/DatabaseBase.php | 183 +++++++++++++++++++ 1 file changed, 183 insertions(+) diff --git a/tests/e2e/Services/Database/DatabaseBase.php b/tests/e2e/Services/Database/DatabaseBase.php index a097777f5..9068987ba 100644 --- a/tests/e2e/Services/Database/DatabaseBase.php +++ b/tests/e2e/Services/Database/DatabaseBase.php @@ -100,6 +100,189 @@ trait DatabaseBase return $data; } + // /** + // * @depends testCreateAttributes + // */ + // public function testAttributeResponseModels(array $data): array + public function testAttributeResponseModels() + { + $collection= $this->client->call(Client::METHOD_POST, '/database/collections', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'collectionId' => 'unique()', + 'name' => 'Response Models', + 'read' => ['role:all'], + 'write' => ['role:all'], + 'permission' => 'document', + ]); + + $this->assertEquals($collection['headers']['status-code'], 201); + $this->assertEquals($collection['body']['name'], 'Response Models'); + + $collectionId = $collection['body']['$id']; + + $string = $this->client->call(Client::METHOD_POST, '/database/collections/' . $collectionId . '/attributes/string', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'attributeId' => 'string', + 'size' => 16, + 'required' => true, + ]); + + $email = $this->client->call(Client::METHOD_POST, '/database/collections/' . $collectionId . '/attributes/email', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'attributeId' => 'email', + 'required' => true, + ]); + + $ip = $this->client->call(Client::METHOD_POST, '/database/collections/' . $collectionId . '/attributes/ip', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'attributeId' => 'ip', + 'required' => true, + ]); + + $url = $this->client->call(Client::METHOD_POST, '/database/collections/' . $collectionId . '/attributes/url', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'attributeId' => 'url', + 'required' => true, + ]); + + $integer = $this->client->call(Client::METHOD_POST, '/database/collections/' . $collectionId . '/attributes/integer', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'attributeId' => 'integer', + 'required' => true, + 'min' => 1, + 'max' => 5, + 'default' => 3 + ]); + + $float = $this->client->call(Client::METHOD_POST, '/database/collections/' . $collectionId . '/attributes/float', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'attributeId' => 'float', + 'required' => true, + 'min' => 1.5, + 'max' => 5.5, + 'default' => 3.5 + ]); + + $boolean = $this->client->call(Client::METHOD_POST, '/database/collections/' . $collectionId . '/attributes/boolean', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'attributeId' => 'boolean', + 'required' => true, + ]); + + $this->assertEquals(201, $string['headers']['status-code']); + $this->assertEquals('string', $string['body']['key']); + $this->assertEquals('string', $string['body']['type']); + $this->assertEquals('processing', $string['body']['status']); + $this->assertEquals(true, $string['body']['required']); + $this->assertEquals(false, $string['body']['array']); + + $this->assertEquals(16, $string['body']['size']); + + $this->assertEquals(201, $email['headers']['status-code']); + $this->assertEquals('email', $email['body']['key']); + $this->assertEquals('string', $email['body']['type']); + $this->assertEquals('processing', $email['body']['status']); + $this->assertEquals(true, $email['body']['required']); + $this->assertEquals(false, $email['body']['array']); + + $this->assertEquals('email', $string['body']['format']); + + $this->assertEquals(201, $ip['headers']['status-code']); + $this->assertEquals('ip', $ip['body']['key']); + $this->assertEquals('string', $ip['body']['type']); + $this->assertEquals('processing', $ip['body']['status']); + $this->assertEquals(true, $ip['body']['required']); + $this->assertEquals(false, $ip['body']['array']); + + $this->assertEquals('ip', $ip['body']['format']); + + $this->assertEquals(201, $url['headers']['status-code']); + $this->assertEquals('url', $url['body']['key']); + $this->assertEquals('string', $url['body']['type']); + $this->assertEquals('processing', $url['body']['status']); + $this->assertEquals(true, $url['body']['required']); + $this->assertEquals(false, $url['body']['array']); + + $this->assertEquals('url', $url['body']['format']); + + $this->assertEquals(201, $integer['headers']['status-code']); + $this->assertEquals('integer', $integer['body']['key']); + $this->assertEquals('integer', $integer['body']['type']); + $this->assertEquals('processing', $integer['body']['status']); + $this->assertEquals(true, $integer['body']['required']); + $this->assertEquals(false, $integer['body']['array']); + + $this->assertEquals(1, $integer['body']['min']); + $this->assertEquals(5, $integer['body']['max']); + $this->assertEquals(3, $integer['body']['default']); + + $this->assertEquals(201, $float['headers']['status-code']); + $this->assertEquals('float', $float['body']['key']); + $this->assertEquals('double', $float['body']['type']); + $this->assertEquals('processing', $float['body']['status']); + $this->assertEquals(true, $float['body']['required']); + $this->assertEquals(false, $float['body']['array']); + + $this->assertEquals(1.5, $float['body']['min']); + $this->assertEquals(5.5, $float['body']['max']); + $this->assertEquals(3.5, $float['body']['default']); + + $this->assertEquals(201, $boolean['headers']['status-code']); + $this->assertEquals('boolean', $boolean['body']['key']); + $this->assertEquals('boolean', $boolean['body']['type']); + $this->assertEquals('processing', $boolean['body']['status']); + $this->assertEquals(true, $boolean['body']['required']); + $this->assertEquals(false, $boolean['body']['array']); + + + // wait for database worker to create attributes + sleep(2); + + $collection = $this->client->call(Client::METHOD_GET, '/database/collections/' . $collectionId, array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), []); + + var_dump($collection); + + $this->assertIsArray($collection['body']['attributes']); + $this->assertCount(7, $collection['body']['attributes']); + $this->assertEquals($collection['body']['attributes'][0]['key'], $string['body']['key']); + $this->assertEquals($collection['body']['attributes'][1]['key'], $email['body']['key']); + $this->assertEquals($collection['body']['attributes'][2]['key'], $ip['body']['key']); + $this->assertEquals($collection['body']['attributes'][3]['key'], $url['body']['key']); + $this->assertEquals($collection['body']['attributes'][4]['key'], $integer['body']['key']); + $this->assertEquals($collection['body']['attributes'][5]['key'], $float['body']['key']); + $this->assertEquals($collection['body']['attributes'][6]['key'], $boolean['body']['key']); + + // return $data; + } + /** * @depends testCreateAttributes */ From 6df9d579c4d5ada9bdf92b158e33d9750a10a035 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Tue, 24 Aug 2021 14:57:19 -0400 Subject: [PATCH 21/58] Comment out default values for non string attributes --- tests/e2e/Services/Database/DatabaseBase.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/e2e/Services/Database/DatabaseBase.php b/tests/e2e/Services/Database/DatabaseBase.php index 9068987ba..8a59f074d 100644 --- a/tests/e2e/Services/Database/DatabaseBase.php +++ b/tests/e2e/Services/Database/DatabaseBase.php @@ -169,7 +169,7 @@ trait DatabaseBase 'required' => true, 'min' => 1, 'max' => 5, - 'default' => 3 + // 'default' => 3 ]); $float = $this->client->call(Client::METHOD_POST, '/database/collections/' . $collectionId . '/attributes/float', array_merge([ @@ -181,7 +181,7 @@ trait DatabaseBase 'required' => true, 'min' => 1.5, 'max' => 5.5, - 'default' => 3.5 + // 'default' => 3.5 ]); $boolean = $this->client->call(Client::METHOD_POST, '/database/collections/' . $collectionId . '/attributes/boolean', array_merge([ @@ -209,7 +209,7 @@ trait DatabaseBase $this->assertEquals(true, $email['body']['required']); $this->assertEquals(false, $email['body']['array']); - $this->assertEquals('email', $string['body']['format']); + $this->assertEquals('email', $email['body']['format']); $this->assertEquals(201, $ip['headers']['status-code']); $this->assertEquals('ip', $ip['body']['key']); @@ -238,7 +238,7 @@ trait DatabaseBase $this->assertEquals(1, $integer['body']['min']); $this->assertEquals(5, $integer['body']['max']); - $this->assertEquals(3, $integer['body']['default']); + // $this->assertEquals(3, $integer['body']['default']); $this->assertEquals(201, $float['headers']['status-code']); $this->assertEquals('float', $float['body']['key']); @@ -249,7 +249,7 @@ trait DatabaseBase $this->assertEquals(1.5, $float['body']['min']); $this->assertEquals(5.5, $float['body']['max']); - $this->assertEquals(3.5, $float['body']['default']); + // $this->assertEquals(3.5, $float['body']['default']); $this->assertEquals(201, $boolean['headers']['status-code']); $this->assertEquals('boolean', $boolean['body']['key']); @@ -260,7 +260,7 @@ trait DatabaseBase // wait for database worker to create attributes - sleep(2); + sleep(5); $collection = $this->client->call(Client::METHOD_GET, '/database/collections/' . $collectionId, array_merge([ 'content-type' => 'application/json', From 5c040bd5f370d745427baa00adaee898e4d3b15c Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Tue, 24 Aug 2021 14:57:34 -0400 Subject: [PATCH 22/58] Add min and max for response model --- app/controllers/api/database.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index 0490712e1..8648aee54 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -657,6 +657,13 @@ App::post('/v1/database/collections/:collectionId/attributes/integer') ], ]), $response, $dbForInternal, $database, $audits); + $formatOptions = $attribute->getAttribute('formatOptions', []); + + if (!empty($formatOptions)) { + $attribute->setAttribute('min', \intval($formatOptions['min'])); + $attribute->setAttribute('max', \intval($formatOptions['max'])); + } + $response->dynamic($attribute, Response::MODEL_ATTRIBUTE_INTEGER); }); @@ -712,6 +719,13 @@ App::post('/v1/database/collections/:collectionId/attributes/float') ], ]), $response, $dbForInternal, $database, $audits); + $formatOptions = $attribute->getAttribute('formatOptions', []); + + if (!empty($formatOptions)) { + $attribute->setAttribute('min', \floatval($formatOptions['min'])); + $attribute->setAttribute('max', \floatval($formatOptions['max'])); + } + $response->dynamic($attribute, Response::MODEL_ATTRIBUTE_FLOAT); }); From 84f9f71b81dc392950545d8a7186ac01cf653603 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Wed, 25 Aug 2021 15:36:45 -0400 Subject: [PATCH 23/58] Fix race condition between database controller and worker --- app/controllers/api/database.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index 8648aee54..70dc62048 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -91,16 +91,20 @@ function createAttribute($collectionId, $attribute, $response, $dbForInternal, $ $dbForInternal->purgeDocument('collections', $collectionId); + // Pass clone of $attribute object to workers + // so we can later modify Document to fit response model + $clone = clone $attribute; + $database ->setParam('type', DATABASE_TYPE_CREATE_ATTRIBUTE) ->setParam('collection', $collection) - ->setParam('document', $attribute) + ->setParam('document', $clone) ; $audits ->setParam('event', 'database.attributes.create') ->setParam('resource', 'database/collection/'.$collection->getId()) - ->setParam('data', $attribute) + ->setParam('data', $clone) ; $response->setStatusCode(Response::STATUS_CODE_CREATED); From 1c52b0b4dc7ab171e8a77cf9cf673aa5eb126a9e Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Wed, 25 Aug 2021 15:37:07 -0400 Subject: [PATCH 24/58] Prefer Document array data structure for attributes --- app/controllers/api/database.php | 34 +++++++++++++++----------------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index 70dc62048..cf7fcec02 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -835,19 +835,22 @@ App::get('/v1/database/collections/:collectionId/attributes/:attributeId') throw new Exception('Collection not found', 404); } - $attributes = $collection->getAttributes(); + // Search for matching attribute in collection + $attribute = null; + $attributes = $collection->getAttribute('attributes'); /** @var Document[] $attributes */ - // Search for attribute - $attributeIndex = array_search($attributeId, array_column($attributes, '$id')); + foreach ($attributes as $a) { + if ($a->getId() === $attributeId) { + $attribute = $a; + break; // stop once the attribute is found + } + } - if ($attributeIndex === false) { + if (\is_null($attribute)) { throw new Exception('Attribute not found', 404); } - $attribute = new Document([\array_merge($attributes[$attributeIndex], [ - 'collectionId' => $collectionId, - ])]); - + // Select response model based on type and format $type = $attribute->getAttribute('type'); $format = $attribute->getAttribute('format'); $formatOptions = $attribute->getAttribute('formatOptions'); @@ -857,7 +860,7 @@ App::get('/v1/database/collections/:collectionId/attributes/:attributeId') Database::VAR_INTEGER => Response::MODEL_ATTRIBUTE_INTEGER, Database::VAR_FLOAT => Response::MODEL_ATTRIBUTE_FLOAT, Database::VAR_STRING => match($format) { - APP_DATABASE_ATTRIBUTE_URL => Response::MODEL_ATTRIBUTE_EMAIL, + APP_DATABASE_ATTRIBUTE_EMAIL => Response::MODEL_ATTRIBUTE_EMAIL, APP_DATABASE_ATTRIBUTE_IP => Response::MODEL_ATTRIBUTE_IP, APP_DATABASE_ATTRIBUTE_URL => Response::MODEL_ATTRIBUTE_URL, default => Response::MODEL_ATTRIBUTE_STRING, @@ -865,16 +868,11 @@ App::get('/v1/database/collections/:collectionId/attributes/:attributeId') default => Response::MODEL_ATTRIBUTE, }; - // Format response if options are provided - // And response model needs to be modified - if (!empty($formatOptions) && - ($type === Response::MODEL_ATTRIBUTE_INTEGER || - $type === Response::MODEL_ATTRIBUTE_FLOAT)) + // Format response + if ($model === Response::MODEL_ATTRIBUTE_INTEGER || $model === Response::MODEL_ATTRIBUTE_FLOAT) { - $attribute->setAttribute('min', $formatOptions['min'], $type); - $attribute->setAttribute('max', $formatOptions['max'], $type); - // unset($attribute['format']); - // unset($attribute['formatOptions']); + $attribute->setAttribute('min', $formatOptions['min']); + $attribute->setAttribute('max', $formatOptions['max']); } $response->dynamic($attribute, $model); From 0f3c42368d0ab5b694c4e5200a6bdecfafc13502 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Wed, 25 Aug 2021 15:37:21 -0400 Subject: [PATCH 25/58] Test for proper response models for getAttribute --- tests/e2e/Services/Database/DatabaseBase.php | 111 +++++++++++++++++-- 1 file changed, 103 insertions(+), 8 deletions(-) diff --git a/tests/e2e/Services/Database/DatabaseBase.php b/tests/e2e/Services/Database/DatabaseBase.php index 8a59f074d..3b8ca2ca1 100644 --- a/tests/e2e/Services/Database/DatabaseBase.php +++ b/tests/e2e/Services/Database/DatabaseBase.php @@ -199,7 +199,6 @@ trait DatabaseBase $this->assertEquals('processing', $string['body']['status']); $this->assertEquals(true, $string['body']['required']); $this->assertEquals(false, $string['body']['array']); - $this->assertEquals(16, $string['body']['size']); $this->assertEquals(201, $email['headers']['status-code']); @@ -208,7 +207,6 @@ trait DatabaseBase $this->assertEquals('processing', $email['body']['status']); $this->assertEquals(true, $email['body']['required']); $this->assertEquals(false, $email['body']['array']); - $this->assertEquals('email', $email['body']['format']); $this->assertEquals(201, $ip['headers']['status-code']); @@ -217,7 +215,6 @@ trait DatabaseBase $this->assertEquals('processing', $ip['body']['status']); $this->assertEquals(true, $ip['body']['required']); $this->assertEquals(false, $ip['body']['array']); - $this->assertEquals('ip', $ip['body']['format']); $this->assertEquals(201, $url['headers']['status-code']); @@ -226,7 +223,6 @@ trait DatabaseBase $this->assertEquals('processing', $url['body']['status']); $this->assertEquals(true, $url['body']['required']); $this->assertEquals(false, $url['body']['array']); - $this->assertEquals('url', $url['body']['format']); $this->assertEquals(201, $integer['headers']['status-code']); @@ -235,7 +231,6 @@ trait DatabaseBase $this->assertEquals('processing', $integer['body']['status']); $this->assertEquals(true, $integer['body']['required']); $this->assertEquals(false, $integer['body']['array']); - $this->assertEquals(1, $integer['body']['min']); $this->assertEquals(5, $integer['body']['max']); // $this->assertEquals(3, $integer['body']['default']); @@ -246,7 +241,6 @@ trait DatabaseBase $this->assertEquals('processing', $float['body']['status']); $this->assertEquals(true, $float['body']['required']); $this->assertEquals(false, $float['body']['array']); - $this->assertEquals(1.5, $float['body']['min']); $this->assertEquals(5.5, $float['body']['max']); // $this->assertEquals(3.5, $float['body']['default']); @@ -258,16 +252,117 @@ trait DatabaseBase $this->assertEquals(true, $boolean['body']['required']); $this->assertEquals(false, $boolean['body']['array']); - // wait for database worker to create attributes sleep(5); + $stringResponse = $this->client->call(Client::METHOD_GET, "/database/collections/{$collectionId}/attributes/{$collectionId}_{$string['body']['key']}",array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ])); + + $emailResponse = $this->client->call(Client::METHOD_GET, "/database/collections/{$collectionId}/attributes/{$collectionId}_{$email['body']['key']}",array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ])); + + $ipResponse = $this->client->call(Client::METHOD_GET, "/database/collections/{$collectionId}/attributes/{$collectionId}_{$ip['body']['key']}",array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ])); + + $urlResponse = $this->client->call(Client::METHOD_GET, "/database/collections/{$collectionId}/attributes/{$collectionId}_{$url['body']['key']}",array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ])); + + $integerResponse = $this->client->call(Client::METHOD_GET, "/database/collections/{$collectionId}/attributes/{$collectionId}_{$integer['body']['key']}",array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ])); + + $floatResponse = $this->client->call(Client::METHOD_GET, "/database/collections/{$collectionId}/attributes/{$collectionId}_{$float['body']['key']}",array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ])); + + $booleanResponse = $this->client->call(Client::METHOD_GET, "/database/collections/{$collectionId}/attributes/{$collectionId}_{$boolean['body']['key']}",array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ])); + + $this->assertEquals(200, $stringResponse['headers']['status-code']); + $this->assertEquals($string['body']['key'], $stringResponse['body']['key']); + $this->assertEquals($string['body']['type'], $stringResponse['body']['type']); + $this->assertEquals('available', $stringResponse['body']['status']); + $this->assertEquals($string['body']['required'], $stringResponse['body']['required']); + $this->assertEquals($string['body']['array'], $stringResponse['body']['array']); + $this->assertEquals(16, $stringResponse['body']['size']); + + $this->assertEquals(200, $emailResponse['headers']['status-code']); + $this->assertEquals($email['body']['key'], $emailResponse['body']['key']); + $this->assertEquals($email['body']['type'], $emailResponse['body']['type']); + $this->assertEquals('available', $emailResponse['body']['status']); + $this->assertEquals($email['body']['required'], $emailResponse['body']['required']); + $this->assertEquals($email['body']['array'], $emailResponse['body']['array']); + $this->assertEquals($email['body']['format'], $emailResponse['body']['format']); + + $this->assertEquals(200, $ipResponse['headers']['status-code']); + $this->assertEquals($ip['body']['key'], $ipResponse['body']['key']); + $this->assertEquals($ip['body']['type'], $ipResponse['body']['type']); + $this->assertEquals('available', $ipResponse['body']['status']); + $this->assertEquals($ip['body']['required'], $ipResponse['body']['required']); + $this->assertEquals($ip['body']['array'], $ipResponse['body']['array']); + $this->assertEquals($ip['body']['format'], $ipResponse['body']['format']); + + $this->assertEquals(200, $urlResponse['headers']['status-code']); + $this->assertEquals($url['body']['key'], $urlResponse['body']['key']); + $this->assertEquals($url['body']['type'], $urlResponse['body']['type']); + $this->assertEquals('available', $urlResponse['body']['status']); + $this->assertEquals($url['body']['required'], $urlResponse['body']['required']); + $this->assertEquals($url['body']['array'], $urlResponse['body']['array']); + $this->assertEquals($url['body']['format'], $urlResponse['body']['format']); + + $this->assertEquals(200, $integerResponse['headers']['status-code']); + $this->assertEquals($integer['body']['key'], $integerResponse['body']['key']); + $this->assertEquals($integer['body']['type'], $integerResponse['body']['type']); + $this->assertEquals('available', $integerResponse['body']['status']); + $this->assertEquals($integer['body']['required'], $integerResponse['body']['required']); + $this->assertEquals($integer['body']['array'], $integerResponse['body']['array']); + $this->assertEquals($integer['body']['min'], $integerResponse['body']['min']); + $this->assertEquals($integer['body']['max'], $integerResponse['body']['max']); + // $this->assertEquals(3, $integer['body']['default']); + + $this->assertEquals(200, $floatResponse['headers']['status-code']); + $this->assertEquals($float['body']['key'], $floatResponse['body']['key']); + $this->assertEquals($float['body']['type'], $floatResponse['body']['type']); + $this->assertEquals('available', $floatResponse['body']['status']); + $this->assertEquals($float['body']['required'], $floatResponse['body']['required']); + $this->assertEquals($float['body']['array'], $floatResponse['body']['array']); + $this->assertEquals($float['body']['min'], $floatResponse['body']['min']); + $this->assertEquals($float['body']['max'], $floatResponse['body']['max']); + // $this->assertEquals(3.5, $float['body']['default']); + + $this->assertEquals(200, $booleanResponse['headers']['status-code']); + $this->assertEquals($boolean['body']['key'], $booleanResponse['body']['key']); + $this->assertEquals($boolean['body']['type'], $booleanResponse['body']['type']); + $this->assertEquals('available', $booleanResponse['body']['status']); + $this->assertEquals($boolean['body']['required'], $booleanResponse['body']['required']); + $this->assertEquals($boolean['body']['array'], $booleanResponse['body']['array']); + $collection = $this->client->call(Client::METHOD_GET, '/database/collections/' . $collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), []); + ])); + // TODO@kodumbeats test for proper attribute response in collection var_dump($collection); $this->assertIsArray($collection['body']['attributes']); From 547241523153922eb1206a05dc7c97a19d68f634 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Wed, 25 Aug 2021 16:43:15 -0400 Subject: [PATCH 26/58] Encode attribute default as json string --- app/controllers/api/database.php | 16 ++++++++++++++-- app/workers/database.php | 3 +++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index cf7fcec02..080ddb954 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -55,7 +55,8 @@ function createAttribute($collectionId, $attribute, $response, $dbForInternal, $ $formatOptions = $attribute->getAttribute('formatOptions', []); $filters = $attribute->getAttribute('filters', []); // filters are hidden from the endpoint $default = $attribute->getAttribute('default', null); - $default = (empty($default)) ? null : (int)$default; + // $default = (empty($default)) ? null : (int)$default; + $defaultEncoded = (\is_null($default)) ? '' : json_encode(['value'=>$default]); $collection = $dbForInternal->getDocument('collections', $collectionId); @@ -69,6 +70,11 @@ function createAttribute($collectionId, $attribute, $response, $dbForInternal, $ } } + // Must throw here since dbForExternal->createAttribute is performed by db worker + if ($required && $default) { + throw new Exception('Cannot set default value for required attribute', 400); + } + try { $attribute = $dbForInternal->createDocument('attributes', new Document([ '$id' => $collectionId.'_'.$attributeId, @@ -79,7 +85,7 @@ function createAttribute($collectionId, $attribute, $response, $dbForInternal, $ 'size' => $size, 'required' => $required, 'signed' => $signed, - 'default' => $default, + 'default' => $defaultEncoded, 'array' => $array, 'format' => $format, 'formatOptions' => $formatOptions, @@ -91,6 +97,9 @@ function createAttribute($collectionId, $attribute, $response, $dbForInternal, $ $dbForInternal->purgeDocument('collections', $collectionId); + // Only attributes table needs $default encoded as a string, reset before response + $attribute->setAttribute('default', $default); + // Pass clone of $attribute object to workers // so we can later modify Document to fit response model $clone = clone $attribute; @@ -869,6 +878,9 @@ App::get('/v1/database/collections/:collectionId/attributes/:attributeId') }; // Format response + $default = \json_decode($attribute->getAttribute('default', []), true)['value'] ?? null; + $attribute->setAttribute('default', $default); + if ($model === Response::MODEL_ATTRIBUTE_INTEGER || $model === Response::MODEL_ATTRIBUTE_FLOAT) { $attribute->setAttribute('min', $formatOptions['min']); diff --git a/app/workers/database.php b/app/workers/database.php index fd3824615..381fb1c5e 100644 --- a/app/workers/database.php +++ b/app/workers/database.php @@ -88,6 +88,9 @@ class DatabaseV1 extends Worker if(!$dbForExternal->createAttribute($collectionId, $key, $type, $size, $required, $default, $signed, $array, $format, $formatOptions, $filters)) { throw new Exception('Failed to create Attribute'); } + if (!\is_null($default)) { + $attribute->setAttribute('default', json_encode(['value' => $default])); + } $dbForInternal->updateDocument('attributes', $attribute->getId(), $attribute->setAttribute('status', 'available')); } catch (\Throwable $th) { Console::error($th->getMessage()); From 2ead9c52f6e01ee0b19f1569a42379ebeef93d02 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Wed, 25 Aug 2021 16:44:07 -0400 Subject: [PATCH 27/58] Test attribute default values have proper casting in response model --- tests/e2e/Services/Database/DatabaseBase.php | 57 ++++++++++++-------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/tests/e2e/Services/Database/DatabaseBase.php b/tests/e2e/Services/Database/DatabaseBase.php index 3b8ca2ca1..b175f8a79 100644 --- a/tests/e2e/Services/Database/DatabaseBase.php +++ b/tests/e2e/Services/Database/DatabaseBase.php @@ -130,7 +130,8 @@ trait DatabaseBase ]), [ 'attributeId' => 'string', 'size' => 16, - 'required' => true, + 'required' => false, + 'default' => 'default', ]); $email = $this->client->call(Client::METHOD_POST, '/database/collections/' . $collectionId . '/attributes/email', array_merge([ @@ -139,7 +140,8 @@ trait DatabaseBase 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'attributeId' => 'email', - 'required' => true, + 'required' => false, + 'default' => 'default@example.com', ]); $ip = $this->client->call(Client::METHOD_POST, '/database/collections/' . $collectionId . '/attributes/ip', array_merge([ @@ -148,7 +150,8 @@ trait DatabaseBase 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'attributeId' => 'ip', - 'required' => true, + 'required' => false, + 'default' => '192.0.2.0', ]); $url = $this->client->call(Client::METHOD_POST, '/database/collections/' . $collectionId . '/attributes/url', array_merge([ @@ -157,7 +160,8 @@ trait DatabaseBase 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'attributeId' => 'url', - 'required' => true, + 'required' => false, + 'default' => 'http://example.com', ]); $integer = $this->client->call(Client::METHOD_POST, '/database/collections/' . $collectionId . '/attributes/integer', array_merge([ @@ -166,10 +170,10 @@ trait DatabaseBase 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'attributeId' => 'integer', - 'required' => true, + 'required' => false, 'min' => 1, 'max' => 5, - // 'default' => 3 + 'default' => 3 ]); $float = $this->client->call(Client::METHOD_POST, '/database/collections/' . $collectionId . '/attributes/float', array_merge([ @@ -178,10 +182,10 @@ trait DatabaseBase 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'attributeId' => 'float', - 'required' => true, + 'required' => false, 'min' => 1.5, 'max' => 5.5, - // 'default' => 3.5 + 'default' => 3.5 ]); $boolean = $this->client->call(Client::METHOD_POST, '/database/collections/' . $collectionId . '/attributes/boolean', array_merge([ @@ -190,67 +194,73 @@ trait DatabaseBase 'x-appwrite-key' => $this->getProject()['apiKey'] ]), [ 'attributeId' => 'boolean', - 'required' => true, + 'required' => false, + 'default' => true, ]); $this->assertEquals(201, $string['headers']['status-code']); $this->assertEquals('string', $string['body']['key']); $this->assertEquals('string', $string['body']['type']); $this->assertEquals('processing', $string['body']['status']); - $this->assertEquals(true, $string['body']['required']); + $this->assertEquals(false, $string['body']['required']); $this->assertEquals(false, $string['body']['array']); $this->assertEquals(16, $string['body']['size']); + $this->assertEquals('default', $string['body']['default']); $this->assertEquals(201, $email['headers']['status-code']); $this->assertEquals('email', $email['body']['key']); $this->assertEquals('string', $email['body']['type']); $this->assertEquals('processing', $email['body']['status']); - $this->assertEquals(true, $email['body']['required']); + $this->assertEquals(false, $email['body']['required']); $this->assertEquals(false, $email['body']['array']); $this->assertEquals('email', $email['body']['format']); + $this->assertEquals('default@example.com', $email['body']['default']); $this->assertEquals(201, $ip['headers']['status-code']); $this->assertEquals('ip', $ip['body']['key']); $this->assertEquals('string', $ip['body']['type']); $this->assertEquals('processing', $ip['body']['status']); - $this->assertEquals(true, $ip['body']['required']); + $this->assertEquals(false, $ip['body']['required']); $this->assertEquals(false, $ip['body']['array']); $this->assertEquals('ip', $ip['body']['format']); + $this->assertEquals('192.0.2.0', $ip['body']['default']); $this->assertEquals(201, $url['headers']['status-code']); $this->assertEquals('url', $url['body']['key']); $this->assertEquals('string', $url['body']['type']); $this->assertEquals('processing', $url['body']['status']); - $this->assertEquals(true, $url['body']['required']); + $this->assertEquals(false, $url['body']['required']); $this->assertEquals(false, $url['body']['array']); $this->assertEquals('url', $url['body']['format']); + $this->assertEquals('http://example.com', $url['body']['default']); $this->assertEquals(201, $integer['headers']['status-code']); $this->assertEquals('integer', $integer['body']['key']); $this->assertEquals('integer', $integer['body']['type']); $this->assertEquals('processing', $integer['body']['status']); - $this->assertEquals(true, $integer['body']['required']); + $this->assertEquals(false, $integer['body']['required']); $this->assertEquals(false, $integer['body']['array']); $this->assertEquals(1, $integer['body']['min']); $this->assertEquals(5, $integer['body']['max']); - // $this->assertEquals(3, $integer['body']['default']); + $this->assertEquals(3, $integer['body']['default']); $this->assertEquals(201, $float['headers']['status-code']); $this->assertEquals('float', $float['body']['key']); $this->assertEquals('double', $float['body']['type']); $this->assertEquals('processing', $float['body']['status']); - $this->assertEquals(true, $float['body']['required']); + $this->assertEquals(false, $float['body']['required']); $this->assertEquals(false, $float['body']['array']); $this->assertEquals(1.5, $float['body']['min']); $this->assertEquals(5.5, $float['body']['max']); - // $this->assertEquals(3.5, $float['body']['default']); + $this->assertEquals(3.5, $float['body']['default']); $this->assertEquals(201, $boolean['headers']['status-code']); $this->assertEquals('boolean', $boolean['body']['key']); $this->assertEquals('boolean', $boolean['body']['type']); $this->assertEquals('processing', $boolean['body']['status']); - $this->assertEquals(true, $boolean['body']['required']); + $this->assertEquals(false, $boolean['body']['required']); $this->assertEquals(false, $boolean['body']['array']); + $this->assertEquals(true, $boolean['body']['default']); // wait for database worker to create attributes sleep(5); @@ -304,6 +314,7 @@ trait DatabaseBase $this->assertEquals($string['body']['required'], $stringResponse['body']['required']); $this->assertEquals($string['body']['array'], $stringResponse['body']['array']); $this->assertEquals(16, $stringResponse['body']['size']); + $this->assertEquals($string['body']['default'], $stringResponse['body']['default']); $this->assertEquals(200, $emailResponse['headers']['status-code']); $this->assertEquals($email['body']['key'], $emailResponse['body']['key']); @@ -312,6 +323,7 @@ trait DatabaseBase $this->assertEquals($email['body']['required'], $emailResponse['body']['required']); $this->assertEquals($email['body']['array'], $emailResponse['body']['array']); $this->assertEquals($email['body']['format'], $emailResponse['body']['format']); + $this->assertEquals($email['body']['default'], $emailResponse['body']['default']); $this->assertEquals(200, $ipResponse['headers']['status-code']); $this->assertEquals($ip['body']['key'], $ipResponse['body']['key']); @@ -320,6 +332,7 @@ trait DatabaseBase $this->assertEquals($ip['body']['required'], $ipResponse['body']['required']); $this->assertEquals($ip['body']['array'], $ipResponse['body']['array']); $this->assertEquals($ip['body']['format'], $ipResponse['body']['format']); + $this->assertEquals($ip['body']['default'], $ipResponse['body']['default']); $this->assertEquals(200, $urlResponse['headers']['status-code']); $this->assertEquals($url['body']['key'], $urlResponse['body']['key']); @@ -328,6 +341,7 @@ trait DatabaseBase $this->assertEquals($url['body']['required'], $urlResponse['body']['required']); $this->assertEquals($url['body']['array'], $urlResponse['body']['array']); $this->assertEquals($url['body']['format'], $urlResponse['body']['format']); + $this->assertEquals($url['body']['default'], $urlResponse['body']['default']); $this->assertEquals(200, $integerResponse['headers']['status-code']); $this->assertEquals($integer['body']['key'], $integerResponse['body']['key']); @@ -337,7 +351,7 @@ trait DatabaseBase $this->assertEquals($integer['body']['array'], $integerResponse['body']['array']); $this->assertEquals($integer['body']['min'], $integerResponse['body']['min']); $this->assertEquals($integer['body']['max'], $integerResponse['body']['max']); - // $this->assertEquals(3, $integer['body']['default']); + $this->assertEquals($integer['body']['default'], $integerResponse['body']['default']); $this->assertEquals(200, $floatResponse['headers']['status-code']); $this->assertEquals($float['body']['key'], $floatResponse['body']['key']); @@ -347,7 +361,7 @@ trait DatabaseBase $this->assertEquals($float['body']['array'], $floatResponse['body']['array']); $this->assertEquals($float['body']['min'], $floatResponse['body']['min']); $this->assertEquals($float['body']['max'], $floatResponse['body']['max']); - // $this->assertEquals(3.5, $float['body']['default']); + $this->assertEquals($float['body']['default'], $floatResponse['body']['default']); $this->assertEquals(200, $booleanResponse['headers']['status-code']); $this->assertEquals($boolean['body']['key'], $booleanResponse['body']['key']); @@ -355,6 +369,7 @@ trait DatabaseBase $this->assertEquals('available', $booleanResponse['body']['status']); $this->assertEquals($boolean['body']['required'], $booleanResponse['body']['required']); $this->assertEquals($boolean['body']['array'], $booleanResponse['body']['array']); + $this->assertEquals($boolean['body']['default'], $booleanResponse['body']['default']); $collection = $this->client->call(Client::METHOD_GET, '/database/collections/' . $collectionId, array_merge([ 'content-type' => 'application/json', @@ -363,7 +378,7 @@ trait DatabaseBase ])); // TODO@kodumbeats test for proper attribute response in collection - var_dump($collection); + // var_dump($collection); $this->assertIsArray($collection['body']['attributes']); $this->assertCount(7, $collection['body']['attributes']); From 87de870093c8d15e96718cfe0702e5f290b141f1 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Fri, 27 Aug 2021 13:09:56 -0400 Subject: [PATCH 28/58] Accept callback to get nested type of rule for Document arrays --- src/Appwrite/Utopia/Response.php | 7 ++++--- src/Appwrite/Utopia/Response/Model.php | 9 ++++++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index 1c73ac14c..67d47eea4 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -340,11 +340,12 @@ class Response extends SwooleResponse foreach ($data[$key] as &$item) { if ($item instanceof Document) { - if (!array_key_exists($rule['type'], $this->models)) { - throw new Exception('Missing model for rule: '. $rule['type']); + $ruleType = (!\is_null($rule['getNestedType'])) ? $rule['getNestedType']($item) : $rule['type']; + if (!array_key_exists($ruleType, $this->models)) { + throw new Exception('Missing model for rule: '. $ruleType); } - $item = $this->output($item, $rule['type']); + $item = $this->output($item, $ruleType); } } } diff --git a/src/Appwrite/Utopia/Response/Model.php b/src/Appwrite/Utopia/Response/Model.php index 73b660963..40a882527 100644 --- a/src/Appwrite/Utopia/Response/Model.php +++ b/src/Appwrite/Utopia/Response/Model.php @@ -68,8 +68,14 @@ abstract class Model /** * Add a New Rule + * If rule is an array of documents with varying models + * Pass callable $getNestedType that accepts Document and returns the nested response type + * + * @param string $key + * @param array $options + * @param callable $getNestedType function(Document $value): string */ - protected function addRule(string $key, array $options): self + protected function addRule(string $key, array $options, callable $getNestedType = null): self { $this->rules[$key] = array_merge([ 'require' => true, @@ -78,6 +84,7 @@ abstract class Model 'default' => null, 'example' => '', 'array' => false, + 'getNestedType' => $getNestedType ], $options); return $this; From ddde87f32ac4f4291221df6ebf20bfbfbda9918b Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Fri, 27 Aug 2021 13:11:29 -0400 Subject: [PATCH 29/58] Create custom response model for attributeList --- src/Appwrite/Utopia/Response.php | 3 +- .../Utopia/Response/Model/AttributeList.php | 62 +++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 src/Appwrite/Utopia/Response/Model/AttributeList.php diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index 67d47eea4..a653ddbb0 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -11,6 +11,7 @@ use Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response\Model\None; use Appwrite\Utopia\Response\Model\Any; use Appwrite\Utopia\Response\Model\Attribute; +use Appwrite\Utopia\Response\Model\AttributeList; use Appwrite\Utopia\Response\Model\AttributeString; use Appwrite\Utopia\Response\Model\AttributeInteger; use Appwrite\Utopia\Response\Model\AttributeFloat; @@ -170,7 +171,6 @@ class Response extends SwooleResponse ->setModel(new ErrorDev()) // Lists ->setModel(new BaseList('Collections List', self::MODEL_COLLECTION_LIST, 'collections', self::MODEL_COLLECTION)) - ->setModel(new BaseList('Attributes List', self::MODEL_ATTRIBUTE_LIST, 'attributes', self::MODEL_ATTRIBUTE)) ->setModel(new BaseList('Indexes List', self::MODEL_INDEX_LIST, 'indexes', self::MODEL_INDEX)) ->setModel(new BaseList('Documents List', self::MODEL_DOCUMENT_LIST, 'documents', self::MODEL_DOCUMENT)) ->setModel(new BaseList('Users List', self::MODEL_USER_LIST, 'users', self::MODEL_USER)) @@ -195,6 +195,7 @@ class Response extends SwooleResponse // Entities ->setModel(new Collection()) ->setModel(new Attribute()) + ->setModel(new AttributeList()) ->setModel(new AttributeString()) ->setModel(new AttributeInteger()) ->setModel(new AttributeFloat()) diff --git a/src/Appwrite/Utopia/Response/Model/AttributeList.php b/src/Appwrite/Utopia/Response/Model/AttributeList.php new file mode 100644 index 000000000..5484db61f --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/AttributeList.php @@ -0,0 +1,62 @@ +addRule('sum', [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Total sum of items in the list.', + 'default' => 0, + 'example' => 5, + ]) + ->addRule('attributes', [ + 'type' => Response::MODEL_ATTRIBUTE, + 'description' => 'List of attributes.', + 'default' => [], + 'array' => true, + 'getNestedType' => function(Document $attribute) { + return match($attribute->getAttribute('type')) { + self::TYPE_BOOLEAN => Response::MODEL_ATTRIBUTE_BOOLEAN, + self::TYPE_INTEGER=> Response::MODEL_ATTRIBUTE_INTEGER, + self::TYPE_FLOAT => Response::MODEL_ATTRIBUTE_FLOAT, + self::TYPE_STRING => match($attribute->getAttribute('format')) { + APP_DATABASE_ATTRIBUTE_EMAIL => Response::MODEL_ATTRIBUTE_EMAIL, + APP_DATABASE_ATTRIBUTE_IP => Response::MODEL_ATTRIBUTE_IP, + APP_DATABASE_ATTRIBUTE_URL => Response::MODEL_ATTRIBUTE_URL, + default => Response::MODEL_ATTRIBUTE_STRING, + }, + default => Response::MODEL_ATTRIBUTE, + }; + }, + ]) + ; + } + + /** + * Get Name + * + * @return string + */ + public function getName():string + { + return 'Attributes List'; + } + + /** + * Get Collection + * + * @return string + */ + public function getType():string + { + return Response::MODEL_ATTRIBUTE_LIST; + } +} \ No newline at end of file From a619c26aff08dc7343bcc797c49f2dc1997eb436 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Fri, 27 Aug 2021 13:12:16 -0400 Subject: [PATCH 30/58] Use database filter to encode default value as JSON string to preseve type --- app/config/collections2.php | 2 +- app/controllers/api/database.php | 15 ++------------- app/init.php | 14 +++++++++++++- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/app/config/collections2.php b/app/config/collections2.php index 8079bdd7c..a01133fdd 100644 --- a/app/config/collections2.php +++ b/app/config/collections2.php @@ -174,7 +174,7 @@ $collections = [ 'required' => false, 'default' => null, 'array' => false, - 'filters' => [], + 'filters' => ['defaultValue'], ], [ '$id' => 'signed', diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index 080ddb954..c01d38fa6 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -55,8 +55,6 @@ function createAttribute($collectionId, $attribute, $response, $dbForInternal, $ $formatOptions = $attribute->getAttribute('formatOptions', []); $filters = $attribute->getAttribute('filters', []); // filters are hidden from the endpoint $default = $attribute->getAttribute('default', null); - // $default = (empty($default)) ? null : (int)$default; - $defaultEncoded = (\is_null($default)) ? '' : json_encode(['value'=>$default]); $collection = $dbForInternal->getDocument('collections', $collectionId); @@ -85,7 +83,7 @@ function createAttribute($collectionId, $attribute, $response, $dbForInternal, $ 'size' => $size, 'required' => $required, 'signed' => $signed, - 'default' => $defaultEncoded, + 'default' => $default, 'array' => $array, 'format' => $format, 'formatOptions' => $formatOptions, @@ -97,9 +95,6 @@ function createAttribute($collectionId, $attribute, $response, $dbForInternal, $ $dbForInternal->purgeDocument('collections', $collectionId); - // Only attributes table needs $default encoded as a string, reset before response - $attribute->setAttribute('default', $default); - // Pass clone of $attribute object to workers // so we can later modify Document to fit response model $clone = clone $attribute; @@ -805,13 +800,7 @@ App::get('/v1/database/collections/:collectionId/attributes') throw new Exception('Collection not found', 404); } - $attributes = $collection->getAttributes(); - - $attributes = array_map(function ($attribute) use ($collection) { - return new Document([\array_merge($attribute, [ - 'collectionId' => $collection->getId(), - ])]); - }, $attributes); + $attributes = $collection->getAttribute('attributes', []); $response->dynamic(new Document([ 'sum' => \count($attributes), diff --git a/app/init.php b/app/init.php index f6b82bba3..8f93c717d 100644 --- a/app/init.php +++ b/app/init.php @@ -145,7 +145,7 @@ if(!empty($user) || !empty($pass)) { } /** - * DB Filters + * Old DB Filters */ DatabaseOld::addFilter('json', function($value) { @@ -181,6 +181,18 @@ DatabaseOld::addFilter('encrypt', } ); +/** + * New DB Filters + */ +Database::addFilter('defaultValue', + function($value) { + return \json_encode(['value' => $value]); + }, + function($value) { + return \json_decode($value, true)['value']; + } +); + Database::addFilter('subQueryAttributes', function($value) { return null; From 6c5ac312fa95878cc3d755d187ad2b8a0d188074 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Fri, 27 Aug 2021 16:24:48 -0400 Subject: [PATCH 31/58] Inherit from Attribute model since custom strings should not respond with size --- src/Appwrite/Utopia/Response/Model/AttributeEmail.php | 4 ++-- src/Appwrite/Utopia/Response/Model/AttributeIP.php | 4 ++-- src/Appwrite/Utopia/Response/Model/AttributeURL.php | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Appwrite/Utopia/Response/Model/AttributeEmail.php b/src/Appwrite/Utopia/Response/Model/AttributeEmail.php index 1c058e6b0..15bc4674e 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeEmail.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeEmail.php @@ -3,9 +3,9 @@ namespace Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response; -use Appwrite\Utopia\Response\Model\AttributeString; +use Appwrite\Utopia\Response\Model\Attribute; -class AttributeEmail extends AttributeString +class AttributeEmail extends Attribute { public function __construct() { diff --git a/src/Appwrite/Utopia/Response/Model/AttributeIP.php b/src/Appwrite/Utopia/Response/Model/AttributeIP.php index 8272c2760..ec3a9cfed 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeIP.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeIP.php @@ -3,9 +3,9 @@ namespace Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response; -use Appwrite\Utopia\Response\Model\AttributeString; +use Appwrite\Utopia\Response\Model\Attribute; -class AttributeIP extends AttributeString +class AttributeIP extends Attribute { public function __construct() { diff --git a/src/Appwrite/Utopia/Response/Model/AttributeURL.php b/src/Appwrite/Utopia/Response/Model/AttributeURL.php index 3bb05f4fa..3caddbc10 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeURL.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeURL.php @@ -3,9 +3,9 @@ namespace Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response; -use Appwrite\Utopia\Response\Model\AttributeString; +use Appwrite\Utopia\Response\Model\Attribute; -class AttributeURL extends AttributeString +class AttributeURL extends Attribute { public function __construct() { From fb80088286aee0c37d980779c6cbe0109f919a13 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Fri, 27 Aug 2021 16:27:48 -0400 Subject: [PATCH 32/58] Create range filter for numeric attributes --- app/config/collections2.php | 2 +- app/controllers/api/database.php | 21 ++++++--------------- app/init.php | 26 ++++++++++++++++++++++++-- app/workers/database.php | 3 --- 4 files changed, 31 insertions(+), 21 deletions(-) diff --git a/app/config/collections2.php b/app/config/collections2.php index a01133fdd..a14d58cf2 100644 --- a/app/config/collections2.php +++ b/app/config/collections2.php @@ -214,7 +214,7 @@ $collections = [ 'required' => false, 'default' => new stdClass, 'array' => false, - 'filters' => ['json'], + 'filters' => ['json', 'range'], ], [ '$id' => 'filters', diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index c01d38fa6..3b839cae6 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -800,7 +800,9 @@ App::get('/v1/database/collections/:collectionId/attributes') throw new Exception('Collection not found', 404); } - $attributes = $collection->getAttribute('attributes', []); + $attributes = $dbForInternal->find('attributes', [ + new Query('collectionId', Query::TYPE_EQUAL, [$collection->getId()]) + ], 100); $response->dynamic(new Document([ 'sum' => \count($attributes), @@ -833,18 +835,9 @@ App::get('/v1/database/collections/:collectionId/attributes/:attributeId') throw new Exception('Collection not found', 404); } - // Search for matching attribute in collection - $attribute = null; - $attributes = $collection->getAttribute('attributes'); /** @var Document[] $attributes */ + $attribute = $dbForInternal->getDocument('attributes', $attributeId); - foreach ($attributes as $a) { - if ($a->getId() === $attributeId) { - $attribute = $a; - break; // stop once the attribute is found - } - } - - if (\is_null($attribute)) { + if ($attribute === false) { throw new Exception('Attribute not found', 404); } @@ -867,9 +860,7 @@ App::get('/v1/database/collections/:collectionId/attributes/:attributeId') }; // Format response - $default = \json_decode($attribute->getAttribute('default', []), true)['value'] ?? null; - $attribute->setAttribute('default', $default); - + // TODO@kodumbeats test if this is necessary with range filter if ($model === Response::MODEL_ATTRIBUTE_INTEGER || $model === Response::MODEL_ATTRIBUTE_FLOAT) { $attribute->setAttribute('min', $formatOptions['min']); diff --git a/app/init.php b/app/init.php index 8f93c717d..eaf8358a1 100644 --- a/app/init.php +++ b/app/init.php @@ -186,10 +186,32 @@ DatabaseOld::addFilter('encrypt', */ Database::addFilter('defaultValue', function($value) { - return \json_encode(['value' => $value]); + return json_encode(['value' => $value]); }, function($value) { - return \json_decode($value, true)['value']; + return json_decode($value, true)['value']; + } +); + +Database::addFilter('range', + function($value, Document $attribute) { + if ($attribute->isSet('min')) { + $attribute->removeAttribute('min'); + } + if ($attribute->isSet('max')) { + $attribute->removeAttribute('max'); + } + return $value; + }, + function($value, Document $attribute) { + $formatOptions = json_decode($attribute->getAttribute('formatOptions', []), true); + if (isset($formatOptions['min']) || isset($formatOptions['max'])) { + $attribute + ->setAttribute('min', $formatOptions['min']) + ->setAttribute('max', $formatOptions['max']) + ; + } + return $value; } ); diff --git a/app/workers/database.php b/app/workers/database.php index 381fb1c5e..fd3824615 100644 --- a/app/workers/database.php +++ b/app/workers/database.php @@ -88,9 +88,6 @@ class DatabaseV1 extends Worker if(!$dbForExternal->createAttribute($collectionId, $key, $type, $size, $required, $default, $signed, $array, $format, $formatOptions, $filters)) { throw new Exception('Failed to create Attribute'); } - if (!\is_null($default)) { - $attribute->setAttribute('default', json_encode(['value' => $default])); - } $dbForInternal->updateDocument('attributes', $attribute->getId(), $attribute->setAttribute('status', 'available')); } catch (\Throwable $th) { Console::error($th->getMessage()); From 783e9d86c0049fe06dc070078cb57f35b7c7fc74 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Fri, 27 Aug 2021 16:27:59 -0400 Subject: [PATCH 33/58] Fix response models --- src/Appwrite/Utopia/Response/Model.php | 2 +- src/Appwrite/Utopia/Response/Model/AttributeFloat.php | 8 ++++---- src/Appwrite/Utopia/Response/Model/AttributeList.php | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Appwrite/Utopia/Response/Model.php b/src/Appwrite/Utopia/Response/Model.php index 40a882527..a763692c7 100644 --- a/src/Appwrite/Utopia/Response/Model.php +++ b/src/Appwrite/Utopia/Response/Model.php @@ -8,7 +8,7 @@ abstract class Model { const TYPE_STRING = 'string'; const TYPE_INTEGER = 'integer'; - const TYPE_FLOAT = 'float'; + const TYPE_FLOAT = 'double'; const TYPE_BOOLEAN = 'boolean'; const TYPE_JSON = 'json'; diff --git a/src/Appwrite/Utopia/Response/Model/AttributeFloat.php b/src/Appwrite/Utopia/Response/Model/AttributeFloat.php index a0f68ec6a..7c4ead9e7 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeFloat.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeFloat.php @@ -13,18 +13,18 @@ class AttributeFloat extends Attribute $this ->addRule('min', [ - 'type' => self::TYPE_INTEGER, + 'type' => self::TYPE_FLOAT, 'description' => 'Minimum value to enforce for new documents.', 'default' => null, - 'example' => 1, + 'example' => 1.5, 'array' => false, 'require' => false, ]) ->addRule('max', [ - 'type' => self::TYPE_INTEGER, + 'type' => self::TYPE_FLOAT, 'description' => 'Maximum value to enforce for new documents.', 'default' => null, - 'example' => 10, + 'example' => 10.5, 'array' => false, 'require' => false, ]) diff --git a/src/Appwrite/Utopia/Response/Model/AttributeList.php b/src/Appwrite/Utopia/Response/Model/AttributeList.php index 5484db61f..26ea146ec 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeList.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeList.php @@ -25,7 +25,7 @@ class AttributeList extends Model 'getNestedType' => function(Document $attribute) { return match($attribute->getAttribute('type')) { self::TYPE_BOOLEAN => Response::MODEL_ATTRIBUTE_BOOLEAN, - self::TYPE_INTEGER=> Response::MODEL_ATTRIBUTE_INTEGER, + self::TYPE_INTEGER => Response::MODEL_ATTRIBUTE_INTEGER, self::TYPE_FLOAT => Response::MODEL_ATTRIBUTE_FLOAT, self::TYPE_STRING => match($attribute->getAttribute('format')) { APP_DATABASE_ATTRIBUTE_EMAIL => Response::MODEL_ATTRIBUTE_EMAIL, From a9c1a91a3eb37488293dfa91d3c38775aae3ce94 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Fri, 27 Aug 2021 16:30:26 -0400 Subject: [PATCH 34/58] Test response model for listAttributes endpoint --- tests/e2e/Services/Database/DatabaseBase.php | 74 +++++++++++++++++++- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/tests/e2e/Services/Database/DatabaseBase.php b/tests/e2e/Services/Database/DatabaseBase.php index b175f8a79..52de1e89f 100644 --- a/tests/e2e/Services/Database/DatabaseBase.php +++ b/tests/e2e/Services/Database/DatabaseBase.php @@ -371,13 +371,83 @@ trait DatabaseBase $this->assertEquals($boolean['body']['array'], $booleanResponse['body']['array']); $this->assertEquals($boolean['body']['default'], $booleanResponse['body']['default']); - $collection = $this->client->call(Client::METHOD_GET, '/database/collections/' . $collectionId, array_merge([ + $attributes = $this->client->call(Client::METHOD_GET, '/database/collections/' . $collectionId . '/attributes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - // TODO@kodumbeats test for proper attribute response in collection + $this->assertEquals(200, $attributes['headers']['status-code']); + $this->assertEquals(7, $attributes['body']['sum']); + + $attributes = $attributes['body']['attributes']; + + $this->assertIsArray($attributes); + $this->assertCount(7, $attributes); + + $this->assertEquals($stringResponse['body']['key'], $attributes[0]['key']); + $this->assertEquals($stringResponse['body']['type'], $attributes[0]['type']); + $this->assertEquals($stringResponse['body']['status'], $attributes[0]['status']); + $this->assertEquals($stringResponse['body']['required'], $attributes[0]['required']); + $this->assertEquals($stringResponse['body']['array'], $attributes[0]['array']); + $this->assertEquals($stringResponse['body']['size'], $attributes[0]['size']); + $this->assertEquals($stringResponse['body']['default'], $attributes[0]['default']); + + $this->assertEquals($emailResponse['body']['key'], $attributes[1]['key']); + $this->assertEquals($emailResponse['body']['type'], $attributes[1]['type']); + $this->assertEquals($emailResponse['body']['status'], $attributes[1]['status']); + $this->assertEquals($emailResponse['body']['required'], $attributes[1]['required']); + $this->assertEquals($emailResponse['body']['array'], $attributes[1]['array']); + $this->assertEquals($emailResponse['body']['default'], $attributes[1]['default']); + $this->assertEquals($emailResponse['body']['format'], $attributes[1]['format']); + + $this->assertEquals($ipResponse['body']['key'], $attributes[2]['key']); + $this->assertEquals($ipResponse['body']['type'], $attributes[2]['type']); + $this->assertEquals($ipResponse['body']['status'], $attributes[2]['status']); + $this->assertEquals($ipResponse['body']['required'], $attributes[2]['required']); + $this->assertEquals($ipResponse['body']['array'], $attributes[2]['array']); + $this->assertEquals($ipResponse['body']['default'], $attributes[2]['default']); + $this->assertEquals($ipResponse['body']['format'], $attributes[2]['format']); + + $this->assertEquals($urlResponse['body']['key'], $attributes[3]['key']); + $this->assertEquals($urlResponse['body']['type'], $attributes[3]['type']); + $this->assertEquals($urlResponse['body']['status'], $attributes[3]['status']); + $this->assertEquals($urlResponse['body']['required'], $attributes[3]['required']); + $this->assertEquals($urlResponse['body']['array'], $attributes[3]['array']); + $this->assertEquals($urlResponse['body']['default'], $attributes[3]['default']); + $this->assertEquals($urlResponse['body']['format'], $attributes[3]['format']); + + $this->assertEquals($integerResponse['body']['key'], $attributes[4]['key']); + $this->assertEquals($integerResponse['body']['type'], $attributes[4]['type']); + $this->assertEquals($integerResponse['body']['status'], $attributes[4]['status']); + $this->assertEquals($integerResponse['body']['required'], $attributes[4]['required']); + $this->assertEquals($integerResponse['body']['array'], $attributes[4]['array']); + $this->assertEquals($integerResponse['body']['default'], $attributes[4]['default']); + $this->assertEquals($integerResponse['body']['min'], $attributes[4]['min']); + $this->assertEquals($integerResponse['body']['max'], $attributes[4]['max']); + + $this->assertEquals($floatResponse['body']['key'], $attributes[5]['key']); + $this->assertEquals($floatResponse['body']['type'], $attributes[5]['type']); + $this->assertEquals($floatResponse['body']['status'], $attributes[5]['status']); + $this->assertEquals($floatResponse['body']['required'], $attributes[5]['required']); + $this->assertEquals($floatResponse['body']['array'], $attributes[5]['array']); + $this->assertEquals($floatResponse['body']['default'], $attributes[5]['default']); + $this->assertEquals($floatResponse['body']['min'], $attributes[5]['min']); + $this->assertEquals($floatResponse['body']['max'], $attributes[5]['max']); + + $this->assertEquals($booleanResponse['body']['key'], $attributes[6]['key']); + $this->assertEquals($booleanResponse['body']['type'], $attributes[6]['type']); + $this->assertEquals($booleanResponse['body']['status'], $attributes[6]['status']); + $this->assertEquals($booleanResponse['body']['required'], $attributes[6]['required']); + $this->assertEquals($booleanResponse['body']['array'], $attributes[6]['array']); + $this->assertEquals($booleanResponse['body']['default'], $attributes[6]['default']); + + $collection = $this->client->call(Client::METHOD_GET, '/database/collections/' . $collectionId, array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ])); + // var_dump($collection); $this->assertIsArray($collection['body']['attributes']); From f5b25c28dfbdaf12254eb8763dc69ee6b721bf44 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Fri, 27 Aug 2021 16:44:53 -0400 Subject: [PATCH 35/58] Pick up changes to encodeAttribute for range filter --- composer.json | 2 +- composer.lock | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/composer.json b/composer.json index 8467da809..ea8e195fb 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,7 @@ "utopia-php/cache": "0.4.*", "utopia-php/cli": "0.11.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "dev-feat-adjusted-query-validator as 0.10.0", + "utopia-php/database": "dev-feat-adjust-encodeAttribute as 0.10.0", "utopia-php/locale": "0.4.*", "utopia-php/registry": "0.5.*", "utopia-php/preloader": "0.2.*", diff --git a/composer.lock b/composer.lock index 792a6214d..63709836d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "aac413429914bd9299a7ae722f00cef8", + "content-hash": "95e162b8789c0727b4afac3191962fff", "packages": [ { "name": "adhocore/jwt", @@ -355,16 +355,16 @@ }, { "name": "composer/package-versions-deprecated", - "version": "1.11.99.2", + "version": "1.11.99.3", "source": { "type": "git", "url": "https://github.com/composer/package-versions-deprecated.git", - "reference": "c6522afe5540d5fc46675043d3ed5a45a740b27c" + "reference": "fff576ac850c045158a250e7e27666e146e78d18" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/c6522afe5540d5fc46675043d3ed5a45a740b27c", - "reference": "c6522afe5540d5fc46675043d3ed5a45a740b27c", + "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/fff576ac850c045158a250e7e27666e146e78d18", + "reference": "fff576ac850c045158a250e7e27666e146e78d18", "shasum": "" }, "require": { @@ -408,7 +408,7 @@ "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", "support": { "issues": "https://github.com/composer/package-versions-deprecated/issues", - "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.2" + "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.3" }, "funding": [ { @@ -424,7 +424,7 @@ "type": "tidelift" } ], - "time": "2021-05-24T07:46:03+00:00" + "time": "2021-08-17T13:49:14+00:00" }, { "name": "dragonmantank/cron-expression", @@ -1984,16 +1984,16 @@ }, { "name": "utopia-php/database", - "version": "dev-feat-adjusted-query-validator", + "version": "dev-feat-adjust-encodeAttribute", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "cb73391371f70ddb54bc0000064b15c5f173cb7a" + "reference": "5ef32ec85143daf78796e7826453244d24f8a86a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/cb73391371f70ddb54bc0000064b15c5f173cb7a", - "reference": "cb73391371f70ddb54bc0000064b15c5f173cb7a", + "url": "https://api.github.com/repos/utopia-php/database/zipball/5ef32ec85143daf78796e7826453244d24f8a86a", + "reference": "5ef32ec85143daf78796e7826453244d24f8a86a", "shasum": "" }, "require": { @@ -2041,9 +2041,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/feat-adjusted-query-validator" + "source": "https://github.com/utopia-php/database/tree/feat-adjust-encodeAttribute" }, - "time": "2021-08-23T14:18:47+00:00" + "time": "2021-08-27T20:39:51+00:00" }, { "name": "utopia-php/domains", @@ -6257,7 +6257,7 @@ "aliases": [ { "package": "utopia-php/database", - "version": "dev-feat-adjusted-query-validator", + "version": "dev-feat-adjust-encodeAttribute", "alias": "0.10.0", "alias_normalized": "0.10.0.0" } @@ -6287,5 +6287,5 @@ "platform-overrides": { "php": "8.0" }, - "plugin-api-version": "2.0.0" + "plugin-api-version": "2.1.0" } From d135a14bd4fcaf99895807150bd4b127c7cff93c Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Fri, 27 Aug 2021 16:45:33 -0400 Subject: [PATCH 36/58] Test for attribute response model in collection subquery --- tests/e2e/Services/Database/DatabaseBase.php | 74 +++++++++++++++++--- 1 file changed, 65 insertions(+), 9 deletions(-) diff --git a/tests/e2e/Services/Database/DatabaseBase.php b/tests/e2e/Services/Database/DatabaseBase.php index 52de1e89f..b2d604ead 100644 --- a/tests/e2e/Services/Database/DatabaseBase.php +++ b/tests/e2e/Services/Database/DatabaseBase.php @@ -450,15 +450,71 @@ trait DatabaseBase // var_dump($collection); - $this->assertIsArray($collection['body']['attributes']); - $this->assertCount(7, $collection['body']['attributes']); - $this->assertEquals($collection['body']['attributes'][0]['key'], $string['body']['key']); - $this->assertEquals($collection['body']['attributes'][1]['key'], $email['body']['key']); - $this->assertEquals($collection['body']['attributes'][2]['key'], $ip['body']['key']); - $this->assertEquals($collection['body']['attributes'][3]['key'], $url['body']['key']); - $this->assertEquals($collection['body']['attributes'][4]['key'], $integer['body']['key']); - $this->assertEquals($collection['body']['attributes'][5]['key'], $float['body']['key']); - $this->assertEquals($collection['body']['attributes'][6]['key'], $boolean['body']['key']); + $this->assertEquals(200, $collection['headers']['status-code']); + + $attributes = $collection['body']['attributes']; + + $this->assertIsArray($attributes); + $this->assertCount(7, $attributes); + + var_dump($attributes); + + $this->assertEquals($stringResponse['body']['key'], $attributes[0]['key']); + $this->assertEquals($stringResponse['body']['type'], $attributes[0]['type']); + $this->assertEquals($stringResponse['body']['status'], $attributes[0]['status']); + $this->assertEquals($stringResponse['body']['required'], $attributes[0]['required']); + $this->assertEquals($stringResponse['body']['array'], $attributes[0]['array']); + $this->assertEquals($stringResponse['body']['size'], $attributes[0]['size']); + $this->assertEquals($stringResponse['body']['default'], $attributes[0]['default']); + + $this->assertEquals($emailResponse['body']['key'], $attributes[1]['key']); + $this->assertEquals($emailResponse['body']['type'], $attributes[1]['type']); + $this->assertEquals($emailResponse['body']['status'], $attributes[1]['status']); + $this->assertEquals($emailResponse['body']['required'], $attributes[1]['required']); + $this->assertEquals($emailResponse['body']['array'], $attributes[1]['array']); + $this->assertEquals($emailResponse['body']['default'], $attributes[1]['default']); + $this->assertEquals($emailResponse['body']['format'], $attributes[1]['format']); + + $this->assertEquals($ipResponse['body']['key'], $attributes[2]['key']); + $this->assertEquals($ipResponse['body']['type'], $attributes[2]['type']); + $this->assertEquals($ipResponse['body']['status'], $attributes[2]['status']); + $this->assertEquals($ipResponse['body']['required'], $attributes[2]['required']); + $this->assertEquals($ipResponse['body']['array'], $attributes[2]['array']); + $this->assertEquals($ipResponse['body']['default'], $attributes[2]['default']); + $this->assertEquals($ipResponse['body']['format'], $attributes[2]['format']); + + $this->assertEquals($urlResponse['body']['key'], $attributes[3]['key']); + $this->assertEquals($urlResponse['body']['type'], $attributes[3]['type']); + $this->assertEquals($urlResponse['body']['status'], $attributes[3]['status']); + $this->assertEquals($urlResponse['body']['required'], $attributes[3]['required']); + $this->assertEquals($urlResponse['body']['array'], $attributes[3]['array']); + $this->assertEquals($urlResponse['body']['default'], $attributes[3]['default']); + $this->assertEquals($urlResponse['body']['format'], $attributes[3]['format']); + + $this->assertEquals($integerResponse['body']['key'], $attributes[4]['key']); + $this->assertEquals($integerResponse['body']['type'], $attributes[4]['type']); + $this->assertEquals($integerResponse['body']['status'], $attributes[4]['status']); + $this->assertEquals($integerResponse['body']['required'], $attributes[4]['required']); + $this->assertEquals($integerResponse['body']['array'], $attributes[4]['array']); + $this->assertEquals($integerResponse['body']['default'], $attributes[4]['default']); + $this->assertEquals($integerResponse['body']['min'], $attributes[4]['min']); + $this->assertEquals($integerResponse['body']['max'], $attributes[4]['max']); + + $this->assertEquals($floatResponse['body']['key'], $attributes[5]['key']); + $this->assertEquals($floatResponse['body']['type'], $attributes[5]['type']); + $this->assertEquals($floatResponse['body']['status'], $attributes[5]['status']); + $this->assertEquals($floatResponse['body']['required'], $attributes[5]['required']); + $this->assertEquals($floatResponse['body']['array'], $attributes[5]['array']); + $this->assertEquals($floatResponse['body']['default'], $attributes[5]['default']); + $this->assertEquals($floatResponse['body']['min'], $attributes[5]['min']); + $this->assertEquals($floatResponse['body']['max'], $attributes[5]['max']); + + $this->assertEquals($booleanResponse['body']['key'], $attributes[6]['key']); + $this->assertEquals($booleanResponse['body']['type'], $attributes[6]['type']); + $this->assertEquals($booleanResponse['body']['status'], $attributes[6]['status']); + $this->assertEquals($booleanResponse['body']['required'], $attributes[6]['required']); + $this->assertEquals($booleanResponse['body']['array'], $attributes[6]['array']); + $this->assertEquals($booleanResponse['body']['default'], $attributes[6]['default']); // return $data; } From 8d7b4a9c2d45d737953babc180a957398259a348 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Fri, 27 Aug 2021 19:42:24 -0400 Subject: [PATCH 37/58] Get proper attribute models in collection document --- .../Utopia/Response/Model/Collection.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Appwrite/Utopia/Response/Model/Collection.php b/src/Appwrite/Utopia/Response/Model/Collection.php index 398bcf770..f023be261 100644 --- a/src/Appwrite/Utopia/Response/Model/Collection.php +++ b/src/Appwrite/Utopia/Response/Model/Collection.php @@ -4,6 +4,7 @@ namespace Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Model; +use Utopia\Database\Document; use stdClass; class Collection extends Model @@ -48,7 +49,21 @@ class Collection extends Model 'description' => 'Collection attributes.', 'default' => [], 'example' => new stdClass, - 'array' => true + 'array' => true, + 'getNestedType' => function(Document $attribute) { + return match($attribute->getAttribute('type')) { + self::TYPE_BOOLEAN => Response::MODEL_ATTRIBUTE_BOOLEAN, + self::TYPE_INTEGER => Response::MODEL_ATTRIBUTE_INTEGER, + self::TYPE_FLOAT => Response::MODEL_ATTRIBUTE_FLOAT, + self::TYPE_STRING => match($attribute->getAttribute('format')) { + APP_DATABASE_ATTRIBUTE_EMAIL => Response::MODEL_ATTRIBUTE_EMAIL, + APP_DATABASE_ATTRIBUTE_IP => Response::MODEL_ATTRIBUTE_IP, + APP_DATABASE_ATTRIBUTE_URL => Response::MODEL_ATTRIBUTE_URL, + default => Response::MODEL_ATTRIBUTE_STRING, + }, + default => Response::MODEL_ATTRIBUTE, + }; + }, ]) ->addRule('indexes', [ 'type' => Response::MODEL_INDEX, From ed705829459f5d668587af0fb70640c6250ffe35 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Fri, 27 Aug 2021 19:42:53 -0400 Subject: [PATCH 38/58] Fix error on null default values --- app/init.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/init.php b/app/init.php index eaf8358a1..b8fcbdb11 100644 --- a/app/init.php +++ b/app/init.php @@ -189,6 +189,9 @@ Database::addFilter('defaultValue', return json_encode(['value' => $value]); }, function($value) { + if (is_null($value)) { + return null; + } return json_decode($value, true)['value']; } ); From c3534b43835f7d4ec37c2911dc6ffa99f7cd6ff8 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Fri, 27 Aug 2021 19:45:18 -0400 Subject: [PATCH 39/58] Clean up code --- app/controllers/api/database.php | 9 --------- tests/e2e/Services/Database/DatabaseBase.php | 15 +++++---------- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index 2c134022d..b97c1dee0 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -846,7 +846,6 @@ App::get('/v1/database/collections/:collectionId/attributes/:attributeId') // Select response model based on type and format $type = $attribute->getAttribute('type'); $format = $attribute->getAttribute('format'); - $formatOptions = $attribute->getAttribute('formatOptions'); $model = match($type) { Database::VAR_BOOLEAN => Response::MODEL_ATTRIBUTE_BOOLEAN, @@ -861,14 +860,6 @@ App::get('/v1/database/collections/:collectionId/attributes/:attributeId') default => Response::MODEL_ATTRIBUTE, }; - // Format response - // TODO@kodumbeats test if this is necessary with range filter - if ($model === Response::MODEL_ATTRIBUTE_INTEGER || $model === Response::MODEL_ATTRIBUTE_FLOAT) - { - $attribute->setAttribute('min', $formatOptions['min']); - $attribute->setAttribute('max', $formatOptions['max']); - } - $response->dynamic($attribute, $model); }); diff --git a/tests/e2e/Services/Database/DatabaseBase.php b/tests/e2e/Services/Database/DatabaseBase.php index b2d604ead..380f6bd26 100644 --- a/tests/e2e/Services/Database/DatabaseBase.php +++ b/tests/e2e/Services/Database/DatabaseBase.php @@ -100,11 +100,10 @@ trait DatabaseBase return $data; } - // /** - // * @depends testCreateAttributes - // */ - // public function testAttributeResponseModels(array $data): array - public function testAttributeResponseModels() + /** + * @depends testCreateAttributes + */ + public function testAttributeResponseModels(array $data): array { $collection= $this->client->call(Client::METHOD_POST, '/database/collections', array_merge([ 'content-type' => 'application/json', @@ -448,8 +447,6 @@ trait DatabaseBase 'x-appwrite-key' => $this->getProject()['apiKey'] ])); - // var_dump($collection); - $this->assertEquals(200, $collection['headers']['status-code']); $attributes = $collection['body']['attributes']; @@ -457,8 +454,6 @@ trait DatabaseBase $this->assertIsArray($attributes); $this->assertCount(7, $attributes); - var_dump($attributes); - $this->assertEquals($stringResponse['body']['key'], $attributes[0]['key']); $this->assertEquals($stringResponse['body']['type'], $attributes[0]['type']); $this->assertEquals($stringResponse['body']['status'], $attributes[0]['status']); @@ -516,7 +511,7 @@ trait DatabaseBase $this->assertEquals($booleanResponse['body']['array'], $attributes[6]['array']); $this->assertEquals($booleanResponse['body']['default'], $attributes[6]['default']); - // return $data; + return $data; } /** From 559fe95b7cb63208398c258b1a00ac537f5c7010 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Fri, 27 Aug 2021 20:32:44 -0400 Subject: [PATCH 40/58] Prefer single query to internal DB --- app/controllers/api/database.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index b97c1dee0..a38c342b2 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -802,9 +802,7 @@ App::get('/v1/database/collections/:collectionId/attributes') throw new Exception('Collection not found', 404); } - $attributes = $dbForInternal->find('attributes', [ - new Query('collectionId', Query::TYPE_EQUAL, [$collection->getId()]) - ], 100); + $attributes = $collection->getAttribute('attributes'); $response->dynamic(new Document([ 'sum' => \count($attributes), @@ -837,9 +835,9 @@ App::get('/v1/database/collections/:collectionId/attributes/:attributeId') throw new Exception('Collection not found', 404); } - $attribute = $dbForInternal->getDocument('attributes', $attributeId); + $attribute = $collection->find('$id', $attributeId, 'attributes'); - if ($attribute === false) { + if (!$attribute) { throw new Exception('Attribute not found', 404); } From 53b8a1c245800b9df14c4dfa70327f93a692bcf3 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Tue, 31 Aug 2021 14:00:28 -0400 Subject: [PATCH 41/58] Rename defaultValue filter to casting --- app/config/collections2.php | 2 +- app/init.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/config/collections2.php b/app/config/collections2.php index a14d58cf2..6e13f19f2 100644 --- a/app/config/collections2.php +++ b/app/config/collections2.php @@ -174,7 +174,7 @@ $collections = [ 'required' => false, 'default' => null, 'array' => false, - 'filters' => ['defaultValue'], + 'filters' => ['casting'], ], [ '$id' => 'signed', diff --git a/app/init.php b/app/init.php index b8fcbdb11..cdaf8cfeb 100644 --- a/app/init.php +++ b/app/init.php @@ -184,7 +184,7 @@ DatabaseOld::addFilter('encrypt', /** * New DB Filters */ -Database::addFilter('defaultValue', +Database::addFilter('casting', function($value) { return json_encode(['value' => $value]); }, From 0992576e525394c6dbbf5f8b22eaa381cb0bb756 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Tue, 14 Sep 2021 10:26:16 +0200 Subject: [PATCH 42/58] introduce response type array --- src/Appwrite/Utopia/Response.php | 21 +++++++++++++-- src/Appwrite/Utopia/Response/Model.php | 7 ++--- .../Utopia/Response/Model/Attribute.php | 2 ++ .../Response/Model/AttributeBoolean.php | 4 +++ .../Utopia/Response/Model/AttributeEmail.php | 5 ++++ .../Utopia/Response/Model/AttributeFloat.php | 4 +++ .../Utopia/Response/Model/AttributeIP.php | 5 ++++ .../Response/Model/AttributeInteger.php | 4 +++ .../Utopia/Response/Model/AttributeList.php | 26 +++++++------------ .../Utopia/Response/Model/AttributeString.php | 4 +++ .../Utopia/Response/Model/AttributeURL.php | 5 ++++ .../Utopia/Response/Model/Collection.php | 24 +++++++---------- 12 files changed, 73 insertions(+), 38 deletions(-) diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index a653ddbb0..00e4194c8 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -341,7 +341,24 @@ class Response extends SwooleResponse foreach ($data[$key] as &$item) { if ($item instanceof Document) { - $ruleType = (!\is_null($rule['getNestedType'])) ? $rule['getNestedType']($item) : $rule['type']; + if (\is_array($rule['type'])) { + foreach ($rule['type'] as $type) { + $condition = false; + foreach ($this->getModel($type)->conditions as $attribute => $val) { + $condition = $item->getAttribute($attribute) === $val; + if(!$condition) { + break; + } + } + if ($condition) { + $ruleType = $type; + break; + } + } + } else { + $ruleType = $rule['type']; + } + if (!array_key_exists($ruleType, $this->models)) { throw new Exception('Missing model for rule: '. $ruleType); } @@ -350,7 +367,7 @@ class Response extends SwooleResponse } } } - + $output[$key] = $data[$key]; } diff --git a/src/Appwrite/Utopia/Response/Model.php b/src/Appwrite/Utopia/Response/Model.php index a763692c7..4c3143ca9 100644 --- a/src/Appwrite/Utopia/Response/Model.php +++ b/src/Appwrite/Utopia/Response/Model.php @@ -69,13 +69,11 @@ abstract class Model /** * Add a New Rule * If rule is an array of documents with varying models - * Pass callable $getNestedType that accepts Document and returns the nested response type * * @param string $key * @param array $options - * @param callable $getNestedType function(Document $value): string */ - protected function addRule(string $key, array $options, callable $getNestedType = null): self + protected function addRule(string $key, array $options): self { $this->rules[$key] = array_merge([ 'require' => true, @@ -83,8 +81,7 @@ abstract class Model 'description' => '', 'default' => null, 'example' => '', - 'array' => false, - 'getNestedType' => $getNestedType + 'array' => false ], $options); return $this; diff --git a/src/Appwrite/Utopia/Response/Model/Attribute.php b/src/Appwrite/Utopia/Response/Model/Attribute.php index 2c9dbf7c2..281a37a73 100644 --- a/src/Appwrite/Utopia/Response/Model/Attribute.php +++ b/src/Appwrite/Utopia/Response/Model/Attribute.php @@ -44,6 +44,8 @@ class Attribute extends Model ; } + public array $conditions = []; + /** * Get Name * diff --git a/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php b/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php index 4076bc9eb..66aab770d 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php @@ -23,6 +23,10 @@ class AttributeBoolean extends Attribute ; } + public array $conditions = [ + 'type' => self::TYPE_BOOLEAN + ]; + /** * Get Name * diff --git a/src/Appwrite/Utopia/Response/Model/AttributeEmail.php b/src/Appwrite/Utopia/Response/Model/AttributeEmail.php index 15bc4674e..a048e2c41 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeEmail.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeEmail.php @@ -31,6 +31,11 @@ class AttributeEmail extends Attribute ; } + public array $conditions = [ + 'type' => self::TYPE_STRING, + 'format' => \APP_DATABASE_ATTRIBUTE_EMAIL + ]; + /** * Get Name * diff --git a/src/Appwrite/Utopia/Response/Model/AttributeFloat.php b/src/Appwrite/Utopia/Response/Model/AttributeFloat.php index 7c4ead9e7..56ed9c68d 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeFloat.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeFloat.php @@ -39,6 +39,10 @@ class AttributeFloat extends Attribute ; } + public array $conditions = [ + 'type' => self::TYPE_FLOAT, + ]; + /** * Get Name * diff --git a/src/Appwrite/Utopia/Response/Model/AttributeIP.php b/src/Appwrite/Utopia/Response/Model/AttributeIP.php index ec3a9cfed..6e3a8d7ba 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeIP.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeIP.php @@ -31,6 +31,11 @@ class AttributeIP extends Attribute ; } + public array $conditions = [ + 'type' => self::TYPE_STRING, + 'format' => \APP_DATABASE_ATTRIBUTE_IP + ]; + /** * Get Name * diff --git a/src/Appwrite/Utopia/Response/Model/AttributeInteger.php b/src/Appwrite/Utopia/Response/Model/AttributeInteger.php index f11344d79..b2e86c79b 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeInteger.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeInteger.php @@ -39,6 +39,10 @@ class AttributeInteger extends Attribute ; } + public array $conditions = [ + 'type' => self::TYPE_INTEGER, + ]; + /** * Get Name * * @return string diff --git a/src/Appwrite/Utopia/Response/Model/AttributeList.php b/src/Appwrite/Utopia/Response/Model/AttributeList.php index 26ea146ec..cad333bdf 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeList.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeList.php @@ -18,24 +18,18 @@ class AttributeList extends Model 'example' => 5, ]) ->addRule('attributes', [ - 'type' => Response::MODEL_ATTRIBUTE, + 'type' => [ + Response::MODEL_ATTRIBUTE_BOOLEAN, + Response::MODEL_ATTRIBUTE_INTEGER, + Response::MODEL_ATTRIBUTE_FLOAT, + Response::MODEL_ATTRIBUTE_EMAIL, + Response::MODEL_ATTRIBUTE_URL, + Response::MODEL_ATTRIBUTE_IP, + Response::MODEL_ATTRIBUTE_STRING // needs to be last, since its condition would dominate any other string attribute + ], 'description' => 'List of attributes.', 'default' => [], - 'array' => true, - 'getNestedType' => function(Document $attribute) { - return match($attribute->getAttribute('type')) { - self::TYPE_BOOLEAN => Response::MODEL_ATTRIBUTE_BOOLEAN, - self::TYPE_INTEGER => Response::MODEL_ATTRIBUTE_INTEGER, - self::TYPE_FLOAT => Response::MODEL_ATTRIBUTE_FLOAT, - self::TYPE_STRING => match($attribute->getAttribute('format')) { - APP_DATABASE_ATTRIBUTE_EMAIL => Response::MODEL_ATTRIBUTE_EMAIL, - APP_DATABASE_ATTRIBUTE_IP => Response::MODEL_ATTRIBUTE_IP, - APP_DATABASE_ATTRIBUTE_URL => Response::MODEL_ATTRIBUTE_URL, - default => Response::MODEL_ATTRIBUTE_STRING, - }, - default => Response::MODEL_ATTRIBUTE, - }; - }, + 'array' => true ]) ; } diff --git a/src/Appwrite/Utopia/Response/Model/AttributeString.php b/src/Appwrite/Utopia/Response/Model/AttributeString.php index 22f7e52a3..9feaf6b7b 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeString.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeString.php @@ -29,6 +29,10 @@ class AttributeString extends Attribute ; } + public array $conditions = [ + 'type' => self::TYPE_STRING, + ]; + /** * Get Name * diff --git a/src/Appwrite/Utopia/Response/Model/AttributeURL.php b/src/Appwrite/Utopia/Response/Model/AttributeURL.php index 3caddbc10..476d9bba0 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeURL.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeURL.php @@ -31,6 +31,11 @@ class AttributeURL extends Attribute ; } + public array $conditions = [ + 'type' => self::TYPE_STRING, + 'format' => \APP_DATABASE_ATTRIBUTE_URL + ]; + /** * Get Name * diff --git a/src/Appwrite/Utopia/Response/Model/Collection.php b/src/Appwrite/Utopia/Response/Model/Collection.php index f023be261..e52539691 100644 --- a/src/Appwrite/Utopia/Response/Model/Collection.php +++ b/src/Appwrite/Utopia/Response/Model/Collection.php @@ -45,25 +45,19 @@ class Collection extends Model 'example' => 'document', ]) ->addRule('attributes', [ - 'type' => Response::MODEL_ATTRIBUTE, + 'type' => [ + Response::MODEL_ATTRIBUTE_BOOLEAN, + Response::MODEL_ATTRIBUTE_INTEGER, + Response::MODEL_ATTRIBUTE_FLOAT, + Response::MODEL_ATTRIBUTE_EMAIL, + Response::MODEL_ATTRIBUTE_URL, + Response::MODEL_ATTRIBUTE_IP, + Response::MODEL_ATTRIBUTE_STRING, // needs to be last, since its condition would dominate any other string attribute + ], 'description' => 'Collection attributes.', 'default' => [], 'example' => new stdClass, 'array' => true, - 'getNestedType' => function(Document $attribute) { - return match($attribute->getAttribute('type')) { - self::TYPE_BOOLEAN => Response::MODEL_ATTRIBUTE_BOOLEAN, - self::TYPE_INTEGER => Response::MODEL_ATTRIBUTE_INTEGER, - self::TYPE_FLOAT => Response::MODEL_ATTRIBUTE_FLOAT, - self::TYPE_STRING => match($attribute->getAttribute('format')) { - APP_DATABASE_ATTRIBUTE_EMAIL => Response::MODEL_ATTRIBUTE_EMAIL, - APP_DATABASE_ATTRIBUTE_IP => Response::MODEL_ATTRIBUTE_IP, - APP_DATABASE_ATTRIBUTE_URL => Response::MODEL_ATTRIBUTE_URL, - default => Response::MODEL_ATTRIBUTE_STRING, - }, - default => Response::MODEL_ATTRIBUTE, - }; - }, ]) ->addRule('indexes', [ 'type' => Response::MODEL_INDEX, From 4cf16c88edf04ae97724762bdafdfb56f2075499 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Wed, 15 Sep 2021 11:17:09 -0400 Subject: [PATCH 43/58] Update docblocks for getType --- src/Appwrite/Utopia/Response/Model/AttributeBoolean.php | 2 +- src/Appwrite/Utopia/Response/Model/AttributeEmail.php | 2 +- src/Appwrite/Utopia/Response/Model/AttributeFloat.php | 2 +- src/Appwrite/Utopia/Response/Model/AttributeIP.php | 2 +- src/Appwrite/Utopia/Response/Model/AttributeInteger.php | 2 +- src/Appwrite/Utopia/Response/Model/AttributeList.php | 2 +- src/Appwrite/Utopia/Response/Model/AttributeString.php | 2 +- src/Appwrite/Utopia/Response/Model/AttributeURL.php | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php b/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php index 66aab770d..de7ae5813 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php @@ -38,7 +38,7 @@ class AttributeBoolean extends Attribute } /** - * Get Collection + * Get Type * * @return string */ diff --git a/src/Appwrite/Utopia/Response/Model/AttributeEmail.php b/src/Appwrite/Utopia/Response/Model/AttributeEmail.php index a048e2c41..268412a55 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeEmail.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeEmail.php @@ -47,7 +47,7 @@ class AttributeEmail extends Attribute } /** - * Get Collection + * Get Type * * @return string */ diff --git a/src/Appwrite/Utopia/Response/Model/AttributeFloat.php b/src/Appwrite/Utopia/Response/Model/AttributeFloat.php index 56ed9c68d..93033f5b0 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeFloat.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeFloat.php @@ -54,7 +54,7 @@ class AttributeFloat extends Attribute } /** - * Get Collection + * Get Type * * @return string */ diff --git a/src/Appwrite/Utopia/Response/Model/AttributeIP.php b/src/Appwrite/Utopia/Response/Model/AttributeIP.php index 6e3a8d7ba..2b8f64ded 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeIP.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeIP.php @@ -47,7 +47,7 @@ class AttributeIP extends Attribute } /** - * Get Collection + * Get Type * * @return string */ diff --git a/src/Appwrite/Utopia/Response/Model/AttributeInteger.php b/src/Appwrite/Utopia/Response/Model/AttributeInteger.php index b2e86c79b..9ff94c8f5 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeInteger.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeInteger.php @@ -53,7 +53,7 @@ class AttributeInteger extends Attribute } /** - * Get Collection + * Get Type * * @return string */ diff --git a/src/Appwrite/Utopia/Response/Model/AttributeList.php b/src/Appwrite/Utopia/Response/Model/AttributeList.php index cad333bdf..0cf67b3bd 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeList.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeList.php @@ -45,7 +45,7 @@ class AttributeList extends Model } /** - * Get Collection + * Get Type * * @return string */ diff --git a/src/Appwrite/Utopia/Response/Model/AttributeString.php b/src/Appwrite/Utopia/Response/Model/AttributeString.php index 9feaf6b7b..e7ea85326 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeString.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeString.php @@ -44,7 +44,7 @@ class AttributeString extends Attribute } /** - * Get Collection + * Get Type * * @return string */ diff --git a/src/Appwrite/Utopia/Response/Model/AttributeURL.php b/src/Appwrite/Utopia/Response/Model/AttributeURL.php index 476d9bba0..489e03885 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeURL.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeURL.php @@ -47,7 +47,7 @@ class AttributeURL extends Attribute } /** - * Get Collection + * Get Type * * @return string */ From e8f77ae3633873f922fd7ae922f4c48c6d6897a8 Mon Sep 17 00:00:00 2001 From: Matej Baco Date: Tue, 21 Sep 2021 14:01:18 +0200 Subject: [PATCH 44/58] OpenAPI3 support for anyOf --- composer.lock | 119 +++++++++--------- .../Specification/Format/OpenAPI3.php | 28 ++++- 2 files changed, 84 insertions(+), 63 deletions(-) diff --git a/composer.lock b/composer.lock index c867efc33..27c2af756 100644 --- a/composer.lock +++ b/composer.lock @@ -248,16 +248,16 @@ }, { "name": "chillerlan/php-settings-container", - "version": "2.1.1", + "version": "2.1.2", "source": { "type": "git", "url": "https://github.com/chillerlan/php-settings-container.git", - "reference": "98ccc1b31b31a53bcb563465c4961879b2b93096" + "reference": "ec834493a88682dd69652a1eeaf462789ed0c5f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/chillerlan/php-settings-container/zipball/98ccc1b31b31a53bcb563465c4961879b2b93096", - "reference": "98ccc1b31b31a53bcb563465c4961879b2b93096", + "url": "https://api.github.com/repos/chillerlan/php-settings-container/zipball/ec834493a88682dd69652a1eeaf462789ed0c5f5", + "reference": "ec834493a88682dd69652a1eeaf462789ed0c5f5", "shasum": "" }, "require": { @@ -307,7 +307,7 @@ "type": "ko_fi" } ], - "time": "2021-01-06T15:57:03+00:00" + "time": "2021-09-06T15:17:01+00:00" }, { "name": "colinmollenhour/credis", @@ -355,16 +355,16 @@ }, { "name": "composer/package-versions-deprecated", - "version": "1.11.99.3", + "version": "1.11.99.4", "source": { "type": "git", "url": "https://github.com/composer/package-versions-deprecated.git", - "reference": "fff576ac850c045158a250e7e27666e146e78d18" + "reference": "b174585d1fe49ceed21928a945138948cb394600" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/fff576ac850c045158a250e7e27666e146e78d18", - "reference": "fff576ac850c045158a250e7e27666e146e78d18", + "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/b174585d1fe49ceed21928a945138948cb394600", + "reference": "b174585d1fe49ceed21928a945138948cb394600", "shasum": "" }, "require": { @@ -408,7 +408,7 @@ "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", "support": { "issues": "https://github.com/composer/package-versions-deprecated/issues", - "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.3" + "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.4" }, "funding": [ { @@ -424,7 +424,7 @@ "type": "tidelift" } ], - "time": "2021-08-17T13:49:14+00:00" + "time": "2021-09-13T08:41:34+00:00" }, { "name": "dragonmantank/cron-expression", @@ -3383,16 +3383,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.12.0", + "version": "v4.13.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "6608f01670c3cc5079e18c1dab1104e002579143" + "reference": "50953a2691a922aa1769461637869a0a2faa3f53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6608f01670c3cc5079e18c1dab1104e002579143", - "reference": "6608f01670c3cc5079e18c1dab1104e002579143", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/50953a2691a922aa1769461637869a0a2faa3f53", + "reference": "50953a2691a922aa1769461637869a0a2faa3f53", "shasum": "" }, "require": { @@ -3433,9 +3433,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.12.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.0" }, - "time": "2021-07-21T10:44:31+00:00" + "time": "2021-09-20T12:20:58+00:00" }, { "name": "openlss/lib-array2xml", @@ -3712,16 +3712,16 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.4.0", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0" + "reference": "30f38bffc6f24293dadd1823936372dfa9e86e2f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", - "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/30f38bffc6f24293dadd1823936372dfa9e86e2f", + "reference": "30f38bffc6f24293dadd1823936372dfa9e86e2f", "shasum": "" }, "require": { @@ -3729,7 +3729,8 @@ "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { - "ext-tokenizer": "*" + "ext-tokenizer": "*", + "psalm/phar": "^4.8" }, "type": "library", "extra": { @@ -3755,39 +3756,39 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.4.0" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.5.0" }, - "time": "2020-09-17T18:55:26+00:00" + "time": "2021-09-17T15:28:14+00:00" }, { "name": "phpspec/prophecy", - "version": "1.13.0", + "version": "1.14.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "be1996ed8adc35c3fd795488a653f4b518be70ea" + "reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/be1996ed8adc35c3fd795488a653f4b518be70ea", - "reference": "be1996ed8adc35c3fd795488a653f4b518be70ea", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e", + "reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e", "shasum": "" }, "require": { "doctrine/instantiator": "^1.2", - "php": "^7.2 || ~8.0, <8.1", + "php": "^7.2 || ~8.0, <8.2", "phpdocumentor/reflection-docblock": "^5.2", "sebastian/comparator": "^3.0 || ^4.0", "sebastian/recursion-context": "^3.0 || ^4.0" }, "require-dev": { - "phpspec/phpspec": "^6.0", + "phpspec/phpspec": "^6.0 || ^7.0", "phpunit/phpunit": "^8.0 || ^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.11.x-dev" + "dev-master": "1.x-dev" } }, "autoload": { @@ -3822,29 +3823,29 @@ ], "support": { "issues": "https://github.com/phpspec/prophecy/issues", - "source": "https://github.com/phpspec/prophecy/tree/1.13.0" + "source": "https://github.com/phpspec/prophecy/tree/1.14.0" }, - "time": "2021-03-17T13:42:18+00:00" + "time": "2021-09-10T09:02:12+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.6", + "version": "9.2.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "f6293e1b30a2354e8428e004689671b83871edde" + "reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f6293e1b30a2354e8428e004689671b83871edde", - "reference": "f6293e1b30a2354e8428e004689671b83871edde", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d4c798ed8d51506800b441f7a13ecb0f76f12218", + "reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.10.2", + "nikic/php-parser": "^4.12.0", "php": ">=7.3", "phpunit/php-file-iterator": "^3.0.3", "phpunit/php-text-template": "^2.0.2", @@ -3893,7 +3894,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.6" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.7" }, "funding": [ { @@ -3901,7 +3902,7 @@ "type": "github" } ], - "time": "2021-03-28T07:26:59+00:00" + "time": "2021-09-17T05:39:03+00:00" }, { "name": "phpunit/php-file-iterator", @@ -5313,16 +5314,16 @@ }, { "name": "symfony/console", - "version": "v5.3.6", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "51b71afd6d2dc8f5063199357b9880cea8d8bfe2" + "reference": "8b1008344647462ae6ec57559da166c2bfa5e16a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/51b71afd6d2dc8f5063199357b9880cea8d8bfe2", - "reference": "51b71afd6d2dc8f5063199357b9880cea8d8bfe2", + "url": "https://api.github.com/repos/symfony/console/zipball/8b1008344647462ae6ec57559da166c2bfa5e16a", + "reference": "8b1008344647462ae6ec57559da166c2bfa5e16a", "shasum": "" }, "require": { @@ -5392,7 +5393,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.3.6" + "source": "https://github.com/symfony/console/tree/v5.3.7" }, "funding": [ { @@ -5408,7 +5409,7 @@ "type": "tidelift" } ], - "time": "2021-07-27T19:10:22+00:00" + "time": "2021-08-25T20:02:16+00:00" }, { "name": "symfony/deprecation-contracts", @@ -5882,16 +5883,16 @@ }, { "name": "symfony/string", - "version": "v5.3.3", + "version": "v5.3.7", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "bd53358e3eccec6a670b5f33ab680d8dbe1d4ae1" + "reference": "8d224396e28d30f81969f083a58763b8b9ceb0a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/bd53358e3eccec6a670b5f33ab680d8dbe1d4ae1", - "reference": "bd53358e3eccec6a670b5f33ab680d8dbe1d4ae1", + "url": "https://api.github.com/repos/symfony/string/zipball/8d224396e28d30f81969f083a58763b8b9ceb0a5", + "reference": "8d224396e28d30f81969f083a58763b8b9ceb0a5", "shasum": "" }, "require": { @@ -5945,7 +5946,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.3.3" + "source": "https://github.com/symfony/string/tree/v5.3.7" }, "funding": [ { @@ -5961,7 +5962,7 @@ "type": "tidelift" } ], - "time": "2021-06-27T11:44:38+00:00" + "time": "2021-08-26T08:00:08+00:00" }, { "name": "theseer/tokenizer", @@ -6015,16 +6016,16 @@ }, { "name": "twig/twig", - "version": "v2.14.6", + "version": "v2.14.7", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "27e5cf2b05e3744accf39d4c68a3235d9966d260" + "reference": "8e202327ee1ed863629de9b18a5ec70ac614d88f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/27e5cf2b05e3744accf39d4c68a3235d9966d260", - "reference": "27e5cf2b05e3744accf39d4c68a3235d9966d260", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/8e202327ee1ed863629de9b18a5ec70ac614d88f", + "reference": "8e202327ee1ed863629de9b18a5ec70ac614d88f", "shasum": "" }, "require": { @@ -6034,7 +6035,7 @@ }, "require-dev": { "psr/container": "^1.0", - "symfony/phpunit-bridge": "^4.4.9|^5.0.9" + "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0" }, "type": "library", "extra": { @@ -6078,7 +6079,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v2.14.6" + "source": "https://github.com/twigphp/Twig/tree/v2.14.7" }, "funding": [ { @@ -6090,7 +6091,7 @@ "type": "tidelift" } ], - "time": "2021-05-16T12:12:47+00:00" + "time": "2021-09-17T08:39:54+00:00" }, { "name": "vimeo/psalm", diff --git a/src/Appwrite/Specification/Format/OpenAPI3.php b/src/Appwrite/Specification/Format/OpenAPI3.php index 5095c5395..f032e6652 100644 --- a/src/Appwrite/Specification/Format/OpenAPI3.php +++ b/src/Appwrite/Specification/Format/OpenAPI3.php @@ -6,6 +6,8 @@ use Appwrite\Specification\Format; use Appwrite\Template\Template; use stdClass; use Utopia\Validator; +use function array_map; +use function var_dump; class OpenAPI3 extends Format { @@ -39,7 +41,13 @@ class OpenAPI3 extends Format } if (!is_object($model)) return; foreach ($model->getRules() as $rule) { - $this->getUsedModels($rule['type'], $usedModels); + if(\is_array($rule['type'])) { + foreach ($rule['type'] as $type) { + $this->getUsedModels($type, $usedModels); + } + } else { + $this->getUsedModels($rule['type'], $usedModels); + } } } @@ -430,12 +438,24 @@ class OpenAPI3 extends Format $type = 'object'; $rule['type'] = ($rule['type']) ? $rule['type'] : 'none'; - $items = [ - '$ref' => '#/components/schemas/'.$rule['type'], - ]; + if(\is_array($rule['type'])) { + $items = [ + 'oneOf' => \array_map(function($type) { + return ['$ref' => '#/components/schemas/'.$type]; + }, $rule['type']) + ]; + } else { + $items = [ + '$ref' => '#/components/schemas/'.$rule['type'], + ]; + } + + break; } + + if($rule['array']) { $output['components']['schemas'][$model->getType()]['properties'][$name] = [ 'type' => 'array', From a87d482e495a41c625a2ab4d7fc3ac2a89e7d4dc Mon Sep 17 00:00:00 2001 From: Matej Baco Date: Tue, 21 Sep 2021 14:12:43 +0200 Subject: [PATCH 45/58] Swagger2 support for arrays (work-around) --- .../Specification/Format/OpenAPI3.php | 6 --- .../Specification/Format/Swagger2.php | 46 +++++++++++++------ 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/src/Appwrite/Specification/Format/OpenAPI3.php b/src/Appwrite/Specification/Format/OpenAPI3.php index f032e6652..54e668fbe 100644 --- a/src/Appwrite/Specification/Format/OpenAPI3.php +++ b/src/Appwrite/Specification/Format/OpenAPI3.php @@ -6,8 +6,6 @@ use Appwrite\Specification\Format; use Appwrite\Template\Template; use stdClass; use Utopia\Validator; -use function array_map; -use function var_dump; class OpenAPI3 extends Format { @@ -449,13 +447,9 @@ class OpenAPI3 extends Format '$ref' => '#/components/schemas/'.$rule['type'], ]; } - - break; } - - if($rule['array']) { $output['components']['schemas'][$model->getType()]['properties'][$name] = [ 'type' => 'array', diff --git a/src/Appwrite/Specification/Format/Swagger2.php b/src/Appwrite/Specification/Format/Swagger2.php index 2a3be45d1..5e14bd1f3 100644 --- a/src/Appwrite/Specification/Format/Swagger2.php +++ b/src/Appwrite/Specification/Format/Swagger2.php @@ -39,7 +39,13 @@ class Swagger2 extends Format } if (!is_object($model)) return; foreach ($model->getRules() as $rule) { - $this->getUsedModels($rule['type'], $usedModels); + if(\is_array($rule['type'])) { + foreach ($rule['type'] as $type) { + $this->getUsedModels($type, $usedModels); + } + } else { + $this->getUsedModels($rule['type'], $usedModels); + } } } @@ -91,15 +97,15 @@ class Swagger2 extends Format if (isset($output['securityDefinitions']['Project'])) { $output['securityDefinitions']['Project']['x-appwrite'] = ['demo' => '5df5acd0d48c2']; } - + if (isset($output['securityDefinitions']['Key'])) { $output['securityDefinitions']['Key']['x-appwrite'] = ['demo' => '919c2d18fb5d4...a2ae413da83346ad2']; } - + if (isset($output['securityDefinitions']['JWT'])) { $output['securityDefinitions']['JWT']['x-appwrite'] = ['demo' => 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...']; } - + if (isset($output['securityDefinitions']['Locale'])) { $output['securityDefinitions']['Locale']['x-appwrite'] = ['demo' => 'en']; } @@ -147,7 +153,7 @@ class Swagger2 extends Format if(empty($routeSecurity)) { $sdkPlatofrms[] = APP_PLATFORM_CLIENT; } - + $temp = [ 'summary' => $route->getDesc(), 'operationId' => $route->getLabel('sdk.namespace', 'default').ucfirst($id), @@ -216,7 +222,7 @@ class Swagger2 extends Format if ((!empty($scope))) { // && 'public' != $scope $securities = ['Project' => []]; - + foreach($route->getLabel('sdk.auth', []) as $security) { if(array_key_exists($security, $this->keys)) { $securities[$security] = []; @@ -226,7 +232,7 @@ class Swagger2 extends Format $temp['x-appwrite']['auth'] = array_slice($securities, 0, $this->authCount); $temp['security'][] = $securities; } - + $body = [ 'name' => 'payload', 'in' => 'body', @@ -399,7 +405,7 @@ class Swagger2 extends Format if($model->isAny()) { $output['definitions'][$model->getType()]['additionalProperties'] = true; } - + if(!empty($required)) { $output['definitions'][$model->getType()]['required'] = $required; } @@ -414,7 +420,7 @@ class Swagger2 extends Format case 'json': $type = 'string'; break; - + case 'integer': $type = 'integer'; $format = 'int32'; @@ -424,19 +430,29 @@ class Swagger2 extends Format $type = 'number'; $format = 'float'; break; - + case 'boolean': $type = 'boolean'; break; - + default: $type = 'object'; $rule['type'] = ($rule['type']) ? $rule['type'] : 'none'; - $items = [ - 'type' => $type, - '$ref' => '#/definitions/'.$rule['type'], - ]; + if(\is_array($rule['type'])) { + // THIS IS NOT SUPPORTED IN 2.0!!! +// $items = [ +// 'oneOf' => \array_map(function($type) { +// return ['$ref' => '#/definitions/'.$type]; +// }, $rule['type']) +// ]; + + $items = []; + } else { + $items = [ + '$ref' => '#/definitions/'.$rule['type'], + ]; + } break; } From b97542e581910e452da8a6d01a1be77282e7b5d3 Mon Sep 17 00:00:00 2001 From: Matej Baco Date: Tue, 21 Sep 2021 14:16:24 +0200 Subject: [PATCH 46/58] Swagger2 array fix --- src/Appwrite/Specification/Format/Swagger2.php | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Appwrite/Specification/Format/Swagger2.php b/src/Appwrite/Specification/Format/Swagger2.php index 5e14bd1f3..493dac0bb 100644 --- a/src/Appwrite/Specification/Format/Swagger2.php +++ b/src/Appwrite/Specification/Format/Swagger2.php @@ -440,14 +440,11 @@ class Swagger2 extends Format $rule['type'] = ($rule['type']) ? $rule['type'] : 'none'; if(\is_array($rule['type'])) { - // THIS IS NOT SUPPORTED IN 2.0!!! -// $items = [ -// 'oneOf' => \array_map(function($type) { -// return ['$ref' => '#/definitions/'.$type]; -// }, $rule['type']) -// ]; - - $items = []; + $items = [ + 'oneOf' => \array_map(function($type) { + return ['$ref' => '#/definitions/'.$type]; + }, $rule['type']) + ]; } else { $items = [ '$ref' => '#/definitions/'.$rule['type'], From 1eeddc80151fb3bc2bf8ea393955134b4dd4566c Mon Sep 17 00:00:00 2001 From: Matej Baco Date: Tue, 21 Sep 2021 14:19:25 +0200 Subject: [PATCH 47/58] This should not be removed --- src/Appwrite/Specification/Format/Swagger2.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Appwrite/Specification/Format/Swagger2.php b/src/Appwrite/Specification/Format/Swagger2.php index 493dac0bb..70811536c 100644 --- a/src/Appwrite/Specification/Format/Swagger2.php +++ b/src/Appwrite/Specification/Format/Swagger2.php @@ -447,6 +447,7 @@ class Swagger2 extends Format ]; } else { $items = [ + 'type' => $type, '$ref' => '#/definitions/'.$rule['type'], ]; } From d0e777edd5e27e8ca8c7ea5b7668865c61090a50 Mon Sep 17 00:00:00 2001 From: Matej Baco Date: Tue, 21 Sep 2021 14:25:41 +0200 Subject: [PATCH 48/58] Swagger Double type fix --- src/Appwrite/Specification/Format/OpenAPI3.php | 7 ++++++- src/Appwrite/Specification/Format/Swagger2.php | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Appwrite/Specification/Format/OpenAPI3.php b/src/Appwrite/Specification/Format/OpenAPI3.php index 54e668fbe..82eb69533 100644 --- a/src/Appwrite/Specification/Format/OpenAPI3.php +++ b/src/Appwrite/Specification/Format/OpenAPI3.php @@ -33,7 +33,7 @@ class OpenAPI3 extends Format */ protected function getUsedModels($model, array &$usedModels) { - if (is_string($model) && !in_array($model, ['string', 'integer', 'boolean', 'json', 'float'])) { + if (is_string($model) && !in_array($model, ['string', 'integer', 'boolean', 'json', 'float', 'double'])) { $usedModels[] = $model; return; } @@ -427,6 +427,11 @@ class OpenAPI3 extends Format $type = 'number'; $format = 'float'; break; + + case 'double': + $type = 'number'; + $format = 'double'; + break; case 'boolean': $type = 'boolean'; diff --git a/src/Appwrite/Specification/Format/Swagger2.php b/src/Appwrite/Specification/Format/Swagger2.php index 70811536c..397b97f96 100644 --- a/src/Appwrite/Specification/Format/Swagger2.php +++ b/src/Appwrite/Specification/Format/Swagger2.php @@ -33,7 +33,7 @@ class Swagger2 extends Format */ protected function getUsedModels($model, array &$usedModels) { - if (is_string($model) && !in_array($model, ['string', 'integer', 'boolean', 'json', 'float'])) { + if (is_string($model) && !in_array($model, ['string', 'integer', 'boolean', 'json', 'float', 'double'])) { $usedModels[] = $model; return; } @@ -431,6 +431,11 @@ class Swagger2 extends Format $format = 'float'; break; + case 'double': + $type = 'number'; + $format = 'double'; + break; + case 'boolean': $type = 'boolean'; break; From 9c9a17a2a44ac06113e9ec54b1e9248425b16091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Tue, 21 Sep 2021 20:33:11 +0200 Subject: [PATCH 49/58] Apply suggestions from code review Co-authored-by: Torsten Dittmann --- src/Appwrite/Specification/Format/OpenAPI3.php | 2 +- src/Appwrite/Specification/Format/Swagger2.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Appwrite/Specification/Format/OpenAPI3.php b/src/Appwrite/Specification/Format/OpenAPI3.php index 82eb69533..0c055fe70 100644 --- a/src/Appwrite/Specification/Format/OpenAPI3.php +++ b/src/Appwrite/Specification/Format/OpenAPI3.php @@ -443,7 +443,7 @@ class OpenAPI3 extends Format if(\is_array($rule['type'])) { $items = [ - 'oneOf' => \array_map(function($type) { + 'anyOf' => \array_map(function($type) { return ['$ref' => '#/components/schemas/'.$type]; }, $rule['type']) ]; diff --git a/src/Appwrite/Specification/Format/Swagger2.php b/src/Appwrite/Specification/Format/Swagger2.php index 397b97f96..88cec0b2a 100644 --- a/src/Appwrite/Specification/Format/Swagger2.php +++ b/src/Appwrite/Specification/Format/Swagger2.php @@ -446,7 +446,7 @@ class Swagger2 extends Format if(\is_array($rule['type'])) { $items = [ - 'oneOf' => \array_map(function($type) { + 'anyOf' => \array_map(function($type) { return ['$ref' => '#/definitions/'.$type]; }, $rule['type']) ]; From c87e686ca2224b202dcf4da5b6cc25dfa43c72d8 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Wed, 22 Sep 2021 21:29:56 -0400 Subject: [PATCH 50/58] Fix createUrlAttribute description --- app/controllers/api/database.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index a031888ce..0451287a2 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -785,7 +785,7 @@ App::post('/v1/database/collections/:collectionId/attributes/ip') }); App::post('/v1/database/collections/:collectionId/attributes/url') - ->desc('Create IP Address Attribute') + ->desc('Create URL Attribute') ->groups(['api', 'database']) ->label('event', 'database.attributes.create') ->label('scope', 'collections.write') From c97b15325507b6eca319fca1fa38ab741be4e43a Mon Sep 17 00:00:00 2001 From: Matej Baco Date: Thu, 23 Sep 2021 13:12:50 +0200 Subject: [PATCH 51/58] Implemented oneOf for non-array results with multiple types --- .../Specification/Format/OpenAPI3.php | 19 ++++++++++++++----- .../Specification/Format/Swagger2.php | 18 +++++++++++++----- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/Appwrite/Specification/Format/OpenAPI3.php b/src/Appwrite/Specification/Format/OpenAPI3.php index 0c055fe70..7bcfdd00a 100644 --- a/src/Appwrite/Specification/Format/OpenAPI3.php +++ b/src/Appwrite/Specification/Format/OpenAPI3.php @@ -6,6 +6,7 @@ use Appwrite\Specification\Format; use Appwrite\Template\Template; use stdClass; use Utopia\Validator; +use function var_dump; class OpenAPI3 extends Format { @@ -442,11 +443,19 @@ class OpenAPI3 extends Format $rule['type'] = ($rule['type']) ? $rule['type'] : 'none'; if(\is_array($rule['type'])) { - $items = [ - 'anyOf' => \array_map(function($type) { - return ['$ref' => '#/components/schemas/'.$type]; - }, $rule['type']) - ]; + if($rule['array']) { + $items = [ + 'anyOf' => \array_map(function($type) { + return ['$ref' => '#/components/schemas/'.$type]; + }, $rule['type']) + ]; + } else { + $items = [ + 'oneOf' => \array_map(function($type) { + return ['$ref' => '#/components/schemas/'.$type]; + }, $rule['type']) + ]; + } } else { $items = [ '$ref' => '#/components/schemas/'.$rule['type'], diff --git a/src/Appwrite/Specification/Format/Swagger2.php b/src/Appwrite/Specification/Format/Swagger2.php index 88cec0b2a..66324567b 100644 --- a/src/Appwrite/Specification/Format/Swagger2.php +++ b/src/Appwrite/Specification/Format/Swagger2.php @@ -445,11 +445,19 @@ class Swagger2 extends Format $rule['type'] = ($rule['type']) ? $rule['type'] : 'none'; if(\is_array($rule['type'])) { - $items = [ - 'anyOf' => \array_map(function($type) { - return ['$ref' => '#/definitions/'.$type]; - }, $rule['type']) - ]; + if($rule['array']) { + $items = [ + 'anyOf' => \array_map(function($type) { + return ['$ref' => '#/definitions/'.$type]; + }, $rule['type']) + ]; + } else { + $items = [ + 'oneOf' => \array_map(function($type) { + return ['$ref' => '#/definitions/'.$type]; + }, $rule['type']) + ]; + } } else { $items = [ 'type' => $type, From 36f55c8726364fdda25c629647046ff6fd3f8acc Mon Sep 17 00:00:00 2001 From: Matej Baco Date: Thu, 23 Sep 2021 13:13:22 +0200 Subject: [PATCH 52/58] Removed var dump --- src/Appwrite/Specification/Format/OpenAPI3.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Appwrite/Specification/Format/OpenAPI3.php b/src/Appwrite/Specification/Format/OpenAPI3.php index 7bcfdd00a..1d462669c 100644 --- a/src/Appwrite/Specification/Format/OpenAPI3.php +++ b/src/Appwrite/Specification/Format/OpenAPI3.php @@ -6,7 +6,6 @@ use Appwrite\Specification\Format; use Appwrite\Template\Template; use stdClass; use Utopia\Validator; -use function var_dump; class OpenAPI3 extends Format { From 73c0b23680c310cdde8ab8010d9599cf07db1210 Mon Sep 17 00:00:00 2001 From: Matej Baco Date: Thu, 30 Sep 2021 11:59:01 +0200 Subject: [PATCH 53/58] Swagger (2,3) support for multiple types of response --- app/controllers/web/home.php | 9 +- .../Specification/Format/OpenAPI3.php | 86 +++++++++++++------ .../Specification/Format/Swagger2.php | 59 ++++++++++--- 3 files changed, 114 insertions(+), 40 deletions(-) diff --git a/app/controllers/web/home.php b/app/controllers/web/home.php index 1d9e86d87..9f4d2412a 100644 --- a/app/controllers/web/home.php +++ b/app/controllers/web/home.php @@ -387,11 +387,10 @@ App::get('/specs/:format') } $routes[] = $route; - $model = $response->getModel($route->getLabel('sdk.response.model', 'none')); - - if($model) { - $models[$model->getType()] = $model; - } + $modelLabel = $route->getLabel('sdk.response.model', 'none'); + $model = \is_array($modelLabel) ? \array_map(function($m) use($response) { + return $response->getModel($m); + }, $modelLabel) : $response->getModel($modelLabel); } } diff --git a/src/Appwrite/Specification/Format/OpenAPI3.php b/src/Appwrite/Specification/Format/OpenAPI3.php index 1d462669c..b0a61114c 100644 --- a/src/Appwrite/Specification/Format/OpenAPI3.php +++ b/src/Appwrite/Specification/Format/OpenAPI3.php @@ -6,6 +6,7 @@ use Appwrite\Specification\Format; use Appwrite\Template\Template; use stdClass; use Utopia\Validator; +use function gettype; class OpenAPI3 extends Format { @@ -25,14 +26,14 @@ class OpenAPI3 extends Format * Get Used Models * * Recursively get all used models - * + * * @param object $model * @param array $models * * @return void */ protected function getUsedModels($model, array &$usedModels) - { + { if (is_string($model) && !in_array($model, ['string', 'integer', 'boolean', 'json', 'float', 'double'])) { $usedModels[] = $model; return; @@ -99,7 +100,7 @@ class OpenAPI3 extends Format if (isset($output['components']['securitySchemes']['Project'])) { $output['components']['securitySchemes']['Project']['x-appwrite'] = ['demo' => '5df5acd0d48c2']; } - + if (isset($output['components']['securitySchemes']['Key'])) { $output['components']['securitySchemes']['Key']['x-appwrite'] = ['demo' => '919c2d18fb5d4...a2ae413da83346ad2']; } @@ -107,7 +108,7 @@ class OpenAPI3 extends Format if (isset($output['securityDefinitions']['JWT'])) { $output['securityDefinitions']['JWT']['x-appwrite'] = ['demo' => 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...']; } - + if (isset($output['components']['securitySchemes']['Locale'])) { $output['components']['securitySchemes']['Locale']['x-appwrite'] = ['demo' => 'en']; } @@ -131,7 +132,7 @@ class OpenAPI3 extends Format $id = $route->getLabel('sdk.method', \uniqid()); $desc = (!empty($route->getLabel('sdk.description', ''))) ? \realpath(__DIR__.'/../../../../'.$route->getLabel('sdk.description', '')) : null; $produces = $route->getLabel('sdk.response.type', null); - $model = $route->getLabel('sdk.response.model', 'none'); + $model = $route->getLabel('sdk.response.model', 'none'); $routeSecurity = $route->getLabel('sdk.auth', []); $sdkPlatofrms = []; @@ -155,7 +156,7 @@ class OpenAPI3 extends Format if(empty($routeSecurity)) { $sdkPlatofrms[] = APP_PLATFORM_CLIENT; } - + $temp = [ 'summary' => $route->getDesc(), 'operationId' => $route->getLabel('sdk.namespace', 'default').ucfirst($id), @@ -181,13 +182,24 @@ class OpenAPI3 extends Format ]; foreach ($this->models as $key => $value) { - if($value->getType() === $model) { - $model = $value; - break; + if(\is_array($model)) { + $model = \array_map(function($m) use($value) { + if($m === $value->getType()) { + return $value; + } + + return $m; + }, $model); + } else { + if($value->getType() === $model) { + $model = $value; + break; + } } + } - if($model->isNone()) { + if(!(\is_array($model)) && $model->isNone()) { $temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [ 'description' => (in_array($produces, [ 'image/*', @@ -204,17 +216,43 @@ class OpenAPI3 extends Format // ], ]; } else { - $usedModels[] = $model->getType(); - $temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [ - 'description' => $model->getName(), - 'content' => [ - $produces => [ - 'schema' => [ - '$ref' => '#/components/schemas/'.$model->getType(), + if(\is_array($model)) { + $modelDescription = \join(', or ', \array_map(function ($m) { + return $m->getName(); + }, $model)); + + // model has multiple possible responses, we will use oneOf + foreach ($model as $m) { + $usedModels[] = $m->getType(); + } + + $temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [ + 'description' => $modelDescription, + 'content' => [ + $produces => [ + 'schema' => [ + 'oneOf' => \array_map(function($m) { + return ['$ref' => '#/components/schemas/'.$m->getType()]; + }, $model) + ], ], ], - ], - ]; + ]; + } else { + // Response definition using one type + $usedModels[] = $model->getType(); + $temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [ + 'description' => $model->getName(), + 'content' => [ + $produces => [ + 'schema' => [ + '$ref' => '#/components/schemas/'.$model->getType(), + ], + ], + ], + ]; + } + } if($route->getLabel('sdk.response.code', 500) === 204) { @@ -224,7 +262,7 @@ class OpenAPI3 extends Format if ((!empty($scope))) { // && 'public' != $scope $securities = ['Project' => []]; - + foreach($route->getLabel('sdk.auth', []) as $security) { if(array_key_exists($security, $this->keys)) { $securities[$security] = []; @@ -402,7 +440,7 @@ class OpenAPI3 extends Format if($model->isAny()) { $output['components']['schemas'][$model->getType()]['additionalProperties'] = true; } - + if(!empty($required)) { $output['components']['schemas'][$model->getType()]['required'] = $required; } @@ -417,7 +455,7 @@ class OpenAPI3 extends Format case 'json': $type = 'string'; break; - + case 'integer': $type = 'integer'; $format = 'int32'; @@ -432,11 +470,11 @@ class OpenAPI3 extends Format $type = 'number'; $format = 'double'; break; - + case 'boolean': $type = 'boolean'; break; - + default: $type = 'object'; $rule['type'] = ($rule['type']) ? $rule['type'] : 'none'; diff --git a/src/Appwrite/Specification/Format/Swagger2.php b/src/Appwrite/Specification/Format/Swagger2.php index 66324567b..a8dcffb1e 100644 --- a/src/Appwrite/Specification/Format/Swagger2.php +++ b/src/Appwrite/Specification/Format/Swagger2.php @@ -183,13 +183,22 @@ class Swagger2 extends Format } foreach ($this->models as $key => $value) { - if($value->getType() === $model) { - $model = $value; - break; + if(\is_array($model)) { + $model = \array_map(function($m) use($value) { + if($m === $value->getType()) { + return $value; + } + return $m; + }, $model); + } else { + if($value->getType() === $model) { + $model = $value; + break; + } } } - if($model->isNone()) { + if(!(\is_array($model)) && $model->isNone()) { $temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [ 'description' => (in_array($produces, [ 'image/*', @@ -206,13 +215,41 @@ class Swagger2 extends Format ], ]; } else { - $usedModels[] = $model->getType(); - $temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [ - 'description' => $model->getName(), - 'schema' => [ - '$ref' => '#/definitions/'.$model->getType(), - ], - ]; + + if(\is_array($model)) { + $modelDescription = \join(', or ', \array_map(function ($m) { + return $m->getName(); + }, $model)); + // model has multiple possible responses, we will use oneOf + foreach ($model as $m) { + $usedModels[] = $m->getType(); + } + $temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [ + 'description' => $modelDescription, + 'content' => [ + $produces => [ + 'schema' => [ + 'oneOf' => \array_map(function($m) { + return ['$ref' => '#/definitions/'.$m->getType()]; + }, $model) + ], + ], + ], + ]; + } else { + // Response definition using one type + $usedModels[] = $model->getType(); + $temp['responses'][(string)$route->getLabel('sdk.response.code', '500')] = [ + 'description' => $model->getName(), + 'content' => [ + $produces => [ + 'schema' => [ + '$ref' => '#/definitions/'.$model->getType(), + ], + ], + ], + ]; + } } if(in_array($route->getLabel('sdk.response.code', 500), [204, 301, 302, 308], true)) { From dd04158ae1baad6e940393484f33e8e1261623f2 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Thu, 30 Sep 2021 15:03:18 -0400 Subject: [PATCH 54/58] Return oneOf models for getAttribute --- app/controllers/api/database.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index a031888ce..2973adc40 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -1040,7 +1040,14 @@ App::get('/v1/database/collections/:collectionId/attributes/:attributeId') ->label('sdk.description', '/docs/references/database/get-attribute.md') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_ATTRIBUTE) + ->label('sdk.response.model', [ + Response::MODEL_ATTRIBUTE_BOOLEAN, + Response::MODEL_ATTRIBUTE_INTEGER, + Response::MODEL_ATTRIBUTE_FLOAT, + Response::MODEL_ATTRIBUTE_EMAIL, + Response::MODEL_ATTRIBUTE_URL, + Response::MODEL_ATTRIBUTE_IP, + Response::MODEL_ATTRIBUTE_STRING,])// needs to be last, since its condition would dominate any other string attribute ->param('collectionId', '', new UID(), 'Collection unique ID. You can create a new collection using the Database service [server integration](/docs/server/database#createCollection).') ->param('attributeId', '', new Key(), 'Attribute ID.') ->inject('response') From 7ca035960dc9019dcaca2b1fa95fe751ec59d155 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Thu, 30 Sep 2021 15:37:21 -0400 Subject: [PATCH 55/58] Fix attribute response model spec definitions --- app/controllers/api/database.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index 0451287a2..950095b11 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -663,7 +663,7 @@ App::post('/v1/database/collections/:collectionId/attributes/string') ->label('sdk.description', '/docs/references/database/create-attribute-string.md') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_ATTRIBUTE) + ->label('sdk.response.model', Response::MODEL_ATTRIBUTE_STRING) ->param('collectionId', '', new UID(), 'Collection unique ID. You can create a new collection using the Database service [server integration](/docs/server/database#createCollection).') ->param('attributeId', '', new Key(), 'Attribute ID.') ->param('size', null, new Integer(), 'Attribute size for text attributes, in number of characters.') @@ -711,7 +711,7 @@ App::post('/v1/database/collections/:collectionId/attributes/email') ->label('sdk.description', '/docs/references/database/create-attribute-email.md') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_ATTRIBUTE) + ->label('sdk.response.model', Response::MODEL_ATTRIBUTE_EMAIL) ->param('collectionId', '', new UID(), 'Collection unique ID. You can create a new collection using the Database service [server integration](/docs/server/database#createCollection).') ->param('attributeId', '', new Key(), 'Attribute ID.') ->param('required', null, new Boolean(), 'Is attribute required?') @@ -753,7 +753,7 @@ App::post('/v1/database/collections/:collectionId/attributes/ip') ->label('sdk.description', '/docs/references/database/create-attribute-ip.md') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_ATTRIBUTE) + ->label('sdk.response.model', Response::MODEL_ATTRIBUTE_IP) ->param('collectionId', '', new UID(), 'Collection unique ID. You can create a new collection using the Database service [server integration](/docs/server/database#createCollection).') ->param('attributeId', '', new Key(), 'Attribute ID.') ->param('required', null, new Boolean(), 'Is attribute required?') @@ -795,7 +795,7 @@ App::post('/v1/database/collections/:collectionId/attributes/url') ->label('sdk.description', '/docs/references/database/create-attribute-url.md') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_ATTRIBUTE) + ->label('sdk.response.model', Response::MODEL_ATTRIBUTE_URL) ->param('collectionId', '', new UID(), 'Collection unique ID. You can create a new collection using the Database service [server integration](/docs/server/database#createCollection).') ->param('attributeId', '', new Key(), 'Attribute ID.') ->param('required', null, new Boolean(), 'Is attribute required?') @@ -837,7 +837,7 @@ App::post('/v1/database/collections/:collectionId/attributes/integer') ->label('sdk.description', '/docs/references/database/create-attribute-integer.md') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_ATTRIBUTE) + ->label('sdk.response.model', Response::MODEL_ATTRIBUTE_INTEGER) ->param('collectionId', '', new UID(), 'Collection unique ID. You can create a new collection using the Database service [server integration](/docs/server/database#createCollection).') ->param('attributeId', '', new Key(), 'Attribute ID.') ->param('required', null, new Boolean(), 'Is attribute required?') @@ -901,7 +901,7 @@ App::post('/v1/database/collections/:collectionId/attributes/float') ->label('sdk.description', '/docs/references/database/create-attribute-float.md') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_ATTRIBUTE) + ->label('sdk.response.model', Response::MODEL_ATTRIBUTE_FLOAT) ->param('collectionId', '', new UID(), 'Collection unique ID. You can create a new collection using the Database service [server integration](/docs/server/database#createCollection).') ->param('attributeId', '', new Key(), 'Attribute ID.') ->param('required', null, new Boolean(), 'Is attribute required?') @@ -965,7 +965,7 @@ App::post('/v1/database/collections/:collectionId/attributes/boolean') ->label('sdk.description', '/docs/references/database/create-attribute-boolean.md') ->label('sdk.response.code', Response::STATUS_CODE_CREATED) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) - ->label('sdk.response.model', Response::MODEL_ATTRIBUTE) + ->label('sdk.response.model', Response::MODEL_ATTRIBUTE_BOOLEAN) ->param('collectionId', '', new UID(), 'Collection unique ID. You can create a new collection using the Database service [server integration](/docs/server/database#createCollection).') ->param('attributeId', '', new Key(), 'Attribute ID.') ->param('required', null, new Boolean(), 'Is attribute required?') From 22132ef42004cc56b7a846444dcd82f6636c6199 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Tue, 5 Oct 2021 09:05:19 -0400 Subject: [PATCH 56/58] Update to utopia-php/database:0.10.0 --- composer.json | 11 +++------ composer.lock | 63 ++++++++++++++++++++++++--------------------------- 2 files changed, 33 insertions(+), 41 deletions(-) diff --git a/composer.json b/composer.json index b251fb13a..b3d21a4b0 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,7 @@ "utopia-php/cache": "0.4.*", "utopia-php/cli": "0.11.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "dev-feat-adjust-encodeAttribute as 0.10.0", + "utopia-php/database": "0.10.0", "utopia-php/locale": "0.4.*", "utopia-php/registry": "0.5.*", "utopia-php/preloader": "0.2.*", @@ -63,12 +63,7 @@ "adhocore/jwt": "1.1.2", "slickdeals/statsd": "3.1.0" }, - "repositories": [ - { - "type": "git", - "url": "https://github.com/utopia-php/database" - } - ], + "repositories": [], "require-dev": { "appwrite/sdk-generator": "0.13.0", "swoole/ide-helper": "4.6.7", @@ -83,4 +78,4 @@ "php": "8.0" } } -} \ No newline at end of file +} diff --git a/composer.lock b/composer.lock index 27c2af756..7eee04c86 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "31670d6cc60a22007b4ed59a7dc9448f", + "content-hash": "dfb8fa19daa736b3687617c98f309983", "packages": [ { "name": "adhocore/jwt", @@ -1984,11 +1984,17 @@ }, { "name": "utopia-php/database", - "version": "dev-feat-adjust-encodeAttribute", + "version": "0.10.0", "source": { "type": "git", - "url": "https://github.com/utopia-php/database", - "reference": "5ef32ec85143daf78796e7826453244d24f8a86a" + "url": "https://github.com/utopia-php/database.git", + "reference": "b7c60b0ec769a9050dd2b939b78ff1f5d4fa27e8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/utopia-php/database/zipball/b7c60b0ec769a9050dd2b939b78ff1f5d4fa27e8", + "reference": "b7c60b0ec769a9050dd2b939b78ff1f5d4fa27e8", + "shasum": "" }, "require": { "ext-mongodb": "*", @@ -2011,11 +2017,7 @@ "Utopia\\Database\\": "src/Database" } }, - "autoload-dev": { - "psr-4": { - "Utopia\\Tests\\": "tests/Database" - } - }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -2037,7 +2039,11 @@ "upf", "utopia" ], - "time": "2021-08-27T20:39:51+00:00" + "support": { + "issues": "https://github.com/utopia-php/database/issues", + "source": "https://github.com/utopia-php/database/tree/0.10.0" + }, + "time": "2021-10-04T17:23:25+00:00" }, { "name": "utopia-php/domains", @@ -2576,16 +2582,16 @@ "packages-dev": [ { "name": "amphp/amp", - "version": "v2.6.0", + "version": "v2.6.1", "source": { "type": "git", "url": "https://github.com/amphp/amp.git", - "reference": "caa95edeb1ca1bf7532e9118ede4a3c3126408cc" + "reference": "c5fc66a78ee38d7ac9195a37bacaf940eb3f65ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/amp/zipball/caa95edeb1ca1bf7532e9118ede4a3c3126408cc", - "reference": "caa95edeb1ca1bf7532e9118ede4a3c3126408cc", + "url": "https://api.github.com/repos/amphp/amp/zipball/c5fc66a78ee38d7ac9195a37bacaf940eb3f65ae", + "reference": "c5fc66a78ee38d7ac9195a37bacaf940eb3f65ae", "shasum": "" }, "require": { @@ -2653,7 +2659,7 @@ "support": { "irc": "irc://irc.freenode.org/amphp", "issues": "https://github.com/amphp/amp/issues", - "source": "https://github.com/amphp/amp/tree/v2.6.0" + "source": "https://github.com/amphp/amp/tree/v2.6.1" }, "funding": [ { @@ -2661,7 +2667,7 @@ "type": "github" } ], - "time": "2021-07-16T20:06:06+00:00" + "time": "2021-09-23T18:43:08+00:00" }, { "name": "amphp/byte-stream", @@ -3712,16 +3718,16 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.5.0", + "version": "1.5.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "30f38bffc6f24293dadd1823936372dfa9e86e2f" + "reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/30f38bffc6f24293dadd1823936372dfa9e86e2f", - "reference": "30f38bffc6f24293dadd1823936372dfa9e86e2f", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/a12f7e301eb7258bb68acd89d4aefa05c2906cae", + "reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae", "shasum": "" }, "require": { @@ -3756,9 +3762,9 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.5.0" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.5.1" }, - "time": "2021-09-17T15:28:14+00:00" + "time": "2021-10-02T14:08:47+00:00" }, { "name": "phpspec/prophecy", @@ -6249,18 +6255,9 @@ "time": "2015-12-17T08:42:14+00:00" } ], - "aliases": [ - { - "package": "utopia-php/database", - "version": "dev-feat-adjust-encodeAttribute", - "alias": "0.10.0", - "alias_normalized": "0.10.0.0" - } - ], + "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "utopia-php/database": 20 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { From 481ff1e2f969eecc306cbe5d360595a0ffe459c0 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Tue, 5 Oct 2021 09:05:40 -0400 Subject: [PATCH 57/58] Refactor purgeDocument calls to deleteCachedDocument --- app/controllers/api/database.php | 8 ++++---- app/workers/database.php | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index 6d7268c24..0b288a9ab 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -96,7 +96,7 @@ function createAttribute($collectionId, $attribute, $response, $dbForInternal, $ throw new Exception('Attribute already exists', 409); } - $dbForInternal->purgeDocument('collections', $collectionId); + $dbForInternal->deleteCachedDocument('collections', $collectionId); // Pass clone of $attribute object to workers // so we can later modify Document to fit response model @@ -1131,7 +1131,7 @@ App::delete('/v1/database/collections/:collectionId/attributes/:attributeId') } $attribute = $dbForInternal->updateDocument('attributes', $attribute->getId(), $attribute->setAttribute('status', 'deleting')); - $dbForInternal->purgeDocument('collections', $collectionId); + $dbForInternal->deleteCachedDocument('collections', $collectionId); $database ->setParam('type', DATABASE_TYPE_DELETE_ATTRIBUTE) @@ -1238,7 +1238,7 @@ App::post('/v1/database/collections/:collectionId/indexes') throw new Exception('Index already exists', 409); } - $dbForInternal->purgeDocument('collections', $collectionId); + $dbForInternal->deleteCachedDocument('collections', $collectionId); $database ->setParam('type', DATABASE_TYPE_CREATE_INDEX) @@ -1383,7 +1383,7 @@ App::delete('/v1/database/collections/:collectionId/indexes/:indexId') } $index = $dbForInternal->updateDocument('indexes', $index->getId(), $index->setAttribute('status', 'deleting')); - $dbForInternal->purgeDocument('collections', $collectionId); + $dbForInternal->deleteCachedDocument('collections', $collectionId); $database ->setParam('type', DATABASE_TYPE_DELETE_INDEX) diff --git a/app/workers/database.php b/app/workers/database.php index 2366b3799..fb841c644 100644 --- a/app/workers/database.php +++ b/app/workers/database.php @@ -94,7 +94,7 @@ class DatabaseV1 extends Worker $dbForInternal->updateDocument('attributes', $attribute->getId(), $attribute->setAttribute('status', 'failed')); } - $dbForInternal->purgeDocument('collections', $collectionId); + $dbForInternal->deleteCachedDocument('collections', $collectionId); } /** @@ -120,7 +120,7 @@ class DatabaseV1 extends Worker $dbForInternal->updateDocument('attributes', $attribute->getId(), $attribute->setAttribute('status', 'failed')); } - $dbForInternal->purgeDocument('collections', $collectionId); + $dbForInternal->deleteCachedDocument('collections', $collectionId); } /** @@ -150,7 +150,7 @@ class DatabaseV1 extends Worker $dbForInternal->updateDocument('indexes', $index->getId(), $index->setAttribute('status', 'failed')); } - $dbForInternal->purgeDocument('collections', $collectionId); + $dbForInternal->deleteCachedDocument('collections', $collectionId); } /** @@ -177,6 +177,6 @@ class DatabaseV1 extends Worker $dbForInternal->updateDocument('indexes', $index->getId(), $index->setAttribute('status', 'failed')); } - $dbForInternal->purgeDocument('collections', $collectionId); + $dbForInternal->deleteCachedDocument('collections', $collectionId); } } From dc06e42348e4f0ae5f7ad9355ab13caf9d47a2dc Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Tue, 5 Oct 2021 09:16:27 -0400 Subject: [PATCH 58/58] Remove standard lib imports --- src/Appwrite/Specification/Format/OpenAPI3.php | 2 -- src/Appwrite/Utopia/Response/Model/Collection.php | 1 - 2 files changed, 3 deletions(-) diff --git a/src/Appwrite/Specification/Format/OpenAPI3.php b/src/Appwrite/Specification/Format/OpenAPI3.php index b0a61114c..8d375d2f9 100644 --- a/src/Appwrite/Specification/Format/OpenAPI3.php +++ b/src/Appwrite/Specification/Format/OpenAPI3.php @@ -4,9 +4,7 @@ namespace Appwrite\Specification\Format; use Appwrite\Specification\Format; use Appwrite\Template\Template; -use stdClass; use Utopia\Validator; -use function gettype; class OpenAPI3 extends Format { diff --git a/src/Appwrite/Utopia/Response/Model/Collection.php b/src/Appwrite/Utopia/Response/Model/Collection.php index e52539691..e46603fd9 100644 --- a/src/Appwrite/Utopia/Response/Model/Collection.php +++ b/src/Appwrite/Utopia/Response/Model/Collection.php @@ -5,7 +5,6 @@ namespace Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Model; use Utopia\Database\Document; -use stdClass; class Collection extends Model {