Compare commits

..
Author SHA1 Message Date
Hemachandar b5d26bb426 Fix errors on downloading function deployment output 2025-10-24 19:59:48 +05:30
Jake BarnbyandGitHub 2e699ef8b9 Merge pull request #10678 from appwrite/update-domains-0.9.1
update domain lib to 0.9.1
2025-10-22 04:53:35 +00:00
Chirag Aggarwal 9c30f32281 update domain lib to 0.9.1 2025-10-22 09:29:45 +05:30
Steven NguyenandGitHub 2652a21332 Merge pull request #10404 from appwrite/feat-1.8.0-release-prep
Prepare 1.8.0 release
2025-10-21 15:40:07 -07:00
Luke B. SilverandGitHub 16a2dd0b27 Merge pull request #10672 from appwrite/update-cli-10.2.2
chore: update cli to 10.2.2
2025-10-21 10:53:16 +01:00
Chirag Aggarwal 8154a8524a update sdk gen 2025-10-21 12:51:10 +05:30
Chirag Aggarwal 0e567e3e68 chore: update cli to 10.2.2 2025-10-21 11:40:50 +05:30
Jake BarnbyandGitHub f150cffa17 Merge pull request #10670 from appwrite/revert-auth
Revert "Merge pull request #10468 from appwrite/feat-apps-module-dl"
2025-10-21 02:58:23 +00:00
Jake Barnby f4efb81832 Update lock 2025-10-21 15:07:53 +13:00
Jake Barnby ddde13a78f Revert "Merge pull request #10468 from appwrite/feat-apps-module-dl"
This reverts commit 9dd1939d1f, reversing
changes made to 8dfdfcb522.

# Conflicts:
#	app/config/collections/common.php
#	app/controllers/api/users.php
#	app/init/resources.php
#	composer.lock
2025-10-21 14:59:30 +13:00
Jake BarnbyandGitHub e2d3624713 Merge pull request #10664 from appwrite/feat-update-db
Update db
2025-10-20 14:11:36 +00:00
Matej BačoandGitHub 411951f9d5 Merge pull request #10669 from appwrite/copilot/update-github-comment-title
Change GitHub alert from NOTE to TIP in VCS build comments
2025-10-20 16:03:59 +02:00
Jake Barnby caa699e181 Update database 2025-10-21 02:25:51 +13:00
copilot-swe-agent[bot]andMeldiron d9773f44b1 Change GitHub alert from NOTE to TIP in VCS comments
Co-authored-by: Meldiron <19310830+Meldiron@users.noreply.github.com>
2025-10-20 12:32:38 +00:00
copilot-swe-agent[bot] 46dd8fdc68 Initial plan 2025-10-20 12:28:04 +00:00
Jake Barnby 94d02aff4f Fix DB tests 2025-10-21 01:24:50 +13:00
Jake Barnby d23f993a6c Fix validator constructor 2025-10-21 00:13:43 +13:00
Jake Barnby bfe639fb70 Fix key 2025-10-21 00:13:32 +13:00
Jake Barnby 568651291e Update libs 2025-10-20 23:13:17 +13:00
Damodar LohaniandGitHub 254f026458 Merge pull request #10667 from appwrite/fix-auth-refactor
Fix: reset argon 2 options to previous default
2025-10-19 14:00:25 +05:45
Damodar Lohani 248d3aea7a Fix: reset argon 2 options to previous default 2025-10-19 05:44:44 +00:00
Jake Barnby 11042af051 Update db 2025-10-18 02:19:43 +13:00
Luke B. SilverandGitHub 07d55d17a3 Merge pull request #10658 from appwrite/update-domains-0.8.3
update domain lib to 0.8.4
2025-10-17 13:09:36 +01:00
Chirag Aggarwal abfab60eec update to 0.8.4 2025-10-17 17:05:47 +05:30
Chirag Aggarwal fc3ac122dd Merge branch '1.8.x' into update-domains-0.8.3 2025-10-17 17:05:24 +05:30
Jake BarnbyandGitHub 3963b632d8 Merge pull request #10663 from appwrite/update-apple-swift
chore: update apple and swift sdks to 13.2.2
2025-10-17 07:01:25 +00:00
Chirag Aggarwal 1936a01464 chore: update apple and swift sdks to 13.2.2 2025-10-17 12:28:31 +05:30
Luke B. SilverandGitHub 2cbfa6930f Merge pull request #10655 from appwrite/fix-test-dependencies-projects
Refactor ProjectsConsoleClientTest to remove test dependencies
2025-10-16 11:30:50 +01:00
Chirag Aggarwal 33a856af41 update domain lib to 0.8.3 2025-10-16 15:54:43 +05:30
Chirag Aggarwal 5d1d937fde remove changes 2025-10-16 15:29:59 +05:30
Chirag Aggarwal 83ec855f4b skip harder ones 2025-10-16 15:18:21 +05:30
Luke B. SilverandGitHub 5ce9b8eaeb Merge pull request #10656 from appwrite/feat-replace-sleep-in-webhooks-service
Replace sleep in webhook tests with assertEventually
2025-10-16 10:45:32 +01:00
Khushboo Verma be983eb68a Remove race condition 2025-10-16 14:40:47 +05:30
Chirag Aggarwal c6f144313d more tests 2025-10-16 14:29:57 +05:30
Chirag Aggarwal ae8ec1c736 formatting 2025-10-16 14:26:39 +05:30
Chirag Aggarwal 19d7f02371 more tests 2025-10-16 14:25:12 +05:30
Khushboo Verma f0660f3fda Replace sleep in webhook tests with assertEventually 2025-10-16 14:23:35 +05:30
Chirag Aggarwal 9ded176cf2 Refactor ProjectsConsoleClientTest to remove test dependencies
- Remove @depends annotations to make tests independent
- Each test now creates its own team and project instead of relying on shared state
- Replace sleep() calls with assertEventually() for more reliable async testing
- Change test methods to return void instead of passing data between tests
- Remove unnecessary sleep() call that was causing test flakiness
2025-10-16 14:21:30 +05:30
Damodar LohaniandGitHub 2e10cd0009 Merge pull request #10654 from appwrite/fix-undefined-var
Fix: undefined variable warning
2025-10-16 13:40:04 +05:45
Damodar Lohani 7ff664e62b Fix: undefined $user 2025-10-16 07:38:13 +00:00
Damodar LohaniandGitHub 9dd1939d1f Merge pull request #10468 from appwrite/feat-apps-module-dl
Feat apps module dl
2025-10-16 11:40:27 +05:45
Damodar LohaniandGitHub 8dfdfcb522 Merge pull request #10652 from appwrite/fix-undefined-sequence
Fix undefined sequence
2025-10-16 10:34:37 +05:45
Damodar LohaniandGitHub b63c2804f1 Fix: undefined $sequence 2025-10-16 10:26:49 +05:45
Damodar Lohani ced2270571 remove unused injection 2025-10-16 03:39:39 +00:00
Damodar Lohani d3436077a1 remove unused hash 2025-10-16 03:39:18 +00:00
Damodar Lohani e06349e803 update argon2 instances 2025-10-16 03:34:45 +00:00
Damodar Lohani 9849b9d678 Fix empty check 2025-10-16 02:41:53 +00:00
Damodar Lohani 22136867ed add additional check 2025-10-16 02:29:30 +00:00
Damodar Lohani 2df621f9c5 Fix: update comment, typings 2025-10-16 02:23:41 +00:00
Damodar Lohani 9a599e2015 update recommended param for argon2 2025-10-16 02:20:28 +00:00
Damodar Lohani 431dd96b98 chaining 2025-10-16 02:17:59 +00:00
Damodar Lohani 4d8f950955 fix roles filtering 2025-10-16 02:17:52 +00:00
Damodar Lohani 08e559180d fix missing injection 2025-10-16 02:08:07 +00:00
Damodar Lohani 4cb63068de improve install loop 2025-10-16 02:07:17 +00:00
Damodar Lohani f062b39cfa Fix encoding 2025-10-16 02:06:01 +00:00
Damodar Lohani 06ee421965 update composer 2025-10-15 07:11:27 +00:00
Damodar Lohani c3c69cc43b Merge remote-tracking branch 'origin/1.8.x' into feat-apps-module-dl 2025-10-15 07:05:23 +00:00
Damodar Lohani e47d53ddcc Merge remote-tracking branch 'origin/main' into feat-apps-module-dl 2025-10-15 07:04:38 +00:00
Jake BarnbyandGitHub 290a7b27db Merge branch 'main' into 1.8.x 2025-10-15 18:45:38 +13:00
Damodar Lohani 5e5b22d649 fix jwt 2025-10-12 04:38:14 +00:00
Damodar Lohani 1b17c32405 update block 2025-10-12 03:51:37 +00:00
Damodar Lohani d56dff954f Merge remote-tracking branch 'origin/1.8.x' into feat-apps-module-dl 2025-10-12 00:34:07 +00:00
Damodar Lohani 4540362f42 Fix: token hash magic url session 2025-09-18 01:37:19 +00:00
Damodar Lohani 3065f53d83 Fix token hash 2025-09-18 01:14:14 +00:00
Damodar Lohani 74f181d7a8 fix token length 2025-09-17 10:18:49 +00:00
Damodar LohaniandGitHub 337eda8538 Merge branch '1.8.x' into feat-apps-module-dl 2025-09-17 14:49:22 +05:45
Damodar LohaniandGitHub 20c3641ac1 Merge branch '1.8.x' into feat-apps-module-dl 2025-09-16 10:25:30 +05:45
Damodar Lohani 33f7056e7a reest callback 2025-09-16 04:38:52 +00:00
Damodar Lohani 73e7c98131 Fix token length update 2025-09-16 04:36:30 +00:00
Damodar Lohani 1157d6fd10 Fix re-hashing 2025-09-16 04:27:00 +00:00
Damodar Lohani cfd82d9709 use newer syntax 2025-09-15 10:57:31 +00:00
Damodar Lohani 21245836c7 Merge remote-tracking branch 'origin/1.8.x' into feat-apps-module-dl 2025-09-15 10:44:43 +00:00
Damodar Lohani b5ca4c1166 update suggestion 2025-09-15 10:43:40 +00:00
Damodar Lohani 780799f87a update to initialize first 2025-09-15 10:41:29 +00:00
Damodar Lohani 4579e41ace update check 2025-09-15 10:33:21 +00:00
Damodar Lohani 19cf94bd7e Fix oauth2 changes 2025-09-15 10:22:45 +00:00
Damodar Lohani 13b98409ae reset length 2025-09-14 05:56:56 +00:00
Damodar Lohani 518389d32c fix length 2025-09-14 05:37:06 +00:00
Damodar Lohani 800db0b99d Fix magic URL token length 2025-09-14 05:23:30 +00:00
Damodar Lohani cfa4530797 composer update 2025-09-14 05:03:20 +00:00
Damodar Lohani d42841d80a fix: remove hardcode, reuse hasher 2025-09-14 05:02:50 +00:00
3b668f7806 Update composer.json
Co-authored-by: Matej Bačo <matejbacocom@gmail.com>
2025-09-14 10:45:53 +05:45
32b290a231 Update src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php
Co-authored-by: Matej Bačo <matejbacocom@gmail.com>
2025-09-14 10:44:46 +05:45
Damodar Lohani 365aaca56d fix: remove legacy token generator use 2025-09-14 04:58:34 +00:00
Damodar Lohani 1c726d0466 fix: encoded not defined 2025-09-14 04:53:49 +00:00
Damodar Lohani c903caabcc remove dump 2025-09-14 04:50:13 +00:00
Damodar Lohani 53a117bd0f Merge remote-tracking branch 'origin/1.8.x' into feat-apps-module-dl 2025-09-14 04:49:34 +00:00
Damodar Lohani 72f5793928 revert date format 2025-09-11 09:18:23 +00:00
Damodar LohaniandGitHub b8e3a19586 Merge branch '1.8.x' into feat-apps-module-dl 2025-09-11 14:47:14 +05:45
Damodar Lohani e36de6b72b revert date format 2025-09-11 08:59:27 +00:00
Damodar Lohani bcec5c0922 revert date format 2025-09-11 08:57:27 +00:00
Damodar Lohani 72186f1882 reset det change 2025-09-11 08:46:38 +00:00
Damodar Lohani e4d70a4d4f Fix: default options 2025-09-11 07:55:52 +00:00
Damodar Lohani 6d19d76bac Fix scope check 2025-09-11 06:51:01 +00:00
Damodar Lohani 55bebd92f3 Fix date format 2025-09-11 06:27:58 +00:00
Damodar LohaniandGitHub 0d4df67958 Merge branch '1.8.x' into feat-apps-module-dl 2025-09-11 11:59:31 +05:45
Damodar Lohani 356fbed325 fix password update 2025-09-10 09:09:12 +00:00
Damodar Lohani 4578819a58 revert test update 2025-09-10 07:59:00 +00:00
Damodar Lohani 6099313cb4 Fxi teams tests 2025-09-10 07:57:45 +00:00
Damodar Lohani 487663f892 fixed attribute 2025-09-10 07:30:22 +00:00
Damodar LohaniandGitHub d8e769ef1f Merge branch '1.8.x' into feat-apps-module-dl 2025-09-10 12:48:44 +05:45
Damodar Lohani 41dbe1a384 Fix internal ID refactor 2025-09-10 07:03:11 +00:00
Damodar Lohani 631c00023e update lock 2025-09-10 04:38:14 +00:00
Damodar Lohani 4478edc211 fix linter 2025-09-10 04:25:21 +00:00
Damodar Lohani 2be8895dfd Merge remote-tracking branch 'origin/1.8.x' into feat-apps-module-dl 2025-09-10 03:56:34 +00:00
Christy Jacob b5c5f76acc Merge branch '1.7.x' of github.com:appwrite/appwrite into feat-apps-module 2025-06-20 17:39:28 +04:00
Eldad Fux 6f861a91ee Updated auth lib 2025-04-29 21:33:59 +02:00
Eldad Fux 0483c7efb5 Merge fixes 2025-04-29 20:44:05 +02:00
Eldad Fux fb29fe7b3c Merge remote-tracking branch 'origin/1.7.x' into feat-apps-module 2025-04-29 20:12:31 +02:00
Eldad Fux 1bf1766822 Merge remote-tracking branch 'origin/feat-sites' into feat-apps-module 2025-03-28 08:20:24 +01:00
Eldad Fux 57edb4a385 Removed leftovers 2025-03-28 08:17:47 +01:00
Eldad Fux 17c555ab6c Expanded the identities collection 2025-03-28 02:13:17 +01:00
Eldad Fux d6bd72cfd3 formatting 2025-03-19 14:10:56 +01:00
Eldad Fux 8c9123beaa Fixed tests 2025-03-19 13:54:32 +01:00
Eldad Fux 3d967e695f Updated auth lib 2025-03-19 07:57:28 +01:00
Eldad Fux a7d7e39dfd Fixed tests 2025-03-18 22:47:17 +01:00
Eldad Fux 38cb95e940 Fixed tests 2025-03-18 22:28:19 +01:00
Eldad Fux b2b20c48b3 Fixed tests 2025-03-18 22:12:03 +01:00
Eldad Fux fed6579491 Update teams tests 2025-03-18 21:52:41 +01:00
Eldad Fux 8cb85cafbd Fixes realtime tests 2025-03-18 20:24:38 +01:00
Eldad Fux 55e560bb41 Fixed unit tests 2025-03-18 19:08:58 +01:00
Eldad Fux dd9a40221e Merge remote-tracking branch 'origin/feat-sites' into feat-apps-module 2025-03-18 17:38:32 +01:00
Eldad Fux 24300cd3bd tests 2025-03-18 17:22:58 +01:00
Eldad Fux 4d5961c3ab Fixed test 2025-03-18 16:20:37 +01:00
Eldad Fux afb40218d7 Fixed tests 2025-03-18 16:12:13 +01:00
Eldad Fux 3daa3821ef Fixed syntax error 2025-03-18 10:24:42 +01:00
Eldad Fux 84cec0e32c format 2025-03-18 10:18:29 +01:00
Eldad Fux 7bae15d4fe Merge remote-tracking branch 'origin/feat-sites' into feat-apps-module 2025-03-18 10:15:06 +01:00
Eldad Fux 0180f72067 Removed unsed methods and tests 2025-03-18 00:30:31 +01:00
Eldad Fux f537091eb2 Fixed tests 2025-03-17 23:57:44 +01:00
Eldad Fux c99c83a006 Merge remote-tracking branch 'origin/feat-sites' into feat-apps-module 2025-03-17 23:15:57 +01:00
Eldad Fux 113828cd00 Improved errors 2025-03-17 22:51:22 +01:00
Eldad Fux 477add3022 Formatting 2025-03-17 21:49:10 +01:00
Eldad Fux 8aa5714173 cleanups 2025-03-17 21:44:31 +01:00
Eldad Fux fdb83c51f7 formatting 2025-03-17 12:46:07 +01:00
Eldad Fux c15739bba7 Merge remote-tracking branch 'origin/feat-sites' into feat-apps-module 2025-03-17 12:44:49 +01:00
Eldad Fux 1ce84f1650 WIP 2025-03-17 12:39:35 +01:00
Eldad Fux f618a8b563 Fixed account test 2025-03-16 22:16:02 +01:00
Eldad Fux 9346efc24a Fixed some tests 2025-03-16 19:35:42 +01:00
Eldad Fux a5e57a9a67 Work in progress, moving to instance based auth 2025-03-16 18:54:55 +01:00
Eldad Fux cc724218b0 fixed formatting 2025-03-16 18:32:46 +01:00
Eldad Fux 706ce4b3b6 WIP - cleaning up auth managment 2025-03-16 18:30:48 +01:00
Eldad Fux c08355df8d Updated composer 2025-03-16 10:34:45 +01:00
Eldad Fux 2d5904e3d0 Merge remote-tracking branch 'origin/feat-sites' into feat-apps-module 2025-03-16 10:26:55 +01:00
Eldad Fux d1318cf016 Updated dependencies 2025-03-10 02:19:57 +01:00
Eldad Fux 91921859a2 Merge remote-tracking branch 'origin/1.6.x' into feat-apps-module 2025-03-10 02:14:35 +01:00
Eldad Fux a058925252 Code formatting 2025-03-10 00:23:22 +01:00
Eldad Fux fadb24f295 revert change to build 2025-03-10 00:21:49 +01:00
Eldad Fux 748119334d Merge remote-tracking branch 'origin/feat-sites' into feat-apps-module 2025-03-10 00:18:23 +01:00
Eldad Fux cb05b87dda Upgraded users to use utopia/auth 2025-03-10 00:08:04 +01:00
Eldad Fux aa36d944db Add teamId to project array in e2e test 2025-03-01 22:00:37 +01:00
18 changed files with 759 additions and 429 deletions
-83
View File
@@ -1,83 +0,0 @@
# Fixes and upgrades for the Appwrite Auth / Users / Teams services.
"product / auth":
- "(auth|session|login|logout|register|2fa|mfa|users|teams|memberships|invite|oauth|oauth2|sso|jwt)"
# Fixes and upgrades for the Appwrite Realtime API.
"api / realtime":
- "(realtime|subscribe|websockets)"
# Console, UI and UX issues
"product / console":
- "(console)"
# Fixes and upgrades for the Appwrite Storage.
"product / storage":
- "(storage|bucket|file|image|preview|download)"
# Fixes and upgrades for the Appwrite Database.
"product / databases":
- "(database|collection|tables|attribute|column|document|row|query|queries|indexes|search|filter|sort|pagination)"
# Fixes and upgrades for the Appwrite Functions.
"product / functions":
- "(function|runtime|deployment|execution|trigger|cron|schedule)"
# Fixes and upgrades for the Appwrite Docs.
# "product / docs":
# -
# Fixes and upgrades for the Appwrite Migrations.
"product / migrations":
- "(migrate|migration)"
# Fixes and upgrades for the Appwrite Messaging.
"product / messaging":
- "(messaging|email|sms|push|provider|topic|target|notification)"
# Fixes and upgrades for the Appwrite Platform.
# "product / platform":
# -
# Fixes and upgrades for database relationships
"feature / relationships":
- "(relationship)"
# Issues found only on Appwrite Cloud
# "product / cloud":
# -
# Fixes and upgrades for the Appwrite VCS.
"product / vcs":
- "(repo|push|vcs|repository)"
# Fixes and upgrades for the Appwrite GraphQL API.
"api / graphql":
- "(graphql|gql|mutation)"
# Fixes and upgrades for the Appwrite Assistant.
"product / assistant":
- "(assistant)"
# Fixes and upgrades for the Appwrite Domains.
"product / domains":
- "(domain|dns|ssl|certificate)"
# Fixes and upgrades for the Appwrite Locale.
"product / locale":
- "(locale|i18n|internationalization|localization|l10n|translation|timezone|country)"
# Fixes and upgrades for the Appwrite Avatars.
"product / avatars":
- "(avatar|initial|flag|icon)"
# Fixes and upgrades for Appwrite Sites.
"product / sites":
- "(site|web|hosting|domain|ssl|certificate|nextjs|nuxt|react|angular|vue|svelte|astro)"
# Fixes and upgrades for the Appwrite CLI.
"sdk / cli":
- "(cli|command line)"
# Issues only found when self-hosting Appwrite
"product / self-hosted":
- "(self-host|self host)"
-22
View File
@@ -1,22 +0,0 @@
name: Auto Label Issue
on:
issues:
types: [opened]
permissions:
issues: write
contents: read
jobs:
labeler:
runs-on: ubuntu-latest
steps:
- name: Issue Labeler
uses: github/issue-labeler@v3.4
with:
configuration-path: .github/labeler.yml
enable-versioned-regex: false
include-title: 1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+3 -3
View File
@@ -79,7 +79,7 @@ return [
[
'key' => 'apple',
'name' => 'Apple',
'version' => '13.2.1',
'version' => '13.2.2',
'url' => 'https://github.com/appwrite/sdk-for-apple',
'package' => 'https://github.com/appwrite/sdk-for-apple',
'enabled' => true,
@@ -226,7 +226,7 @@ return [
[
'key' => 'cli',
'name' => 'Command Line',
'version' => '10.2.1',
'version' => '10.2.2',
'url' => 'https://github.com/appwrite/sdk-for-cli',
'package' => 'https://www.npmjs.com/package/appwrite-cli',
'enabled' => true,
@@ -418,7 +418,7 @@ return [
[
'key' => 'swift',
'name' => 'Swift',
'version' => '13.2.1',
'version' => '13.2.2',
'url' => 'https://github.com/appwrite/sdk-for-swift',
'package' => 'https://github.com/appwrite/sdk-for-swift',
'enabled' => true,
+12 -33
View File
@@ -201,40 +201,19 @@ $createSession = function (string $userId, string $secret, Request $request, Res
default => throw new Exception(Exception::USER_INVALID_TOKEN)
});
$sessionData = [
'$id' => ID::unique(),
'userId' => $user->getId(),
'userInternalId' => $user->getSequence(),
'secret' => Auth::hash($sessionSecret), // One way hash encryption to protect DB leak
'userAgent' => $request->getUserAgent('UNKNOWN'),
'ip' => $request->getIP(),
'factors' => [$factor],
'countryCode' => ($record) ? \strtolower($record['country']['iso_code']) : '--',
'expire' => DateTime::addSeconds(new \DateTime(), $duration)
];
// For OAuth2 tokens, retrieve and add provider tokens from identity
if ($verifiedToken->getAttribute('type') === Auth::TOKEN_TYPE_OAUTH2) {
// Find the most recently updated identity for this user
$identities = $dbForProject->find('identities', [
Query::equal('userInternalId', [$user->getSequence()]),
Query::orderDesc('$updatedAt'),
Query::limit(1)
]);
$latestIdentity = !empty($identities) ? $identities[0] : null;
if ($latestIdentity && !$latestIdentity->isEmpty()) {
$sessionData['provider'] = $latestIdentity->getAttribute('provider', '');
$sessionData['providerUid'] = $latestIdentity->getAttribute('providerUid', '');
$sessionData['providerAccessToken'] = $latestIdentity->getAttribute('providerAccessToken', '');
$sessionData['providerRefreshToken'] = $latestIdentity->getAttribute('providerRefreshToken', '');
$sessionData['providerAccessTokenExpiry'] = $latestIdentity->getAttribute('providerAccessTokenExpiry', '');
}
}
$session = new Document(array_merge(
$sessionData,
[
'$id' => ID::unique(),
'userId' => $user->getId(),
'userInternalId' => $user->getSequence(),
'provider' => Auth::getSessionProviderByTokenType($verifiedToken->getAttribute('type')),
'secret' => Auth::hash($sessionSecret), // One way hash encryption to protect DB leak
'userAgent' => $request->getUserAgent('UNKNOWN'),
'ip' => $request->getIP(),
'factors' => [$factor],
'countryCode' => ($record) ? \strtolower($record['country']['iso_code']) : '--',
'expire' => DateTime::addSeconds(new \DateTime(), $duration)
],
$detector->getOS(),
$detector->getClient(),
$detector->getDevice()
+2 -2
View File
@@ -52,9 +52,9 @@
"utopia-php/cache": "0.13.*",
"utopia-php/cli": "0.15.*",
"utopia-php/config": "0.2.*",
"utopia-php/database": "2.*",
"utopia-php/database": "3.*",
"utopia-php/detector": "0.1.*",
"utopia-php/domains": "0.8.*",
"utopia-php/domains": "0.9.*",
"utopia-php/dns": "0.3.*",
"utopia-php/dsn": "0.2.1",
"utopia-php/framework": "0.33.*",
Generated
+384 -70
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "568800edca746c4e8d0d50648b25f589",
"content-hash": "b48bd33d40081c107b826f78981e0a54",
"packages": [
{
"name": "adhocore/jwt",
@@ -756,16 +756,16 @@
},
{
"name": "google/protobuf",
"version": "v4.32.1",
"version": "v4.33.0",
"source": {
"type": "git",
"url": "https://github.com/protocolbuffers/protobuf-php.git",
"reference": "c4ed1c1f9bbc1e91766e2cd6c0af749324fe87cb"
"reference": "b50269e23204e5ae859a326ec3d90f09efe3047d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/c4ed1c1f9bbc1e91766e2cd6c0af749324fe87cb",
"reference": "c4ed1c1f9bbc1e91766e2cd6c0af749324fe87cb",
"url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/b50269e23204e5ae859a326ec3d90f09efe3047d",
"reference": "b50269e23204e5ae859a326ec3d90f09efe3047d",
"shasum": ""
},
"require": {
@@ -794,9 +794,9 @@
"proto"
],
"support": {
"source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.32.1"
"source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.33.0"
},
"time": "2025-09-14T05:14:52+00:00"
"time": "2025-10-15T20:10:28+00:00"
},
{
"name": "league/csv",
@@ -959,6 +959,83 @@
},
"time": "2025-08-20T17:20:16+00:00"
},
{
"name": "mongodb/mongodb",
"version": "2.1.1",
"source": {
"type": "git",
"url": "https://github.com/mongodb/mongo-php-library.git",
"reference": "f399d24905dd42f97dfe0af9706129743ef247ac"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mongodb/mongo-php-library/zipball/f399d24905dd42f97dfe0af9706129743ef247ac",
"reference": "f399d24905dd42f97dfe0af9706129743ef247ac",
"shasum": ""
},
"require": {
"composer-runtime-api": "^2.0",
"ext-mongodb": "^2.1",
"php": "^8.1",
"psr/log": "^1.1.4|^2|^3",
"symfony/polyfill-php85": "^1.32"
},
"replace": {
"mongodb/builder": "*"
},
"require-dev": {
"doctrine/coding-standard": "^12.0",
"phpunit/phpunit": "^10.5.35",
"rector/rector": "^1.2",
"squizlabs/php_codesniffer": "^3.7",
"vimeo/psalm": "6.5.*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"files": [
"src/functions.php"
],
"psr-4": {
"MongoDB\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Andreas Braun",
"email": "andreas.braun@mongodb.com"
},
{
"name": "Jeremy Mikola",
"email": "jmikola@gmail.com"
},
{
"name": "Jérôme Tamarelle",
"email": "jerome.tamarelle@mongodb.com"
}
],
"description": "MongoDB driver library",
"homepage": "https://jira.mongodb.org/browse/PHPLIB",
"keywords": [
"database",
"driver",
"mongodb",
"persistence"
],
"support": {
"issues": "https://github.com/mongodb/mongo-php-library/issues",
"source": "https://github.com/mongodb/mongo-php-library/tree/2.1.1"
},
"time": "2025-08-13T20:50:05+00:00"
},
{
"name": "mustangostang/spyc",
"version": "0.6.3",
@@ -3017,6 +3094,86 @@
],
"time": "2025-07-08T02:45:35+00:00"
},
{
"name": "symfony/polyfill-php85",
"version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php85.git",
"reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91",
"reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91",
"shasum": ""
},
"require": {
"php": ">=7.2"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Php85\\": ""
},
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 8.5+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php85/tree/v1.33.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2025-06-23T16:12:55+00:00"
},
{
"name": "symfony/service-contracts",
"version": "v3.6.0",
@@ -3293,16 +3450,16 @@
},
{
"name": "utopia-php/abuse",
"version": "1.0.1",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/abuse.git",
"reference": "cd591568791556d246d901d6aaf9935ab02c3f9a"
"reference": "611fa66a97e87c0dbbc133a717d970da7a5ca828"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/cd591568791556d246d901d6aaf9935ab02c3f9a",
"reference": "cd591568791556d246d901d6aaf9935ab02c3f9a",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/611fa66a97e87c0dbbc133a717d970da7a5ca828",
"reference": "611fa66a97e87c0dbbc133a717d970da7a5ca828",
"shasum": ""
},
"require": {
@@ -3310,7 +3467,7 @@
"ext-pdo": "*",
"ext-redis": "*",
"php": ">=8.0",
"utopia-php/database": "2.*"
"utopia-php/database": "*"
},
"require-dev": {
"laravel/pint": "1.*",
@@ -3338,9 +3495,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/abuse/issues",
"source": "https://github.com/utopia-php/abuse/tree/1.0.1"
"source": "https://github.com/utopia-php/abuse/tree/1.0.2"
},
"time": "2025-09-04T12:46:54+00:00"
"time": "2025-10-20T07:18:33+00:00"
},
{
"name": "utopia-php/analytics",
@@ -3390,21 +3547,21 @@
},
{
"name": "utopia-php/audit",
"version": "1.0.1",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/audit.git",
"reference": "5ef26d6a2ab2db7bb86288a1a6ef970307b46f22"
"reference": "8c17065c2473d4ca799f65585ca74eb53e1be211"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/5ef26d6a2ab2db7bb86288a1a6ef970307b46f22",
"reference": "5ef26d6a2ab2db7bb86288a1a6ef970307b46f22",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/8c17065c2473d4ca799f65585ca74eb53e1be211",
"reference": "8c17065c2473d4ca799f65585ca74eb53e1be211",
"shasum": ""
},
"require": {
"php": ">=8.0",
"utopia-php/database": "2.*"
"utopia-php/database": "*"
},
"require-dev": {
"laravel/pint": "1.*",
@@ -3431,9 +3588,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/audit/issues",
"source": "https://github.com/utopia-php/audit/tree/1.0.1"
"source": "https://github.com/utopia-php/audit/tree/1.0.2"
},
"time": "2025-09-04T12:46:43+00:00"
"time": "2025-10-20T07:14:26+00:00"
},
{
"name": "utopia-php/cache",
@@ -3634,30 +3791,80 @@
"time": "2020-10-24T09:49:09+00:00"
},
{
"name": "utopia-php/database",
"version": "2.3.2",
"name": "utopia-php/console",
"version": "0.0.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/database.git",
"reference": "35c978ddd20b649d119296094686d3cc9fcf161f"
"url": "https://github.com/utopia-php/console.git",
"reference": "f77104e4a888fa9cb3e08f32955ec09479ab7a92"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/database/zipball/35c978ddd20b649d119296094686d3cc9fcf161f",
"reference": "35c978ddd20b649d119296094686d3cc9fcf161f",
"url": "https://api.github.com/repos/utopia-php/console/zipball/f77104e4a888fa9cb3e08f32955ec09479ab7a92",
"reference": "f77104e4a888fa9cb3e08f32955ec09479ab7a92",
"shasum": ""
},
"require": {
"php": ">=7.4"
},
"require-dev": {
"laravel/pint": "1.2.*",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^9.3",
"squizlabs/php_codesniffer": "^3.6",
"swoole/ide-helper": "4.8.8"
},
"type": "library",
"autoload": {
"psr-4": {
"Utopia\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "Console helpers for logging, prompting, and executing commands",
"keywords": [
"cli",
"console",
"php",
"terminal",
"utopia"
],
"support": {
"issues": "https://github.com/utopia-php/console/issues",
"source": "https://github.com/utopia-php/console/tree/0.0.1"
},
"time": "2025-10-20T14:41:36+00:00"
},
{
"name": "utopia-php/database",
"version": "3.0.2",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/database.git",
"reference": "b92554e2e7b3b00f0f0acb2b53c6a11e1349b81e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/database/zipball/b92554e2e7b3b00f0f0acb2b53c6a11e1349b81e",
"reference": "b92554e2e7b3b00f0f0acb2b53c6a11e1349b81e",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"ext-mongodb": "*",
"ext-pdo": "*",
"php": ">=8.1",
"utopia-php/cache": "0.13.*",
"utopia-php/framework": "0.33.*",
"utopia-php/mongo": "0.11.*",
"utopia-php/pools": "0.8.*"
},
"require-dev": {
"fakerphp/faker": "1.23.*",
"laravel/pint": "1.*",
"laravel/pint": "*",
"pcov/clobber": "2.*",
"phpstan/phpstan": "1.*",
"phpunit/phpunit": "9.*",
@@ -3685,9 +3892,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/database/issues",
"source": "https://github.com/utopia-php/database/tree/2.3.2"
"source": "https://github.com/utopia-php/database/tree/3.0.2"
},
"time": "2025-10-07T03:09:32+00:00"
"time": "2025-10-20T23:58:56+00:00"
},
{
"name": "utopia-php/detector",
@@ -3792,21 +3999,22 @@
},
{
"name": "utopia-php/domains",
"version": "0.8.2",
"version": "0.9.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/domains.git",
"reference": "caa294dcebd05c8af876c8afef3e992faccdf645"
"reference": "99b4ec95d5d6b7a5c990a66c56412212d9af37e7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/domains/zipball/caa294dcebd05c8af876c8afef3e992faccdf645",
"reference": "caa294dcebd05c8af876c8afef3e992faccdf645",
"url": "https://api.github.com/repos/utopia-php/domains/zipball/99b4ec95d5d6b7a5c990a66c56412212d9af37e7",
"reference": "99b4ec95d5d6b7a5c990a66c56412212d9af37e7",
"shasum": ""
},
"require": {
"php": ">=8.0",
"utopia-php/framework": "0.33.*"
"utopia-php/cache": "0.13.*",
"utopia-php/validators": "0.0.*"
},
"require-dev": {
"laravel/pint": "1.2.*",
@@ -3847,9 +4055,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/domains/issues",
"source": "https://github.com/utopia-php/domains/tree/0.8.2"
"source": "https://github.com/utopia-php/domains/tree/0.9.1"
},
"time": "2025-10-06T09:56:54+00:00"
"time": "2025-10-21T14:52:27+00:00"
},
{
"name": "utopia-php/dsn",
@@ -4187,16 +4395,16 @@
},
{
"name": "utopia-php/migration",
"version": "1.1.0",
"version": "1.3.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/migration.git",
"reference": "6fb6f8f032cd34c3c65728a55d494adeac2ff038"
"reference": "b6985b235ab64f07a6b88569e20cf9b2df7d838c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/migration/zipball/6fb6f8f032cd34c3c65728a55d494adeac2ff038",
"reference": "6fb6f8f032cd34c3c65728a55d494adeac2ff038",
"url": "https://api.github.com/repos/utopia-php/migration/zipball/b6985b235ab64f07a6b88569e20cf9b2df7d838c",
"reference": "b6985b235ab64f07a6b88569e20cf9b2df7d838c",
"shasum": ""
},
"require": {
@@ -4204,9 +4412,9 @@
"ext-curl": "*",
"ext-openssl": "*",
"php": ">=8.1",
"utopia-php/database": "2.*",
"utopia-php/console": "0.0.*",
"utopia-php/database": "3.*",
"utopia-php/dsn": "0.2.*",
"utopia-php/framework": "0.33.*",
"utopia-php/storage": "0.18.*"
},
"require-dev": {
@@ -4214,7 +4422,6 @@
"laravel/pint": "1.*",
"phpstan/phpstan": "1.*",
"phpunit/phpunit": "11.*",
"utopia-php/cli": "0.16.*",
"vlucas/phpdotenv": "5.*"
},
"type": "library",
@@ -4237,9 +4444,70 @@
],
"support": {
"issues": "https://github.com/utopia-php/migration/issues",
"source": "https://github.com/utopia-php/migration/tree/1.1.0"
"source": "https://github.com/utopia-php/migration/tree/1.3.1"
},
"time": "2025-09-10T05:45:30+00:00"
"time": "2025-10-21T08:13:54+00:00"
},
{
"name": "utopia-php/mongo",
"version": "0.11.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/mongo.git",
"reference": "34bc0cda8ea368cde68702a6fffe2c3ac625398e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/mongo/zipball/34bc0cda8ea368cde68702a6fffe2c3ac625398e",
"reference": "34bc0cda8ea368cde68702a6fffe2c3ac625398e",
"shasum": ""
},
"require": {
"ext-mongodb": "2.1.*",
"mongodb/mongodb": "2.1.*",
"php": ">=8.0",
"ramsey/uuid": "4.9.*"
},
"require-dev": {
"fakerphp/faker": "1.*",
"laravel/pint": "*",
"phpstan/phpstan": "*",
"phpunit/phpunit": "9.*",
"swoole/ide-helper": "5.1.*"
},
"type": "library",
"autoload": {
"psr-4": {
"Utopia\\Mongo\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Eldad Fux",
"email": "eldad@appwrite.io"
},
{
"name": "Wess",
"email": "wess@appwrite.io"
}
],
"description": "A simple library to manage Mongo database",
"keywords": [
"database",
"mongo",
"php",
"upf",
"utopia"
],
"support": {
"issues": "https://github.com/utopia-php/mongo/issues",
"source": "https://github.com/utopia-php/mongo/tree/0.11.0"
},
"time": "2025-10-20T11:11:23+00:00"
},
{
"name": "utopia-php/orchestration",
@@ -4779,6 +5047,52 @@
},
"time": "2025-03-17T11:57:52+00:00"
},
{
"name": "utopia-php/validators",
"version": "0.0.2",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/validators.git",
"reference": "894210695c5d35fa248fb65f7fe7237b6ff4fb0b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/validators/zipball/894210695c5d35fa248fb65f7fe7237b6ff4fb0b",
"reference": "894210695c5d35fa248fb65f7fe7237b6ff4fb0b",
"shasum": ""
},
"require": {
"php": ">=8.1"
},
"require-dev": {
"ext-xdebug": "*",
"laravel/pint": "^1.2",
"phpstan/phpstan": "1.*",
"phpunit/phpunit": "^9.5.25"
},
"type": "library",
"autoload": {
"psr-4": {
"Utopia\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "A lightweight collection of reusable validators for Utopia projects",
"keywords": [
"php",
"utopia",
"validation",
"validator"
],
"support": {
"issues": "https://github.com/utopia-php/validators/issues",
"source": "https://github.com/utopia-php/validators/tree/0.0.2"
},
"time": "2025-10-20T21:52:28+00:00"
},
{
"name": "utopia-php/vcs",
"version": "0.11.0",
@@ -4879,28 +5193,28 @@
},
{
"name": "webmozart/assert",
"version": "1.11.0",
"version": "1.12.0",
"source": {
"type": "git",
"url": "https://github.com/webmozarts/assert.git",
"reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991"
"reference": "541057574806f942c94662b817a50f63f7345360"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991",
"reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991",
"url": "https://api.github.com/repos/webmozarts/assert/zipball/541057574806f942c94662b817a50f63f7345360",
"reference": "541057574806f942c94662b817a50f63f7345360",
"shasum": ""
},
"require": {
"ext-ctype": "*",
"ext-date": "*",
"ext-filter": "*",
"php": "^7.2 || ^8.0"
},
"conflict": {
"phpstan/phpstan": "<0.12.20",
"vimeo/psalm": "<4.6.1 || 4.6.2"
},
"require-dev": {
"phpunit/phpunit": "^8.5.13"
"suggest": {
"ext-intl": "",
"ext-simplexml": "",
"ext-spl": ""
},
"type": "library",
"extra": {
@@ -4931,9 +5245,9 @@
],
"support": {
"issues": "https://github.com/webmozarts/assert/issues",
"source": "https://github.com/webmozarts/assert/tree/1.11.0"
"source": "https://github.com/webmozarts/assert/tree/1.12.0"
},
"time": "2022-06-03T18:03:27+00:00"
"time": "2025-10-20T12:43:39+00:00"
},
{
"name": "webonyx/graphql-php",
@@ -5004,16 +5318,16 @@
"packages-dev": [
{
"name": "appwrite/sdk-generator",
"version": "1.4.4",
"version": "1.4.6",
"source": {
"type": "git",
"url": "https://github.com/appwrite/sdk-generator.git",
"reference": "a20b20cfd70a1879f0d0fb2b4f669aa5ed836c49"
"reference": "997e27a1224767a8da890454213d3123936b64bc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/a20b20cfd70a1879f0d0fb2b4f669aa5ed836c49",
"reference": "a20b20cfd70a1879f0d0fb2b4f669aa5ed836c49",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/997e27a1224767a8da890454213d3123936b64bc",
"reference": "997e27a1224767a8da890454213d3123936b64bc",
"shasum": ""
},
"require": {
@@ -5049,9 +5363,9 @@
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
"support": {
"issues": "https://github.com/appwrite/sdk-generator/issues",
"source": "https://github.com/appwrite/sdk-generator/tree/1.4.4"
"source": "https://github.com/appwrite/sdk-generator/tree/1.4.6"
},
"time": "2025-10-13T09:20:49+00:00"
"time": "2025-10-21T08:49:37+00:00"
},
{
"name": "doctrine/annotations",
@@ -5528,16 +5842,16 @@
},
{
"name": "nikic/php-parser",
"version": "v5.6.1",
"version": "v5.6.2",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2"
"reference": "3a454ca033b9e06b63282ce19562e892747449bb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
"reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb",
"reference": "3a454ca033b9e06b63282ce19562e892747449bb",
"shasum": ""
},
"require": {
@@ -5580,9 +5894,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1"
"source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2"
},
"time": "2025-08-13T20:13:15+00:00"
"time": "2025-10-21T19:32:17+00:00"
},
{
"name": "phar-io/manifest",
+4
View File
@@ -1,5 +1,9 @@
# Change Log
## 13.2.2
* Fix issue: Missing AppwriteEnums dependency causing build failure
## 13.2.1
* Add transaction support for Databases and TablesDB
+6
View File
@@ -1,5 +1,11 @@
# Change Log
## 10.2.2
* Fix `logout` command showing duplicate sessions
* Fix `logout` command showing a blank email even when logged out
* Add syncing of `tablesDB` resource during `push tables` command
## 10.2.1
* Add transaction support for Databases and TablesDB
+4
View File
@@ -1,5 +1,9 @@
# Change Log
## 13.2.2
* Fix issue: Missing AppwriteEnums dependency causing build failure
## 13.2.1
* Add transaction support for Databases and TablesDB
@@ -160,7 +160,7 @@ class Create extends Action
throw new Exception($this->getParentInvalidTypeException(), "Cannot create an index for a relationship $contextType: " . $oldAttributes[$attributeIndex]['key']);
}
// ensure attribute is available
// Ensure attribute is available
if ($attributeStatus !== 'available') {
$contextType = ucfirst($contextType);
throw new Exception($this->getParentNotAvailableException(), "$contextType not available: " . $oldAttributes[$attributeIndex]['key']);
@@ -171,7 +171,7 @@ class Create extends Action
}
if ($attributeArray === true) {
$lengths[$i] = Database::ARRAY_INDEX_LENGTH;
$lengths[$i] = Database::MAX_ARRAY_INDEX_LENGTH;
$orders[$i] = null;
}
}
@@ -190,21 +190,18 @@ class Create extends Action
'orders' => $orders,
]);
$maxIndexLength = $dbForProject->getAdapter()->getMaxIndexLength();
$internalIndexesKeys = $dbForProject->getAdapter()->getInternalIndexesKeys();
$supportForIndexArray = $dbForProject->getAdapter()->getSupportForIndexArray();
$supportForSpatialAttributes = $dbForProject->getAdapter()->getSupportForSpatialAttributes();
$supportForSpatialIndexNull = $dbForProject->getAdapter()->getSupportForSpatialIndexNull();
$supportForSpatialIndexOrder = $dbForProject->getAdapter()->getSupportForSpatialIndexOrder();
$validator = new IndexValidator(
$collection->getAttribute('attributes'),
$maxIndexLength,
$internalIndexesKeys,
$supportForIndexArray,
$supportForSpatialAttributes,
$supportForSpatialIndexNull,
$supportForSpatialIndexOrder
$collection->getAttribute('indexes'),
$dbForProject->getAdapter()->getMaxIndexLength(),
$dbForProject->getAdapter()->getInternalIndexesKeys(),
$dbForProject->getAdapter()->getSupportForIndexArray(),
$dbForProject->getAdapter()->getSupportForSpatialIndexNull(),
$dbForProject->getAdapter()->getSupportForSpatialIndexOrder(),
$dbForProject->getAdapter()->getSupportForVectors(),
$dbForProject->getAdapter()->getSupportForAttributes(),
$dbForProject->getAdapter()->getSupportForMultipleFulltextIndexes(),
$dbForProject->getAdapter()->getSupportForIdenticalIndexes()
);
if (!$validator->isValid($index)) {
@@ -105,9 +105,7 @@ class Get extends Action
$response
->setContentType('application/gzip')
->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate')
->addHeader('Expires', '0')
->addHeader('Pragma', 'no-cache')
->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days
->addHeader('X-Peak', \memory_get_peak_usage())
->addHeader('Content-Disposition', 'attachment; filename="' . $deploymentId . '-' . $type . '.tar.gz"');
@@ -134,6 +132,7 @@ class Get extends Action
->setStatusCode(Response::STATUS_CODE_PARTIALCONTENT);
$response->send($device->read($path, $start, ($end - $start + 1)));
return;
}
if ($size > APP_STORAGE_READ_BUFFER) {
+1 -1
View File
@@ -428,7 +428,7 @@ class StatsUsage extends Action
/**
* Sort by unique index key reduce locks/deadlocks
*/
usort($projectStats['stats'], function ($a, $b) {
usort($projectStats['stats'], function ($a, $b) use ($sequence) {
// Metric DESC
$cmp = strcmp($b['metric'], $a['metric']);
if ($cmp !== 0) {
+1 -1
View File
@@ -193,7 +193,7 @@ class Comment
}
$tip = $this->tips[array_rand($this->tips)];
$text .= "\n<br>\n\n> [!NOTE]\n> $tip\n\n";
$text .= "\n<br>\n\n> [!TIP]\n> $tip\n\n";
return $text;
}
@@ -1281,7 +1281,7 @@ trait DatabasesBase
]);
$this->assertEquals(400, $fulltextReleaseYear['headers']['status-code']);
$this->assertEquals($fulltextReleaseYear['body']['message'], 'Attribute "releaseYear" cannot be part of a FULLTEXT index, must be of type string');
$this->assertEquals($fulltextReleaseYear['body']['message'], 'Attribute "releaseYear" cannot be part of a fulltext index, must be of type string');
$noAttributes = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([
'content-type' => 'application/json',
@@ -1465,7 +1465,7 @@ trait DatabasesBase
$this->assertEquals([128, 200], $index['body']['lengths']);
// Test case for lengths array overriding
// set a length for an array attribute, it should get overriden with Database::ARRAY_INDEX_LENGTH
// set a length for an array attribute, it should get overriden with Database::MAX_ARRAY_INDEX_LENGTH
$create = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$collectionId}/indexes", [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -1483,7 +1483,7 @@ trait DatabasesBase
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]);
$this->assertEquals([Database::ARRAY_INDEX_LENGTH], $index['body']['lengths']);
$this->assertEquals([Database::MAX_ARRAY_INDEX_LENGTH], $index['body']['lengths']);
// Test case for count of lengths greater than attributes (should throw 400)
$create = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$collectionId}/indexes", [
@@ -1281,7 +1281,7 @@ trait DatabasesBase
]);
$this->assertEquals(400, $fulltextReleaseYear['headers']['status-code']);
$this->assertEquals($fulltextReleaseYear['body']['message'], 'Attribute "releaseYear" cannot be part of a FULLTEXT index, must be of type string');
$this->assertEquals($fulltextReleaseYear['body']['message'], 'Attribute "releaseYear" cannot be part of a fulltext index, must be of type string');
$noAttributes = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $data['moviesId'] . '/indexes', array_merge([
'content-type' => 'application/json',
@@ -113,13 +113,33 @@ class ProjectsConsoleClientTest extends Scope
];
}
/**
* @depends testCreateProject
*/
public function testCreateDuplicateProject($data)
public function testCreateDuplicateProject(): void
{
$teamId = $data['teamId'] ?? '';
$projectId = $data['projectId'] ?? '';
// Create a team
$team = $this->client->call(Client::METHOD_POST, '/teams', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'teamId' => ID::unique(),
'name' => 'Duplicate Test Team',
]);
$this->assertEquals(201, $team['headers']['status-code']);
$teamId = $team['body']['$id'];
// Create a project
$projectId = ID::unique();
$response = $this->client->call(Client::METHOD_POST, '/projects', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'projectId' => $projectId,
'name' => 'Original Project',
'teamId' => $teamId,
'region' => System::getEnv('_APP_REGION', 'default')
]);
$this->assertEquals(201, $response['headers']['status-code']);
/**
* Test for FAILURE
@@ -417,12 +437,32 @@ class ProjectsConsoleClientTest extends Scope
return $data;
}
/**
* @depends testCreateProject
*/
public function testGetProject($data): array
public function testGetProject(): void
{
$id = $data['projectId'] ?? '';
// Create a team
$team = $this->client->call(Client::METHOD_POST, '/teams', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'teamId' => ID::unique(),
'name' => 'Get Project Test Team',
]);
$this->assertEquals(201, $team['headers']['status-code']);
// Create a project
$response = $this->client->call(Client::METHOD_POST, '/projects', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'projectId' => ID::unique(),
'name' => 'Project Test',
'teamId' => $team['body']['$id'],
'region' => System::getEnv('_APP_REGION', 'default')
]);
$this->assertEquals(201, $response['headers']['status-code']);
$id = $response['body']['$id'];
/**
* Test for SUCCESS
@@ -440,7 +480,6 @@ class ProjectsConsoleClientTest extends Scope
/**
* Test for FAILURE
*/
$response = $this->client->call(Client::METHOD_GET, '/projects/empty', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -454,8 +493,6 @@ class ProjectsConsoleClientTest extends Scope
], $this->getHeaders()));
$this->assertEquals(400, $response['headers']['status-code']);
return $data;
}
/**
@@ -513,12 +550,33 @@ class ProjectsConsoleClientTest extends Scope
return $data;
}
/**
* @depends testCreateProject
*/
public function testUpdateProject($data): array
public function testUpdateProject(): void
{
$id = $data['projectId'] ?? '';
// Create a team
$team = $this->client->call(Client::METHOD_POST, '/teams', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'teamId' => ID::unique(),
'name' => 'Update Project Test Team',
]);
$this->assertEquals(201, $team['headers']['status-code']);
$teamId = $team['body']['$id'];
// Create a project
$response = $this->client->call(Client::METHOD_POST, '/projects', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'projectId' => ID::unique(),
'name' => 'Project Test',
'teamId' => $teamId,
'region' => System::getEnv('_APP_REGION', 'default')
]);
$this->assertEquals(201, $response['headers']['status-code']);
$id = $response['body']['$id'];
/**
* Test for SUCCESS
@@ -543,7 +601,6 @@ class ProjectsConsoleClientTest extends Scope
/**
* Test for FAILURE
*/
$response = $this->client->call(Client::METHOD_POST, '/projects', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -553,8 +610,6 @@ class ProjectsConsoleClientTest extends Scope
]);
$this->assertEquals(401, $response['headers']['status-code']);
return ['projectId' => $projectId];
}
/**
@@ -608,11 +663,35 @@ class ProjectsConsoleClientTest extends Scope
/**
* @group smtpAndTemplates
* @depends testCreateProject
*/
public function testCreateProjectSMTPTests($data): array
public function testCreateProjectSMTPTests(): void
{
$id = $data['projectId'];
// Create a team
$team = $this->client->call(Client::METHOD_POST, '/teams', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'teamId' => ID::unique(),
'name' => 'Create Project SMTP Tests Test Team',
]);
$this->assertEquals(201, $team['headers']['status-code']);
$teamId = $team['body']['$id'];
// Create a project
$response = $this->client->call(Client::METHOD_POST, '/projects', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'projectId' => ID::unique(),
'name' => 'Project Test',
'teamId' => $teamId,
'region' => System::getEnv('_APP_REGION', 'default')
]);
$this->assertEquals(201, $response['headers']['status-code']);
$id = $response['body']['$id'];
$response = $this->client->call(Client::METHOD_POST, '/projects/' . $id . '/smtp/tests', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -681,8 +760,6 @@ class ProjectsConsoleClientTest extends Scope
]);
$this->assertEquals(400, $response['headers']['status-code']);
return $data;
}
/**
@@ -794,7 +871,6 @@ class ProjectsConsoleClientTest extends Scope
/**
* Test for SUCCESS
*/
$response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/duration', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -951,10 +1027,32 @@ class ProjectsConsoleClientTest extends Scope
return ['projectId' => $projectId];
}
/** @depends testCreateProject */
public function testUpdateProjectInvalidateSessions($data): array
public function testUpdateProjectInvalidateSessions(): void
{
$id = $data['projectId'];
// Create a team for the test project
$team = $this->client->call(Client::METHOD_POST, '/teams', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'teamId' => ID::unique(),
'name' => 'Session Invalidation Test Team',
]);
$this->assertEquals(201, $team['headers']['status-code']);
// Create a test project
$response = $this->client->call(Client::METHOD_POST, '/projects', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'projectId' => ID::unique(),
'name' => 'Session Invalidation Test Project',
'teamId' => $team['body']['$id'],
'region' => System::getEnv('_APP_REGION', 'default')
]);
$this->assertEquals(201, $response['headers']['status-code']);
$id = $response['body']['$id'];
// Check defaults
$response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([
@@ -996,22 +1094,41 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertTrue($response['body']['authInvalidateSessions']);
return $data;
}
/**
* @depends testCreateProject
*/
public function testUpdateProjectOAuth($data): array
public function testUpdateProjectOAuth(): void
{
$id = $data['projectId'] ?? '';
// Create a team
$team = $this->client->call(Client::METHOD_POST, '/teams', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'teamId' => ID::unique(),
'name' => 'Update Project OAuth Test Team',
]);
$this->assertEquals(201, $team['headers']['status-code']);
$teamId = $team['body']['$id'];
// Create a project
$response = $this->client->call(Client::METHOD_POST, '/projects', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'projectId' => ID::unique(),
'name' => 'Project Test',
'teamId' => $teamId,
'region' => System::getEnv('_APP_REGION', 'default')
]);
$this->assertEquals(201, $response['headers']['status-code']);
$id = $response['body']['$id'];
$providers = require(__DIR__ . '/../../../../app/config/oAuthProviders.php');
/**
* Test for SUCCESS
*/
foreach ($providers as $key => $provider) {
$response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/oauth2', array_merge([
'content-type' => 'application/json',
@@ -1096,7 +1213,6 @@ class ProjectsConsoleClientTest extends Scope
/**
* Test for FAILURE
*/
$response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/oauth2', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -1107,18 +1223,37 @@ class ProjectsConsoleClientTest extends Scope
]);
$this->assertEquals(400, $response['headers']['status-code']);
return $data;
}
/**
* @depends testCreateProject
*/
public function testUpdateProjectAuthStatus($data): array
public function testUpdateProjectAuthStatus(): void
{
$id = $data['projectId'] ?? '';
$auth = require(__DIR__ . '/../../../../app/config/auth.php');
// Create a team
$team = $this->client->call(Client::METHOD_POST, '/teams', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'teamId' => ID::unique(),
'name' => 'Update Project Auth Status Test Team',
]);
$this->assertEquals(201, $team['headers']['status-code']);
$teamId = $team['body']['$id'];
// Create a project
$response = $this->client->call(Client::METHOD_POST, '/projects', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'projectId' => ID::unique(),
'name' => 'Project Test',
'teamId' => $teamId,
'region' => System::getEnv('_APP_REGION', 'default')
]);
$this->assertEquals(201, $response['headers']['status-code']);
$id = $response['body']['$id'];
$auth = require(__DIR__ . '/../../../../app/config/auth.php');
$originalEmail = uniqid() . 'user@localhost.test';
$originalPassword = 'password';
$originalName = 'User Name';
@@ -1252,8 +1387,6 @@ class ProjectsConsoleClientTest extends Scope
'status' => true,
]);
}
return $data;
}
/**
@@ -1458,9 +1591,6 @@ class ProjectsConsoleClientTest extends Scope
$sessionCookie = $response['headers']['set-cookie'];
$sessionId2 = $response['body']['$id'];
// request was called in parallel and test failed
sleep(5);
/**
* List sessions
*/
@@ -3358,15 +3488,15 @@ class ProjectsConsoleClientTest extends Scope
{
$id = $data['projectId'] ?? '';
sleep(1);
$this->assertEventually(function () use ($id) {
$response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
$response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/platforms', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(8, $response['body']['total']);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(8, $response['body']['total']);
});
/**
* Test for FAILURE
@@ -4016,16 +4146,16 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(204, $project1['headers']['status-code']);
\sleep(3);
// Ensure project 2 user is still there
$user2 = $this->client->call(Client::METHOD_GET, '/users/' . $user2['body']['$id'], [
'content-type' => 'application/json',
'x-appwrite-project' => $project2Id,
'x-appwrite-key' => $key2['body']['secret'],
]);
$this->assertEventually(function () use ($user2, $project2Id, $key2) {
$response = $this->client->call(Client::METHOD_GET, '/users/' . $user2['body']['$id'], [
'content-type' => 'application/json',
'x-appwrite-project' => $project2Id,
'x-appwrite-key' => $key2['body']['secret'],
]);
$this->assertEquals(200, $user2['headers']['status-code']);
$this->assertEquals(200, $response['headers']['status-code']);
});
// Create another user in project 2 in case read hits stale cache
$user3 = $this->client->call(Client::METHOD_POST, '/users', [
+49 -49
View File
@@ -147,25 +147,25 @@ trait WebhooksBase
$this->assertEquals($extra['body']['key'], 'extra');
// wait for database worker to kick in
sleep(10);
$webhook = $this->getLastRequest();
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
$this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString('databases.' . $databaseId . '.collections.*.attributes.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString('databases.' . $databaseId . '.collections.*.attributes.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}.attributes.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}.attributes.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
$this->assertNotEmpty($webhook['data']['key']);
$this->assertEquals($webhook['data']['key'], 'extra');
$this->assertEventually(function () use ($databaseId, $actorsId) {
$webhook = $this->getLastRequest();
$this->assertNotEmpty($webhook);
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
$this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString('databases.' . $databaseId . '.collections.*.attributes.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString('databases.' . $databaseId . '.collections.*.attributes.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}.attributes.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}.attributes.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
$this->assertNotEmpty($webhook['data']['key']);
$this->assertEquals($webhook['data']['key'], 'extra');
}, 15000, 500);
$removed = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $data['actorsId'] . '/attributes/' . $extra['body']['key'], array_merge([
'content-type' => 'application/json',
@@ -498,25 +498,25 @@ trait WebhooksBase
$this->assertEquals($extra['body']['key'], 'extra');
// wait for database worker to kick in
sleep(10);
$webhook = $this->getLastRequest();
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*.columns.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*.columns.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.columns.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.columns.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
$this->assertNotEmpty($webhook['data']['key']);
$this->assertEquals($webhook['data']['key'], 'extra');
$this->assertEventually(function () use ($databaseId, $actorsId) {
$webhook = $this->getLastRequest();
$this->assertNotEmpty($webhook);
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
$this->assertEquals($webhook['method'], 'POST');
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*.columns.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*.columns.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.columns.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.columns.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
$this->assertNotEmpty($webhook['data']['key']);
$this->assertEquals($webhook['data']['key'], 'extra');
}, 15000, 500);
$removed = $this->client->call(Client::METHOD_DELETE, '/tablesdb/' . $databaseId . '/tables/' . $data['actorsId'] . '/columns/' . $extra['body']['key'], array_merge([
'content-type' => 'application/json',
@@ -1487,17 +1487,17 @@ trait WebhooksBase
$this->assertNotEmpty($newCollection['body']['$id']);
}
sleep(10);
$this->assertEventually(function () use ($projectId, $webhookId) {
$webhook = $this->client->call(Client::METHOD_GET, '/projects/' . $projectId . '/webhooks/' . $webhookId, array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
'x-appwrite-project' => 'console',
]));
$webhook = $this->client->call(Client::METHOD_GET, '/projects/' . $projectId . '/webhooks/' . $webhookId, array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json',
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
'x-appwrite-project' => 'console',
]));
// assert that the webhook is now disabled after 10 consecutive failures
$this->assertEquals($webhook['body']['enabled'], false);
$this->assertEquals($webhook['body']['attempts'], 10);
// assert that the webhook is now disabled after 10 consecutive failures
$this->assertEquals($webhook['body']['enabled'], false);
$this->assertEquals($webhook['body']['attempts'], 10);
}, 15000, 500);
}
}
@@ -2,6 +2,7 @@
namespace Tests\E2E\Services\Webhooks;
use Appwrite\Tests\Async;
use CURLFile;
use Tests\E2E\Client;
use Tests\E2E\Scopes\ProjectCustom;
@@ -15,6 +16,7 @@ use Utopia\Database\Validator\Datetime as DatetimeValidator;
class WebhooksCustomServerTest extends Scope
{
use Async;
use WebhooksBase;
use ProjectCustom;
use SideServer;
@@ -89,24 +91,24 @@ class WebhooksCustomServerTest extends Scope
$this->assertEquals('fullname', $index['body']['key']);
// wait for database worker to create index
sleep(5);
$this->assertEventually(function () use ($databaseId, $actorsId) {
$webhook = $this->getLastRequest();
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
$webhook = $this->getLastRequest();
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
$this->assertEquals('POST', $webhook['method']);
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
$this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString('databases.' . $databaseId . '.collections.*.indexes.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString('databases.' . $databaseId . '.collections.*.indexes.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}.indexes.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}.indexes.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
$this->assertTrue(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''));
$this->assertEquals('POST', $webhook['method']);
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
$this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString('databases.' . $databaseId . '.collections.*.indexes.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString('databases.' . $databaseId . '.collections.*.indexes.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}.indexes.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("databases.{$databaseId}.collections.{$actorsId}.indexes.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
$this->assertTrue(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''));
}, 10000, 500);
// Remove index
$this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $data['actorsId'] . '/indexes/' . $index['body']['key'], array_merge([
@@ -275,24 +277,24 @@ class WebhooksCustomServerTest extends Scope
$this->assertEquals('fullname', $index['body']['key']);
// wait for database worker to create index
sleep(5);
$this->assertEventually(function () use ($databaseId, $actorsId) {
$webhook = $this->getLastRequest();
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
$webhook = $this->getLastRequest();
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
$this->assertEquals('POST', $webhook['method']);
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*.indexes.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*.indexes.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.indexes.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.indexes.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
$this->assertTrue(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''));
$this->assertEquals('POST', $webhook['method']);
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*.indexes.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*.indexes.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.indexes.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.indexes.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
$this->assertTrue(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''));
}, 10000, 500);
// Remove index
$this->client->call(Client::METHOD_DELETE, '/tablesdb/' . $databaseId . '/tables/' . $data['actorsId'] . '/indexes/' . $index['body']['key'], array_merge([
@@ -735,27 +737,27 @@ class WebhooksCustomServerTest extends Scope
$this->assertNotEmpty($response['body']['$id']);
// Wait for deployment to be built.
sleep(5);
$this->assertEventually(function () use ($deploymentId, $id) {
$webhook = $this->getLastRequest();
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
$webhook = $this->getLastRequest();
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
$this->assertEquals('POST', $webhook['method']);
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
// $this->assertStringContainsString('functions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString('functions.*.deployments.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString('functions.*.deployments.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.*.deployments.{$deploymentId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.*.deployments.{$deploymentId}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.{$id}.deployments.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.{$id}.deployments.*.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.{$id}.deployments.{$deploymentId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.{$id}.deployments.{$deploymentId}.update", $webhook['headers']['X-Appwrite-Webhook-Events']); TODO @christyjacob4 : enable test once we allow functions.* events
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
$this->assertEquals('POST', $webhook['method']);
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
// $this->assertStringContainsString('functions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString('functions.*.deployments.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString('functions.*.deployments.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.*.deployments.{$deploymentId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.*.deployments.{$deploymentId}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.{$id}.deployments.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.{$id}.deployments.*.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.{$id}.deployments.{$deploymentId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.{$id}.deployments.{$deploymentId}.update", $webhook['headers']['X-Appwrite-Webhook-Events']); TODO @christyjacob4 : enable test once we allow functions.* events
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
}, 10000, 500);
/**
* Test for FAILURE
@@ -806,27 +808,27 @@ class WebhooksCustomServerTest extends Scope
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
// wait for timeout function to complete
sleep(20);
$this->assertEventually(function () use ($executionId, $id) {
$webhook = $this->getLastRequest();
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
$webhook = $this->getLastRequest();
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
$this->assertEquals('POST', $webhook['method']);
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
// $this->assertStringContainsString('functions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString('functions.*.executions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString('functions.*.executions.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.*.executions.{$executionId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.*.executions.{$executionId}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.{$id}.executions.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.{$id}.executions.*.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.{$id}.executions.{$executionId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.{$id}.executions.{$executionId}.update", $webhook['headers']['X-Appwrite-Webhook-Events']); TODO @christyjacob4 : enable test once we allow functions.* events
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
$this->assertEquals('POST', $webhook['method']);
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
// $this->assertStringContainsString('functions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString('functions.*.executions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString('functions.*.executions.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.*.executions.{$executionId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.*.executions.{$executionId}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.{$id}.executions.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.{$id}.executions.*.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.{$id}.executions.{$executionId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
// $this->assertStringContainsString("functions.{$id}.executions.{$executionId}.update", $webhook['headers']['X-Appwrite-Webhook-Events']); TODO @christyjacob4 : enable test once we allow functions.* events
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
}, 30000, 1000);
/**
* Test for FAILURE