diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 7792dbb11f..7b8dbf4037 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -4,6 +4,7 @@ use Utopia\App; use Appwrite\Event\Delete; use Appwrite\Extend\Exception; use Utopia\Audit\Audit; +use Utopia\Database\Validator\DatetimeValidator; use Utopia\Validator\Boolean; use Utopia\Validator\FloatValidator; use Utopia\Validator\Integer; @@ -887,7 +888,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_ATTRIBUTE_STRING) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('key', '', new Key(), 'Attribute Key.') ->param('size', null, new Range(1, APP_DATABASE_ATTRIBUTE_STRING_MAX_LENGTH, Range::TYPE_INTEGER), 'Attribute size for text attributes, in number of characters.') ->param('required', null, new Boolean(), 'Is attribute required?') @@ -934,7 +935,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/email' ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_ATTRIBUTE_EMAIL) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') ->param('default', null, new Email(), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true) @@ -975,7 +976,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/enum') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_ATTRIBUTE_ENUM) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('key', '', new Key(), 'Attribute Key.') ->param('elements', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' elements are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.') ->param('required', null, new Boolean(), 'Is attribute required?') @@ -1032,7 +1033,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/ip') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_ATTRIBUTE_IP) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') ->param('default', null, new IP(), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true) @@ -1073,7 +1074,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/url') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_ATTRIBUTE_URL) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') ->param('default', null, new URL(), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true) @@ -1114,7 +1115,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/intege ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_ATTRIBUTE_INTEGER) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') ->param('min', null, new Integer(), 'Minimum value to enforce on new documents', true) @@ -1184,7 +1185,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/float' ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_ATTRIBUTE_FLOAT) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') ->param('min', null, new FloatValidator(), 'Minimum value to enforce on new documents', true) @@ -1257,7 +1258,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/boolea ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_ATTRIBUTE_BOOLEAN) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') ->param('default', null, new Boolean(), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true) @@ -1283,6 +1284,48 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/boolea $response->dynamic($attribute, Response::MODEL_ATTRIBUTE_BOOLEAN); }); + +App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/datetime') + ->alias('/v1/database/collections/:collectionId/attributes/datetime', ['databaseId' => 'default']) + ->desc('Create datetime Attribute') + ->groups(['api', 'database']) + ->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create') + ->label('scope', 'collections.write') + ->label('sdk.namespace', 'databases') + ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) + ->label('sdk.method', 'createDatetimeAttribute') + ->label('sdk.description', '/docs/references/databases/create-datetime-attribute.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_ATTRIBUTE_DATETIME) + ->param('databaseId', '', new UID(), 'Database ID.') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') + ->param('key', '', new Key(), 'Attribute Key.') + ->param('required', null, new Boolean(), 'Is attribute required?') + ->param('default', null, new DatetimeValidator(), '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('dbForProject') + ->inject('database') + ->inject('audits') + ->inject('usage') + ->inject('events') + ->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?bool $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, EventAudit $audits, Stats $usage, Event $events) { + + $attribute = createAttribute($databaseId, $collectionId, new Document([ + 'key' => $key, + 'type' => Database::VAR_DATETIME, + 'size' => 0, + 'required' => $required, + 'default' => $default, + 'array' => $array, + 'filters' => ['datetime'] + ]), $response, $dbForProject, $database, $audits, $events, $usage); + + $response->dynamic($attribute, Response::MODEL_ATTRIBUTE_DATETIME); + }); + + App::get('/v1/databases/:databaseId/collections/:collectionId/attributes') ->alias('/v1/database/collections/:collectionId/attributes', ['databaseId' => 'default']) ->desc('List Attributes') @@ -1296,7 +1339,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_ATTRIBUTE_LIST) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->inject('response') ->inject('dbForProject') ->inject('usage') @@ -1337,6 +1380,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes/:key') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', [ + Response::MODEL_ATTRIBUTE_DATETIME, Response::MODEL_ATTRIBUTE_BOOLEAN, Response::MODEL_ATTRIBUTE_INTEGER, Response::MODEL_ATTRIBUTE_FLOAT, @@ -1346,7 +1390,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes/:key') Response::MODEL_ATTRIBUTE_IP, Response::MODEL_ATTRIBUTE_STRING,])// needs to be last, since its condition would dominate any other string attribute ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('key', '', new Key(), 'Attribute Key.') ->inject('response') ->inject('dbForProject') @@ -1376,6 +1420,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes/:key') $format = $attribute->getAttribute('format'); $model = match ($type) { + Database::VAR_DATETIME => Response::MODEL_ATTRIBUTE_DATETIME, Database::VAR_BOOLEAN => Response::MODEL_ATTRIBUTE_BOOLEAN, Database::VAR_INTEGER => Response::MODEL_ATTRIBUTE_INTEGER, Database::VAR_FLOAT => Response::MODEL_ATTRIBUTE_FLOAT, @@ -1409,7 +1454,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) ->label('sdk.response.model', Response::MODEL_NONE) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('key', '', new Key(), 'Attribute Key.') ->inject('response') ->inject('dbForProject') @@ -1460,6 +1505,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key $format = $attribute->getAttribute('format'); $model = match ($type) { + Database::VAR_DATETIME => Response::MODEL_ATTRIBUTE_DATETIME, Database::VAR_BOOLEAN => Response::MODEL_ATTRIBUTE_BOOLEAN, Database::VAR_INTEGER => Response::MODEL_ATTRIBUTE_INTEGER, Database::VAR_FLOAT => Response::MODEL_ATTRIBUTE_FLOAT, @@ -1504,7 +1550,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_INDEX) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('key', null, new Key(), 'Index Key.') ->param('type', null, new WhiteList([Database::INDEX_KEY, Database::INDEX_FULLTEXT, Database::INDEX_UNIQUE, Database::INDEX_SPATIAL, Database::INDEX_ARRAY]), 'Index type.') ->param('attributes', null, new ArrayList(new Key(true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of attributes to index. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' attributes are allowed, each 32 characters long.') @@ -1659,7 +1705,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_INDEX_LIST) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->inject('response') ->inject('dbForProject') ->inject('usage') @@ -1701,7 +1747,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes/:key') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_INDEX) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('key', null, new Key(), 'Index Key.') ->inject('response') ->inject('dbForProject') @@ -1752,7 +1798,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key') ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) ->label('sdk.response.model', Response::MODEL_NONE) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', null, new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') + ->param('collectionId', null, new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('key', '', new Key(), 'Index Key.') ->inject('response') ->inject('dbForProject') @@ -1829,7 +1875,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') ->label('sdk.response.model', Response::MODEL_DOCUMENT) ->param('databaseId', '', new UID(), 'Database ID.') ->param('documentId', '', new CustomId(), 'Document ID. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') - ->param('collectionId', null, new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection). Make sure to define attributes before creating documents.') + ->param('collectionId', null, new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection). Make sure to define attributes before creating documents.') ->param('data', [], new JSON(), 'Document data as JSON object.') ->param('read', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with read permissions. By default only the current user is granted with read permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.', true) ->param('write', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with write permissions. By default only the current user is granted with write permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.', true) @@ -1950,8 +1996,8 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_DOCUMENT_LIST) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') - ->param('queries', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/database#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true) + ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') + ->param('queries', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true) ->param('limit', 25, new Range(0, 100), 'Maximum number of documents to return in response. By default will return maximum 25 results. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' results allowed per request.', true) ->param('offset', 0, new Range(0, APP_LIMIT_COUNT), 'Offset value. The default value is 0. Use this value to manage pagination. [learn more about pagination](https://appwrite.io/docs/pagination)', true) ->param('cursor', '', new UID(), 'ID of the document used as the starting point for the query, excluding the document itself. Should be used for efficient pagination when working with large sets of data. [learn more about pagination](https://appwrite.io/docs/pagination)', true) @@ -2064,7 +2110,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_DOCUMENT) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', null, new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') + ->param('collectionId', null, new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('documentId', null, new UID(), 'Document ID.') ->inject('response') ->inject('dbForProject') @@ -2367,7 +2413,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu ->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT) ->label('sdk.response.model', Response::MODEL_NONE) ->param('databaseId', '', new UID(), 'Database ID.') - ->param('collectionId', null, new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).') + ->param('collectionId', null, new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).') ->param('documentId', null, new UID(), 'Document ID.') ->inject('response') ->inject('dbForProject') diff --git a/app/init.php b/app/init.php index 146a4fc2a7..9c2bf32fed 100644 --- a/app/init.php +++ b/app/init.php @@ -93,6 +93,7 @@ const APP_VERSION_STABLE = '0.15.3'; const APP_DATABASE_ATTRIBUTE_EMAIL = 'email'; const APP_DATABASE_ATTRIBUTE_ENUM = 'enum'; const APP_DATABASE_ATTRIBUTE_IP = 'ip'; +const APP_DATABASE_ATTRIBUTE_DATETIME = 'datetime'; const APP_DATABASE_ATTRIBUTE_URL = 'url'; const APP_DATABASE_ATTRIBUTE_INT_RANGE = 'intRange'; const APP_DATABASE_ATTRIBUTE_FLOAT_RANGE = 'floatRange'; diff --git a/composer.json b/composer.json index a9feb4e861..cfb78c1f54 100644 --- a/composer.json +++ b/composer.json @@ -50,7 +50,7 @@ "utopia-php/cache": "0.6.*", "utopia-php/cli": "0.13.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "dev-feat-attr-datetime as 0.18.7", + "utopia-php/database": "0.19.*", "utopia-php/locale": "0.4.*", "utopia-php/registry": "0.5.*", "utopia-php/preloader": "0.2.*", diff --git a/docker-compose.yml b/docker-compose.yml index 3e4216d111..df2938cbc7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -103,7 +103,7 @@ services: - ./phpunit.xml:/usr/src/code/phpunit.xml - ./tests:/usr/src/code/tests - ./app:/usr/src/code/app - - ./vendor/utopia/database:/usr/src/code/vendor/utopia/database + - ./vendor/utopia-php/database:/usr/src/code/vendor/utopia-php/database - ./docs:/usr/src/code/docs - ./public:/usr/src/code/public - ./src:/usr/src/code/src @@ -208,7 +208,6 @@ services: - ./app:/usr/src/code/app - ./src:/usr/src/code/src # - ./vendor:/usr/src/code/vendor - - ./vendor/utopia/database:/usr/src/code/vendor/utopia/database depends_on: - mariadb - redis @@ -562,6 +561,7 @@ services: volumes: - ./app:/usr/src/code/app - ./src:/usr/src/code/src + #- ./vendor/utopia-php/database:/usr/src/code/vendor/utopia-php/database depends_on: - redis environment: diff --git a/docs/references/databases/create-collection.md b/docs/references/databases/create-collection.md index 6f6da13d53..259ad987ee 100644 --- a/docs/references/databases/create-collection.md +++ b/docs/references/databases/create-collection.md @@ -1 +1 @@ -Create a new Collection. Before using this route, you should create a new database resource using either a [server integration](/docs/server/database#databaseCreateCollection) API or directly from your database console. \ No newline at end of file +Create a new Collection. Before using this route, you should create a new database resource using either a [server integration](/docs/server/databases#databasesCreateCollection) API or directly from your database console. \ No newline at end of file diff --git a/docs/references/databases/create-document.md b/docs/references/databases/create-document.md index 25d0b403cd..10898b7d4d 100644 --- a/docs/references/databases/create-document.md +++ b/docs/references/databases/create-document.md @@ -1 +1 @@ -Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](/docs/server/database#databaseCreateCollection) API or directly from your database console. \ No newline at end of file +Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](/docs/server/databases#databasesCreateCollection) API or directly from your database console. \ No newline at end of file diff --git a/docs/references/storage/create-file.md b/docs/references/storage/create-file.md index b577d1a05d..77e5cf2225 100644 --- a/docs/references/storage/create-file.md +++ b/docs/references/storage/create-file.md @@ -1,4 +1,4 @@ -Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](/docs/server/database#storageCreateBucket) API or directly from your Appwrite console. +Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](/docs/server/storage#storageCreateBucket) API or directly from your Appwrite console. Larger files should be uploaded using multiple requests with the [content-range](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Range) header to send a partial request with a maximum supported chunk of `5MB`. The `content-range` header values should always be in bytes. diff --git a/docs/services/databases.md b/docs/services/databases.md index e5359c18ff..00076dc8da 100644 --- a/docs/services/databases.md +++ b/docs/services/databases.md @@ -2,6 +2,6 @@ The Databases service allows you to create structured collections of documents, All data returned by the Databases service are represented as structured JSON documents. -The Databases service can contain multiple databases, each database can contain multiple collections. A collection is a group of similarly structured documents. The accepted structure of documents is defined by [collection attributes](/docs/database#attributes). The collection attributes help you ensure all your user-submitted data is validated and stored according to the collection structure. +The Databases service can contain multiple databases, each database can contain multiple collections. A collection is a group of similarly structured documents. The accepted structure of documents is defined by [collection attributes](/docs/databases#attributes). The collection attributes help you ensure all your user-submitted data is validated and stored according to the collection structure. Using Appwrite permissions architecture, you can assign read or write access to each collection or document in your project for either a specific user, team, user role, or even grant it with public access (`role:all`). You can learn more about [how Appwrite handles permissions and access control](/docs/permissions). \ No newline at end of file diff --git a/public/scripts/dependencies/appwrite.js b/public/scripts/dependencies/appwrite.js index 2651ddb21a..458241f0dd 100644 --- a/public/scripts/dependencies/appwrite.js +++ b/public/scripts/dependencies/appwrite.js @@ -2227,7 +2227,7 @@ * * Create a new Document. Before using this route, you should create a new * collection resource using either a [server - * integration](/docs/server/database#databaseCreateCollection) API or + * integration](/docs/server/databases#databasesCreateCollection) API or * directly from your database console. * * @param {string} databaseId @@ -4745,7 +4745,7 @@ * * Create a new file. Before using this route, you should create a new bucket * resource using either a [server - * integration](/docs/server/database#storageCreateBucket) API or directly + * integration](/docs/server/storage#storageCreateBucket) API or directly * from your Appwrite console. * * Larger files should be uploaded using multiple requests with the diff --git a/src/Appwrite/Stats/Usage.php b/src/Appwrite/Stats/Usage.php index 48a461c354..31daeca3a0 100644 --- a/src/Appwrite/Stats/Usage.php +++ b/src/Appwrite/Stats/Usage.php @@ -311,9 +311,8 @@ class Usage } } - //$time = \strtotime($point['time']); - $time = $point['time']; //todo: check is this datetime format? - $value = (!empty($point['value'])) ? $point['value'] : 0; + $time = $point['time']; //todo: check is this datetime format? + $value = (!empty($point['value'])) ? $point['value'] : 0; $this->createOrUpdateMetric( $projectId, diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index 3ca3dbb3c4..6a7aee6ede 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -20,6 +20,7 @@ use Appwrite\Utopia\Response\Model\AttributeEmail; use Appwrite\Utopia\Response\Model\AttributeEnum; use Appwrite\Utopia\Response\Model\AttributeIP; use Appwrite\Utopia\Response\Model\AttributeURL; +use Appwrite\Utopia\Response\Model\AttributeDatetime; use Appwrite\Utopia\Response\Model\BaseList; use Appwrite\Utopia\Response\Model\Collection; use Appwrite\Utopia\Response\Model\Database; @@ -116,6 +117,7 @@ class Response extends SwooleResponse public const MODEL_ATTRIBUTE_ENUM = 'attributeEnum'; public const MODEL_ATTRIBUTE_IP = 'attributeIp'; public const MODEL_ATTRIBUTE_URL = 'attributeUrl'; + public const MODEL_ATTRIBUTE_DATETIME = 'attributeDatetime'; // Users public const MODEL_USER = 'user'; @@ -255,6 +257,7 @@ class Response extends SwooleResponse ->setModel(new AttributeEnum()) ->setModel(new AttributeIP()) ->setModel(new AttributeURL()) + ->setModel(new AttributeDatetime()) ->setModel(new Index()) ->setModel(new ModelDocument()) ->setModel(new Log()) diff --git a/src/Appwrite/Utopia/Response/Model/AttributeDatetime.php b/src/Appwrite/Utopia/Response/Model/AttributeDatetime.php new file mode 100644 index 0000000000..b0aac3c686 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/AttributeDatetime.php @@ -0,0 +1,69 @@ +addRule('key', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute Key.', + 'default' => '', + 'example' => 'birthDay', + ]) + ->addRule('type', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Attribute type.', + 'default' => '', + 'example' => '1975-12-06 13:30:59', + ]) + ->addRule('format', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Datetime format.', + 'default' => APP_DATABASE_ATTRIBUTE_DATETIME, + 'example' => APP_DATABASE_ATTRIBUTE_DATETIME, + 'array' => false, + 'require' => true, + ]) + ->addRule('default', [ + 'type' => self::TYPE_STRING, + 'description' => 'Default value for attribute when not provided. Only null is optional', + 'default' => null, + 'example' => '1975-12-06 13:30:59', + 'array' => false, + 'require' => false, + ]) + ; + } + + public array $conditions = [ + 'type' => self::TYPE_DATETIME, + 'format' => \APP_DATABASE_ATTRIBUTE_DATETIME + ]; + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'AttributeDatetime'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_ATTRIBUTE_DATETIME; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/AttributeList.php b/src/Appwrite/Utopia/Response/Model/AttributeList.php index eb398e455a..92ce9cd6cd 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeList.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeList.php @@ -26,6 +26,7 @@ class AttributeList extends Model Response::MODEL_ATTRIBUTE_ENUM, Response::MODEL_ATTRIBUTE_URL, Response::MODEL_ATTRIBUTE_IP, + Response::MODEL_ATTRIBUTE_DATETIME, Response::MODEL_ATTRIBUTE_STRING // needs to be last, since its condition would dominate any other string attribute ], 'description' => 'List of attributes.', diff --git a/src/Appwrite/Utopia/Response/Model/Bucket.php b/src/Appwrite/Utopia/Response/Model/Bucket.php index 96cf300f46..89f8c5778a 100644 --- a/src/Appwrite/Utopia/Response/Model/Bucket.php +++ b/src/Appwrite/Utopia/Response/Model/Bucket.php @@ -18,13 +18,13 @@ class Bucket extends Model ]) ->addRule('$createdAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' creation date in Datetime', + 'description' => 'Bucket creation date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) ->addRule('$updatedAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' update date in Datetime', + 'description' => 'Bucket update date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) diff --git a/src/Appwrite/Utopia/Response/Model/Collection.php b/src/Appwrite/Utopia/Response/Model/Collection.php index bca8d12c2d..3b3c734228 100644 --- a/src/Appwrite/Utopia/Response/Model/Collection.php +++ b/src/Appwrite/Utopia/Response/Model/Collection.php @@ -18,13 +18,13 @@ class Collection extends Model ]) ->addRule('$createdAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' creation date in Datetime', + 'description' => 'Collection creation date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) ->addRule('$updatedAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' update date in Datetime', + 'description' => 'Collection update date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) @@ -75,6 +75,7 @@ class Collection extends Model Response::MODEL_ATTRIBUTE_ENUM, Response::MODEL_ATTRIBUTE_URL, Response::MODEL_ATTRIBUTE_IP, + Response::MODEL_ATTRIBUTE_DATETIME, Response::MODEL_ATTRIBUTE_STRING, // needs to be last, since its condition would dominate any other string attribute ], 'description' => 'Collection attributes.', diff --git a/src/Appwrite/Utopia/Response/Model/Deployment.php b/src/Appwrite/Utopia/Response/Model/Deployment.php index eddc323182..c293e3508c 100644 --- a/src/Appwrite/Utopia/Response/Model/Deployment.php +++ b/src/Appwrite/Utopia/Response/Model/Deployment.php @@ -18,13 +18,13 @@ class Deployment extends Model ]) ->addRule('$createdAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' creation date in Datetime', + 'description' => 'Deployment creation date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) ->addRule('$updatedAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' update date in Datetime', + 'description' => 'Deployment update date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) diff --git a/src/Appwrite/Utopia/Response/Model/Document.php b/src/Appwrite/Utopia/Response/Model/Document.php index 811311bbf8..b25bfb6724 100644 --- a/src/Appwrite/Utopia/Response/Model/Document.php +++ b/src/Appwrite/Utopia/Response/Model/Document.php @@ -44,13 +44,13 @@ class Document extends Any ]) ->addRule('$createdAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' creation date in Datetime', + 'description' => 'Document creation date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) ->addRule('$updatedAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' update date in Datetime', + 'description' => 'Document update date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) diff --git a/src/Appwrite/Utopia/Response/Model/Domain.php b/src/Appwrite/Utopia/Response/Model/Domain.php index 621797c963..2cb98c14fa 100644 --- a/src/Appwrite/Utopia/Response/Model/Domain.php +++ b/src/Appwrite/Utopia/Response/Model/Domain.php @@ -23,13 +23,13 @@ class Domain extends Model ]) ->addRule('$createdAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' creation date in Datetime', + 'description' => 'Domain creation date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) ->addRule('$updatedAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' update date in Datetime', + 'description' => 'Domain update date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) diff --git a/src/Appwrite/Utopia/Response/Model/Execution.php b/src/Appwrite/Utopia/Response/Model/Execution.php index fe47d6afd6..98c2741465 100644 --- a/src/Appwrite/Utopia/Response/Model/Execution.php +++ b/src/Appwrite/Utopia/Response/Model/Execution.php @@ -18,13 +18,13 @@ class Execution extends Model ]) ->addRule('$createdAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' creation date in Datetime', + 'description' => 'Execution creation date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) ->addRule('$updatedAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' upate date in Datetime', + 'description' => 'Execution upate date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) diff --git a/src/Appwrite/Utopia/Response/Model/File.php b/src/Appwrite/Utopia/Response/Model/File.php index 7d8d810461..750a721f92 100644 --- a/src/Appwrite/Utopia/Response/Model/File.php +++ b/src/Appwrite/Utopia/Response/Model/File.php @@ -24,13 +24,13 @@ class File extends Model ]) ->addRule('$createdAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' creation date in Datetime', + 'description' => 'File creation date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) ->addRule('$updatedAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' update date in Datetime', + 'description' => 'File update date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) diff --git a/src/Appwrite/Utopia/Response/Model/Key.php b/src/Appwrite/Utopia/Response/Model/Key.php index daa35a4220..c52311c328 100644 --- a/src/Appwrite/Utopia/Response/Model/Key.php +++ b/src/Appwrite/Utopia/Response/Model/Key.php @@ -23,13 +23,13 @@ class Key extends Model ]) ->addRule('$createdAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' creation date in Datetime', + 'description' => 'Key creation date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) ->addRule('$updatedAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' update date in Datetime', + 'description' => 'Key update date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) @@ -41,7 +41,7 @@ class Key extends Model ]) ->addRule('expire', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' expiration date in Datetime', + 'description' => 'Key expiration date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) diff --git a/src/Appwrite/Utopia/Response/Model/Log.php b/src/Appwrite/Utopia/Response/Model/Log.php index 3891b41364..835cb3d9e3 100644 --- a/src/Appwrite/Utopia/Response/Model/Log.php +++ b/src/Appwrite/Utopia/Response/Model/Log.php @@ -48,7 +48,7 @@ class Log extends Model ]) ->addRule('time', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' creation date in Datetime.', + 'description' => 'Log creation date in Datetime.', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) diff --git a/src/Appwrite/Utopia/Response/Model/Membership.php b/src/Appwrite/Utopia/Response/Model/Membership.php index d068417d81..547b8db3d7 100644 --- a/src/Appwrite/Utopia/Response/Model/Membership.php +++ b/src/Appwrite/Utopia/Response/Model/Membership.php @@ -18,13 +18,13 @@ class Membership extends Model ]) ->addRule('$createdAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' creation date in Datetime', + 'description' => 'Membership creation date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) ->addRule('$updatedAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' update date in Datetime', + 'description' => 'Membership update date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) diff --git a/src/Appwrite/Utopia/Response/Model/Platform.php b/src/Appwrite/Utopia/Response/Model/Platform.php index 21fe580640..b99ac2011d 100644 --- a/src/Appwrite/Utopia/Response/Model/Platform.php +++ b/src/Appwrite/Utopia/Response/Model/Platform.php @@ -23,13 +23,13 @@ class Platform extends Model ]) ->addRule('$createdAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' creation date in Datetime', + 'description' => 'Platform creation date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) ->addRule('$updatedAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' update date in Datetime', + 'description' => 'Platform update date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) diff --git a/src/Appwrite/Utopia/Response/Model/Project.php b/src/Appwrite/Utopia/Response/Model/Project.php index 967f29dc57..301d15edc8 100644 --- a/src/Appwrite/Utopia/Response/Model/Project.php +++ b/src/Appwrite/Utopia/Response/Model/Project.php @@ -25,13 +25,13 @@ class Project extends Model ]) ->addRule('$createdAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' creation date in Datetime', + 'description' => 'Project creation date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) ->addRule('$updatedAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' update date in Datetime', + 'description' => 'Project update date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) diff --git a/src/Appwrite/Utopia/Response/Model/Session.php b/src/Appwrite/Utopia/Response/Model/Session.php index 62058f6db5..86c98f768c 100644 --- a/src/Appwrite/Utopia/Response/Model/Session.php +++ b/src/Appwrite/Utopia/Response/Model/Session.php @@ -18,7 +18,7 @@ class Session extends Model ]) ->addRule('$createdAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' creation date in Datetime', + 'description' => 'Session creation date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) @@ -30,7 +30,7 @@ class Session extends Model ]) ->addRule('expire', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' expiration date in Datetime', + 'description' => 'Session expiration date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) diff --git a/src/Appwrite/Utopia/Response/Model/Team.php b/src/Appwrite/Utopia/Response/Model/Team.php index af50515357..8763bbe814 100644 --- a/src/Appwrite/Utopia/Response/Model/Team.php +++ b/src/Appwrite/Utopia/Response/Model/Team.php @@ -18,13 +18,13 @@ class Team extends Model ]) ->addRule('$createdAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' creation date in Datetime', + 'description' => 'Team creation date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) ->addRule('$updatedAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' update date in Datetime', + 'description' => 'Team update date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) diff --git a/src/Appwrite/Utopia/Response/Model/Token.php b/src/Appwrite/Utopia/Response/Model/Token.php index b4fa5041c2..1b6ae092a6 100644 --- a/src/Appwrite/Utopia/Response/Model/Token.php +++ b/src/Appwrite/Utopia/Response/Model/Token.php @@ -18,7 +18,7 @@ class Token extends Model ]) ->addRule('$createdAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' creation date in Datetime', + 'description' => 'Token creation date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) diff --git a/src/Appwrite/Utopia/Response/Model/User.php b/src/Appwrite/Utopia/Response/Model/User.php index a39226a76e..d47fa414de 100644 --- a/src/Appwrite/Utopia/Response/Model/User.php +++ b/src/Appwrite/Utopia/Response/Model/User.php @@ -19,13 +19,13 @@ class User extends Model ]) ->addRule('$createdAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' creation date in Datetime.', + 'description' => 'User creation date in Datetime.', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) ->addRule('$updatedAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' update date in Datetime.', + 'description' => 'User update date in Datetime.', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) diff --git a/src/Appwrite/Utopia/Response/Model/Webhook.php b/src/Appwrite/Utopia/Response/Model/Webhook.php index 6f79dd9101..5aec6bdbe1 100644 --- a/src/Appwrite/Utopia/Response/Model/Webhook.php +++ b/src/Appwrite/Utopia/Response/Model/Webhook.php @@ -23,13 +23,13 @@ class Webhook extends Model ]) ->addRule('$createdAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' creation date in Datetime', + 'description' => 'Webhook creation date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) ->addRule('$updatedAt', [ 'type' => self::TYPE_DATETIME, - 'description' => get_class() . ' update date in Datetime', + 'description' => 'Webhook update date in Datetime', 'default' => '', 'example' => '1975-12-06 13:30:59', ]) diff --git a/tests/e2e/Services/Databases/DatabasesBase.php b/tests/e2e/Services/Databases/DatabasesBase.php index 507038fdb4..398071c22e 100644 --- a/tests/e2e/Services/Databases/DatabasesBase.php +++ b/tests/e2e/Services/Databases/DatabasesBase.php @@ -166,6 +166,14 @@ trait DatabasesBase 'array' => true, ]); + $datetime = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/attributes/datetime', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'key' => 'birthDay', + 'required' => false, + ]); $this->assertEquals($title['headers']['status-code'], 202); $this->assertEquals($title['body']['key'], 'title'); $this->assertEquals($title['body']['type'], 'string'); @@ -189,6 +197,11 @@ trait DatabasesBase $this->assertEquals($actors['body']['required'], false); $this->assertEquals($actors['body']['array'], true); + $this->assertEquals($datetime['headers']['status-code'], 201); + $this->assertEquals($datetime['body']['key'], 'birthDay'); + $this->assertEquals($datetime['body']['type'], 'datetime'); + $this->assertEquals($datetime['body']['required'], false); + // wait for database worker to create attributes sleep(2); @@ -199,11 +212,12 @@ trait DatabasesBase ]), []); $this->assertIsArray($movies['body']['attributes']); - $this->assertCount(4, $movies['body']['attributes']); + $this->assertCount(5, $movies['body']['attributes']); $this->assertEquals($movies['body']['attributes'][0]['key'], $title['body']['key']); $this->assertEquals($movies['body']['attributes'][1]['key'], $releaseYear['body']['key']); $this->assertEquals($movies['body']['attributes'][2]['key'], $duration['body']['key']); $this->assertEquals($movies['body']['attributes'][3]['key'], $actors['body']['key']); + $this->assertEquals($movies['body']['attributes'][4]['key'], $datetime['body']['key']); return $data; } @@ -319,6 +333,16 @@ trait DatabasesBase 'default' => true, ]); + $datetime = $this->client->call(Client::METHOD_POST, $attributesPath . '/datetime', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'key' => 'datetime', + 'required' => false, + 'default' => null, + ]); + $this->assertEquals(202, $string['headers']['status-code']); $this->assertEquals('string', $string['body']['key']); $this->assertEquals('string', $string['body']['type']); @@ -386,6 +410,13 @@ trait DatabasesBase $this->assertEquals(false, $boolean['body']['array']); $this->assertEquals(true, $boolean['body']['default']); + $this->assertEquals(201, $datetime['headers']['status-code']); + $this->assertEquals('datetime', $datetime['body']['key']); + $this->assertEquals('datetime', $datetime['body']['type']); + $this->assertEquals(false, $datetime['body']['required']); + $this->assertEquals(false, $datetime['body']['array']); + $this->assertEquals(null, $datetime['body']['default']); + // wait for database worker to create attributes sleep(30); @@ -437,6 +468,12 @@ trait DatabasesBase 'x-appwrite-key' => $this->getProject()['apiKey'] ])); + $datetimeResponse = $this->client->call(Client::METHOD_GET, $attributesPath . '/' . $datetime['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']); @@ -511,6 +548,14 @@ trait DatabasesBase $this->assertEquals($boolean['body']['array'], $booleanResponse['body']['array']); $this->assertEquals($boolean['body']['default'], $booleanResponse['body']['default']); + $this->assertEquals(200, $datetimeResponse['headers']['status-code']); + $this->assertEquals($datetime['body']['key'], $datetimeResponse['body']['key']); + $this->assertEquals($datetime['body']['type'], $datetimeResponse['body']['type']); + $this->assertEquals('available', $datetimeResponse['body']['status']); + $this->assertEquals($datetime['body']['required'], $datetimeResponse['body']['required']); + $this->assertEquals($datetime['body']['array'], $datetimeResponse['body']['array']); + $this->assertEquals($datetime['body']['default'], $datetimeResponse['body']['default']); + $attributes = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -518,12 +563,12 @@ trait DatabasesBase ])); $this->assertEquals(200, $attributes['headers']['status-code']); - $this->assertEquals(8, $attributes['body']['total']); + $this->assertEquals(9, $attributes['body']['total']); $attributes = $attributes['body']['attributes']; $this->assertIsArray($attributes); - $this->assertCount(8, $attributes); + $this->assertCount(9, $attributes); $this->assertEquals($stringResponse['body']['key'], $attributes[0]['key']); $this->assertEquals($stringResponse['body']['type'], $attributes[0]['type']); @@ -591,6 +636,13 @@ trait DatabasesBase $this->assertEquals($booleanResponse['body']['array'], $attributes[7]['array']); $this->assertEquals($booleanResponse['body']['default'], $attributes[7]['default']); + $this->assertEquals($datetimeResponse['body']['key'], $attributes[8]['key']); + $this->assertEquals($datetimeResponse['body']['type'], $attributes[8]['type']); + $this->assertEquals($datetimeResponse['body']['status'], $attributes[8]['status']); + $this->assertEquals($datetimeResponse['body']['required'], $attributes[8]['required']); + $this->assertEquals($datetimeResponse['body']['array'], $attributes[8]['array']); + $this->assertEquals($datetimeResponse['body']['default'], $attributes[8]['default']); + $collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -602,7 +654,7 @@ trait DatabasesBase $attributes = $collection['body']['attributes']; $this->assertIsArray($attributes); - $this->assertCount(8, $attributes); + $this->assertCount(9, $attributes); $this->assertEquals($stringResponse['body']['key'], $attributes[0]['key']); $this->assertEquals($stringResponse['body']['type'], $attributes[0]['type']); @@ -670,6 +722,13 @@ trait DatabasesBase $this->assertEquals($booleanResponse['body']['array'], $attributes[7]['array']); $this->assertEquals($booleanResponse['body']['default'], $attributes[7]['default']); + $this->assertEquals($datetimeResponse['body']['key'], $attributes[8]['key']); + $this->assertEquals($datetimeResponse['body']['type'], $attributes[8]['type']); + $this->assertEquals($datetimeResponse['body']['status'], $attributes[8]['status']); + $this->assertEquals($datetimeResponse['body']['required'], $attributes[8]['required']); + $this->assertEquals($datetimeResponse['body']['array'], $attributes[8]['array']); + $this->assertEquals($datetimeResponse['body']['default'], $attributes[8]['default']); + /** * Test for FAILURE */ @@ -764,6 +823,23 @@ trait DatabasesBase $this->assertEquals('available', $movies['body']['indexes'][1]['status']); $this->assertEquals('available', $movies['body']['indexes'][2]['status']); + + $releaseWithDate = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'key' => 'birthDay', + 'type' => 'key', + 'attributes' => ['birthDay'], + ]); + + $this->assertEquals(201, $releaseWithDate['headers']['status-code']); + $this->assertEquals('birthDay', $releaseWithDate['body']['key']); + $this->assertEquals('key', $releaseWithDate['body']['type']); + $this->assertCount(1, $releaseWithDate['body']['attributes']); + $this->assertEquals('birthDay', $releaseWithDate['body']['attributes'][0]); + return $data; } @@ -781,6 +857,7 @@ trait DatabasesBase 'data' => [ 'title' => 'Captain America', 'releaseYear' => 1944, + 'birthDay' => '1975-06-12 14:12:55+02:00', 'actors' => [ 'Chris Evans', 'Samuel Jackson', @@ -798,6 +875,7 @@ trait DatabasesBase 'data' => [ 'title' => 'Spider-Man: Far From Home', 'releaseYear' => 2019, + 'birthDay' => null, 'actors' => [ 'Tom Holland', 'Zendaya Maree Stoermer', @@ -816,6 +894,7 @@ trait DatabasesBase 'data' => [ 'title' => 'Spider-Man: Homecoming', 'releaseYear' => 2017, + 'birthDay' => '1975-06-12 14:12:55 America/New_York', 'duration' => 0, 'actors' => [ 'Tom Holland', @@ -848,6 +927,7 @@ trait DatabasesBase $this->assertCount(2, $document1['body']['actors']); $this->assertEquals($document1['body']['actors'][0], 'Chris Evans'); $this->assertEquals($document1['body']['actors'][1], 'Samuel Jackson'); + $this->assertEquals($document1['body']['birthDay'], '1975-06-12 12:12:55.000'); $this->assertEquals($document2['headers']['status-code'], 201); $this->assertEquals($document2['body']['title'], 'Spider-Man: Far From Home'); @@ -861,6 +941,7 @@ trait DatabasesBase $this->assertEquals($document2['body']['actors'][0], 'Tom Holland'); $this->assertEquals($document2['body']['actors'][1], 'Zendaya Maree Stoermer'); $this->assertEquals($document2['body']['actors'][2], 'Samuel Jackson'); + $this->assertEquals($document2['body']['birthDay'], null); $this->assertEquals($document3['headers']['status-code'], 201); $this->assertEquals($document3['body']['title'], 'Spider-Man: Homecoming'); @@ -873,6 +954,7 @@ trait DatabasesBase $this->assertCount(2, $document3['body']['actors']); $this->assertEquals($document3['body']['actors'][0], 'Tom Holland'); $this->assertEquals($document3['body']['actors'][1], 'Zendaya Maree Stoermer'); + $this->assertEquals($document3['body']['birthDay'], '1975-06-12 18:12:55.000');// UTC for NY $this->assertEquals($document4['headers']['status-code'], 400); @@ -999,6 +1081,7 @@ trait DatabasesBase $this->assertEquals($response['body']['releaseYear'], $document['releaseYear']); $this->assertEquals($response['body']['$read'], $document['$read']); $this->assertEquals($response['body']['$write'], $document['$write']); + $this->assertEquals($response['body']['birthDay'], $document['birthDay']); $this->assertFalse(array_key_exists('$internalId', $response['body'])); } } @@ -1342,7 +1425,7 @@ trait DatabasesBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['$createdAt.greater(132)'], + 'queries' => ['$createdAt.greater("1976-06-12")'], ]); $this->assertCount(3, $documents['body']['documents']); @@ -1351,7 +1434,7 @@ trait DatabasesBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'queries' => ['$createdAt.lesser(132)'], + 'queries' => ['$createdAt.lesser("1976-06-12")'], ]); $this->assertCount(0, $documents['body']['documents']); @@ -1398,6 +1481,19 @@ trait DatabasesBase $this->assertEquals(400, $documents['headers']['status-code']); + + $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['birthDay.greater("1960-01-01 10:10:10+02:30")'], + ]); + + $this->assertEquals($documents['headers']['status-code'], 200); + $this->assertEquals('1975-06-12 12:12:55.000', $documents['body']['documents'][0]['birthDay']); + $this->assertEquals('1975-06-12 18:12:55.000', $documents['body']['documents'][1]['birthDay']); + $this->assertCount(2, $documents['body']['documents']); + return []; } @@ -1415,6 +1511,7 @@ trait DatabasesBase 'data' => [ 'title' => 'Thor: Ragnaroc', 'releaseYear' => 2017, + 'birthDay' => '1976-06-12 14:12:55', 'actors' => [], '$createdAt' => 5 // Should be ignored ], @@ -1428,6 +1525,7 @@ trait DatabasesBase $this->assertEquals($document['body']['title'], 'Thor: Ragnaroc'); $this->assertEquals($document['body']['releaseYear'], 2017); $this->assertEquals(true, DateTime::isValid($document['body']['$createdAt'])); + $this->assertEquals(true, DateTime::isValid($document['body']['birthDay'])); $this->assertEquals('user:' . $this->getUser()['$id'], $document['body']['$read'][0]); $this->assertEquals('user:' . $this->getUser()['$id'], $document['body']['$write'][0]); @@ -1478,6 +1576,7 @@ trait DatabasesBase 'data' => [ 'title' => 'Thor: Ragnarok', 'releaseYear' => 2017, + 'birthDay' => '1975-06-12 14:12:55', 'actors' => [], ], 'read' => ['user:' . $this->getUser()['$id']], @@ -1690,6 +1789,26 @@ trait DatabasesBase 'default' => 'NORTH' ]); + $goodDatetime = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/datetime', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'key' => 'birthDay', + 'required' => false, + 'default' => null + ]); + + $datetimeDefault = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/datetime', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'key' => 'badBirthDay', + 'required' => false, + 'default' => 'bad' + ]); + $this->assertEquals(202, $email['headers']['status-code']); $this->assertEquals(202, $ip['headers']['status-code']); $this->assertEquals(202, $url['headers']['status-code']); @@ -1699,6 +1818,7 @@ trait DatabasesBase $this->assertEquals(202, $upperBound['headers']['status-code']); $this->assertEquals(202, $lowerBound['headers']['status-code']); $this->assertEquals(202, $enum['headers']['status-code']); + $this->assertEquals(202, $goodDatetime['headers']['status-code']); $this->assertEquals(400, $invalidRange['headers']['status-code']); $this->assertEquals(400, $defaultArray['headers']['status-code']); $this->assertEquals(400, $defaultRequired['headers']['status-code']); @@ -1706,7 +1826,7 @@ trait DatabasesBase $this->assertEquals(400, $enumDefaultStrict['headers']['status-code']); $this->assertEquals('Minimum value must be lesser than maximum value', $invalidRange['body']['message']); $this->assertEquals('Cannot set default value for array attributes', $defaultArray['body']['message']); - + $this->assertEquals(400, $datetimeDefault['headers']['status-code']); // wait for worker to add attributes sleep(3); @@ -1716,7 +1836,7 @@ trait DatabasesBase 'x-appwrite-key' => $this->getProject()['apiKey'], ]), []); - $this->assertCount(9, $collection['body']['attributes']); + $this->assertCount(10, $collection['body']['attributes']); /** * Test for successful validation @@ -1952,6 +2072,18 @@ trait DatabasesBase 'write' => ['user:' . $this->getUser()['$id']], ]); + $badTime = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'documentId' => 'unique()', + 'data' => [ + 'birthDay' => '2020-10-10 27:30:10+01:00', + ], + 'read' => ['user:' . $this->getUser()['$id']], + 'write' => ['user:' . $this->getUser()['$id']], + ]); + $this->assertEquals(400, $badEmail['headers']['status-code']); $this->assertEquals(400, $badEnum['headers']['status-code']); $this->assertEquals(400, $badIp['headers']['status-code']); @@ -1961,6 +2093,7 @@ trait DatabasesBase $this->assertEquals(400, $badProbability['headers']['status-code']); $this->assertEquals(400, $tooHigh['headers']['status-code']); $this->assertEquals(400, $tooLow['headers']['status-code']); + $this->assertEquals(400, $badTime['headers']['status-code']); $this->assertEquals('Invalid document structure: Attribute "email" has invalid format. Value must be a valid email address', $badEmail['body']['message']); $this->assertEquals('Invalid document structure: Attribute "enum" has invalid format. Value must be one of (yes, no, maybe)', $badEnum['body']['message']); $this->assertEquals('Invalid document structure: Attribute "ip" has invalid format. Value must be a valid IP address', $badIp['body']['message']); @@ -2407,16 +2540,17 @@ trait DatabasesBase $document = $this->client->call(Client::METHOD_PATCH, '/databases/' . $data['databaseId'] . '/collections/' . $data['moviesId'] . '/documents/' . $documentId, $headers, [ 'data' => [ 'title' => 'Again Updated Date Test', - '$createdAt' => 1657271810, // Try to update it, should not work - '$updatedAt' => 1657271810 // Try to update it, should not work + '$createdAt' => '2022-08-01 13:09:23.040', // $createdAt is not updatable + '$updatedAt' => '2022-08-01 13:09:23.050' // system will update it not api ] ]); $this->assertEquals($document['body']['title'], 'Again Updated Date Test'); $this->assertEquals($document['body']['$createdAt'], $createdAt); + $this->assertNotEquals($document['body']['$createdAt'], '2022-08-01 13:09:23.040'); $this->assertNotEquals($document['body']['$updatedAt'], $updatedAt); $this->assertNotEquals($document['body']['$updatedAt'], $updatedAtSecond); - $this->assertNotEquals($document['body']['$updatedAt'], 1657271810); + $this->assertNotEquals($document['body']['$updatedAt'], '2022-08-01 13:09:23.050'); return $data; }