1
0
Fork 0
mirror of synced 2024-07-04 06:00:53 +12:00

Merge branch 'feat-database-update-attribute' of github.com:appwrite/appwrite into feat-relations-2

 Conflicts:
	app/controllers/api/databases.php
	composer.json
	composer.lock
This commit is contained in:
fogelito 2023-03-16 12:14:37 +02:00
commit 79bfa025cb
35 changed files with 2934 additions and 272 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -48,6 +48,7 @@ use Appwrite\Utopia\Database\Validator\Queries\Databases;
use Appwrite\Utopia\Database\Validator\Queries\Documents;
use Utopia\Config\Config;
use MaxMind\Db\Reader;
use Utopia\Validator\Nullable;
/**
* Create attribute of varying type
@ -156,6 +157,163 @@ function createAttribute(string $databaseId, string $collectionId, Document $att
return $attribute;
}
function updateAttribute(
string $databaseId,
string $collectionId,
string $key,
Database $dbForProject,
Event $events,
string $type,
string $filter = null,
string|bool|int|float $default = null,
bool $required = null,
int|float $min = null,
int|float $max = null,
array $elements = null
): Document {
$db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
if ($db->isEmpty()) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
}
$collection = $dbForProject->getDocument('database_' . $db->getInternalId(), $collectionId);
if ($collection->isEmpty()) {
throw new Exception(Exception::COLLECTION_NOT_FOUND);
}
$attribute = $dbForProject->getDocument('attributes', ID::custom($db->getInternalId() . '_' . $collection->getInternalId() . '_' . $key));
if ($attribute->isEmpty()) {
throw new Exception(Exception::ATTRIBUTE_NOT_FOUND);
}
if ($attribute->getAttribute('status') !== 'available') {
throw new Exception(Exception::ATTRIBUTE_NOT_AVAILABLE);
}
if ($attribute->getAttribute(('type') !== $type)) {
throw new Exception(Exception::ATTRIBUTE_TYPE_INVALID);
}
if ($attribute->getAttribute('type') === Database::VAR_STRING && $attribute->getAttribute(('filter') !== $filter)) {
throw new Exception(Exception::ATTRIBUTE_TYPE_INVALID);
}
if ($required && isset($default)) {
throw new Exception(Exception::ATTRIBUTE_DEFAULT_UNSUPPORTED, 'Cannot set default value for required attribute');
}
if ($attribute->getAttribute('array', false) && isset($default)) {
throw new Exception(Exception::ATTRIBUTE_DEFAULT_UNSUPPORTED, 'Cannot set default value for array attributes');
}
$collectionId = 'database_' . $db->getInternalId() . '_collection_' . $collection->getInternalId();
$attribute
->setAttribute('default', $default)
->setAttribute('required', $required);
$formatOptions = $attribute->getAttribute('formatOptions');
switch ($attribute->getAttribute('format')) {
case APP_DATABASE_ATTRIBUTE_INT_RANGE:
if ($min === $formatOptions['min'] && $max === $formatOptions['max']) {
break;
}
if ($min > $max) {
throw new Exception(Exception::ATTRIBUTE_VALUE_INVALID, 'Minimum value must be lesser than maximum value');
}
$validator = new Range($min, $max, Database::VAR_INTEGER);
if (!is_null($default) && !$validator->isValid($default)) {
throw new Exception(Exception::ATTRIBUTE_VALUE_INVALID, $validator->getDescription());
}
$options = [
'min' => $min,
'max' => $max
];
$attribute->setAttribute('formatOptions', $options);
break;
case APP_DATABASE_ATTRIBUTE_FLOAT_RANGE:
if ($min === $formatOptions['min'] && $max === $formatOptions['max']) {
break;
}
if ($min > $max) {
throw new Exception(Exception::ATTRIBUTE_VALUE_INVALID, 'Minimum value must be lesser than maximum value');
}
if (!is_null($default)) {
$default = \floatval($default);
}
$validator = new Range($min, $max, Database::VAR_FLOAT);
if (!is_null($default) && !$validator->isValid($default)) {
throw new Exception(Exception::ATTRIBUTE_VALUE_INVALID, $validator->getDescription());
}
$options = [
'min' => $min,
'max' => $max
];
$attribute->setAttribute('formatOptions', $options);
break;
case APP_DATABASE_ATTRIBUTE_ENUM:
if (empty($elements)) {
throw new Exception(Exception::ATTRIBUTE_VALUE_INVALID, 'Enum elements must not be empty');
}
//TODO: before merging - this iteration is kinda hard to follow because of the $size variable?
$size = 0;
foreach ($elements as $element) {
$length = \strlen($element);
if ($length === 0) {
throw new Exception(Exception::ATTRIBUTE_VALUE_INVALID, 'Each enum element must not be empty');
}
$size = ($length > $size) ? $length : $size;
}
if (!is_null($default) && !in_array($default, $elements)) {
throw new Exception(Exception::ATTRIBUTE_VALUE_INVALID, 'Default value not found in elements');
}
$options = [
'elements' => $elements
];
$attribute->setAttribute('formatOptions', $options);
break;
}
$dbForProject->updateAttribute(
collection: $collectionId,
id: $key,
required: $required,
default: $default,
formatOptions: $options ?? null
);
$dbForProject->updateDocument('attributes', $db->getInternalId() . '_' . $collection->getInternalId() . '_' . $key, $attribute);
$dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $collectionId);
$events
->setContext('collection', $collection)
->setContext('database', $db)
->setParam('databaseId', $databaseId)
->setParam('collectionId', $collection->getId())
->setParam('attributeId', $attribute->getId());
return $attribute;
}
App::post('/v1/databases')
->desc('Create Database')
->groups(['api', 'database'])
@ -973,7 +1131,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/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/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('elements', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE, min: 0), 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?')
->param('default', null, new Text(0), '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)
@ -1534,6 +1692,394 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes/:key')
$response->dynamic($attribute, $model);
});
App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/:key/string')
->desc('Update String Attribute')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update')
->label('audits.event', 'attribute.update')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
->label('usage.metric', 'collections.{scope}.requests.update')
->label('usage.params', ['databaseId:{request.databaseId}'])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'databases')
->label('sdk.method', 'updateStringAttribute')
->label('sdk.description', '/docs/references/databases/update-string-attribute.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->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/databases#databasesCreateCollection).')
->param('key', '', new Key(), 'Attribute Key.')
->param('required', null, new Boolean(), 'Is attribute required?')
->param('default', null, new Nullable(new Text(0)), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $events) {
$attribute = updateAttribute(
databaseId: $databaseId,
collectionId: $collectionId,
key: $key,
dbForProject: $dbForProject,
events: $events,
type: Database::VAR_STRING,
default: $default,
required: $required
);
$response
->setStatusCode(Response::STATUS_CODE_OK)
->dynamic($attribute, Response::MODEL_ATTRIBUTE_STRING);
});
App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/:key/email')
->desc('Update Email Attribute')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update')
->label('audits.event', 'attribute.update')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
->label('usage.metric', 'collections.{scope}.requests.update')
->label('usage.params', ['databaseId:{request.databaseId}'])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'databases')
->label('sdk.method', 'updateEmailAttribute')
->label('sdk.description', '/docs/references/databases/update-email-attribute.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->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/databases#databasesCreateCollection).')
->param('key', '', new Key(), 'Attribute Key.')
->param('required', null, new Boolean(), 'Is attribute required?')
->param('default', null, new Nullable(new Email()), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $events) {
$attribute = updateAttribute(
databaseId: $databaseId,
collectionId: $collectionId,
key: $key,
dbForProject: $dbForProject,
events: $events,
type: Database::VAR_STRING,
filter: APP_DATABASE_ATTRIBUTE_EMAIL,
default: $default,
required: $required
);
$response
->setStatusCode(Response::STATUS_CODE_OK)
->dynamic($attribute, Response::MODEL_ATTRIBUTE_EMAIL);
});
App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/:key/enum')
->desc('Update Enum Attribute')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update')
->label('audits.event', 'attribute.update')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
->label('usage.metric', 'collections.{scope}.requests.update')
->label('usage.params', ['databaseId:{request.databaseId}'])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'databases')
->label('sdk.method', 'updateEnumAttribute')
->label('sdk.description', '/docs/references/databases/update-enum-attribute.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->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/databases#databasesCreateCollection).')
->param('key', '', new Key(), 'Attribute Key.')
->param('elements', null, 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?')
->param('default', null, new Nullable(new Text(0)), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, ?array $elements, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $events) {
$attribute = updateAttribute(
databaseId: $databaseId,
collectionId: $collectionId,
key: $key,
dbForProject: $dbForProject,
events: $events,
type: Database::VAR_STRING,
filter: APP_DATABASE_ATTRIBUTE_ENUM,
default: $default,
required: $required,
elements: $elements
);
$response
->setStatusCode(Response::STATUS_CODE_OK)
->dynamic($attribute, Response::MODEL_ATTRIBUTE_ENUM);
});
App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/:key/ip')
->desc('Update IP Address Attribute')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update')
->label('audits.event', 'attribute.update')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
->label('usage.metric', 'collections.{scope}.requests.update')
->label('usage.params', ['databaseId:{request.databaseId}'])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'databases')
->label('sdk.method', 'updateIpAttribute')
->label('sdk.description', '/docs/references/databases/update-ip-attribute.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->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/databases#databasesCreateCollection).')
->param('key', '', new Key(), 'Attribute Key.')
->param('required', null, new Boolean(), 'Is attribute required?')
->param('default', null, new Nullable(new IP()), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $events) {
$attribute = updateAttribute(
databaseId: $databaseId,
collectionId: $collectionId,
key: $key,
dbForProject: $dbForProject,
events: $events,
type: Database::VAR_STRING,
filter: APP_DATABASE_ATTRIBUTE_IP,
default: $default,
required: $required
);
$response
->setStatusCode(Response::STATUS_CODE_OK)
->dynamic($attribute, Response::MODEL_ATTRIBUTE_IP);
});
App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/:key/url')
->desc('Update URL Attribute')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update')
->label('audits.event', 'attribute.update')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
->label('usage.metric', 'collections.{scope}.requests.update')
->label('usage.params', ['databaseId:{request.databaseId}'])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'databases')
->label('sdk.method', 'updateUrlAttribute')
->label('sdk.description', '/docs/references/databases/update-url-attribute.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->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/databases#databasesCreateCollection).')
->param('key', '', new Key(), 'Attribute Key.')
->param('required', null, new Boolean(), 'Is attribute required?')
->param('default', null, new Nullable(new URL()), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $events) {
$attribute = updateAttribute(
databaseId: $databaseId,
collectionId: $collectionId,
key: $key,
dbForProject: $dbForProject,
events: $events,
type: Database::VAR_STRING,
filter: APP_DATABASE_ATTRIBUTE_URL,
default: $default,
required: $required
);
$response
->setStatusCode(Response::STATUS_CODE_OK)
->dynamic($attribute, Response::MODEL_ATTRIBUTE_URL);
});
App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/:key/integer')
->desc('Update Integer Attribute')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update')
->label('audits.event', 'attribute.update')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
->label('usage.metric', 'collections.{scope}.requests.update')
->label('usage.params', ['databaseId:{request.databaseId}'])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'databases')
->label('sdk.method', 'updateIntegerAttribute')
->label('sdk.description', '/docs/references/databases/update-integer-attribute.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->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/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')
->param('max', null, new Integer(), 'Maximum value to enforce on new documents')
->param('default', null, new Nullable(new Integer()), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?int $min, ?int $max, ?int $default, Response $response, Database $dbForProject, Event $events) {
$attribute = updateAttribute(
databaseId: $databaseId,
collectionId: $collectionId,
key: $key,
dbForProject: $dbForProject,
events: $events,
type: Database::VAR_INTEGER,
default: $default,
required: $required,
min: $min,
max: $max
);
$formatOptions = $attribute->getAttribute('formatOptions', []);
if (!empty($formatOptions)) {
$attribute->setAttribute('min', \intval($formatOptions['min']));
$attribute->setAttribute('max', \intval($formatOptions['max']));
}
$response
->setStatusCode(Response::STATUS_CODE_OK)
->dynamic($attribute, Response::MODEL_ATTRIBUTE_INTEGER);
});
App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/:key/float')
->desc('Update Float Attribute')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update')
->label('audits.event', 'attribute.update')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
->label('usage.metric', 'collections.{scope}.requests.update')
->label('usage.params', ['databaseId:{request.databaseId}'])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'databases')
->label('sdk.method', 'updateFloatAttribute')
->label('sdk.description', '/docs/references/databases/update-float-attribute.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->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/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')
->param('max', null, new FloatValidator(), 'Maximum value to enforce on new documents')
->param('default', null, new Nullable(new FloatValidator()), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?float $min, ?float $max, ?float $default, Response $response, Database $dbForProject, Event $events) {
$attribute = updateAttribute(
databaseId: $databaseId,
collectionId: $collectionId,
key: $key,
dbForProject: $dbForProject,
events: $events,
type: Database::VAR_FLOAT,
default: $default,
required: $required,
min: $min,
max: $max
);
$formatOptions = $attribute->getAttribute('formatOptions', []);
if (!empty($formatOptions)) {
$attribute->setAttribute('min', \floatval($formatOptions['min']));
$attribute->setAttribute('max', \floatval($formatOptions['max']));
}
$response
->setStatusCode(Response::STATUS_CODE_OK)
->dynamic($attribute, Response::MODEL_ATTRIBUTE_FLOAT);
});
App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/:key/boolean')
->desc('Update Boolean Attribute')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update')
->label('audits.event', 'attribute.update')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
->label('usage.metric', 'collections.{scope}.requests.update')
->label('usage.params', ['databaseId:{request.databaseId}'])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'databases')
->label('sdk.method', 'updateBooleanAttribute')
->label('sdk.description', '/docs/references/databases/update-boolean-attribute.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->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/databases#databasesCreateCollection).')
->param('key', '', new Key(), 'Attribute Key.')
->param('required', null, new Boolean(), 'Is attribute required?')
->param('default', null, new Nullable(new Boolean()), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?bool $default, Response $response, Database $dbForProject, Event $events) {
$attribute = updateAttribute(
databaseId: $databaseId,
collectionId: $collectionId,
key: $key,
dbForProject: $dbForProject,
events: $events,
type: Database::VAR_BOOLEAN,
default: $default,
required: $required
);
$response
->setStatusCode(Response::STATUS_CODE_OK)
->dynamic($attribute, Response::MODEL_ATTRIBUTE_BOOLEAN);
});
App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/:key/datetime')
->desc('Update DateTime Attribute')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
->label('event', 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update')
->label('audits.event', 'attribute.update')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
->label('usage.metric', 'collections.{scope}.requests.update')
->label('usage.params', ['databaseId:{request.databaseId}'])
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
->label('sdk.namespace', 'databases')
->label('sdk.method', 'updateDatetimeAttribute')
->label('sdk.description', '/docs/references/databases/update-datetime-attribute.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->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/databases#databasesCreateCollection).')
->param('key', '', new Key(), 'Attribute Key.')
->param('required', null, new Boolean(), 'Is attribute required?')
->param('default', null, new Nullable(new DatetimeValidator()), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $events) {
$attribute = updateAttribute(
databaseId: $databaseId,
collectionId: $collectionId,
key: $key,
dbForProject: $dbForProject,
events: $events,
type: Database::VAR_DATETIME,
default: $default,
required: $required
);
$response
->setStatusCode(Response::STATUS_CODE_OK)
->dynamic($attribute, Response::MODEL_ATTRIBUTE_DATETIME);
});
App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key')
->alias('/v1/database/collections/:collectionId/attributes/:key', ['databaseId' => 'default'])
->desc('Delete Attribute')
@ -1577,7 +2123,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key
}
// Only update status if removing available attribute
if ($attribute->getAttribute('status' === 'available')) {
if ($attribute->getAttribute('status') === 'available') {
$attribute = $dbForProject->updateDocument('attributes', $attribute->getId(), $attribute->setAttribute('status', 'deleting'));
}

View file

@ -25,7 +25,6 @@ use Appwrite\Task\Validator\Cron;
use Appwrite\Utopia\Database\Validator\Queries\Deployments;
use Appwrite\Utopia\Database\Validator\Queries\Executions;
use Appwrite\Utopia\Database\Validator\Queries\Functions;
use Appwrite\Utopia\Database\Validator\Queries\Variables;
use Utopia\App;
use Utopia\Database\Database;
use Utopia\Database\Document;
@ -33,7 +32,6 @@ use Utopia\Database\DateTime;
use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Assoc;
use Utopia\Validator\Text;
use Utopia\Validator\Range;
use Utopia\Validator\WhiteList;
@ -63,7 +61,7 @@ App::post('/v1/functions')
->label('sdk.response.model', Response::MODEL_FUNCTION)
->param('functionId', '', new CustomId(), 'Function ID. Choose a custom ID or generate a random ID with `ID.unique()`. 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('name', '', new Text(128), 'Function name. Max length: 128 chars.')
->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.')
->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.', true)
->param('runtime', '', new WhiteList(array_keys(Config::getParam('runtimes')), true), 'Execution runtime.')
->param('events', [], new ArrayList(new ValidatorEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.', true)
->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true)
@ -440,7 +438,7 @@ App::put('/v1/functions/:functionId')
->label('sdk.response.model', Response::MODEL_FUNCTION)
->param('functionId', '', new UID(), 'Function ID.')
->param('name', '', new Text(128), 'Function name. Max length: 128 chars.')
->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.')
->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.', true)
->param('events', [], new ArrayList(new ValidatorEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.', true)
->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true)
->param('timeout', 15, new Range(1, (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)), 'Maximum execution time in seconds.', true)
@ -601,8 +599,8 @@ App::post('/v1/functions/:functionId/deployments')
->label('sdk.response.model', Response::MODEL_DEPLOYMENT)
->param('functionId', '', new UID(), 'Function ID.')
->param('entrypoint', '', new Text('1028'), 'Entrypoint File.')
->param('code', [], new File(), 'Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.', false)
->param('activate', false, new Boolean(true), 'Automatically activate the deployment when it is finished building.', false)
->param('code', [], new File(), 'Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.', skipValidation: true)
->param('activate', false, new Boolean(true), 'Automatically activate the deployment when it is finished building.')
->inject('request')
->inject('response')
->inject('dbForProject')
@ -1348,7 +1346,7 @@ App::post('/v1/functions/:functionId/variables')
->label('sdk.response.model', Response::MODEL_VARIABLE)
->param('functionId', '', new UID(), 'Function unique ID.', false)
->param('key', null, new Text(Database::LENGTH_KEY), 'Variable key. Max length: ' . Database::LENGTH_KEY . ' chars.', false)
->param('value', null, new Text(8192), 'Variable value. Max length: 8192 chars.', false)
->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', false)
->inject('response')
->inject('dbForProject')
->action(function (string $functionId, string $key, string $value, Response $response, Database $dbForProject) {
@ -1464,7 +1462,7 @@ App::put('/v1/functions/:functionId/variables/:variableId')
->param('functionId', '', new UID(), 'Function unique ID.', false)
->param('variableId', '', new UID(), 'Variable unique ID.', false)
->param('key', null, new Text(255), 'Variable key. Max length: 255 chars.', false)
->param('value', null, new Text(8192), 'Variable value. Max length: 8192 chars.', true)
->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', true)
->inject('response')
->inject('dbForProject')
->action(function (string $functionId, string $variableId, string $key, ?string $value, Response $response, Database $dbForProject) {

View file

@ -30,7 +30,7 @@ App::get('/v1/graphql')
->label('sdk.response.model', Response::MODEL_ANY)
->label('abuse-limit', 60)
->label('abuse-time', 60)
->param('query', '', new Text(0), 'The query to execute.')
->param('query', '', new Text(0, 0), 'The query to execute.')
->param('operationName', '', new Text(256), 'The name of the operation to execute.', true)
->param('variables', '', new Text(0), 'The JSON encoded variables to use in the query.', true)
->inject('request')

View file

@ -348,7 +348,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
->label('sdk.response.model', Response::MODEL_FILE)
->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
->param('fileId', '', new CustomId(), 'File ID. Choose a custom ID or generate a random ID with `ID.unique()`. 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('file', [], new File(), 'Binary file.', false)
->param('file', [], new File(), 'Binary file.', skipValidation: true)
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE]), 'An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](/docs/permissions).', true)
->inject('request')
->inject('response')

View file

@ -594,7 +594,7 @@ App::get('/.well-known/acme-challenge')
$uriChunks = \explode('/', $request->getURI());
$token = $uriChunks[\count($uriChunks) - 1];
$validator = new Text(100, [
$validator = new Text(100, allowList: [
...Text::NUMBERS,
...Text::ALPHABET_LOWER,
...Text::ALPHABET_UPPER,

View file

@ -165,14 +165,14 @@ App::post('/v1/runtimes')
->desc("Create a new runtime server")
->param('runtimeId', '', new Text(64), 'Unique runtime ID.')
->param('source', '', new Text(0), 'Path to source files.')
->param('destination', '', new Text(0), 'Destination folder to store build files into.', true)
->param('destination', '', new Text(0, 0), 'Destination folder to store build files into.', true)
->param('vars', [], new Assoc(), 'Environment Variables required for the build.')
->param('commands', [], new ArrayList(new Text(1024), 100), 'Commands required to build the container. Maximum of 100 commands are allowed, each 1024 characters long.')
->param('runtime', '', new Text(128), 'Runtime for the cloud function.')
->param('baseImage', '', new Text(128), 'Base image name of the runtime.')
->param('entrypoint', '', new Text(256), 'Entrypoint of the code file.', true)
->param('remove', false, new Boolean(), 'Remove a runtime after execution.')
->param('workdir', '', new Text(256), 'Working directory.', true)
->param('workdir', '', new Text(256, 0), 'Working directory.', true)
->inject('orchestrationPool')
->inject('activeRuntimes')
->inject('response')
@ -459,7 +459,7 @@ App::post('/v1/execution')
->desc('Create an execution')
->param('runtimeId', '', new Text(64), 'The runtimeID to execute.')
->param('vars', [], new Assoc(), 'Environment variables required for the build.')
->param('data', '', new Text(8192), 'Data to be forwarded to the function, this is user specified.', true)
->param('data', '', new Text(8192, 0), 'Data to be forwarded to the function, this is user specified.', true)
->param('timeout', 15, new Range(1, (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)), 'Function maximum execution time in seconds.')
->inject('activeRuntimes')
->inject('response')

39
composer.lock generated
View file

@ -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": "65ec111f49af9c148eb69dc16aec7a10",
"content-hash": "db9e7adb4caf775eaa200d3888b65579",
"packages": [
{
"name": "adhocore/jwt",
@ -2113,20 +2113,19 @@
},
{
"name": "utopia-php/database",
"version": "dev-feat-relationships",
"version": "0.33.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/database.git",
"reference": "dc842d7c1c209ef55c7ce84c056efbc1dcd24283"
"reference": "7453256728053cddfb0c872ac8ca60157c4d8a11"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/database/zipball/dc842d7c1c209ef55c7ce84c056efbc1dcd24283",
"reference": "dc842d7c1c209ef55c7ce84c056efbc1dcd24283",
"url": "https://api.github.com/repos/utopia-php/database/zipball/7453256728053cddfb0c872ac8ca60157c4d8a11",
"reference": "7453256728053cddfb0c872ac8ca60157c4d8a11",
"shasum": ""
},
"require": {
"ext-pdo": "*",
"php": ">=8.0",
"utopia-php/cache": "0.8.*",
"utopia-php/framework": "0.*.*",
@ -2136,14 +2135,11 @@
"ext-mongodb": "*",
"ext-redis": "*",
"fakerphp/faker": "^1.14",
"laravel/pint": "1.4.*",
"mongodb/mongodb": "1.8.0",
"pcov/clobber": "^2.0",
"phpstan/phpstan": "1.9.*",
"phpunit/phpunit": "^9.4",
"rregeer/phpunit-coverage-check": "^0.3.1",
"swoole/ide-helper": "4.8.0",
"utopia-php/cli": "^0.14.0"
"utopia-php/cli": "^0.14.0",
"vimeo/psalm": "4.0.1"
},
"type": "library",
"autoload": {
@ -2155,7 +2151,7 @@
"license": [
"MIT"
],
"description": "A simple library to manage application persistence using multiple database adapters",
"description": "A simple library to manage application persistency using multiple database adapters",
"keywords": [
"database",
"framework",
@ -2165,9 +2161,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/database/issues",
"source": "https://github.com/utopia-php/database/tree/feat-relationships"
"source": "https://github.com/utopia-php/database/tree/0.33.0"
},
"time": "2023-03-15T07:38:26+00:00"
"time": "2023-03-08T08:46:35+00:00"
},
{
"name": "utopia-php/domains",
@ -5567,18 +5563,9 @@
"time": "2023-02-08T07:49:20+00:00"
}
],
"aliases": [
{
"package": "utopia-php/database",
"version": "dev-feat-relationships",
"alias": "0.33.0",
"alias_normalized": "0.33.0.0"
}
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {
"utopia-php/database": 20
},
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
@ -5602,5 +5589,5 @@
"platform-overrides": {
"php": "8.0"
},
"plugin-api-version": "2.2.0"
"plugin-api-version": "2.3.0"
}

View file

@ -0,0 +1 @@
Update an email attribute. Changing the `default` value will not update already existing documents.

View file

@ -0,0 +1 @@
Update an enum attribute. Changing the `default` value will not update already existing documents.

View file

@ -0,0 +1 @@
Update a float attribute. Changing the `default` value will not update already existing documents.

View file

@ -0,0 +1 @@
Update an integer attribute. Changing the `default` value will not update already existing documents.

View file

@ -0,0 +1 @@
Update an ip attribute. Changing the `default` value will not update already existing documents.

View file

@ -0,0 +1 @@
Update a string attribute. Changing the `default` value will not update already existing documents.

View file

@ -0,0 +1 @@
Update an url attribute. Changing the `default` value will not update already existing documents.

View file

@ -146,6 +146,7 @@ class Exception extends \Exception
public const ATTRIBUTE_ALREADY_EXISTS = 'attribute_already_exists';
public const ATTRIBUTE_LIMIT_EXCEEDED = 'attribute_limit_exceeded';
public const ATTRIBUTE_VALUE_INVALID = 'attribute_value_invalid';
public const ATTRIBUTE_TYPE_INVALID = 'attribute_type_invalid';
/** Indexes */
public const INDEX_NOT_FOUND = 'index_not_found';

View file

@ -11,6 +11,7 @@ use GraphQL\Type\Definition\UnionType;
use Utopia\App;
use Utopia\Route;
use Utopia\Validator;
use Utopia\Validator\Nullable;
class Mapper
{
@ -109,9 +110,6 @@ class Mapper
'type' => $parameterType,
'description' => $parameter['description'],
];
if ($parameter['optional']) {
$params[$name]['defaultValue'] = $parameter['default'];
}
}
$field = [
@ -224,6 +222,12 @@ class Mapper
? \call_user_func_array($validator, $utopia->getResources($injections))
: $validator;
$isNullable = $validator instanceof Nullable;
if ($isNullable) {
$validator = $validator->getValidator();
}
switch ((!empty($validator)) ? $validator::class : '') {
case 'Appwrite\Network\Validator\CNAME':
case 'Appwrite\Task\Validator\Cron':
@ -294,7 +298,7 @@ class Mapper
break;
}
if ($required) {
if ($required && !$isNullable) {
$type = Type::nonNull($type);
}

View file

@ -8,6 +8,7 @@ use Appwrite\Utopia\Response\Model;
use Utopia\Database\Helpers\Permission;
use Utopia\Database\Helpers\Role;
use Utopia\Validator;
use Utopia\Validator\Nullable;
class OpenAPI3 extends Format
{
@ -284,6 +285,13 @@ class OpenAPI3 extends Format
}
}
$isNullable = $validator instanceof Nullable;
if ($isNullable) {
/** @var Nullable $validator */
$validator = $validator->getValidator();
}
switch ((!empty($validator)) ? \get_class($validator) : '') {
case 'Utopia\Validator\Text':
$node['schema']['type'] = $validator->getType();
@ -449,6 +457,10 @@ class OpenAPI3 extends Format
if ($node['x-global'] ?? false) {
$body['content'][$consumes[0]]['schema']['properties'][$name]['x-global'] = true;
}
if ($isNullable) {
$body['content'][$consumes[0]]['schema']['properties'][$name]['x-nullable'] = true;
}
}
$url = \str_replace(':' . $name, '{' . $name . '}', $url);

View file

@ -8,6 +8,7 @@ use Appwrite\Utopia\Response\Model;
use Utopia\Database\Helpers\Permission;
use Utopia\Database\Helpers\Role;
use Utopia\Validator;
use Utopia\Validator\Nullable;
class Swagger2 extends Format
{
@ -285,6 +286,13 @@ class Swagger2 extends Format
}
}
$isNullable = $validator instanceof Nullable;
if ($isNullable) {
/** @var Nullable $validator */
$validator = $validator->getValidator();
}
switch ((!empty($validator)) ? \get_class($validator) : '') {
case 'Utopia\Validator\Text':
$node['type'] = $validator->getType();
@ -448,6 +456,10 @@ class Swagger2 extends Format
$body['schema']['properties'][$name]['x-global'] = true;
}
if ($isNullable) {
$body['schema']['properties'][$name]['x-nullable'] = true;
}
if (\array_key_exists('items', $node)) {
$body['schema']['properties'][$name]['items'] = $node['items'];
}

View file

@ -46,14 +46,7 @@ trait ProjectCustom
'name' => 'Demo Project',
'teamId' => $team['body']['$id'],
'description' => 'Demo Project Description',
'logo' => '',
'url' => 'https://appwrite.io',
'legalName' => '',
'legalCountry' => '',
'legalState' => '',
'legalCity' => '',
'legalAddress' => '',
'legalTaxId' => '',
]);
$this->assertEquals(201, $project['headers']['status-code']);
@ -111,8 +104,6 @@ trait ProjectCustom
],
'url' => 'http://request-catcher:5000/webhook',
'security' => false,
'httpUser' => '',
'httpPass' => '',
]);
$this->assertEquals(201, $webhook['headers']['status-code']);

File diff suppressed because it is too large Load diff

View file

@ -109,6 +109,7 @@ class FunctionsCustomClientTest extends Scope
], [
'entrypoint' => 'index.php',
'code' => new CURLFile($code, 'application/x-gzip', \basename($code)),
'activate' => true
]);
$deploymentId = $deployment['body']['$id'] ?? '';
@ -223,6 +224,7 @@ class FunctionsCustomClientTest extends Scope
], [
'entrypoint' => 'index.php',
'code' => new CURLFile($code, 'application/x-gzip', \basename($code)), //different tarball names intentional
'activate' => true
]);
$deploymentId = $deployment['body']['$id'] ?? '';
@ -321,6 +323,7 @@ class FunctionsCustomClientTest extends Scope
], [
'entrypoint' => 'index.php',
'code' => new CURLFile($code, 'application/x-gzip', \basename($code)), //different tarball names intentional
'activate' => true
]);
$deploymentId = $deployment['body']['$id'] ?? '';
@ -549,6 +552,7 @@ class FunctionsCustomClientTest extends Scope
], [
'entrypoint' => 'index.php',
'code' => new CURLFile($code, 'application/x-gzip', \basename($code)), //different tarball names intentional
'activate' => true
]);
$deploymentId = $deployment['body']['$id'] ?? '';

View file

@ -363,6 +363,7 @@ class FunctionsCustomServerTest extends Scope
], $this->getHeaders()), [
'entrypoint' => 'index.php',
'code' => new CURLFile($code, 'application/x-gzip', \basename($code)),
'activate' => true
]);
$deploymentId = $deployment['body']['$id'] ?? '';
@ -411,6 +412,7 @@ class FunctionsCustomServerTest extends Scope
$largeTag = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/deployments', array_merge($headers, $this->getHeaders()), [
'entrypoint' => 'index.php',
'code' => $curlFile,
'activate' => true
]);
$counter++;
$id = $largeTag['body']['$id'];
@ -741,7 +743,6 @@ class FunctionsCustomServerTest extends Scope
/**
* Test for SUCCESS
*/
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/executions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@ -752,7 +753,6 @@ class FunctionsCustomServerTest extends Scope
$this->assertEquals(201, $execution['headers']['status-code']);
$this->assertEquals('completed', $execution['body']['status']);
$this->assertStringContainsString($data['deploymentId'], $execution['body']['response']);
$this->assertStringContainsString('Test1', $execution['body']['response']);
$this->assertStringContainsString('http', $execution['body']['response']);
$this->assertStringContainsString('PHP', $execution['body']['response']);
@ -869,7 +869,6 @@ class FunctionsCustomServerTest extends Scope
'name' => 'Test ' . $name,
'runtime' => $name,
'events' => [],
'schedule' => '',
'timeout' => $timeout,
]);
@ -953,7 +952,6 @@ class FunctionsCustomServerTest extends Scope
'name' => 'Test ' . $name,
'runtime' => $name,
'events' => [],
'schedule' => '',
'timeout' => $timeout,
]);
@ -967,6 +965,7 @@ class FunctionsCustomServerTest extends Scope
], $this->getHeaders()), [
'entrypoint' => $entrypoint,
'code' => new CURLFile($code, 'application/x-gzip', basename($code)),
'activate' => true
]);
$deploymentId = $deployment['body']['$id'] ?? '';
@ -1063,7 +1062,6 @@ class FunctionsCustomServerTest extends Scope
'name' => 'Test ' . $name,
'runtime' => $name,
'events' => [],
'schedule' => '',
'timeout' => $timeout,
]);
@ -1176,7 +1174,6 @@ class FunctionsCustomServerTest extends Scope
'name' => 'Test ' . $name,
'runtime' => $name,
'events' => [],
'schedule' => '',
'timeout' => $timeout,
]);
@ -1290,7 +1287,6 @@ class FunctionsCustomServerTest extends Scope
'name' => 'Test ' . $name,
'runtime' => $name,
'events' => [],
'schedule' => '',
'timeout' => $timeout,
]);
@ -1404,7 +1400,6 @@ class FunctionsCustomServerTest extends Scope
'name' => 'Test ' . $name,
'runtime' => $name,
'events' => [],
'schedule' => '',
'timeout' => $timeout,
]);

View file

@ -26,6 +26,15 @@ trait Base
public static string $CREATE_IP_ATTRIBUTE = 'create_ip_attribute';
public static string $CREATE_ENUM_ATTRIBUTE = 'create_enum_attribute';
public static string $CREATE_DATETIME_ATTRIBUTE = 'create_datetime_attribute';
public static string $UPDATE_STRING_ATTRIBUTE = 'update_string_attribute';
public static string $UPDATE_INTEGER_ATTRIBUTE = 'update_integer_attribute';
public static string $UPDATE_FLOAT_ATTRIBUTE = 'update_float_attribute';
public static string $UPDATE_BOOLEAN_ATTRIBUTE = 'update_boolean_attribute';
public static string $UPDATE_URL_ATTRIBUTE = 'update_url_attribute';
public static string $UPDATE_EMAIL_ATTRIBUTE = 'update_email_attribute';
public static string $UPDATE_IP_ATTRIBUTE = 'update_ip_attribute';
public static string $UPDATE_ENUM_ATTRIBUTE = 'update_enum_attribute';
public static string $UPDATE_DATETIME_ATTRIBUTE = 'update_datetime_attribute';
public static string $GET_ATTRIBUTES = 'get_attributes';
public static string $GET_ATTRIBUTE = 'get_attribute';
public static string $DELETE_ATTRIBUTE = 'delete_attribute';
@ -451,6 +460,74 @@ trait Base
array
}
}';
case self::$UPDATE_STRING_ATTRIBUTE:
return 'mutation updateStringAttribute($databaseId: String!, $collectionId: String!, $key: String!, $required: Boolean!, $default: String){
databasesUpdateStringAttribute(databaseId: $databaseId, collectionId: $collectionId, key: $key, required: $required, default: $default) {
required
default
}
}';
case self::$UPDATE_INTEGER_ATTRIBUTE:
return 'mutation updateIntegerAttribute($databaseId: String!, $collectionId: String!, $key: String!, $required: Boolean!, $min: Int!, $max: Int!, $default: Int){
databasesUpdateIntegerAttribute(databaseId: $databaseId, collectionId: $collectionId, key: $key, required: $required, min: $min, max: $max, default: $default) {
required
min
max
default
}
}';
case self::$UPDATE_FLOAT_ATTRIBUTE:
return 'mutation updateFloatAttribute($databaseId: String!, $collectionId: String!, $key: String!, $required: Boolean!, $min: Float!, $max: Float!, $default: Float){
databasesUpdateFloatAttribute(databaseId: $databaseId, collectionId: $collectionId, key: $key, min: $min, max: $max, required: $required, default: $default) {
required
min
max
default
}
}';
case self::$UPDATE_BOOLEAN_ATTRIBUTE:
return 'mutation updateBooleanAttribute($databaseId: String!, $collectionId: String!, $key: String!, $required: Boolean!, $default: Boolean){
databasesUpdateBooleanAttribute(databaseId: $databaseId, collectionId: $collectionId, key: $key, required: $required, default: $default) {
required
default
}
}';
case self::$UPDATE_URL_ATTRIBUTE:
return 'mutation updateUrlAttribute($databaseId: String!, $collectionId: String!, $key: String!, $required: Boolean!, $default: String){
databasesUpdateUrlAttribute(databaseId: $databaseId, collectionId: $collectionId, key: $key, required: $required, default: $default) {
required
default
}
}';
case self::$UPDATE_EMAIL_ATTRIBUTE:
return 'mutation updateEmailAttribute($databaseId: String!, $collectionId: String!, $key: String!, $required: Boolean!, $default: String){
databasesUpdateEmailAttribute(databaseId: $databaseId, collectionId: $collectionId, key: $key, required: $required, default: $default) {
required
default
}
}';
case self::$UPDATE_IP_ATTRIBUTE:
return 'mutation updateIpAttribute($databaseId: String!, $collectionId: String!, $key: String!, $required: Boolean!, $default: String){
databasesUpdateIpAttribute(databaseId: $databaseId, collectionId: $collectionId, key: $key, required: $required, default: $default) {
required
default
}
}';
case self::$UPDATE_ENUM_ATTRIBUTE:
return 'mutation updateEnumAttribute($databaseId: String!, $collectionId: String!, $key: String!, $elements: [String!]!, $required: Boolean!, $default: String){
databasesUpdateEnumAttribute(databaseId: $databaseId, collectionId: $collectionId, key: $key, elements: $elements, required: $required, default: $default) {
elements
required
default
}
}';
case self::$UPDATE_DATETIME_ATTRIBUTE:
return 'mutation updateDatetimeAttribute($databaseId: String!, $collectionId: String!, $key: String!, $required: Boolean!, $default: String){
databasesUpdateDatetimeAttribute(databaseId: $databaseId, collectionId: $collectionId, key: $key, required: $required, default: $default) {
required
default
}
}';
case self::$CREATE_INDEX:
return 'mutation createIndex($databaseId: String!, $collectionId: String!, $key: String!, $type: String!, $attributes: [String!]!, $orders: [String!]){
databasesCreateIndex(databaseId: $databaseId, collectionId: $collectionId, key: $key, type: $type, attributes: $attributes, orders: $orders) {

View file

@ -112,6 +112,42 @@ class DatabaseServerTest extends Scope
return $data;
}
/**
* @depends testCreateStringAttribute
* @throws Exception
*/
public function testUpdateStringAttribute($data): array
{
// Wait for attributes to be available
sleep(3);
$projectId = $this->getProject()['$id'];
$query = $this->getQuery(self::$UPDATE_STRING_ATTRIBUTE);
$gqlPayload = [
'query' => $query,
'variables' => [
'databaseId' => $data['database']['_id'],
'collectionId' => $data['collection']['_id'],
'key' => 'name',
'required' => false,
'default' => 'Default Value',
]
];
$attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $projectId,
], $this->getHeaders()), $gqlPayload);
$this->assertIsArray($attribute['body']['data']);
$this->assertIsArray($attribute['body']['data']['databasesUpdateStringAttribute']);
$this->assertFalse($attribute['body']['data']['databasesUpdateStringAttribute']['required']);
$this->assertEquals('Default Value', $attribute['body']['data']['databasesUpdateStringAttribute']['default']);
$this->assertEquals(200, $attribute['headers']['status-code']);
return $data;
}
/**
* @depends testCreateCollection
* @throws Exception
@ -144,6 +180,46 @@ class DatabaseServerTest extends Scope
return $data;
}
/**
* @depends testCreateIntegerAttribute
* @throws Exception
*/
public function testUpdateIntegerAttribute($data): array
{
// Wait for attributes to be available
sleep(3);
$projectId = $this->getProject()['$id'];
$query = $this->getQuery(self::$UPDATE_INTEGER_ATTRIBUTE);
$gqlPayload = [
'query' => $query,
'variables' => [
'databaseId' => $data['database']['_id'],
'collectionId' => $data['collection']['_id'],
'key' => 'age',
'required' => false,
'min' => 12,
'max' => 160,
'default' => 50
]
];
$attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $projectId,
], $this->getHeaders()), $gqlPayload);
$this->assertIsArray($attribute['body']['data']);
$this->assertIsArray($attribute['body']['data']['databasesUpdateIntegerAttribute']);
$this->assertFalse($attribute['body']['data']['databasesUpdateIntegerAttribute']['required']);
$this->assertEquals(12, $attribute['body']['data']['databasesUpdateIntegerAttribute']['min']);
$this->assertEquals(160, $attribute['body']['data']['databasesUpdateIntegerAttribute']['max']);
$this->assertEquals(50, $attribute['body']['data']['databasesUpdateIntegerAttribute']['default']);
$this->assertEquals(200, $attribute['headers']['status-code']);
return $data;
}
/**
* @depends testCreateCollection
* @throws Exception
@ -174,6 +250,42 @@ class DatabaseServerTest extends Scope
return $data;
}
/**
* @depends testCreateBooleanAttribute
* @throws Exception
*/
public function testUpdateBooleanAttribute($data): array
{
// Wait for attributes to be available
sleep(3);
$projectId = $this->getProject()['$id'];
$query = $this->getQuery(self::$UPDATE_BOOLEAN_ATTRIBUTE);
$gqlPayload = [
'query' => $query,
'variables' => [
'databaseId' => $data['database']['_id'],
'collectionId' => $data['collection']['_id'],
'key' => 'alive',
'required' => false,
'default' => true
]
];
$attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $projectId,
], $this->getHeaders()), $gqlPayload);
$this->assertIsArray($attribute['body']['data']);
$this->assertIsArray($attribute['body']['data']['databasesUpdateBooleanAttribute']);
$this->assertFalse($attribute['body']['data']['databasesUpdateBooleanAttribute']['required']);
$this->assertTrue($attribute['body']['data']['databasesUpdateBooleanAttribute']['default']);
$this->assertEquals(200, $attribute['headers']['status-code']);
return $data;
}
/**
* @depends testCreateCollection
* @throws Exception
@ -207,6 +319,46 @@ class DatabaseServerTest extends Scope
return $data;
}
/**
* @depends testCreateFloatAttribute
* @throws Exception
*/
public function testUpdateFloatAttribute($data): array
{
// Wait for attributes to be available
sleep(3);
$projectId = $this->getProject()['$id'];
$query = $this->getQuery(self::$UPDATE_FLOAT_ATTRIBUTE);
$gqlPayload = [
'query' => $query,
'variables' => [
'databaseId' => $data['database']['_id'],
'collectionId' => $data['collection']['_id'],
'key' => 'salary',
'required' => false,
'min' => 100.0,
'max' => 1000000.0,
'default' => 2500.0
]
];
$attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $projectId,
], $this->getHeaders()), $gqlPayload);
$this->assertIsArray($attribute['body']['data']);
$this->assertIsArray($attribute['body']['data']['databasesUpdateFloatAttribute']);
$this->assertFalse($attribute['body']['data']['databasesUpdateFloatAttribute']['required']);
$this->assertEquals(100.0, $attribute['body']['data']['databasesUpdateFloatAttribute']['min']);
$this->assertEquals(1000000.0, $attribute['body']['data']['databasesUpdateFloatAttribute']['max']);
$this->assertEquals(2500.0, $attribute['body']['data']['databasesUpdateFloatAttribute']['default']);
$this->assertEquals(200, $attribute['headers']['status-code']);
return $data;
}
/**
* @depends testCreateCollection
* @throws Exception
@ -237,6 +389,42 @@ class DatabaseServerTest extends Scope
return $data;
}
/**
* @depends testCreateEmailAttribute
* @throws Exception
*/
public function testUpdateEmailAttribute($data): array
{
// Wait for attributes to be available
sleep(3);
$projectId = $this->getProject()['$id'];
$query = $this->getQuery(self::$UPDATE_EMAIL_ATTRIBUTE);
$gqlPayload = [
'query' => $query,
'variables' => [
'databaseId' => $data['database']['_id'],
'collectionId' => $data['collection']['_id'],
'key' => 'email',
'required' => false,
'default' => 'torsten@appwrite.io',
]
];
$attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $projectId,
], $this->getHeaders()), $gqlPayload);
$this->assertIsArray($attribute['body']['data']);
$this->assertIsArray($attribute['body']['data']['databasesUpdateEmailAttribute']);
$this->assertFalse($attribute['body']['data']['databasesUpdateEmailAttribute']['required']);
$this->assertEquals('torsten@appwrite.io', $attribute['body']['data']['databasesUpdateEmailAttribute']['default']);
$this->assertEquals(200, $attribute['headers']['status-code']);
return $data;
}
/**
* @depends testCreateCollection
* @throws Exception
@ -272,6 +460,50 @@ class DatabaseServerTest extends Scope
return $data;
}
/**
* @depends testCreateEnumAttribute
* @throws Exception
*/
public function testUpdateEnumAttribute($data): array
{
// Wait for attributes to be available
sleep(3);
$projectId = $this->getProject()['$id'];
$query = $this->getQuery(self::$UPDATE_ENUM_ATTRIBUTE);
$gqlPayload = [
'query' => $query,
'variables' => [
'databaseId' => $data['database']['_id'],
'collectionId' => $data['collection']['_id'],
'key' => 'role',
'required' => false,
'elements' => [
'crew',
'tech',
'actor'
],
'default' => 'tech'
]
];
$attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $projectId,
], $this->getHeaders()), $gqlPayload);
$this->assertIsArray($attribute['body']['data']);
$this->assertIsArray($attribute['body']['data']['databasesUpdateEnumAttribute']);
$this->assertFalse($attribute['body']['data']['databasesUpdateEnumAttribute']['required']);
$this->assertEquals('tech', $attribute['body']['data']['databasesUpdateEnumAttribute']['default']);
$this->assertContains('tech', $attribute['body']['data']['databasesUpdateEnumAttribute']['elements']);
$this->assertNotContains('guest', $attribute['body']['data']['databasesUpdateEnumAttribute']['elements']);
$this->assertEquals(200, $attribute['headers']['status-code']);
return $data;
}
/**
* @depends testCreateCollection
* @throws Exception
@ -302,6 +534,42 @@ class DatabaseServerTest extends Scope
return $data;
}
/**
* @depends testCreateDatetimeAttribute
* @throws Exception
*/
public function testUpdateDatetimeAttribute($data): array
{
// Wait for attributes to be available
sleep(3);
$projectId = $this->getProject()['$id'];
$query = $this->getQuery(self::$UPDATE_DATETIME_ATTRIBUTE);
$gqlPayload = [
'query' => $query,
'variables' => [
'databaseId' => $data['database']['_id'],
'collectionId' => $data['collection']['_id'],
'key' => 'dob',
'required' => false,
'default' => '2000-01-01T00:00:00Z'
]
];
$attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $projectId,
], $this->getHeaders()), $gqlPayload);
$this->assertIsArray($attribute['body']['data']);
$this->assertIsArray($attribute['body']['data']['databasesUpdateDatetimeAttribute']);
$this->assertFalse($attribute['body']['data']['databasesUpdateDatetimeAttribute']['required']);
$this->assertEquals('2000-01-01T00:00:00Z', $attribute['body']['data']['databasesUpdateDatetimeAttribute']['default']);
$this->assertEquals(200, $attribute['headers']['status-code']);
return $data;
}
/**
* @depends testCreateCollection
* @throws Exception
@ -333,6 +601,42 @@ class DatabaseServerTest extends Scope
return $data;
}
/**
* @depends testCreateIPAttribute
* @throws Exception
*/
public function testUpdateIPAttribute($data): array
{
// Wait for attributes to be available
sleep(3);
$projectId = $this->getProject()['$id'];
$query = $this->getQuery(self::$UPDATE_IP_ATTRIBUTE);
$gqlPayload = [
'query' => $query,
'variables' => [
'databaseId' => $data['database']['_id'],
'collectionId' => $data['collection']['_id'],
'key' => 'ip',
'required' => false,
'default' => '127.0.0.1'
]
];
$attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $projectId,
], $this->getHeaders()), $gqlPayload);
$this->assertIsArray($attribute['body']['data']);
$this->assertIsArray($attribute['body']['data']['databasesUpdateIpAttribute']);
$this->assertFalse($attribute['body']['data']['databasesUpdateIpAttribute']['required']);
$this->assertEquals('127.0.0.1', $attribute['body']['data']['databasesUpdateIpAttribute']['default']);
$this->assertEquals(200, $attribute['headers']['status-code']);
return $data;
}
/**
* @depends testCreateCollection
* @throws Exception
@ -365,15 +669,46 @@ class DatabaseServerTest extends Scope
}
/**
* @depends testCreateStringAttribute
* @depends testCreateIntegerAttribute
* @depends testCreateURLAttribute
* @throws Exception
*/
public function testCreateIndex($data): array
public function testUpdateURLAttribute($data): void
{
// Wait for attributes to be available
sleep(3);
$projectId = $this->getProject()['$id'];
$query = $this->getQuery(self::$UPDATE_URL_ATTRIBUTE);
$gqlPayload = [
'query' => $query,
'variables' => [
'databaseId' => $data['database']['_id'],
'collectionId' => $data['collection']['_id'],
'key' => 'url',
'required' => false,
'default' => 'https://cloud.appwrite.io'
]
];
$attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $projectId,
], $this->getHeaders()), $gqlPayload);
$this->assertIsArray($attribute['body']['data']);
$this->assertIsArray($attribute['body']['data']['databasesUpdateUrlAttribute']);
$this->assertFalse($attribute['body']['data']['databasesUpdateUrlAttribute']['required']);
$this->assertEquals('https://cloud.appwrite.io', $attribute['body']['data']['databasesUpdateUrlAttribute']['default']);
$this->assertEquals(200, $attribute['headers']['status-code']);
}
/**
* @depends testUpdateStringAttribute
* @depends testUpdateIntegerAttribute
* @throws Exception
*/
public function testCreateIndex($data): array
{
$projectId = $this->getProject()['$id'];
$query = $this->getQuery(self::$CREATE_INDEX);
$gqlPayload = [
@ -407,10 +742,10 @@ class DatabaseServerTest extends Scope
}
/**
* @depends testCreateStringAttribute
* @depends testCreateIntegerAttribute
* @depends testCreateBooleanAttribute
* @depends testCreateEnumAttribute
* @depends testUpdateStringAttribute
* @depends testUpdateIntegerAttribute
* @depends testUpdateBooleanAttribute
* @depends testUpdateEnumAttribute
* @throws Exception
*/
public function testCreateDocument($data): array
@ -458,45 +793,45 @@ class DatabaseServerTest extends Scope
];
}
// /**
// * @depends testCreateStringAttribute
// * @depends testCreateIntegerAttribute
// * @depends testCreateBooleanAttribute
// * @depends testCreateFloatAttribute
// * @depends testCreateEmailAttribute
// * @depends testCreateEnumAttribute
// * @depends testCreateDatetimeAttribute
// * @throws Exception
// */
// public function testCreateCustomEntity(): array
// {
// $projectId = $this->getProject()['$id'];
// $query = $this->getQuery(self::$CREATE_CUSTOM_ENTITY);
// $gqlPayload = [
// 'query' => $query,
// 'variables' => [
// 'name' => 'John Doe',
// 'age' => 35,
// 'alive' => true,
// 'salary' => 9999.9,
// 'email' => 'johndoe@appwrite.io',
// 'role' => 'crew',
// 'dob' => '2000-01-01T00:00:00Z',
// ]
// ];
//
// $actor = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
// 'content-type' => 'application/json',
// 'x-appwrite-project' => $projectId,
// ], $this->getHeaders()), $gqlPayload);
//
// $this->assertArrayNotHasKey('errors', $actor['body']);
// $this->assertIsArray($actor['body']['data']);
// $actor = $actor['body']['data']['actorsCreate'];
// $this->assertIsArray($actor);
//
// return $actor;
// }
// /**
// * @depends testCreateStringAttribute
// * @depends testCreateIntegerAttribute
// * @depends testCreateBooleanAttribute
// * @depends testCreateFloatAttribute
// * @depends testCreateEmailAttribute
// * @depends testCreateEnumAttribute
// * @depends testCreateDatetimeAttribute
// * @throws Exception
// */
// public function testCreateCustomEntity(): array
// {
// $projectId = $this->getProject()['$id'];
// $query = $this->getQuery(self::$CREATE_CUSTOM_ENTITY);
// $gqlPayload = [
// 'query' => $query,
// 'variables' => [
// 'name' => 'John Doe',
// 'age' => 35,
// 'alive' => true,
// 'salary' => 9999.9,
// 'email' => 'johndoe@appwrite.io',
// 'role' => 'crew',
// 'dob' => '2000-01-01T00:00:00Z',
// ]
// ];
//
// $actor = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
// 'content-type' => 'application/json',
// 'x-appwrite-project' => $projectId,
// ], $this->getHeaders()), $gqlPayload);
//
// $this->assertArrayNotHasKey('errors', $actor['body']);
// $this->assertIsArray($actor['body']['data']);
// $actor = $actor['body']['data']['actorsCreate'];
// $this->assertIsArray($actor);
//
// return $actor;
// }
public function testGetDatabases(): void
{
@ -593,8 +928,8 @@ class DatabaseServerTest extends Scope
}
/**
* @depends testCreateStringAttribute
* @depends testCreateIntegerAttribute
* @depends testUpdateStringAttribute
* @depends testUpdateIntegerAttribute
* @throws Exception
*/
public function testGetAttributes($data): void
@ -752,52 +1087,52 @@ class DatabaseServerTest extends Scope
$this->assertIsArray($document['body']['data']['databasesGetDocument']);
}
// /**
// * @depends testCreateCustomEntity
// * @throws Exception
// */
// public function testGetCustomEntities($data)
// {
// $projectId = $this->getProject()['$id'];
// $query = $this->getQuery(self::$GET_CUSTOM_ENTITIES);
// $gqlPayload = [
// 'query' => $query,
// ];
//
// $customEntities = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
// 'content-type' => 'application/json',
// 'x-appwrite-project' => $projectId,
// ], $this->getHeaders()), $gqlPayload);
//
// $this->assertArrayNotHasKey('errors', $customEntities['body']);
// $this->assertIsArray($customEntities['body']['data']);
// $this->assertIsArray($customEntities['body']['data']['actorsList']);
// }
//
// /**
// * @depends testCreateCustomEntity
// * @throws Exception
// */
// public function testGetCustomEntity($data)
// {
// $projectId = $this->getProject()['$id'];
// $query = $this->getQuery(self::$GET_CUSTOM_ENTITY);
// $gqlPayload = [
// 'query' => $query,
// 'variables' => [
// 'id' => $data['id'],
// ]
// ];
//
// $entity = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
// 'content-type' => 'application/json',
// 'x-appwrite-project' => $projectId,
// ], $this->getHeaders()), $gqlPayload);
//
// $this->assertArrayNotHasKey('errors', $entity['body']);
// $this->assertIsArray($entity['body']['data']);
// $this->assertIsArray($entity['body']['data']['actorsGet']);
// }
// /**
// * @depends testCreateCustomEntity
// * @throws Exception
// */
// public function testGetCustomEntities($data)
// {
// $projectId = $this->getProject()['$id'];
// $query = $this->getQuery(self::$GET_CUSTOM_ENTITIES);
// $gqlPayload = [
// 'query' => $query,
// ];
//
// $customEntities = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
// 'content-type' => 'application/json',
// 'x-appwrite-project' => $projectId,
// ], $this->getHeaders()), $gqlPayload);
//
// $this->assertArrayNotHasKey('errors', $customEntities['body']);
// $this->assertIsArray($customEntities['body']['data']);
// $this->assertIsArray($customEntities['body']['data']['actorsList']);
// }
//
// /**
// * @depends testCreateCustomEntity
// * @throws Exception
// */
// public function testGetCustomEntity($data)
// {
// $projectId = $this->getProject()['$id'];
// $query = $this->getQuery(self::$GET_CUSTOM_ENTITY);
// $gqlPayload = [
// 'query' => $query,
// 'variables' => [
// 'id' => $data['id'],
// ]
// ];
//
// $entity = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
// 'content-type' => 'application/json',
// 'x-appwrite-project' => $projectId,
// ], $this->getHeaders()), $gqlPayload);
//
// $this->assertArrayNotHasKey('errors', $entity['body']);
// $this->assertIsArray($entity['body']['data']);
// $this->assertIsArray($entity['body']['data']['actorsGet']);
// }
/**
* @depends testCreateDatabase
@ -885,33 +1220,33 @@ class DatabaseServerTest extends Scope
$this->assertStringContainsString('New Document Name', $document['data']);
}
// /**
// * @depends testCreateCustomEntity
// * @throws Exception
// */
// public function testUpdateCustomEntity(array $data)
// {
// $projectId = $this->getProject()['$id'];
// $query = $this->getQuery(self::$UPDATE_CUSTOM_ENTITY);
// $gqlPayload = [
// 'query' => $query,
// 'variables' => [
// 'id' => $data['id'],
// 'name' => 'New Custom Entity Name',
// ]
// ];
//
// $entity = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
// 'content-type' => 'application/json',
// 'x-appwrite-project' => $projectId,
// ], $this->getHeaders()), $gqlPayload);
//
// $this->assertArrayNotHasKey('errors', $entity['body']);
// $this->assertIsArray($entity['body']['data']);
// $entity = $entity['body']['data']['actorsUpdate'];
// $this->assertIsArray($entity);
// $this->assertStringContainsString('New Custom Entity Name', $entity['name']);
// }
// /**
// * @depends testCreateCustomEntity
// * @throws Exception
// */
// public function testUpdateCustomEntity(array $data)
// {
// $projectId = $this->getProject()['$id'];
// $query = $this->getQuery(self::$UPDATE_CUSTOM_ENTITY);
// $gqlPayload = [
// 'query' => $query,
// 'variables' => [
// 'id' => $data['id'],
// 'name' => 'New Custom Entity Name',
// ]
// ];
//
// $entity = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
// 'content-type' => 'application/json',
// 'x-appwrite-project' => $projectId,
// ], $this->getHeaders()), $gqlPayload);
//
// $this->assertArrayNotHasKey('errors', $entity['body']);
// $this->assertIsArray($entity['body']['data']);
// $entity = $entity['body']['data']['actorsUpdate'];
// $this->assertIsArray($entity);
// $this->assertStringContainsString('New Custom Entity Name', $entity['name']);
// }
/**
* @depends testCreateDocument
@ -939,32 +1274,32 @@ class DatabaseServerTest extends Scope
$this->assertEquals(204, $document['headers']['status-code']);
}
// /**
// * @depends testCreateCustomEntity
// * @throws Exception
// */
// public function testDeleteCustomEntity(array $data)
// {
// $projectId = $this->getProject()['$id'];
// $query = $this->getQuery(self::$DELETE_CUSTOM_ENTITY);
// $gqlPayload = [
// 'query' => $query,
// 'variables' => [
// 'id' => $data['id'],
// ]
// ];
//
// $entity = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
// 'content-type' => 'application/json',
// 'x-appwrite-project' => $projectId,
// ], $this->getHeaders()), $gqlPayload);
//
// $this->assertIsNotArray($entity['body']);
// $this->assertEquals(204, $entity['headers']['status-code']);
// }
// /**
// * @depends testCreateCustomEntity
// * @throws Exception
// */
// public function testDeleteCustomEntity(array $data)
// {
// $projectId = $this->getProject()['$id'];
// $query = $this->getQuery(self::$DELETE_CUSTOM_ENTITY);
// $gqlPayload = [
// 'query' => $query,
// 'variables' => [
// 'id' => $data['id'],
// ]
// ];
//
// $entity = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
// 'content-type' => 'application/json',
// 'x-appwrite-project' => $projectId,
// ], $this->getHeaders()), $gqlPayload);
//
// $this->assertIsNotArray($entity['body']);
// $this->assertEquals(204, $entity['headers']['status-code']);
// }
/**
* @depends testCreateStringAttribute
* @depends testUpdateStringAttribute
* @throws Exception
*/
public function testDeleteAttribute($data): void

View file

@ -1655,8 +1655,6 @@ class ProjectsConsoleClientTest extends Scope
'events' => ['users.*.delete', 'users.*.sessions.*.delete', 'buckets.*.files.*.create'],
'url' => 'https://appwrite.io/new',
'security' => false,
'httpUser' => '',
'httpPass' => ''
]);
$this->assertEquals(200, $response['headers']['status-code']);
@ -1703,8 +1701,6 @@ class ProjectsConsoleClientTest extends Scope
'events' => ['users.*.delete', 'users.*.sessions.*.delete', 'buckets.*.files.*.unknown'],
'url' => 'https://appwrite.io/new',
'security' => false,
'httpUser' => '',
'httpPass' => '',
]);
$this->assertEquals(400, $response['headers']['status-code']);
@ -1717,8 +1713,6 @@ class ProjectsConsoleClientTest extends Scope
'events' => ['users.*.delete', 'users.*.sessions.*.delete', 'buckets.*.files.*.create'],
'url' => 'appwrite.io/new',
'security' => false,
'httpUser' => '',
'httpPass' => '',
]);
$this->assertEquals(400, $response['headers']['status-code']);
@ -2090,8 +2084,6 @@ class ProjectsConsoleClientTest extends Scope
], $this->getHeaders()), [
'type' => 'web',
'name' => 'Web App',
'key' => '',
'store' => '',
'hostname' => 'localhost',
]);
@ -2112,8 +2104,6 @@ class ProjectsConsoleClientTest extends Scope
'type' => 'flutter-ios',
'name' => 'Flutter App (iOS)',
'key' => 'com.example.ios',
'store' => '',
'hostname' => '',
]);
$this->assertEquals(201, $response['headers']['status-code']);
@ -2133,8 +2123,6 @@ class ProjectsConsoleClientTest extends Scope
'type' => 'flutter-android',
'name' => 'Flutter App (Android)',
'key' => 'com.example.android',
'store' => '',
'hostname' => '',
]);
$this->assertEquals(201, $response['headers']['status-code']);
@ -2153,8 +2141,6 @@ class ProjectsConsoleClientTest extends Scope
], $this->getHeaders()), [
'type' => 'flutter-web',
'name' => 'Flutter App (Web)',
'key' => '',
'store' => '',
'hostname' => 'flutter.appwrite.io',
]);
@ -2175,8 +2161,6 @@ class ProjectsConsoleClientTest extends Scope
'type' => 'apple-ios',
'name' => 'iOS App',
'key' => 'com.example.ios',
'store' => '',
'hostname' => '',
]);
$this->assertEquals(201, $response['headers']['status-code']);
@ -2196,8 +2180,6 @@ class ProjectsConsoleClientTest extends Scope
'type' => 'apple-macos',
'name' => 'macOS App',
'key' => 'com.example.macos',
'store' => '',
'hostname' => '',
]);
$this->assertEquals(201, $response['headers']['status-code']);
@ -2217,8 +2199,6 @@ class ProjectsConsoleClientTest extends Scope
'type' => 'apple-watchos',
'name' => 'watchOS App',
'key' => 'com.example.watchos',
'store' => '',
'hostname' => '',
]);
$this->assertEquals(201, $response['headers']['status-code']);
@ -2238,8 +2218,6 @@ class ProjectsConsoleClientTest extends Scope
'type' => 'apple-tvos',
'name' => 'tvOS App',
'key' => 'com.example.tvos',
'store' => '',
'hostname' => '',
]);
$this->assertEquals(201, $response['headers']['status-code']);
@ -2261,8 +2239,6 @@ class ProjectsConsoleClientTest extends Scope
], $this->getHeaders()), [
'type' => 'unknown',
'name' => 'Web App',
'key' => '',
'store' => '',
'hostname' => 'localhost',
]);
@ -2457,8 +2433,6 @@ class ProjectsConsoleClientTest extends Scope
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'name' => 'Web App 2',
'key' => '',
'store' => '',
'hostname' => 'localhost-new',
]);
@ -2479,8 +2453,6 @@ class ProjectsConsoleClientTest extends Scope
], $this->getHeaders()), [
'name' => 'Flutter App (iOS) 2',
'key' => 'com.example.ios2',
'store' => '',
'hostname' => '',
]);
$this->assertEquals(200, $response['headers']['status-code']);
@ -2500,8 +2472,6 @@ class ProjectsConsoleClientTest extends Scope
], $this->getHeaders()), [
'name' => 'Flutter App (Android) 2',
'key' => 'com.example.android2',
'store' => '',
'hostname' => '',
]);
$this->assertEquals(200, $response['headers']['status-code']);
@ -2520,8 +2490,6 @@ class ProjectsConsoleClientTest extends Scope
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'name' => 'Flutter App (Web) 2',
'key' => '',
'store' => '',
'hostname' => 'flutter2.appwrite.io',
]);
@ -2542,8 +2510,6 @@ class ProjectsConsoleClientTest extends Scope
], $this->getHeaders()), [
'name' => 'iOS App 2',
'key' => 'com.example.ios2',
'store' => '',
'hostname' => '',
]);
$this->assertEquals(200, $response['headers']['status-code']);
@ -2563,8 +2529,6 @@ class ProjectsConsoleClientTest extends Scope
], $this->getHeaders()), [
'name' => 'macOS App 2',
'key' => 'com.example.macos2',
'store' => '',
'hostname' => '',
]);
$this->assertEquals(200, $response['headers']['status-code']);
@ -2584,8 +2548,6 @@ class ProjectsConsoleClientTest extends Scope
], $this->getHeaders()), [
'name' => 'watchOS App 2',
'key' => 'com.example.watchos2',
'store' => '',
'hostname' => '',
]);
$this->assertEquals(200, $response['headers']['status-code']);
@ -2605,8 +2567,6 @@ class ProjectsConsoleClientTest extends Scope
], $this->getHeaders()), [
'name' => 'tvOS App 2',
'key' => 'com.example.tvos2',
'store' => '',
'hostname' => '',
]);
$this->assertEquals(200, $response['headers']['status-code']);
@ -2627,8 +2587,6 @@ class ProjectsConsoleClientTest extends Scope
], $this->getHeaders()), [
'name' => 'Flutter App (Android) 2',
'key' => 'com.example.android2',
'store' => '',
'hostname' => '',
]);
$this->assertEquals(404, $response['headers']['status-code']);
@ -2836,8 +2794,6 @@ class ProjectsConsoleClientTest extends Scope
], $this->getHeaders()), [
'type' => 'web',
'name' => 'Too Long Hostname',
'key' => '',
'store' => '',
'hostname' => \str_repeat("bestdomain", 25) . '.com' // 250 + 4 chars total (exactly above limit)
]);

View file

@ -443,7 +443,7 @@ class RealtimeConsoleClientTest extends Scope
'users.*.delete',
],
'schedule' => '0 0 1 1 *',
'timeout' => 10,
'timeout' => 10
]);
$functionId = $response1['body']['$id'] ?? '';
@ -482,6 +482,7 @@ class RealtimeConsoleClientTest extends Scope
], $this->getHeaders()), [
'entrypoint' => 'index.php',
'code' => new CURLFile($code, 'application/x-gzip', \basename($code)),
'activate' => true
]);
$deploymentId = $deployment['body']['$id'] ?? '';

View file

@ -1284,7 +1284,8 @@ class RealtimeCustomClientTest extends Scope
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'entrypoint' => 'index.php',
'code' => new CURLFile($code, 'application/x-gzip', basename($code))
'code' => new CURLFile($code, 'application/x-gzip', basename($code)),
'activate' => true
]);
$deploymentId = $deployment['body']['$id'] ?? '';

View file

@ -517,11 +517,22 @@ trait TeamsBaseClient
'x-appwrite-project' => $this->getProject()['$id'],
]), [
'secret' => $secret,
'userId' => ID::custom(''),
'userId' => ID::custom('$notallowed'),
]);
$this->assertEquals(400, $response['headers']['status-code']);
$response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid . '/status', array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
]), [
'secret' => $secret,
'userId' => ID::custom(''),
]);
$this->assertEquals(401, $response['headers']['status-code']);
$response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid . '/status', array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',

View file

@ -484,16 +484,6 @@ class WebhooksCustomServerTest extends Scope
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
$function = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'name' => 'Test Failure',
'execute' => [ 'not-valid-permission' ]
]);
$this->assertEquals($function['headers']['status-code'], 400);
return $data;
}
@ -516,7 +506,8 @@ class WebhooksCustomServerTest extends Scope
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'entrypoint' => 'index.php',
'code' => new CURLFile($code, 'application/x-gzip', \basename($code))
'code' => new CURLFile($code, 'application/x-gzip', \basename($code)),
'activate' => true
]);
$id = $data['functionId'] ?? '';