mirror of
https://github.com/appwrite/appwrite
synced 2026-05-23 00:49:02 +00:00
Merge branch 'master' of https://github.com/appwrite/appwrite into 1.3.x
This commit is contained in:
commit
125c14d492
17 changed files with 554 additions and 192 deletions
|
|
@ -15,14 +15,14 @@
|
|||
|
||||
## Bugs
|
||||
|
||||
- Fix minimum length for string attribute default values [#5606](https://github.com/appwrite/appwrite/pull/5606)
|
||||
- Fix minimum length for string attribute default values [#5606](https://github.com/appwrite/appwrite/pull/5606), [#5602](https://github.com/appwrite/appwrite/pull/5602)
|
||||
- Update framework to fix route mismatches [#5603](https://github.com/appwrite/appwrite/pull/5603)
|
||||
|
||||
# Version 1.3.4
|
||||
|
||||
## Bugs
|
||||
|
||||
- Update migration to properly migrate bucket permissiosn [#5497](https://github.com/appwrite/appwrite/pull/5497)
|
||||
- Update migration to properly migrate bucket permissions [#5497](https://github.com/appwrite/appwrite/pull/5497)
|
||||
|
||||
# Version 1.3.3
|
||||
|
||||
|
|
@ -35,6 +35,7 @@
|
|||
- Fixed auto-setting custom ID on nested documents [#5363](https://github.com/appwrite/appwrite/pull/5363)
|
||||
- Fixed listDocuments not returning all the documents [#5395](https://github.com/appwrite/appwrite/pull/5395)
|
||||
- Fixed deleting keys, webhooks, platforms and domains after deleting project [#5395](https://github.com/appwrite/appwrite/pull/5395)
|
||||
- Fixed empty team prefs returning as JSON object rather array [#5361](https://github.com/appwrite/appwrite/pull/5361)
|
||||
|
||||
# Version 1.3.1
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,17 @@ $collections = [
|
|||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('enabled'),
|
||||
'type' => Database::VAR_BOOLEAN,
|
||||
'signed' => true,
|
||||
'size' => 0,
|
||||
'format' => '',
|
||||
'filters' => [],
|
||||
'required' => false,
|
||||
'default' => true,
|
||||
'array' => false,
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('search'),
|
||||
'type' => Database::VAR_STRING,
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ return [
|
|||
],
|
||||
Exception::USER_BLOCKED => [
|
||||
'name' => Exception::USER_BLOCKED,
|
||||
'description' => 'The current user has been blocked. You can unblock the user from the Appwrite console.',
|
||||
'description' => 'The current user has been blocked.',
|
||||
'code' => 401,
|
||||
],
|
||||
Exception::USER_INVALID_TOKEN => [
|
||||
|
|
@ -403,9 +403,14 @@ return [
|
|||
'description' => 'The document structure is invalid. Please ensure the attributes match the collection definition.',
|
||||
'code' => 400,
|
||||
],
|
||||
Exception::DOCUMENT_MISSING_DATA => [
|
||||
'name' => Exception::DOCUMENT_MISSING_DATA,
|
||||
'description' => 'The document data is missing. You must provide the document data.',
|
||||
'code' => 400,
|
||||
],
|
||||
Exception::DOCUMENT_MISSING_PAYLOAD => [
|
||||
'name' => Exception::DOCUMENT_MISSING_PAYLOAD,
|
||||
'description' => 'The document payload is missing.',
|
||||
'description' => 'The document data and permissions are missing. You must provide either the document data or permissions to be updated.',
|
||||
'code' => 400,
|
||||
],
|
||||
Exception::DOCUMENT_ALREADY_EXISTS => [
|
||||
|
|
@ -494,6 +499,11 @@ return [
|
|||
'description' => 'Project with the requested ID could not be found. Please check the value of the X-Appwrite-Project header to ensure the correct project ID is being used.',
|
||||
'code' => 404,
|
||||
],
|
||||
Exception::PROJECT_ALREADY_EXISTS => [
|
||||
'name' => Exception::PROJECT_ALREADY_EXISTS,
|
||||
'description' => 'Project with the requested ID already exists.',
|
||||
'code' => 409,
|
||||
],
|
||||
Exception::PROJECT_UNKNOWN => [
|
||||
'name' => Exception::PROJECT_UNKNOWN,
|
||||
'description' => 'The project ID is either missing or not valid. Please check the value of the X-Appwrite-Project header to ensure the correct project ID is being used.',
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ return [
|
|||
],
|
||||
[
|
||||
'name' => '_APP_LOGGING_PROVIDER',
|
||||
'description' => 'This variable allows you to enable logging errors to 3rd party providers. This value is empty by default, to enable the logger set the value to one of \'sentry\', \'raygun\', \'appsignal\', \'logowl\'',
|
||||
'description' => 'This variable allows you to enable logging errors to 3rd party providers. This value is empty by default, to enable the logger set the value to one of \'sentry\', \'raygun\', \'appSignal\', \'logOwl\'',
|
||||
'introduction' => '0.12.0',
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
|
|
|
|||
|
|
@ -1763,11 +1763,12 @@ App::patch('/v1/account/status')
|
|||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_USER)
|
||||
->inject('requestTimestamp')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $events) {
|
||||
->action(function (?\DateTime $requestTimestamp, Request $request, Response $response, Document $user, Database $dbForProject, Event $events) {
|
||||
|
||||
$user->setAttribute('status', false);
|
||||
|
||||
|
|
@ -1781,6 +1782,12 @@ App::patch('/v1/account/status')
|
|||
$response->addHeader('X-Fallback-Cookies', \json_encode([]));
|
||||
}
|
||||
|
||||
$protocol = $request->getProtocol();
|
||||
$response
|
||||
->addCookie(Auth::$cookieName . '_legacy', '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null)
|
||||
->addCookie(Auth::$cookieName, '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite'))
|
||||
;
|
||||
|
||||
$response->dynamic($user, Response::MODEL_ACCOUNT);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -327,22 +327,22 @@ function updateAttribute(
|
|||
}
|
||||
|
||||
if ($type === Database::VAR_RELATIONSHIP) {
|
||||
$options = \array_merge($attribute->getAttribute('options', []), $options);
|
||||
$attribute->setAttribute('options', $options);
|
||||
$primaryDocumentOptions = \array_merge($attribute->getAttribute('options', []), $options);
|
||||
$attribute->setAttribute('options', $primaryDocumentOptions);
|
||||
|
||||
$dbForProject->updateRelationship(
|
||||
collection: $collectionId,
|
||||
id: $key,
|
||||
onDelete: $options['onDelete'],
|
||||
onDelete: $primaryDocumentOptions['onDelete'],
|
||||
);
|
||||
|
||||
if ($options['twoWay']) {
|
||||
$relatedCollection = $dbForProject->getDocument('database_' . $db->getInternalId(), $options['relatedCollection']);
|
||||
$relatedAttribute = $dbForProject->getDocument('attributes', $db->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $options['twoWayKey']);
|
||||
if ($primaryDocumentOptions['twoWay']) {
|
||||
$relatedCollection = $dbForProject->getDocument('database_' . $db->getInternalId(), $primaryDocumentOptions['relatedCollection']);
|
||||
|
||||
$relatedAttribute = $dbForProject->getDocument('attributes', $db->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $primaryDocumentOptions['twoWayKey']);
|
||||
$relatedOptions = \array_merge($relatedAttribute->getAttribute('options'), $options);
|
||||
$relatedAttribute->setAttribute('options', $relatedOptions);
|
||||
|
||||
$dbForProject->updateDocument('attributes', $db->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $options['twoWayKey'], $relatedAttribute);
|
||||
$dbForProject->updateDocument('attributes', $db->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $primaryDocumentOptions['twoWayKey'], $relatedAttribute);
|
||||
$dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $relatedCollection->getId());
|
||||
}
|
||||
} else {
|
||||
|
|
@ -384,11 +384,12 @@ App::post('/v1/databases')
|
|||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_DATABASE) // Model for database needs to be created
|
||||
->param('databaseId', '', new CustomId(), 'Unique 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), 'Collection name. Max length: 128 chars.')
|
||||
->param('name', '', new Text(128), 'Database name. Max length: 128 chars.')
|
||||
->param('enabled', true, new Boolean(), 'Is database enabled?', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $databaseId, string $name, Response $response, Database $dbForProject, Event $events) {
|
||||
->action(function (string $databaseId, string $name, bool $enabled, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$databaseId = $databaseId == 'unique()' ? ID::unique() : $databaseId;
|
||||
|
||||
|
|
@ -396,6 +397,7 @@ App::post('/v1/databases')
|
|||
$dbForProject->createDocument('databases', new Document([
|
||||
'$id' => $databaseId,
|
||||
'name' => $name,
|
||||
'enabled' => $enabled,
|
||||
'search' => implode(' ', [$databaseId, $name]),
|
||||
]));
|
||||
$database = $dbForProject->getDocument('databases', $databaseId);
|
||||
|
|
@ -507,7 +509,7 @@ App::get('/v1/databases/:databaseId')
|
|||
->inject('dbForProject')
|
||||
->action(function (string $databaseId, Response $response, Database $dbForProject) {
|
||||
|
||||
$database = $dbForProject->getDocument('databases', $databaseId);
|
||||
$database = $dbForProject->getDocument('databases', $databaseId);
|
||||
|
||||
if ($database->isEmpty()) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
|
|
@ -619,12 +621,13 @@ App::put('/v1/databases/:databaseId')
|
|||
->label('sdk.response.model', Response::MODEL_DATABASE)
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('name', null, new Text(128), 'Database name. Max length: 128 chars.')
|
||||
->param('enabled', true, new Boolean(), 'Is database enabled?', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $databaseId, string $name, Response $response, Database $dbForProject, Event $events) {
|
||||
->action(function (string $databaseId, string $name, bool $enabled, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$database = $dbForProject->getDocument('databases', $databaseId);
|
||||
$database = $dbForProject->getDocument('databases', $databaseId);
|
||||
|
||||
if ($database->isEmpty()) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
|
|
@ -633,6 +636,7 @@ App::put('/v1/databases/:databaseId')
|
|||
try {
|
||||
$database = $dbForProject->updateDocument('databases', $databaseId, $database
|
||||
->setAttribute('name', $name)
|
||||
->setAttribute('enabled', $enabled)
|
||||
->setAttribute('search', implode(' ', [$databaseId, $name])));
|
||||
} catch (AuthorizationException $exception) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
|
|
@ -714,14 +718,16 @@ App::post('/v1/databases/:databaseId/collections')
|
|||
->param('name', '', new Text(128), 'Collection name. Max length: 128 chars.')
|
||||
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](/docs/permissions).', true)
|
||||
->param('documentSecurity', false, new Boolean(true), 'Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](/docs/permissions).', true)
|
||||
->param('enabled', true, new Boolean(), 'Is collection enabled?', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('mode')
|
||||
->inject('events')
|
||||
->action(function (string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, Response $response, Database $dbForProject, Event $events) {
|
||||
->action(function (string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, bool $enabled, Response $response, Database $dbForProject, string $mode, Event $events) {
|
||||
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
|
||||
|
||||
if ($database->isEmpty()) {
|
||||
if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
@ -737,7 +743,7 @@ App::post('/v1/databases/:databaseId/collections')
|
|||
'databaseId' => $databaseId,
|
||||
'$permissions' => $permissions ?? [],
|
||||
'documentSecurity' => $documentSecurity,
|
||||
'enabled' => true,
|
||||
'enabled' => $enabled,
|
||||
'name' => $name,
|
||||
'search' => implode(' ', [$collectionId, $name]),
|
||||
]));
|
||||
|
|
@ -779,11 +785,12 @@ App::get('/v1/databases/:databaseId/collections')
|
|||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $databaseId, array $queries, string $search, Response $response, Database $dbForProject) {
|
||||
->inject('mode')
|
||||
->action(function (string $databaseId, array $queries, string $search, Response $response, Database $dbForProject, string $mode) {
|
||||
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
|
||||
|
||||
if ($database->isEmpty()) {
|
||||
if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
@ -834,11 +841,12 @@ App::get('/v1/databases/:databaseId/collections/:collectionId')
|
|||
->param('collectionId', '', new UID(), 'Collection ID.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $databaseId, string $collectionId, Response $response, Database $dbForProject) {
|
||||
->inject('mode')
|
||||
->action(function (string $databaseId, string $collectionId, Response $response, Database $dbForProject, string $mode) {
|
||||
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
|
||||
|
||||
if ($database->isEmpty()) {
|
||||
if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
@ -874,7 +882,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/logs')
|
|||
->inject('geodb')
|
||||
->action(function (string $databaseId, string $collectionId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
|
||||
|
||||
if ($database->isEmpty()) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
|
|
@ -972,12 +980,13 @@ App::put('/v1/databases/:databaseId/collections/:collectionId')
|
|||
->param('enabled', true, new Boolean(), 'Is collection enabled?', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('mode')
|
||||
->inject('events')
|
||||
->action(function (string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, bool $enabled, Response $response, Database $dbForProject, Event $events) {
|
||||
->action(function (string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, bool $enabled, Response $response, Database $dbForProject, string $mode, Event $events) {
|
||||
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
|
||||
|
||||
if ($database->isEmpty()) {
|
||||
if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
@ -1036,13 +1045,14 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId')
|
|||
->param('collectionId', '', new UID(), 'Collection ID.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('mode')
|
||||
->inject('events')
|
||||
->inject('deletes')
|
||||
->action(function (string $databaseId, string $collectionId, Response $response, Database $dbForProject, Event $events, Delete $deletes) {
|
||||
->action(function (string $databaseId, string $collectionId, Response $response, Database $dbForProject, string $mode, Event $events, Delete $deletes) {
|
||||
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
|
||||
|
||||
if ($database->isEmpty()) {
|
||||
if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
@ -1060,15 +1070,13 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId')
|
|||
|
||||
$deletes
|
||||
->setType(DELETE_TYPE_DOCUMENT)
|
||||
->setDocument($collection)
|
||||
;
|
||||
->setDocument($collection);
|
||||
|
||||
$events
|
||||
->setContext('database', $database)
|
||||
->setParam('databaseId', $databaseId)
|
||||
->setParam('collectionId', $collection->getId())
|
||||
->setPayload($response->output($collection, Response::MODEL_COLLECTION))
|
||||
;
|
||||
->setPayload($response->output($collection, Response::MODEL_COLLECTION));
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
|
|
@ -1593,7 +1601,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/relati
|
|||
Database $dbForProject,
|
||||
EventDatabase $database,
|
||||
Event $events
|
||||
) {
|
||||
) {
|
||||
$key ??= $relatedCollectionId;
|
||||
$twoWayKey ??= $collectionId;
|
||||
|
||||
|
|
@ -1653,7 +1661,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes')
|
|||
->inject('dbForProject')
|
||||
->action(function (string $databaseId, string $collectionId, Response $response, Database $dbForProject) {
|
||||
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
|
||||
|
||||
if ($database->isEmpty()) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
|
|
@ -1704,7 +1712,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes/:key')
|
|||
->inject('dbForProject')
|
||||
->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject) {
|
||||
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
|
||||
|
||||
if ($database->isEmpty()) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
|
|
@ -2177,7 +2185,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/:key/
|
|||
$events,
|
||||
type: Database::VAR_RELATIONSHIP,
|
||||
required: false,
|
||||
options : [
|
||||
options: [
|
||||
'onDelete' => $onDelete
|
||||
]
|
||||
);
|
||||
|
|
@ -2218,7 +2226,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key
|
|||
->inject('events')
|
||||
->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject, EventDatabase $database, Event $events) {
|
||||
|
||||
$db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
$db = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
|
||||
|
||||
if ($db->isEmpty()) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
|
|
@ -2271,8 +2279,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key
|
|||
->setType(DATABASE_TYPE_DELETE_ATTRIBUTE)
|
||||
->setCollection($collection)
|
||||
->setDatabase($db)
|
||||
->setDocument($attribute)
|
||||
;
|
||||
->setDocument($attribute);
|
||||
|
||||
// Select response model based on type and format
|
||||
$type = $attribute->getAttribute('type');
|
||||
|
|
@ -2300,8 +2307,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key
|
|||
->setParam('attributeId', $attribute->getId())
|
||||
->setContext('collection', $collection)
|
||||
->setContext('database', $db)
|
||||
->setPayload($response->output($attribute, $model))
|
||||
;
|
||||
->setPayload($response->output($attribute, $model));
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
|
|
@ -2335,7 +2341,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes')
|
|||
->inject('events')
|
||||
->action(function (string $databaseId, string $collectionId, string $key, string $type, array $attributes, array $orders, Response $response, Database $dbForProject, EventDatabase $database, Event $events) {
|
||||
|
||||
$db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
$db = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
|
||||
|
||||
if ($db->isEmpty()) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
|
|
@ -2358,7 +2364,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes')
|
|||
}
|
||||
|
||||
// Convert Document[] to array of attribute metadata
|
||||
$oldAttributes = \array_map(fn ($a) => $a->getArrayCopy(), $collection->getAttribute('attributes'));
|
||||
$oldAttributes = \array_map(fn($a) => $a->getArrayCopy(), $collection->getAttribute('attributes'));
|
||||
|
||||
$oldAttributes[] = [
|
||||
'key' => '$id',
|
||||
|
|
@ -2444,16 +2450,14 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes')
|
|||
->setType(DATABASE_TYPE_CREATE_INDEX)
|
||||
->setDatabase($db)
|
||||
->setCollection($collection)
|
||||
->setDocument($index)
|
||||
;
|
||||
->setDocument($index);
|
||||
|
||||
$events
|
||||
->setParam('databaseId', $databaseId)
|
||||
->setParam('collectionId', $collection->getId())
|
||||
->setParam('indexId', $index->getId())
|
||||
->setContext('collection', $collection)
|
||||
->setContext('database', $db)
|
||||
;
|
||||
->setContext('database', $db);
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
|
||||
|
|
@ -2480,7 +2484,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes')
|
|||
->inject('dbForProject')
|
||||
->action(function (string $databaseId, string $collectionId, Response $response, Database $dbForProject) {
|
||||
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
|
||||
|
||||
if ($database->isEmpty()) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
|
|
@ -2520,7 +2524,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes/:key')
|
|||
->inject('dbForProject')
|
||||
->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject) {
|
||||
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
|
||||
|
||||
if ($database->isEmpty()) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
|
|
@ -2571,7 +2575,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key')
|
|||
->inject('events')
|
||||
->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject, EventDatabase $database, Event $events) {
|
||||
|
||||
$db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
$db = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
|
||||
|
||||
if ($db->isEmpty()) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
|
|
@ -2599,8 +2603,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key')
|
|||
->setType(DATABASE_TYPE_DELETE_INDEX)
|
||||
->setDatabase($db)
|
||||
->setCollection($collection)
|
||||
->setDocument($index)
|
||||
;
|
||||
->setDocument($index);
|
||||
|
||||
$events
|
||||
->setParam('databaseId', $databaseId)
|
||||
|
|
@ -2608,8 +2611,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key')
|
|||
->setParam('indexId', $index->getId())
|
||||
->setContext('collection', $collection)
|
||||
->setContext('database', $db)
|
||||
->setPayload($response->output($index, Response::MODEL_INDEX))
|
||||
;
|
||||
->setPayload($response->output($index, Response::MODEL_INDEX));
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
|
|
@ -2621,7 +2623,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
|
|||
->label('event', 'databases.[databaseId].collections.[collectionId].documents.[documentId].create')
|
||||
->label('scope', 'documents.write')
|
||||
->label('audits.event', 'document.create')
|
||||
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
|
||||
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}/document/{response.$id}')
|
||||
->label('usage.metric', 'documents.{scope}.requests.create')
|
||||
->label('usage.params', ['databaseId:{request.databaseId}', 'collectionId:{request.collectionId}'])
|
||||
->label('abuse-key', 'ip:{ip},method:{method},url:{url},userId:{userId}')
|
||||
|
|
@ -2651,7 +2653,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
|
|||
$data = (\is_string($data)) ? \json_decode($data, true) : $data; // Cast to JSON array
|
||||
|
||||
if (empty($data)) {
|
||||
throw new Exception(Exception::DOCUMENT_MISSING_PAYLOAD);
|
||||
throw new Exception(Exception::DOCUMENT_MISSING_DATA);
|
||||
}
|
||||
|
||||
if (isset($data['$id'])) {
|
||||
|
|
@ -2660,7 +2662,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
|
|||
|
||||
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
|
||||
|
||||
if ($database->isEmpty()) {
|
||||
if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
@ -2735,7 +2737,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
|
|||
|
||||
$relationships = \array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
);
|
||||
|
||||
foreach ($relationships as $relationship) {
|
||||
|
|
@ -2814,7 +2816,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
|
|||
|
||||
$relationships = \array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
);
|
||||
|
||||
foreach ($relationships as $relationship) {
|
||||
|
|
@ -2847,8 +2849,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
|
|||
->setParam('collectionId', $collection->getId())
|
||||
->setParam('documentId', $document->getId())
|
||||
->setContext('collection', $collection)
|
||||
->setContext('database', $database)
|
||||
;
|
||||
->setContext('database', $database);
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
|
|
@ -2878,9 +2879,9 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
|
|||
->inject('mode')
|
||||
->action(function (string $databaseId, string $collectionId, array $queries, Response $response, Database $dbForProject, string $mode) {
|
||||
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
|
||||
|
||||
if ($database->isEmpty()) {
|
||||
if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
@ -2940,7 +2941,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
|
|||
|
||||
$relationships = \array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
);
|
||||
|
||||
foreach ($relationships as $relationship) {
|
||||
|
|
@ -2956,8 +2957,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
|
|||
}
|
||||
|
||||
$relatedCollectionId = $relationship->getAttribute('relatedCollection');
|
||||
$relatedCollection = Authorization::skip(fn() =>
|
||||
$dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId));
|
||||
$relatedCollection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId));
|
||||
|
||||
foreach ($relations as $index => $doc) {
|
||||
if ($doc instanceof Document) {
|
||||
|
|
@ -2977,7 +2977,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
|
|||
return true;
|
||||
};
|
||||
|
||||
// The linter is forcing this indentation
|
||||
// The linter is forcing this indentation
|
||||
foreach ($documents as $document) {
|
||||
$processDocument($collection, $document);
|
||||
}
|
||||
|
|
@ -3013,9 +3013,9 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen
|
|||
->inject('mode')
|
||||
->action(function (string $databaseId, string $collectionId, string $documentId, array $queries, Response $response, Database $dbForProject, string $mode) {
|
||||
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
|
||||
|
||||
if ($database->isEmpty()) {
|
||||
if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
@ -3053,7 +3053,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen
|
|||
|
||||
$relationships = \array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
);
|
||||
|
||||
foreach ($relationships as $relationship) {
|
||||
|
|
@ -3108,7 +3108,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen
|
|||
->inject('geodb')
|
||||
->action(function (string $databaseId, string $collectionId, string $documentId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
|
||||
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
|
||||
|
||||
if ($database->isEmpty()) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
|
|
@ -3225,9 +3225,9 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
|
|||
throw new Exception(Exception::DOCUMENT_MISSING_PAYLOAD);
|
||||
}
|
||||
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
|
||||
|
||||
if ($database->isEmpty()) {
|
||||
if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
@ -3304,7 +3304,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
|
|||
|
||||
$relationships = \array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
);
|
||||
|
||||
foreach ($relationships as $relationship) {
|
||||
|
|
@ -3372,7 +3372,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
|
|||
try {
|
||||
$document = $dbForProject->withRequestTimestamp(
|
||||
$requestTimestamp,
|
||||
fn () => $dbForProject->updateDocument(
|
||||
fn() => $dbForProject->updateDocument(
|
||||
'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(),
|
||||
$document->getId(),
|
||||
$newDocument
|
||||
|
|
@ -3393,7 +3393,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
|
|||
|
||||
$relationships = \array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
);
|
||||
|
||||
foreach ($relationships as $relationship) {
|
||||
|
|
@ -3426,8 +3426,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
|
|||
->setParam('collectionId', $collection->getId())
|
||||
->setParam('documentId', $document->getId())
|
||||
->setContext('collection', $collection)
|
||||
->setContext('database', $database)
|
||||
;
|
||||
->setContext('database', $database);
|
||||
|
||||
$response->dynamic($document, Response::MODEL_DOCUMENT);
|
||||
});
|
||||
|
|
@ -3464,9 +3463,9 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
|
|||
->inject('mode')
|
||||
->action(function (string $databaseId, string $collectionId, string $documentId, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Event $events, Delete $deletes, string $mode) {
|
||||
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
|
||||
|
||||
if ($database->isEmpty()) {
|
||||
if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
@ -3501,7 +3500,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
|
|||
|
||||
$relationships = \array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
);
|
||||
|
||||
foreach ($relationships as $relationship) {
|
||||
|
|
@ -3532,7 +3531,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
|
|||
|
||||
$checkPermissions($collection, $document);
|
||||
|
||||
Authorization::skip(fn () => $dbForProject->withRequestTimestamp($requestTimestamp, function () use ($dbForProject, $database, $collection, $documentId) {
|
||||
Authorization::skip(fn() => $dbForProject->withRequestTimestamp($requestTimestamp, function () use ($dbForProject, $database, $collection, $documentId) {
|
||||
try {
|
||||
$dbForProject->deleteDocument(
|
||||
'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(),
|
||||
|
|
@ -3555,7 +3554,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
|
|||
|
||||
$relationships = \array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
);
|
||||
|
||||
foreach ($relationships as $relationship) {
|
||||
|
|
@ -3585,8 +3584,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
|
|||
|
||||
$deletes
|
||||
->setType(DELETE_TYPE_AUDIT)
|
||||
->setDocument($document)
|
||||
;
|
||||
->setDocument($document);
|
||||
|
||||
$events
|
||||
->setParam('databaseId', $databaseId)
|
||||
|
|
@ -3594,8 +3592,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
|
|||
->setParam('documentId', $document->getId())
|
||||
->setContext('collection', $collection)
|
||||
->setContext('database', $database)
|
||||
->setPayload($response->output($document, Response::MODEL_DOCUMENT))
|
||||
;
|
||||
->setPayload($response->output($document, Response::MODEL_DOCUMENT));
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
|
|
@ -3700,16 +3697,16 @@ App::get('/v1/databases/usage')
|
|||
'databasesCount' => $stats['databases.$all.count.total'] ?? [],
|
||||
'documentsCount' => $stats['documents.$all.count.total'] ?? [],
|
||||
'collectionsCount' => $stats['collections.$all.count.total'] ?? [],
|
||||
'documentsCreate' => $stats['documents.$all.requests.create'] ?? [],
|
||||
'documentsRead' => $stats['documents.$all.requests.read'] ?? [],
|
||||
'documentsCreate' => $stats['documents.$all.requests.create'] ?? [],
|
||||
'documentsRead' => $stats['documents.$all.requests.read'] ?? [],
|
||||
'documentsUpdate' => $stats['documents.$all.requests.update'] ?? [],
|
||||
'documentsDelete' => $stats['documents.$all.requests.delete'] ?? [],
|
||||
'collectionsCreate' => $stats['collections.$all.requests.create'] ?? [],
|
||||
'collectionsRead' => $stats['collections.$all.requests.read'] ?? [],
|
||||
'collectionsRead' => $stats['collections.$all.requests.read'] ?? [],
|
||||
'collectionsUpdate' => $stats['collections.$all.requests.update'] ?? [],
|
||||
'collectionsDelete' => $stats['collections.$all.requests.delete'] ?? [],
|
||||
'databasesCreate' => $stats['databases.$all.requests.create'] ?? [],
|
||||
'databasesRead' => $stats['databases.$all.requests.read'] ?? [],
|
||||
'databasesRead' => $stats['databases.$all.requests.read'] ?? [],
|
||||
'databasesUpdate' => $stats['databases.$all.requests.update'] ?? [],
|
||||
'databasesDelete' => $stats['databases.$all.requests.delete'] ?? [],
|
||||
]);
|
||||
|
|
@ -3813,12 +3810,12 @@ App::get('/v1/databases/:databaseId/usage')
|
|||
'range' => $range,
|
||||
'collectionsCount' => $stats["collections.{$databaseId}.count.total"] ?? [],
|
||||
'collectionsCreate' => $stats["collections.{$databaseId}.requests.create"] ?? [],
|
||||
'collectionsRead' => $stats["collections.{$databaseId}.requests.read"] ?? [],
|
||||
'collectionsRead' => $stats["collections.{$databaseId}.requests.read"] ?? [],
|
||||
'collectionsUpdate' => $stats["collections.{$databaseId}.requests.update"] ?? [],
|
||||
'collectionsDelete' => $stats["collections.{$databaseId}.requests.delete"] ?? [],
|
||||
'documentsCount' => $stats["documents.{$databaseId}.count.total"] ?? [],
|
||||
'documentsCreate' => $stats["documents.{$databaseId}.requests.create"] ?? [],
|
||||
'documentsRead' => $stats["documents.{$databaseId}.requests.read"] ?? [],
|
||||
'documentsCreate' => $stats["documents.{$databaseId}.requests.create"] ?? [],
|
||||
'documentsRead' => $stats["documents.{$databaseId}.requests.read"] ?? [],
|
||||
'documentsUpdate' => $stats["documents.{$databaseId}.requests.update"] ?? [],
|
||||
'documentsDelete' => $stats["documents.{$databaseId}.requests.delete"] ?? [],
|
||||
]);
|
||||
|
|
@ -3928,8 +3925,8 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/usage')
|
|||
'documentsCount' => $stats["documents.{$databaseId}/{$collectionId}.count.total"] ?? [],
|
||||
'documentsCreate' => $stats["documents.{$databaseId}/{$collectionId}.requests.create"] ?? [],
|
||||
'documentsRead' => $stats["documents.{$databaseId}/{$collectionId}.requests.read"] ?? [],
|
||||
'documentsUpdate' => $stats["documents.{$databaseId}/{$collectionId}.requests.update"] ?? [],
|
||||
'documentsDelete' => $stats["documents.{$databaseId}/{$collectionId}.requests.delete" ?? []]
|
||||
'documentsUpdate' => $stats["documents.{$databaseId}/{$collectionId}.requests.update"] ?? [],
|
||||
'documentsDelete' => $stats["documents.{$databaseId}/{$collectionId}.requests.delete" ?? []]
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ use Utopia\Domains\Domain;
|
|||
use Utopia\Registry\Registry;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Projects;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Hostname;
|
||||
|
|
@ -91,38 +92,43 @@ App::post('/v1/projects')
|
|||
throw new Exception(Exception::PROJECT_RESERVED_PROJECT, "'console' is a reserved project.");
|
||||
}
|
||||
|
||||
$project = $dbForConsole->createDocument('projects', new Document([
|
||||
'$id' => $projectId,
|
||||
'$permissions' => [
|
||||
Permission::read(Role::team(ID::custom($teamId))),
|
||||
Permission::update(Role::team(ID::custom($teamId), 'owner')),
|
||||
Permission::update(Role::team(ID::custom($teamId), 'developer')),
|
||||
Permission::delete(Role::team(ID::custom($teamId), 'owner')),
|
||||
Permission::delete(Role::team(ID::custom($teamId), 'developer')),
|
||||
],
|
||||
'name' => $name,
|
||||
'teamInternalId' => $team->getInternalId(),
|
||||
'teamId' => $team->getId(),
|
||||
'region' => $region,
|
||||
'description' => $description,
|
||||
'logo' => $logo,
|
||||
'url' => $url,
|
||||
'version' => APP_VERSION_STABLE,
|
||||
'legalName' => $legalName,
|
||||
'legalCountry' => $legalCountry,
|
||||
'legalState' => $legalState,
|
||||
'legalCity' => $legalCity,
|
||||
'legalAddress' => $legalAddress,
|
||||
'legalTaxId' => ID::custom($legalTaxId),
|
||||
'services' => new stdClass(),
|
||||
'platforms' => null,
|
||||
'authProviders' => [],
|
||||
'webhooks' => null,
|
||||
'keys' => null,
|
||||
'domains' => null,
|
||||
'auths' => $auths,
|
||||
'search' => implode(' ', [$projectId, $name]),
|
||||
]));
|
||||
try {
|
||||
$project = $dbForConsole->createDocument('projects', new Document([
|
||||
'$id' => $projectId,
|
||||
'$permissions' => [
|
||||
Permission::read(Role::team(ID::custom($teamId))),
|
||||
Permission::update(Role::team(ID::custom($teamId), 'owner')),
|
||||
Permission::update(Role::team(ID::custom($teamId), 'developer')),
|
||||
Permission::delete(Role::team(ID::custom($teamId), 'owner')),
|
||||
Permission::delete(Role::team(ID::custom($teamId), 'developer')),
|
||||
],
|
||||
'name' => $name,
|
||||
'teamInternalId' => $team->getInternalId(),
|
||||
'teamId' => $team->getId(),
|
||||
'region' => $region,
|
||||
'description' => $description,
|
||||
'logo' => $logo,
|
||||
'url' => $url,
|
||||
'version' => APP_VERSION_STABLE,
|
||||
'legalName' => $legalName,
|
||||
'legalCountry' => $legalCountry,
|
||||
'legalState' => $legalState,
|
||||
'legalCity' => $legalCity,
|
||||
'legalAddress' => $legalAddress,
|
||||
'legalTaxId' => ID::custom($legalTaxId),
|
||||
'services' => new stdClass(),
|
||||
'platforms' => null,
|
||||
'authProviders' => [],
|
||||
'webhooks' => null,
|
||||
'keys' => null,
|
||||
'domains' => null,
|
||||
'auths' => $auths,
|
||||
'search' => implode(' ', [$projectId, $name]),
|
||||
]));
|
||||
} catch (Duplicate $th) {
|
||||
throw new Exception(Exception::PROJECT_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
/** @var array $collections */
|
||||
$collections = Config::getParam('collections', []);
|
||||
|
||||
|
|
@ -678,17 +684,11 @@ App::delete('/v1/projects/:projectId')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
|
||||
->label('sdk.response.model', Response::MODEL_NONE)
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('password', '', new Password(), 'Your user password for confirmation. Must be at least 8 chars.')
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->inject('dbForConsole')
|
||||
->inject('deletes')
|
||||
->action(function (string $projectId, string $password, Response $response, Document $user, Database $dbForConsole, Delete $deletes) {
|
||||
|
||||
if (!Auth::passwordVerify($password, $user->getAttribute('password'), $user->getAttribute('hash'), $user->getAttribute('hashOptions'))) { // Double check user password
|
||||
throw new Exception(Exception::USER_INVALID_CREDENTIALS);
|
||||
}
|
||||
|
||||
->action(function (string $projectId, Response $response, Document $user, Database $dbForConsole, Delete $deletes) {
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
|
|
|
|||
|
|
@ -515,6 +515,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
|||
}
|
||||
|
||||
$mimeType = $deviceFiles->getFileMimeType($path); // Get mime-type before compression and encryption
|
||||
$fileHash = $deviceFiles->getFileHash($path); // Get file hash before compression and encryption
|
||||
$data = '';
|
||||
// Compression
|
||||
$algorithm = $bucket->getAttribute('compression', COMPRESSION_TYPE_NONE);
|
||||
|
|
@ -548,7 +549,6 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
|||
}
|
||||
|
||||
$sizeActual = $deviceFiles->getFileSize($path);
|
||||
$fileHash = $deviceFiles->getFileHash($path);
|
||||
|
||||
$openSSLVersion = null;
|
||||
$openSSLCipher = null;
|
||||
|
|
|
|||
|
|
@ -224,9 +224,9 @@ $cli
|
|||
}
|
||||
}
|
||||
|
||||
Console::log("Running \"docker compose -f {$path}/docker-compose.yml up -d --remove-orphans --renew-anon-volumes\"");
|
||||
Console::log("Running \"docker compose up -d --remove-orphans --renew-anon-volumes\"");
|
||||
|
||||
$exit = Console::execute("${env} docker compose -f {$path}/docker-compose.yml up -d --remove-orphans --renew-anon-volumes", '', $stdout, $stderr);
|
||||
$exit = Console::execute("${env} docker compose --project-directory {$path} up -d --remove-orphans --renew-anon-volumes", '', $stdout, $stderr);
|
||||
|
||||
if ($exit !== 0) {
|
||||
$message = 'Failed to install Appwrite dockers';
|
||||
|
|
|
|||
|
|
@ -134,6 +134,7 @@ class Exception extends \Exception
|
|||
/** Documents */
|
||||
public const DOCUMENT_NOT_FOUND = 'document_not_found';
|
||||
public const DOCUMENT_INVALID_STRUCTURE = 'document_invalid_structure';
|
||||
public const DOCUMENT_MISSING_DATA = 'document_missing_data';
|
||||
public const DOCUMENT_MISSING_PAYLOAD = 'document_missing_payload';
|
||||
public const DOCUMENT_ALREADY_EXISTS = 'document_already_exists';
|
||||
public const DOCUMENT_UPDATE_CONFLICT = 'document_update_conflict';
|
||||
|
|
@ -160,6 +161,7 @@ class Exception extends \Exception
|
|||
public const PROJECT_UNKNOWN = 'project_unknown';
|
||||
public const PROJECT_PROVIDER_DISABLED = 'project_provider_disabled';
|
||||
public const PROJECT_PROVIDER_UNSUPPORTED = 'project_provider_unsupported';
|
||||
public const PROJECT_ALREADY_EXISTS = 'project_already_exists';
|
||||
public const PROJECT_INVALID_SUCCESS_URL = 'project_invalid_success_url';
|
||||
public const PROJECT_INVALID_FAILURE_URL = 'project_invalid_failure_url';
|
||||
public const PROJECT_RESERVED_PROJECT = 'project_reserved_project';
|
||||
|
|
|
|||
|
|
@ -34,6 +34,12 @@ class Database extends Model
|
|||
'default' => '',
|
||||
'example' => self::TYPE_DATETIME_EXAMPLE,
|
||||
])
|
||||
->addRule('enabled', [
|
||||
'type' => self::TYPE_BOOLEAN,
|
||||
'description' => 'Database enabled.',
|
||||
'default' => true,
|
||||
'example' => false,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -225,6 +225,8 @@ class AccountCustomClientTest extends Scope
|
|||
]);
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
$this->assertStringContainsString('a_session_' . $this->getProject()['$id'] . '=deleted', $response['headers']['set-cookie']);
|
||||
$this->assertEquals('[]', $response['headers']['x-fallback-cookies']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
|
|
|
|||
|
|
@ -20,13 +20,13 @@ class DatabasesConsoleClientTest extends Scope
|
|||
$database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
], $this->getHeaders()), [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'invalidDocumentDatabase',
|
||||
]);
|
||||
$this->assertEquals(201, $database['headers']['status-code']);
|
||||
$this->assertEquals('invalidDocumentDatabase', $database['body']['name']);
|
||||
$this->assertTrue($database['body']['enabled']);
|
||||
|
||||
$databaseId = $database['body']['$id'];
|
||||
/**
|
||||
|
|
@ -50,7 +50,129 @@ class DatabasesConsoleClientTest extends Scope
|
|||
$this->assertEquals(201, $movies['headers']['status-code']);
|
||||
$this->assertEquals($movies['body']['name'], 'Movies');
|
||||
|
||||
return ['moviesId' => $movies['body']['$id'], 'databaseId' => $databaseId];
|
||||
/**
|
||||
* Test When database is disabled but can still create collections
|
||||
*/
|
||||
$database = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'invalidDocumentDatabase Updated',
|
||||
'enabled' => false,
|
||||
]);
|
||||
|
||||
$this->assertFalse($database['body']['enabled']);
|
||||
|
||||
$tvShows = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'collectionId' => ID::unique(),
|
||||
'name' => 'TvShows',
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::create(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
'documentSecurity' => true,
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $tvShows['headers']['status-code']);
|
||||
$this->assertEquals($tvShows['body']['name'], 'TvShows');
|
||||
|
||||
return ['moviesId' => $movies['body']['$id'], 'databaseId' => $databaseId, 'tvShowsId' => $tvShows['body']['$id']];
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateCollection
|
||||
* @param array $data
|
||||
*/
|
||||
public function testListCollection(array $data)
|
||||
{
|
||||
/**
|
||||
* Test When database is disabled but can still call list collections
|
||||
*/
|
||||
$databaseId = $data['databaseId'];
|
||||
|
||||
$collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $collections['headers']['status-code']);
|
||||
$this->assertEquals(2, $collections['body']['total']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateCollection
|
||||
* @param array $data
|
||||
*/
|
||||
public function testGetCollection(array $data)
|
||||
{
|
||||
$databaseId = $data['databaseId'];
|
||||
$moviesCollectionId = $data['moviesId'];
|
||||
|
||||
/**
|
||||
* Test When database is disabled but can still call get collection
|
||||
*/
|
||||
$collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $moviesCollectionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $collection['headers']['status-code']);
|
||||
$this->assertEquals('Movies', $collection['body']['name']);
|
||||
$this->assertEquals($moviesCollectionId, $collection['body']['$id']);
|
||||
$this->assertTrue($collection['body']['enabled']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateCollection
|
||||
* @param array $data
|
||||
*/
|
||||
public function testUpdateCollection(array $data)
|
||||
{
|
||||
$databaseId = $data['databaseId'];
|
||||
$moviesCollectionId = $data['moviesId'];
|
||||
|
||||
/**
|
||||
* Test When database is disabled but can still call update collection
|
||||
*/
|
||||
$collection = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $moviesCollectionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'Movies Updated',
|
||||
'enabled' => false
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $collection['headers']['status-code']);
|
||||
$this->assertEquals('Movies Updated', $collection['body']['name']);
|
||||
$this->assertEquals($moviesCollectionId, $collection['body']['$id']);
|
||||
$this->assertFalse($collection['body']['enabled']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateCollection
|
||||
* @param array $data
|
||||
*/
|
||||
public function testDeleteCollection(array $data)
|
||||
{
|
||||
$databaseId = $data['databaseId'];
|
||||
$tvShowsId = $data['tvShowsId'];
|
||||
|
||||
/**
|
||||
* Test When database is disabled but can still call Delete collection
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $tvShowsId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(204, $response['headers']['status-code']);
|
||||
$this->assertEquals($response['body'], "");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -225,4 +225,95 @@ class DatabasesCustomClientTest extends Scope
|
|||
|
||||
return [];
|
||||
}
|
||||
|
||||
public function testUpdateTwoWayRelationship(): void
|
||||
{
|
||||
|
||||
$database = $this->client->call(Client::METHOD_POST, '/databases', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'Test Database'
|
||||
]);
|
||||
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
|
||||
// Creating collection 1
|
||||
$collection1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'collectionId' => ID::unique(),
|
||||
'name' => 'level1',
|
||||
'documentSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::create(Role::user($this->getUser()['$id'])),
|
||||
Permission::read(Role::user($this->getUser()['$id'])),
|
||||
Permission::update(Role::user($this->getUser()['$id'])),
|
||||
Permission::delete(Role::user($this->getUser()['$id'])),
|
||||
]
|
||||
]);
|
||||
|
||||
// Creating collection 2
|
||||
$collection2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'collectionId' => ID::unique(),
|
||||
'name' => 'level2',
|
||||
'documentSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::create(Role::user($this->getUser()['$id'])),
|
||||
Permission::read(Role::user($this->getUser()['$id'])),
|
||||
Permission::update(Role::user($this->getUser()['$id'])),
|
||||
Permission::delete(Role::user($this->getUser()['$id'])),
|
||||
]
|
||||
]);
|
||||
|
||||
\sleep(2);
|
||||
|
||||
// Creating two way relationship between collection 1 and collection 2 from collection 1
|
||||
$relation = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'] . '/attributes/relationship', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'relatedCollectionId' => $collection2['body']['$id'],
|
||||
'type' => 'oneToMany',
|
||||
'twoWay' => true,
|
||||
'onDelete' => 'cascade',
|
||||
'key' => $collection2['body']['$id'],
|
||||
'twoWayKey' => $collection1['body']['$id']
|
||||
]);
|
||||
|
||||
\sleep(3);
|
||||
|
||||
// Update relation from collection 2 to on delete restrict
|
||||
$this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collection2['body']['$id'] . '/attributes/' . $collection1['body']['$id'] . '/relationship', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'onDelete' => 'restrict',
|
||||
]);
|
||||
|
||||
// Fetching attributes after updating relation to compare
|
||||
$collection1Attributes = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collection1['body']['$id'], [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]);
|
||||
|
||||
$collection1RelationAttribute = $collection1Attributes['body']['attributes'][0];
|
||||
|
||||
$this->assertEquals($relation['body']['side'], $collection1RelationAttribute['side']);
|
||||
$this->assertEquals($relation['body']['twoWayKey'], $collection1RelationAttribute['twoWayKey']);
|
||||
$this->assertEquals($relation['body']['relatedCollection'], $collection1RelationAttribute['relatedCollection']);
|
||||
$this->assertEquals('restrict', $collection1RelationAttribute['onDelete']);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'databaseId' => ID::custom('first'),
|
||||
'name' => 'Test 1',
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $test1['headers']['status-code']);
|
||||
$this->assertEquals('Test 1', $test1['body']['name']);
|
||||
|
||||
|
|
@ -56,7 +57,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [ 'limit(1)' ],
|
||||
'queries' => ['limit(1)'],
|
||||
]);
|
||||
$this->assertEquals(200, $databases['headers']['status-code']);
|
||||
$this->assertCount(1, $databases['body']['databases']);
|
||||
|
|
@ -65,7 +66,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [ 'offset(1)' ],
|
||||
'queries' => ['offset(1)'],
|
||||
]);
|
||||
$this->assertEquals(200, $databases['headers']['status-code']);
|
||||
$this->assertCount(1, $databases['body']['databases']);
|
||||
|
|
@ -74,7 +75,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [ 'equal("name", ["Test 1", "Test 2"])' ],
|
||||
'queries' => ['equal("name", ["Test 1", "Test 2"])'],
|
||||
]);
|
||||
$this->assertEquals(200, $databases['headers']['status-code']);
|
||||
$this->assertCount(2, $databases['body']['databases']);
|
||||
|
|
@ -83,7 +84,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [ 'equal("name", "Test 2")' ],
|
||||
'queries' => ['equal("name", "Test 2")'],
|
||||
]);
|
||||
$this->assertEquals(200, $databases['headers']['status-code']);
|
||||
$this->assertCount(1, $databases['body']['databases']);
|
||||
|
|
@ -92,7 +93,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [ 'equal("$id", "first")' ],
|
||||
'queries' => ['equal("$id", "first")'],
|
||||
]);
|
||||
$this->assertEquals(200, $databases['headers']['status-code']);
|
||||
$this->assertCount(1, $databases['body']['databases']);
|
||||
|
|
@ -104,7 +105,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [ 'orderDesc("")' ],
|
||||
'queries' => ['orderDesc("")'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(2, $databases['body']['total']);
|
||||
|
|
@ -123,7 +124,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [ 'cursorAfter("' . $base['body']['databases'][0]['$id'] . '")' ],
|
||||
'queries' => ['cursorAfter("' . $base['body']['databases'][0]['$id'] . '")'],
|
||||
]);
|
||||
|
||||
$this->assertCount(1, $databases['body']['databases']);
|
||||
|
|
@ -133,7 +134,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [ 'cursorAfter("' . $base['body']['databases'][1]['$id'] . '")' ],
|
||||
'queries' => ['cursorAfter("' . $base['body']['databases'][1]['$id'] . '")'],
|
||||
]);
|
||||
|
||||
$this->assertCount(0, $databases['body']['databases']);
|
||||
|
|
@ -151,7 +152,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [ 'cursorBefore("' . $base['body']['databases'][1]['$id'] . '")' ],
|
||||
'queries' => ['cursorBefore("' . $base['body']['databases'][1]['$id'] . '")'],
|
||||
]);
|
||||
|
||||
$this->assertCount(1, $databases['body']['databases']);
|
||||
|
|
@ -161,7 +162,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [ 'cursorBefore("' . $base['body']['databases'][0]['$id'] . '")' ],
|
||||
'queries' => ['cursorBefore("' . $base['body']['databases'][0]['$id'] . '")'],
|
||||
]);
|
||||
|
||||
$this->assertCount(0, $databases['body']['databases']);
|
||||
|
|
@ -207,7 +208,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [ 'cursorAfter("unknown")' ],
|
||||
'queries' => ['cursorAfter("unknown")'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
|
@ -244,10 +245,44 @@ class DatabasesCustomServerTest extends Scope
|
|||
$this->assertEquals(200, $database['headers']['status-code']);
|
||||
$this->assertEquals($databaseId, $database['body']['$id']);
|
||||
$this->assertEquals('Test 1', $database['body']['name']);
|
||||
|
||||
$this->assertEquals(true, $database['body']['enabled']);
|
||||
return ['databaseId' => $database['body']['$id']];
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testListDatabases
|
||||
*/
|
||||
public function testUpdateDatabase(array $data)
|
||||
{
|
||||
$databaseId = $data['databaseId'];
|
||||
|
||||
$database = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'name' => 'Test 1 Updated',
|
||||
'enabled' => false,
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $database['headers']['status-code']);
|
||||
$this->assertEquals('Test 1 Updated', $database['body']['name']);
|
||||
$this->assertFalse($database['body']['enabled']);
|
||||
|
||||
// Now update the database without the passing the enabled parameter
|
||||
$database = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'name' => 'Test 1'
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $database['headers']['status-code']);
|
||||
$this->assertEquals('Test 1', $database['body']['name']);
|
||||
$this->assertTrue($database['body']['enabled']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testListDatabases
|
||||
*/
|
||||
|
|
@ -273,7 +308,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
}
|
||||
|
||||
public function testListCollections()
|
||||
public function testListCollections(): array
|
||||
{
|
||||
$database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
|
@ -285,6 +320,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
]);
|
||||
$this->assertEquals(201, $database['headers']['status-code']);
|
||||
$this->assertEquals('invalidDocumentDatabase', $database['body']['name']);
|
||||
$this->assertTrue($database['body']['enabled']);
|
||||
|
||||
$databaseId = $database['body']['$id'];
|
||||
/**
|
||||
|
|
@ -329,7 +365,9 @@ class DatabasesCustomServerTest extends Scope
|
|||
|
||||
$this->assertEquals(2, $collections['body']['total']);
|
||||
$this->assertEquals($test1['body']['$id'], $collections['body']['collections'][0]['$id']);
|
||||
$this->assertEquals($test1['body']['enabled'], $collections['body']['collections'][0]['enabled']);
|
||||
$this->assertEquals($test2['body']['$id'], $collections['body']['collections'][1]['$id']);
|
||||
$this->assertEquals($test1['body']['enabled'], $collections['body']['collections'][0]['enabled']);
|
||||
|
||||
$base = array_reverse($collections['body']['collections']);
|
||||
|
||||
|
|
@ -337,7 +375,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [ 'limit(1)' ]
|
||||
'queries' => ['limit(1)']
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $collections['headers']['status-code']);
|
||||
|
|
@ -347,7 +385,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [ 'offset(1)' ]
|
||||
'queries' => ['offset(1)']
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $collections['headers']['status-code']);
|
||||
|
|
@ -357,7 +395,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [ 'equal("enabled", true)' ]
|
||||
'queries' => ['equal("enabled", true)']
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $collections['headers']['status-code']);
|
||||
|
|
@ -367,7 +405,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [ 'equal("enabled", false)' ]
|
||||
'queries' => ['equal("enabled", false)']
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $collections['headers']['status-code']);
|
||||
|
|
@ -380,7 +418,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [ 'orderDesc("")' ],
|
||||
'queries' => ['orderDesc("")'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(2, $collections['body']['total']);
|
||||
|
|
@ -399,7 +437,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [ 'cursorAfter("' . $base['body']['collections'][0]['$id'] . '")' ],
|
||||
'queries' => ['cursorAfter("' . $base['body']['collections'][0]['$id'] . '")'],
|
||||
]);
|
||||
|
||||
$this->assertCount(1, $collections['body']['collections']);
|
||||
|
|
@ -409,7 +447,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [ 'cursorAfter("' . $base['body']['collections'][1]['$id'] . '")' ],
|
||||
'queries' => ['cursorAfter("' . $base['body']['collections'][1]['$id'] . '")'],
|
||||
]);
|
||||
|
||||
$this->assertCount(0, $collections['body']['collections']);
|
||||
|
|
@ -427,7 +465,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [ 'cursorBefore("' . $base['body']['collections'][1]['$id'] . '")' ],
|
||||
'queries' => ['cursorBefore("' . $base['body']['collections'][1]['$id'] . '")'],
|
||||
]);
|
||||
|
||||
$this->assertCount(1, $collections['body']['collections']);
|
||||
|
|
@ -437,7 +475,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [ 'cursorBefore("' . $base['body']['collections'][0]['$id'] . '")' ],
|
||||
'queries' => ['cursorBefore("' . $base['body']['collections'][0]['$id'] . '")'],
|
||||
]);
|
||||
|
||||
$this->assertCount(0, $collections['body']['collections']);
|
||||
|
|
@ -483,7 +521,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [ 'cursorAfter("unknown")' ],
|
||||
'queries' => ['cursorAfter("unknown")'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
|
@ -506,6 +544,53 @@ class DatabasesCustomServerTest extends Scope
|
|||
]);
|
||||
|
||||
$this->assertEquals(409, $response['headers']['status-code']);
|
||||
return [
|
||||
'databaseId' => $databaseId,
|
||||
'collectionId' => $test1['body']['$id'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testListCollections
|
||||
*/
|
||||
public function testGetCollection(array $data): void
|
||||
{
|
||||
$databaseId = $data['databaseId'];
|
||||
$collectionId = $data['collectionId'];
|
||||
|
||||
$collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $collection['headers']['status-code']);
|
||||
$this->assertEquals('Test 1', $collection['body']['name']);
|
||||
$this->assertEquals('first', $collection['body']['$id']);
|
||||
$this->assertTrue($collection['body']['enabled']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testListCollections
|
||||
*/
|
||||
public function testUpdateCollection(array $data)
|
||||
{
|
||||
$databaseId = $data['databaseId'];
|
||||
$collectionId = $data['collectionId'];
|
||||
|
||||
$collection = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'name' => 'Test 1 Updated',
|
||||
'enabled' => false
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $collection['headers']['status-code']);
|
||||
$this->assertEquals('Test 1 Updated', $collection['body']['name']);
|
||||
$this->assertEquals('first', $collection['body']['$id']);
|
||||
$this->assertFalse($collection['body']['enabled']);
|
||||
}
|
||||
|
||||
public function testDeleteAttribute(): array
|
||||
|
|
@ -589,7 +674,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'data' => [
|
||||
'firstName' => 'lorem',
|
||||
'lastName' => 'ipsum',
|
||||
'unneeded' => 'dolor'
|
||||
'unneeded' => 'dolor'
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
|
|
@ -1432,7 +1517,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null;
|
||||
$attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null;
|
||||
$this->assertNotNull($attribute);
|
||||
$this->assertFalse($attribute['required']);
|
||||
$this->assertEquals('lorem', $attribute['default']);
|
||||
|
|
@ -1574,7 +1659,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null;
|
||||
$attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null;
|
||||
$this->assertNotNull($attribute);
|
||||
$this->assertFalse($attribute['required']);
|
||||
$this->assertEquals('torsten@appwrite.io', $attribute['default']);
|
||||
|
|
@ -1717,7 +1802,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null;
|
||||
$attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null;
|
||||
$this->assertNotNull($attribute);
|
||||
$this->assertFalse($attribute['required']);
|
||||
$this->assertEquals('127.0.0.1', $attribute['default']);
|
||||
|
|
@ -1859,7 +1944,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null;
|
||||
$attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null;
|
||||
$this->assertNotNull($attribute);
|
||||
$this->assertFalse($attribute['required']);
|
||||
$this->assertEquals('http://appwrite.io', $attribute['default']);
|
||||
|
|
@ -2005,7 +2090,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null;
|
||||
$attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null;
|
||||
$this->assertNotNull($attribute);
|
||||
$this->assertFalse($attribute['required']);
|
||||
$this->assertEquals(123, $attribute['default']);
|
||||
|
|
@ -2268,7 +2353,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null;
|
||||
$attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null;
|
||||
$this->assertNotNull($attribute);
|
||||
$this->assertFalse($attribute['required']);
|
||||
$this->assertEquals(123.456, $attribute['default']);
|
||||
|
|
@ -2527,7 +2612,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null;
|
||||
$attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null;
|
||||
$this->assertNotNull($attribute);
|
||||
$this->assertFalse($attribute['required']);
|
||||
$this->assertEquals(true, $attribute['default']);
|
||||
|
|
@ -2669,7 +2754,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null;
|
||||
$attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null;
|
||||
$this->assertNotNull($attribute);
|
||||
$this->assertFalse($attribute['required']);
|
||||
$this->assertEquals('1975-06-12 14:12:55+02:00', $attribute['default']);
|
||||
|
|
@ -2816,7 +2901,7 @@ class DatabasesCustomServerTest extends Scope
|
|||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$attribute = array_values(array_filter($new['body']['attributes'], fn (array $a) => $a['key'] === $key))[0] ?? null;
|
||||
$attribute = array_values(array_filter($new['body']['attributes'], fn(array $a) => $a['key'] === $key))[0] ?? null;
|
||||
$this->assertNotNull($attribute);
|
||||
$this->assertFalse($attribute['required']);
|
||||
$this->assertEquals('lorem', $attribute['default']);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace Tests\E2E\Services\Projects;
|
||||
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\ProjectConsole;
|
||||
use Tests\E2E\Scopes\SideClient;
|
||||
|
|
@ -98,7 +99,37 @@ class ProjectsConsoleClientTest extends Scope
|
|||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
return ['projectId' => $projectId];
|
||||
return [
|
||||
'projectId' => $projectId,
|
||||
'teamId' => $team['body']['$id']
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateProject
|
||||
*/
|
||||
public function testCreateDuplicateProject($data)
|
||||
{
|
||||
$teamId = $data['teamId'] ?? '';
|
||||
$projectId = $data['projectId'] ?? '';
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_POST, '/projects', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'projectId' => $projectId,
|
||||
'name' => 'Project Duplicate',
|
||||
'teamId' => $teamId,
|
||||
'region' => 'default'
|
||||
]);
|
||||
|
||||
$this->assertEquals(409, $response['headers']['status-code']);
|
||||
$this->assertEquals(409, $response['body']['code']);
|
||||
$this->assertEquals(Exception::PROJECT_ALREADY_EXISTS, $response['body']['type']);
|
||||
$this->assertEquals('Project with the requested ID already exists.', $response['body']['message']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2981,15 +3012,13 @@ class ProjectsConsoleClientTest extends Scope
|
|||
|
||||
$this->assertEquals(200, $project['headers']['status-code']);
|
||||
|
||||
// Delete team
|
||||
$team = $this->client->call(Client::METHOD_DELETE, '/projects/' . $projectId, array_merge([
|
||||
// Delete Project
|
||||
$project = $this->client->call(Client::METHOD_DELETE, '/projects/' . $projectId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'password' => 'password'
|
||||
]);
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(204, $team['headers']['status-code']);
|
||||
$this->assertEquals(204, $project['headers']['status-code']);
|
||||
|
||||
// Ensure I can get team but not a project
|
||||
$team = $this->client->call(Client::METHOD_GET, '/teams/' . $teamId, array_merge([
|
||||
|
|
|
|||
|
|
@ -57,8 +57,7 @@ trait StorageBase
|
|||
$this->assertEquals('logo.png', $file['body']['name']);
|
||||
$this->assertEquals('image/png', $file['body']['mimeType']);
|
||||
$this->assertEquals(47218, $file['body']['sizeOriginal']);
|
||||
$this->assertTrue(md5_file(realpath(__DIR__ . '/../../../resources/logo.png')) != $file['body']['signature']); // should validate that the file is encrypted
|
||||
|
||||
$this->assertTrue(md5_file(realpath(__DIR__ . '/../../../resources/logo.png')) == $file['body']['signature']);
|
||||
/**
|
||||
* Test for Large File above 20MB
|
||||
* This should also validate the test for when Bucket encryption
|
||||
|
|
@ -289,7 +288,7 @@ trait StorageBase
|
|||
$this->assertEquals('logo.png', $file['body']['name']);
|
||||
$this->assertEquals('image/png', $file['body']['mimeType']);
|
||||
$this->assertEquals(47218, $file['body']['sizeOriginal']);
|
||||
$this->assertTrue(md5_file(realpath(__DIR__ . '/../../../resources/logo.png')) != $file['body']['signature']); // should validate that the file is encrypted
|
||||
$this->assertTrue(md5_file(realpath(__DIR__ . '/../../../resources/logo.png')) == $file['body']['signature']);
|
||||
|
||||
return ['bucketId' => $bucketId];
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue