diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 277a509447..c6837673d5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,7 +9,31 @@ You can [find issues using this query](https://github.com/search?q=org%3Aappwrit ## How to Start? -If you are worried or don’t know where to start, check out the next section that explains what kind of help we could use and where you can get involved. You can send your questions to [@appwrite on Twitter](https://twitter.com/appwrite) or to anyone from the [Appwrite team on Discord](https://appwrite.io/discord). You can also submit an issue, and a maintainer can guide you! +Welcome! We're excited that you're interested in contributing to Appwrite. To make sure your time is valued and your contributions are successful, please follow these steps before writing any code: + +### 🔍 Step 1: Find an Issue + +Browse open issues and look for ones labeled [good first issue](https://github.com/search?q=org%3Aappwrite+is%3Aopen+type%3Aissue+label%3A%22good+first+issue%22&type=issues) or [help wanted](https://github.com/search?q=org%3Aappwrite+is%3Aopen+type%3Aissue+label%3A%22help+wanted%22&type=issues). + +If you're not sure which issue to pick, ask in our ⁠[maintainers channel](https://discord.com/channels/564160730845151244/636852860709240842) on Discord. + +### 📝 Step 2: Ask to Be Assigned + +Before working on an issue, comment on the GitHub issue asking to be assigned. This prevents multiple people working on the same task. + +Then, create a thread in the ⁠[maintainers channel](https://discord.com/channels/564160730845151244/636852860709240842) on Discord with a link to the issue. + +Our team is small and may not see your GitHub comment right away - posting in the ⁠[maintainers channel](https://discord.com/channels/564160730845151244/636852860709240842) ensures it gets seen. + +### 💬 Step 3: Don’t Submit Random PRs + +If you're not working on an assigned issue, create a GitHub issue first. + +PRs submitted without context or discussion may not align with our roadmap and may be closed without review. + +### ⚠️ Please Note + +We’re a very small team managing a large project. Many PRs are submitted, and while we appreciate every effort, we can only review contributions that follow the process above. This helps us keep things fair and organized. ## Code of Conduct diff --git a/app/cli.php b/app/cli.php index 86ec241c93..504e4fb5e6 100644 --- a/app/cli.php +++ b/app/cli.php @@ -191,9 +191,15 @@ CLI::setResource('getLogsDB', function (Group $pools, Cache $cache) { CLI::setResource('publisher', function (Group $pools) { return new BrokerPool(publisher: $pools->get('publisher')); }, ['pools']); -CLI::setResource('publisherRedis', function () { - // Stub -}); +CLI::setResource('publisherDatabases', function (BrokerPool $publisher) { + return $publisher; +}, ['publisher']); +CLI::setResource('publisherMigrations', function (BrokerPool $publisher) { + return $publisher; +}, ['publisher']); +CLI::setResource('publisherStatsUsage', function (BrokerPool $publisher) { + return $publisher; +}, ['publisher']); CLI::setResource('queueForStatsUsage', function (Publisher $publisher) { return new StatsUsage($publisher); }, ['publisher']); diff --git a/app/config/locale/templates/email-base-styled.tpl b/app/config/locale/templates/email-base-styled.tpl index f6d3e8cd63..b5aece0253 100644 --- a/app/config/locale/templates/email-base-styled.tpl +++ b/app/config/locale/templates/email-base-styled.tpl @@ -120,6 +120,11 @@ +
+ {{preview}} +
{{previewWhitespace}}
+
+
diff --git a/app/config/locale/templates/email-base.tpl b/app/config/locale/templates/email-base.tpl index 13056fd5ae..f6807ce7b2 100644 --- a/app/config/locale/templates/email-base.tpl +++ b/app/config/locale/templates/email-base.tpl @@ -121,6 +121,11 @@ +
+ {{preview}} +
{{previewWhitespace}}
+
+
diff --git a/app/config/locale/translations/en.json b/app/config/locale/translations/en.json index dbfa2e1be8..072a7f7552 100644 --- a/app/config/locale/translations/en.json +++ b/app/config/locale/translations/en.json @@ -4,6 +4,7 @@ "settings.direction": "ltr", "emails.sender": "%s Team", "emails.verification.subject": "Account Verification", + "emails.verification.preview": "Verify your email to activate your {{project}} account.", "emails.verification.hello": "Hello {{user}},", "emails.verification.body": "Follow this link to verify your email address to your {{b}}{{project}}{{/b}} account.", "emails.verification.footer": "If you didn’t ask to verify this address, you can ignore this message.", @@ -11,6 +12,7 @@ "emails.verification.buttonText": "Confirm email address", "emails.verification.signature": "{{project}} team", "emails.magicSession.subject": "{{project}} Login", + "emails.magicSession.preview": "Sign in to {{project}} with your secure link. Expires in 1 hour.", "emails.magicSession.hello": "Hello {{user}},", "emails.magicSession.optionButton": "Click the button below to securely sign in to your {{b}}{{project}}{{/b}} account. This link will expire in 1 hour.", "emails.magicSession.buttonText": "Sign in to {{project}}", @@ -20,6 +22,7 @@ "emails.magicSession.thanks": "Thanks,", "emails.magicSession.signature": "{{project}} team", "emails.sessionAlert.subject": "Security alert: new session on your {{project}} account", + "emails.sessionAlert.preview": "New login detected on {{project}} at {{time}} UTC.", "emails.sessionAlert.hello": "Hello {{user}},", "emails.sessionAlert.body": "A new session has been created on your {{b}}{{project}}{{/b}} account, {{b}}on {{date}}, {{year}} at {{time}} UTC{{/b}}.\nHere are the details of the new session: ", "emails.sessionAlert.listDevice": "Device: {{b}}{{device}}{{/b}}", @@ -29,6 +32,7 @@ "emails.sessionAlert.thanks": "Thanks,", "emails.sessionAlert.signature": "{{project}} team", "emails.otpSession.subject": "OTP for {{project}} Login", + "emails.otpSession.preview": "Use OTP {{otp}} to sign in to {{project}}. Expires in 15 minutes.", "emails.otpSession.hello": "Hello {{user}},", "emails.otpSession.description": "Enter the following verification code when prompted to securely sign in to your {{b}}{{project}}{{/b}} account. This code will expire in 15 minutes.", "emails.otpSession.clientInfo": "This sign in was requested using {{b}}{{agentClient}}{{/b}} on {{b}}{{agentDevice}}{{/b}} {{b}}{{agentOs}}{{/b}}. If you didn't request the sign in, you can safely ignore this email.", @@ -36,12 +40,14 @@ "emails.otpSession.thanks": "Thanks,", "emails.otpSession.signature": "{{project}} team", "emails.mfaChallenge.subject": "Verification Code for {{project}}", + "emails.mfaChallenge.preview": "Use code {{otp}} for two-step verification in {{project}}. Expires in 15 minutes.", "emails.mfaChallenge.hello": "Hello {{user}},", - "emails.mfaChallenge.description": "Enter the following verification code to verify your email and activate two-step verification in {{b}}{{project}}{{/b}}. This code will expire in 15 minutes.", + "emails.mfaChallenge.description": "Enter the following code to confirm your two-step verification in {{b}}{{project}}{{/b}}. This code will expire in 15 minutes.", "emails.mfaChallenge.clientInfo": "This verification code was requested using {{b}}{{agentClient}}{{/b}} on {{b}}{{agentDevice}}{{/b}} {{b}}{{agentOs}}{{/b}}. If you didn't request the verification code, you can safely ignore this email.", "emails.mfaChallenge.thanks": "Thanks,", "emails.mfaChallenge.signature": "{{project}} team", "emails.recovery.subject": "Password Reset", + "emails.recovery.preview": "Reset your {{project}} password using the link.", "emails.recovery.hello": "Hello {{user}},", "emails.recovery.body": "Follow this link to reset your {{b}}{{project}}{{/b}} password.", "emails.recovery.footer": "If you didn't ask to reset your password, you can ignore this message.", @@ -49,6 +55,7 @@ "emails.recovery.buttonText": "Reset password", "emails.recovery.signature": "{{project}} team", "emails.invitation.subject": "Invitation to %s Team at %s", + "emails.invitation.preview": "{{owner}} invited you to join {{team}} at {{project}}", "emails.invitation.hello": "Hello {{user}},", "emails.invitation.body": "This mail was sent to you because {{b}}{{owner}}{{/b}} wanted to invite you to become a member of the {{b}}{{team}}{{/b}} team at {{b}}{{project}}{{/b}}.", "emails.invitation.footer": "If you are not interested, you can ignore this message.", @@ -56,6 +63,7 @@ "emails.invitation.buttonText": "Accept invite to {{team}}", "emails.invitation.signature": "{{project}} team", "emails.certificate.subject": "Certificate failure for %s", + "emails.certificate.preview": "Your domain %s certificate generation has failed.", "emails.certificate.hello": "Hello,", "emails.certificate.body": "Certificate for your domain '{{domain}}' could not be generated. This is attempt no. {{attempt}}, and the failure was caused by: {{error}}", "emails.certificate.footer": "Your previous certificate will be valid for 30 days since the first failure. We highly recommend investigating this case, otherwise your domain will end up without a valid SSL communication.", diff --git a/app/config/specs/open-api3-1.7.x-client.json b/app/config/specs/open-api3-1.7.x-client.json index d09108e51d..3cf675c5ad 100644 --- a/app/config/specs/open-api3-1.7.x-client.json +++ b/app/config/specs/open-api3-1.7.x-client.json @@ -4467,10 +4467,7 @@ { "name": "createDocument", "auth": { - "Admin": [], - "Session": [], - "Key": [], - "JWT": [] + "Project": [] }, "parameters": [ "databaseId", diff --git a/app/config/specs/open-api3-1.7.x-console.json b/app/config/specs/open-api3-1.7.x-console.json index b7450bc7e6..0bfebf37b9 100644 --- a/app/config/specs/open-api3-1.7.x-console.json +++ b/app/config/specs/open-api3-1.7.x-console.json @@ -8026,10 +8026,7 @@ { "name": "createDocument", "auth": { - "Admin": [], - "Session": [], - "Key": [], - "JWT": [] + "Project": [] }, "parameters": [ "databaseId", @@ -8055,8 +8052,7 @@ { "name": "createDocuments", "auth": { - "Admin": [], - "Key": [] + "Project": [] }, "parameters": [ "databaseId", diff --git a/app/config/specs/open-api3-1.7.x-server.json b/app/config/specs/open-api3-1.7.x-server.json index 8056d5f21b..bd78f99a76 100644 --- a/app/config/specs/open-api3-1.7.x-server.json +++ b/app/config/specs/open-api3-1.7.x-server.json @@ -7507,10 +7507,8 @@ { "name": "createDocument", "auth": { - "Admin": [], - "Session": [], - "Key": [], - "JWT": [] + "Project": [], + "Session": [] }, "parameters": [ "databaseId", @@ -7536,7 +7534,7 @@ { "name": "createDocuments", "auth": { - "Admin": [], + "Project": [], "Key": [] }, "parameters": [ diff --git a/app/config/specs/swagger2-1.7.x-client.json b/app/config/specs/swagger2-1.7.x-client.json index c3353e157f..95d88bb925 100644 --- a/app/config/specs/swagger2-1.7.x-client.json +++ b/app/config/specs/swagger2-1.7.x-client.json @@ -4604,10 +4604,7 @@ { "name": "createDocument", "auth": { - "Admin": [], - "Session": [], - "Key": [], - "JWT": [] + "Project": [] }, "parameters": [ "databaseId", diff --git a/app/config/specs/swagger2-1.7.x-console.json b/app/config/specs/swagger2-1.7.x-console.json index 4fa839aa39..314564477c 100644 --- a/app/config/specs/swagger2-1.7.x-console.json +++ b/app/config/specs/swagger2-1.7.x-console.json @@ -8146,10 +8146,7 @@ { "name": "createDocument", "auth": { - "Admin": [], - "Session": [], - "Key": [], - "JWT": [] + "Project": [] }, "parameters": [ "databaseId", @@ -8175,8 +8172,7 @@ { "name": "createDocuments", "auth": { - "Admin": [], - "Key": [] + "Project": [] }, "parameters": [ "databaseId", diff --git a/app/config/specs/swagger2-1.7.x-server.json b/app/config/specs/swagger2-1.7.x-server.json index 5dc7b6d925..c67d26dd54 100644 --- a/app/config/specs/swagger2-1.7.x-server.json +++ b/app/config/specs/swagger2-1.7.x-server.json @@ -7617,10 +7617,8 @@ { "name": "createDocument", "auth": { - "Admin": [], - "Session": [], - "Key": [], - "JWT": [] + "Project": [], + "Session": [] }, "parameters": [ "databaseId", @@ -7646,7 +7644,7 @@ { "name": "createDocuments", "auth": { - "Admin": [], + "Project": [], "Key": [] }, "parameters": [ diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index dbbff5ce74..fcce0c3a63 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -71,6 +71,7 @@ $oauthDefaultFailure = '/console/auth/oauth2/failure'; function sendSessionAlert(Locale $locale, Document $user, Document $project, Document $session, Mail $queueForMails) { $subject = $locale->getText("emails.sessionAlert.subject"); + $preview = $locale->getText("emails.sessionAlert.preview"); $customTemplate = $project->getAttribute('templates', [])['email.sessionAlert-' . $locale->default] ?? []; $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-session-alert.tpl'); @@ -158,6 +159,7 @@ function sendSessionAlert(Locale $locale, Document $user, Document $project, Doc $queueForMails ->setSubject($subject) + ->setPreview($preview) ->setBody($body) ->setVariables($emailVariables) ->setRecipient($email) @@ -2035,6 +2037,7 @@ App::post('/v1/account/tokens/magic-url') $url = Template::unParseURL($url); $subject = $locale->getText("emails.magicSession.subject"); + $preview = $locale->getText("emails.magicSession.preview"); $customTemplate = $project->getAttribute('templates', [])['email.magicSession-' . $locale->default] ?? []; $detector = new Detector($request->getUserAgent('UNKNOWN')); @@ -2123,6 +2126,7 @@ App::post('/v1/account/tokens/magic-url') $queueForMails ->setSubject($subject) + ->setPreview($preview) ->setBody($body) ->setVariables($emailVariables) ->setRecipient($email) @@ -2264,6 +2268,7 @@ App::post('/v1/account/tokens/email') $dbForProject->purgeCachedDocument('users', $user->getId()); $subject = $locale->getText("emails.otpSession.subject"); + $preview = $locale->getText("emails.otpSession.preview"); $customTemplate = $project->getAttribute('templates', [])['email.otpSession-' . $locale->default] ?? []; $detector = new Detector($request->getUserAgent('UNKNOWN')); @@ -2349,6 +2354,7 @@ App::post('/v1/account/tokens/email') $queueForMails ->setSubject($subject) + ->setPreview($preview) ->setBody($body) ->setVariables($emailVariables) ->setRecipient($email) @@ -3287,6 +3293,7 @@ App::post('/v1/account/recovery') $projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]'); $body = $locale->getText("emails.recovery.body"); $subject = $locale->getText("emails.recovery.subject"); + $preview = $locale->getText("emails.recovery.preview"); $customTemplate = $project->getAttribute('templates', [])['email.recovery-' . $locale->default] ?? []; $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl'); @@ -3361,6 +3368,7 @@ App::post('/v1/account/recovery') ->setBody($body) ->setVariables($emailVariables) ->setSubject($subject) + ->setPreview($preview) ->trigger(); $recovery->setAttribute('secret', $secret); @@ -3542,6 +3550,7 @@ App::post('/v1/account/verification') $projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]'); $body = $locale->getText("emails.verification.body"); + $preview = $locale->getText("emails.verification.preview"); $subject = $locale->getText("emails.verification.subject"); $customTemplate = $project->getAttribute('templates', [])['email.verification-' . $locale->default] ?? []; @@ -3614,6 +3623,7 @@ App::post('/v1/account/verification') $queueForMails ->setSubject($subject) + ->setPreview($preview) ->setBody($body) ->setVariables($emailVariables) ->setRecipient($user->getAttribute('email')) @@ -4459,6 +4469,7 @@ App::post('/v1/account/mfa/challenge') } $subject = $locale->getText("emails.mfaChallenge.subject"); + $preview = $locale->getText("emails.mfaChallenge.preview"); $customTemplate = $project->getAttribute('templates', [])['email.mfaChallenge-' . $locale->default] ?? []; $detector = new Detector($request->getUserAgent('UNKNOWN')); @@ -4535,6 +4546,7 @@ App::post('/v1/account/mfa/challenge') $queueForMails ->setSubject($subject) + ->setPreview($preview) ->setBody($body) ->setVariables($emailVariables) ->setRecipient($user->getAttribute('email')) diff --git a/app/controllers/api/health.php b/app/controllers/api/health.php index 43368b8d3f..39ebae9590 100644 --- a/app/controllers/api/health.php +++ b/app/controllers/api/health.php @@ -522,17 +522,11 @@ App::get('/v1/health/queue/databases') )) ->param('name', 'database_db_main', new Text(256), 'Queue name for which to check the queue size', true) ->param('threshold', 5000, new Integer(true), 'Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.', true) - ->inject('publisher') - ->inject('publisherRedis') + ->inject('publisherDatabases') ->inject('response') - ->action(function (string $name, int|string $threshold, Publisher $publisher, ?Publisher $publisherRedis, Response $response) { + ->action(function (string $name, int|string $threshold, Publisher $publisherDatabases, Response $response) { $threshold = \intval($threshold); - - $isRedisFallback = \str_contains(System::getEnv('_APP_WORKER_REDIS_FALLBACK', ''), 'databases'); - - $size = $isRedisFallback - ? $publisherRedis->getQueueSize(new Queue($name)) - : $publisher->getQueueSize(new Queue($name)); + $size = $publisherDatabases->getQueueSize(new Queue($name)); if ($size >= $threshold) { throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}."); @@ -659,17 +653,12 @@ App::get('/v1/health/queue/migrations') contentType: ContentType::JSON )) ->param('threshold', 5000, new Integer(true), 'Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.', true) - ->inject('publisher') - ->inject('publisherRedis') + ->inject('publisherMigrations') ->inject('response') - ->action(function (int|string $threshold, Publisher $publisher, ?Publisher $publisherRedis, Response $response) { + ->action(function (int|string $threshold, Publisher $publisherMigrations, Response $response) { $threshold = \intval($threshold); - $isRedisFallback = \str_contains(System::getEnv('_APP_WORKER_REDIS_FALLBACK', ''), 'migrations'); - - $size = $isRedisFallback - ? $publisherRedis->getQueueSize(new Queue(Event::MIGRATIONS_QUEUE_NAME)) - : $publisher->getQueueSize(new Queue(Event::MIGRATIONS_QUEUE_NAME)); + $size = $publisherMigrations->getQueueSize(new Queue(Event::MIGRATIONS_QUEUE_NAME)); if ($size >= $threshold) { throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}."); diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index c6e242296b..480f6c63c6 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -1870,7 +1870,7 @@ App::get('/v1/storage/usage') $total = []; Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats, &$total) { foreach ($metrics as $metric) { - $result = $dbForProject->findOne('stats', [ + $result = $dbForProject->findOne('stats', [ Query::equal('metric', [$metric]), Query::equal('period', ['inf']) ]); @@ -1899,7 +1899,7 @@ App::get('/v1/storage/usage') }; foreach ($metrics as $metric) { - $usage[$metric]['total'] = $stats[$metric]['total']; + $usage[$metric]['total'] = $stats[$metric]['total']; $usage[$metric]['data'] = []; $leap = time() - ($days['limit'] * $days['factor']); while ($leap < time()) { @@ -1917,8 +1917,8 @@ App::get('/v1/storage/usage') 'filesTotal' => $usage[$metrics[1]]['total'], 'filesStorageTotal' => $usage[$metrics[2]]['total'], 'buckets' => $usage[$metrics[0]]['data'], - 'files' => $usage[$metrics[1]]['data'], - 'storage' => $usage[$metrics[2]]['data'], + 'files' => $usage[$metrics[1]]['data'], + 'storage' => $usage[$metrics[2]]['data'], ]), Response::MODEL_USAGE_STORAGE); }); @@ -1970,7 +1970,7 @@ App::get('/v1/storage/:bucketId/usage') ? $dbForLogs : $dbForProject; - $result = $db->findOne('stats', [ + $result = $db->findOne('stats', [ Query::equal('metric', [$metric]), Query::equal('period', ['inf']) ]); @@ -2000,7 +2000,7 @@ App::get('/v1/storage/:bucketId/usage') }; foreach ($metrics as $metric) { - $usage[$metric]['total'] = $stats[$metric]['total']; + $usage[$metric]['total'] = $stats[$metric]['total']; $usage[$metric]['data'] = []; $leap = time() - ($days['limit'] * $days['factor']); while ($leap < time()) { diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 98ec49ca48..fe411d53ab 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -657,6 +657,7 @@ App::post('/v1/teams/:teamId/memberships') $projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]'); $body = $locale->getText("emails.invitation.body"); + $preview = $locale->getText("emails.invitation.preview"); $subject = \sprintf($locale->getText("emails.invitation.subject"), $team->getAttribute('name'), $projectName); $customTemplate = $project->getAttribute('templates', [])['email.invitation-' . $locale->default] ?? []; @@ -729,6 +730,7 @@ App::post('/v1/teams/:teamId/memberships') $queueForMails ->setSubject($subject) ->setBody($body) + ->setPreview($preview) ->setRecipient($invitee->getAttribute('email')) ->setName($invitee->getAttribute('name', '')) ->setVariables($emailVariables) diff --git a/app/controllers/api/vcs.php b/app/controllers/api/vcs.php index a8efd093b5..9271e87448 100644 --- a/app/controllers/api/vcs.php +++ b/app/controllers/api/vcs.php @@ -1137,6 +1137,7 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories/:pro $repository['pushedAt'] = $repository['pushed_at'] ?? ''; $repository['organization'] = $installation->getAttribute('organization', ''); $repository['provider'] = $installation->getAttribute('provider', ''); + $repository['defaultBranch'] = $repository['default_branch'] ?? ''; $response->dynamic(new Document($repository), Response::MODEL_PROVIDER_REPOSITORY); }); @@ -1234,7 +1235,8 @@ App::post('/v1/vcs/github/events') $providerRepositoryUrl = $parsedPayload["repositoryUrl"] ?? ''; $providerCommitHash = $parsedPayload["commitHash"] ?? ''; $providerRepositoryOwner = $parsedPayload["owner"] ?? ''; - $providerCommitAuthor = $parsedPayload["headCommitAuthor"] ?? ''; + $providerCommitAuthorName = $parsedPayload["headCommitAuthorName"] ?? ''; + $providerCommitAuthorEmail = $parsedPayload["headCommitAuthorEmail"] ?? ''; $providerCommitAuthorUrl = $parsedPayload["authorUrl"] ?? ''; $providerCommitMessage = $parsedPayload["headCommitMessage"] ?? ''; $providerCommitUrl = $parsedPayload["headCommitUrl"] ?? ''; @@ -1247,9 +1249,9 @@ App::post('/v1/vcs/github/events') Query::limit(100), ])); - // create new deployment only on push and not when branch is created or deleted - if (!$providerBranchCreated && !$providerBranchDeleted) { - $createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthor, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, '', false, $dbForPlatform, $queueForBuilds, $getProjectDB, $request); + // create new deployment only on push (not committed by us) and not when branch is created or deleted + if ($providerCommitAuthorEmail !== APP_VCS_GITHUB_EMAIL && !$providerBranchCreated && !$providerBranchDeleted) { + $createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthorName, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, '', false, $dbForPlatform, $queueForBuilds, $getProjectDB, $request); } } elseif ($event == $github::EVENT_INSTALLATION) { if ($parsedPayload["action"] == "deleted") { diff --git a/app/init/constants.php b/app/init/constants.php index 0e69dd737c..f2f9f82698 100644 --- a/app/init/constants.php +++ b/app/init/constants.php @@ -80,6 +80,8 @@ const APP_COMPUTE_SPECIFICATION_DEFAULT = Specification::S_1VCPU_512MB; const APP_PLATFORM_SERVER = 'server'; const APP_PLATFORM_CLIENT = 'client'; const APP_PLATFORM_CONSOLE = 'console'; +const APP_VCS_GITHUB_USERNAME = 'Appwrite'; +const APP_VCS_GITHUB_EMAIL = 'team@appwrite.io'; // Database Reconnect const DATABASE_RECONNECT_SLEEP = 2; diff --git a/app/init/resources.php b/app/init/resources.php index b75c32cba0..0193da60b1 100644 --- a/app/init/resources.php +++ b/app/init/resources.php @@ -80,15 +80,27 @@ App::setResource('localeCodes', function () { App::setResource('publisher', function (Group $pools) { return new BrokerPool(publisher: $pools->get('publisher')); }, ['pools']); -App::setResource('publisherRedis', function () { - // Stub -}); +App::setResource('publisherDatabases', function (BrokerPool $publisher) { + return $publisher; +}, ['publisher']); +App::setResource('publisherMigrations', function (BrokerPool $publisher) { + return $publisher; +}, ['publisher']); +App::setResource('publisherStatsUsage', function (BrokerPool $publisher) { + return $publisher; +}, ['publisher']); App::setResource('consumer', function (Group $pools) { return new BrokerPool(consumer: $pools->get('consumer')); }, ['pools']); -App::setResource('consumerRedis', function () { - // Stub -}); +App::setResource('consumerDatabases', function (BrokerPool $consumer) { + return $consumer; +}, ['consumer']); +App::setResource('consumerMigrations', function (BrokerPool $consumer) { + return $consumer; +}, ['publisher']); +App::setResource('consumerStatsUsage', function (BrokerPool $consumer) { + return $consumer; +}, ['publisher']); App::setResource('queueForMessaging', function (Publisher $publisher) { return new Messaging($publisher); }, ['publisher']); diff --git a/app/worker.php b/app/worker.php index 4f0f569a9e..90f3368fe7 100644 --- a/app/worker.php +++ b/app/worker.php @@ -247,17 +247,33 @@ Server::setResource('publisher', function (Group $pools) { return new BrokerPool(publisher: $pools->get('publisher')); }, ['pools']); -Server::setResource('publisherRedis', function () { - // Stub -}); +Server::setResource('publisherDatabases', function (BrokerPool $publisher) { + return $publisher; +}, ['publisher']); + +Server::setResource('publisherMigrations', function (BrokerPool $publisher) { + return $publisher; +}, ['publisher']); + +Server::setResource('publisherStatsUsage', function (BrokerPool $publisher) { + return $publisher; +}, ['publisher']); Server::setResource('consumer', function (Group $pools) { return new BrokerPool(consumer: $pools->get('consumer')); }, ['pools']); -Server::setResource('consumerRedis', function () { - // Stub -}); +Server::setResource('consumerDatabases', function (BrokerPool $consumer) { + return $consumer; +}, ['consumer']); + +Server::setResource('consumerMigrations', function (BrokerPool $consumer) { + return $consumer; +}, ['consumer']); + +Server::setResource('consumerStatsUsage', function (BrokerPool $consumer) { + return $consumer; +}, ['consumer']); Server::setResource('queueForStatsUsage', function (Publisher $publisher) { return new StatsUsage($publisher); diff --git a/composer.json b/composer.json index 1ebd6716e3..aca7b9cda5 100644 --- a/composer.json +++ b/composer.json @@ -73,7 +73,7 @@ "utopia-php/swoole": "0.8.*", "utopia-php/system": "0.9.*", "utopia-php/telemetry": "0.1.*", - "utopia-php/vcs": "0.10.*", + "utopia-php/vcs": "0.11.*", "utopia-php/websocket": "0.3.*", "matomo/device-detector": "6.1.*", "dragonmantank/cron-expression": "3.3.*", diff --git a/composer.lock b/composer.lock index 618c8c704e..a5207b2590 100644 --- a/composer.lock +++ b/composer.lock @@ -4587,16 +4587,16 @@ }, { "name": "utopia-php/vcs", - "version": "0.10.5", + "version": "0.11.0", "source": { "type": "git", "url": "https://github.com/utopia-php/vcs.git", - "reference": "b358439dc387f6097019eb83ebb9fc258fe9da05" + "reference": "0e665eaa7d906168525bf6aac50b6bcc3e4fe528" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/vcs/zipball/b358439dc387f6097019eb83ebb9fc258fe9da05", - "reference": "b358439dc387f6097019eb83ebb9fc258fe9da05", + "url": "https://api.github.com/repos/utopia-php/vcs/zipball/0e665eaa7d906168525bf6aac50b6bcc3e4fe528", + "reference": "0e665eaa7d906168525bf6aac50b6bcc3e4fe528", "shasum": "" }, "require": { @@ -4630,9 +4630,9 @@ ], "support": { "issues": "https://github.com/utopia-php/vcs/issues", - "source": "https://github.com/utopia-php/vcs/tree/0.10.5" + "source": "https://github.com/utopia-php/vcs/tree/0.11.0" }, - "time": "2025-06-10T15:01:16+00:00" + "time": "2025-07-23T13:54:58+00:00" }, { "name": "utopia-php/websocket", diff --git a/docs/examples/1.7.x/client-android/java/databases/create-document.md b/docs/examples/1.7.x/client-android/java/databases/create-document.md index 7fb129bb0b..4804d751e3 100644 --- a/docs/examples/1.7.x/client-android/java/databases/create-document.md +++ b/docs/examples/1.7.x/client-android/java/databases/create-document.md @@ -4,9 +4,7 @@ import io.appwrite.services.Databases; Client client = new Client(context) .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint - .setSession("") // The user session to authenticate with - .setKey("") // - .setJWT(""); // Your secret JSON Web Token + .setProject(""); // Your project ID Databases databases = new Databases(client); diff --git a/docs/examples/1.7.x/client-android/java/databases/decrement-document-attribute.md b/docs/examples/1.7.x/client-android/java/databases/decrement-document-attribute.md new file mode 100644 index 0000000000..de6a4ab48d --- /dev/null +++ b/docs/examples/1.7.x/client-android/java/databases/decrement-document-attribute.md @@ -0,0 +1,27 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client(context) + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject(""); // Your project ID + +Databases databases = new Databases(client); + +databases.decrementDocumentAttribute( + "", // databaseId + "", // collectionId + "", // documentId + "", // attribute + 0, // value (optional) + 0, // min (optional) + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); + diff --git a/docs/examples/1.7.x/client-android/java/databases/increment-document-attribute.md b/docs/examples/1.7.x/client-android/java/databases/increment-document-attribute.md new file mode 100644 index 0000000000..94ffa9d749 --- /dev/null +++ b/docs/examples/1.7.x/client-android/java/databases/increment-document-attribute.md @@ -0,0 +1,27 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client(context) + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject(""); // Your project ID + +Databases databases = new Databases(client); + +databases.incrementDocumentAttribute( + "", // databaseId + "", // collectionId + "", // documentId + "", // attribute + 0, // value (optional) + 0, // max (optional) + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); + diff --git a/docs/examples/1.7.x/client-android/kotlin/databases/create-document.md b/docs/examples/1.7.x/client-android/kotlin/databases/create-document.md index 0bafb315e7..849a636afb 100644 --- a/docs/examples/1.7.x/client-android/kotlin/databases/create-document.md +++ b/docs/examples/1.7.x/client-android/kotlin/databases/create-document.md @@ -4,9 +4,7 @@ import io.appwrite.services.Databases val client = Client(context) .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint - .setSession("") // The user session to authenticate with - .setKey("") // - .setJWT("") // Your secret JSON Web Token + .setProject("") // Your project ID val databases = Databases(client) diff --git a/docs/examples/1.7.x/client-android/kotlin/databases/decrement-document-attribute.md b/docs/examples/1.7.x/client-android/kotlin/databases/decrement-document-attribute.md new file mode 100644 index 0000000000..c500fa8687 --- /dev/null +++ b/docs/examples/1.7.x/client-android/kotlin/databases/decrement-document-attribute.md @@ -0,0 +1,18 @@ +import io.appwrite.Client +import io.appwrite.coroutines.CoroutineCallback +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + +val databases = Databases(client) + +val result = databases.decrementDocumentAttribute( + databaseId = "", + collectionId = "", + documentId = "", + attribute = "", + value = 0, // (optional) + min = 0, // (optional) +) \ No newline at end of file diff --git a/docs/examples/1.7.x/client-android/kotlin/databases/increment-document-attribute.md b/docs/examples/1.7.x/client-android/kotlin/databases/increment-document-attribute.md new file mode 100644 index 0000000000..0ae6b02d3d --- /dev/null +++ b/docs/examples/1.7.x/client-android/kotlin/databases/increment-document-attribute.md @@ -0,0 +1,18 @@ +import io.appwrite.Client +import io.appwrite.coroutines.CoroutineCallback +import io.appwrite.services.Databases + +val client = Client(context) + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + +val databases = Databases(client) + +val result = databases.incrementDocumentAttribute( + databaseId = "", + collectionId = "", + documentId = "", + attribute = "", + value = 0, // (optional) + max = 0, // (optional) +) \ No newline at end of file diff --git a/docs/examples/1.7.x/client-apple/examples/databases/create-document.md b/docs/examples/1.7.x/client-apple/examples/databases/create-document.md index 6c2baee728..51adb64bb3 100644 --- a/docs/examples/1.7.x/client-apple/examples/databases/create-document.md +++ b/docs/examples/1.7.x/client-apple/examples/databases/create-document.md @@ -2,9 +2,7 @@ import Appwrite let client = Client() .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint - .setSession("") // The user session to authenticate with - .setKey("") // - .setJWT("") // Your secret JSON Web Token + .setProject("") // Your project ID let databases = Databases(client) diff --git a/docs/examples/1.7.x/client-apple/examples/databases/decrement-document-attribute.md b/docs/examples/1.7.x/client-apple/examples/databases/decrement-document-attribute.md new file mode 100644 index 0000000000..8ef2637bf2 --- /dev/null +++ b/docs/examples/1.7.x/client-apple/examples/databases/decrement-document-attribute.md @@ -0,0 +1,17 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + +let databases = Databases(client) + +let document = try await databases.decrementDocumentAttribute( + databaseId: "", + collectionId: "", + documentId: "", + attribute: "", + value: 0, // optional + min: 0 // optional +) + diff --git a/docs/examples/1.7.x/client-apple/examples/databases/increment-document-attribute.md b/docs/examples/1.7.x/client-apple/examples/databases/increment-document-attribute.md new file mode 100644 index 0000000000..f64b2cd76c --- /dev/null +++ b/docs/examples/1.7.x/client-apple/examples/databases/increment-document-attribute.md @@ -0,0 +1,17 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + +let databases = Databases(client) + +let document = try await databases.incrementDocumentAttribute( + databaseId: "", + collectionId: "", + documentId: "", + attribute: "", + value: 0, // optional + max: 0 // optional +) + diff --git a/docs/examples/1.7.x/client-flutter/examples/databases/create-document.md b/docs/examples/1.7.x/client-flutter/examples/databases/create-document.md index 4f286fff95..27efc34580 100644 --- a/docs/examples/1.7.x/client-flutter/examples/databases/create-document.md +++ b/docs/examples/1.7.x/client-flutter/examples/databases/create-document.md @@ -2,9 +2,7 @@ import 'package:appwrite/appwrite.dart'; Client client = Client() .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - .setSession('') // The user session to authenticate with - .setKey('') // - .setJWT(''); // Your secret JSON Web Token + .setProject(''); // Your project ID Databases databases = Databases(client); diff --git a/docs/examples/1.7.x/client-flutter/examples/databases/decrement-document-attribute.md b/docs/examples/1.7.x/client-flutter/examples/databases/decrement-document-attribute.md new file mode 100644 index 0000000000..ec0d9ee300 --- /dev/null +++ b/docs/examples/1.7.x/client-flutter/examples/databases/decrement-document-attribute.md @@ -0,0 +1,16 @@ +import 'package:appwrite/appwrite.dart'; + +Client client = Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +Databases databases = Databases(client); + +Document result = await databases.decrementDocumentAttribute( + databaseId: '', + collectionId: '', + documentId: '', + attribute: '', + value: 0, // optional + min: 0, // optional +); diff --git a/docs/examples/1.7.x/client-flutter/examples/databases/increment-document-attribute.md b/docs/examples/1.7.x/client-flutter/examples/databases/increment-document-attribute.md new file mode 100644 index 0000000000..78f5b0cb6f --- /dev/null +++ b/docs/examples/1.7.x/client-flutter/examples/databases/increment-document-attribute.md @@ -0,0 +1,16 @@ +import 'package:appwrite/appwrite.dart'; + +Client client = Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +Databases databases = Databases(client); + +Document result = await databases.incrementDocumentAttribute( + databaseId: '', + collectionId: '', + documentId: '', + attribute: '', + value: 0, // optional + max: 0, // optional +); diff --git a/docs/examples/1.7.x/client-graphql/examples/databases/create-document.md b/docs/examples/1.7.x/client-graphql/examples/databases/create-document.md index 4e2d90660b..4f525d6b1f 100644 --- a/docs/examples/1.7.x/client-graphql/examples/databases/create-document.md +++ b/docs/examples/1.7.x/client-graphql/examples/databases/create-document.md @@ -7,6 +7,7 @@ mutation { permissions: ["read("any")"] ) { _id + _sequence _collectionId _databaseId _createdAt diff --git a/docs/examples/1.7.x/client-graphql/examples/databases/decrement-document-attribute.md b/docs/examples/1.7.x/client-graphql/examples/databases/decrement-document-attribute.md new file mode 100644 index 0000000000..2e7970049d --- /dev/null +++ b/docs/examples/1.7.x/client-graphql/examples/databases/decrement-document-attribute.md @@ -0,0 +1,19 @@ +mutation { + databasesDecrementDocumentAttribute( + databaseId: "", + collectionId: "", + documentId: "", + attribute: "", + value: 0, + min: 0 + ) { + _id + _sequence + _collectionId + _databaseId + _createdAt + _updatedAt + _permissions + data + } +} diff --git a/docs/examples/1.7.x/client-graphql/examples/databases/increment-document-attribute.md b/docs/examples/1.7.x/client-graphql/examples/databases/increment-document-attribute.md new file mode 100644 index 0000000000..322ed69ced --- /dev/null +++ b/docs/examples/1.7.x/client-graphql/examples/databases/increment-document-attribute.md @@ -0,0 +1,19 @@ +mutation { + databasesIncrementDocumentAttribute( + databaseId: "", + collectionId: "", + documentId: "", + attribute: "", + value: 0, + max: 0 + ) { + _id + _sequence + _collectionId + _databaseId + _createdAt + _updatedAt + _permissions + data + } +} diff --git a/docs/examples/1.7.x/client-graphql/examples/databases/update-document.md b/docs/examples/1.7.x/client-graphql/examples/databases/update-document.md index 5e80894620..aea605d9d7 100644 --- a/docs/examples/1.7.x/client-graphql/examples/databases/update-document.md +++ b/docs/examples/1.7.x/client-graphql/examples/databases/update-document.md @@ -7,6 +7,7 @@ mutation { permissions: ["read("any")"] ) { _id + _sequence _collectionId _databaseId _createdAt diff --git a/docs/examples/1.7.x/client-graphql/examples/databases/upsert-document.md b/docs/examples/1.7.x/client-graphql/examples/databases/upsert-document.md index 2ccab1c490..9d1e753081 100644 --- a/docs/examples/1.7.x/client-graphql/examples/databases/upsert-document.md +++ b/docs/examples/1.7.x/client-graphql/examples/databases/upsert-document.md @@ -7,6 +7,7 @@ mutation { permissions: ["read("any")"] ) { _id + _sequence _collectionId _databaseId _createdAt diff --git a/docs/examples/1.7.x/client-react-native/examples/databases/create-document.md b/docs/examples/1.7.x/client-react-native/examples/databases/create-document.md index ec768fcfaf..1b28231ed3 100644 --- a/docs/examples/1.7.x/client-react-native/examples/databases/create-document.md +++ b/docs/examples/1.7.x/client-react-native/examples/databases/create-document.md @@ -2,9 +2,7 @@ import { Client, Databases } from "react-native-appwrite"; const client = new Client() .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - .setSession('') // The user session to authenticate with - .setKey('') // - .setJWT(''); // Your secret JSON Web Token + .setProject(''); // Your project ID const databases = new Databases(client); diff --git a/docs/examples/1.7.x/client-react-native/examples/databases/decrement-document-attribute.md b/docs/examples/1.7.x/client-react-native/examples/databases/decrement-document-attribute.md new file mode 100644 index 0000000000..4c9c2d9923 --- /dev/null +++ b/docs/examples/1.7.x/client-react-native/examples/databases/decrement-document-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "react-native-appwrite"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const databases = new Databases(client); + +const result = await databases.decrementDocumentAttribute( + '', // databaseId + '', // collectionId + '', // documentId + '', // attribute + null, // value (optional) + null // min (optional) +); + +console.log(result); diff --git a/docs/examples/1.7.x/client-react-native/examples/databases/increment-document-attribute.md b/docs/examples/1.7.x/client-react-native/examples/databases/increment-document-attribute.md new file mode 100644 index 0000000000..3a9d94904f --- /dev/null +++ b/docs/examples/1.7.x/client-react-native/examples/databases/increment-document-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "react-native-appwrite"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const databases = new Databases(client); + +const result = await databases.incrementDocumentAttribute( + '', // databaseId + '', // collectionId + '', // documentId + '', // attribute + null, // value (optional) + null // max (optional) +); + +console.log(result); diff --git a/docs/examples/1.7.x/client-rest/examples/databases/decrement-document-attribute.md b/docs/examples/1.7.x/client-rest/examples/databases/decrement-document-attribute.md new file mode 100644 index 0000000000..7f056fb965 --- /dev/null +++ b/docs/examples/1.7.x/client-rest/examples/databases/decrement-document-attribute.md @@ -0,0 +1,12 @@ +PATCH /v1/databases/{databaseId}/collections/{collectionId}/documents/{documentId}/{attribute}/decrement HTTP/1.1 +Host: cloud.appwrite.io +Content-Type: application/json +X-Appwrite-Response-Format: 1.7.0 +X-Appwrite-Project: +X-Appwrite-Session: +X-Appwrite-JWT: + +{ + "value": 0, + "min": 0 +} diff --git a/docs/examples/1.7.x/client-rest/examples/databases/increment-document-attribute.md b/docs/examples/1.7.x/client-rest/examples/databases/increment-document-attribute.md new file mode 100644 index 0000000000..002d10238b --- /dev/null +++ b/docs/examples/1.7.x/client-rest/examples/databases/increment-document-attribute.md @@ -0,0 +1,12 @@ +PATCH /v1/databases/{databaseId}/collections/{collectionId}/documents/{documentId}/{attribute}/increment HTTP/1.1 +Host: cloud.appwrite.io +Content-Type: application/json +X-Appwrite-Response-Format: 1.7.0 +X-Appwrite-Project: +X-Appwrite-Session: +X-Appwrite-JWT: + +{ + "value": 0, + "max": 0 +} diff --git a/docs/examples/1.7.x/client-web/examples/databases/create-document.md b/docs/examples/1.7.x/client-web/examples/databases/create-document.md index 401a67488c..916cc92689 100644 --- a/docs/examples/1.7.x/client-web/examples/databases/create-document.md +++ b/docs/examples/1.7.x/client-web/examples/databases/create-document.md @@ -2,9 +2,7 @@ import { Client, Databases } from "appwrite"; const client = new Client() .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - .setSession('') // The user session to authenticate with - .setKey('') // - .setJWT(''); // Your secret JSON Web Token + .setProject(''); // Your project ID const databases = new Databases(client); diff --git a/docs/examples/1.7.x/client-web/examples/databases/decrement-document-attribute.md b/docs/examples/1.7.x/client-web/examples/databases/decrement-document-attribute.md new file mode 100644 index 0000000000..10d785a9a8 --- /dev/null +++ b/docs/examples/1.7.x/client-web/examples/databases/decrement-document-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "appwrite"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const databases = new Databases(client); + +const result = await databases.decrementDocumentAttribute( + '', // databaseId + '', // collectionId + '', // documentId + '', // attribute + null, // value (optional) + null // min (optional) +); + +console.log(result); diff --git a/docs/examples/1.7.x/client-web/examples/databases/increment-document-attribute.md b/docs/examples/1.7.x/client-web/examples/databases/increment-document-attribute.md new file mode 100644 index 0000000000..4b32be959c --- /dev/null +++ b/docs/examples/1.7.x/client-web/examples/databases/increment-document-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "appwrite"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const databases = new Databases(client); + +const result = await databases.incrementDocumentAttribute( + '', // databaseId + '', // collectionId + '', // documentId + '', // attribute + null, // value (optional) + null // max (optional) +); + +console.log(result); diff --git a/docs/examples/1.7.x/console-cli/examples/databases/decrement-document-attribute.md b/docs/examples/1.7.x/console-cli/examples/databases/decrement-document-attribute.md new file mode 100644 index 0000000000..e6607ea833 --- /dev/null +++ b/docs/examples/1.7.x/console-cli/examples/databases/decrement-document-attribute.md @@ -0,0 +1,7 @@ +appwrite databases decrementDocumentAttribute \ + --databaseId \ + --collectionId \ + --documentId \ + --attribute '' \ + + diff --git a/docs/examples/1.7.x/console-cli/examples/databases/increment-document-attribute.md b/docs/examples/1.7.x/console-cli/examples/databases/increment-document-attribute.md new file mode 100644 index 0000000000..8a5150eebd --- /dev/null +++ b/docs/examples/1.7.x/console-cli/examples/databases/increment-document-attribute.md @@ -0,0 +1,7 @@ +appwrite databases incrementDocumentAttribute \ + --databaseId \ + --collectionId \ + --documentId \ + --attribute '' \ + + diff --git a/docs/examples/1.7.x/console-web/examples/databases/create-document.md b/docs/examples/1.7.x/console-web/examples/databases/create-document.md index 4524017dd5..1b96d07899 100644 --- a/docs/examples/1.7.x/console-web/examples/databases/create-document.md +++ b/docs/examples/1.7.x/console-web/examples/databases/create-document.md @@ -2,9 +2,7 @@ import { Client, Databases } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - .setSession('') // - .setKey('') // Your secret API key - .setJWT(''); // Your secret JSON Web Token + .setProject(''); // Your project ID const databases = new Databases(client); diff --git a/docs/examples/1.7.x/console-web/examples/databases/create-documents.md b/docs/examples/1.7.x/console-web/examples/databases/create-documents.md index 9651a99775..09f3007208 100644 --- a/docs/examples/1.7.x/console-web/examples/databases/create-documents.md +++ b/docs/examples/1.7.x/console-web/examples/databases/create-documents.md @@ -2,7 +2,7 @@ import { Client, Databases } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - .setKey(''); // Your secret API key + .setProject(''); // Your project ID const databases = new Databases(client); diff --git a/docs/examples/1.7.x/console-web/examples/databases/decrement-document-attribute.md b/docs/examples/1.7.x/console-web/examples/databases/decrement-document-attribute.md new file mode 100644 index 0000000000..f090f53b49 --- /dev/null +++ b/docs/examples/1.7.x/console-web/examples/databases/decrement-document-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const databases = new Databases(client); + +const result = await databases.decrementDocumentAttribute( + '', // databaseId + '', // collectionId + '', // documentId + '', // attribute + null, // value (optional) + null // min (optional) +); + +console.log(result); diff --git a/docs/examples/1.7.x/console-web/examples/databases/increment-document-attribute.md b/docs/examples/1.7.x/console-web/examples/databases/increment-document-attribute.md new file mode 100644 index 0000000000..62ebd6fe3c --- /dev/null +++ b/docs/examples/1.7.x/console-web/examples/databases/increment-document-attribute.md @@ -0,0 +1,18 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const databases = new Databases(client); + +const result = await databases.incrementDocumentAttribute( + '', // databaseId + '', // collectionId + '', // documentId + '', // attribute + null, // value (optional) + null // max (optional) +); + +console.log(result); diff --git a/docs/examples/1.7.x/console-web/examples/databases/upsert-document.md b/docs/examples/1.7.x/console-web/examples/databases/upsert-document.md new file mode 100644 index 0000000000..3b89ed3aef --- /dev/null +++ b/docs/examples/1.7.x/console-web/examples/databases/upsert-document.md @@ -0,0 +1,17 @@ +import { Client, Databases } from "@appwrite.io/console"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const databases = new Databases(client); + +const result = await databases.upsertDocument( + '', // databaseId + '', // collectionId + '', // documentId + {}, // data + ["read("any")"] // permissions (optional) +); + +console.log(result); diff --git a/docs/examples/1.7.x/console-web/examples/databases/upsert-documents.md b/docs/examples/1.7.x/console-web/examples/databases/upsert-documents.md index c58bd1e99c..2d12f7caec 100644 --- a/docs/examples/1.7.x/console-web/examples/databases/upsert-documents.md +++ b/docs/examples/1.7.x/console-web/examples/databases/upsert-documents.md @@ -9,7 +9,7 @@ const databases = new Databases(client); const result = await databases.upsertDocuments( '', // databaseId '', // collectionId - [] // documents (optional) + [] // documents ); console.log(result); diff --git a/docs/examples/1.7.x/console-web/examples/proxy/create-redirect-rule.md b/docs/examples/1.7.x/console-web/examples/proxy/create-redirect-rule.md index 43b3f79d8a..294e496987 100644 --- a/docs/examples/1.7.x/console-web/examples/proxy/create-redirect-rule.md +++ b/docs/examples/1.7.x/console-web/examples/proxy/create-redirect-rule.md @@ -1,4 +1,4 @@ -import { Client, Proxy, } from "@appwrite.io/console"; +import { Client, Proxy, , ProxyResourceType } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint @@ -9,7 +9,9 @@ const proxy = new Proxy(client); const result = await proxy.createRedirectRule( '', // domain 'https://example.com', // url - .MovedPermanently301 // statusCode + .MovedPermanently301, // statusCode + '', // resourceId + ProxyResourceType.Site // resourceType ); console.log(result); diff --git a/docs/examples/1.7.x/console-web/examples/vcs/get-repository-contents.md b/docs/examples/1.7.x/console-web/examples/vcs/get-repository-contents.md index 8a04ba1ae4..6d0cbd19ee 100644 --- a/docs/examples/1.7.x/console-web/examples/vcs/get-repository-contents.md +++ b/docs/examples/1.7.x/console-web/examples/vcs/get-repository-contents.md @@ -9,7 +9,8 @@ const vcs = new Vcs(client); const result = await vcs.getRepositoryContents( '', // installationId '', // providerRepositoryId - '' // providerRootDirectory (optional) + '', // providerRootDirectory (optional) + '' // providerReference (optional) ); console.log(result); diff --git a/docs/examples/1.7.x/server-dart/examples/databases/create-document.md b/docs/examples/1.7.x/server-dart/examples/databases/create-document.md index 1c9af5112c..1d58fc586c 100644 --- a/docs/examples/1.7.x/server-dart/examples/databases/create-document.md +++ b/docs/examples/1.7.x/server-dart/examples/databases/create-document.md @@ -2,9 +2,8 @@ import 'package:dart_appwrite/dart_appwrite.dart'; Client client = Client() .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - .setSession('') // The user session to authenticate with - .setKey('') // Your secret API key - .setJWT(''); // Your secret JSON Web Token + .setProject('') // Your project ID + .setSession(''); // The user session to authenticate with Databases databases = Databases(client); diff --git a/docs/examples/1.7.x/server-dart/examples/databases/create-documents.md b/docs/examples/1.7.x/server-dart/examples/databases/create-documents.md index 7b4409a0b1..ba0e34950b 100644 --- a/docs/examples/1.7.x/server-dart/examples/databases/create-documents.md +++ b/docs/examples/1.7.x/server-dart/examples/databases/create-documents.md @@ -2,6 +2,7 @@ import 'package:dart_appwrite/dart_appwrite.dart'; Client client = Client() .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject('') // Your project ID .setKey(''); // Your secret API key Databases databases = Databases(client); diff --git a/docs/examples/1.7.x/server-dart/examples/databases/decrement-document-attribute.md b/docs/examples/1.7.x/server-dart/examples/databases/decrement-document-attribute.md new file mode 100644 index 0000000000..c8ec38dab8 --- /dev/null +++ b/docs/examples/1.7.x/server-dart/examples/databases/decrement-document-attribute.md @@ -0,0 +1,17 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +Client client = Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject('') // Your project ID + .setKey(''); // Your secret API key + +Databases databases = Databases(client); + +Document result = await databases.decrementDocumentAttribute( + databaseId: '', + collectionId: '', + documentId: '', + attribute: '', + value: 0, // (optional) + min: 0, // (optional) +); diff --git a/docs/examples/1.7.x/server-dart/examples/databases/increment-document-attribute.md b/docs/examples/1.7.x/server-dart/examples/databases/increment-document-attribute.md new file mode 100644 index 0000000000..6e5134b03a --- /dev/null +++ b/docs/examples/1.7.x/server-dart/examples/databases/increment-document-attribute.md @@ -0,0 +1,17 @@ +import 'package:dart_appwrite/dart_appwrite.dart'; + +Client client = Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject('') // Your project ID + .setKey(''); // Your secret API key + +Databases databases = Databases(client); + +Document result = await databases.incrementDocumentAttribute( + databaseId: '', + collectionId: '', + documentId: '', + attribute: '', + value: 0, // (optional) + max: 0, // (optional) +); diff --git a/docs/examples/1.7.x/server-deno/examples/databases/create-document.md b/docs/examples/1.7.x/server-deno/examples/databases/create-document.md index f18b4f30dc..be8a1bdac9 100644 --- a/docs/examples/1.7.x/server-deno/examples/databases/create-document.md +++ b/docs/examples/1.7.x/server-deno/examples/databases/create-document.md @@ -2,9 +2,8 @@ import { Client, Databases } from "https://deno.land/x/appwrite/mod.ts"; const client = new Client() .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - .setSession('') // The user session to authenticate with - .setKey('') // Your secret API key - .setJWT(''); // Your secret JSON Web Token + .setProject('') // Your project ID + .setSession(''); // The user session to authenticate with const databases = new Databases(client); diff --git a/docs/examples/1.7.x/server-deno/examples/databases/create-documents.md b/docs/examples/1.7.x/server-deno/examples/databases/create-documents.md index f5e320e193..26c9796cf0 100644 --- a/docs/examples/1.7.x/server-deno/examples/databases/create-documents.md +++ b/docs/examples/1.7.x/server-deno/examples/databases/create-documents.md @@ -2,6 +2,7 @@ import { Client, Databases } from "https://deno.land/x/appwrite/mod.ts"; const client = new Client() .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject('') // Your project ID .setKey(''); // Your secret API key const databases = new Databases(client); diff --git a/docs/examples/1.7.x/server-deno/examples/databases/decrement-document-attribute.md b/docs/examples/1.7.x/server-deno/examples/databases/decrement-document-attribute.md new file mode 100644 index 0000000000..0142188185 --- /dev/null +++ b/docs/examples/1.7.x/server-deno/examples/databases/decrement-document-attribute.md @@ -0,0 +1,17 @@ +import { Client, Databases } from "https://deno.land/x/appwrite/mod.ts"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject('') // Your project ID + .setKey(''); // Your secret API key + +const databases = new Databases(client); + +const response = await databases.decrementDocumentAttribute( + '', // databaseId + '', // collectionId + '', // documentId + '', // attribute + null, // value (optional) + null // min (optional) +); diff --git a/docs/examples/1.7.x/server-deno/examples/databases/increment-document-attribute.md b/docs/examples/1.7.x/server-deno/examples/databases/increment-document-attribute.md new file mode 100644 index 0000000000..9202a94bb9 --- /dev/null +++ b/docs/examples/1.7.x/server-deno/examples/databases/increment-document-attribute.md @@ -0,0 +1,17 @@ +import { Client, Databases } from "https://deno.land/x/appwrite/mod.ts"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject('') // Your project ID + .setKey(''); // Your secret API key + +const databases = new Databases(client); + +const response = await databases.incrementDocumentAttribute( + '', // databaseId + '', // collectionId + '', // documentId + '', // attribute + null, // value (optional) + null // max (optional) +); diff --git a/docs/examples/1.7.x/server-deno/examples/databases/upsert-document.md b/docs/examples/1.7.x/server-deno/examples/databases/upsert-document.md new file mode 100644 index 0000000000..f05100e3df --- /dev/null +++ b/docs/examples/1.7.x/server-deno/examples/databases/upsert-document.md @@ -0,0 +1,16 @@ +import { Client, Databases } from "https://deno.land/x/appwrite/mod.ts"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject('') // Your project ID + .setSession(''); // The user session to authenticate with + +const databases = new Databases(client); + +const response = await databases.upsertDocument( + '', // databaseId + '', // collectionId + '', // documentId + {}, // data + ["read("any")"] // permissions (optional) +); diff --git a/docs/examples/1.7.x/server-deno/examples/databases/upsert-documents.md b/docs/examples/1.7.x/server-deno/examples/databases/upsert-documents.md index c0ee477875..0cd804bfb6 100644 --- a/docs/examples/1.7.x/server-deno/examples/databases/upsert-documents.md +++ b/docs/examples/1.7.x/server-deno/examples/databases/upsert-documents.md @@ -10,5 +10,5 @@ const databases = new Databases(client); const response = await databases.upsertDocuments( '', // databaseId '', // collectionId - [] // documents (optional) + [] // documents ); diff --git a/docs/examples/1.7.x/server-dotnet/examples/databases/create-document.md b/docs/examples/1.7.x/server-dotnet/examples/databases/create-document.md index cb4bc62ced..52254e0c25 100644 --- a/docs/examples/1.7.x/server-dotnet/examples/databases/create-document.md +++ b/docs/examples/1.7.x/server-dotnet/examples/databases/create-document.md @@ -4,9 +4,8 @@ using Appwrite.Services; Client client = new Client() .SetEndPoint("https://.cloud.appwrite.io/v1") // Your API Endpoint - .SetSession("") // The user session to authenticate with - .SetKey("") // Your secret API key - .SetJWT(""); // Your secret JSON Web Token + .SetProject("") // Your project ID + .SetSession(""); // The user session to authenticate with Databases databases = new Databases(client); diff --git a/docs/examples/1.7.x/server-dotnet/examples/databases/create-documents.md b/docs/examples/1.7.x/server-dotnet/examples/databases/create-documents.md index 495a3080fa..dad710f0df 100644 --- a/docs/examples/1.7.x/server-dotnet/examples/databases/create-documents.md +++ b/docs/examples/1.7.x/server-dotnet/examples/databases/create-documents.md @@ -4,6 +4,7 @@ using Appwrite.Services; Client client = new Client() .SetEndPoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("") // Your project ID .SetKey(""); // Your secret API key Databases databases = new Databases(client); diff --git a/docs/examples/1.7.x/server-dotnet/examples/databases/decrement-document-attribute.md b/docs/examples/1.7.x/server-dotnet/examples/databases/decrement-document-attribute.md new file mode 100644 index 0000000000..c327458f61 --- /dev/null +++ b/docs/examples/1.7.x/server-dotnet/examples/databases/decrement-document-attribute.md @@ -0,0 +1,19 @@ +using Appwrite; +using Appwrite.Models; +using Appwrite.Services; + +Client client = new Client() + .SetEndPoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("") // Your project ID + .SetKey(""); // Your secret API key + +Databases databases = new Databases(client); + +Document result = await databases.DecrementDocumentAttribute( + databaseId: "", + collectionId: "", + documentId: "", + attribute: "", + value: 0, // optional + min: 0 // optional +); \ No newline at end of file diff --git a/docs/examples/1.7.x/server-dotnet/examples/databases/increment-document-attribute.md b/docs/examples/1.7.x/server-dotnet/examples/databases/increment-document-attribute.md new file mode 100644 index 0000000000..be52584aaf --- /dev/null +++ b/docs/examples/1.7.x/server-dotnet/examples/databases/increment-document-attribute.md @@ -0,0 +1,19 @@ +using Appwrite; +using Appwrite.Models; +using Appwrite.Services; + +Client client = new Client() + .SetEndPoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("") // Your project ID + .SetKey(""); // Your secret API key + +Databases databases = new Databases(client); + +Document result = await databases.IncrementDocumentAttribute( + databaseId: "", + collectionId: "", + documentId: "", + attribute: "", + value: 0, // optional + max: 0 // optional +); \ No newline at end of file diff --git a/docs/examples/1.7.x/server-go/examples/databases/create-document.md b/docs/examples/1.7.x/server-go/examples/databases/create-document.md index 8990beaa8d..fe96a0d601 100644 --- a/docs/examples/1.7.x/server-go/examples/databases/create-document.md +++ b/docs/examples/1.7.x/server-go/examples/databases/create-document.md @@ -9,9 +9,8 @@ import ( func main() { client := client.New( client.WithEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + client.WithProject("") // Your project ID client.WithSession("") // The user session to authenticate with - client.WithKey("") // Your secret API key - client.WithJWT("") // Your secret JSON Web Token ) service := databases.New(client) diff --git a/docs/examples/1.7.x/server-go/examples/databases/create-documents.md b/docs/examples/1.7.x/server-go/examples/databases/create-documents.md index d9492df5f7..9e4da5dac7 100644 --- a/docs/examples/1.7.x/server-go/examples/databases/create-documents.md +++ b/docs/examples/1.7.x/server-go/examples/databases/create-documents.md @@ -9,6 +9,7 @@ import ( func main() { client := client.New( client.WithEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + client.WithProject("") // Your project ID client.WithKey("") // Your secret API key ) diff --git a/docs/examples/1.7.x/server-go/examples/databases/decrement-document-attribute.md b/docs/examples/1.7.x/server-go/examples/databases/decrement-document-attribute.md new file mode 100644 index 0000000000..1d9c094030 --- /dev/null +++ b/docs/examples/1.7.x/server-go/examples/databases/decrement-document-attribute.md @@ -0,0 +1,31 @@ +package main + +import ( + "fmt" + "github.com/appwrite/sdk-for-go/client" + "github.com/appwrite/sdk-for-go/databases" +) + +func main() { + client := client.New( + client.WithEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + client.WithProject("") // Your project ID + client.WithKey("") // Your secret API key + ) + + service := databases.New(client) + response, error := service.DecrementDocumentAttribute( + "", + "", + "", + "", + databases.WithDecrementDocumentAttributeValue(0), + databases.WithDecrementDocumentAttributeMin(0), + ) + + if error != nil { + panic(error) + } + + fmt.Println(response) +} diff --git a/docs/examples/1.7.x/server-go/examples/databases/increment-document-attribute.md b/docs/examples/1.7.x/server-go/examples/databases/increment-document-attribute.md new file mode 100644 index 0000000000..fa63e9c8df --- /dev/null +++ b/docs/examples/1.7.x/server-go/examples/databases/increment-document-attribute.md @@ -0,0 +1,31 @@ +package main + +import ( + "fmt" + "github.com/appwrite/sdk-for-go/client" + "github.com/appwrite/sdk-for-go/databases" +) + +func main() { + client := client.New( + client.WithEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + client.WithProject("") // Your project ID + client.WithKey("") // Your secret API key + ) + + service := databases.New(client) + response, error := service.IncrementDocumentAttribute( + "", + "", + "", + "", + databases.WithIncrementDocumentAttributeValue(0), + databases.WithIncrementDocumentAttributeMax(0), + ) + + if error != nil { + panic(error) + } + + fmt.Println(response) +} diff --git a/docs/examples/1.7.x/server-go/examples/databases/upsert-documents.md b/docs/examples/1.7.x/server-go/examples/databases/upsert-documents.md index 7e4550d512..d2731cd128 100644 --- a/docs/examples/1.7.x/server-go/examples/databases/upsert-documents.md +++ b/docs/examples/1.7.x/server-go/examples/databases/upsert-documents.md @@ -17,7 +17,7 @@ func main() { response, error := service.UpsertDocuments( "", "", - databases.WithUpsertDocumentsDocuments([]interface{}{}), + []interface{}{}, ) if error != nil { diff --git a/docs/examples/1.7.x/server-graphql/examples/databases/create-document.md b/docs/examples/1.7.x/server-graphql/examples/databases/create-document.md index 4e2d90660b..4f525d6b1f 100644 --- a/docs/examples/1.7.x/server-graphql/examples/databases/create-document.md +++ b/docs/examples/1.7.x/server-graphql/examples/databases/create-document.md @@ -7,6 +7,7 @@ mutation { permissions: ["read("any")"] ) { _id + _sequence _collectionId _databaseId _createdAt diff --git a/docs/examples/1.7.x/server-graphql/examples/databases/create-documents.md b/docs/examples/1.7.x/server-graphql/examples/databases/create-documents.md index 3e3a50f3ab..8ce79dcbb5 100644 --- a/docs/examples/1.7.x/server-graphql/examples/databases/create-documents.md +++ b/docs/examples/1.7.x/server-graphql/examples/databases/create-documents.md @@ -7,6 +7,7 @@ mutation { total documents { _id + _sequence _collectionId _databaseId _createdAt diff --git a/docs/examples/1.7.x/server-graphql/examples/databases/create-string-attribute.md b/docs/examples/1.7.x/server-graphql/examples/databases/create-string-attribute.md index 62d97d6962..489f9ce015 100644 --- a/docs/examples/1.7.x/server-graphql/examples/databases/create-string-attribute.md +++ b/docs/examples/1.7.x/server-graphql/examples/databases/create-string-attribute.md @@ -19,5 +19,6 @@ mutation { _updatedAt size default + encrypt } } diff --git a/docs/examples/1.7.x/server-graphql/examples/databases/decrement-document-attribute.md b/docs/examples/1.7.x/server-graphql/examples/databases/decrement-document-attribute.md new file mode 100644 index 0000000000..2e7970049d --- /dev/null +++ b/docs/examples/1.7.x/server-graphql/examples/databases/decrement-document-attribute.md @@ -0,0 +1,19 @@ +mutation { + databasesDecrementDocumentAttribute( + databaseId: "", + collectionId: "", + documentId: "", + attribute: "", + value: 0, + min: 0 + ) { + _id + _sequence + _collectionId + _databaseId + _createdAt + _updatedAt + _permissions + data + } +} diff --git a/docs/examples/1.7.x/server-graphql/examples/databases/delete-documents.md b/docs/examples/1.7.x/server-graphql/examples/databases/delete-documents.md index ad5826f22a..5822d3b950 100644 --- a/docs/examples/1.7.x/server-graphql/examples/databases/delete-documents.md +++ b/docs/examples/1.7.x/server-graphql/examples/databases/delete-documents.md @@ -7,6 +7,7 @@ mutation { total documents { _id + _sequence _collectionId _databaseId _createdAt diff --git a/docs/examples/1.7.x/server-graphql/examples/databases/increment-document-attribute.md b/docs/examples/1.7.x/server-graphql/examples/databases/increment-document-attribute.md new file mode 100644 index 0000000000..322ed69ced --- /dev/null +++ b/docs/examples/1.7.x/server-graphql/examples/databases/increment-document-attribute.md @@ -0,0 +1,19 @@ +mutation { + databasesIncrementDocumentAttribute( + databaseId: "", + collectionId: "", + documentId: "", + attribute: "", + value: 0, + max: 0 + ) { + _id + _sequence + _collectionId + _databaseId + _createdAt + _updatedAt + _permissions + data + } +} diff --git a/docs/examples/1.7.x/server-graphql/examples/databases/update-document.md b/docs/examples/1.7.x/server-graphql/examples/databases/update-document.md index 5e80894620..aea605d9d7 100644 --- a/docs/examples/1.7.x/server-graphql/examples/databases/update-document.md +++ b/docs/examples/1.7.x/server-graphql/examples/databases/update-document.md @@ -7,6 +7,7 @@ mutation { permissions: ["read("any")"] ) { _id + _sequence _collectionId _databaseId _createdAt diff --git a/docs/examples/1.7.x/server-graphql/examples/databases/update-documents.md b/docs/examples/1.7.x/server-graphql/examples/databases/update-documents.md index c05acb16a0..83c0c07f84 100644 --- a/docs/examples/1.7.x/server-graphql/examples/databases/update-documents.md +++ b/docs/examples/1.7.x/server-graphql/examples/databases/update-documents.md @@ -8,6 +8,7 @@ mutation { total documents { _id + _sequence _collectionId _databaseId _createdAt diff --git a/docs/examples/1.7.x/server-graphql/examples/databases/update-string-attribute.md b/docs/examples/1.7.x/server-graphql/examples/databases/update-string-attribute.md index afafb307f5..f9398c9ca1 100644 --- a/docs/examples/1.7.x/server-graphql/examples/databases/update-string-attribute.md +++ b/docs/examples/1.7.x/server-graphql/examples/databases/update-string-attribute.md @@ -18,5 +18,6 @@ mutation { _updatedAt size default + encrypt } } diff --git a/docs/examples/1.7.x/server-graphql/examples/databases/upsert-document.md b/docs/examples/1.7.x/server-graphql/examples/databases/upsert-document.md new file mode 100644 index 0000000000..9d1e753081 --- /dev/null +++ b/docs/examples/1.7.x/server-graphql/examples/databases/upsert-document.md @@ -0,0 +1,18 @@ +mutation { + databasesUpsertDocument( + databaseId: "", + collectionId: "", + documentId: "", + data: "{}", + permissions: ["read("any")"] + ) { + _id + _sequence + _collectionId + _databaseId + _createdAt + _updatedAt + _permissions + data + } +} diff --git a/docs/examples/1.7.x/server-graphql/examples/databases/upsert-documents.md b/docs/examples/1.7.x/server-graphql/examples/databases/upsert-documents.md index d6e7bba9a3..2bfb765915 100644 --- a/docs/examples/1.7.x/server-graphql/examples/databases/upsert-documents.md +++ b/docs/examples/1.7.x/server-graphql/examples/databases/upsert-documents.md @@ -7,6 +7,7 @@ mutation { total documents { _id + _sequence _collectionId _databaseId _createdAt diff --git a/docs/examples/1.7.x/server-kotlin/java/databases/create-document.md b/docs/examples/1.7.x/server-kotlin/java/databases/create-document.md index 368b816219..5231be33d6 100644 --- a/docs/examples/1.7.x/server-kotlin/java/databases/create-document.md +++ b/docs/examples/1.7.x/server-kotlin/java/databases/create-document.md @@ -4,9 +4,8 @@ import io.appwrite.services.Databases; Client client = new Client() .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint - .setSession("") // The user session to authenticate with - .setKey("") // Your secret API key - .setJWT(""); // Your secret JSON Web Token + .setProject("") // Your project ID + .setSession(""); // The user session to authenticate with Databases databases = new Databases(client); diff --git a/docs/examples/1.7.x/server-kotlin/java/databases/create-documents.md b/docs/examples/1.7.x/server-kotlin/java/databases/create-documents.md index d816af366d..0de0c276ed 100644 --- a/docs/examples/1.7.x/server-kotlin/java/databases/create-documents.md +++ b/docs/examples/1.7.x/server-kotlin/java/databases/create-documents.md @@ -4,6 +4,7 @@ import io.appwrite.services.Databases; Client client = new Client() .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID .setKey(""); // Your secret API key Databases databases = new Databases(client); diff --git a/docs/examples/1.7.x/server-kotlin/java/databases/decrement-document-attribute.md b/docs/examples/1.7.x/server-kotlin/java/databases/decrement-document-attribute.md new file mode 100644 index 0000000000..34b74726ff --- /dev/null +++ b/docs/examples/1.7.x/server-kotlin/java/databases/decrement-document-attribute.md @@ -0,0 +1,28 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + .setKey(""); // Your secret API key + +Databases databases = new Databases(client); + +databases.decrementDocumentAttribute( + "", // databaseId + "", // collectionId + "", // documentId + "", // attribute + 0, // value (optional) + 0, // min (optional) + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); + diff --git a/docs/examples/1.7.x/server-kotlin/java/databases/increment-document-attribute.md b/docs/examples/1.7.x/server-kotlin/java/databases/increment-document-attribute.md new file mode 100644 index 0000000000..ca9c357f19 --- /dev/null +++ b/docs/examples/1.7.x/server-kotlin/java/databases/increment-document-attribute.md @@ -0,0 +1,28 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + .setKey(""); // Your secret API key + +Databases databases = new Databases(client); + +databases.incrementDocumentAttribute( + "", // databaseId + "", // collectionId + "", // documentId + "", // attribute + 0, // value (optional) + 0, // max (optional) + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); + diff --git a/docs/examples/1.7.x/server-kotlin/java/databases/upsert-document.md b/docs/examples/1.7.x/server-kotlin/java/databases/upsert-document.md new file mode 100644 index 0000000000..daa44141e2 --- /dev/null +++ b/docs/examples/1.7.x/server-kotlin/java/databases/upsert-document.md @@ -0,0 +1,27 @@ +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Databases; + +Client client = new Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + .setSession(""); // The user session to authenticate with + +Databases databases = new Databases(client); + +databases.upsertDocument( + "", // databaseId + "", // collectionId + "", // documentId + mapOf( "a" to "b" ), // data + listOf("read("any")"), // permissions (optional) + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + System.out.println(result); + }) +); + diff --git a/docs/examples/1.7.x/server-kotlin/java/databases/upsert-documents.md b/docs/examples/1.7.x/server-kotlin/java/databases/upsert-documents.md index e2f2a46337..95e9a33ef2 100644 --- a/docs/examples/1.7.x/server-kotlin/java/databases/upsert-documents.md +++ b/docs/examples/1.7.x/server-kotlin/java/databases/upsert-documents.md @@ -12,7 +12,7 @@ Databases databases = new Databases(client); databases.upsertDocuments( "", // databaseId "", // collectionId - listOf(), // documents (optional) + listOf(), // documents new CoroutineCallback<>((result, error) -> { if (error != null) { error.printStackTrace(); diff --git a/docs/examples/1.7.x/server-kotlin/kotlin/databases/create-document.md b/docs/examples/1.7.x/server-kotlin/kotlin/databases/create-document.md index 93da01eefa..695fdbdfaa 100644 --- a/docs/examples/1.7.x/server-kotlin/kotlin/databases/create-document.md +++ b/docs/examples/1.7.x/server-kotlin/kotlin/databases/create-document.md @@ -4,9 +4,8 @@ import io.appwrite.services.Databases val client = Client() .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID .setSession("") // The user session to authenticate with - .setKey("") // Your secret API key - .setJWT("") // Your secret JSON Web Token val databases = Databases(client) diff --git a/docs/examples/1.7.x/server-kotlin/kotlin/databases/create-documents.md b/docs/examples/1.7.x/server-kotlin/kotlin/databases/create-documents.md index 01692c62ad..41a98dc016 100644 --- a/docs/examples/1.7.x/server-kotlin/kotlin/databases/create-documents.md +++ b/docs/examples/1.7.x/server-kotlin/kotlin/databases/create-documents.md @@ -4,6 +4,7 @@ import io.appwrite.services.Databases val client = Client() .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID .setKey("") // Your secret API key val databases = Databases(client) diff --git a/docs/examples/1.7.x/server-kotlin/kotlin/databases/decrement-document-attribute.md b/docs/examples/1.7.x/server-kotlin/kotlin/databases/decrement-document-attribute.md new file mode 100644 index 0000000000..05204d76c6 --- /dev/null +++ b/docs/examples/1.7.x/server-kotlin/kotlin/databases/decrement-document-attribute.md @@ -0,0 +1,19 @@ +import io.appwrite.Client +import io.appwrite.coroutines.CoroutineCallback +import io.appwrite.services.Databases + +val client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + .setKey("") // Your secret API key + +val databases = Databases(client) + +val response = databases.decrementDocumentAttribute( + databaseId = "", + collectionId = "", + documentId = "", + attribute = "", + value = 0, // optional + min = 0 // optional +) diff --git a/docs/examples/1.7.x/server-kotlin/kotlin/databases/increment-document-attribute.md b/docs/examples/1.7.x/server-kotlin/kotlin/databases/increment-document-attribute.md new file mode 100644 index 0000000000..40c1224ae7 --- /dev/null +++ b/docs/examples/1.7.x/server-kotlin/kotlin/databases/increment-document-attribute.md @@ -0,0 +1,19 @@ +import io.appwrite.Client +import io.appwrite.coroutines.CoroutineCallback +import io.appwrite.services.Databases + +val client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + .setKey("") // Your secret API key + +val databases = Databases(client) + +val response = databases.incrementDocumentAttribute( + databaseId = "", + collectionId = "", + documentId = "", + attribute = "", + value = 0, // optional + max = 0 // optional +) diff --git a/docs/examples/1.7.x/server-kotlin/kotlin/databases/upsert-document.md b/docs/examples/1.7.x/server-kotlin/kotlin/databases/upsert-document.md new file mode 100644 index 0000000000..d8be0e13db --- /dev/null +++ b/docs/examples/1.7.x/server-kotlin/kotlin/databases/upsert-document.md @@ -0,0 +1,18 @@ +import io.appwrite.Client +import io.appwrite.coroutines.CoroutineCallback +import io.appwrite.services.Databases + +val client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + .setSession("") // The user session to authenticate with + +val databases = Databases(client) + +val response = databases.upsertDocument( + databaseId = "", + collectionId = "", + documentId = "", + data = mapOf( "a" to "b" ), + permissions = listOf("read("any")") // optional +) diff --git a/docs/examples/1.7.x/server-kotlin/kotlin/databases/upsert-documents.md b/docs/examples/1.7.x/server-kotlin/kotlin/databases/upsert-documents.md index 7459b384a1..ca861c61b2 100644 --- a/docs/examples/1.7.x/server-kotlin/kotlin/databases/upsert-documents.md +++ b/docs/examples/1.7.x/server-kotlin/kotlin/databases/upsert-documents.md @@ -12,5 +12,5 @@ val databases = Databases(client) val response = databases.upsertDocuments( databaseId = "", collectionId = "", - documents = listOf() // optional + documents = listOf() ) diff --git a/docs/examples/1.7.x/server-nodejs/examples/databases/create-document.md b/docs/examples/1.7.x/server-nodejs/examples/databases/create-document.md index 44cfc3c199..a2e77b9241 100644 --- a/docs/examples/1.7.x/server-nodejs/examples/databases/create-document.md +++ b/docs/examples/1.7.x/server-nodejs/examples/databases/create-document.md @@ -2,9 +2,8 @@ const sdk = require('node-appwrite'); const client = new sdk.Client() .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - .setSession('') // The user session to authenticate with - .setKey('') // Your secret API key - .setJWT(''); // Your secret JSON Web Token + .setProject('') // Your project ID + .setSession(''); // The user session to authenticate with const databases = new sdk.Databases(client); diff --git a/docs/examples/1.7.x/server-nodejs/examples/databases/create-documents.md b/docs/examples/1.7.x/server-nodejs/examples/databases/create-documents.md index 1b2088221b..d73df44cd1 100644 --- a/docs/examples/1.7.x/server-nodejs/examples/databases/create-documents.md +++ b/docs/examples/1.7.x/server-nodejs/examples/databases/create-documents.md @@ -2,6 +2,7 @@ const sdk = require('node-appwrite'); const client = new sdk.Client() .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject('') // Your project ID .setKey(''); // Your secret API key const databases = new sdk.Databases(client); diff --git a/docs/examples/1.7.x/server-nodejs/examples/databases/decrement-document-attribute.md b/docs/examples/1.7.x/server-nodejs/examples/databases/decrement-document-attribute.md new file mode 100644 index 0000000000..6bfc5f17cd --- /dev/null +++ b/docs/examples/1.7.x/server-nodejs/examples/databases/decrement-document-attribute.md @@ -0,0 +1,17 @@ +const sdk = require('node-appwrite'); + +const client = new sdk.Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject('') // Your project ID + .setKey(''); // Your secret API key + +const databases = new sdk.Databases(client); + +const result = await databases.decrementDocumentAttribute( + '', // databaseId + '', // collectionId + '', // documentId + '', // attribute + null, // value (optional) + null // min (optional) +); diff --git a/docs/examples/1.7.x/server-nodejs/examples/databases/increment-document-attribute.md b/docs/examples/1.7.x/server-nodejs/examples/databases/increment-document-attribute.md new file mode 100644 index 0000000000..0ba024514a --- /dev/null +++ b/docs/examples/1.7.x/server-nodejs/examples/databases/increment-document-attribute.md @@ -0,0 +1,17 @@ +const sdk = require('node-appwrite'); + +const client = new sdk.Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject('') // Your project ID + .setKey(''); // Your secret API key + +const databases = new sdk.Databases(client); + +const result = await databases.incrementDocumentAttribute( + '', // databaseId + '', // collectionId + '', // documentId + '', // attribute + null, // value (optional) + null // max (optional) +); diff --git a/docs/examples/1.7.x/server-php/examples/databases/create-document.md b/docs/examples/1.7.x/server-php/examples/databases/create-document.md index 8726b37719..bf1ee3f62a 100644 --- a/docs/examples/1.7.x/server-php/examples/databases/create-document.md +++ b/docs/examples/1.7.x/server-php/examples/databases/create-document.md @@ -5,9 +5,8 @@ use Appwrite\Services\Databases; $client = (new Client()) ->setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - ->setSession('') // The user session to authenticate with - ->setKey('') // Your secret API key - ->setJWT(''); // Your secret JSON Web Token + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with $databases = new Databases($client); diff --git a/docs/examples/1.7.x/server-php/examples/databases/create-documents.md b/docs/examples/1.7.x/server-php/examples/databases/create-documents.md index 96008e2495..bc05f67260 100644 --- a/docs/examples/1.7.x/server-php/examples/databases/create-documents.md +++ b/docs/examples/1.7.x/server-php/examples/databases/create-documents.md @@ -5,6 +5,7 @@ use Appwrite\Services\Databases; $client = (new Client()) ->setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID ->setKey(''); // Your secret API key $databases = new Databases($client); diff --git a/docs/examples/1.7.x/server-php/examples/databases/decrement-document-attribute.md b/docs/examples/1.7.x/server-php/examples/databases/decrement-document-attribute.md new file mode 100644 index 0000000000..40e14af844 --- /dev/null +++ b/docs/examples/1.7.x/server-php/examples/databases/decrement-document-attribute.md @@ -0,0 +1,20 @@ +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setKey(''); // Your secret API key + +$databases = new Databases($client); + +$result = $databases->decrementDocumentAttribute( + databaseId: '', + collectionId: '', + documentId: '', + attribute: '', + value: null, // optional + min: null // optional +); \ No newline at end of file diff --git a/docs/examples/1.7.x/server-php/examples/databases/increment-document-attribute.md b/docs/examples/1.7.x/server-php/examples/databases/increment-document-attribute.md new file mode 100644 index 0000000000..fb61d87295 --- /dev/null +++ b/docs/examples/1.7.x/server-php/examples/databases/increment-document-attribute.md @@ -0,0 +1,20 @@ +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setKey(''); // Your secret API key + +$databases = new Databases($client); + +$result = $databases->incrementDocumentAttribute( + databaseId: '', + collectionId: '', + documentId: '', + attribute: '', + value: null, // optional + max: null // optional +); \ No newline at end of file diff --git a/docs/examples/1.7.x/server-php/examples/databases/upsert-document.md b/docs/examples/1.7.x/server-php/examples/databases/upsert-document.md new file mode 100644 index 0000000000..6cff8296a3 --- /dev/null +++ b/docs/examples/1.7.x/server-php/examples/databases/upsert-document.md @@ -0,0 +1,19 @@ +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setSession(''); // The user session to authenticate with + +$databases = new Databases($client); + +$result = $databases->upsertDocument( + databaseId: '', + collectionId: '', + documentId: '', + data: [], + permissions: ["read("any")"] // optional +); \ No newline at end of file diff --git a/docs/examples/1.7.x/server-php/examples/databases/upsert-documents.md b/docs/examples/1.7.x/server-php/examples/databases/upsert-documents.md index 7b9459e8f4..d9f9efda5c 100644 --- a/docs/examples/1.7.x/server-php/examples/databases/upsert-documents.md +++ b/docs/examples/1.7.x/server-php/examples/databases/upsert-documents.md @@ -13,5 +13,5 @@ $databases = new Databases($client); $result = $databases->upsertDocuments( databaseId: '', collectionId: '', - documents: [] // optional + documents: [] ); \ No newline at end of file diff --git a/docs/examples/1.7.x/server-python/examples/databases/create-document.md b/docs/examples/1.7.x/server-python/examples/databases/create-document.md index 1a8500b0f2..1eaf0246f3 100644 --- a/docs/examples/1.7.x/server-python/examples/databases/create-document.md +++ b/docs/examples/1.7.x/server-python/examples/databases/create-document.md @@ -3,9 +3,8 @@ from appwrite.services.databases import Databases client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID client.set_session('') # The user session to authenticate with -client.set_key('') # Your secret API key -client.set_jwt('') # Your secret JSON Web Token databases = Databases(client) diff --git a/docs/examples/1.7.x/server-python/examples/databases/create-documents.md b/docs/examples/1.7.x/server-python/examples/databases/create-documents.md index 7c6ef24bdb..1b94e5165a 100644 --- a/docs/examples/1.7.x/server-python/examples/databases/create-documents.md +++ b/docs/examples/1.7.x/server-python/examples/databases/create-documents.md @@ -3,6 +3,7 @@ from appwrite.services.databases import Databases client = Client() client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID client.set_key('') # Your secret API key databases = Databases(client) diff --git a/docs/examples/1.7.x/server-python/examples/databases/decrement-document-attribute.md b/docs/examples/1.7.x/server-python/examples/databases/decrement-document-attribute.md new file mode 100644 index 0000000000..397bdd4bde --- /dev/null +++ b/docs/examples/1.7.x/server-python/examples/databases/decrement-document-attribute.md @@ -0,0 +1,18 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +databases = Databases(client) + +result = databases.decrement_document_attribute( + database_id = '', + collection_id = '', + document_id = '', + attribute = '', + value = None, # optional + min = None # optional +) diff --git a/docs/examples/1.7.x/server-python/examples/databases/increment-document-attribute.md b/docs/examples/1.7.x/server-python/examples/databases/increment-document-attribute.md new file mode 100644 index 0000000000..d5700e0b30 --- /dev/null +++ b/docs/examples/1.7.x/server-python/examples/databases/increment-document-attribute.md @@ -0,0 +1,18 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_key('') # Your secret API key + +databases = Databases(client) + +result = databases.increment_document_attribute( + database_id = '', + collection_id = '', + document_id = '', + attribute = '', + value = None, # optional + max = None # optional +) diff --git a/docs/examples/1.7.x/server-python/examples/databases/upsert-document.md b/docs/examples/1.7.x/server-python/examples/databases/upsert-document.md new file mode 100644 index 0000000000..c491ea4f44 --- /dev/null +++ b/docs/examples/1.7.x/server-python/examples/databases/upsert-document.md @@ -0,0 +1,17 @@ +from appwrite.client import Client +from appwrite.services.databases import Databases + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint +client.set_project('') # Your project ID +client.set_session('') # The user session to authenticate with + +databases = Databases(client) + +result = databases.upsert_document( + database_id = '', + collection_id = '', + document_id = '', + data = {}, + permissions = ["read("any")"] # optional +) diff --git a/docs/examples/1.7.x/server-python/examples/databases/upsert-documents.md b/docs/examples/1.7.x/server-python/examples/databases/upsert-documents.md index 99720649d6..5136d5fcb1 100644 --- a/docs/examples/1.7.x/server-python/examples/databases/upsert-documents.md +++ b/docs/examples/1.7.x/server-python/examples/databases/upsert-documents.md @@ -11,5 +11,5 @@ databases = Databases(client) result = databases.upsert_documents( database_id = '', collection_id = '', - documents = [] # optional + documents = [] ) diff --git a/docs/examples/1.7.x/server-rest/examples/databases/decrement-document-attribute.md b/docs/examples/1.7.x/server-rest/examples/databases/decrement-document-attribute.md new file mode 100644 index 0000000000..1db075f1eb --- /dev/null +++ b/docs/examples/1.7.x/server-rest/examples/databases/decrement-document-attribute.md @@ -0,0 +1,13 @@ +PATCH /v1/databases/{databaseId}/collections/{collectionId}/documents/{documentId}/{attribute}/decrement HTTP/1.1 +Host: cloud.appwrite.io +Content-Type: application/json +X-Appwrite-Response-Format: 1.7.0 +X-Appwrite-Project: +X-Appwrite-Key: +X-Appwrite-Session: +X-Appwrite-JWT: + +{ + "value": 0, + "min": 0 +} diff --git a/docs/examples/1.7.x/server-rest/examples/databases/increment-document-attribute.md b/docs/examples/1.7.x/server-rest/examples/databases/increment-document-attribute.md new file mode 100644 index 0000000000..1dda580f90 --- /dev/null +++ b/docs/examples/1.7.x/server-rest/examples/databases/increment-document-attribute.md @@ -0,0 +1,13 @@ +PATCH /v1/databases/{databaseId}/collections/{collectionId}/documents/{documentId}/{attribute}/increment HTTP/1.1 +Host: cloud.appwrite.io +Content-Type: application/json +X-Appwrite-Response-Format: 1.7.0 +X-Appwrite-Project: +X-Appwrite-Key: +X-Appwrite-Session: +X-Appwrite-JWT: + +{ + "value": 0, + "max": 0 +} diff --git a/docs/examples/1.7.x/server-rest/examples/databases/upsert-document.md b/docs/examples/1.7.x/server-rest/examples/databases/upsert-document.md new file mode 100644 index 0000000000..1885072eac --- /dev/null +++ b/docs/examples/1.7.x/server-rest/examples/databases/upsert-document.md @@ -0,0 +1,13 @@ +PUT /v1/databases/{databaseId}/collections/{collectionId}/documents/{documentId} HTTP/1.1 +Host: cloud.appwrite.io +Content-Type: application/json +X-Appwrite-Response-Format: 1.7.0 +X-Appwrite-Project: +X-Appwrite-Session: +X-Appwrite-Key: +X-Appwrite-JWT: + +{ + "data": {}, + "permissions": ["read(\"any\")"] +} diff --git a/docs/examples/1.7.x/server-ruby/examples/databases/create-document.md b/docs/examples/1.7.x/server-ruby/examples/databases/create-document.md index ce8dea79ef..e6831084a1 100644 --- a/docs/examples/1.7.x/server-ruby/examples/databases/create-document.md +++ b/docs/examples/1.7.x/server-ruby/examples/databases/create-document.md @@ -4,9 +4,8 @@ include Appwrite client = Client.new .set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint + .set_project('') # Your project ID .set_session('') # The user session to authenticate with - .set_key('') # Your secret API key - .set_jwt('') # Your secret JSON Web Token databases = Databases.new(client) diff --git a/docs/examples/1.7.x/server-ruby/examples/databases/create-documents.md b/docs/examples/1.7.x/server-ruby/examples/databases/create-documents.md index 469234c91e..16abc5e465 100644 --- a/docs/examples/1.7.x/server-ruby/examples/databases/create-documents.md +++ b/docs/examples/1.7.x/server-ruby/examples/databases/create-documents.md @@ -4,6 +4,7 @@ include Appwrite client = Client.new .set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint + .set_project('') # Your project ID .set_key('') # Your secret API key databases = Databases.new(client) diff --git a/docs/examples/1.7.x/server-ruby/examples/databases/decrement-document-attribute.md b/docs/examples/1.7.x/server-ruby/examples/databases/decrement-document-attribute.md new file mode 100644 index 0000000000..9b5a5f4006 --- /dev/null +++ b/docs/examples/1.7.x/server-ruby/examples/databases/decrement-document-attribute.md @@ -0,0 +1,19 @@ +require 'appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint + .set_project('') # Your project ID + .set_key('') # Your secret API key + +databases = Databases.new(client) + +result = databases.decrement_document_attribute( + database_id: '', + collection_id: '', + document_id: '', + attribute: '', + value: null, # optional + min: null # optional +) diff --git a/docs/examples/1.7.x/server-ruby/examples/databases/increment-document-attribute.md b/docs/examples/1.7.x/server-ruby/examples/databases/increment-document-attribute.md new file mode 100644 index 0000000000..40d8ba2ab7 --- /dev/null +++ b/docs/examples/1.7.x/server-ruby/examples/databases/increment-document-attribute.md @@ -0,0 +1,19 @@ +require 'appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint + .set_project('') # Your project ID + .set_key('') # Your secret API key + +databases = Databases.new(client) + +result = databases.increment_document_attribute( + database_id: '', + collection_id: '', + document_id: '', + attribute: '', + value: null, # optional + max: null # optional +) diff --git a/docs/examples/1.7.x/server-ruby/examples/databases/upsert-document.md b/docs/examples/1.7.x/server-ruby/examples/databases/upsert-document.md new file mode 100644 index 0000000000..238081864f --- /dev/null +++ b/docs/examples/1.7.x/server-ruby/examples/databases/upsert-document.md @@ -0,0 +1,18 @@ +require 'appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint + .set_project('') # Your project ID + .set_session('') # The user session to authenticate with + +databases = Databases.new(client) + +result = databases.upsert_document( + database_id: '', + collection_id: '', + document_id: '', + data: {}, + permissions: ["read("any")"] # optional +) diff --git a/docs/examples/1.7.x/server-ruby/examples/databases/upsert-documents.md b/docs/examples/1.7.x/server-ruby/examples/databases/upsert-documents.md index 353e38fe2b..30c42aa439 100644 --- a/docs/examples/1.7.x/server-ruby/examples/databases/upsert-documents.md +++ b/docs/examples/1.7.x/server-ruby/examples/databases/upsert-documents.md @@ -12,5 +12,5 @@ databases = Databases.new(client) result = databases.upsert_documents( database_id: '', collection_id: '', - documents: [] # optional + documents: [] ) diff --git a/docs/examples/1.7.x/server-swift/examples/databases/create-document.md b/docs/examples/1.7.x/server-swift/examples/databases/create-document.md index 4ee21048ab..daeaf144e1 100644 --- a/docs/examples/1.7.x/server-swift/examples/databases/create-document.md +++ b/docs/examples/1.7.x/server-swift/examples/databases/create-document.md @@ -2,9 +2,8 @@ import Appwrite let client = Client() .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID .setSession("") // The user session to authenticate with - .setKey("") // Your secret API key - .setJWT("") // Your secret JSON Web Token let databases = Databases(client) diff --git a/docs/examples/1.7.x/server-swift/examples/databases/create-documents.md b/docs/examples/1.7.x/server-swift/examples/databases/create-documents.md index 39a58ab3fd..2e992d9e3a 100644 --- a/docs/examples/1.7.x/server-swift/examples/databases/create-documents.md +++ b/docs/examples/1.7.x/server-swift/examples/databases/create-documents.md @@ -2,6 +2,7 @@ import Appwrite let client = Client() .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID .setKey("") // Your secret API key let databases = Databases(client) diff --git a/docs/examples/1.7.x/server-swift/examples/databases/decrement-document-attribute.md b/docs/examples/1.7.x/server-swift/examples/databases/decrement-document-attribute.md new file mode 100644 index 0000000000..88ba9ae01b --- /dev/null +++ b/docs/examples/1.7.x/server-swift/examples/databases/decrement-document-attribute.md @@ -0,0 +1,18 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + .setKey("") // Your secret API key + +let databases = Databases(client) + +let document = try await databases.decrementDocumentAttribute( + databaseId: "", + collectionId: "", + documentId: "", + attribute: "", + value: 0, // optional + min: 0 // optional +) + diff --git a/docs/examples/1.7.x/server-swift/examples/databases/increment-document-attribute.md b/docs/examples/1.7.x/server-swift/examples/databases/increment-document-attribute.md new file mode 100644 index 0000000000..452b200e34 --- /dev/null +++ b/docs/examples/1.7.x/server-swift/examples/databases/increment-document-attribute.md @@ -0,0 +1,18 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + .setKey("") // Your secret API key + +let databases = Databases(client) + +let document = try await databases.incrementDocumentAttribute( + databaseId: "", + collectionId: "", + documentId: "", + attribute: "", + value: 0, // optional + max: 0 // optional +) + diff --git a/docs/examples/1.7.x/server-swift/examples/databases/upsert-document.md b/docs/examples/1.7.x/server-swift/examples/databases/upsert-document.md new file mode 100644 index 0000000000..e78bd458a0 --- /dev/null +++ b/docs/examples/1.7.x/server-swift/examples/databases/upsert-document.md @@ -0,0 +1,17 @@ +import Appwrite + +let client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint + .setProject("") // Your project ID + .setSession("") // The user session to authenticate with + +let databases = Databases(client) + +let document = try await databases.upsertDocument( + databaseId: "", + collectionId: "", + documentId: "", + data: [:], + permissions: ["read("any")"] // optional +) + diff --git a/docs/examples/1.7.x/server-swift/examples/databases/upsert-documents.md b/docs/examples/1.7.x/server-swift/examples/databases/upsert-documents.md index 353cc5c502..544f02f9c0 100644 --- a/docs/examples/1.7.x/server-swift/examples/databases/upsert-documents.md +++ b/docs/examples/1.7.x/server-swift/examples/databases/upsert-documents.md @@ -10,6 +10,6 @@ let databases = Databases(client) let documentList = try await databases.upsertDocuments( databaseId: "", collectionId: "", - documents: [] // optional + documents: [] ) diff --git a/docs/sdks/web/CHANGELOG.md b/docs/sdks/web/CHANGELOG.md index 5923160f8f..b9875998a9 100644 --- a/docs/sdks/web/CHANGELOG.md +++ b/docs/sdks/web/CHANGELOG.md @@ -1,9 +1,34 @@ # Change Log +## 18.1.1 + +* Fix using `devKeys` resulting in an error by conditionally removing credentials + +## 18.1.0 + +* Add `devKeys` support to `Client` service +* Add `upsertDocument` support to `Databases` service + ## 18.0.0 * Add `` to doc examples due to the new multi region endpoints * Remove `Gif` from ImageFormat enum * Remove `search` param from `listExecutions` method * Add `token` param to `getFilePreview` and `getFileView` for File tokens usage -* Improve CORS error catching in `client.call` method \ No newline at end of file +* Improve CORS error catching in `client.call` method + +## 17.0.2 + +* Fix requests failing by removing `Content-Type` header from `GET` and `HEAD` requests + +## 17.0.1 + +* Remove unnecessary titles from method descriptions +* Fix duplicate adding of payload params +* Remove unnecessary awaits and asyncs +* Ensure `AppwriteException` response is always string + +## 17.0.0 + +* Fix pong response & chunked upload +* Add `ping` support to `Realtime` service diff --git a/src/Appwrite/Event/Mail.php b/src/Appwrite/Event/Mail.php index 1d0ae2a471..aaaa148fde 100644 --- a/src/Appwrite/Event/Mail.php +++ b/src/Appwrite/Event/Mail.php @@ -10,6 +10,7 @@ class Mail extends Event protected string $name = ''; protected string $subject = ''; protected string $body = ''; + protected string $preview = ''; protected array $smtp = []; protected array $variables = []; protected string $bodyTemplate = ''; @@ -93,6 +94,28 @@ class Mail extends Event return $this->body; } + /** + * Sets preview for the mail event. + * + * @return string + */ + public function setPreview(string $preview): self + { + $this->preview = $preview; + + return $this; + } + + /** + * Returns preview for the mail event. + * + * @return string + */ + public function getPreview(string $preview): string + { + return $this->preview; + } + /** * Sets name for the mail event. * @@ -409,6 +432,7 @@ class Mail extends Event 'subject' => $this->subject, 'bodyTemplate' => $this->bodyTemplate, 'body' => $this->body, + 'preview' => $this->preview, 'smtp' => $this->smtp, 'variables' => $this->variables, 'attachment' => $this->attachment, diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php index d502a78e07..905acf15df 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php @@ -82,7 +82,7 @@ class Create extends Base ->param('path', '/', new Text(2048), 'HTTP path of execution. Path can include query params. Default value is /', true) ->param('method', 'POST', new Whitelist(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], true), 'HTTP method of execution. Default value is GET.', true) ->param('headers', [], new AnyOf([new Assoc(), new Text(65535)], AnyOf::TYPE_MIXED), 'HTTP headers of execution. Defaults to empty.', true) - ->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true, precision: DateTimeValidator::PRECISION_MINUTES, offset: 60), 'Scheduled execution time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes.', true) + ->param('scheduledAt', null, new Text(100), 'Scheduled execution time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes.', true) ->inject('response') ->inject('request') ->inject('project') @@ -123,6 +123,13 @@ class Create extends Base throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Scheduled executions must run asynchronously. Set scheduledAt to a future date, or set async to true.'); } + if (!is_null($scheduledAt)) { + $validator = new DatetimeValidator(requireDateInFuture: true, precision: DateTimeValidator::PRECISION_MINUTES, offset: 60); + if (!$validator->isValid($scheduledAt)) { + throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Execution schedule must be a valid date, and at least 1 minute from now'); + } + } + /** * @var array $headers */ diff --git a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php index 890c8572d9..67bea01a28 100644 --- a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php +++ b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php @@ -444,7 +444,7 @@ class Builds extends Action Console::execute('rsync -av --exclude \'.git\' ' . \escapeshellarg($tmpTemplateDirectory . '/' . $templateRootDirectory . '/') . ' ' . \escapeshellarg($tmpDirectory . '/' . $rootDirectory), '', $stdout, $stderr); // Commit and push - $exit = Console::execute('git config --global user.email "team@appwrite.io" && git config --global user.name "Appwrite" && cd ' . \escapeshellarg($tmpDirectory) . ' && git checkout -b ' . \escapeshellarg($branchName) . ' && git add . && git commit -m "Create ' . \escapeshellarg($resource->getAttribute('name', '')) . ' function" && git push origin ' . \escapeshellarg($branchName), '', $stdout, $stderr); + $exit = Console::execute('git config --global user.email '. \escapeshellarg(APP_VCS_GITHUB_EMAIL) .' && git config --global user.name '. \escapeshellarg(APP_VCS_GITHUB_USERNAME) .' && cd ' . \escapeshellarg($tmpDirectory) . ' && git checkout -b ' . \escapeshellarg($branchName) . ' && git add . && git commit -m "Create ' . \escapeshellarg($resource->getAttribute('name', '')) . ' function" && git push origin ' . \escapeshellarg($branchName), '', $stdout, $stderr); if ($exit !== 0) { throw new \Exception('Unable to push code repository: ' . $stderr); @@ -516,7 +516,7 @@ class Builds extends Action ->setPayload($deployment->getArrayCopy()) ->trigger(); - $this->runGitAction('processing', $github, $providerCommitHash, $owner, $repositoryName, $project, $resource, $deployment->getId(), $dbForProject, $dbForPlatform); + $this->runGitAction('processing', $github, $providerCommitHash, $owner, $repositoryName, $project, $resource, $deployment->getId(), $dbForProject, $dbForPlatform, $queueForRealtime); } /** Request the executor to build the code... */ @@ -532,7 +532,7 @@ class Builds extends Action ->trigger(); if ($isVcsEnabled) { - $this->runGitAction('building', $github, $providerCommitHash, $owner, $repositoryName, $project, $resource, $deployment->getId(), $dbForProject, $dbForPlatform); + $this->runGitAction('building', $github, $providerCommitHash, $owner, $repositoryName, $project, $resource, $deployment->getId(), $dbForProject, $dbForPlatform, $queueForRealtime); } $deploymentModel = new Deployment(); @@ -980,6 +980,8 @@ class Builds extends Action throw new \Exception($screenshotError); } + $mimeType = "image/png"; + foreach ($screenshots as $data) { $key = $data['key']; $screenshot = $data['screenshot']; @@ -988,7 +990,7 @@ class Builds extends Action $fileName = $fileId . '.png'; $path = $deviceForFiles->getPath($fileName); $path = str_ireplace($deviceForFiles->getRoot(), $deviceForFiles->getRoot() . DIRECTORY_SEPARATOR . $bucket->getId(), $path); // Add bucket id to path after root - $success = $deviceForFiles->write($path, $screenshot, "image/png"); + $success = $deviceForFiles->write($path, $screenshot, $mimeType); if (!$success) { throw new \Exception("Screenshot failed to save"); @@ -1005,10 +1007,10 @@ class Builds extends Action 'name' => $fileName, 'path' => $path, 'signature' => $deviceForFiles->getFileHash($path), - 'mimeType' => $deviceForFiles->getFileMimeType($path), + 'mimeType' => $mimeType, 'sizeOriginal' => \strlen($screenshot), 'sizeActual' => $deviceForFiles->getFileSize($path), - 'algorithm' => Compression::GZIP, + 'algorithm' => Compression::NONE, 'comment' => '', 'chunksTotal' => 1, 'chunksUploaded' => 1, @@ -1017,7 +1019,7 @@ class Builds extends Action 'openSSLTag' => null, 'openSSLIV' => null, 'search' => implode(' ', [$fileId, $fileName]), - 'metadata' => ['content_type' => $deviceForFiles->getFileMimeType($path)], + 'metadata' => ['content_type' => $mimeType], ]); Authorization::skip(fn () => $dbForPlatform->createDocument('bucket_' . $bucket->getSequence(), $file)); @@ -1067,7 +1069,7 @@ class Builds extends Action ->trigger(); if ($isVcsEnabled) { - $this->runGitAction('ready', $github, $providerCommitHash, $owner, $repositoryName, $project, $resource, $deployment->getId(), $dbForProject, $dbForPlatform); + $this->runGitAction('ready', $github, $providerCommitHash, $owner, $repositoryName, $project, $resource, $deployment->getId(), $dbForProject, $dbForPlatform, $queueForRealtime); } Console::success("Build id: $deploymentId created"); @@ -1285,7 +1287,7 @@ class Builds extends Action ->trigger(); if ($isVcsEnabled) { - $this->runGitAction('failed', $github, $providerCommitHash, $owner, $repositoryName, $project, $resource, $deployment->getId(), $dbForProject, $dbForPlatform); + $this->runGitAction('failed', $github, $providerCommitHash, $owner, $repositoryName, $project, $resource, $deployment->getId(), $dbForProject, $dbForPlatform, $queueForRealtime); } } finally { $queueForRealtime @@ -1439,98 +1441,116 @@ class Builds extends Action Document $resource, string $deploymentId, Database $dbForProject, - Database $dbForPlatform + Database $dbForPlatform, + Realtime $queueForRealtime, ): void { - if ($resource->getAttribute('providerSilentMode', false) === true) { - return; - } - - $deployment = $dbForProject->getDocument('deployments', $deploymentId); - $commentId = $deployment->getAttribute('providerCommentId', ''); - - if (!empty($providerCommitHash)) { - $message = match ($status) { - 'ready' => 'Build succeeded.', - 'failed' => 'Build failed.', - 'processing' => 'Building...', - default => $status - }; - - $state = match ($status) { - 'ready' => 'success', - 'failed' => 'failure', - 'processing' => 'pending', - default => $status - }; - - $resourceName = $resource->getAttribute('name'); - $projectName = $project->getAttribute('name'); - - $name = "{$resourceName} ({$projectName})"; - - $protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') == 'disabled' ? 'http' : 'https'; - $hostname = System::getEnv('_APP_CONSOLE_DOMAIN', System::getEnv('_APP_DOMAIN', '')); - - $projectId = $project->getId(); - $region = $project->getAttribute('region', 'default'); - $resourceId = $resource->getId(); - $providerTargetUrl = match ($resource->getCollection()) { - 'functions' => "{$protocol}://{$hostname}/console/project-{$region}-{$projectId}/functions/function-{$resourceId}", - 'sites' => "{$protocol}://{$hostname}/console/project-{$region}-{$projectId}/sites/site-{$resourceId}", - default => throw new \Exception('Invalid resource type') - }; - - $github->updateCommitStatus($repositoryName, $providerCommitHash, $owner, $state, $message, $providerTargetUrl, $name); - } - - if (!empty($commentId)) { - $retries = 0; - - while (true) { - $retries++; - - try { - $dbForPlatform->createDocument('vcsCommentLocks', new Document([ - '$id' => $commentId - ])); - break; - } catch (\Throwable $err) { - if ($retries >= 9) { - throw $err; - } - - \sleep(1); - } + try { + if ($resource->getAttribute('providerSilentMode', false) === true) { + return; } - // Wrap in try/finally to ensure lock file gets deleted - try { - $resourceType = match($resource->getCollection()) { - 'functions' => 'function', - 'sites' => 'site', - default => throw new \Exception('Invalid resource type') + $deployment = $dbForProject->getDocument('deployments', $deploymentId); + $commentId = $deployment->getAttribute('providerCommentId', ''); + + if (!empty($providerCommitHash)) { + $message = match ($status) { + 'ready' => 'Build succeeded.', + 'failed' => 'Build failed.', + 'processing' => 'Building...', + default => $status }; - $rule = Authorization::skip(fn () => $dbForPlatform->findOne('rules', [ - Query::equal("projectInternalId", [$project->getSequence()]), - Query::equal("type", ["deployment"]), - Query::equal("deploymentInternalId", [$deployment->getSequence()]), - ])); + $state = match ($status) { + 'ready' => 'success', + 'failed' => 'failure', + 'processing' => 'pending', + default => $status + }; + + $resourceName = $resource->getAttribute('name'); + $projectName = $project->getAttribute('name'); + + $name = "{$resourceName} ({$projectName})"; $protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') == 'disabled' ? 'http' : 'https'; - $previewUrl = match($resource->getCollection()) { - 'functions' => '', - 'sites' => !empty($rule) ? ("{$protocol}://" . $rule->getAttribute('domain', '')) : '', + $hostname = System::getEnv('_APP_CONSOLE_DOMAIN', System::getEnv('_APP_DOMAIN', '')); + + $projectId = $project->getId(); + $region = $project->getAttribute('region', 'default'); + $resourceId = $resource->getId(); + $providerTargetUrl = match ($resource->getCollection()) { + 'functions' => "{$protocol}://{$hostname}/console/project-{$region}-{$projectId}/functions/function-{$resourceId}", + 'sites' => "{$protocol}://{$hostname}/console/project-{$region}-{$projectId}/sites/site-{$resourceId}", default => throw new \Exception('Invalid resource type') }; - $comment = new Comment(); - $comment->parseComment($github->getComment($owner, $repositoryName, $commentId)); - $comment->addBuild($project, $resource, $resourceType, $status, $deployment->getId(), ['type' => 'logs'], $previewUrl); - $github->updateComment($owner, $repositoryName, $commentId, $comment->generateComment()); - } finally { - $dbForPlatform->deleteDocument('vcsCommentLocks', $commentId); + $github->updateCommitStatus($repositoryName, $providerCommitHash, $owner, $state, $message, $providerTargetUrl, $name); } + + if (!empty($commentId)) { + $retries = 0; + + while (true) { + $retries++; + + try { + $dbForPlatform->createDocument('vcsCommentLocks', new Document([ + '$id' => $commentId + ])); + break; + } catch (\Throwable $err) { + if ($retries >= 9) { + throw $err; + } + + \sleep(1); + } + } + + // Wrap in try/finally to ensure lock file gets deleted + try { + $resourceType = match($resource->getCollection()) { + 'functions' => 'function', + 'sites' => 'site', + default => throw new \Exception('Invalid resource type') + }; + + $rule = Authorization::skip(fn () => $dbForPlatform->findOne('rules', [ + Query::equal("projectInternalId", [$project->getSequence()]), + Query::equal("type", ["deployment"]), + Query::equal("deploymentInternalId", [$deployment->getSequence()]), + ])); + + $protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') == 'disabled' ? 'http' : 'https'; + $previewUrl = match($resource->getCollection()) { + 'functions' => '', + 'sites' => !empty($rule) ? ("{$protocol}://" . $rule->getAttribute('domain', '')) : '', + default => throw new \Exception('Invalid resource type') + }; + + $comment = new Comment(); + $comment->parseComment($github->getComment($owner, $repositoryName, $commentId)); + $comment->addBuild($project, $resource, $resourceType, $status, $deployment->getId(), ['type' => 'logs'], $previewUrl); + $github->updateComment($owner, $repositoryName, $commentId, $comment->generateComment()); + } finally { + $dbForPlatform->deleteDocument('vcsCommentLocks', $commentId); + } + } + } catch (\Throwable $th) { + Console::warning("Git action failed:"); + Console::warning($th->getMessage()); + Console::warning($th->getTraceAsString()); + + $logs = $deployment->getAttribute('buildLogs', ''); + $date = \date('H:i:s'); + $logs .= "[$date] [appwrite] Git action failed. Deployment will continue. \n"; + + $deployment->setAttribute('buildLogs', $logs); + $deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment); + + $queueForRealtime + ->setPayload($deployment->getArrayCopy()) + ->trigger(); } } diff --git a/src/Appwrite/Platform/Tasks/ScheduleBase.php b/src/Appwrite/Platform/Tasks/ScheduleBase.php index 7686815868..222051a67f 100644 --- a/src/Appwrite/Platform/Tasks/ScheduleBase.php +++ b/src/Appwrite/Platform/Tasks/ScheduleBase.php @@ -11,7 +11,6 @@ use Utopia\Database\Exception; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; use Utopia\Platform\Action; -use Utopia\Pools\Group; use Utopia\Queue\Broker\Pool as BrokerPool; use Utopia\System\System; use Utopia\Telemetry\Adapter as Telemetry; @@ -26,7 +25,7 @@ abstract class ScheduleBase extends Action protected array $schedules = []; protected BrokerPool $publisher; - protected ?BrokerPool $publisherRedis = null; + protected BrokerPool $publisherMigrations; private ?Histogram $collectSchedulesTelemetryDuration = null; private ?Gauge $collectSchedulesTelemetryCount = null; @@ -36,7 +35,7 @@ abstract class ScheduleBase extends Action abstract public static function getName(): string; abstract public static function getSupportedResource(): string; abstract public static function getCollectionId(): string; - abstract protected function enqueueResources(Group $pools, Database $dbForPlatform, callable $getProjectDB): void; + abstract protected function enqueueResources(Database $dbForPlatform, callable $getProjectDB): void; public function __construct() { @@ -44,7 +43,8 @@ abstract class ScheduleBase extends Action $this ->desc("Execute {$type}s scheduled in Appwrite") - ->inject('pools') + ->inject('publisher') + ->inject('publisherMigrations') ->inject('dbForPlatform') ->inject('getProjectDB') ->inject('telemetry') @@ -67,18 +67,13 @@ abstract class ScheduleBase extends Action * 2. Create timer that sync all changes from 'schedules' collection to local copy. Only reading changes thanks to 'resourceUpdatedAt' attribute * 3. Create timer that prepares coroutines for soon-to-execute schedules. When it's ready, coroutine sleeps until exact time before sending request to worker. */ - public function action(Group $pools, Database $dbForPlatform, callable $getProjectDB, Telemetry $telemetry): void + public function action(BrokerPool $publisher, BrokerPool $publisherMigrations, Database $dbForPlatform, callable $getProjectDB, Telemetry $telemetry): void { Console::title(\ucfirst(static::getSupportedResource()) . ' scheduler V1'); Console::success(APP_NAME . ' ' . \ucfirst(static::getSupportedResource()) . ' scheduler v1 has started'); - $this->publisher = new BrokerPool($pools->get('publisher')); - - try { - $this->publisherRedis = new BrokerPool($pools->get('publisherRedis')); - } catch (\Throwable) { - $this->publisherRedis = null; - } + $this->publisher = $publisher; + $this->publisherMigrations = $publisherMigrations; $this->scheduleTelemetryCount = $telemetry->createGauge('task.schedule.count'); $this->collectSchedulesTelemetryDuration = $telemetry->createHistogram('task.schedule.collect_schedules.duration', 's'); @@ -101,7 +96,7 @@ abstract class ScheduleBase extends Action while (true) { try { - go(fn () => $this->enqueueResources($pools, $dbForPlatform, $getProjectDB)); + go(fn () => $this->enqueueResources($dbForPlatform, $getProjectDB)); $this->scheduleTelemetryCount->record(count($this->schedules), ['resourceType' => static::getSupportedResource()]); sleep(static::ENQUEUE_TIMER); } catch (\Throwable $th) { diff --git a/src/Appwrite/Platform/Tasks/ScheduleExecutions.php b/src/Appwrite/Platform/Tasks/ScheduleExecutions.php index acb2dd3070..96a5a05f0e 100644 --- a/src/Appwrite/Platform/Tasks/ScheduleExecutions.php +++ b/src/Appwrite/Platform/Tasks/ScheduleExecutions.php @@ -5,8 +5,6 @@ namespace Appwrite\Platform\Tasks; use Appwrite\Event\Func; use Swoole\Coroutine as Co; use Utopia\Database\Database; -use Utopia\Pools\Group; -use Utopia\System\System; class ScheduleExecutions extends ScheduleBase { @@ -28,17 +26,11 @@ class ScheduleExecutions extends ScheduleBase return 'executions'; } - protected function enqueueResources(Group $pools, Database $dbForPlatform, callable $getProjectDB): void + protected function enqueueResources(Database $dbForPlatform, callable $getProjectDB): void { $intervalEnd = (new \DateTime())->modify('+' . self::ENQUEUE_TIMER . ' seconds'); - $isRedisFallback = \str_contains(System::getEnv('_APP_WORKER_REDIS_FALLBACK', ''), 'functions'); - - $queueForFunctions = new Func( - $isRedisFallback - ? $this->publisherRedis - : $this->publisher - ); + $queueForFunctions = new Func($this->publisher); foreach ($this->schedules as $schedule) { if (!$schedule['active']) { diff --git a/src/Appwrite/Platform/Tasks/ScheduleFunctions.php b/src/Appwrite/Platform/Tasks/ScheduleFunctions.php index 7a3363d74d..43f1025c08 100644 --- a/src/Appwrite/Platform/Tasks/ScheduleFunctions.php +++ b/src/Appwrite/Platform/Tasks/ScheduleFunctions.php @@ -8,7 +8,6 @@ use Utopia\CLI\Console; use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Pools\Group; -use Utopia\System\System; class ScheduleFunctions extends ScheduleBase { @@ -32,7 +31,7 @@ class ScheduleFunctions extends ScheduleBase return 'functions'; } - protected function enqueueResources(Group $pools, Database $dbForPlatform, callable $getProjectDB): void + protected function enqueueResources(Database $dbForPlatform, callable $getProjectDB): void { $timerStart = \microtime(true); $time = DateTime::now(); @@ -91,13 +90,7 @@ class ScheduleFunctions extends ScheduleBase $this->updateProjectAccess($schedule['project'], $dbForPlatform); - $isRedisFallback = \str_contains(System::getEnv('_APP_WORKER_REDIS_FALLBACK', ''), 'functions'); - - $queueForFunctions = new Func( - $isRedisFallback - ? $this->publisherRedis - : $this->publisher - ); + $queueForFunctions = new Func($this->publisher); $queueForFunctions ->setType('schedule') diff --git a/src/Appwrite/Platform/Tasks/ScheduleMessages.php b/src/Appwrite/Platform/Tasks/ScheduleMessages.php index af15f9583f..c4e1376ff9 100644 --- a/src/Appwrite/Platform/Tasks/ScheduleMessages.php +++ b/src/Appwrite/Platform/Tasks/ScheduleMessages.php @@ -4,7 +4,6 @@ namespace Appwrite\Platform\Tasks; use Appwrite\Event\Messaging; use Utopia\Database\Database; -use Utopia\Pools\Group; class ScheduleMessages extends ScheduleBase { @@ -26,7 +25,7 @@ class ScheduleMessages extends ScheduleBase return 'messages'; } - protected function enqueueResources(Group $pools, Database $dbForPlatform, callable $getProjectDB): void + protected function enqueueResources(Database $dbForPlatform, callable $getProjectDB): void { foreach ($this->schedules as $schedule) { if (!$schedule['active']) { diff --git a/src/Appwrite/Platform/Tasks/Specs.php b/src/Appwrite/Platform/Tasks/Specs.php index 4876e8d96c..53cbced174 100644 --- a/src/Appwrite/Platform/Tasks/Specs.php +++ b/src/Appwrite/Platform/Tasks/Specs.php @@ -200,7 +200,6 @@ class Specs extends Action foreach ($sdks as $sdk) { /** @var Method $sdk */ - $hide = $sdk->isHidden(); if ($hide === true || (\is_array($hide) && \in_array($platform, $hide))) { continue; @@ -284,7 +283,8 @@ class Specs extends Action $routes, $models, $keys[$platform], - $authCounts[$platform] ?? 0 + $authCounts[$platform] ?? 0, + $platforms[$platform] ]; foreach (['swagger2', 'open-api3'] as $format) { diff --git a/src/Appwrite/Platform/Workers/Certificates.php b/src/Appwrite/Platform/Workers/Certificates.php index 381d4f4ecd..207f95ff7d 100644 --- a/src/Appwrite/Platform/Workers/Certificates.php +++ b/src/Appwrite/Platform/Workers/Certificates.php @@ -382,9 +382,11 @@ class Certificates extends Action ]; $subject = \sprintf($locale->getText("emails.certificate.subject"), $domain); + $preview = \sprintf($locale->getText("emails.certificate.preview"), $domain); $queueForMails ->setSubject($subject) + ->setPreview($preview) ->setBody($body) ->setName('Appwrite Administrator') ->setBodyTemplate(__DIR__ . '/../../../../app/config/locale/templates/email-base-styled.tpl') diff --git a/src/Appwrite/Platform/Workers/Mails.php b/src/Appwrite/Platform/Workers/Mails.php index 4e8b5e085c..117b689863 100644 --- a/src/Appwrite/Platform/Workers/Mails.php +++ b/src/Appwrite/Platform/Workers/Mails.php @@ -14,6 +14,11 @@ use Utopia\System\System; class Mails extends Action { + protected int $previewMaxLen = 150; + + protected string $whitespaceCodes = ' ‌​‍‎‏'; + + public static function getName(): string { return 'mails'; @@ -74,6 +79,7 @@ class Mails extends Action $variables['host'] = $protocol . '://' . $hostname; $name = $payload['name']; $body = $payload['body']; + $preview = $payload['preview'] ?? ''; $variables['subject'] = $subject; $variables['year'] = date("Y"); @@ -92,6 +98,27 @@ class Mails extends Action foreach ($this->richTextParams as $key => $value) { $bodyTemplate->setParam('{{' . $key . '}}', $value, escapeHtml: false); } + + $previewWhitespace = ''; + + if (!empty($preview)) { + $previewTemplate = Template::fromString($preview); + foreach ($variables as $key => $value) { + $previewTemplate->setParam('{{' . $key . '}}', $value); + } + // render() will return the subject in

tags, so use strip_tags() to remove them + $preview = \strip_tags($previewTemplate->render()); + + $previewLen = strlen($preview); + if ($previewLen < $this->previewMaxLen) { + $previewWhitespace = str_repeat($this->whitespaceCodes, $this->previewMaxLen - $previewLen); + } + } + + + $bodyTemplate->setParam('{{preview}}', $preview); + $bodyTemplate->setParam('{{previewWhitespace}}', $previewWhitespace, false); + $body = $bodyTemplate->render(); $subjectTemplate = Template::fromString($subject); diff --git a/src/Appwrite/Platform/Workers/Webhooks.php b/src/Appwrite/Platform/Workers/Webhooks.php index 3ffc3f0aad..394eae5fb8 100644 --- a/src/Appwrite/Platform/Workers/Webhooks.php +++ b/src/Appwrite/Platform/Workers/Webhooks.php @@ -241,6 +241,7 @@ class Webhooks extends Action // TODO: Use setbodyTemplate once #7307 is merged $subject = 'Webhook deliveries have been paused'; + $preview = 'Webhook deliveries to your endpoint have been paused.'; $body = Template::fromFile(__DIR__ . '/../../../../app/config/locale/templates/email-base-styled.tpl'); $body @@ -250,6 +251,7 @@ class Webhooks extends Action $queueForMails ->setSubject($subject) + ->setPreview($preview) ->setBody($body->render()); foreach ($users as $user) { diff --git a/src/Appwrite/SDK/Specification/Format.php b/src/Appwrite/SDK/Specification/Format.php index a8b71e0810..4a5ebd4566 100644 --- a/src/Appwrite/SDK/Specification/Format.php +++ b/src/Appwrite/SDK/Specification/Format.php @@ -24,6 +24,7 @@ abstract class Format protected array $services; protected array $keys; protected int $authCount; + protected string $platform; protected array $params = [ 'name' => '', 'description' => '', @@ -50,7 +51,7 @@ abstract class Format ] ]; - public function __construct(App $app, array $services, array $routes, array $models, array $keys, int $authCount) + public function __construct(App $app, array $services, array $routes, array $models, array $keys, int $authCount, string $platform) { $this->app = $app; $this->services = $services; @@ -58,6 +59,7 @@ abstract class Format $this->models = $models; $this->keys = $keys; $this->authCount = $authCount; + $this->platform = $platform; } /** diff --git a/src/Appwrite/SDK/Specification/Format/OpenAPI3.php b/src/Appwrite/SDK/Specification/Format/OpenAPI3.php index ea543ef899..96c8317c8f 100644 --- a/src/Appwrite/SDK/Specification/Format/OpenAPI3.php +++ b/src/Appwrite/SDK/Specification/Format/OpenAPI3.php @@ -183,9 +183,44 @@ class OpenAPI3 extends Format foreach ($additionalMethods as $method) { /** @var Method $method */ $desc = $method->getDescriptionFilePath(); + + $methodSecurities = $method->getAuth(); + $methodSdkPlatforms = []; + foreach ($methodSecurities as $value) { + switch ($value) { + case AuthType::SESSION: + $methodSdkPlatforms[] = APP_PLATFORM_CLIENT; + break; + case AuthType::JWT: + case AuthType::KEY: + $methodSdkPlatforms[] = APP_PLATFORM_SERVER; + break; + case AuthType::ADMIN: + $methodSdkPlatforms[] = APP_PLATFORM_CONSOLE; + break; + } + } + + if (empty($methodSecurities)) { + $methodSdkPlatforms[] = APP_PLATFORM_SERVER; + $methodSdkPlatforms[] = APP_PLATFORM_CLIENT; + } + + if ($this->platform !== APP_PLATFORM_CONSOLE && !\in_array($this->platform, $methodSdkPlatforms)) { + continue; + } + + $methodSecurities = ['Project' => []]; + foreach ($method->getAuth() as $security) { + /** @var AuthType $security */ + if (\array_key_exists($security->value, $this->keys)) { + $methodSecurities[$security->value] = []; + } + } + $additionalMethod = [ 'name' => $method->getMethodName(), - 'auth' => \array_merge(...\array_map(fn ($auth) => [$auth->value => []], $method->getAuth())), + 'auth' => \array_slice($methodSecurities, 0, $this->authCount), 'parameters' => [], 'required' => [], 'responses' => [], @@ -288,7 +323,7 @@ class OpenAPI3 extends Format } } - if ((!empty($scope))) { + if (!empty($scope)) { $securities = ['Project' => []]; foreach ($sdk->getAuth() as $security) { diff --git a/src/Appwrite/SDK/Specification/Format/Swagger2.php b/src/Appwrite/SDK/Specification/Format/Swagger2.php index bcf14ee9a2..9b104637b4 100644 --- a/src/Appwrite/SDK/Specification/Format/Swagger2.php +++ b/src/Appwrite/SDK/Specification/Format/Swagger2.php @@ -192,9 +192,43 @@ class Swagger2 extends Format /** @var Method $method */ $desc = $method->getDescriptionFilePath(); + $methodSecurities = $method->getAuth(); + $methodSdkPlatforms = []; + foreach ($methodSecurities as $value) { + switch ($value) { + case AuthType::SESSION: + $methodSdkPlatforms[] = APP_PLATFORM_CLIENT; + break; + case AuthType::JWT: + case AuthType::KEY: + $methodSdkPlatforms[] = APP_PLATFORM_SERVER; + break; + case AuthType::ADMIN: + $methodSdkPlatforms[] = APP_PLATFORM_CONSOLE; + break; + } + } + + if (empty($methodSecurities)) { + $methodSdkPlatforms[] = APP_PLATFORM_SERVER; + $methodSdkPlatforms[] = APP_PLATFORM_CLIENT; + } + + if ($this->platform !== APP_PLATFORM_CONSOLE && !\in_array($this->platform, $methodSdkPlatforms)) { + continue; + } + + $methodSecurities = ['Project' => []]; + foreach ($method->getAuth() as $security) { + /** @var AuthType $security */ + if (\array_key_exists($security->value, $this->keys)) { + $methodSecurities[$security->value] = []; + } + } + $additionalMethod = [ 'name' => $method->getMethodName(), - 'auth' => \array_merge(...\array_map(fn ($auth) => [$auth->value => []], $method->getAuth())), + 'auth' => \array_slice($methodSecurities, 0, $this->authCount), 'parameters' => [], 'required' => [], 'responses' => [], @@ -293,7 +327,7 @@ class Swagger2 extends Format } } - if ((!empty($scope))) { // && 'public' != $scope + if (!empty($scope)) { // && 'public' != $scope $securities = ['Project' => []]; foreach ($sdk->getAuth() as $security) { diff --git a/src/Appwrite/Utopia/Response/Model/ProviderRepository.php b/src/Appwrite/Utopia/Response/Model/ProviderRepository.php index 518b5de9ee..eee058a05b 100644 --- a/src/Appwrite/Utopia/Response/Model/ProviderRepository.php +++ b/src/Appwrite/Utopia/Response/Model/ProviderRepository.php @@ -41,6 +41,12 @@ class ProviderRepository extends Model 'default' => false, 'example' => true, ]) + ->addRule('defaultBranch', [ + 'type' => self::TYPE_STRING, + 'description' => "VCS (Version Control System) repository's default branch name.", + 'default' => '', + 'example' => 'main', + ]) ->addRule('pushedAt', [ 'type' => self::TYPE_DATETIME, 'description' => 'Last commit date in ISO 8601 format.', diff --git a/tests/e2e/Services/Account/AccountBase.php b/tests/e2e/Services/Account/AccountBase.php index 1a77cccb18..7c83edf3e3 100644 --- a/tests/e2e/Services/Account/AccountBase.php +++ b/tests/e2e/Services/Account/AccountBase.php @@ -170,6 +170,7 @@ trait AccountBase $userId = $response['body']['userId']; $lastEmail = $this->getLastEmail(); + $this->assertEquals('otpuser@appwrite.io', $lastEmail['to'][0]['address']); $this->assertEquals('OTP for ' . $this->getProject()['name'] . ' Login', $lastEmail['subject']); @@ -178,6 +179,7 @@ trait AccountBase $code = ($matches[0] ?? [])[0] ?? ''; $this->assertNotEmpty($code); + $this->assertStringContainsStringIgnoringCase('Use OTP ' . $code . ' to sign in to '. $this->getProject()['name'] . '. Expires in 15 minutes.', $lastEmail['text']); $response = $this->client->call(Client::METHOD_POST, '/account/sessions/token', array_merge([ 'origin' => 'http://localhost', diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index cbddb85481..bd3fec8439 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -925,6 +925,7 @@ class AccountCustomClientTest extends Scope $this->assertEquals($email, $lastEmail['to'][0]['address']); $this->assertEquals($name, $lastEmail['to'][0]['name']); $this->assertEquals('Account Verification', $lastEmail['subject']); + $this->assertStringContainsStringIgnoringCase('Verify your email to activate your ' . $this->getProject()['name'] . ' account.', $lastEmail['text']); $tokens = $this->extractQueryParamsFromEmailLink($lastEmail['html']); $verification = $tokens['secret']; @@ -1228,6 +1229,8 @@ class AccountCustomClientTest extends Scope $this->assertEquals($email, $lastEmail['to'][0]['address']); $this->assertEquals($name, $lastEmail['to'][0]['name']); $this->assertEquals('Password Reset', $lastEmail['subject']); + $this->assertStringContainsStringIgnoringCase('Reset your ' . $this->getProject()['name'] . ' password using the link.', $lastEmail['text']); + $tokens = $this->extractQueryParamsFromEmailLink($lastEmail['html']); @@ -1432,6 +1435,7 @@ class AccountCustomClientTest extends Scope $this->assertNotEmpty($response['body']['expire']); $this->assertEmpty($response['body']['secret']); $this->assertEmpty($response['body']['phrase']); + $this->assertStringContainsStringIgnoringCase('New login detected on '. $this->getProject()['name'], $lastEmail['text']); $userId = $response['body']['userId']; @@ -2691,6 +2695,7 @@ class AccountCustomClientTest extends Scope $lastEmail = $this->getLastEmail(); $this->assertEquals($email, $lastEmail['to'][0]['address']); $this->assertEquals($this->getProject()['name'] . ' Login', $lastEmail['subject']); + $this->assertStringContainsStringIgnoringCase('Sign in to '. $this->getProject()['name'] . ' with your secure link. Expires in 1 hour.', $lastEmail['text']); $this->assertStringNotContainsStringIgnoringCase('security phrase', $lastEmail['text']); $token = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 64); diff --git a/tests/e2e/Services/Databases/Legacy/DatabasesBase.php b/tests/e2e/Services/Databases/Legacy/DatabasesBase.php index c37615125e..554b47f4a5 100644 --- a/tests/e2e/Services/Databases/Legacy/DatabasesBase.php +++ b/tests/e2e/Services/Databases/Legacy/DatabasesBase.php @@ -1979,33 +1979,39 @@ trait DatabasesBase ]); $this->assertEquals(2, $documents['body']['total']); - // test without passing permissions - $document = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $documentId, array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'data' => [ - 'title' => 'Thor: Ragnarok', - 'releaseYear' => 2000 - ] - ]); + if ($this->getSide() === 'client') { + // Skipped on server side: Creating a document with no permissions results in an empty permissions array, whereas on client side it assigns permissions to the current user - $this->assertEquals(200, $document['headers']['status-code']); - $this->assertEquals('Thor: Ragnarok', $document['body']['title']); + // test without passing permissions + $document = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $documentId, array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'data' => [ + 'title' => 'Thor: Ragnarok', + 'releaseYear' => 2000 + ] + ]); - $document = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $documentId, array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ])); + $this->assertEquals(200, $document['headers']['status-code']); + $this->assertEquals('Thor: Ragnarok', $document['body']['title']); + $this->assertCount(3, $document['body']['$permissions']); + $permissionsCreated = $document['body']['$permissions']; + // checking the default created permission + $defaultPermission = [ + Permission::read(Role::user($this->getUser()['$id'])), + Permission::update(Role::user($this->getUser()['$id'])), + Permission::delete(Role::user($this->getUser()['$id'])) + ]; + // ignoring the order of the permission and checking the permissions + $this->assertEqualsCanonicalizing($defaultPermission, $permissionsCreated); - $this->assertEquals(200, $document['headers']['status-code']); + $document = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $documentId, array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'] + ], $this->getHeaders())); - $deleteResponse = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $documentId, array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ])); + $this->assertEquals(200, $document['headers']['status-code']); $this->assertEquals(204, $deleteResponse['headers']['status-code']); diff --git a/tests/e2e/Services/Sites/SitesConsoleClientTest.php b/tests/e2e/Services/Sites/SitesConsoleClientTest.php index 28ce2a35ec..227e36a50e 100644 --- a/tests/e2e/Services/Sites/SitesConsoleClientTest.php +++ b/tests/e2e/Services/Sites/SitesConsoleClientTest.php @@ -92,12 +92,51 @@ class SitesConsoleClientTest extends Scope $this->assertNotEquals($screenshotDarkHash, $screenshotHash); + $screenshotId = $deployment['body']['screenshotLight']; $file = $this->client->call(Client::METHOD_GET, "/storage/buckets/screenshots/files/$screenshotId/view?project=console"); $this->assertEquals(404, $file['headers']['status-code']); + $screenshotId = $deployment['body']['screenshotDark']; $file = $this->client->call(Client::METHOD_GET, "/storage/buckets/screenshots/files/$screenshotId/view?project=console"); $this->assertEquals(404, $file['headers']['status-code']); + // Verify previews + $screenshotId = $deployment['body']['screenshotLight']; + $file = $this->client->call(Client::METHOD_GET, "/storage/buckets/screenshots/files/$screenshotId/preview?project=console", array_merge($this->getHeaders(), [ + 'x-appwrite-mode' => 'default' // NOT ADMIN! + ])); + + $this->assertEquals(200, $file['headers']['status-code']); + $this->assertNotEmpty(200, $file['body']); + $this->assertGreaterThan(1, $file['headers']['content-length']); + $this->assertEquals('image/png', $file['headers']['content-type']); + + $screenshotHash = \md5($file['body']); + $this->assertNotEmpty($screenshotHash); + + $screenshotId = $deployment['body']['screenshotDark']; + $file = $this->client->call(Client::METHOD_GET, "/storage/buckets/screenshots/files/$screenshotId/preview?project=console", array_merge($this->getHeaders(), [ + 'x-appwrite-mode' => 'default' // NOT ADMIN! + ])); + + $this->assertEquals(200, $file['headers']['status-code']); + $this->assertNotEmpty(200, $file['body']); + $this->assertGreaterThan(1, $file['headers']['content-length']); + $this->assertEquals('image/png', $file['headers']['content-type']); + + $screenshotDarkHash = \md5($file['body']); + $this->assertNotEmpty($screenshotDarkHash); + + $this->assertNotEquals($screenshotDarkHash, $screenshotHash); + + $screenshotId = $deployment['body']['screenshotLight']; + $file = $this->client->call(Client::METHOD_GET, "/storage/buckets/screenshots/files/$screenshotId/preview?project=console"); + $this->assertEquals(404, $file['headers']['status-code']); + + $screenshotId = $deployment['body']['screenshotDark']; + $file = $this->client->call(Client::METHOD_GET, "/storage/buckets/screenshots/files/$screenshotId/preview?project=console"); + $this->assertEquals(404, $file['headers']['status-code']); + $this->cleanupSite($siteId); } }