mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Merge branch 'main' into 'fix-flutter-web-env'.
This commit is contained in:
@@ -4490,6 +4490,29 @@
|
||||
}
|
||||
],
|
||||
"description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
|
||||
},
|
||||
{
|
||||
"name": "createDocuments",
|
||||
"auth": {
|
||||
"Key": []
|
||||
},
|
||||
"parameters": [
|
||||
"databaseId",
|
||||
"collectionId",
|
||||
"documents"
|
||||
],
|
||||
"required": [
|
||||
"databaseId",
|
||||
"collectionId",
|
||||
"documents"
|
||||
],
|
||||
"responses": [
|
||||
{
|
||||
"code": 201,
|
||||
"model": "#\/components\/schemas\/documentList"
|
||||
}
|
||||
],
|
||||
"description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
|
||||
}
|
||||
],
|
||||
"auth": {
|
||||
|
||||
@@ -30695,7 +30695,7 @@
|
||||
"tags": [
|
||||
"tokens"
|
||||
],
|
||||
"description": "Create a new token. A token is linked to a file. Token can be passed as a header or request get parameter.",
|
||||
"description": "Create a new token. A token is linked to a file. Token can be passed as a request URL search parameter.",
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "ResourceToken",
|
||||
@@ -30716,7 +30716,7 @@
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
"demo": "tokens\/create-file-token.md",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new token. A token is linked to a file. Token can be passed as a header or request get parameter.",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new token. A token is linked to a file. Token can be passed as a request URL search parameter.",
|
||||
"rate-limit": 60,
|
||||
"rate-time": 60,
|
||||
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
|
||||
|
||||
@@ -21777,7 +21777,7 @@
|
||||
"tags": [
|
||||
"tokens"
|
||||
],
|
||||
"description": "Create a new token. A token is linked to a file. Token can be passed as a header or request get parameter.",
|
||||
"description": "Create a new token. A token is linked to a file. Token can be passed as a request URL search parameter.",
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "ResourceToken",
|
||||
@@ -21798,7 +21798,7 @@
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
"demo": "tokens\/create-file-token.md",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new token. A token is linked to a file. Token can be passed as a header or request get parameter.",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new token. A token is linked to a file. Token can be passed as a request URL search parameter.",
|
||||
"rate-limit": 60,
|
||||
"rate-time": 60,
|
||||
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
|
||||
|
||||
@@ -4490,6 +4490,29 @@
|
||||
}
|
||||
],
|
||||
"description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
|
||||
},
|
||||
{
|
||||
"name": "createDocuments",
|
||||
"auth": {
|
||||
"Key": []
|
||||
},
|
||||
"parameters": [
|
||||
"databaseId",
|
||||
"collectionId",
|
||||
"documents"
|
||||
],
|
||||
"required": [
|
||||
"databaseId",
|
||||
"collectionId",
|
||||
"documents"
|
||||
],
|
||||
"responses": [
|
||||
{
|
||||
"code": 201,
|
||||
"model": "#\/components\/schemas\/documentList"
|
||||
}
|
||||
],
|
||||
"description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
|
||||
}
|
||||
],
|
||||
"auth": {
|
||||
|
||||
@@ -30695,7 +30695,7 @@
|
||||
"tags": [
|
||||
"tokens"
|
||||
],
|
||||
"description": "Create a new token. A token is linked to a file. Token can be passed as a header or request get parameter.",
|
||||
"description": "Create a new token. A token is linked to a file. Token can be passed as a request URL search parameter.",
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "ResourceToken",
|
||||
@@ -30716,7 +30716,7 @@
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
"demo": "tokens\/create-file-token.md",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new token. A token is linked to a file. Token can be passed as a header or request get parameter.",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new token. A token is linked to a file. Token can be passed as a request URL search parameter.",
|
||||
"rate-limit": 60,
|
||||
"rate-time": 60,
|
||||
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
|
||||
|
||||
@@ -21777,7 +21777,7 @@
|
||||
"tags": [
|
||||
"tokens"
|
||||
],
|
||||
"description": "Create a new token. A token is linked to a file. Token can be passed as a header or request get parameter.",
|
||||
"description": "Create a new token. A token is linked to a file. Token can be passed as a request URL search parameter.",
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "ResourceToken",
|
||||
@@ -21798,7 +21798,7 @@
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
"demo": "tokens\/create-file-token.md",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new token. A token is linked to a file. Token can be passed as a header or request get parameter.",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new token. A token is linked to a file. Token can be passed as a request URL search parameter.",
|
||||
"rate-limit": 60,
|
||||
"rate-time": 60,
|
||||
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
|
||||
|
||||
@@ -4630,6 +4630,29 @@
|
||||
}
|
||||
],
|
||||
"description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
|
||||
},
|
||||
{
|
||||
"name": "createDocuments",
|
||||
"auth": {
|
||||
"Key": []
|
||||
},
|
||||
"parameters": [
|
||||
"databaseId",
|
||||
"collectionId",
|
||||
"documents"
|
||||
],
|
||||
"required": [
|
||||
"databaseId",
|
||||
"collectionId",
|
||||
"documents"
|
||||
],
|
||||
"responses": [
|
||||
{
|
||||
"code": 201,
|
||||
"model": "#\/definitions\/documentList"
|
||||
}
|
||||
],
|
||||
"description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
|
||||
}
|
||||
],
|
||||
"auth": {
|
||||
|
||||
@@ -30922,7 +30922,7 @@
|
||||
"tags": [
|
||||
"tokens"
|
||||
],
|
||||
"description": "Create a new token. A token is linked to a file. Token can be passed as a header or request get parameter.",
|
||||
"description": "Create a new token. A token is linked to a file. Token can be passed as a request URL search parameter.",
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "ResourceToken",
|
||||
@@ -30939,7 +30939,7 @@
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
"demo": "tokens\/create-file-token.md",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new token. A token is linked to a file. Token can be passed as a header or request get parameter.",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new token. A token is linked to a file. Token can be passed as a request URL search parameter.",
|
||||
"rate-limit": 60,
|
||||
"rate-time": 60,
|
||||
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
|
||||
|
||||
@@ -22062,7 +22062,7 @@
|
||||
"tags": [
|
||||
"tokens"
|
||||
],
|
||||
"description": "Create a new token. A token is linked to a file. Token can be passed as a header or request get parameter.",
|
||||
"description": "Create a new token. A token is linked to a file. Token can be passed as a request URL search parameter.",
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "ResourceToken",
|
||||
@@ -22079,7 +22079,7 @@
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
"demo": "tokens\/create-file-token.md",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new token. A token is linked to a file. Token can be passed as a header or request get parameter.",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new token. A token is linked to a file. Token can be passed as a request URL search parameter.",
|
||||
"rate-limit": 60,
|
||||
"rate-time": 60,
|
||||
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
|
||||
|
||||
@@ -4630,6 +4630,29 @@
|
||||
}
|
||||
],
|
||||
"description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
|
||||
},
|
||||
{
|
||||
"name": "createDocuments",
|
||||
"auth": {
|
||||
"Key": []
|
||||
},
|
||||
"parameters": [
|
||||
"databaseId",
|
||||
"collectionId",
|
||||
"documents"
|
||||
],
|
||||
"required": [
|
||||
"databaseId",
|
||||
"collectionId",
|
||||
"documents"
|
||||
],
|
||||
"responses": [
|
||||
{
|
||||
"code": 201,
|
||||
"model": "#\/definitions\/documentList"
|
||||
}
|
||||
],
|
||||
"description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
|
||||
}
|
||||
],
|
||||
"auth": {
|
||||
|
||||
@@ -30922,7 +30922,7 @@
|
||||
"tags": [
|
||||
"tokens"
|
||||
],
|
||||
"description": "Create a new token. A token is linked to a file. Token can be passed as a header or request get parameter.",
|
||||
"description": "Create a new token. A token is linked to a file. Token can be passed as a request URL search parameter.",
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "ResourceToken",
|
||||
@@ -30939,7 +30939,7 @@
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
"demo": "tokens\/create-file-token.md",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new token. A token is linked to a file. Token can be passed as a header or request get parameter.",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new token. A token is linked to a file. Token can be passed as a request URL search parameter.",
|
||||
"rate-limit": 60,
|
||||
"rate-time": 60,
|
||||
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
|
||||
|
||||
@@ -22062,7 +22062,7 @@
|
||||
"tags": [
|
||||
"tokens"
|
||||
],
|
||||
"description": "Create a new token. A token is linked to a file. Token can be passed as a header or request get parameter.",
|
||||
"description": "Create a new token. A token is linked to a file. Token can be passed as a request URL search parameter.",
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "ResourceToken",
|
||||
@@ -22079,7 +22079,7 @@
|
||||
"type": "",
|
||||
"deprecated": false,
|
||||
"demo": "tokens\/create-file-token.md",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new token. A token is linked to a file. Token can be passed as a header or request get parameter.",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new token. A token is linked to a file. Token can be passed as a request URL search parameter.",
|
||||
"rate-limit": 60,
|
||||
"rate-time": 60,
|
||||
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
|
||||
|
||||
@@ -1351,4 +1351,23 @@ return [
|
||||
'providerVersion' => '0.3.*',
|
||||
'variables' => [],
|
||||
],
|
||||
[
|
||||
'key' => 'gallery-for-lynx',
|
||||
'name' => 'Lynx gallery',
|
||||
'tagline' => 'A Lynx website showcasing gallery with smooth animations.',
|
||||
'score' => 1, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
|
||||
'useCases' => [UseCases::STARTER],
|
||||
'screenshotDark' => $url . '/images/sites/templates/gallery-for-lynx-dark.png',
|
||||
'screenshotLight' => $url . '/images/sites/templates/gallery-for-lynx-light.png',
|
||||
'frameworks' => [
|
||||
getFramework('LYNX', [
|
||||
'providerRootDirectory' => './lynx/gallery',
|
||||
]),
|
||||
],
|
||||
'vcsProvider' => 'github',
|
||||
'providerRepositoryId' => 'templates-for-sites',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerVersion' => '0.3.*',
|
||||
'variables' => []
|
||||
],
|
||||
];
|
||||
|
||||
@@ -106,6 +106,15 @@ return [
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
],
|
||||
[
|
||||
'name' => '_APP_DOMAIN_SITES',
|
||||
'description' => 'A domain to use for site preview URLs.',
|
||||
'introduction' => '',
|
||||
'default' => 'sites.localhost',
|
||||
'required' => false,
|
||||
'question' => '',
|
||||
'filter' => ''
|
||||
],
|
||||
[
|
||||
'name' => '_APP_DOMAIN_TARGET',
|
||||
'description' => 'Deprecated since 1.7.0. A DNS A record hostname to serve as a CNAME target for your Appwrite custom domains. You can use the same value as used for the Appwrite \'_APP_DOMAIN\' variable. The default value is \'localhost\'.',
|
||||
|
||||
@@ -4202,6 +4202,244 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
|
||||
$response->dynamic($document, Response::MODEL_DOCUMENT);
|
||||
});
|
||||
|
||||
App::put('/v1/databases/:databaseId/collections/:collectionId/documents/:documentId')
|
||||
->desc('Upsert document')
|
||||
->groups(['api', 'database'])
|
||||
->label('event', 'databases.[databaseId].collections.[collectionId].documents.[documentId].upsert')
|
||||
->label('scope', 'documents.write')
|
||||
->label('resourceType', RESOURCE_TYPE_DATABASES)
|
||||
->label('audits.event', 'document.upsert')
|
||||
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}/document/{response.$id}')
|
||||
->label('abuse-key', 'ip:{ip},method:{method},url:{url},userId:{userId}')
|
||||
->label('abuse-limit', APP_LIMIT_WRITE_RATE_DEFAULT * 2)
|
||||
->label('abuse-time', APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT)
|
||||
->label('sdk', new Method(
|
||||
namespace: 'databases',
|
||||
group: 'documents',
|
||||
name: 'upsertDocument',
|
||||
description: '/docs/references/databases/upsert-document.md',
|
||||
auth: [AuthType::SESSION, AuthType::KEY, AuthType::JWT],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: Response::MODEL_DOCUMENT,
|
||||
)
|
||||
],
|
||||
contentType: ContentType::JSON
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID.')
|
||||
->param('documentId', '', new CustomId(), 'Document ID.')
|
||||
->param('data', [], new JSON(), 'Document data as JSON object. Include all required attributes of the document to be created or updated.')
|
||||
->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 permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true)
|
||||
->inject('requestTimestamp')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForStatsUsage')
|
||||
->action(function (string $databaseId, string $collectionId, string $documentId, string|array $data, ?array $permissions, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Event $queueForEvents, StatsUsage $queueForStatsUsage) {
|
||||
$data = (\is_string($data)) ? \json_decode($data, true) : $data; // Cast to JSON array
|
||||
|
||||
if (empty($data) && \is_null($permissions)) {
|
||||
throw new Exception(Exception::DOCUMENT_MISSING_PAYLOAD);
|
||||
}
|
||||
|
||||
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
|
||||
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
}
|
||||
|
||||
$collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId));
|
||||
if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) {
|
||||
throw new Exception(Exception::COLLECTION_NOT_FOUND);
|
||||
}
|
||||
|
||||
// Map aggregate permissions into the multiple permissions they represent.
|
||||
$permissions = Permission::aggregate($permissions, [
|
||||
Database::PERMISSION_READ,
|
||||
Database::PERMISSION_UPDATE,
|
||||
Database::PERMISSION_DELETE,
|
||||
]);
|
||||
|
||||
// Users can only manage their own roles, API keys and Admin users can manage any
|
||||
$roles = Authorization::getRoles();
|
||||
if (!$isAPIKey && !$isPrivilegedUser && !\is_null($permissions)) {
|
||||
foreach (Database::PERMISSIONS as $type) {
|
||||
foreach ($permissions as $permission) {
|
||||
$permission = Permission::parse($permission);
|
||||
if ($permission->getPermission() != $type) {
|
||||
continue;
|
||||
}
|
||||
$role = (new Role(
|
||||
$permission->getRole(),
|
||||
$permission->getIdentifier(),
|
||||
$permission->getDimension()
|
||||
))->toString();
|
||||
if (!Authorization::isRole($role)) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED, 'Permissions must be one of: (' . \implode(', ', $roles) . ')');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$data['$id'] = $documentId;
|
||||
$data['$permissions'] = $permissions;
|
||||
$newDocument = new Document($data);
|
||||
|
||||
$operations = 0;
|
||||
|
||||
$setCollection = (function (Document $collection, Document $document) use (&$setCollection, $dbForProject, $database, &$operations) {
|
||||
|
||||
$operations++;
|
||||
|
||||
$relationships = \array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
);
|
||||
|
||||
foreach ($relationships as $relationship) {
|
||||
$related = $document->getAttribute($relationship->getAttribute('key'));
|
||||
|
||||
if (empty($related)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$isList = \is_array($related) && \array_values($related) === $related;
|
||||
|
||||
if ($isList) {
|
||||
$relations = $related;
|
||||
} else {
|
||||
$relations = [$related];
|
||||
}
|
||||
|
||||
$relatedCollectionId = $relationship->getAttribute('relatedCollection');
|
||||
$relatedCollection = Authorization::skip(
|
||||
fn () => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId)
|
||||
);
|
||||
|
||||
foreach ($relations as &$relation) {
|
||||
// If the relation is an array it can be either update or create a child document.
|
||||
if (
|
||||
\is_array($relation)
|
||||
&& \array_values($relation) !== $relation
|
||||
&& !isset($relation['$id'])
|
||||
) {
|
||||
$relation['$id'] = ID::unique();
|
||||
$relation = new Document($relation);
|
||||
}
|
||||
if ($relation instanceof Document) {
|
||||
$oldDocument = Authorization::skip(fn () => $dbForProject->getDocument(
|
||||
'database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId(),
|
||||
$relation->getId()
|
||||
));
|
||||
$relation->removeAttribute('$collectionId');
|
||||
$relation->removeAttribute('$databaseId');
|
||||
// Attribute $collection is required for Utopia.
|
||||
$relation->setAttribute(
|
||||
'$collection',
|
||||
'database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId()
|
||||
);
|
||||
|
||||
if ($oldDocument->isEmpty()) {
|
||||
if (isset($relation['$id']) && $relation['$id'] === 'unique()') {
|
||||
$relation['$id'] = ID::unique();
|
||||
}
|
||||
}
|
||||
$setCollection($relatedCollection, $relation);
|
||||
}
|
||||
}
|
||||
|
||||
if ($isList) {
|
||||
$document->setAttribute($relationship->getAttribute('key'), \array_values($relations));
|
||||
} else {
|
||||
$document->setAttribute($relationship->getAttribute('key'), \reset($relations));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$setCollection($collection, $newDocument);
|
||||
|
||||
$queueForStatsUsage
|
||||
->addMetric(METRIC_DATABASES_OPERATIONS_WRITES, \max(1, $operations))
|
||||
->addMetric(str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_OPERATIONS_WRITES), \max(1, $operations));
|
||||
|
||||
$upserted = [];
|
||||
try {
|
||||
$modified = $dbForProject->createOrUpdateDocuments(
|
||||
'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(),
|
||||
[$newDocument],
|
||||
onNext: function (Document $document) use (&$upserted) {
|
||||
$upserted[] = $document;
|
||||
},
|
||||
);
|
||||
} catch (ConflictException) {
|
||||
throw new Exception(Exception::DOCUMENT_UPDATE_CONFLICT);
|
||||
} catch (DuplicateException) {
|
||||
throw new Exception(Exception::DOCUMENT_ALREADY_EXISTS);
|
||||
} catch (RelationshipException $e) {
|
||||
throw new Exception(Exception::RELATIONSHIP_VALUE_INVALID, $e->getMessage());
|
||||
} catch (StructureException $e) {
|
||||
throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, $e->getMessage());
|
||||
}
|
||||
|
||||
$document = $upserted[0];
|
||||
// Add $collectionId and $databaseId for all documents
|
||||
$processDocument = function (Document $collection, Document $document) use (&$processDocument, $dbForProject, $database) {
|
||||
$document->setAttribute('$databaseId', $database->getId());
|
||||
$document->setAttribute('$collectionId', $collection->getId());
|
||||
|
||||
$relationships = \array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
);
|
||||
|
||||
foreach ($relationships as $relationship) {
|
||||
$related = $document->getAttribute($relationship->getAttribute('key'));
|
||||
|
||||
if (empty($related)) {
|
||||
continue;
|
||||
}
|
||||
if (!\is_array($related)) {
|
||||
$related = [$related];
|
||||
}
|
||||
|
||||
$relatedCollectionId = $relationship->getAttribute('relatedCollection');
|
||||
$relatedCollection = Authorization::skip(
|
||||
fn () => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId)
|
||||
);
|
||||
|
||||
foreach ($related as $relation) {
|
||||
if ($relation instanceof Document) {
|
||||
$processDocument($relatedCollection, $relation);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$processDocument($collection, $document);
|
||||
|
||||
$relationships = \array_map(
|
||||
fn ($document) => $document->getAttribute('key'),
|
||||
\array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
)
|
||||
);
|
||||
|
||||
$queueForEvents
|
||||
->setParam('databaseId', $databaseId)
|
||||
->setParam('collectionId', $collection->getId())
|
||||
->setParam('documentId', $document->getId())
|
||||
->setContext('collection', $collection)
|
||||
->setContext('database', $database)
|
||||
->setPayload($response->getPayload(), sensitive: $relationships);
|
||||
|
||||
$response->dynamic($document, Response::MODEL_DOCUMENT);
|
||||
});
|
||||
|
||||
App::patch('/v1/databases/:databaseId/collections/:collectionId/documents')
|
||||
->desc('Update documents')
|
||||
->groups(['api', 'database'])
|
||||
|
||||
@@ -177,7 +177,7 @@ $image = $this->getParam('image', '');
|
||||
appwrite-console:
|
||||
<<: *x-logging
|
||||
container_name: appwrite-console
|
||||
image: <?php echo $organization; ?>/console:6.0.1
|
||||
image: <?php echo $organization; ?>/console:6.0.8
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
|
||||
Generated
+6
-6
@@ -4105,16 +4105,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/platform",
|
||||
"version": "0.7.6",
|
||||
"version": "0.7.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/platform.git",
|
||||
"reference": "6bc7fbb43ec2b7f9ee5bdef5d4b5e4a81860950b"
|
||||
"reference": "8c43cd866148a7c4c495e3401268429e338004b3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/platform/zipball/6bc7fbb43ec2b7f9ee5bdef5d4b5e4a81860950b",
|
||||
"reference": "6bc7fbb43ec2b7f9ee5bdef5d4b5e4a81860950b",
|
||||
"url": "https://api.github.com/repos/utopia-php/platform/zipball/8c43cd866148a7c4c495e3401268429e338004b3",
|
||||
"reference": "8c43cd866148a7c4c495e3401268429e338004b3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4149,9 +4149,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/platform/issues",
|
||||
"source": "https://github.com/utopia-php/platform/tree/0.7.6"
|
||||
"source": "https://github.com/utopia-php/platform/tree/0.7.7"
|
||||
},
|
||||
"time": "2025-05-18T20:31:24+00:00"
|
||||
"time": "2025-05-20T09:23:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/pools",
|
||||
|
||||
+1
-1
@@ -213,7 +213,7 @@ services:
|
||||
appwrite-console:
|
||||
<<: *x-logging
|
||||
container_name: appwrite-console
|
||||
image: appwrite/console:6.0.7
|
||||
image: appwrite/console:6.0.8
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import io.appwrite.Client;
|
||||
import io.appwrite.coroutines.CoroutineCallback;
|
||||
import io.appwrite.services.Databases;
|
||||
|
||||
Client client = new Client(context)
|
||||
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
|
||||
.setKey(""); //
|
||||
|
||||
Databases databases = new Databases(client);
|
||||
|
||||
databases.createDocuments(
|
||||
"<DATABASE_ID>", // databaseId
|
||||
"<COLLECTION_ID>", // collectionId
|
||||
listOf(), // documents
|
||||
new CoroutineCallback<>((result, error) -> {
|
||||
if (error != null) {
|
||||
error.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d("Appwrite", result.toString());
|
||||
})
|
||||
);
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import io.appwrite.Client
|
||||
import io.appwrite.coroutines.CoroutineCallback
|
||||
import io.appwrite.services.Databases
|
||||
|
||||
val client = Client(context)
|
||||
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
|
||||
.setKey("") //
|
||||
|
||||
val databases = Databases(client)
|
||||
|
||||
val result = databases.createDocuments(
|
||||
databaseId = "<DATABASE_ID>",
|
||||
collectionId = "<COLLECTION_ID>",
|
||||
documents = listOf(),
|
||||
)
|
||||
@@ -0,0 +1,14 @@
|
||||
import Appwrite
|
||||
|
||||
let client = Client()
|
||||
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
|
||||
.setKey("") //
|
||||
|
||||
let databases = Databases(client)
|
||||
|
||||
let documentList = try await databases.createDocuments(
|
||||
databaseId: "<DATABASE_ID>",
|
||||
collectionId: "<COLLECTION_ID>",
|
||||
documents: []
|
||||
)
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import 'package:appwrite/appwrite.dart';
|
||||
|
||||
Client client = Client()
|
||||
.setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint
|
||||
.setKey(''); //
|
||||
|
||||
Databases databases = Databases(client);
|
||||
|
||||
DocumentList result = await databases.createDocuments(
|
||||
databaseId: '<DATABASE_ID>',
|
||||
collectionId: '<COLLECTION_ID>',
|
||||
documents: [],
|
||||
);
|
||||
@@ -0,0 +1,18 @@
|
||||
mutation {
|
||||
databasesCreateDocuments(
|
||||
databaseId: "<DATABASE_ID>",
|
||||
collectionId: "<COLLECTION_ID>",
|
||||
documents: []
|
||||
) {
|
||||
total
|
||||
documents {
|
||||
_id
|
||||
_collectionId
|
||||
_databaseId
|
||||
_createdAt
|
||||
_updatedAt
|
||||
_permissions
|
||||
data
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Client, Databases } from "react-native-appwrite";
|
||||
|
||||
const client = new Client()
|
||||
.setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint
|
||||
.setKey(''); //
|
||||
|
||||
const databases = new Databases(client);
|
||||
|
||||
const result = await databases.createDocuments(
|
||||
'<DATABASE_ID>', // databaseId
|
||||
'<COLLECTION_ID>', // collectionId
|
||||
[] // documents
|
||||
);
|
||||
|
||||
console.log(result);
|
||||
@@ -0,0 +1,11 @@
|
||||
POST /v1/databases/{databaseId}/collections/{collectionId}/documents HTTP/1.1
|
||||
Host: cloud.appwrite.io
|
||||
Content-Type: application/json
|
||||
X-Appwrite-Response-Format: 1.7.0
|
||||
X-Appwrite-Project: <YOUR_PROJECT_ID>
|
||||
X-Appwrite-Session:
|
||||
X-Appwrite-JWT: <YOUR_JWT>
|
||||
|
||||
{
|
||||
"documents": []
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Client, Databases } from "appwrite";
|
||||
|
||||
const client = new Client()
|
||||
.setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint
|
||||
.setKey(''); //
|
||||
|
||||
const databases = new Databases(client);
|
||||
|
||||
const result = await databases.createDocuments(
|
||||
'<DATABASE_ID>', // databaseId
|
||||
'<COLLECTION_ID>', // collectionId
|
||||
[] // documents
|
||||
);
|
||||
|
||||
console.log(result);
|
||||
@@ -0,0 +1 @@
|
||||
appwrite account createAnonymousSession
|
||||
@@ -0,0 +1,3 @@
|
||||
appwrite account createEmailPasswordSession \
|
||||
--email email@example.com \
|
||||
--password password
|
||||
@@ -0,0 +1,4 @@
|
||||
appwrite account createEmailToken \
|
||||
--userId <USER_ID> \
|
||||
--email email@example.com \
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
appwrite account createJWT
|
||||
@@ -0,0 +1,5 @@
|
||||
appwrite account createMagicURLToken \
|
||||
--userId <USER_ID> \
|
||||
--email email@example.com \
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
appwrite account createMfaAuthenticator \
|
||||
--type totp
|
||||
@@ -0,0 +1,2 @@
|
||||
appwrite account createMfaChallenge \
|
||||
--factor email
|
||||
@@ -0,0 +1 @@
|
||||
appwrite account createMfaRecoveryCodes
|
||||
@@ -0,0 +1,5 @@
|
||||
appwrite account createOAuth2Session \
|
||||
--provider amazon \
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
appwrite account createOAuth2Token \
|
||||
--provider amazon \
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
appwrite account createPhoneToken \
|
||||
--userId <USER_ID> \
|
||||
--phone +12065550100
|
||||
@@ -0,0 +1 @@
|
||||
appwrite account createPhoneVerification
|
||||
@@ -0,0 +1,4 @@
|
||||
appwrite account createPushTarget \
|
||||
--targetId <TARGET_ID> \
|
||||
--identifier <IDENTIFIER> \
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
appwrite account createRecovery \
|
||||
--email email@example.com \
|
||||
--url https://example.com
|
||||
@@ -0,0 +1,3 @@
|
||||
appwrite account createSession \
|
||||
--userId <USER_ID> \
|
||||
--secret <SECRET>
|
||||
@@ -0,0 +1,2 @@
|
||||
appwrite account createVerification \
|
||||
--url https://example.com
|
||||
@@ -0,0 +1,5 @@
|
||||
appwrite account create \
|
||||
--userId <USER_ID> \
|
||||
--email email@example.com \
|
||||
--password '' \
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
appwrite account deleteIdentity \
|
||||
--identityId <IDENTITY_ID>
|
||||
@@ -0,0 +1,2 @@
|
||||
appwrite account deleteMfaAuthenticator \
|
||||
--type totp
|
||||
@@ -0,0 +1,2 @@
|
||||
appwrite account deletePushTarget \
|
||||
--targetId <TARGET_ID>
|
||||
@@ -0,0 +1,2 @@
|
||||
appwrite account deleteSession \
|
||||
--sessionId <SESSION_ID>
|
||||
@@ -0,0 +1 @@
|
||||
appwrite account deleteSessions
|
||||
@@ -0,0 +1 @@
|
||||
appwrite account delete
|
||||
@@ -0,0 +1 @@
|
||||
appwrite account getMfaRecoveryCodes
|
||||
@@ -0,0 +1 @@
|
||||
appwrite account getPrefs
|
||||
@@ -0,0 +1,2 @@
|
||||
appwrite account getSession \
|
||||
--sessionId <SESSION_ID>
|
||||
@@ -0,0 +1 @@
|
||||
appwrite account get
|
||||
@@ -0,0 +1,2 @@
|
||||
appwrite account listIdentities \
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
appwrite account listLogs \
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
appwrite account listMfaFactors
|
||||
@@ -0,0 +1 @@
|
||||
appwrite account listSessions
|
||||
@@ -0,0 +1,3 @@
|
||||
appwrite account updateEmail \
|
||||
--email email@example.com \
|
||||
--password password
|
||||
@@ -0,0 +1,2 @@
|
||||
appwrite account updateMFA \
|
||||
--mfa false
|
||||
@@ -0,0 +1,3 @@
|
||||
appwrite account updateMagicURLSession \
|
||||
--userId <USER_ID> \
|
||||
--secret <SECRET>
|
||||
@@ -0,0 +1,3 @@
|
||||
appwrite account updateMfaAuthenticator \
|
||||
--type totp \
|
||||
--otp <OTP>
|
||||
@@ -0,0 +1,3 @@
|
||||
appwrite account updateMfaChallenge \
|
||||
--challengeId <CHALLENGE_ID> \
|
||||
--otp <OTP>
|
||||
@@ -0,0 +1 @@
|
||||
appwrite account updateMfaRecoveryCodes
|
||||
@@ -0,0 +1,2 @@
|
||||
appwrite account updateName \
|
||||
--name <NAME>
|
||||
@@ -0,0 +1,3 @@
|
||||
appwrite account updatePassword \
|
||||
--password '' \
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
appwrite account updatePhoneSession \
|
||||
--userId <USER_ID> \
|
||||
--secret <SECRET>
|
||||
@@ -0,0 +1,3 @@
|
||||
appwrite account updatePhoneVerification \
|
||||
--userId <USER_ID> \
|
||||
--secret <SECRET>
|
||||
@@ -0,0 +1,3 @@
|
||||
appwrite account updatePhone \
|
||||
--phone +12065550100 \
|
||||
--password password
|
||||
@@ -0,0 +1,2 @@
|
||||
appwrite account updatePrefs \
|
||||
--prefs '{ "key": "value" }'
|
||||
@@ -0,0 +1,3 @@
|
||||
appwrite account updatePushTarget \
|
||||
--targetId <TARGET_ID> \
|
||||
--identifier <IDENTIFIER>
|
||||
@@ -0,0 +1,4 @@
|
||||
appwrite account updateRecovery \
|
||||
--userId <USER_ID> \
|
||||
--secret <SECRET> \
|
||||
--password ''
|
||||
@@ -0,0 +1,2 @@
|
||||
appwrite account updateSession \
|
||||
--sessionId <SESSION_ID>
|
||||
@@ -0,0 +1 @@
|
||||
appwrite account updateStatus
|
||||
@@ -0,0 +1,3 @@
|
||||
appwrite account updateVerification \
|
||||
--userId <USER_ID> \
|
||||
--secret <SECRET>
|
||||
@@ -0,0 +1,2 @@
|
||||
appwrite assistant chat \
|
||||
--prompt <PROMPT>
|
||||
@@ -0,0 +1,5 @@
|
||||
appwrite avatars getBrowser \
|
||||
--code aa \
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
appwrite avatars getCreditCard \
|
||||
--code amex \
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
appwrite avatars getFavicon \
|
||||
--url https://example.com
|
||||
@@ -0,0 +1,5 @@
|
||||
appwrite avatars getFlag \
|
||||
--code af \
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
appwrite avatars getImage \
|
||||
--url https://example.com \
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
appwrite avatars getInitials \
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
appwrite avatars getQR \
|
||||
--text <TEXT> \
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
appwrite console getResource \
|
||||
--value <VALUE> \
|
||||
--type rules
|
||||
@@ -0,0 +1 @@
|
||||
appwrite console variables
|
||||
@@ -0,0 +1,7 @@
|
||||
appwrite databases createBooleanAttribute \
|
||||
--databaseId <DATABASE_ID> \
|
||||
--collectionId <COLLECTION_ID> \
|
||||
--key '' \
|
||||
--required false \
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
appwrite databases createCollection \
|
||||
--databaseId <DATABASE_ID> \
|
||||
--collectionId <COLLECTION_ID> \
|
||||
--name <NAME> \
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
appwrite databases createDatetimeAttribute \
|
||||
--databaseId <DATABASE_ID> \
|
||||
--collectionId <COLLECTION_ID> \
|
||||
--key '' \
|
||||
--required false \
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
appwrite databases createDocument \
|
||||
--databaseId <DATABASE_ID> \
|
||||
--collectionId <COLLECTION_ID> \
|
||||
--documentId <DOCUMENT_ID> \
|
||||
--data '{ "key": "value" }' \
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
appwrite databases createDocuments \
|
||||
--databaseId <DATABASE_ID> \
|
||||
--collectionId <COLLECTION_ID> \
|
||||
--documents one two three
|
||||
@@ -0,0 +1,7 @@
|
||||
appwrite databases createEmailAttribute \
|
||||
--databaseId <DATABASE_ID> \
|
||||
--collectionId <COLLECTION_ID> \
|
||||
--key '' \
|
||||
--required false \
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
appwrite databases createEnumAttribute \
|
||||
--databaseId <DATABASE_ID> \
|
||||
--collectionId <COLLECTION_ID> \
|
||||
--key '' \
|
||||
--elements one two three \
|
||||
--required false \
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
appwrite databases createFloatAttribute \
|
||||
--databaseId <DATABASE_ID> \
|
||||
--collectionId <COLLECTION_ID> \
|
||||
--key '' \
|
||||
--required false \
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
appwrite databases createIndex \
|
||||
--databaseId <DATABASE_ID> \
|
||||
--collectionId <COLLECTION_ID> \
|
||||
--key '' \
|
||||
--type key \
|
||||
--attributes one two three \
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
appwrite databases createIntegerAttribute \
|
||||
--databaseId <DATABASE_ID> \
|
||||
--collectionId <COLLECTION_ID> \
|
||||
--key '' \
|
||||
--required false \
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
appwrite databases createIpAttribute \
|
||||
--databaseId <DATABASE_ID> \
|
||||
--collectionId <COLLECTION_ID> \
|
||||
--key '' \
|
||||
--required false \
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
appwrite databases createRelationshipAttribute \
|
||||
--databaseId <DATABASE_ID> \
|
||||
--collectionId <COLLECTION_ID> \
|
||||
--relatedCollectionId <RELATED_COLLECTION_ID> \
|
||||
--type oneToOne \
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
appwrite databases createStringAttribute \
|
||||
--databaseId <DATABASE_ID> \
|
||||
--collectionId <COLLECTION_ID> \
|
||||
--key '' \
|
||||
--size 1 \
|
||||
--required false \
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
appwrite databases createUrlAttribute \
|
||||
--databaseId <DATABASE_ID> \
|
||||
--collectionId <COLLECTION_ID> \
|
||||
--key '' \
|
||||
--required false \
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
appwrite databases create \
|
||||
--databaseId <DATABASE_ID> \
|
||||
--name <NAME> \
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
appwrite databases deleteAttribute \
|
||||
--databaseId <DATABASE_ID> \
|
||||
--collectionId <COLLECTION_ID> \
|
||||
--key ''
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user