Compare commits

...
Author SHA1 Message Date
Jake BarnbyandGitHub e704e96290 Revert "Feat: Lazy-load relationships" 2025-06-16 11:48:27 -04:00
Jake BarnbyandGitHub a21ccfd694 Merge pull request #9669 from appwrite/lazy-load-relationships
Feat: Lazy-load relationships
2025-06-16 11:48:18 -04:00
Jake Barnby 89f0c28e26 Merge remote-tracking branch 'origin/1.7.x' into 1.8.x
# Conflicts:
#	.coderabbit.yaml
2025-06-16 11:37:50 -04:00
Christy JacobandGitHub ea33588f26 Merge pull request #10017 from appwrite/update-delete-project-signature
Update delete project scope
2025-06-16 18:48:33 +04:00
shimon 384b423129 update deleteProject scope 2025-06-16 17:46:23 +03:00
Christy JacobandGitHub 006153e14a Merge pull request #10016 from appwrite/feat-support-tar-2
feat: tar support
2025-06-16 13:45:59 +04:00
loks0n 9196ae7908 feat: tar support 2025-06-16 10:44:15 +01:00
Christy JacobandGitHub b46a4dfd3e Merge pull request #10005 from appwrite/update-coderabbit-config
chore: update coderabbit config file
2025-06-16 12:43:05 +04:00
Chirag AggarwalandGitHub b096af22a7 Merge branch '1.7.x' into update-coderabbit-config 2025-06-14 12:05:47 +05:30
Chirag Aggarwal c8854e01de chore: formatting 2025-06-14 12:05:40 +05:30
Chirag Aggarwal 089a80e9a3 chore: update coderabbit config file 2025-06-14 11:57:21 +05:30
Steven NguyenandGitHub 52f83c4015 Merge pull request #10004 from appwrite/fix-invalid-factors
fix: prevent 'Attribute "factors" must be an array' error
2025-06-13 10:46:24 -07:00
DarshanandGitHub 9dd5898dfd Merge branch '1.7.x' into fix-invalid-factors 2025-06-13 22:30:43 +05:30
Steven NguyenandGitHub 7b322f8502 Merge pull request #10003 from appwrite/update-assistant
Update appwrite-assistant image version to 0.8.3
2025-06-13 09:35:43 -07:00
Steven Nguyen 160c937dc2 fix: prevent 'Attribute "factors" must be an array' error
Because array_unique() preserves keys, the $factors can go from:

[
    0 => 'password',
    1 => 'totp',
    2 => 'totp',
    3 => 'email'
]

to:

[
    0 => 'password',
    1 => 'totp',
    3 => 'email'
]

and because this is not an array list, the validation fails.

Using array_values() after array_unique() will reset the keys to be sequential, resulting in:

[
    0 => 'password',
    1 => 'totp',
    2 => 'email'
]
2025-06-13 09:17:05 -07:00
Chirag Aggarwal c510af0a90 Update appwrite-assistant image version to 0.8.3 2025-06-13 20:21:03 +05:30
DarshanandGitHub 44a5a3eca1 Merge branch '1.8.x' into lazy-load-relationships 2025-06-13 20:01:01 +05:30
Darshan f09042dfb1 update: swap request/response filters from 1.7.x to 1.8.x. 2025-06-13 16:47:40 +05:30
Matej BačoandGitHub 4704f6f0b0 Merge pull request #9991 from appwrite/feat-ref-param-to-vcs-list-contents
Add ref param to vcs list contents
2025-06-13 12:49:47 +02:00
Khushboo VermaandGitHub 3f14c27c9c Merge branch '1.7.x' into feat-ref-param-to-vcs-list-contents 2025-06-13 16:03:11 +05:30
Matej BačoandGitHub 3ce2ad188a Merge pull request #9966 from appwrite/feat-speed-up-site-tests
Use static code instead of astro in tests
2025-06-13 12:31:08 +02:00
Khushboo Verma 481f1b48b2 Merge branch 'feat-ref-param-to-vcs-list-contents' of github.com:appwrite/appwrite into feat-ref-param-to-vcs-list-contents 2025-06-13 15:55:24 +05:30
Khushboo Verma 221f15313c Update var name and generate specs 2025-06-13 15:55:02 +05:30
Khushboo Verma 4099f8968a Merge branch '1.7.x' into feat-ref-param-to-vcs-list-contents 2025-06-13 15:51:35 +05:30
Matej BačoandGitHub e7c0111229 Merge branch '1.7.x' into feat-speed-up-site-tests 2025-06-13 12:05:48 +02:00
Jake Barnby fc0e1b607d Update database 2025-06-12 14:57:12 -04:00
Jake Barnby bc7b310c51 Merge remote-tracking branch 'origin/1.7.x' into 1.8.x 2025-06-12 12:20:34 -04:00
Jake Barnby cf830affc9 Check not development for plan error 2025-06-12 12:20:21 -04:00
Matej BačoandGitHub 4d650114f2 Merge pull request #10000 from appwrite/chore-remove-endpoint-selector
chore: remove endpoint selector
2025-06-12 15:39:10 +02:00
loks0n bc41838c66 chore: remove endpoint selector 2025-06-12 14:22:17 +01:00
loks0n 3d9e22a6df chore: remove endpoint selector for edge 2025-06-12 14:18:05 +01:00
Khushboo VermaandGitHub 1b6d05a0fb Merge branch '1.7.x' into feat-ref-param-to-vcs-list-contents 2025-06-12 11:45:53 +05:30
Darshan 9f30b0263a simplify: queries. 2025-06-12 09:15:36 +05:30
Darshan 5aa88be49c simplify: queries. 2025-06-12 09:14:02 +05:30
Darshan f6fa1aea99 revert: unnecessary changes. 2025-06-12 09:10:59 +05:30
Darshan df9a6d81fd remove: unnecessary change. 2025-06-12 09:07:56 +05:30
Darshan 6f493e7c29 remove: unnecessary change. 2025-06-12 09:07:22 +05:30
DarshanandGitHub d5bbb95f3b Merge branch '1.8.x' into lazy-load-relationships 2025-06-12 09:05:56 +05:30
Darshan 87c9f93fa7 address comment. 2025-06-12 09:05:37 +05:30
Jake Barnby 517870dd45 Test timing 2025-06-11 20:41:02 -04:00
Jake Barnby 7dd45b0644 Merge remote-tracking branch 'origin/1.7.x' into 1.8.x
# Conflicts:
#	src/Appwrite/Platform/Workers/StatsUsageDump.php
2025-06-11 17:22:20 -04:00
Jake BarnbyandGitHub 7fb4dc5f07 Merge pull request #9997 from ArnabChatterjee20k/dat-452
Transfer control for the migration
2025-06-11 16:05:15 -04:00
Christy JacobandGitHub e267283fa9 Merge pull request #9996 from appwrite/feat-after-build-hook
feat after build hook
2025-06-11 21:16:01 +04:00
ArnabChatterjee20k 84f4a5dba0 added logging of errors instead of throwing 2025-06-11 22:11:43 +05:30
loks0n 0c8ae4f34f feat(builds): after build hook 2025-06-11 16:40:42 +01:00
Christy JacobandGitHub 0e17aeaa57 Merge pull request #9946 from appwrite/fix-usage-queues
Fix usage queues
2025-06-11 18:54:39 +04:00
Christy JacobandGitHub 78d542427a Merge pull request #9995 from appwrite/optimise-maintenance-task
fix: project iteration loop
2025-06-11 18:51:21 +04:00
Christy Jacob b4b28a9cf4 fix: project iteration loop 2025-06-11 18:36:52 +04:00
Khushboo VermaandGitHub 22f64040e3 Merge branch '1.7.x' into feat-ref-param-to-vcs-list-contents 2025-06-11 18:10:58 +05:30
Darshan 93472ac40e remove: response format based tests. 2025-06-11 10:38:22 +05:30
Darshan d6829dfb34 Merge branch '1.8.x' into 'lazy-load-relationships'. 2025-06-11 10:08:51 +05:30
Darshan 4332adaf37 update: tests to correctly run on 1.6.x response format. 2025-06-11 10:06:32 +05:30
Steven NguyenandGitHub c14d40cc5a Merge pull request #9993 from appwrite/re-revert-pla-2914
chore: restore unique filename for health check #9842
2025-06-10 21:34:52 -07:00
Steven NguyenandGitHub eab0faab83 Merge pull request #9987 from appwrite/update-sdks-2
chore: update SDK versions
2025-06-10 21:34:18 -07:00
Chirag Aggarwal 851894947f chore: restore unique filename for health check #9842 2025-06-11 03:55:11 +00:00
Jake Barnby 077c80ca26 Fix exclude 2025-06-10 19:57:41 -04:00
Jake Barnby 082309697c Fix DB delete cache purge 2025-06-10 15:55:54 -04:00
Jake Barnby 963d177b17 Update admin spec 2025-06-10 15:50:18 -04:00
Jake Barnby 178dec01fd Add admin key 2025-06-10 15:44:40 -04:00
Jake Barnby 5f588b0c65 Fix open API specs 2025-06-10 15:22:13 -04:00
Jake Barnby d067d215b1 Generate latest 2025-06-10 15:09:15 -04:00
Jake Barnby a77eea6b55 Fix numeric type values 2025-06-10 15:05:26 -04:00
Jake Barnby d3af2e4735 Add SDK version support 2025-06-10 14:27:19 -04:00
Jake Barnby a82bd62ef6 Remove bundle 2025-06-10 14:11:49 -04:00
Jake Barnby a95a651d30 Add specs 2025-06-10 14:08:21 -04:00
Jake Barnby 8c6f0a4e7b Fix merge 2025-06-10 13:42:41 -04:00
Jake Barnby 52de9030c4 Merge remote-tracking branch 'origin/1.7.x' into 1.8.x 2025-06-10 13:20:02 -04:00
Jake BarnbyandGitHub ff92b23d8e Merge pull request #9986 from appwrite/feat-incr
Add increment + decrement routes
2025-06-10 13:19:24 -04:00
Christy JacobandGitHub 0554f9295b Merge pull request #9989 from appwrite/optimise-maintenance-task
Optimise maintenance task
2025-06-10 20:48:06 +04:00
Jake Barnby ffb27284e5 Type as integer in query base 2025-06-10 11:51:17 -04:00
Jake Barnby e1a291ff21 Consistent messages 2025-06-10 11:50:57 -04:00
Khushboo Verma 72090248e5 Add ref param to vcs list contents 2025-06-10 20:37:37 +05:30
Christy Jacob 261adac306 chore: linter 2025-06-10 16:40:02 +04:00
Chirag Aggarwal a1ff96829d chore: update pkgs 2025-06-10 12:38:48 +00:00
Christy Jacob e8e2bb87f6 chore: update maintenance task to only iterate over active projects 2025-06-10 16:17:38 +04:00
Christy Jacob b1e11ab854 chore: update maintenance task to only iterate over active projects 2025-06-10 16:14:53 +04:00
Christy Jacob bc3e1990d0 chore: update maintenance task to only iterate over active projects 2025-06-10 16:12:24 +04:00
Darshan 357b290e36 revert: unnecessary change added during merge. 2025-06-10 10:46:55 +05:30
Darshan 45619e6093 bump: composer. 2025-06-10 10:41:26 +05:30
Darshan 5b6bc81b29 Merge branch '1.8.x' into 'lazy-load-relationships'. 2025-06-10 10:40:48 +05:30
Darshan 2fa5bc614c add: 1.6.x format tests. 2025-06-10 10:35:51 +05:30
Jake Barnby 6ea61106f4 Update model 2025-06-10 00:37:33 -04:00
Jake Barnby cf13a45188 Docs 2025-06-10 00:36:55 -04:00
Jake Barnby 91b1670e52 Fix event 2025-06-10 00:35:03 -04:00
Jake Barnby e6881c10d4 Fix desc 2025-06-10 00:32:38 -04:00
Jake Barnby 5585a75624 Fix auth skips 2025-06-10 00:22:46 -04:00
Jake Barnby fd7d4db4c4 Fix path param 2025-06-10 00:22:38 -04:00
Jake Barnby 9fc2c5db69 Add increment + decrement routes 2025-06-09 23:56:30 -04:00
Jake Barnby bd4bb48da2 Fix merge 2025-06-09 20:50:02 -04:00
Jake Barnby 41ce945c02 Update lock 2025-06-09 20:23:15 -04:00
Jake Barnby c852cb3ed0 Merge remote-tracking branch 'origin/1.7.x' into 1.8.x
# Conflicts:
#	composer.lock
#	src/Appwrite/Platform/Workers/Audits.php
2025-06-09 20:08:41 -04:00
Darshan fa67144f32 fix: add a small timer again for 1.6.x response format. 2025-06-09 19:59:01 +05:30
Darshan 2202b11a26 fix: cases for backwards compatibility to add database and collection ids when using a wildcard. 2025-06-09 19:45:48 +05:30
Matej BačoandGitHub 166b19b65c Merge pull request #9982 from appwrite/fix-redirect-rule-parent-1.7.x
Fix: Redirect rule parent resource
2025-06-09 14:03:49 +02:00
Matej Bačo d6bcb46b36 Fix specs and sdk generation 2025-06-09 13:47:38 +02:00
Matej Bačo 11f31a15b6 Link parent resource of redirect rule to allow list querying 2025-06-09 13:47:29 +02:00
Darshan 2e0fb694d4 fix: internal ids usage. 2025-06-09 17:08:37 +05:30
Darshan 452aa708df fix: internal ids usage. 2025-06-09 15:03:19 +05:30
Darshan e699c998bb update: remove extra line. 2025-06-09 14:49:06 +05:30
Darshan 564fe5323c revert: local docker config. 2025-06-09 14:47:47 +05:30
Darshan 387e8eaa2f fix: tests 2025-06-09 14:47:13 +05:30
Darshan 17f0f51c46 fix: tests 2025-06-09 14:47:13 +05:30
Darshan 0ee4f3c4ce bump: dependencies; fix: tests and logic. 2025-06-09 14:23:04 +05:30
Darshan e5dc4ac056 Merge branch '1.8.x' into 'lazy-load-relationships'. 2025-06-09 13:55:17 +05:30
Damodar LohaniandGitHub e3743f72ad Merge branch '1.7.x' into fix-usage-queues 2025-06-08 06:24:41 +05:45
Matej BačoandGitHub 9866e6fa2f Merge pull request #9971 from appwrite/fix-deployment-download-2
Fix cache issues with proxy for deployment download
2025-06-06 14:32:53 +02:00
Matej Bačo 66f7d1a3c9 Fix cache issues with proxy for deployment download 2025-06-04 16:54:07 +02:00
Christy JacobandGitHub c0fd5f6233 Merge branch '1.7.x' into fix-usage-queues 2025-06-04 13:58:56 +04:00
Christy JacobandGitHub 3a1cd22be5 Merge pull request #9731 from appwrite/PLA-2683
chore(audits): return queue pre-fetch results
2025-06-04 13:44:36 +04:00
Khushboo Verma aee3280a9c Use static code instead of astro in tests 2025-06-04 13:50:36 +05:30
Matej Bačo f9be8dc966 Missed spot from previous commit 2025-06-03 13:20:56 +02:00
Matej Bačo 7522a3a56e Fix multiregion view logs 2025-06-03 13:20:24 +02:00
Fabian Gruber fc14144a0b chore(audits): return queue pre-fetch results 2025-06-03 11:40:12 +02:00
Christy JacobandGitHub b47ab90665 Merge pull request #9940 from appwrite/PLA-2950
fix(gif preview): enable resource limits
2025-06-03 12:56:36 +04:00
Christy JacobandGitHub 41cda120d1 Merge pull request #9903 from appwrite/storage-telemetry
Bring back telemetry for storage.
2025-06-03 12:37:55 +04:00
Fabian Gruber 584ca3065f fix(gif preview): enable resource limits 2025-06-03 10:35:26 +02:00
Christy JacobandGitHub 809d31bba2 Merge branch '1.7.x' into storage-telemetry 2025-06-03 12:06:12 +04:00
Christy JacobandGitHub 2b44b95073 Merge pull request #9890 from appwrite/PLA-2762
worker: Graceful shutdown on SIGTERM
2025-06-03 12:02:24 +04:00
Christy JacobandGitHub 419b134703 Merge pull request #9955 from appwrite/spr/1.7.x/7d7dffac
tests: increase deployment timeouts
2025-06-02 22:42:12 +04:00
Christy JacobandGitHub 9fb12fde35 Merge pull request #9956 from appwrite/spr/1.7.x/35fcc17d
tests: make usagetests robust
2025-06-02 22:41:31 +04:00
Christy JacobandGitHub d14eb3f12d Merge pull request #9957 from appwrite/spr/1.7.x/336a4f07
tests: fix flaky messaging test
2025-06-02 22:40:57 +04:00
loks0n 71c54f5742 tests: increase deployment timeouts
commit-id:7d7dffac
2025-06-02 19:05:23 +01:00
loks0n c19d123d48 tests: make usagetests robust
commit-id:35fcc17d
2025-06-02 19:05:23 +01:00
loks0n b9579c8922 tests: fix flaky messaging test
commit-id:336a4f07
2025-06-02 19:05:23 +01:00
Christy JacobandGitHub 7ed1d7bd37 Merge pull request #9954 from appwrite/spr/1.7.x/3865765d
tests: fix flaky account tests
2025-06-02 21:52:40 +04:00
loks0n 854304dd16 tests: fix flaky account tests
commit-id:3865765d
2025-06-02 17:09:13 +01:00
Matej Bačo c449144926 Fix flaky usage tests 2025-06-02 17:56:13 +02:00
Matej Bačo c92a14d318 Simplify router redirect 2025-06-02 12:47:13 +02:00
Matej BačoandGitHub 2514391007 Merge pull request #9949 from appwrite/fix-github-comments-and-deployment-on-branch-deletion
Fix github comments and deployment creation on branch deletion
2025-06-02 12:01:21 +02:00
Khushboo Verma 7049a58f21 Update composer.lock 2025-06-02 15:06:00 +05:30
Khushboo Verma 288f3b2cc8 Fix order 2025-06-02 14:12:25 +05:30
Khushboo Verma e7963e6825 Update composer.lock 2025-06-02 14:07:53 +05:30
Khushboo Verma 0ac6decc99 Fix github comments and deployment creation on branch deletion 2025-06-02 14:04:03 +05:30
Damodar Lohani df67dd5576 Fix: remove stats usage dump worker 2025-06-01 02:09:30 +00:00
Jake BarnbyandGitHub a799a2a40b Merge pull request #9941 from appwrite/chore-update-database
Update database for upsert fix
2025-05-30 15:12:41 +00:00
Jake Barnby 8716ef98ca Update database for upsert fix 2025-05-31 02:44:54 +12:00
Jake BarnbyandGitHub 7e4a3bb018 Merge pull request #9938 from appwrite/fix-deletion-logic
Fix deletion logic
2025-05-30 12:56:23 +00:00
Darshan 67cb3aad2f fix: test. 2025-05-30 18:05:03 +05:30
Darshan e1ee9ba89e fix: logic. 2025-05-30 18:04:57 +05:30
Fabian Gruber d98c06abf2 feat(worker): install stop hooks and close consumer 2025-05-30 13:53:29 +02:00
Fabian Gruber 8d5d9dc463 chore: use exec to replace /bin/sh shell with the actual program 2025-05-30 13:53:08 +02:00
Jake BarnbyandGitHub 2af8b3046f Merge pull request #9936 from appwrite/chore-update-queue
Update queue
2025-05-30 10:28:46 +00:00
Jake Barnby 1f5d2b0ec6 Update queue 2025-05-30 22:08:04 +12:00
Jake BarnbyandGitHub b189ba669e Merge pull request #9888 from appwrite/fix-teams-deletion
Fix teams deletion
2025-05-30 09:23:02 +00:00
Matej BačoandGitHub 217e765f7b Merge pull request #9927 from appwrite/chore-remove-powered-by-in-error-pages
Remove powered by from error pages
2025-05-30 11:13:36 +02:00
Darshan 36bc41a748 reset: stuff on target branch [missed]. 2025-05-30 14:34:21 +05:30
Darshan 4fc84bec7d reset: stuff on target branch. 2025-05-30 14:33:37 +05:30
Darshan f7f746a543 Merge branch '1.7.x' into 'fix-teams-deletion'. 2025-05-30 14:25:22 +05:30
Darshan 3063ac899c update: tests. 2025-05-30 14:21:11 +05:30
Khushboo Verma b309808592 Remove all 'powered by' divs 2025-05-30 14:18:35 +05:30
Darshan 65ae22d7cd update: messages because the check is only for console project > organizations. 2025-05-30 14:08:25 +05:30
Darshan 2ef2c59d18 update: exceptions and messages. 2025-05-30 14:03:51 +05:30
Khushboo Verma 34150f0c38 Remove div 2025-05-30 12:39:33 +05:30
Khushboo Verma 48f26d85ca Merge branch '1.7.x' into chore-remove-powered-by-in-error-pages 2025-05-30 11:27:29 +05:30
Khushboo Verma 502b7df2d0 Remove powered by from all error pages 2025-05-30 11:26:05 +05:30
Jake Barnby f6cd1d4220 Merge remote-tracking branch 'origin/fix-disable-tcp-hook' into 1.7.x 2025-05-30 01:51:18 +12:00
Jake Barnby 972c9dde21 Revert "Merge pull request #9932 from appwrite/fix-disable-tcp-hook"
This reverts commit 7a34c7b8df, reversing
changes made to 2b9b76f7bd.
2025-05-30 01:51:00 +12:00
Jake BarnbyandGitHub c770147755 Merge pull request #9924 from appwrite/remove-index-roles
Remove roles index
2025-05-29 13:02:31 +00:00
Khushboo Verma 0a80ffe4a7 Fix error 2025-05-29 18:29:15 +05:30
Khushboo Verma 7db4932084 Merge branch '1.7.x' into chore-remove-powered-by-in-error-pages 2025-05-29 18:28:56 +05:30
Jake BarnbyandGitHub 7a34c7b8df Merge pull request #9932 from appwrite/fix-disable-tcp-hook
Disable TCP hook on stats resources
2025-05-29 12:54:51 +00:00
fogelito 9829ba2afb Not sure we need it but ok 2025-05-29 15:40:11 +03:00
fogelito 0097a0edcd Update migration self-hosted 2025-05-29 15:37:08 +03:00
Jake Barnby c6b1209b8f Disable TCP hook on stats resources 2025-05-30 00:32:55 +12:00
fogelito d7653c68ce formatting 2025-05-29 14:51:18 +03:00
Jake BarnbyandGitHub 2b9b76f7bd Merge pull request #9928 from appwrite/chore-update-database
Update database
2025-05-29 11:49:26 +00:00
Jake Barnby 823d8604bd Update database 2025-05-29 22:39:12 +12:00
Khushboo Verma c4510004ce update test 2025-05-29 14:46:25 +05:30
Khushboo Verma 7d284a9872 Remove powered by from error pages 2025-05-29 14:34:21 +05:30
Jake Barnby 9dc179b022 Merge remote-tracking branch 'origin/1.7.x' into 1.8.x
# Conflicts:
#	composer.json
#	composer.lock
2025-05-29 20:01:50 +12:00
Damodar LohaniandGitHub 8b53f1b5f5 Merge pull request #9764 from appwrite/fix-update-messaging-library
Fix: update messaging library
2025-05-29 11:34:23 +05:45
Damodar Lohani 601b6760a5 fix version pinning 2025-05-29 05:33:26 +00:00
Damodar Lohani c9c2b575ba Merge remote-tracking branch 'origin/1.7.x' into fix-update-messaging-library 2025-05-29 02:58:48 +00:00
fogelito 0d46d4d6e9 Remove roles index 2025-05-28 15:54:58 +03:00
Jake Barnby ebb05cba92 Merge remote-tracking branch 'origin/1.7.x' into 1.8.x
# Conflicts:
#	src/Appwrite/Platform/Modules/Compute/Base.php
#	src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php
#	src/Appwrite/Platform/Modules/Functions/Workers/Builds.php
#	src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php
2025-05-28 21:20:35 +12:00
Jake BarnbyandGitHub 61f0e5b3f3 Merge pull request #9920 from appwrite/feat-sync-1.6
Feat sync 1.6
2025-05-28 09:12:45 +00:00
Jake Barnby 9cd521390f Merge remote-tracking branch 'origin/1.6.x' into feat-sync-1.6
# Conflicts:
#	composer.lock
#	src/Appwrite/Platform/Workers/Builds.php
2025-05-28 21:00:38 +12:00
Matej BačoandGitHub af6499bd47 Merge pull request #9919 from appwrite/feat-update-branch-url
Shorten commit url and branch url
2025-05-28 10:57:51 +02:00
Khushboo Verma 814abddf93 Truncate commit hash to 16 chars 2025-05-28 14:10:12 +05:30
707ef16f79 Update src/Appwrite/Platform/Modules/Functions/Workers/Builds.php
Co-authored-by: Matej Bačo <matejbacocom@gmail.com>
2025-05-28 14:02:03 +05:30
aa07ba0027 Update app/controllers/api/vcs.php
Co-authored-by: Matej Bačo <matejbacocom@gmail.com>
2025-05-28 14:01:55 +05:30
Khushboo Verma 66ac440f9d Add missing separator 2025-05-28 12:55:50 +05:30
Khushboo Verma 320bf69208 Shorten commit url 2025-05-28 12:50:47 +05:30
Darshan 7e6f4befa5 reset: stuff from main. 2025-05-27 19:21:28 +05:30
Darshan 2de9b85d6b Merge branch 'main' into 'fix-teams-deletion'. 2025-05-27 19:16:40 +05:30
Jake Barnby b7702340ba Fix allowed attributes list for user target list queries 2025-05-28 01:13:29 +12:00
Matej BačoandGitHub 340211e3a8 Merge pull request #9915 from appwrite/1.7.x-logging
Fix: Rule querying improt
2025-05-27 11:58:53 +02:00
Matej Bačo 501d29f696 Implement a fix 2025-05-27 11:54:34 +02:00
Matej Bačo 675179def8 Improve logs 2025-05-27 11:41:46 +02:00
Matej Bačo cedc4eb2df Add logging 2025-05-27 11:06:08 +02:00
Matej Bačo 64cea46183 Permissiosn fix for sites 2025-05-27 10:47:28 +02:00
Matej Bačo 852c6fc3fe Fix rules non-updated 2025-05-27 10:35:08 +02:00
Damodar Lohani 8a09a4b415 fix linter 2025-05-27 08:21:31 +00:00
Matej BačoandGitHub 11725869e2 Merge pull request #9914 from appwrite/feat-new-flutter-dart-runtimes
Feat: add flutter 3.32 and dart 3.8
2025-05-27 09:57:23 +02:00
Damodar Lohani 968b6302d0 Feat: add flutter 3.32 and dart 3.8 2025-05-27 07:36:28 +00:00
Damodar LohaniandGitHub 9c62b45cd4 Merge branch '1.6.x' into fix-update-messaging-library 2025-05-27 11:08:34 +05:45
Jake Barnby 8e8402fbd8 Coderabbit 2025-05-27 16:54:58 +12:00
Jake BarnbyandGitHub 4ffa89fe35 Merge pull request #9870 from appwrite/feat-expose-sequence
Feat expose sequence
2025-05-27 02:40:47 +00:00
Jake Barnby 59c1f55183 Merge remote-tracking branch 'origin/1.8.x' into feat-expose-sequence 2025-05-27 13:58:04 +12:00
Jake Barnby dd25072cdf Merge pull request #9868 from ArnabChatterjee20k/dat-532
added encrypt property in the attribute string response model
# Conflicts:
#	tests/e2e/Services/Databases/DatabasesCustomServerTest.php
2025-05-27 13:57:51 +12:00
Jake BarnbyandGitHub 8df77a2295 Merge pull request #9900 from appwrite/chore-cli-release
Release cli
2025-05-27 01:40:29 +00:00
Jake Barnby 6159e9caa7 Merge remote-tracking branch 'origin/1.8.x' into feat-expose-sequence 2025-05-27 13:40:01 +12:00
Jake Barnby 2d29317179 Update lock 2025-05-27 13:38:26 +12:00
Jake Barnby 3158c15111 Merge remote-tracking branch 'origin/1.7.x' into 1.8.x
# Conflicts:
#	app/controllers/api/functions.php
#	app/controllers/api/project.php
#	app/controllers/api/proxy.php
#	app/controllers/api/storage.php
#	app/controllers/api/vcs.php
#	app/controllers/general.php
#	app/controllers/shared/api.php
#	app/init/database/filters.php
#	composer.json
#	composer.lock
#	src/Appwrite/Migration/Migration.php
#	src/Appwrite/Migration/Version/V15.php
#	src/Appwrite/Migration/Version/V16.php
#	src/Appwrite/Migration/Version/V17.php
#	src/Appwrite/Migration/Version/V18.php
#	src/Appwrite/Migration/Version/V19.php
#	src/Appwrite/Migration/Version/V20.php
#	src/Appwrite/Migration/Version/V21.php
#	src/Appwrite/Platform/Tasks/Migrate.php
#	src/Appwrite/Platform/Workers/Builds.php
#	src/Appwrite/Platform/Workers/Deletes.php
#	src/Appwrite/Platform/Workers/Functions.php
#	src/Appwrite/Platform/Workers/StatsResources.php
#	src/Appwrite/Platform/Workers/StatsUsage.php
2025-05-27 13:36:23 +12:00
Jake BarnbyandGitHub 021fb48dc1 Merge branch '1.7.x' into chore-cli-release 2025-05-27 01:25:31 +00:00
Jake Barnby 35585fe864 Update lock 2025-05-27 13:06:40 +12:00
Matej Bačo deffe25c30 Fix queries not updating well 2025-05-26 17:54:06 +02:00
Fabian Gruber 4fafb47508 Bring back telemetry for storage.
This reverts commit 6906a97c22.
2025-05-26 17:43:29 +02:00
Matej BačoandGitHub 08370c10ee Merge pull request #9902 from appwrite/fix-rule-deployment-update
Fix: how we update rules on active deployment
2025-05-26 17:01:24 +02:00
Matej Bačo 51f6751b94 Revert 2025-05-26 16:39:23 +02:00
Matej Bačo f6dd9b0d33 Fix how we update rules on active deployment 2025-05-26 16:24:27 +02:00
Steven NguyenandGitHub a68d49a405 Merge pull request #9849 from appwrite/update-sdks-devkeys
chore: update sdk generator and sdks
2025-05-26 07:15:23 -07:00
Jake BarnbyandGitHub d9a02fc0fa Merge branch '1.7.x' into chore-cli-release 2025-05-26 13:53:45 +00:00
Matej Bačo 44e16ce98d Fix commit URLs max length 2025-05-26 12:56:23 +02:00
Jake Barnby 2a5ecb2547 Release cli 2025-05-26 22:25:12 +12:00
Jake BarnbyandGitHub 3f9b4e92e9 Merge pull request #9898 from appwrite/chore-revert
Revert
2025-05-26 10:05:44 +00:00
Jake Barnby c7c9e057ab Update generator 2025-05-26 22:00:39 +12:00
Jake Barnby ab97b7cc54 Merge pull request #9877 from appwrite/revert-9871-feat-sync
Revert "Feat sync encrypt updates"
2025-05-26 21:37:41 +12:00
Jake Barnby b7d0c127a3 Revert "Merge pull request #9878 from ArnabChatterjee20k/dat-532"
This reverts commit a366feba80, reversing
changes made to 484988fcd7.
2025-05-26 21:37:21 +12:00
Darshan 3adbe8a8f5 revert: minor change. 2025-05-26 11:41:58 +05:30
Jake Barnby 554d8365a6 Format 2025-05-26 18:10:08 +12:00
Darshan 64baf1071d fix: wrong variable passed to cache purge. 2025-05-26 11:38:22 +05:30
Darshan 96bef81ebc fix: tests! 2025-05-26 11:33:58 +05:30
Jake Barnby d5999fde53 Ignore plan blocked test for cl 2025-05-26 18:03:03 +12:00
Darshan 856a9a714b fix: memberships patch and delete logic. 2025-05-26 11:29:46 +05:30
Jake Barnby f09bda97f8 Update lock 2025-05-26 17:45:12 +12:00
Jake Barnby 86f7489640 Internal ID -> sequence 2025-05-26 17:42:11 +12:00
Jake Barnby c51cf2f3e4 Merge pull request #9878 from ArnabChatterjee20k/dat-532
updated errro for the string encryption
2025-05-26 17:37:57 +12:00
Jake Barnby a616aa0e93 Revert "Merge pull request #9877 from appwrite/revert-9871-feat-sync"
This reverts commit 1a0e82b4e4, reversing
changes made to 8bc5117259.
2025-05-26 17:36:55 +12:00
Chirag Aggarwal 9bb52cda93 chore: update flutter sdk and changelog 2025-05-26 04:32:10 +00:00
Chirag AggarwalandGitHub 760f26e044 Merge branch 'main' into update-sdks-devkeys 2025-05-26 09:30:09 +05:30
Steven NguyenandGitHub 568f6fd274 Merge pull request #9891 from appwrite/chore-update-console-6-0-13
Update console image to version 6.0.13
2025-05-25 11:15:06 -07:00
Torsten DittmannandGitHub 43d84c680e Merge pull request #9893 from appwrite/chore-upgrade-to-1-7-4
Update version from 1.7.3 to 1.7.4
2025-05-25 19:45:23 +02:00
Torsten Dittmann 7531c64b31 Update version from 1.7.3 to 1.7.4 2025-05-25 19:44:51 +02:00
Torsten Dittmann ddf5b8e156 Update console image to version 6.0.13 2025-05-25 19:39:06 +02:00
Darshan 3f839e3807 update: tests to account for console and custom client projects. 2025-05-25 12:27:29 +05:30
Darshan 24e0b3e8cb fix: missing project check. 2025-05-25 12:19:52 +05:30
Matej BačoandGitHub 3bb5e9085e Merge pull request #9886 from appwrite/fix-console-sdk-file-upload
Chore: Upgrade to fix createDeployment chunk upload
2025-05-25 01:06:41 +02:00
Matej Bačo d3533840c8 Chore: Use release, not branch 2025-05-25 00:50:51 +02:00
Matej Bačo aa9f554853 Fix chunk uploaded manual deployment 2025-05-25 00:05:30 +02:00
Matej Bačo eb8da87eed Fix bug; trigger sdk generation 2025-05-24 23:47:27 +02:00
Matej Bačo 17eab0ecb5 Upgrade to fix createDeployment chunk upload 2025-05-24 23:42:19 +02:00
Steven NguyenandGitHub 4c5094d3dc Merge pull request #9883 from appwrite/fix-migration-default-region
fix(migration): _APP_DEFAULT_REGION is not a valid env var
2025-05-23 20:09:09 -07:00
Steven Nguyen 295e2773f3 fix(migration): _APP_DEFAULT_REGION is not a valid env var
Across the rest of the codebase, we use _APP_REGION with 'default' as
the fallback value. This commit updates the migration to do the same.
2025-05-23 17:46:07 -07:00
Steven NguyenandGitHub 341bcb5222 Merge pull request #9882 from appwrite/feat-1.7.3-release-prep
Prepare 1.7.3 release
2025-05-23 17:45:42 -07:00
Steven Nguyen b932db34f3 Bump appwrite version to 1.7.3 2025-05-23 16:01:00 -07:00
Steven NguyenandGitHub 7208729805 Merge pull request #9881 from appwrite/chore-bump-console-6.0.11
Bump console to version 6.0.11
2025-05-23 16:00:38 -07:00
Steven NguyenandGitHub f9a74868ff Merge pull request #9856 from appwrite/fix-migration-rule-owner
fix(migration): set owner and region while migrating rules
2025-05-23 15:24:33 -07:00
Steven Nguyen 0ec7dcf08d Bump console to version 6.0.11 2025-05-23 15:07:45 -07:00
Steven Nguyen 8ce46c791f fix(migration): set owner and region while migrating rules
These attributes were added to the rules collection in 1.6.2, but the
migration script was not updated to set them. Because they're empty, the
1.7 migration fails while updating rules documents because region is
required.
2025-05-23 15:06:19 -07:00
Eldad A. FuxandGitHub d8904af909 Merge pull request #9879 from appwrite/revert-9865-feat-sequence
Revert "Feat sequence"
2025-05-23 21:41:15 +01:00
Christy JacobandGitHub 28d2ed1baa Revert "Feat sequence" 2025-05-23 21:39:56 +04:00
Jake BarnbyandGitHub a366feba80 Merge pull request #9878 from ArnabChatterjee20k/dat-532
updated errro for the string encryption
2025-05-23 15:27:35 +00:00
Christy JacobandGitHub 484988fcd7 Merge pull request #9875 from appwrite/fix-add-region-to-github-related-urls
Fix URL for view logs in github comment
2025-05-23 19:19:33 +04:00
ArnabChatterjee20k 49f8369fdd updated the message 2025-05-23 20:45:36 +05:30
ArnabChatterjee20k 6af9d1206d added a constant 2025-05-23 20:41:08 +05:30
Jake BarnbyandGitHub 1a0e82b4e4 Merge pull request #9877 from appwrite/revert-9871-feat-sync
Revert "Feat sync encrypt updates"
2025-05-23 15:07:17 +00:00
ArnabChatterjee20k 14fe7a3293 updated errro for the string encryption 2025-05-23 20:35:59 +05:30
Jake BarnbyandGitHub 70feb72de0 Revert "Feat sync encrypt updates" 2025-05-24 03:04:46 +12:00
Khushboo Verma 1434e69b94 Merge branch 'main' into fix-add-region-to-github-related-urls 2025-05-23 20:12:53 +05:30
Khushboo Verma 65a220b702 Fix URL for view logs in github comment 2025-05-23 20:11:27 +05:30
Christy JacobandGitHub 8bc5117259 Merge pull request #9872 from appwrite/feat-add-builds-worker-group
feat: add builds worker group
2025-05-23 17:51:56 +04:00
Christy JacobandGitHub ec77137768 Merge pull request #9873 from appwrite/feat-add-builds-worker-group-main
feat: add builds worker group
2025-05-23 17:51:55 +04:00
Luke B. SilverandGitHub 281c52d58c Merge branch '1.6.x' into feat-add-builds-worker-group 2025-05-23 14:38:13 +01:00
loks0n 18335ebf89 feat: add builds worker group 2025-05-23 14:29:31 +01:00
loks0n 098f891f7c feat: add builds worker group 2025-05-23 14:25:23 +01:00
Jake BarnbyandGitHub 0b0a1c20e9 Merge pull request #9871 from appwrite/feat-sync
Feat sync encrypt updates
2025-05-23 12:01:23 +00:00
Jake Barnby d27dba05d2 Merge pull request #9841 from ArnabChatterjee20k/dat-532
added checking for encrypt and plan allowing encryption of string att…
2025-05-23 23:54:18 +12:00
Jake Barnby 1a2a725cb0 Merge pull request #9868 from ArnabChatterjee20k/dat-532
added encrypt property in the attribute string response model
2025-05-23 23:53:23 +12:00
Jake Barnby a8fb467df7 Update test 2025-05-23 22:53:08 +12:00
Jake Barnby bc778f507d Update to sequence 2025-05-23 22:51:20 +12:00
Jake BarnbyandGitHub 2c7666e0df Merge pull request #9713 from ArnabChatterjee20k/feat/auto-increment
exposed internal id as a part of auto increment id
2025-05-23 10:46:19 +00:00
Jake BarnbyandGitHub 7861cb7c49 Merge branch 'feat-expose-sequence' into feat/auto-increment 2025-05-23 10:45:47 +00:00
Jake BarnbyandGitHub 39d45bdca9 Merge pull request #9865 from appwrite/feat-sequence
Feat sequence
2025-05-23 10:14:15 +00:00
DarshanandGitHub a413a613f5 Merge branch 'main' into feat-sequence 2025-05-23 15:35:39 +05:30
Jake BarnbyandGitHub 5eab81cf03 Merge pull request #9868 from ArnabChatterjee20k/dat-532
added encrypt property in the attribute string response model
2025-05-23 09:03:42 +00:00
ArnabChatterjee20k b8cb6f281d linting 2025-05-23 14:19:00 +05:30
ArnabChatterjee20k 7c760e4b07 linting 2025-05-23 14:16:35 +05:30
ArnabChatterjee20k e586afceb7 updates 2025-05-23 14:11:57 +05:30
ArnabChatterjee20k 6ea3593921 updated collection filter 2025-05-23 13:40:56 +05:30
ArnabChatterjee20k 73764941b6 updated tests and collection method 2025-05-23 13:23:33 +05:30
Jake Barnby 14274d96aa Update libs 2025-05-23 19:42:43 +12:00
Jake Barnby 587b84d04a Merge remote-tracking branch 'origin/1.7.x' into feat-sequence 2025-05-23 19:40:57 +12:00
Jake Barnby fec814e0ec Merge remote-tracking branch 'origin/main' into feat-sequence 2025-05-23 19:40:48 +12:00
ArnabChatterjee20k 02426df1ca linting 2025-05-23 12:53:10 +05:30
ArnabChatterjee20k 1d0577b07d added encrypt to the get and list atttributes 2025-05-23 12:51:59 +05:30
ArnabChatterjee20k 1a4a10400b added test for the encrypted string in the server 2025-05-23 12:12:23 +05:30
ArnabChatterjee20k 0cccb75273 added encrypt property in the attribute string response model 2025-05-23 12:05:42 +05:30
Steven NguyenandGitHub 6526e8d956 Merge pull request #9842 from appwrite/pla-2914
chore: use unique filename for health check
2025-05-22 17:30:32 -07:00
Steven NguyenandGitHub 1e220766b2 Merge pull request #9858 from appwrite/update-flutter-docs
chore: update flutter_web_auth_2 docs to match 4.x
2025-05-22 15:14:25 -07:00
ArnabChatterjee20k 70f7f71a95 Merge branch 'main' into feat/auto-increment 2025-05-22 23:56:40 +05:30
Matej BačoandGitHub 57ee69ad9a Merge pull request #9866 from appwrite/fix-unlimited-deployment-size
Fix: unlimited deployment size
2025-05-22 17:34:54 +02:00
Jake Barnby 04a9b0be34 Fix replace 2025-05-23 03:29:44 +12:00
Matej Bačo b4f5af8461 Fix: unlimited deployment size 2025-05-22 17:25:47 +02:00
Jake Barnby f6bf779119 Update database 2025-05-23 02:57:11 +12:00
Jake Barnby 71e3446498 Change internal ID to sequence 2025-05-23 02:55:29 +12:00
Matej BačoandGitHub 4adea70684 Merge pull request #9863 from appwrite/feat-add-configurable-resource-size
Add configurable deployment and build size
2025-05-22 15:28:40 +02:00
Matej BačoandGitHub 9321f585f5 Update app/worker.php 2025-05-22 15:22:40 +02:00
Jake BarnbyandGitHub 91d729cc55 Merge pull request #9864 from appwrite/fix-generic-s3
Fix bucket not included in path
2025-05-22 13:09:53 +00:00
Jake Barnby bd01d12db5 Format 2025-05-23 00:51:31 +12:00
Jake Barnby d2d9032ede Fix bucket not included in path 2025-05-23 00:49:26 +12:00
Khushboo Verma b727b8c100 Add configurable deployment and build size 2025-05-22 18:01:34 +05:30
Chirag AggarwalandGitHub 080cc4a93f Merge branch 'main' into update-sdks-devkeys 2025-05-22 16:05:20 +05:30
Christy JacobandGitHub 9df0045024 Merge pull request #9861 from appwrite/fix-cname-validation
Fix: CNAME validation
2025-05-22 14:15:27 +04:00
Christy JacobandGitHub 3c74818591 Merge pull request #9859 from appwrite/sites-certificates
fix: send deploymentResourceType in rules verification
2025-05-22 13:30:18 +04:00
Matej BačoandGitHub a734ae163a Merge pull request #9860 from appwrite/fix-error-page-for-development
Only load error page for development mode
2025-05-22 10:31:46 +02:00
Matej Bačo 67a5192705 Fix CNAME validation 2025-05-22 10:13:12 +02:00
Fabian Gruber 128dc1d946 fix: send deploymentResourceType in rules verification 2025-05-22 10:05:45 +02:00
Khushboo Verma d283c820da Only load error page for development mode 2025-05-22 13:34:25 +05:30
Chirag Aggarwal 86526fa1df chore: update changelog 2025-05-22 06:11:28 +00:00
Chirag Aggarwal c5f7a72409 chore: update flutter_web_auth_2 docs to match 4.x 2025-05-22 06:03:35 +00:00
Damodar LohaniandGitHub e81e9d5d67 Merge branch '1.6.x' into fix-update-messaging-library 2025-05-22 09:57:19 +05:45
Matej BačoandGitHub 6b7071ca94 Merge pull request #9852 from appwrite/fix-double-logs
Fix: double logs on failure
2025-05-21 16:59:24 +02:00
Chirag Aggarwal c00d032c5a chore: update platforms 2025-05-21 14:45:09 +00:00
Matej Bačo 83e62dc6e1 Fix double logs on failure 2025-05-21 16:44:04 +02:00
Christy JacobandGitHub 02de47f1dc Merge pull request #9850 from appwrite/task-coroutine-hooks-1.6
fix: task coroutine hooks
2025-05-21 18:31:57 +04:00
Fabian Gruber 241a0c88e1 fix: task coroutine hooks 2025-05-21 16:21:11 +02:00
Chirag Aggarwal 2803693402 chore: sync with main 2025-05-21 13:43:10 +00:00
Jake BarnbyandGitHub 341775de2e Merge pull request #9848 from appwrite/cors-allow-dev-key
fix: allow devkeys header to pass CORS
2025-05-21 11:42:21 +00:00
Chirag Aggarwal eda1bf3207 chore: update test 2025-05-21 11:05:25 +00:00
Luke B. SilverandGitHub 30915b4803 Merge branch 'main' into cors-allow-dev-key 2025-05-21 11:53:09 +01:00
Chirag Aggarwal d9bd867b38 fix: allow devkeys header to pass CORS 2025-05-21 10:32:56 +00:00
Jake BarnbyandGitHub 86b64fdee8 Merge pull request #9845 from appwrite/feat-sync-1.6.x
Sync 1.6.x
2025-05-21 09:59:56 +00:00
Jake BarnbyandGitHub 8fec677579 Merge pull request #9846 from appwrite/feat-sync-1.7.x
Sync 1.7.x
2025-05-21 09:59:45 +00:00
Christy JacobandGitHub 27fae92b89 Merge pull request #9847 from appwrite/PLA-2928
fix(storage): do not allow full range
2025-05-21 13:16:24 +04:00
Fabian Gruber ba3f907028 fix(storage): do not allow full range
This prevents requests with `Range: 0-<file length>` and limits it to APP_STORAGE_READ_BUFFER
2025-05-21 10:57:58 +02:00
Jake BarnbyandGitHub eab446a828 Merge pull request #9841 from ArnabChatterjee20k/dat-532
added checking for encrypt and plan allowing encryption of string att…
2025-05-21 08:51:31 +00:00
Christy JacobandGitHub d25800973c Merge pull request #9826 from appwrite/feat-1.7.2-release-prep
Prepare 1.7.2 release
2025-05-21 12:40:36 +04:00
Jake Barnby 0024926e11 Merge remote-tracking branch 'origin/1.7.x' into feat-sync-1.7.x 2025-05-21 20:15:41 +12:00
Matej BačoandGitHub 8734aeb314 Merge pull request #9844 from appwrite/1.7.x
Append build error to build logs
2025-05-21 10:15:20 +02:00
Jake Barnby 3ec0f08db1 Merge remote-tracking branch 'origin/1.6.x' into feat-sync-1.6.x
# Conflicts:
#	composer.lock
#	src/Appwrite/Messaging/Adapter/Realtime.php
#	src/Appwrite/Platform/Workers/Deletes.php
2025-05-21 20:15:08 +12:00
ArnabChatterjee20k c4df1c8c4b updated exception type 2025-05-21 13:34:08 +05:30
Matej BačoandGitHub 61b20160f4 Merge pull request #9836 from appwrite/fix-show-build-logs-on-failure
Append build error to build logs
2025-05-21 10:02:57 +02:00
Jake BarnbyandGitHub b8a744d088 Merge pull request #9837 from appwrite/feat-dev-key-to-clients
feat: add dev key to clients
2025-05-21 08:00:22 +00:00
ArnabChatterjee20k 82fd8553bf updated the condition 2025-05-21 13:29:24 +05:30
ArnabChatterjee20k 8796670c66 reverted test 2025-05-21 13:19:07 +05:30
Jake BarnbyandGitHub c96232f764 Merge pull request #9843 from appwrite/feat-sync-upsert
Merge pull request #9811 from ArnabChatterjee20k/upsert-single-docume…
2025-05-21 07:44:39 +00:00
ArnabChatterjee20k 9fa6deae61 reverted the tests and updated the plan checking condition 2025-05-21 13:14:22 +05:30
Jake Barnby 20f2cbffda Merge pull request #9811 from ArnabChatterjee20k/upsert-single-document-route
Upsert single document route
2025-05-21 19:29:31 +12:00
Chirag Aggarwal fe5419401a chore: use unique filename for health check 2025-05-21 07:28:25 +00:00
Chirag Aggarwal cca95d5bd2 chore: update to minor versions 2025-05-21 06:36:09 +00:00
ArnabChatterjee20k 43aae24132 updated tests for the custom server test 2025-05-21 11:38:34 +05:30
ArnabChatterjee20k f534b9e460 added checking for encrypt and plan allowing encryption of string attribute 2025-05-21 11:00:01 +05:30
Chirag Aggarwal d302718757 chore: update sdks 2025-05-21 05:19:31 +00:00
Steven NguyenandGitHub e5ad27c33a Merge pull request #9840 from appwrite/1.7.x
Merge 1.7.x into main
2025-05-20 20:49:20 -07:00
Chirag AggarwalandGitHub 58c3232578 Merge branch 'main' into feat-dev-key-to-clients 2025-05-21 09:17:17 +05:30
Steven Nguyen ac8105dea2 Bump appwrite version to 1.7.2 2025-05-20 17:29:32 -07:00
Jake BarnbyandGitHub cbba893f53 Merge pull request #9829 from appwrite/fix-empty-function-migration
Fix migrating functions with no deployments
2025-05-21 00:24:34 +00:00
loks0n dde0dd2218 feat: add dev key to clients 2025-05-20 23:05:48 +01:00
Khushboo Verma 3335f56cf6 Append build error to build logs 2025-05-20 21:15:05 +05:30
Jake BarnbyandGitHub 815849aa64 Merge pull request #9811 from ArnabChatterjee20k/upsert-single-document-route
Upsert single document route
2025-05-20 14:37:10 +00:00
Jake BarnbyandGitHub 727bac5f3d Merge pull request #9834 from appwrite/fix-missing-catch
Catch query exception on get document for selects
2025-05-20 14:32:20 +00:00
Jake BarnbyandGitHub 9f14f1152a Update app/controllers/api/databases.php 2025-05-21 02:22:51 +12:00
Jake Barnby bc34f95646 Update lock 2025-05-21 01:13:08 +12:00
Matej BačoandGitHub dbc66d2221 Merge pull request #9835 from appwrite/feat-lynx-gallery
Feat: Add lynx gallery
2025-05-20 15:10:59 +02:00
Matej Bačo e8661e6d31 Fix starter template for flutter 2025-05-20 15:10:37 +02:00
Matej Bačo 2ad4390958 Add lynx gallery 2025-05-20 15:03:45 +02:00
Jake Barnby fe763093df Catch query exception on get document for selects 2025-05-21 00:58:32 +12:00
ArnabChatterjee20k c5a08b69b0 changed custom id to uid 2025-05-20 18:14:51 +05:30
Matej BačoandGitHub 00e3397b56 Merge pull request #9833 from appwrite/chore-upgrade-console
Chore: Upgrade console
2025-05-20 14:17:18 +02:00
Matej Bačo 69adb689f8 Upgrade console 2025-05-20 14:16:04 +02:00
Matej BačoandGitHub 0379086c48 Merge pull request #9820 from appwrite/update-desc
Update: token desc
2025-05-20 13:35:25 +02:00
Jake BarnbyandGitHub bc5343b559 Apply suggestions from code review 2025-05-20 23:27:31 +12:00
Jake BarnbyandGitHub eb05e8c35c Merge branch 'main' into upsert-single-document-route 2025-05-20 11:12:14 +00:00
Christy JacobandGitHub 5e10670d22 Merge pull request #9831 from appwrite/fix-download-endpoint
fix: download endpoint
2025-05-20 14:21:55 +04:00
loks0n 455554a6a2 fix: download endpoint 2025-05-20 11:14:16 +01:00
Matej Bačo cb97679553 Specs, SDKs and Docs fixes (deprecated params) 2025-05-20 11:50:36 +02:00
ArnabChatterjee20k 80e842444b updated test for upsertion 2025-05-20 14:28:16 +05:30
Matej BačoandGitHub 6400e94d8b Merge pull request #9830 from appwrite/fix-flutter-starter
Fix: flutter starter
2025-05-20 10:49:11 +02:00
Matej Bačo d710b48ef5 Fix: flutter starter 2025-05-20 10:40:21 +02:00
Jake BarnbyandGitHub 2f6a82f4d5 Merge pull request #9757 from appwrite/feat-pool-adapter
Feat pool adapter
2025-05-20 08:25:34 +00:00
Matej BačoandGitHub 1a7982f855 Merge pull request #9828 from appwrite/sites-certificates
certificates: add domainType to certificate worker
2025-05-20 10:16:14 +02:00
Jake Barnby 149dfb9651 Update lock 2025-05-20 20:07:11 +12:00
Fabian Gruber 14873824ce certificates: add domainType to certificate worker 2025-05-20 09:56:46 +02:00
Jake Barnby 2a99bd4bda Fix migrating functions with no deployments 2025-05-20 19:26:26 +12:00
Jake BarnbyandGitHub 534096cac6 Merge branch '1.6.x' into feat-pool-adapter 2025-05-20 07:07:58 +00:00
ArnabChatterjee20kandGitHub 9f50f0c04a Merge branch 'main' into upsert-single-document-route 2025-05-20 12:14:42 +05:30
ArnabChatterjee20k b5d31d1b76 updated the upsert test for the relationship 2025-05-20 12:11:41 +05:30
ArnabChatterjee20k 53e790d886 changed uid to custom id to allow unique values as well 2025-05-20 10:54:09 +05:30
Steven NguyenandGitHub e9d0462548 Merge pull request #9825 from appwrite/fix-app-domain-sites-env-var
fix: add _APP_DOMAIN_SITES variables.php so the env is initialized
2025-05-19 17:05:02 -07:00
Steven Nguyen d2b0048a7f fix: add _APP_DOMAIN_SITES variables.php so the env is initialized
Without this, API calls to Appwrite can result in rule_not_found errors.
2025-05-19 16:04:04 -07:00
Aditya Oberai 4aeca149b0 update specs 2025-05-19 18:44:07 +00:00
12bb74a58d Update src/Appwrite/Platform/Modules/Tokens/Http/Tokens/Buckets/Files/Create.php
Co-authored-by: Matej Bačo <matejbacocom@gmail.com>
2025-05-20 00:11:03 +05:30
Aditya Oberai b2451c37c3 update 1.7.x and latest specs 2025-05-19 14:50:57 +00:00
Darshan 14fe7a7217 update: token desc. 2025-05-19 19:54:34 +05:30
Christy JacobandGitHub f59377e1bb Merge pull request #9815 from appwrite/task-coroutine-hooks-1.6
fix: task coroutine hooks
2025-05-19 16:59:19 +04:00
Christy JacobandGitHub 24312e69f4 Merge pull request #9814 from appwrite/task-coroutine-hooks
fix: task coroutine hooks
2025-05-19 16:59:16 +04:00
Fabian Gruber 1177178885 fix: task coroutine hooks 2025-05-19 14:03:58 +02:00
Fabian Gruber 3274a38c9b fix: task coroutine hooks 2025-05-19 14:02:47 +02:00
Matej BačoandGitHub eb3b09cf0d Merge pull request #9816 from appwrite/chore-upgrade-libs
Chore: upgrade detection, executor and console
2025-05-19 13:16:24 +02:00
Matej Bačo e203ae7327 upgrade detection, executor and console 2025-05-19 13:02:04 +02:00
ArnabChatterjee20k 559b6024bc linting 2025-05-19 16:00:38 +05:30
ArnabChatterjee20k 256aa684a2 updated tests 2025-05-19 15:59:38 +05:30
Matej BačoandGitHub 0ec7ff2cee Merge pull request #9812 from appwrite/fix-remove-search
Remove: `search` to maintain document structure
2025-05-19 11:59:04 +02:00
Darshan fc279cb30c remove: search from deployments. 2025-05-19 15:12:50 +05:30
Darshan abd2cead73 remove: search. 2025-05-19 15:03:59 +05:30
ArnabChatterjee20k 1de778443f resolved comments for the api 2025-05-19 14:30:29 +05:30
ArnabChatterjee20k 08478b8d39 removed document existence check for the document id
updated labels
added tests for upserts
2025-05-19 13:56:11 +05:30
ArnabChatterjee20k 330c298c58 add upsert route for a single document 2025-05-19 12:10:42 +05:30
Eldad A. FuxandGitHub e7c9b3d900 Merge pull request #9810 from appwrite/fix-chunk-reading-realtime
Fix logic of chunk reading
2025-05-19 03:39:16 +01:00
Matej Bačo 6090ca50fc Fix logic of chunk reading 2025-05-19 04:35:44 +02:00
Christy JacobandGitHub 3ba0565e44 Merge pull request #9808 from appwrite/chore-update-domains
chore: update domains
2025-05-19 03:45:43 +02:00
Eldad A. FuxandGitHub 6dbb14bf7b Merge pull request #9809 from appwrite/1.7.x
1.7.x
2025-05-19 02:42:37 +01:00
Christy Jacob b8b0db7a2f chore: update domains 2025-05-19 05:34:38 +04:00
Eldad A. FuxandGitHub 728b758db5 Merge pull request #9806 from appwrite/feat-x-edge-bypass-gateway
feat: bypass gateway
2025-05-18 23:36:37 +01:00
loks0n 33dc7ea97c feat: bypass gateway 2025-05-18 23:23:06 +01:00
Matej BačoandGitHub da811de615 Merge pull request #9805 from appwrite/fix-site-env-vars
Fix: site env vars at runtime
2025-05-19 00:13:36 +02:00
Matej Bačo c1315019cb Litner fix 2025-05-18 23:53:56 +02:00
Matej Bačo 1eb642aff0 Fix site env vars at runtime 2025-05-18 23:53:43 +02:00
Matej BačoandGitHub 908d80e8d9 Merge pull request #9804 from appwrite/fix-function-create-compatibility
Fix: backwards compatibility for function creation
2025-05-18 23:15:59 +02:00
Matej Bačo 02b7e0df4d queries backwards compatibilit 2025-05-18 22:51:17 +02:00
Matej Bačo e84ad1e83c Upgrade libs 2025-05-18 22:37:30 +02:00
Matej Bačo 0e90f64ea6 Fix backwards compatibility for function reation 2025-05-18 22:07:52 +02:00
Matej BačoandGitHub 08e93997b5 Merge pull request #9802 from appwrite/1.7.x
Fix: domain validaiton
2025-05-18 21:45:35 +02:00
Matej BačoandGitHub aaee95a761 Merge branch 'main' into 1.7.x 2025-05-18 21:39:53 +02:00
Matej BačoandGitHub 637b842e16 Merge pull request #9801 from appwrite/fix-request-response-1.7.x
fix: request response formats for 1.7.x
2025-05-18 21:32:36 +02:00
Jake BarnbyandGitHub 9873daa3ad Merge pull request #9649 from appwrite/1.7.x
1.7.x
2025-05-18 15:15:37 +00:00
Damodar Lohani c4f1a682fd Fix: update messaging library 2025-05-15 05:58:11 +00:00
Jake Barnby 55236524e3 Fix merge 2025-05-14 21:42:39 +12:00
Jake Barnby 4e9385f70b Merge remote-tracking branch 'origin/1.6.x' into feat-pool-adapter 2025-05-14 21:29:10 +12:00
Jake Barnby 33fbab7e3d Fix missing capture 2025-05-14 21:28:59 +12:00
Jake Barnby 09152a08e1 Fix merge 2025-05-14 18:27:51 +12:00
Jake Barnby af3388a51f Format 2025-05-14 18:16:54 +12:00
Jake Barnby 16b2449787 Revert "Merge pull request #9703 from appwrite/revert-9659-feat-pool-adapter"
This reverts commit bf9deb09f5, reversing
changes made to d312fe22ff.

# Conflicts:
#	app/cli.php
#	app/init/registers.php
#	composer.lock
#	src/Appwrite/Messaging/Adapter/Realtime.php
#	src/Appwrite/Platform/Tasks/ScheduleBase.php
#	src/Appwrite/Platform/Tasks/ScheduleExecutions.php
#	src/Appwrite/Platform/Tasks/ScheduleFunctions.php
#	src/Appwrite/Platform/Tasks/ScheduleMessages.php
2025-05-14 18:14:07 +12:00
Jake Barnby d8cc770ba5 Merge branch 'feat-pool-adapter' of github.com:appwrite/appwrite into feat-pool-adapter 2025-05-14 16:43:03 +12:00
Jake Barnby 3e914a4f1b Revert name merge issue 2025-05-14 16:42:36 +12:00
Jake Barnby 406630cb61 Update deps 2025-05-14 16:40:47 +12:00
Jake Barnby a4239fc5dc Merge remote-tracking branch 'origin/1.6.x' into feat-pool-adapter 2025-05-14 00:36:45 +12:00
Jake Barnby 0f313afcb5 Merge remote-tracking branch 'origin/1.6.x' into feat-pool-adapter
# Conflicts:
#	src/Appwrite/Messaging/Adapter/Realtime.php
2025-05-13 21:10:57 +12:00
Darshan bc556c559f Merge branch '1.7.x' into 'lazy-load-relationships'. 2025-05-11 14:56:40 +05:30
Darshan 04539bff4a update: make variable private. 2025-05-03 09:59:53 +05:30
Darshan 29647a9dc8 address comments. 2025-05-03 09:59:04 +05:30
Darshan a3db080fcf update: method doc. 2025-05-02 19:56:00 +05:30
Darshan 5ba363b787 Merge remote-tracking branch 'origin/lazy-load-relationships' into lazy-load-relationships 2025-05-02 19:51:55 +05:30
Darshan 0a12b561c8 update: remove unneeded change. 2025-05-02 19:51:38 +05:30
DarshanandGitHub 36c4ed1dca Merge branch '1.7.x' into lazy-load-relationships 2025-05-02 19:49:30 +05:30
Darshan 53133ba54f patch: filters pre 1.7.x 2025-05-02 19:48:39 +05:30
Darshan 22174bec0e attempt: conditional doc fetch. 2025-05-02 12:38:48 +05:30
Darshan b00e7b804a revert: tests. 2025-05-02 09:32:29 +05:30
Darshan 50448126a9 Merge branch '1.7.x' into 'lazy-load-relationships'. 2025-05-01 20:00:32 +05:30
Darshan e7e38c57f7 revert: changes to original. 2025-05-01 19:51:11 +05:30
ArnabChatterjee20k 7750ada4d8 * exposed internal id as a part of auto increment id
* updated test cases regarding internal id
2025-05-01 18:55:04 +05:30
Jake Barnby ea42b823d8 Revert name merge issue 2025-04-30 22:47:41 +12:00
Darshan 6ffe620c57 attempt: fixes, changes. 2025-04-28 15:36:30 +05:30
DarshanandGitHub 7b901b5d34 Merge branch '1.7.x' into lazy-load-relationships 2025-04-24 19:28:17 +05:30
Darshan 511cf72013 fix: tests as per the latest databases changes. 2025-04-19 19:17:25 +05:30
Darshan 12b816178b feat: lazy-load relationships test. 2025-04-19 16:25:08 +05:30
1057 changed files with 187291 additions and 4735 deletions
+7 -1
View File
@@ -8,4 +8,10 @@ reviews:
base_branches:
- main
- 1.6.x
- 1.7.x
- 1.7.x
- 1.8.x
high_level_summary: false
poem: false
sequence_diagrams: false
collapse_walkthrough: true
changed_files_summary: false
+1 -1
View File
@@ -85,7 +85,7 @@ _APP_COMPUTE_RUNTIMES_NETWORK=runtimes
_APP_EXECUTOR_SECRET=your-secret-key
_APP_EXECUTOR_HOST=http://exc1/v1
_APP_FUNCTIONS_RUNTIMES=php-8.0,node-18.0,python-3.9,ruby-3.1
_APP_SITES_RUNTIMES=static-1,node-22,flutter-3.29
_APP_SITES_RUNTIMES=static-1,node-22,flutter-3.32
_APP_MAINTENANCE_INTERVAL=86400
_APP_MAINTENANCE_START_TIME=12:00
_APP_MAINTENANCE_RETENTION_CACHE=2592000
+2 -2
View File
@@ -198,7 +198,7 @@ jobs:
docker compose exec -T \
-e _APP_DATABASE_SHARED_TABLES \
-e _APP_DATABASE_SHARED_TABLES_V1 \
appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug --exclude=devKeys
appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug --exclude-group devKeys
e2e_shared_mode_test:
name: E2E Shared Mode Service Test
@@ -277,7 +277,7 @@ jobs:
docker compose exec -T \
-e _APP_DATABASE_SHARED_TABLES \
-e _APP_DATABASE_SHARED_TABLES_V1 \
appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug --exclude=devKeys
appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug --exclude-group devKeys
e2e_dev_keys:
name: E2E Service Test (Dev Keys)
+5 -5
View File
@@ -415,8 +415,8 @@ In addition, you will also need to add some logic to the `reduce()` method of th
```php
case $document->getCollection() === 'buckets':
$files = $dbForProject->getDocument('stats', md5(self::INFINITY_PERIOD . str_replace('{bucketInternalId}', $document->getInternalId(), METRIC_BUCKET_ID_FILES)));
$storage = $dbForProject->getDocument('stats', md5(self::INFINITY_PERIOD . str_replace('{bucketInternalId}', $document->getInternalId(), METRIC_BUCKET_ID_FILES_STORAGE)));
$files = $dbForProject->getDocument('stats', md5(self::INFINITY_PERIOD . str_replace('{bucketInternalId}', $document->getSequence(), METRIC_BUCKET_ID_FILES)));
$storage = $dbForProject->getDocument('stats', md5(self::INFINITY_PERIOD . str_replace('{bucketInternalId}', $document->getSequence(), METRIC_BUCKET_ID_FILES_STORAGE)));
if (!empty($files['value'])) {
$metrics[] = [
@@ -463,9 +463,9 @@ $queueForStatsUsage
->addMetric(METRIC_BUILDS, 1)
->addMetric(METRIC_BUILDS_STORAGE, $build->getAttribute('size', 0))
->addMetric(METRIC_BUILDS_COMPUTE, (int)$build->getAttribute('duration', 0) * 1000)
->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS), 1)
->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS_STORAGE), $build->getAttribute('size', 0))
->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_BUILDS_COMPUTE), (int)$build->getAttribute('duration', 0) * 1000)
->addMetric(str_replace('{functionInternalId}', $function->getSequence(), METRIC_FUNCTION_ID_BUILDS), 1)
->addMetric(str_replace('{functionInternalId}', $function->getSequence(), METRIC_FUNCTION_ID_BUILDS_STORAGE), $build->getAttribute('size', 0))
->addMetric(str_replace('{functionInternalId}', $function->getSequence(), METRIC_FUNCTION_ID_BUILDS_COMPUTE), (int)$build->getAttribute('duration', 0) * 1000)
->setProject($project)
->trigger();
```
+3 -3
View File
@@ -72,7 +72,7 @@ docker run -it --rm \
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
--entrypoint="install" \
appwrite/appwrite:1.7.0
appwrite/appwrite:1.7.4
```
### Windows
@@ -84,7 +84,7 @@ docker run -it --rm ^
--volume //var/run/docker.sock:/var/run/docker.sock ^
--volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^
--entrypoint="install" ^
appwrite/appwrite:1.7.0
appwrite/appwrite:1.7.4
```
#### PowerShell
@@ -94,7 +94,7 @@ docker run -it --rm `
--volume /var/run/docker.sock:/var/run/docker.sock `
--volume ${pwd}/appwrite:/usr/src/code/appwrite:rw `
--entrypoint="install" `
appwrite/appwrite:1.7.0
appwrite/appwrite:1.7.4
```
运行后,可以在浏览器上访问 http://localhost 找到 Appwrite 控制台。在非 Linux 的本机主机上完成安装后,服务器可能需要几分钟才能启动。
+3 -3
View File
@@ -78,7 +78,7 @@ docker run -it --rm \
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
--entrypoint="install" \
appwrite/appwrite:1.7.0
appwrite/appwrite:1.7.4
```
### Windows
@@ -90,7 +90,7 @@ docker run -it --rm ^
--volume //var/run/docker.sock:/var/run/docker.sock ^
--volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^
--entrypoint="install" ^
appwrite/appwrite:1.7.0
appwrite/appwrite:1.7.4
```
#### PowerShell
@@ -100,7 +100,7 @@ docker run -it --rm `
--volume /var/run/docker.sock:/var/run/docker.sock `
--volume ${pwd}/appwrite:/usr/src/code/appwrite:rw `
--entrypoint="install" `
appwrite/appwrite:1.7.0
appwrite/appwrite:1.7.4
```
Once the Docker installation is complete, go to http://localhost to access the Appwrite console from your browser. Please note that on non-Linux native hosts, the server might take a few minutes to start after completing the installation.
+21 -34
View File
@@ -10,12 +10,15 @@ use Appwrite\Event\StatsUsage;
use Appwrite\Platform\Appwrite;
use Appwrite\Runtimes\Runtimes;
use Executor\Executor;
use Swoole\Runtime;
use Swoole\Timer;
use Utopia\Cache\Adapter\Pool as CachePool;
use Utopia\Cache\Adapter\Sharding;
use Utopia\Cache\Cache;
use Utopia\CLI\CLI;
use Utopia\CLI\Console;
use Utopia\Config\Config;
use Utopia\Database\Adapter\Pool as DatabasePool;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Validator\Authorization;
@@ -23,6 +26,7 @@ use Utopia\DSN\DSN;
use Utopia\Logger\Log;
use Utopia\Platform\Service;
use Utopia\Pools\Group;
use Utopia\Queue\Broker\Pool as BrokerPool;
use Utopia\Queue\Publisher;
use Utopia\Registry\Registry;
use Utopia\System\System;
@@ -45,10 +49,7 @@ CLI::setResource('cache', function ($pools) {
$adapters = [];
foreach ($list as $value) {
$adapters[] = $pools
->get($value)
->pop()
->getResource();
$adapters[] = new CachePool($pools->get($value));
}
return new Cache(new Sharding($adapters));
@@ -68,12 +69,8 @@ CLI::setResource('dbForPlatform', function ($pools, $cache) {
$attempts++;
try {
// Prepare database connection
$dbAdapter = $pools
->get('console')
->pop()
->getResource();
$dbForPlatform = new Database($dbAdapter, $cache);
$adapter = new DatabasePool($pools->get('console'));
$dbForPlatform = new Database($adapter, $cache);
$dbForPlatform
->setNamespace('_console')
@@ -91,7 +88,6 @@ CLI::setResource('dbForPlatform', function ($pools, $cache) {
$ready = true;
} catch (\Throwable $err) {
Console::warning($err->getMessage());
$pools->get('console')->reclaim();
sleep($sleep);
}
} while ($attempts < $maxAttempts && !$ready);
@@ -129,37 +125,33 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform
if (\in_array($dsn->getHost(), $sharedTables)) {
$database
->setSharedTables(true)
->setTenant($project->getInternalId())
->setTenant($project->getSequence())
->setNamespace($dsn->getParam('namespace'));
} else {
$database
->setSharedTables(false)
->setTenant(null)
->setNamespace('_' . $project->getInternalId());
->setNamespace('_' . $project->getSequence());
}
return $database;
}
$dbAdapter = $pools
->get($dsn->getHost())
->pop()
->getResource();
$database = new Database($dbAdapter, $cache);
$adapter = new DatabasePool($pools->get($dsn->getHost()));
$database = new Database($adapter, $cache);
$databases[$dsn->getHost()] = $database;
$sharedTables = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES', ''));
if (\in_array($dsn->getHost(), $sharedTables)) {
$database
->setSharedTables(true)
->setTenant($project->getInternalId())
->setTenant($project->getSequence())
->setNamespace($dsn->getParam('namespace'));
} else {
$database
->setSharedTables(false)
->setTenant(null)
->setNamespace('_' . $project->getInternalId());
->setNamespace('_' . $project->getSequence());
}
$database
@@ -172,21 +164,15 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform
CLI::setResource('getLogsDB', function (Group $pools, Cache $cache) {
$database = null;
return function (?Document $project = null) use ($pools, $cache, $database) {
if ($database !== null && $project !== null && !$project->isEmpty() && $project->getId() !== 'console') {
$database->setTenant($project->getInternalId());
$database->setTenant($project->getSequence());
return $database;
}
$dbAdapter = $pools
->get('logs')
->pop()
->getResource();
$database = new Database(
$dbAdapter,
$cache
);
$adapter = new DatabasePool($pools->get('logs'));
$database = new Database($adapter, $cache);
$database
->setSharedTables(true)
@@ -196,7 +182,7 @@ CLI::setResource('getLogsDB', function (Group $pools, Cache $cache) {
// set tenant
if ($project !== null && !$project->isEmpty() && $project->getId() !== 'console') {
$database->setTenant($project->getInternalId());
$database->setTenant($project->getSequence());
}
return $database;
@@ -210,7 +196,7 @@ CLI::setResource('queueForStatsResources', function (Publisher $publisher) {
return new StatsResources($publisher);
}, ['publisher']);
CLI::setResource('publisher', function (Group $pools) {
return $pools->get('publisher')->pop()->getResource();
return new BrokerPool(publisher: $pools->get('publisher'));
}, ['pools']);
CLI::setResource('queueForFunctions', function (Publisher $publisher) {
return new Func($publisher);
@@ -265,7 +251,7 @@ CLI::setResource('logError', function (Registry $register) {
};
}, ['register']);
CLI::setResource('executor', fn () => new Executor(fn (string $projectId, string $deploymentId) => System::getEnv('_APP_EXECUTOR_HOST')));
CLI::setResource('executor', fn () => new Executor());
CLI::setResource('telemetry', fn () => new NoTelemetry());
@@ -298,4 +284,5 @@ $cli
$cli->shutdown()->action(fn () => Timer::clearAll());
Runtime::enableCoroutine(SWOOLE_HOOK_ALL);
run($cli->run(...));
-7
View File
@@ -1439,13 +1439,6 @@ return [
'lengths' => [],
'orders' => [Database::ORDER_ASC],
],
[
'$id' => ID::custom('_key_roles'),
'type' => Database::INDEX_KEY,
'attributes' => ['roles'],
'lengths' => [128],
'orders' => [],
],
],
],
+1 -1
View File
@@ -11,7 +11,7 @@ use Utopia\System\System;
$console = [
'$id' => ID::custom('console'),
'$internalId' => ID::custom('console'),
'$sequence' => ID::custom('console'),
'name' => 'Appwrite',
'$collection' => ID::custom('projects'),
'description' => 'Appwrite core engine',
+10
View File
@@ -393,6 +393,16 @@ return [
'description' => 'Membership is already confirmed.',
'code' => 409,
],
Exception::MEMBERSHIP_DELETION_PROHIBITED => [
'name' => Exception::MEMBERSHIP_DELETION_PROHIBITED,
'description' => 'Membership deletion is prohibited.',
'code' => 400,
],
Exception::MEMBERSHIP_DOWNGRADE_PROHIBITED => [
'name' => Exception::MEMBERSHIP_DOWNGRADE_PROHIBITED,
'description' => 'Membership role downgrade is prohibited.',
'code' => 400,
],
/** Avatars */
Exception::AVATAR_SET_NOT_FOUND => [
+14 -9
View File
@@ -11,7 +11,7 @@ return [
[
'key' => 'web',
'name' => 'Web',
'version' => '18.0.0',
'version' => '18.1.0',
'url' => 'https://github.com/appwrite/sdk-for-web',
'package' => 'https://www.npmjs.com/package/appwrite',
'enabled' => true,
@@ -59,7 +59,7 @@ return [
[
'key' => 'flutter',
'name' => 'Flutter',
'version' => '16.0.0',
'version' => '17.0.1',
'url' => 'https://github.com/appwrite/sdk-for-flutter',
'package' => 'https://pub.dev/packages/appwrite',
'enabled' => true,
@@ -77,7 +77,7 @@ return [
[
'key' => 'apple',
'name' => 'Apple',
'version' => '10.0.0',
'version' => '10.1.1',
'url' => 'https://github.com/appwrite/sdk-for-apple',
'package' => 'https://github.com/appwrite/sdk-for-apple',
'enabled' => true,
@@ -112,7 +112,7 @@ return [
[
'key' => 'android',
'name' => 'Android',
'version' => '8.0.0',
'version' => '8.1.0',
'url' => 'https://github.com/appwrite/sdk-for-android',
'package' => 'https://search.maven.org/artifact/io.appwrite/sdk-for-android',
'enabled' => true,
@@ -134,7 +134,7 @@ return [
[
'key' => 'react-native',
'name' => 'React Native',
'version' => '0.9.0',
'version' => '0.9.1',
'url' => 'https://github.com/appwrite/sdk-for-react-native',
'package' => 'https://npmjs.com/package/react-native-appwrite',
'enabled' => true,
@@ -199,7 +199,7 @@ return [
[
'key' => 'web',
'name' => 'Console',
'version' => '1.3.0',
'version' => '1.7.0',
'url' => 'https://github.com/appwrite/sdk-for-console',
'package' => '',
'enabled' => true,
@@ -217,7 +217,7 @@ return [
[
'key' => 'cli',
'name' => 'Command Line',
'version' => '6.2.3',
'version' => '8.0.0',
'url' => 'https://github.com/appwrite/sdk-for-cli',
'package' => 'https://www.npmjs.com/package/appwrite-cli',
'enabled' => true,
@@ -231,6 +231,11 @@ return [
'gitRepoName' => 'sdk-for-cli',
'gitUserName' => 'appwrite',
'gitBranch' => 'dev',
'exclude' => [
'services' => [
['name' => 'assistant'],
],
],
],
],
],
@@ -353,7 +358,7 @@ return [
[
'key' => 'dotnet',
'name' => '.NET',
'version' => '0.15.0',
'version' => '0.13.0',
'url' => 'https://github.com/appwrite/sdk-for-dotnet',
'package' => 'https://www.nuget.org/packages/Appwrite',
'enabled' => true,
@@ -411,7 +416,7 @@ return [
[
'key' => 'swift',
'name' => 'Swift',
'version' => '10.0.0',
'version' => '10.1.0',
'url' => 'https://github.com/appwrite/sdk-for-swift',
'package' => 'https://github.com/appwrite/sdk-for-swift',
'enabled' => true,
+153 -38
View File
@@ -1,7 +1,7 @@
{
"openapi": "3.0.0",
"info": {
"version": "1.7.0",
"version": "1.7.4",
"title": "Appwrite",
"description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)",
"termsOfService": "https:\/\/appwrite.io\/policy\/terms",
@@ -4660,6 +4660,115 @@
}
]
},
"put": {
"summary": "Upsert document",
"operationId": "databasesUpsertDocument",
"tags": [
"databases"
],
"description": "Create or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
"responses": {
"200": {
"description": "Document",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/document"
}
}
}
}
},
"x-appwrite": {
"method": "upsertDocument",
"group": "documents",
"weight": 114,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "databases\/upsert-document.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/upsert-document.md",
"rate-limit": 120,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "documents.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "databaseId",
"description": "Database ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<DATABASE_ID>"
},
"in": "path"
},
{
"name": "collectionId",
"description": "Collection ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<COLLECTION_ID>"
},
"in": "path"
},
{
"name": "documentId",
"description": "Document ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<DOCUMENT_ID>"
},
"in": "path"
}
],
"requestBody": {
"content": {
"application\/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"description": "Document data as JSON object. Include all required attributes of the document to be created or updated.",
"x-example": "{}"
},
"permissions": {
"type": "array",
"description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
"x-example": "[\"read(\"any\")\"]",
"items": {
"type": "string"
}
}
},
"required": [
"data"
]
}
}
}
}
},
"patch": {
"summary": "Update document",
"operationId": "databasesUpdateDocument",
@@ -4781,7 +4890,7 @@
"x-appwrite": {
"method": "deleteDocument",
"group": "documents",
"weight": 116,
"weight": 117,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4865,7 +4974,7 @@
"x-appwrite": {
"method": "listExecutions",
"group": "executions",
"weight": 391,
"weight": 392,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4940,7 +5049,7 @@
"x-appwrite": {
"method": "createExecution",
"group": "executions",
"weight": 389,
"weight": 390,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5055,7 +5164,7 @@
"x-appwrite": {
"method": "getExecution",
"group": "executions",
"weight": 390,
"weight": 391,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5129,7 +5238,7 @@
"x-appwrite": {
"method": "query",
"group": "graphql",
"weight": 305,
"weight": 306,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -5181,7 +5290,7 @@
"x-appwrite": {
"method": "mutation",
"group": "graphql",
"weight": 304,
"weight": 305,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -5233,7 +5342,7 @@
"x-appwrite": {
"method": "get",
"group": null,
"weight": 121,
"weight": 122,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5285,7 +5394,7 @@
"x-appwrite": {
"method": "listCodes",
"group": null,
"weight": 122,
"weight": 123,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5337,7 +5446,7 @@
"x-appwrite": {
"method": "listContinents",
"group": null,
"weight": 126,
"weight": 127,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5389,7 +5498,7 @@
"x-appwrite": {
"method": "listCountries",
"group": null,
"weight": 123,
"weight": 124,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5441,7 +5550,7 @@
"x-appwrite": {
"method": "listCountriesEU",
"group": null,
"weight": 124,
"weight": 125,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5493,7 +5602,7 @@
"x-appwrite": {
"method": "listCountriesPhones",
"group": null,
"weight": 125,
"weight": 126,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5545,7 +5654,7 @@
"x-appwrite": {
"method": "listCurrencies",
"group": null,
"weight": 127,
"weight": 128,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5597,7 +5706,7 @@
"x-appwrite": {
"method": "listLanguages",
"group": null,
"weight": 128,
"weight": 129,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5649,7 +5758,7 @@
"x-appwrite": {
"method": "createSubscriber",
"group": "subscribers",
"weight": 351,
"weight": 352,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5732,7 +5841,7 @@
"x-appwrite": {
"method": "deleteSubscriber",
"group": "subscribers",
"weight": 355,
"weight": 356,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5807,7 +5916,7 @@
"x-appwrite": {
"method": "listFiles",
"group": "files",
"weight": 211,
"weight": 212,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5893,7 +6002,7 @@
"x-appwrite": {
"method": "createFile",
"group": "files",
"weight": 210,
"weight": 211,
"cookies": false,
"type": "upload",
"deprecated": false,
@@ -5991,7 +6100,7 @@
"x-appwrite": {
"method": "getFile",
"group": "files",
"weight": 212,
"weight": 213,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6063,7 +6172,7 @@
"x-appwrite": {
"method": "updateFile",
"group": "files",
"weight": 217,
"weight": 218,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6152,7 +6261,7 @@
"x-appwrite": {
"method": "deleteFile",
"group": "files",
"weight": 218,
"weight": 219,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6219,7 +6328,7 @@
"x-appwrite": {
"method": "getFileDownload",
"group": "files",
"weight": 214,
"weight": 215,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6297,7 +6406,7 @@
"x-appwrite": {
"method": "getFilePreview",
"group": "files",
"weight": 213,
"weight": 214,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6524,7 +6633,7 @@
"x-appwrite": {
"method": "getFileView",
"group": "files",
"weight": 215,
"weight": 216,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6609,7 +6718,7 @@
"x-appwrite": {
"method": "list",
"group": "teams",
"weight": 222,
"weight": 223,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6685,7 +6794,7 @@
"x-appwrite": {
"method": "create",
"group": "teams",
"weight": 221,
"weight": 222,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6770,7 +6879,7 @@
"x-appwrite": {
"method": "get",
"group": "teams",
"weight": 223,
"weight": 224,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6832,7 +6941,7 @@
"x-appwrite": {
"method": "updateName",
"group": "teams",
"weight": 225,
"weight": 226,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6906,7 +7015,7 @@
"x-appwrite": {
"method": "delete",
"group": "teams",
"weight": 227,
"weight": 228,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6970,7 +7079,7 @@
"x-appwrite": {
"method": "listMemberships",
"group": "memberships",
"weight": 229,
"weight": 230,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7056,7 +7165,7 @@
"x-appwrite": {
"method": "createMembership",
"group": "memberships",
"weight": 228,
"weight": 229,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7167,7 +7276,7 @@
"x-appwrite": {
"method": "getMembership",
"group": "memberships",
"weight": 230,
"weight": 231,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7239,7 +7348,7 @@
"x-appwrite": {
"method": "updateMembership",
"group": "memberships",
"weight": 231,
"weight": 232,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7326,7 +7435,7 @@
"x-appwrite": {
"method": "deleteMembership",
"group": "memberships",
"weight": 233,
"weight": 234,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7400,7 +7509,7 @@
"x-appwrite": {
"method": "updateMembershipStatus",
"group": "memberships",
"weight": 232,
"weight": 233,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7498,7 +7607,7 @@
"x-appwrite": {
"method": "getPrefs",
"group": "teams",
"weight": 224,
"weight": 225,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7559,7 +7668,7 @@
"x-appwrite": {
"method": "updatePrefs",
"group": "teams",
"weight": 226,
"weight": 227,
"cookies": false,
"type": "",
"deprecated": false,
@@ -9752,6 +9861,12 @@
"name": "X-Appwrite-Session",
"description": "The user session to authenticate with",
"in": "header"
},
"DevKey": {
"type": "apiKey",
"name": "X-Appwrite-Dev-Key",
"description": "Your secret dev API key",
"in": "header"
}
}
},
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+417 -39
View File
@@ -1,7 +1,7 @@
{
"openapi": "3.0.0",
"info": {
"version": "1.7.0",
"version": "1.7.4",
"title": "Appwrite",
"description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)",
"termsOfService": "https:\/\/appwrite.io\/policy\/terms",
@@ -4457,6 +4457,7 @@
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "documents.write",
"platforms": [
"console",
"client",
"server",
"server"
@@ -4466,6 +4467,7 @@
{
"name": "createDocument",
"auth": {
"Admin": [],
"Session": [],
"Key": [],
"JWT": []
@@ -4490,6 +4492,29 @@
}
],
"description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
},
{
"name": "createDocuments",
"auth": {
"Key": []
},
"parameters": [
"databaseId",
"collectionId",
"documents"
],
"required": [
"databaseId",
"collectionId",
"documents"
],
"responses": [
{
"code": 201,
"model": "#\/components\/schemas\/documentList"
}
],
"description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
}
],
"auth": {
@@ -4660,6 +4685,115 @@
}
]
},
"put": {
"summary": "Upsert document",
"operationId": "databasesUpsertDocument",
"tags": [
"databases"
],
"description": "Create or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
"responses": {
"200": {
"description": "Document",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/document"
}
}
}
}
},
"x-appwrite": {
"method": "upsertDocument",
"group": "documents",
"weight": 114,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "databases\/upsert-document.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/upsert-document.md",
"rate-limit": 120,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "documents.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "databaseId",
"description": "Database ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<DATABASE_ID>"
},
"in": "path"
},
{
"name": "collectionId",
"description": "Collection ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<COLLECTION_ID>"
},
"in": "path"
},
{
"name": "documentId",
"description": "Document ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<DOCUMENT_ID>"
},
"in": "path"
}
],
"requestBody": {
"content": {
"application\/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"description": "Document data as JSON object. Include all required attributes of the document to be created or updated.",
"x-example": "{}"
},
"permissions": {
"type": "array",
"description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
"x-example": "[\"read(\"any\")\"]",
"items": {
"type": "string"
}
}
},
"required": [
"data"
]
}
}
}
}
},
"patch": {
"summary": "Update document",
"operationId": "databasesUpdateDocument",
@@ -4781,7 +4915,7 @@
"x-appwrite": {
"method": "deleteDocument",
"group": "documents",
"weight": 116,
"weight": 119,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4842,6 +4976,236 @@
]
}
},
"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}\/{attribute}\/decrement": {
"patch": {
"summary": "Decrement document attribute",
"operationId": "databasesDecrementDocumentAttribute",
"tags": [
"databases"
],
"description": "Decrement a specific attribute of a document by a given value.",
"responses": {
"200": {
"description": "Document",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/document"
}
}
}
}
},
"x-appwrite": {
"method": "decrementDocumentAttribute",
"group": "documents",
"weight": 116,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "databases\/decrement-document-attribute.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/decrement-document-attribute.md",
"rate-limit": 120,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "documents.write",
"platforms": [
"console",
"server",
"client",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "databaseId",
"description": "Database ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<DATABASE_ID>"
},
"in": "path"
},
{
"name": "collectionId",
"description": "Collection ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<COLLECTION_ID>"
},
"in": "path"
},
{
"name": "documentId",
"description": "Document ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<DOCUMENT_ID>"
},
"in": "path"
},
{
"name": "attribute",
"description": "Attribute key.",
"required": true,
"schema": {
"type": "string"
},
"in": "path"
}
],
"requestBody": {
"content": {
"application\/json": {
"schema": {
"type": "object",
"properties": {
"value": {
"type": "number",
"description": "Value to decrement the attribute by. The value must be a number.",
"x-example": null
},
"min": {
"type": "number",
"description": "Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown.",
"x-example": null
}
}
}
}
}
}
}
},
"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}\/{attribute}\/increment": {
"patch": {
"summary": "Increment document attribute",
"operationId": "databasesIncrementDocumentAttribute",
"tags": [
"databases"
],
"description": "Increment a specific attribute of a document by a given value.",
"responses": {
"200": {
"description": "Document",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/document"
}
}
}
}
},
"x-appwrite": {
"method": "incrementDocumentAttribute",
"group": "documents",
"weight": 115,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "databases\/increment-document-attribute.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/increment-document-attribute.md",
"rate-limit": 120,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "documents.write",
"platforms": [
"console",
"server",
"client",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "databaseId",
"description": "Database ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<DATABASE_ID>"
},
"in": "path"
},
{
"name": "collectionId",
"description": "Collection ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<COLLECTION_ID>"
},
"in": "path"
},
{
"name": "documentId",
"description": "Document ID.",
"required": true,
"schema": {
"type": "string",
"x-example": "<DOCUMENT_ID>"
},
"in": "path"
},
{
"name": "attribute",
"description": "Attribute key.",
"required": true,
"schema": {
"type": "string"
},
"in": "path"
}
],
"requestBody": {
"content": {
"application\/json": {
"schema": {
"type": "object",
"properties": {
"value": {
"type": "number",
"description": "Value to increment the attribute by. The value must be a number.",
"x-example": null
},
"max": {
"type": "number",
"description": "Maximum value for the attribute. If the current value is greater than this value, an error will be thrown.",
"x-example": null
}
}
}
}
}
}
}
},
"\/functions\/{functionId}\/executions": {
"get": {
"summary": "List executions",
@@ -4865,7 +5229,7 @@
"x-appwrite": {
"method": "listExecutions",
"group": "executions",
"weight": 391,
"weight": 394,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4940,7 +5304,7 @@
"x-appwrite": {
"method": "createExecution",
"group": "executions",
"weight": 389,
"weight": 392,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5055,7 +5419,7 @@
"x-appwrite": {
"method": "getExecution",
"group": "executions",
"weight": 390,
"weight": 393,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5129,7 +5493,7 @@
"x-appwrite": {
"method": "query",
"group": "graphql",
"weight": 305,
"weight": 308,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -5181,7 +5545,7 @@
"x-appwrite": {
"method": "mutation",
"group": "graphql",
"weight": 304,
"weight": 307,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -5233,7 +5597,7 @@
"x-appwrite": {
"method": "get",
"group": null,
"weight": 121,
"weight": 124,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5285,7 +5649,7 @@
"x-appwrite": {
"method": "listCodes",
"group": null,
"weight": 122,
"weight": 125,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5337,7 +5701,7 @@
"x-appwrite": {
"method": "listContinents",
"group": null,
"weight": 126,
"weight": 129,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5389,7 +5753,7 @@
"x-appwrite": {
"method": "listCountries",
"group": null,
"weight": 123,
"weight": 126,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5441,7 +5805,7 @@
"x-appwrite": {
"method": "listCountriesEU",
"group": null,
"weight": 124,
"weight": 127,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5493,7 +5857,7 @@
"x-appwrite": {
"method": "listCountriesPhones",
"group": null,
"weight": 125,
"weight": 128,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5545,7 +5909,7 @@
"x-appwrite": {
"method": "listCurrencies",
"group": null,
"weight": 127,
"weight": 130,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5597,7 +5961,7 @@
"x-appwrite": {
"method": "listLanguages",
"group": null,
"weight": 128,
"weight": 131,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5649,7 +6013,7 @@
"x-appwrite": {
"method": "createSubscriber",
"group": "subscribers",
"weight": 351,
"weight": 354,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5732,7 +6096,7 @@
"x-appwrite": {
"method": "deleteSubscriber",
"group": "subscribers",
"weight": 355,
"weight": 358,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5807,7 +6171,7 @@
"x-appwrite": {
"method": "listFiles",
"group": "files",
"weight": 211,
"weight": 214,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5893,7 +6257,7 @@
"x-appwrite": {
"method": "createFile",
"group": "files",
"weight": 210,
"weight": 213,
"cookies": false,
"type": "upload",
"deprecated": false,
@@ -5991,7 +6355,7 @@
"x-appwrite": {
"method": "getFile",
"group": "files",
"weight": 212,
"weight": 215,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6063,7 +6427,7 @@
"x-appwrite": {
"method": "updateFile",
"group": "files",
"weight": 217,
"weight": 220,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6152,7 +6516,7 @@
"x-appwrite": {
"method": "deleteFile",
"group": "files",
"weight": 218,
"weight": 221,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6219,7 +6583,7 @@
"x-appwrite": {
"method": "getFileDownload",
"group": "files",
"weight": 214,
"weight": 217,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6297,7 +6661,7 @@
"x-appwrite": {
"method": "getFilePreview",
"group": "files",
"weight": 213,
"weight": 216,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6486,7 +6850,8 @@
"png",
"webp",
"heic",
"avif"
"avif",
"gif"
],
"x-enum-name": "ImageFormat",
"x-enum-keys": [],
@@ -6524,7 +6889,7 @@
"x-appwrite": {
"method": "getFileView",
"group": "files",
"weight": 215,
"weight": 218,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6609,7 +6974,7 @@
"x-appwrite": {
"method": "list",
"group": "teams",
"weight": 222,
"weight": 225,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6685,7 +7050,7 @@
"x-appwrite": {
"method": "create",
"group": "teams",
"weight": 221,
"weight": 224,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6770,7 +7135,7 @@
"x-appwrite": {
"method": "get",
"group": "teams",
"weight": 223,
"weight": 226,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6832,7 +7197,7 @@
"x-appwrite": {
"method": "updateName",
"group": "teams",
"weight": 225,
"weight": 228,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6906,7 +7271,7 @@
"x-appwrite": {
"method": "delete",
"group": "teams",
"weight": 227,
"weight": 230,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6970,7 +7335,7 @@
"x-appwrite": {
"method": "listMemberships",
"group": "memberships",
"weight": 229,
"weight": 232,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7056,7 +7421,7 @@
"x-appwrite": {
"method": "createMembership",
"group": "memberships",
"weight": 228,
"weight": 231,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7167,7 +7532,7 @@
"x-appwrite": {
"method": "getMembership",
"group": "memberships",
"weight": 230,
"weight": 233,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7239,7 +7604,7 @@
"x-appwrite": {
"method": "updateMembership",
"group": "memberships",
"weight": 231,
"weight": 234,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7326,7 +7691,7 @@
"x-appwrite": {
"method": "deleteMembership",
"group": "memberships",
"weight": 233,
"weight": 236,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7400,7 +7765,7 @@
"x-appwrite": {
"method": "updateMembershipStatus",
"group": "memberships",
"weight": 232,
"weight": 235,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7498,7 +7863,7 @@
"x-appwrite": {
"method": "getPrefs",
"group": "teams",
"weight": 224,
"weight": 227,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7559,7 +7924,7 @@
"x-appwrite": {
"method": "updatePrefs",
"group": "teams",
"weight": 226,
"weight": 229,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8073,6 +8438,12 @@
"description": "Document ID.",
"x-example": "5e5ea5c16897e"
},
"$sequence": {
"type": "integer",
"description": "Document automatically incrementing ID.",
"x-example": 1,
"format": "int32"
},
"$collectionId": {
"type": "string",
"description": "Collection ID.",
@@ -8107,6 +8478,7 @@
"additionalProperties": true,
"required": [
"$id",
"$sequence",
"$collectionId",
"$databaseId",
"$createdAt",
@@ -9752,6 +10124,12 @@
"name": "X-Appwrite-Session",
"description": "The user session to authenticate with",
"in": "header"
},
"DevKey": {
"type": "apiKey",
"name": "X-Appwrite-Dev-Key",
"description": "Your secret dev API key",
"in": "header"
}
}
},
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+149 -38
View File
@@ -1,7 +1,7 @@
{
"swagger": "2.0",
"info": {
"version": "1.7.0",
"version": "1.7.4",
"title": "Appwrite",
"description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)",
"termsOfService": "https:\/\/appwrite.io\/policy\/terms",
@@ -61,6 +61,12 @@
"name": "X-Appwrite-Session",
"description": "The user session to authenticate with",
"in": "header"
},
"DevKey": {
"type": "apiKey",
"name": "X-Appwrite-Dev-Key",
"description": "Your secret dev API key",
"in": "header"
}
},
"paths": {
@@ -4791,6 +4797,111 @@
}
]
},
"put": {
"summary": "Upsert document",
"operationId": "databasesUpsertDocument",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"databases"
],
"description": "Create or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
"responses": {
"200": {
"description": "Document",
"schema": {
"$ref": "#\/definitions\/document"
}
}
},
"x-appwrite": {
"method": "upsertDocument",
"group": "documents",
"weight": 114,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "databases\/upsert-document.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/upsert-document.md",
"rate-limit": 120,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "documents.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "databaseId",
"description": "Database ID.",
"required": true,
"type": "string",
"x-example": "<DATABASE_ID>",
"in": "path"
},
{
"name": "collectionId",
"description": "Collection ID.",
"required": true,
"type": "string",
"x-example": "<COLLECTION_ID>",
"in": "path"
},
{
"name": "documentId",
"description": "Document ID.",
"required": true,
"type": "string",
"x-example": "<DOCUMENT_ID>",
"in": "path"
},
{
"name": "payload",
"in": "body",
"schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"description": "Document data as JSON object. Include all required attributes of the document to be created or updated.",
"default": {},
"x-example": "{}"
},
"permissions": {
"type": "array",
"description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
"default": null,
"x-example": "[\"read(\"any\")\"]",
"items": {
"type": "string"
}
}
},
"required": [
"data"
]
}
}
]
},
"patch": {
"summary": "Update document",
"operationId": "databasesUpdateDocument",
@@ -4912,7 +5023,7 @@
"x-appwrite": {
"method": "deleteDocument",
"group": "documents",
"weight": 116,
"weight": 117,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4990,7 +5101,7 @@
"x-appwrite": {
"method": "listExecutions",
"group": "executions",
"weight": 391,
"weight": 392,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5064,7 +5175,7 @@
"x-appwrite": {
"method": "createExecution",
"group": "executions",
"weight": 389,
"weight": 390,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5181,7 +5292,7 @@
"x-appwrite": {
"method": "getExecution",
"group": "executions",
"weight": 390,
"weight": 391,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5253,7 +5364,7 @@
"x-appwrite": {
"method": "query",
"group": "graphql",
"weight": 305,
"weight": 306,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -5327,7 +5438,7 @@
"x-appwrite": {
"method": "mutation",
"group": "graphql",
"weight": 304,
"weight": 305,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -5399,7 +5510,7 @@
"x-appwrite": {
"method": "get",
"group": null,
"weight": 121,
"weight": 122,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5451,7 +5562,7 @@
"x-appwrite": {
"method": "listCodes",
"group": null,
"weight": 122,
"weight": 123,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5503,7 +5614,7 @@
"x-appwrite": {
"method": "listContinents",
"group": null,
"weight": 126,
"weight": 127,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5555,7 +5666,7 @@
"x-appwrite": {
"method": "listCountries",
"group": null,
"weight": 123,
"weight": 124,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5607,7 +5718,7 @@
"x-appwrite": {
"method": "listCountriesEU",
"group": null,
"weight": 124,
"weight": 125,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5659,7 +5770,7 @@
"x-appwrite": {
"method": "listCountriesPhones",
"group": null,
"weight": 125,
"weight": 126,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5711,7 +5822,7 @@
"x-appwrite": {
"method": "listCurrencies",
"group": null,
"weight": 127,
"weight": 128,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5763,7 +5874,7 @@
"x-appwrite": {
"method": "listLanguages",
"group": null,
"weight": 128,
"weight": 129,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5817,7 +5928,7 @@
"x-appwrite": {
"method": "createSubscriber",
"group": "subscribers",
"weight": 351,
"weight": 352,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5902,7 +6013,7 @@
"x-appwrite": {
"method": "deleteSubscriber",
"group": "subscribers",
"weight": 355,
"weight": 356,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5973,7 +6084,7 @@
"x-appwrite": {
"method": "listFiles",
"group": "files",
"weight": 211,
"weight": 212,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6056,7 +6167,7 @@
"x-appwrite": {
"method": "createFile",
"group": "files",
"weight": 210,
"weight": 211,
"cookies": false,
"type": "upload",
"deprecated": false,
@@ -6146,7 +6257,7 @@
"x-appwrite": {
"method": "getFile",
"group": "files",
"weight": 212,
"weight": 213,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6216,7 +6327,7 @@
"x-appwrite": {
"method": "updateFile",
"group": "files",
"weight": 217,
"weight": 218,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6305,7 +6416,7 @@
"x-appwrite": {
"method": "deleteFile",
"group": "files",
"weight": 218,
"weight": 219,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6375,7 +6486,7 @@
"x-appwrite": {
"method": "getFileDownload",
"group": "files",
"weight": 214,
"weight": 215,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6454,7 +6565,7 @@
"x-appwrite": {
"method": "getFilePreview",
"group": "files",
"weight": 213,
"weight": 214,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6660,7 +6771,7 @@
"x-appwrite": {
"method": "getFileView",
"group": "files",
"weight": 215,
"weight": 216,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6739,7 +6850,7 @@
"x-appwrite": {
"method": "list",
"group": "teams",
"weight": 222,
"weight": 223,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6814,7 +6925,7 @@
"x-appwrite": {
"method": "create",
"group": "teams",
"weight": 221,
"weight": 222,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6904,7 +7015,7 @@
"x-appwrite": {
"method": "get",
"group": "teams",
"weight": 223,
"weight": 224,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6966,7 +7077,7 @@
"x-appwrite": {
"method": "updateName",
"group": "teams",
"weight": 225,
"weight": 226,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7041,7 +7152,7 @@
"x-appwrite": {
"method": "delete",
"group": "teams",
"weight": 227,
"weight": 228,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7103,7 +7214,7 @@
"x-appwrite": {
"method": "listMemberships",
"group": "memberships",
"weight": 229,
"weight": 230,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7186,7 +7297,7 @@
"x-appwrite": {
"method": "createMembership",
"group": "memberships",
"weight": 228,
"weight": 229,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7299,7 +7410,7 @@
"x-appwrite": {
"method": "getMembership",
"group": "memberships",
"weight": 230,
"weight": 231,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7369,7 +7480,7 @@
"x-appwrite": {
"method": "updateMembership",
"group": "memberships",
"weight": 231,
"weight": 232,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7455,7 +7566,7 @@
"x-appwrite": {
"method": "deleteMembership",
"group": "memberships",
"weight": 233,
"weight": 234,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7527,7 +7638,7 @@
"x-appwrite": {
"method": "updateMembershipStatus",
"group": "memberships",
"weight": 232,
"weight": 233,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7621,7 +7732,7 @@
"x-appwrite": {
"method": "getPrefs",
"group": "teams",
"weight": 224,
"weight": 225,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7682,7 +7793,7 @@
"x-appwrite": {
"method": "updatePrefs",
"group": "teams",
"weight": 226,
"weight": 227,
"cookies": false,
"type": "",
"deprecated": false,
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+401 -39
View File
@@ -1,7 +1,7 @@
{
"swagger": "2.0",
"info": {
"version": "1.7.0",
"version": "1.7.4",
"title": "Appwrite",
"description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)",
"termsOfService": "https:\/\/appwrite.io\/policy\/terms",
@@ -61,6 +61,12 @@
"name": "X-Appwrite-Session",
"description": "The user session to authenticate with",
"in": "header"
},
"DevKey": {
"type": "apiKey",
"name": "X-Appwrite-Dev-Key",
"description": "Your secret dev API key",
"in": "header"
}
},
"paths": {
@@ -4597,6 +4603,7 @@
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "documents.write",
"platforms": [
"console",
"client",
"server",
"server"
@@ -4606,6 +4613,7 @@
{
"name": "createDocument",
"auth": {
"Admin": [],
"Session": [],
"Key": [],
"JWT": []
@@ -4630,6 +4638,29 @@
}
],
"description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
},
{
"name": "createDocuments",
"auth": {
"Key": []
},
"parameters": [
"databaseId",
"collectionId",
"documents"
],
"required": [
"databaseId",
"collectionId",
"documents"
],
"responses": [
{
"code": 201,
"model": "#\/definitions\/documentList"
}
],
"description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console."
}
],
"auth": {
@@ -4791,6 +4822,111 @@
}
]
},
"put": {
"summary": "Upsert document",
"operationId": "databasesUpsertDocument",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"databases"
],
"description": "Create or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.",
"responses": {
"200": {
"description": "Document",
"schema": {
"$ref": "#\/definitions\/document"
}
}
},
"x-appwrite": {
"method": "upsertDocument",
"group": "documents",
"weight": 114,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "databases\/upsert-document.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/upsert-document.md",
"rate-limit": 120,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "documents.write",
"platforms": [
"client",
"server",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "databaseId",
"description": "Database ID.",
"required": true,
"type": "string",
"x-example": "<DATABASE_ID>",
"in": "path"
},
{
"name": "collectionId",
"description": "Collection ID.",
"required": true,
"type": "string",
"x-example": "<COLLECTION_ID>",
"in": "path"
},
{
"name": "documentId",
"description": "Document ID.",
"required": true,
"type": "string",
"x-example": "<DOCUMENT_ID>",
"in": "path"
},
{
"name": "payload",
"in": "body",
"schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"description": "Document data as JSON object. Include all required attributes of the document to be created or updated.",
"default": {},
"x-example": "{}"
},
"permissions": {
"type": "array",
"description": "An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https:\/\/appwrite.io\/docs\/permissions).",
"default": null,
"x-example": "[\"read(\"any\")\"]",
"items": {
"type": "string"
}
}
},
"required": [
"data"
]
}
}
]
},
"patch": {
"summary": "Update document",
"operationId": "databasesUpdateDocument",
@@ -4912,7 +5048,7 @@
"x-appwrite": {
"method": "deleteDocument",
"group": "documents",
"weight": 116,
"weight": 119,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4967,6 +5103,224 @@
]
}
},
"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}\/{attribute}\/decrement": {
"patch": {
"summary": "Decrement document attribute",
"operationId": "databasesDecrementDocumentAttribute",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"databases"
],
"description": "Decrement a specific attribute of a document by a given value.",
"responses": {
"200": {
"description": "Document",
"schema": {
"$ref": "#\/definitions\/document"
}
}
},
"x-appwrite": {
"method": "decrementDocumentAttribute",
"group": "documents",
"weight": 116,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "databases\/decrement-document-attribute.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/decrement-document-attribute.md",
"rate-limit": 120,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "documents.write",
"platforms": [
"console",
"server",
"client",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "databaseId",
"description": "Database ID.",
"required": true,
"type": "string",
"x-example": "<DATABASE_ID>",
"in": "path"
},
{
"name": "collectionId",
"description": "Collection ID.",
"required": true,
"type": "string",
"x-example": "<COLLECTION_ID>",
"in": "path"
},
{
"name": "documentId",
"description": "Document ID.",
"required": true,
"type": "string",
"x-example": "<DOCUMENT_ID>",
"in": "path"
},
{
"name": "attribute",
"description": "Attribute key.",
"required": true,
"type": "string",
"in": "path"
},
{
"name": "payload",
"in": "body",
"schema": {
"type": "object",
"properties": {
"value": {
"type": "number",
"description": "Value to decrement the attribute by. The value must be a number.",
"default": 1,
"x-example": null
},
"min": {
"type": "number",
"description": "Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown.",
"default": null,
"x-example": null
}
}
}
}
]
}
},
"\/databases\/{databaseId}\/collections\/{collectionId}\/documents\/{documentId}\/{attribute}\/increment": {
"patch": {
"summary": "Increment document attribute",
"operationId": "databasesIncrementDocumentAttribute",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"databases"
],
"description": "Increment a specific attribute of a document by a given value.",
"responses": {
"200": {
"description": "Document",
"schema": {
"$ref": "#\/definitions\/document"
}
}
},
"x-appwrite": {
"method": "incrementDocumentAttribute",
"group": "documents",
"weight": 115,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "databases\/increment-document-attribute.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/databases\/increment-document-attribute.md",
"rate-limit": 120,
"rate-time": 60,
"rate-key": "ip:{ip},method:{method},url:{url},userId:{userId}",
"scope": "documents.write",
"platforms": [
"console",
"server",
"client",
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Session": [],
"JWT": []
}
],
"parameters": [
{
"name": "databaseId",
"description": "Database ID.",
"required": true,
"type": "string",
"x-example": "<DATABASE_ID>",
"in": "path"
},
{
"name": "collectionId",
"description": "Collection ID.",
"required": true,
"type": "string",
"x-example": "<COLLECTION_ID>",
"in": "path"
},
{
"name": "documentId",
"description": "Document ID.",
"required": true,
"type": "string",
"x-example": "<DOCUMENT_ID>",
"in": "path"
},
{
"name": "attribute",
"description": "Attribute key.",
"required": true,
"type": "string",
"in": "path"
},
{
"name": "payload",
"in": "body",
"schema": {
"type": "object",
"properties": {
"value": {
"type": "number",
"description": "Value to increment the attribute by. The value must be a number.",
"default": 1,
"x-example": null
},
"max": {
"type": "number",
"description": "Maximum value for the attribute. If the current value is greater than this value, an error will be thrown.",
"default": null,
"x-example": null
}
}
}
}
]
}
},
"\/functions\/{functionId}\/executions": {
"get": {
"summary": "List executions",
@@ -4990,7 +5344,7 @@
"x-appwrite": {
"method": "listExecutions",
"group": "executions",
"weight": 391,
"weight": 394,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5064,7 +5418,7 @@
"x-appwrite": {
"method": "createExecution",
"group": "executions",
"weight": 389,
"weight": 392,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5181,7 +5535,7 @@
"x-appwrite": {
"method": "getExecution",
"group": "executions",
"weight": 390,
"weight": 393,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5253,7 +5607,7 @@
"x-appwrite": {
"method": "query",
"group": "graphql",
"weight": 305,
"weight": 308,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -5327,7 +5681,7 @@
"x-appwrite": {
"method": "mutation",
"group": "graphql",
"weight": 304,
"weight": 307,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -5399,7 +5753,7 @@
"x-appwrite": {
"method": "get",
"group": null,
"weight": 121,
"weight": 124,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5451,7 +5805,7 @@
"x-appwrite": {
"method": "listCodes",
"group": null,
"weight": 122,
"weight": 125,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5503,7 +5857,7 @@
"x-appwrite": {
"method": "listContinents",
"group": null,
"weight": 126,
"weight": 129,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5555,7 +5909,7 @@
"x-appwrite": {
"method": "listCountries",
"group": null,
"weight": 123,
"weight": 126,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5607,7 +5961,7 @@
"x-appwrite": {
"method": "listCountriesEU",
"group": null,
"weight": 124,
"weight": 127,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5659,7 +6013,7 @@
"x-appwrite": {
"method": "listCountriesPhones",
"group": null,
"weight": 125,
"weight": 128,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5711,7 +6065,7 @@
"x-appwrite": {
"method": "listCurrencies",
"group": null,
"weight": 127,
"weight": 130,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5763,7 +6117,7 @@
"x-appwrite": {
"method": "listLanguages",
"group": null,
"weight": 128,
"weight": 131,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5817,7 +6171,7 @@
"x-appwrite": {
"method": "createSubscriber",
"group": "subscribers",
"weight": 351,
"weight": 354,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5902,7 +6256,7 @@
"x-appwrite": {
"method": "deleteSubscriber",
"group": "subscribers",
"weight": 355,
"weight": 358,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5973,7 +6327,7 @@
"x-appwrite": {
"method": "listFiles",
"group": "files",
"weight": 211,
"weight": 214,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6056,7 +6410,7 @@
"x-appwrite": {
"method": "createFile",
"group": "files",
"weight": 210,
"weight": 213,
"cookies": false,
"type": "upload",
"deprecated": false,
@@ -6146,7 +6500,7 @@
"x-appwrite": {
"method": "getFile",
"group": "files",
"weight": 212,
"weight": 215,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6216,7 +6570,7 @@
"x-appwrite": {
"method": "updateFile",
"group": "files",
"weight": 217,
"weight": 220,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6305,7 +6659,7 @@
"x-appwrite": {
"method": "deleteFile",
"group": "files",
"weight": 218,
"weight": 221,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6375,7 +6729,7 @@
"x-appwrite": {
"method": "getFileDownload",
"group": "files",
"weight": 214,
"weight": 217,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6454,7 +6808,7 @@
"x-appwrite": {
"method": "getFilePreview",
"group": "files",
"weight": 213,
"weight": 216,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6618,7 +6972,8 @@
"png",
"webp",
"heic",
"avif"
"avif",
"gif"
],
"x-enum-name": "ImageFormat",
"x-enum-keys": [],
@@ -6660,7 +7015,7 @@
"x-appwrite": {
"method": "getFileView",
"group": "files",
"weight": 215,
"weight": 218,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6739,7 +7094,7 @@
"x-appwrite": {
"method": "list",
"group": "teams",
"weight": 222,
"weight": 225,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6814,7 +7169,7 @@
"x-appwrite": {
"method": "create",
"group": "teams",
"weight": 221,
"weight": 224,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6904,7 +7259,7 @@
"x-appwrite": {
"method": "get",
"group": "teams",
"weight": 223,
"weight": 226,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6966,7 +7321,7 @@
"x-appwrite": {
"method": "updateName",
"group": "teams",
"weight": 225,
"weight": 228,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7041,7 +7396,7 @@
"x-appwrite": {
"method": "delete",
"group": "teams",
"weight": 227,
"weight": 230,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7103,7 +7458,7 @@
"x-appwrite": {
"method": "listMemberships",
"group": "memberships",
"weight": 229,
"weight": 232,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7186,7 +7541,7 @@
"x-appwrite": {
"method": "createMembership",
"group": "memberships",
"weight": 228,
"weight": 231,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7299,7 +7654,7 @@
"x-appwrite": {
"method": "getMembership",
"group": "memberships",
"weight": 230,
"weight": 233,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7369,7 +7724,7 @@
"x-appwrite": {
"method": "updateMembership",
"group": "memberships",
"weight": 231,
"weight": 234,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7455,7 +7810,7 @@
"x-appwrite": {
"method": "deleteMembership",
"group": "memberships",
"weight": 233,
"weight": 236,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7527,7 +7882,7 @@
"x-appwrite": {
"method": "updateMembershipStatus",
"group": "memberships",
"weight": 232,
"weight": 235,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7621,7 +7976,7 @@
"x-appwrite": {
"method": "getPrefs",
"group": "teams",
"weight": 224,
"weight": 227,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7682,7 +8037,7 @@
"x-appwrite": {
"method": "updatePrefs",
"group": "teams",
"weight": 226,
"weight": 229,
"cookies": false,
"type": "",
"deprecated": false,
@@ -8174,6 +8529,12 @@
"description": "Document ID.",
"x-example": "5e5ea5c16897e"
},
"$sequence": {
"type": "integer",
"description": "Document automatically incrementing ID.",
"x-example": 1,
"format": "int32"
},
"$collectionId": {
"type": "string",
"description": "Collection ID.",
@@ -8208,6 +8569,7 @@
"additionalProperties": true,
"required": [
"$id",
"$sequence",
"$collectionId",
"$databaseId",
"$createdAt",
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1
View File
@@ -7,4 +7,5 @@ return [
"png" => "image/png",
"heic" => "image/heic",
"webp" => "image/webp",
"gif" => "image/gif",
];
+1
View File
@@ -8,4 +8,5 @@ return [
"webp" => "image/webp",
"heic" => "image/heic",
"avif" => "image/avif",
"gif" => "image/gif",
];
+6
View File
@@ -0,0 +1,6 @@
<?php
use Utopia\Image\Image;
use Utopia\System\System;
Image::setResourceLimit('memory', intval(System::getEnv('_APP_IMAGES_RESOURCE_LIMIT_MEMORY', 1024*1024*64)));
+2 -2
View File
@@ -14,7 +14,7 @@ return [
],
'DART' => [
'name' => 'dart',
'versions' => ['3.5', '3.3', '3.1', '3.0', '2.19', '2.18', '2.17', '2.16']
'versions' => ['3.8', '3.5', '3.3', '3.1', '3.0', '2.19', '2.18', '2.17', '2.16']
],
'GO' => [
'name' => 'go',
@@ -38,6 +38,6 @@ return [
],
'FLUTTER' => [
'name' => 'flutter',
'versions' => ['3.24']
'versions' => ['3.32', '3.24']
],
];
+19
View File
@@ -1351,4 +1351,23 @@ return [
'providerVersion' => '0.3.*',
'variables' => [],
],
[
'key' => 'gallery-for-lynx',
'name' => 'Lynx gallery',
'tagline' => 'A Lynx website showcasing gallery with smooth animations.',
'score' => 1, // 0 to 10 based on looks of screenshot (avoid 1,2,3,8,9,10 if possible)
'useCases' => [UseCases::STARTER],
'screenshotDark' => $url . '/images/sites/templates/gallery-for-lynx-dark.png',
'screenshotLight' => $url . '/images/sites/templates/gallery-for-lynx-light.png',
'frameworks' => [
getFramework('LYNX', [
'providerRootDirectory' => './lynx/gallery',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.3.*',
'variables' => []
],
];
+9
View File
@@ -106,6 +106,15 @@ return [
'question' => '',
'filter' => ''
],
[
'name' => '_APP_DOMAIN_SITES',
'description' => 'A domain to use for site preview URLs.',
'introduction' => '',
'default' => 'sites.localhost',
'required' => false,
'question' => '',
'filter' => ''
],
[
'name' => '_APP_DOMAIN_TARGET',
'description' => 'Deprecated since 1.7.0. A DNS A record hostname to serve as a CNAME target for your Appwrite custom domains. You can use the same value as used for the Appwrite \'_APP_DOMAIN\' variable. The default value is \'localhost\'.',
+38 -38
View File
@@ -190,7 +190,7 @@ $createSession = function (string $userId, string $secret, Request $request, Res
[
'$id' => ID::unique(),
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'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'),
@@ -387,7 +387,7 @@ App::post('/v1/account')
'search' => implode(' ', [$userId, $email, $name]),
'accessedAt' => DateTime::now(),
]);
$user->removeAttribute('$internalId');
$user->removeAttribute('$sequence');
$user = Authorization::skip(fn () => $dbForProject->createDocument('users', $user));
try {
$target = Authorization::skip(fn () => $dbForProject->createDocument('targets', new Document([
@@ -397,7 +397,7 @@ App::post('/v1/account')
Permission::delete(Role::user($user->getId())),
],
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'userInternalId' => $user->getSequence(),
'providerType' => MESSAGE_TYPE_EMAIL,
'identifier' => $email,
])));
@@ -907,7 +907,7 @@ App::post('/v1/account/sessions/email')
[
'$id' => ID::unique(),
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'userInternalId' => $user->getSequence(),
'provider' => Auth::SESSION_PROVIDER_EMAIL,
'providerUid' => $email,
'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak
@@ -1056,7 +1056,7 @@ App::post('/v1/account/sessions/anonymous')
'search' => $userId,
'accessedAt' => DateTime::now(),
]);
$user->removeAttribute('$internalId');
$user->removeAttribute('$sequence');
Authorization::skip(fn () => $dbForProject->createDocument('users', $user));
// Create session token
@@ -1069,7 +1069,7 @@ App::post('/v1/account/sessions/anonymous')
[
'$id' => ID::unique(),
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'userInternalId' => $user->getSequence(),
'provider' => Auth::SESSION_PROVIDER_ANONYMOUS,
'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak
'userAgent' => $request->getUserAgent('UNKNOWN'),
@@ -1440,7 +1440,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
$identityWithMatchingEmail = $dbForProject->findOne('identities', [
Query::equal('providerEmail', [$email]),
Query::notEqual('userInternalId', $user->getInternalId()),
Query::notEqual('userInternalId', $user->getSequence()),
]);
if (!$identityWithMatchingEmail->isEmpty()) {
$failureRedirect(Exception::USER_ALREADY_EXISTS);
@@ -1554,7 +1554,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
'search' => implode(' ', [$userId, $email, $name]),
'accessedAt' => DateTime::now(),
]);
$user->removeAttribute('$internalId');
$user->removeAttribute('$sequence');
$userDoc = Authorization::skip(fn () => $dbForProject->createDocument('users', $user));
$dbForProject->createDocument('targets', new Document([
'$permissions' => [
@@ -1563,7 +1563,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
Permission::delete(Role::user($user->getId())),
],
'userId' => $userDoc->getId(),
'userInternalId' => $userDoc->getInternalId(),
'userInternalId' => $userDoc->getSequence(),
'providerType' => MESSAGE_TYPE_EMAIL,
'identifier' => $email,
]));
@@ -1582,7 +1582,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
}
$identity = $dbForProject->findOne('identities', [
Query::equal('userInternalId', [$user->getInternalId()]),
Query::equal('userInternalId', [$user->getSequence()]),
Query::equal('provider', [$provider]),
Query::equal('providerUid', [$oauth2ID]),
]);
@@ -1592,7 +1592,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
$identitiesWithMatchingEmail = $dbForProject->find('identities', [
Query::equal('providerEmail', [$email]),
Query::notEqual('userInternalId', $user->getInternalId()),
Query::notEqual('userInternalId', $user->getSequence()),
]);
if (!empty($identitiesWithMatchingEmail)) {
$failureRedirect(Exception::GENERAL_BAD_REQUEST); /** Return a generic bad request to prevent exposing existing accounts */
@@ -1605,7 +1605,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
Permission::update(Role::user($userId)),
Permission::delete(Role::user($userId)),
],
'userInternalId' => $user->getInternalId(),
'userInternalId' => $user->getSequence(),
'userId' => $userId,
'provider' => $provider,
'providerUid' => $oauth2ID,
@@ -1648,7 +1648,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
$token = new Document([
'$id' => ID::unique(),
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'userInternalId' => $user->getSequence(),
'type' => Auth::TOKEN_TYPE_OAUTH2,
'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak
'expire' => $expire,
@@ -1683,7 +1683,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
$session = new Document(array_merge([
'$id' => ID::unique(),
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'userInternalId' => $user->getSequence(),
'provider' => $provider,
'providerUid' => $oauth2ID,
'providerAccessToken' => $accessToken,
@@ -1736,7 +1736,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
$target
->setAttribute('sessionId', $session->getId())
->setAttribute('sessionInternalId', $session->getInternalId());
->setAttribute('sessionInternalId', $session->getSequence());
$dbForProject->updateDocument('targets', $target->getId(), $target);
}
@@ -1931,7 +1931,7 @@ App::post('/v1/account/tokens/magic-url')
'accessedAt' => DateTime::now(),
]);
$user->removeAttribute('$internalId');
$user->removeAttribute('$sequence');
Authorization::skip(fn () => $dbForProject->createDocument('users', $user));
}
@@ -1941,7 +1941,7 @@ App::post('/v1/account/tokens/magic-url')
$token = new Document([
'$id' => ID::unique(),
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'userInternalId' => $user->getSequence(),
'type' => Auth::TOKEN_TYPE_MAGIC_URL,
'secret' => Auth::hash($tokenSecret), // One way hash encryption to protect DB leak
'expire' => $expire,
@@ -2168,7 +2168,7 @@ App::post('/v1/account/tokens/email')
'accessedAt' => DateTime::now(),
]);
$user->removeAttribute('$internalId');
$user->removeAttribute('$sequence');
Authorization::skip(fn () => $dbForProject->createDocument('users', $user));
}
@@ -2178,7 +2178,7 @@ App::post('/v1/account/tokens/email')
$token = new Document([
'$id' => ID::unique(),
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'userInternalId' => $user->getSequence(),
'type' => Auth::TOKEN_TYPE_EMAIL,
'secret' => Auth::hash($tokenSecret), // One way hash encryption to protect DB leak
'expire' => $expire,
@@ -2460,7 +2460,7 @@ App::post('/v1/account/tokens/phone')
'accessedAt' => DateTime::now(),
]);
$user->removeAttribute('$internalId');
$user->removeAttribute('$sequence');
Authorization::skip(fn () => $dbForProject->createDocument('users', $user));
try {
$target = Authorization::skip(fn () => $dbForProject->createDocument('targets', new Document([
@@ -2470,7 +2470,7 @@ App::post('/v1/account/tokens/phone')
Permission::delete(Role::user($user->getId())),
],
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'userInternalId' => $user->getSequence(),
'providerType' => MESSAGE_TYPE_SMS,
'identifier' => $phone,
])));
@@ -2501,7 +2501,7 @@ App::post('/v1/account/tokens/phone')
$token = new Document([
'$id' => ID::unique(),
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'userInternalId' => $user->getSequence(),
'type' => Auth::TOKEN_TYPE_PHONE,
'secret' => Auth::hash($secret),
'expire' => $expire,
@@ -2703,7 +2703,7 @@ App::get('/v1/account/logs')
$audit = new EventAudit($dbForProject);
$logs = $audit->getLogsByUser($user->getInternalId(), $queries);
$logs = $audit->getLogsByUser($user->getSequence(), $queries);
$output = [];
@@ -2732,7 +2732,7 @@ App::get('/v1/account/logs')
}
$response->dynamic(new Document([
'total' => $audit->countLogsByUser($user->getInternalId(), $queries),
'total' => $audit->countLogsByUser($user->getSequence(), $queries),
'logs' => $output,
]), Response::MODEL_LOG_LIST);
});
@@ -2900,7 +2900,7 @@ App::patch('/v1/account/email')
// Makes sure this email is not already used in another identity
$identityWithMatchingEmail = $dbForProject->findOne('identities', [
Query::equal('providerEmail', [$email]),
Query::notEqual('userInternalId', $user->getInternalId()),
Query::notEqual('userInternalId', $user->getSequence()),
]);
if (!$identityWithMatchingEmail->isEmpty()) {
throw new Exception(Exception::GENERAL_BAD_REQUEST); /** Return a generic bad request to prevent exposing existing accounts */
@@ -3183,7 +3183,7 @@ App::post('/v1/account/recovery')
$recovery = new Document([
'$id' => ID::unique(),
'userId' => $profile->getId(),
'userInternalId' => $profile->getInternalId(),
'userInternalId' => $profile->getSequence(),
'type' => Auth::TOKEN_TYPE_RECOVERY,
'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak
'expire' => $expire,
@@ -3438,7 +3438,7 @@ App::post('/v1/account/verification')
$verification = new Document([
'$id' => ID::unique(),
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'userInternalId' => $user->getSequence(),
'type' => Auth::TOKEN_TYPE_VERIFICATION,
'secret' => Auth::hash($verificationSecret), // One way hash encryption to protect DB leak
'expire' => $expire,
@@ -3685,7 +3685,7 @@ App::post('/v1/account/verification/phone')
$verification = new Document([
'$id' => ID::unique(),
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'userInternalId' => $user->getSequence(),
'type' => Auth::TOKEN_TYPE_PHONE,
'secret' => Auth::hash($secret),
'expire' => $expire,
@@ -3880,7 +3880,7 @@ App::patch('/v1/account/mfa')
if ($user->getAttribute('phone', false) && $user->getAttribute('phoneVerification', false)) {
$factors[] = Type::PHONE;
}
$factors = \array_unique($factors);
$factors = \array_values(\array_unique($factors));
$session->setAttribute('factors', $factors);
$dbForProject->updateDocument('sessions', $session->getId(), $session);
@@ -3979,7 +3979,7 @@ App::post('/v1/account/mfa/authenticators/:type')
$authenticator = new Document([
'$id' => ID::unique(),
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'userInternalId' => $user->getSequence(),
'type' => Type::TOTP,
'verified' => false,
'data' => [
@@ -4065,7 +4065,7 @@ App::put('/v1/account/mfa/authenticators/:type')
$factors = $session->getAttribute('factors', []);
$factors[] = $type;
$factors = \array_unique($factors);
$factors = \array_values(\array_unique($factors));
$session->setAttribute('factors', $factors);
$dbForProject->updateDocument('sessions', $session->getId(), $session);
@@ -4292,7 +4292,7 @@ App::post('/v1/account/mfa/challenge')
$code = Auth::codeGenerator();
$challenge = new Document([
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'userInternalId' => $user->getSequence(),
'type' => $factor,
'token' => Auth::tokenGenerator(),
'code' => $code,
@@ -4549,7 +4549,7 @@ App::put('/v1/account/mfa/challenge')
$factors = $session->getAttribute('factors', []);
$factors[] = $type;
$factors = \array_unique($factors);
$factors = \array_values(\array_unique($factors));
$session
->setAttribute('factors', $factors)
@@ -4621,12 +4621,12 @@ App::post('/v1/account/targets/push')
Permission::delete(Role::user($user->getId())),
],
'providerId' => !empty($providerId) ? $providerId : null,
'providerInternalId' => !empty($providerId) ? $provider->getInternalId() : null,
'providerInternalId' => !empty($providerId) ? $provider->getSequence() : null,
'providerType' => MESSAGE_TYPE_PUSH,
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'userInternalId' => $user->getSequence(),
'sessionId' => $session->getId(),
'sessionInternalId' => $session->getInternalId(),
'sessionInternalId' => $session->getSequence(),
'identifier' => $identifier,
'name' => "{$device['deviceBrand']} {$device['deviceModel']}"
]));
@@ -4745,7 +4745,7 @@ App::delete('/v1/account/targets/:targetId/push')
throw new Exception(Exception::USER_TARGET_NOT_FOUND);
}
if ($user->getInternalId() !== $target->getAttribute('userInternalId')) {
if ($user->getSequence() !== $target->getAttribute('userInternalId')) {
throw new Exception(Exception::USER_TARGET_NOT_FOUND);
}
@@ -4794,7 +4794,7 @@ App::get('/v1/account/identities')
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
}
$queries[] = Query::equal('userInternalId', [$user->getInternalId()]);
$queries[] = Query::equal('userInternalId', [$user->getSequence()]);
/**
* Get cursor document if there was a cursor query, we use array_filter and reset for reference $cursor to $queries
+6 -6
View File
@@ -669,7 +669,7 @@ App::get('/v1/cards/cloud')
}
}
$isPlatinum = $user->getInternalId() % 100 === 0;
$isPlatinum = $user->getSequence() % 100 === 0;
} else {
$name = $mock === 'normal-long' ? 'Sir First Walter O\'Brian Junior' : 'Walter O\'Brian';
$createdAt = new \DateTime('now');
@@ -859,7 +859,7 @@ App::get('/v1/cards/cloud-back')
$isEmployee = \array_key_exists($email, $employees);
$isGolden = $isEmployee || $isHero || $isContributor;
$isPlatinum = $user->getInternalId() % 100 === 0;
$isPlatinum = $user->getSequence() % 100 === 0;
} else {
$userId = '63e0bcf3c3eb803ba530';
@@ -926,9 +926,9 @@ App::get('/v1/cards/cloud-og')
}
if (!$mock) {
$internalId = $user->getInternalId();
$bgVariation = $internalId % 3 === 0 ? '1' : ($internalId % 3 === 1 ? '2' : '3');
$cardVariation = $internalId % 3 === 0 ? '1' : ($internalId % 3 === 1 ? '2' : '3');
$sequence = $user->getSequence();
$bgVariation = $sequence % 3 === 0 ? '1' : ($sequence % 3 === 1 ? '2' : '3');
$cardVariation = $sequence % 3 === 0 ? '1' : ($sequence % 3 === 1 ? '2' : '3');
$name = $user->getAttribute('name', 'Anonymous');
$email = $user->getAttribute('email', '');
@@ -958,7 +958,7 @@ App::get('/v1/cards/cloud-og')
}
}
$isPlatinum = $user->getInternalId() % 100 === 0;
$isPlatinum = $user->getSequence() % 100 === 0;
} else {
$bgVariation = \str_ends_with($mock, '-bg2') ? '2' : (\str_ends_with($mock, '-bg3') ? '3' : '1');
$cardVariation = \str_ends_with($mock, '-right') ? '2' : (\str_ends_with($mock, '-middle') ? '3' : '1');
File diff suppressed because it is too large Load Diff
+71 -75
View File
@@ -3,13 +3,16 @@
use Appwrite\ClamAV\Network;
use Appwrite\Event\Event;
use Appwrite\Extend\Exception;
use Appwrite\PubSub\Adapter\Pool as PubSubPool;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\App;
use Utopia\Cache\Adapter\Pool as CachePool;
use Utopia\Config\Config;
use Utopia\Database\Adapter\Pool as DatabasePool;
use Utopia\Database\Document;
use Utopia\Domains\Validator\PublicDomain;
use Utopia\Pools\Group;
@@ -34,8 +37,8 @@ App::get('/v1/health')
namespace: 'health',
group: 'health',
name: 'get',
auth: [AuthType::KEY],
description: '/docs/references/health/get.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
@@ -70,11 +73,11 @@ App::get('/v1/health/db')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk', new Method(
auth: [AuthType::KEY],
namespace: 'health',
group: 'health',
name: 'getDB',
description: '/docs/references/health/get-db.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
@@ -86,8 +89,8 @@ App::get('/v1/health/db')
->inject('response')
->inject('pools')
->action(function (Response $response, Group $pools) {
$output = [];
$failures = [];
$configs = [
'Console.DB' => Config::getParam('pools-console'),
@@ -97,7 +100,7 @@ App::get('/v1/health/db')
foreach ($configs as $key => $config) {
foreach ($config as $database) {
try {
$adapter = $pools->get($database)->pop()->getResource();
$adapter = new DatabasePool($pools->get($database));
$checkStart = \microtime(true);
@@ -108,16 +111,16 @@ App::get('/v1/health/db')
'ping' => \round((\microtime(true) - $checkStart) / 1000)
]);
} else {
$failure[] = $database;
$failures[] = $database;
}
} catch (\Throwable $th) {
$failure[] = $database;
} catch (\Throwable) {
$failures[] = $database;
}
}
}
if (!empty($failure)) {
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'DB failure on: ' . implode(", ", $failure));
if (!empty($failures)) {
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'DB failure on: ' . implode(", ", $failures));
}
$response->dynamic(new Document([
@@ -131,11 +134,11 @@ App::get('/v1/health/cache')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk', new Method(
auth: [AuthType::KEY],
namespace: 'health',
group: 'health',
name: 'getCache',
description: '/docs/references/health/get-cache.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
@@ -147,44 +150,39 @@ App::get('/v1/health/cache')
->inject('response')
->inject('pools')
->action(function (Response $response, Group $pools) {
$output = [];
$failures = [];
$configs = [
'Cache' => Config::getParam('pools-cache'),
];
foreach ($configs as $key => $config) {
foreach ($config as $database) {
foreach ($config as $cache) {
try {
/** @var \Utopia\Cache\Adapter $adapter */
$adapter = $pools->get($database)->pop()->getResource();
$adapter = new CachePool($pools->get($cache));
$checkStart = \microtime(true);
if ($adapter->ping()) {
$output[] = new Document([
'name' => $key . " ($database)",
'name' => $key . " ($cache)",
'status' => 'pass',
'ping' => \round((\microtime(true) - $checkStart) / 1000)
]);
} else {
$output[] = new Document([
'name' => $key . " ($database)",
'status' => 'fail',
'ping' => \round((\microtime(true) - $checkStart) / 1000)
]);
$failures[] = $cache;
}
} catch (\Throwable $th) {
$output[] = new Document([
'name' => $key . " ($database)",
'status' => 'fail',
'ping' => \round((\microtime(true) - $checkStart) / 1000)
]);
} catch (\Throwable) {
$failures[] = $cache;
}
}
}
if (!empty($failures)) {
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Cache failure on: ' . implode(", ", $failures));
}
$response->dynamic(new Document([
'statuses' => $output,
'total' => count($output),
@@ -196,11 +194,11 @@ App::get('/v1/health/pubsub')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk', new Method(
auth: [AuthType::KEY],
namespace: 'health',
group: 'health',
name: 'getPubSub',
description: '/docs/references/health/get-pubsub.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
@@ -212,44 +210,39 @@ App::get('/v1/health/pubsub')
->inject('response')
->inject('pools')
->action(function (Response $response, Group $pools) {
$output = [];
$failures = [];
$configs = [
'PubSub' => Config::getParam('pools-pubsub'),
];
foreach ($configs as $key => $config) {
foreach ($config as $database) {
foreach ($config as $pubsub) {
try {
/** @var \Appwrite\PubSub\Adapter $adapter */
$adapter = $pools->get($database)->pop()->getResource();
$adapter = new PubSubPool($pools->get($pubsub));
$checkStart = \microtime(true);
if ($adapter->ping()) {
$output[] = new Document([
'name' => $key . " ($database)",
'name' => $key . " ($pubsub)",
'status' => 'pass',
'ping' => \round((\microtime(true) - $checkStart) / 1000)
]);
} else {
$output[] = new Document([
'name' => $key . " ($database)",
'status' => 'fail',
'ping' => \round((\microtime(true) - $checkStart) / 1000)
]);
$failures[] = $pubsub;
}
} catch (\Throwable $th) {
$output[] = new Document([
'name' => $key . " ($database)",
'status' => 'fail',
'ping' => \round((\microtime(true) - $checkStart) / 1000)
]);
} catch (\Throwable) {
$failures[] = $pubsub;
}
}
}
if (!empty($failures)) {
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Pubsub failure on: ' . implode(", ", $failures));
}
$response->dynamic(new Document([
'statuses' => $output,
'total' => count($output),
@@ -261,11 +254,11 @@ App::get('/v1/health/time')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk', new Method(
auth: [AuthType::KEY],
namespace: 'health',
group: 'health',
name: 'getTime',
description: '/docs/references/health/get-time.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
@@ -325,11 +318,11 @@ App::get('/v1/health/queue/webhooks')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk', new Method(
auth: [AuthType::KEY],
namespace: 'health',
group: 'queue',
name: 'getQueueWebhooks',
description: '/docs/references/health/get-queue-webhooks.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
@@ -351,18 +344,18 @@ App::get('/v1/health/queue/webhooks')
}
$response->dynamic(new Document([ 'size' => $size ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']);
});
App::get('/v1/health/queue/logs')
->desc('Get logs queue')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk', new Method(
auth: [AuthType::KEY],
namespace: 'health',
group: 'queue',
name: 'getQueueLogs',
description: '/docs/references/health/get-queue-logs.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
@@ -384,18 +377,18 @@ App::get('/v1/health/queue/logs')
}
$response->dynamic(new Document([ 'size' => $size ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']);
});
App::get('/v1/health/certificate')
->desc('Get the SSL certificate for a domain')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk', new Method(
auth: [AuthType::KEY],
namespace: 'health',
group: 'health',
name: 'getCertificate',
description: '/docs/references/health/get-certificate.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
@@ -441,18 +434,18 @@ App::get('/v1/health/certificate')
'validTo' => $certificatePayload['validTo_time_t'],
'signatureTypeSN' => $certificatePayload['signatureTypeSN'],
]), Response::MODEL_HEALTH_CERTIFICATE);
}, ['response']);
});
App::get('/v1/health/queue/certificates')
->desc('Get certificates queue')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk', new Method(
auth: [AuthType::KEY],
namespace: 'health',
group: 'queue',
name: 'getQueueCertificates',
description: '/docs/references/health/get-queue-certificates.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
@@ -474,18 +467,18 @@ App::get('/v1/health/queue/certificates')
}
$response->dynamic(new Document([ 'size' => $size ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']);
});
App::get('/v1/health/queue/builds')
->desc('Get builds queue')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk', new Method(
auth: [AuthType::KEY],
namespace: 'health',
group: 'queue',
name: 'getQueueBuilds',
description: '/docs/references/health/get-queue-builds.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
@@ -507,18 +500,18 @@ App::get('/v1/health/queue/builds')
}
$response->dynamic(new Document([ 'size' => $size ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']);
});
App::get('/v1/health/queue/databases')
->desc('Get databases queue')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk', new Method(
auth: [AuthType::KEY],
namespace: 'health',
group: 'queue',
name: 'getQueueDatabases',
description: '/docs/references/health/get-queue-databases.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
@@ -541,18 +534,18 @@ App::get('/v1/health/queue/databases')
}
$response->dynamic(new Document([ 'size' => $size ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']);
});
App::get('/v1/health/queue/deletes')
->desc('Get deletes queue')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk', new Method(
auth: [AuthType::KEY],
namespace: 'health',
group: 'queue',
name: 'getQueueDeletes',
description: '/docs/references/health/get-queue-deletes.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
@@ -574,18 +567,18 @@ App::get('/v1/health/queue/deletes')
}
$response->dynamic(new Document([ 'size' => $size ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']);
});
App::get('/v1/health/queue/mails')
->desc('Get mails queue')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk', new Method(
auth: [AuthType::KEY],
namespace: 'health',
group: 'queue',
name: 'getQueueMails',
description: '/docs/references/health/get-queue-mails.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
@@ -607,18 +600,18 @@ App::get('/v1/health/queue/mails')
}
$response->dynamic(new Document([ 'size' => $size ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']);
});
App::get('/v1/health/queue/messaging')
->desc('Get messaging queue')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk', new Method(
auth: [AuthType::KEY],
namespace: 'health',
group: 'queue',
name: 'getQueueMessaging',
description: '/docs/references/health/get-queue-messaging.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
@@ -640,18 +633,18 @@ App::get('/v1/health/queue/messaging')
}
$response->dynamic(new Document([ 'size' => $size ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']);
});
App::get('/v1/health/queue/migrations')
->desc('Get migrations queue')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk', new Method(
auth: [AuthType::KEY],
namespace: 'health',
group: 'queue',
name: 'getQueueMigrations',
description: '/docs/references/health/get-queue-migrations.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
@@ -673,18 +666,18 @@ App::get('/v1/health/queue/migrations')
}
$response->dynamic(new Document([ 'size' => $size ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']);
});
App::get('/v1/health/queue/functions')
->desc('Get functions queue')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk', new Method(
auth: [AuthType::KEY],
namespace: 'health',
group: 'queue',
name: 'getQueueFunctions',
description: '/docs/references/health/get-queue-functions.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
@@ -706,18 +699,18 @@ App::get('/v1/health/queue/functions')
}
$response->dynamic(new Document([ 'size' => $size ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']);
});
App::get('/v1/health/queue/stats-resources')
->desc('Get stats resources queue')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk', new Method(
auth: [AuthType::KEY],
namespace: 'health',
group: 'queue',
name: 'getQueueStatsResources',
description: '/docs/references/health/get-queue-stats-resources.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
@@ -746,11 +739,11 @@ App::get('/v1/health/queue/stats-usage')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk', new Method(
auth: [AuthType::KEY],
namespace: 'health',
group: 'queue',
name: 'getQueueUsage',
description: '/docs/references/health/get-queue-stats-usage.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
@@ -779,11 +772,11 @@ App::get('/v1/health/storage/local')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk', new Method(
auth: [AuthType::KEY],
namespace: 'health',
group: 'storage',
name: 'getStorageLocal',
description: '/docs/references/health/get-storage-local.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
@@ -829,11 +822,11 @@ App::get('/v1/health/storage')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk', new Method(
auth: [AuthType::KEY],
namespace: 'health',
group: 'storage',
name: 'getStorage',
description: '/docs/references/health/get-storage.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
@@ -852,15 +845,18 @@ App::get('/v1/health/storage')
$checkStart = \microtime(true);
foreach ($devices as $device) {
if (!$device->write($device->getPath('health.txt'), 'test', 'text/plain')) {
$uniqueFileName = \uniqid('health', true);
$filePath = $device->getPath($uniqueFileName);
if (!$device->write($filePath, 'test', 'text/plain')) {
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed writing test file to ' . $device->getRoot());
}
if ($device->read($device->getPath('health.txt')) !== 'test') {
if ($device->read($filePath) !== 'test') {
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed reading test file from ' . $device->getRoot());
}
if (!$device->delete($device->getPath('health.txt'))) {
if (!$device->delete($filePath)) {
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed deleting test file from ' . $device->getRoot());
}
}
@@ -878,11 +874,11 @@ App::get('/v1/health/anti-virus')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk', new Method(
auth: [AuthType::KEY],
namespace: 'health',
group: 'health',
name: 'getAntivirus',
description: '/docs/references/health/get-storage-anti-virus.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
@@ -924,11 +920,11 @@ App::get('/v1/health/queue/failed/:name')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk', new Method(
auth: [AuthType::KEY],
namespace: 'health',
group: 'queue',
name: 'getFailedJobs',
description: '/docs/references/health/get-failed-queue-jobs.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
+14 -14
View File
@@ -2511,11 +2511,11 @@ App::post('/v1/messaging/topics/:topicId/subscribers')
Permission::delete(Role::user($user->getId())),
],
'topicId' => $topicId,
'topicInternalId' => $topic->getInternalId(),
'topicInternalId' => $topic->getSequence(),
'targetId' => $targetId,
'targetInternalId' => $target->getInternalId(),
'targetInternalId' => $target->getSequence(),
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'userInternalId' => $user->getSequence(),
'providerType' => $target->getAttribute('providerType'),
'search' => implode(' ', [
$subscriberId,
@@ -2597,7 +2597,7 @@ App::get('/v1/messaging/topics/:topicId/subscribers')
throw new Exception(Exception::TOPIC_NOT_FOUND);
}
$queries[] = Query::equal('topicInternalId', [$topic->getInternalId()]);
$queries[] = Query::equal('topicInternalId', [$topic->getSequence()]);
/**
* Get cursor document if there was a cursor query, we use array_filter and reset for reference $cursor to $queries
@@ -2947,7 +2947,7 @@ App::post('/v1/messaging/messages/email')
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
}
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
$file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId);
if ($file->isEmpty()) {
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
@@ -2989,7 +2989,7 @@ App::post('/v1/messaging/messages/email')
'region' => $project->getAttribute('region'),
'resourceType' => 'message',
'resourceId' => $message->getId(),
'resourceInternalId' => $message->getInternalId(),
'resourceInternalId' => $message->getSequence(),
'resourceUpdatedAt' => DateTime::now(),
'projectId' => $project->getId(),
'schedule' => $scheduledAt,
@@ -3112,7 +3112,7 @@ App::post('/v1/messaging/messages/sms')
'region' => $project->getAttribute('region'),
'resourceType' => 'message',
'resourceId' => $message->getId(),
'resourceInternalId' => $message->getInternalId(),
'resourceInternalId' => $message->getSequence(),
'resourceUpdatedAt' => DateTime::now(),
'projectId' => $project->getId(),
'schedule' => $scheduledAt,
@@ -3232,7 +3232,7 @@ App::post('/v1/messaging/messages/push')
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
}
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
$file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId);
if ($file->isEmpty()) {
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
}
@@ -3330,7 +3330,7 @@ App::post('/v1/messaging/messages/push')
'region' => $project->getAttribute('region'),
'resourceType' => 'message',
'resourceId' => $message->getId(),
'resourceInternalId' => $message->getInternalId(),
'resourceInternalId' => $message->getSequence(),
'resourceUpdatedAt' => DateTime::now(),
'projectId' => $project->getId(),
'schedule' => $scheduledAt,
@@ -3731,7 +3731,7 @@ App::patch('/v1/messaging/messages/email/:messageId')
'region' => $project->getAttribute('region'),
'resourceType' => 'message',
'resourceId' => $message->getId(),
'resourceInternalId' => $message->getInternalId(),
'resourceInternalId' => $message->getSequence(),
'resourceUpdatedAt' => DateTime::now(),
'projectId' => $project->getId(),
'schedule' => $scheduledAt,
@@ -3796,7 +3796,7 @@ App::patch('/v1/messaging/messages/email/:messageId')
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
}
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
$file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId);
if ($file->isEmpty()) {
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
@@ -3933,7 +3933,7 @@ App::patch('/v1/messaging/messages/sms/:messageId')
'region' => $project->getAttribute('region'),
'resourceType' => 'message',
'resourceId' => $message->getId(),
'resourceInternalId' => $message->getInternalId(),
'resourceInternalId' => $message->getSequence(),
'resourceUpdatedAt' => DateTime::now(),
'projectId' => $project->getId(),
'schedule' => $scheduledAt,
@@ -4107,7 +4107,7 @@ App::patch('/v1/messaging/messages/push/:messageId')
'region' => $project->getAttribute('region'),
'resourceType' => 'message',
'resourceId' => $message->getId(),
'resourceInternalId' => $message->getInternalId(),
'resourceInternalId' => $message->getSequence(),
'resourceUpdatedAt' => DateTime::now(),
'projectId' => $project->getId(),
'schedule' => $scheduledAt,
@@ -4210,7 +4210,7 @@ App::patch('/v1/messaging/messages/push/:messageId')
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
}
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
$file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId);
if ($file->isEmpty()) {
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
}
+1 -1
View File
@@ -345,7 +345,7 @@ App::post('/v1/migrations/csv')
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
}
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId));
if ($file->isEmpty()) {
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
}
+9 -9
View File
@@ -150,7 +150,7 @@ App::get('/v1/project/usage')
$executionsBreakdown = array_map(function ($function) use ($dbForProject) {
$id = $function->getId();
$name = $function->getAttribute('name');
$metric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getInternalId()], METRIC_RESOURCE_TYPE_ID_EXECUTIONS);
$metric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getSequence()], METRIC_RESOURCE_TYPE_ID_EXECUTIONS);
$value = $dbForProject->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
@@ -166,7 +166,7 @@ App::get('/v1/project/usage')
$executionsMbSecondsBreakdown = array_map(function ($function) use ($dbForProject) {
$id = $function->getId();
$name = $function->getAttribute('name');
$metric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getInternalId()], METRIC_RESOURCE_TYPE_ID_EXECUTIONS_MB_SECONDS);
$metric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getSequence()], METRIC_RESOURCE_TYPE_ID_EXECUTIONS_MB_SECONDS);
$value = $dbForProject->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
@@ -182,7 +182,7 @@ App::get('/v1/project/usage')
$buildsMbSecondsBreakdown = array_map(function ($function) use ($dbForProject) {
$id = $function->getId();
$name = $function->getAttribute('name');
$metric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getInternalId()], METRIC_RESOURCE_TYPE_ID_BUILDS_MB_SECONDS);
$metric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getSequence()], METRIC_RESOURCE_TYPE_ID_BUILDS_MB_SECONDS);
$value = $dbForProject->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
@@ -198,7 +198,7 @@ App::get('/v1/project/usage')
$bucketsBreakdown = array_map(function ($bucket) use ($dbForProject) {
$id = $bucket->getId();
$name = $bucket->getAttribute('name');
$metric = str_replace('{bucketInternalId}', $bucket->getInternalId(), METRIC_BUCKET_ID_FILES_STORAGE);
$metric = str_replace('{bucketInternalId}', $bucket->getSequence(), METRIC_BUCKET_ID_FILES_STORAGE);
$value = $dbForProject->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
@@ -214,7 +214,7 @@ App::get('/v1/project/usage')
$databasesStorageBreakdown = array_map(function ($database) use ($dbForProject) {
$id = $database->getId();
$name = $database->getAttribute('name');
$metric = str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_STORAGE);
$metric = str_replace('{databaseInternalId}', $database->getSequence(), METRIC_DATABASE_ID_STORAGE);
$value = $dbForProject->findOne('stats', [
Query::equal('metric', [$metric]),
@@ -231,13 +231,13 @@ App::get('/v1/project/usage')
$functionsStorageBreakdown = array_map(function ($function) use ($dbForProject) {
$id = $function->getId();
$name = $function->getAttribute('name');
$deploymentMetric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getInternalId()], METRIC_RESOURCE_TYPE_ID_DEPLOYMENTS_STORAGE);
$deploymentMetric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getSequence()], METRIC_RESOURCE_TYPE_ID_DEPLOYMENTS_STORAGE);
$deploymentValue = $dbForProject->findOne('stats', [
Query::equal('metric', [$deploymentMetric]),
Query::equal('period', ['inf'])
]);
$buildMetric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getInternalId()], METRIC_RESOURCE_TYPE_ID_BUILDS_STORAGE);
$buildMetric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getSequence()], METRIC_RESOURCE_TYPE_ID_BUILDS_STORAGE);
$buildValue = $dbForProject->findOne('stats', [
Query::equal('metric', [$buildMetric]),
Query::equal('period', ['inf'])
@@ -255,7 +255,7 @@ App::get('/v1/project/usage')
$executionsMbSecondsBreakdown = array_map(function ($function) use ($dbForProject) {
$id = $function->getId();
$name = $function->getAttribute('name');
$metric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getInternalId()], METRIC_RESOURCE_TYPE_ID_EXECUTIONS_MB_SECONDS);
$metric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getSequence()], METRIC_RESOURCE_TYPE_ID_EXECUTIONS_MB_SECONDS);
$value = $dbForProject->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
@@ -271,7 +271,7 @@ App::get('/v1/project/usage')
$buildsMbSecondsBreakdown = array_map(function ($function) use ($dbForProject) {
$id = $function->getId();
$name = $function->getAttribute('name');
$metric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getInternalId()], METRIC_RESOURCE_TYPE_ID_BUILDS_MB_SECONDS);
$metric = str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getSequence()], METRIC_RESOURCE_TYPE_ID_BUILDS_MB_SECONDS);
$value = $dbForProject->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
+25 -24
View File
@@ -24,6 +24,7 @@ use Utopia\App;
use Utopia\Audit\Audit;
use Utopia\Cache\Cache;
use Utopia\Config\Config;
use Utopia\Database\Adapter\Pool as DatabasePool;
use Utopia\Database\Database;
use Utopia\Database\DateTime;
use Utopia\Database\Document;
@@ -181,7 +182,7 @@ App::post('/v1/projects')
Permission::delete(Role::team(ID::custom($teamId), 'developer')),
],
'name' => $name,
'teamInternalId' => $team->getInternalId(),
'teamInternalId' => $team->getSequence(),
'teamId' => $team->getId(),
'region' => $region,
'description' => $description,
@@ -223,19 +224,19 @@ App::post('/v1/projects')
$sharedTables = $sharedTablesV1 || $sharedTablesV2;
if (!$sharedTablesV2) {
$adapter = $pools->get($dsn->getHost())->pop()->getResource();
$adapter = new DatabasePool($pools->get($dsn->getHost()));
$dbForProject = new Database($adapter, $cache);
if ($sharedTables) {
$dbForProject
->setSharedTables(true)
->setTenant($sharedTablesV1 ? $project->getInternalId() : null)
->setTenant($sharedTablesV1 ? $project->getSequence() : null)
->setNamespace($dsn->getParam('namespace'));
} else {
$dbForProject
->setSharedTables(false)
->setTenant(null)
->setNamespace('_' . $project->getInternalId());
->setNamespace('_' . $project->getSequence());
}
$create = true;
@@ -503,12 +504,12 @@ App::patch('/v1/projects/:projectId/team')
$project
->setAttribute('teamId', $teamId)
->setAttribute('teamInternalId', $team->getInternalId())
->setAttribute('teamInternalId', $team->getSequence())
->setAttribute('$permissions', $permissions);
$project = $dbForPlatform->updateDocument('projects', $project->getId(), $project);
$installations = $dbForPlatform->find('installations', [
Query::equal('projectInternalId', [$project->getInternalId()]),
Query::equal('projectInternalId', [$project->getSequence()]),
]);
foreach ($installations as $installation) {
$installation->getAttribute('$permissions', $permissions);
@@ -516,7 +517,7 @@ App::patch('/v1/projects/:projectId/team')
}
$repositories = $dbForPlatform->find('repositories', [
Query::equal('projectInternalId', [$project->getInternalId()]),
Query::equal('projectInternalId', [$project->getSequence()]),
]);
foreach ($repositories as $repository) {
$repository->getAttribute('$permissions', $permissions);
@@ -524,7 +525,7 @@ App::patch('/v1/projects/:projectId/team')
}
$vcsComments = $dbForPlatform->find('vcsComments', [
Query::equal('projectInternalId', [$project->getInternalId()]),
Query::equal('projectInternalId', [$project->getSequence()]),
]);
foreach ($vcsComments as $vcsComment) {
$vcsComment->getAttribute('$permissions', $permissions);
@@ -1228,7 +1229,7 @@ App::post('/v1/projects/:projectId/webhooks')
Permission::update(Role::any()),
Permission::delete(Role::any()),
],
'projectInternalId' => $project->getInternalId(),
'projectInternalId' => $project->getSequence(),
'projectId' => $project->getId(),
'name' => $name,
'events' => $events,
@@ -1278,7 +1279,7 @@ App::get('/v1/projects/:projectId/webhooks')
}
$webhooks = $dbForPlatform->find('webhooks', [
Query::equal('projectInternalId', [$project->getInternalId()]),
Query::equal('projectInternalId', [$project->getSequence()]),
Query::limit(5000),
]);
@@ -1319,7 +1320,7 @@ App::get('/v1/projects/:projectId/webhooks/:webhookId')
$webhook = $dbForPlatform->findOne('webhooks', [
Query::equal('$id', [$webhookId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
Query::equal('projectInternalId', [$project->getSequence()]),
]);
if ($webhook->isEmpty()) {
@@ -1369,7 +1370,7 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId')
$webhook = $dbForPlatform->findOne('webhooks', [
Query::equal('$id', [$webhookId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
Query::equal('projectInternalId', [$project->getSequence()]),
]);
if ($webhook->isEmpty()) {
@@ -1426,7 +1427,7 @@ App::patch('/v1/projects/:projectId/webhooks/:webhookId/signature')
$webhook = $dbForPlatform->findOne('webhooks', [
Query::equal('$id', [$webhookId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
Query::equal('projectInternalId', [$project->getSequence()]),
]);
if ($webhook->isEmpty()) {
@@ -1473,7 +1474,7 @@ App::delete('/v1/projects/:projectId/webhooks/:webhookId')
$webhook = $dbForPlatform->findOne('webhooks', [
Query::equal('$id', [$webhookId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
Query::equal('projectInternalId', [$project->getSequence()]),
]);
if ($webhook->isEmpty()) {
@@ -1527,7 +1528,7 @@ App::post('/v1/projects/:projectId/keys')
Permission::update(Role::any()),
Permission::delete(Role::any()),
],
'projectInternalId' => $project->getInternalId(),
'projectInternalId' => $project->getSequence(),
'projectId' => $project->getId(),
'name' => $name,
'scopes' => $scopes,
@@ -1575,7 +1576,7 @@ App::get('/v1/projects/:projectId/keys')
}
$keys = $dbForPlatform->find('keys', [
Query::equal('projectInternalId', [$project->getInternalId()]),
Query::equal('projectInternalId', [$project->getSequence()]),
Query::limit(5000),
]);
@@ -1616,7 +1617,7 @@ App::get('/v1/projects/:projectId/keys/:keyId')
$key = $dbForPlatform->findOne('keys', [
Query::equal('$id', [$keyId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
Query::equal('projectInternalId', [$project->getSequence()]),
]);
if ($key->isEmpty()) {
@@ -1660,7 +1661,7 @@ App::put('/v1/projects/:projectId/keys/:keyId')
$key = $dbForPlatform->findOne('keys', [
Query::equal('$id', [$keyId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
Query::equal('projectInternalId', [$project->getSequence()]),
]);
if ($key->isEmpty()) {
@@ -1711,7 +1712,7 @@ App::delete('/v1/projects/:projectId/keys/:keyId')
$key = $dbForPlatform->findOne('keys', [
Query::equal('$id', [$keyId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
Query::equal('projectInternalId', [$project->getSequence()]),
]);
if ($key->isEmpty()) {
@@ -1810,7 +1811,7 @@ App::post('/v1/projects/:projectId/platforms')
Permission::update(Role::any()),
Permission::delete(Role::any()),
],
'projectInternalId' => $project->getInternalId(),
'projectInternalId' => $project->getSequence(),
'projectId' => $project->getId(),
'type' => $type,
'name' => $name,
@@ -1857,7 +1858,7 @@ App::get('/v1/projects/:projectId/platforms')
}
$platforms = $dbForPlatform->find('platforms', [
Query::equal('projectInternalId', [$project->getInternalId()]),
Query::equal('projectInternalId', [$project->getSequence()]),
Query::limit(5000),
]);
@@ -1898,7 +1899,7 @@ App::get('/v1/projects/:projectId/platforms/:platformId')
$platform = $dbForPlatform->findOne('platforms', [
Query::equal('$id', [$platformId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
Query::equal('projectInternalId', [$project->getSequence()]),
]);
if ($platform->isEmpty()) {
@@ -1942,7 +1943,7 @@ App::put('/v1/projects/:projectId/platforms/:platformId')
$platform = $dbForPlatform->findOne('platforms', [
Query::equal('$id', [$platformId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
Query::equal('projectInternalId', [$project->getSequence()]),
]);
if ($platform->isEmpty()) {
@@ -1996,7 +1997,7 @@ App::delete('/v1/projects/:projectId/platforms/:platformId')
$platform = $dbForPlatform->findOne('platforms', [
Query::equal('$id', [$platformId]),
Query::equal('projectInternalId', [$project->getInternalId()]),
Query::equal('projectInternalId', [$project->getSequence()]),
]);
if ($platform->isEmpty()) {
+41 -9
View File
@@ -58,7 +58,7 @@ App::get('/v1/proxy/rules')
$queries[] = Query::search('search', $search);
}
$queries[] = Query::equal('projectInternalId', [$project->getInternalId()]);
$queries[] = Query::equal('projectInternalId', [$project->getSequence()]);
/**
* Get cursor document if there was a cursor query, we use array_filter and reset for reference $cursor to $queries
@@ -124,7 +124,7 @@ App::get('/v1/proxy/rules/:ruleId')
->action(function (string $ruleId, Response $response, Document $project, Database $dbForPlatform) {
$rule = $dbForPlatform->getDocument('rules', $ruleId);
if ($rule->isEmpty() || $rule->getAttribute('projectInternalId') !== $project->getInternalId()) {
if ($rule->isEmpty() || $rule->getAttribute('projectInternalId') !== $project->getSequence()) {
throw new Exception(Exception::RULE_NOT_FOUND);
}
@@ -165,7 +165,7 @@ App::delete('/v1/proxy/rules/:ruleId')
->action(function (string $ruleId, Response $response, Document $project, Database $dbForPlatform, Delete $queueForDeletes, Event $queueForEvents) {
$rule = $dbForPlatform->getDocument('rules', $ruleId);
if ($rule->isEmpty() || $rule->getAttribute('projectInternalId') !== $project->getInternalId()) {
if ($rule->isEmpty() || $rule->getAttribute('projectInternalId') !== $project->getSequence()) {
throw new Exception(Exception::RULE_NOT_FOUND);
}
@@ -210,15 +210,46 @@ App::patch('/v1/proxy/rules/:ruleId/verification')
->action(function (string $ruleId, Response $response, Certificate $queueForCertificates, Event $queueForEvents, Document $project, Database $dbForPlatform, Log $log) {
$rule = $dbForPlatform->getDocument('rules', $ruleId);
if ($rule->isEmpty() || $rule->getAttribute('projectInternalId') !== $project->getInternalId()) {
if ($rule->isEmpty() || $rule->getAttribute('projectInternalId') !== $project->getSequence()) {
throw new Exception(Exception::RULE_NOT_FOUND);
}
$validators = [];
$targetCNAME = new Domain(System::getEnv('_APP_DOMAIN_TARGET_CNAME', ''));
if ($targetCNAME->isKnown() && !$targetCNAME->isTest()) {
$validators[] = new DNS($targetCNAME->get(), DNS::RECORD_CNAME);
$targetCNAME = null;
switch ($rule->getAttribute('type', '')) {
case 'api':
// For example: fra.cloud.appwrite.io
$targetCNAME = new Domain(System::getEnv('_APP_DOMAIN_TARGET_CNAME', ''));
break;
case 'redirect':
// For example: appwrite.network
$targetCNAME = new Domain(System::getEnv('_APP_DOMAIN_SITES', ''));
break;
case 'deployment':
switch ($rule->getAttribute('deploymentResourceType', '')) {
case 'function':
// For example: fra.appwrite.run
$targetCNAME = new Domain(System::getEnv('_APP_DOMAIN_FUNCTIONS', ''));
break;
case 'site':
// For example: appwrite.network
$targetCNAME = new Domain(System::getEnv('_APP_DOMAIN_SITES', ''));
break;
default:
break;
}
// no break
default:
break;
}
$validators = [];
if (!is_null($targetCNAME)) {
if ($targetCNAME->isKnown() && !$targetCNAME->isTest()) {
$validators[] = new DNS($targetCNAME->get(), DNS::RECORD_CNAME);
}
}
if ((new IP(IP::V4))->isValid(System::getEnv('_APP_DOMAIN_TARGET_A', ''))) {
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_A', ''), DNS::RECORD_A);
}
@@ -260,7 +291,8 @@ App::patch('/v1/proxy/rules/:ruleId/verification')
// Issue a TLS certificate when domain is verified
$queueForCertificates
->setDomain(new Document([
'domain' => $rule->getAttribute('domain')
'domain' => $rule->getAttribute('domain'),
'domainType' => $rule->getAttribute('deploymentResourceType', $rule->getAttribute('type')),
]))
->trigger();
+84 -79
View File
@@ -145,7 +145,7 @@ App::post('/v1/storage/buckets')
$bucket = $dbForProject->getDocument('buckets', $bucketId);
$dbForProject->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes, permissions: $permissions ?? [], documentSecurity: $fileSecurity);
$dbForProject->createCollection('bucket_' . $bucket->getSequence(), $attributes, $indexes, permissions: $permissions ?? [], documentSecurity: $fileSecurity);
} catch (DuplicateException) {
throw new Exception(Exception::STORAGE_BUCKET_ALREADY_EXISTS);
}
@@ -316,17 +316,17 @@ App::put('/v1/storage/buckets/:bucketId')
$permissions = Permission::aggregate($permissions);
$bucket = $dbForProject->updateDocument('buckets', $bucket->getId(), $bucket
->setAttribute('name', $name)
->setAttribute('$permissions', $permissions)
->setAttribute('maximumFileSize', $maximumFileSize)
->setAttribute('allowedFileExtensions', $allowedFileExtensions)
->setAttribute('fileSecurity', $fileSecurity)
->setAttribute('enabled', $enabled)
->setAttribute('encryption', $encryption)
->setAttribute('compression', $compression)
->setAttribute('antivirus', $antivirus));
->setAttribute('name', $name)
->setAttribute('$permissions', $permissions)
->setAttribute('maximumFileSize', $maximumFileSize)
->setAttribute('allowedFileExtensions', $allowedFileExtensions)
->setAttribute('fileSecurity', $fileSecurity)
->setAttribute('enabled', $enabled)
->setAttribute('encryption', $encryption)
->setAttribute('compression', $compression)
->setAttribute('antivirus', $antivirus));
$dbForProject->updateCollection('bucket_' . $bucket->getInternalId(), $permissions, $fileSecurity);
$dbForProject->updateCollection('bucket_' . $bucket->getSequence(), $permissions, $fileSecurity);
$queueForEvents
->setParam('bucketId', $bucket->getId());
@@ -558,7 +558,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
$path = $deviceForFiles->getPath($fileId . '.' . \pathinfo($fileName, PATHINFO_EXTENSION));
$path = str_ireplace($deviceForFiles->getRoot(), $deviceForFiles->getRoot() . DIRECTORY_SEPARATOR . $bucket->getId(), $path); // Add bucket id to path after root
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
$file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId);
$metadata = ['content_type' => $deviceForLocal->getFileMimeType($fileTmpName)];
if (!$file->isEmpty()) {
@@ -652,7 +652,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
'$id' => $fileId,
'$permissions' => $permissions,
'bucketId' => $bucket->getId(),
'bucketInternalId' => $bucket->getInternalId(),
'bucketInternalId' => $bucket->getSequence(),
'name' => $fileName,
'path' => $path,
'signature' => $fileHash,
@@ -671,7 +671,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
'metadata' => $metadata,
]);
$file = $dbForProject->createDocument('bucket_' . $bucket->getInternalId(), $doc);
$file = $dbForProject->createDocument('bucket_' . $bucket->getSequence(), $doc);
} else {
$file = $file
->setAttribute('$permissions', $permissions)
@@ -696,7 +696,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
if (!$validator->isValid($bucket->getCreate())) {
throw new Exception(Exception::USER_UNAUTHORIZED);
}
$file = Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file));
$file = Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getSequence(), $fileId, $file));
}
} else {
if ($file->isEmpty()) {
@@ -704,7 +704,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
'$id' => ID::custom($fileId),
'$permissions' => $permissions,
'bucketId' => $bucket->getId(),
'bucketInternalId' => $bucket->getInternalId(),
'bucketInternalId' => $bucket->getSequence(),
'name' => $fileName,
'path' => $path,
'signature' => '',
@@ -720,7 +720,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
]);
try {
$file = $dbForProject->createDocument('bucket_' . $bucket->getInternalId(), $doc);
$file = $dbForProject->createDocument('bucket_' . $bucket->getSequence(), $doc);
} catch (NotFoundException) {
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
}
@@ -741,7 +741,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
}
try {
$file = Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file));
$file = Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getSequence(), $fileId, $file));
} catch (NotFoundException) {
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
}
@@ -826,9 +826,9 @@ App::get('/v1/storage/buckets/:bucketId/files')
$fileId = $cursor->getValue();
if ($fileSecurity && !$valid) {
$cursorDocument = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
$cursorDocument = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId);
} else {
$cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
$cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId));
}
if ($cursorDocument->isEmpty()) {
@@ -842,11 +842,11 @@ App::get('/v1/storage/buckets/:bucketId/files')
try {
if ($fileSecurity && !$valid) {
$files = $dbForProject->find('bucket_' . $bucket->getInternalId(), $queries);
$total = $dbForProject->count('bucket_' . $bucket->getInternalId(), $filterQueries, APP_LIMIT_COUNT);
$files = $dbForProject->find('bucket_' . $bucket->getSequence(), $queries);
$total = $dbForProject->count('bucket_' . $bucket->getSequence(), $filterQueries, APP_LIMIT_COUNT);
} else {
$files = Authorization::skip(fn () => $dbForProject->find('bucket_' . $bucket->getInternalId(), $queries));
$total = Authorization::skip(fn () => $dbForProject->count('bucket_' . $bucket->getInternalId(), $filterQueries, APP_LIMIT_COUNT));
$files = Authorization::skip(fn () => $dbForProject->find('bucket_' . $bucket->getSequence(), $queries));
$total = Authorization::skip(fn () => $dbForProject->count('bucket_' . $bucket->getSequence(), $filterQueries, APP_LIMIT_COUNT));
}
} catch (NotFoundException) {
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
@@ -902,9 +902,9 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId')
}
if ($fileSecurity && !$valid) {
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
$file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId);
} else {
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId));
}
if ($file->isEmpty()) {
@@ -973,7 +973,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
}
$isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getInternalId();
$isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getSequence();
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
$validator = new Authorization(Database::PERMISSION_READ);
$valid = $validator->isValid($bucket->getRead());
@@ -982,12 +982,12 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
}
if ($fileSecurity && !$valid && !$isToken) {
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
$file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId);
} else {
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId));
}
if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getInternalId()) {
if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getSequence()) {
throw new Exception(Exception::USER_UNAUTHORIZED);
}
@@ -1004,7 +1004,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
$algorithm = $file->getAttribute('algorithm', Compression::NONE);
$cipher = $file->getAttribute('openSSLCipher');
$mime = $file->getAttribute('mimeType');
if (!\in_array($mime, $inputs) || $file->getAttribute('sizeActual') > (int) System::getEnv('_APP_STORAGE_PREVIEW_LIMIT', 20000000)) {
if (!\in_array($mime, $inputs) || $file->getAttribute('sizeActual') > (int) System::getEnv('_APP_STORAGE_PREVIEW_LIMIT', APP_STORAGE_READ_BUFFER)) {
if (!\in_array($mime, $inputs)) {
$path = (\array_key_exists($mime, $fileLogos)) ? $fileLogos[$mime] : $fileLogos['default'];
} else {
@@ -1150,7 +1150,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
}
$isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getInternalId();
$isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getSequence();
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
$validator = new Authorization(Database::PERMISSION_READ);
$valid = $validator->isValid($bucket->getRead());
@@ -1159,12 +1159,12 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
}
if ($fileSecurity && !$valid) {
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
$file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId);
} else {
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId));
}
if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getInternalId()) {
if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getSequence()) {
throw new Exception(Exception::USER_UNAUTHORIZED);
}
@@ -1178,13 +1178,6 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND, 'File not found in ' . $path);
}
$response
->setContentType($file->getAttribute('mimeType'))
->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days
->addHeader('X-Peak', \memory_get_peak_usage())
->addHeader('Content-Disposition', 'attachment; filename="' . $file->getAttribute('name', '') . '"')
;
$size = $file->getAttribute('sizeOriginal', 0);
$rangeHeader = $request->getHeader('range');
@@ -1193,7 +1186,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
$end = $request->getRangeEnd();
$unit = $request->getRangeUnit();
if ($end === null) {
if ($end === null || $end - $start > APP_STORAGE_READ_BUFFER) {
$end = min(($start + MAX_OUTPUT_CHUNK_SIZE - 1), ($size - 1));
}
@@ -1208,6 +1201,13 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
->setStatusCode(Response::STATUS_CODE_PARTIALCONTENT);
}
$response
->setContentType($file->getAttribute('mimeType'))
->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days
->addHeader('X-Peak', \memory_get_peak_usage())
->addHeader('Content-Disposition', 'attachment; filename="' . $file->getAttribute('name', '') . '"')
;
$source = '';
if (!empty($file->getAttribute('openSSLCipher'))) { // Decrypt
$source = $deviceForFiles->read($path);
@@ -1241,12 +1241,15 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
if (!empty($source)) {
if (!empty($rangeHeader)) {
$response->send(substr($source, $start, ($end - $start + 1)));
return;
}
$response->send($source);
return;
}
if (!empty($rangeHeader)) {
$response->send($deviceForFiles->read($path, $start, ($end - $start + 1)));
return;
}
if ($size > APP_STORAGE_READ_BUFFER) {
@@ -1306,7 +1309,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
}
$isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getInternalId();
$isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getSequence();
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
$validator = new Authorization(Database::PERMISSION_READ);
$valid = $validator->isValid($bucket->getRead());
@@ -1315,12 +1318,12 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
}
if ($fileSecurity && !$valid) {
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
$file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId);
} else {
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId));
}
if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getInternalId()) {
if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getSequence()) {
throw new Exception(Exception::USER_UNAUTHORIZED);
}
@@ -1342,15 +1345,6 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
$contentType = $file->getAttribute('mimeType');
}
$response
->setContentType($contentType)
->addHeader('Content-Security-Policy', 'script-src none;')
->addHeader('X-Content-Type-Options', 'nosniff')
->addHeader('Content-Disposition', 'inline; filename="' . $file->getAttribute('name', '') . '"')
->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days
->addHeader('X-Peak', \memory_get_peak_usage())
;
$size = $file->getAttribute('sizeOriginal', 0);
$rangeHeader = $request->getHeader('range');
@@ -1359,8 +1353,8 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
$end = $request->getRangeEnd();
$unit = $request->getRangeUnit();
if ($end === null) {
$end = min(($start + 2000000 - 1), ($size - 1));
if ($end === null || $end - $start > APP_STORAGE_READ_BUFFER) {
$end = min(($start + APP_STORAGE_READ_BUFFER - 1), ($size - 1));
}
if ($unit != 'bytes' || $start >= $end || $end >= $size) {
@@ -1374,6 +1368,15 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
->setStatusCode(Response::STATUS_CODE_PARTIALCONTENT);
}
$response
->setContentType($contentType)
->addHeader('Content-Security-Policy', 'script-src none;')
->addHeader('X-Content-Type-Options', 'nosniff')
->addHeader('Content-Disposition', 'inline; filename="' . $file->getAttribute('name', '') . '"')
->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days
->addHeader('X-Peak', \memory_get_peak_usage())
;
$source = '';
if (!empty($file->getAttribute('openSSLCipher'))) { // Decrypt
$source = $deviceForFiles->read($path);
@@ -1407,6 +1410,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
if (!empty($source)) {
if (!empty($rangeHeader)) {
$response->send(substr($source, $start, ($end - $start + 1)));
return;
}
$response->send($source);
return;
@@ -1474,7 +1478,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push')
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
}
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId));
if ($file->isEmpty()) {
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
@@ -1494,14 +1498,6 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push')
$contentType = $file->getAttribute('mimeType');
}
$response
->setContentType($contentType)
->addHeader('Content-Security-Policy', 'script-src none;')
->addHeader('X-Content-Type-Options', 'nosniff')
->addHeader('Content-Disposition', 'inline; filename="' . $file->getAttribute('name', '') . '"')
->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days
->addHeader('X-Peak', \memory_get_peak_usage());
$size = $file->getAttribute('sizeOriginal', 0);
$rangeHeader = $request->getHeader('range');
@@ -1510,8 +1506,8 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push')
$end = $request->getRangeEnd();
$unit = $request->getRangeUnit();
if ($end === null) {
$end = min(($start + 2000000 - 1), ($size - 1));
if ($end === null || $end - $start > APP_STORAGE_READ_BUFFER) {
$end = min(($start + APP_STORAGE_READ_BUFFER - 1), ($size - 1));
}
if ($unit != 'bytes' || $start >= $end || $end >= $size) {
@@ -1525,6 +1521,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push')
->setStatusCode(Response::STATUS_CODE_PARTIALCONTENT);
}
$response
->setContentType($contentType)
->addHeader('Content-Security-Policy', 'script-src none;')
->addHeader('X-Content-Type-Options', 'nosniff')
->addHeader('Content-Disposition', 'inline; filename="' . $file->getAttribute('name', '') . '"')
->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days
->addHeader('X-Peak', \memory_get_peak_usage());
$source = '';
if (!empty($file->getAttribute('openSSLCipher'))) { // Decrypt
$source = $deviceForFiles->read($path);
@@ -1558,6 +1562,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push')
if (!empty($source)) {
if (!empty($rangeHeader)) {
$response->send(substr($source, $start, ($end - $start + 1)));
return;
}
$response->send($source);
return;
@@ -1638,7 +1643,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
}
// Read permission should not be required for update
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId));
if ($file->isEmpty()) {
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
@@ -1684,9 +1689,9 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
try {
if ($fileSecurity && !$valid) {
$file = $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file);
$file = $dbForProject->updateDocument('bucket_' . $bucket->getSequence(), $fileId, $file);
} else {
$file = Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file));
$file = Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getSequence(), $fileId, $file));
}
} catch (NotFoundException) {
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
@@ -1752,7 +1757,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
}
// Read permission should not be required for delete
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId));
if ($file->isEmpty()) {
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
@@ -1782,9 +1787,9 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
try {
if ($fileSecurity && !$valid) {
$deleted = $dbForProject->deleteDocument('bucket_' . $bucket->getInternalId(), $fileId);
$deleted = $dbForProject->deleteDocument('bucket_' . $bucket->getSequence(), $fileId);
} else {
$deleted = Authorization::skip(fn () => $dbForProject->deleteDocument('bucket_' . $bucket->getInternalId(), $fileId));
$deleted = Authorization::skip(fn () => $dbForProject->deleteDocument('bucket_' . $bucket->getSequence(), $fileId));
}
} catch (NotFoundException) {
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
@@ -1932,14 +1937,14 @@ App::get('/v1/storage/:bucketId/usage')
$stats = $usage = [];
$days = $periods[$range];
$metrics = [
str_replace('{bucketInternalId}', $bucket->getInternalId(), METRIC_BUCKET_ID_FILES),
str_replace('{bucketInternalId}', $bucket->getInternalId(), METRIC_BUCKET_ID_FILES_STORAGE),
str_replace('{bucketInternalId}', $bucket->getInternalId(), METRIC_BUCKET_ID_FILES_IMAGES_TRANSFORMED),
str_replace('{bucketInternalId}', $bucket->getSequence(), METRIC_BUCKET_ID_FILES),
str_replace('{bucketInternalId}', $bucket->getSequence(), METRIC_BUCKET_ID_FILES_STORAGE),
str_replace('{bucketInternalId}', $bucket->getSequence(), METRIC_BUCKET_ID_FILES_IMAGES_TRANSFORMED),
];
Authorization::skip(function () use ($dbForProject, $dbForLogs, $bucket, $days, $metrics, &$stats) {
foreach ($metrics as $metric) {
$db = ($metric === str_replace('{bucketInternalId}', $bucket->getInternalId(), METRIC_BUCKET_ID_FILES_IMAGES_TRANSFORMED))
$db = ($metric === str_replace('{bucketInternalId}', $bucket->getSequence(), METRIC_BUCKET_ID_FILES_IMAGES_TRANSFORMED))
? $dbForLogs
: $dbForProject;
+48 -20
View File
@@ -123,9 +123,9 @@ App::post('/v1/teams')
Permission::delete(Role::team($team->getId(), 'owner')),
],
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'userInternalId' => $user->getSequence(),
'teamId' => $team->getId(),
'teamInternalId' => $team->getInternalId(),
'teamInternalId' => $team->getSequence(),
'roles' => $roles,
'invited' => DateTime::now(),
'joined' => DateTime::now(),
@@ -595,8 +595,8 @@ App::post('/v1/teams/:teamId/memberships')
}
$membership = $dbForProject->findOne('memberships', [
Query::equal('userInternalId', [$invitee->getInternalId()]),
Query::equal('teamInternalId', [$team->getInternalId()]),
Query::equal('userInternalId', [$invitee->getSequence()]),
Query::equal('teamInternalId', [$team->getSequence()]),
]);
$secret = Auth::tokenGenerator();
@@ -612,9 +612,9 @@ App::post('/v1/teams/:teamId/memberships')
Permission::delete(Role::team($team->getId(), 'owner')),
],
'userId' => $invitee->getId(),
'userInternalId' => $invitee->getInternalId(),
'userInternalId' => $invitee->getSequence(),
'teamId' => $team->getId(),
'teamInternalId' => $team->getInternalId(),
'teamInternalId' => $team->getSequence(),
'roles' => $roles,
'invited' => DateTime::now(),
'joined' => ($isPrivilegedUser || $isAppUser) ? DateTime::now() : null,
@@ -842,7 +842,7 @@ App::get('/v1/teams/:teamId/memberships')
}
// Set internal queries
$queries[] = Query::equal('teamInternalId', [$team->getInternalId()]);
$queries[] = Query::equal('teamInternalId', [$team->getSequence()]);
/**
* Get cursor document if there was a cursor query, we use array_filter and reset for reference $cursor to $queries
@@ -1092,15 +1092,18 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId')
collection: 'memberships',
queries: [
Query::contains('roles', ['owner']),
Query::equal('teamInternalId', [$team->getInternalId()])
Query::equal('teamInternalId', [$team->getSequence()])
],
max: 2
);
// Is the role change being requested by the user on their own membership?
$isCurrentUserAnOwner = $user->getSequence() === $membership->getAttribute('userInternalId');
// Prevent role change if there's only one owner left,
// the requester is that owner, and the new `$roles` no longer include 'owner'!
if ($ownersCount === 1 && $isOwner && !\in_array('owner', $roles)) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'There must be at least one owner in the organization.');
// the requester is that owner, and the new `$roles` no longer include 'owner'
if ($ownersCount === 1 && $isOwner && $isCurrentUserAnOwner && !\in_array('owner', $roles)) {
throw new Exception(Exception::MEMBERSHIP_DOWNGRADE_PROHIBITED, 'There must be at least one owner in the organization.');
}
}
@@ -1180,7 +1183,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
throw new Exception(Exception::TEAM_NOT_FOUND);
}
if ($membership->getAttribute('teamInternalId') !== $team->getInternalId()) {
if ($membership->getAttribute('teamInternalId') !== $team->getSequence()) {
throw new Exception(Exception::TEAM_MEMBERSHIP_MISMATCH);
}
@@ -1197,7 +1200,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
$user->setAttributes($dbForProject->getDocument('users', $userId)->getArrayCopy()); // Get user
}
if ($membership->getAttribute('userInternalId') !== $user->getInternalId()) {
if ($membership->getAttribute('userInternalId') !== $user->getSequence()) {
throw new Exception(Exception::TEAM_INVITE_MISMATCH, 'Invite does not belong to current user (' . $user->getAttribute('email') . ')');
}
@@ -1229,7 +1232,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
Permission::delete(Role::user($user->getId())),
],
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'userInternalId' => $user->getSequence(),
'provider' => Auth::SESSION_PROVIDER_EMAIL,
'providerUid' => $user->getAttribute('email'),
'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak
@@ -1315,10 +1318,12 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId')
))
->param('teamId', '', new UID(), 'Team ID.')
->param('membershipId', '', new UID(), 'Membership ID.')
->inject('user')
->inject('project')
->inject('response')
->inject('dbForProject')
->inject('queueForEvents')
->action(function (string $teamId, string $membershipId, Response $response, Database $dbForProject, Event $queueForEvents) {
->action(function (string $teamId, string $membershipId, Document $user, Document $project, Response $response, Database $dbForProject, Event $queueForEvents) {
$membership = $dbForProject->getDocument('memberships', $membershipId);
@@ -1326,9 +1331,9 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId')
throw new Exception(Exception::TEAM_INVITE_NOT_FOUND);
}
$user = $dbForProject->getDocument('users', $membership->getAttribute('userId'));
$profile = $dbForProject->getDocument('users', $membership->getAttribute('userId'));
if ($user->isEmpty()) {
if ($profile->isEmpty()) {
throw new Exception(Exception::USER_NOT_FOUND);
}
@@ -1338,10 +1343,33 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId')
throw new Exception(Exception::TEAM_NOT_FOUND);
}
if ($membership->getAttribute('teamInternalId') !== $team->getInternalId()) {
if ($membership->getAttribute('teamInternalId') !== $team->getSequence()) {
throw new Exception(Exception::TEAM_MEMBERSHIP_MISMATCH);
}
if ($project->getId() === 'console') {
// Quick check:
// fetch up to 2 owners to determine if only one exists
$ownersCount = $dbForProject->count(
collection: 'memberships',
queries: [
Query::contains('roles', ['owner']),
Query::equal('teamInternalId', [$team->getSequence()])
],
max: 2
);
// Is the deletion being requested by the user on their own membership and they are also the owner?
$isSelfOwner =
in_array('owner', $membership->getAttribute('roles')) &&
$membership->getAttribute('userInternalId') === $user->getSequence();
if ($ownersCount === 1 && $isSelfOwner) {
/* Prevent removal if the user is the only owner. */
throw new Exception(Exception::MEMBERSHIP_DELETION_PROHIBITED, 'There must be at least one owner in the organization.');
}
}
try {
$dbForProject->deleteDocument('memberships', $membership->getId());
} catch (AuthorizationException $exception) {
@@ -1350,15 +1378,15 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId')
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove membership from DB');
}
$dbForProject->purgeCachedDocument('users', $user->getId());
$dbForProject->purgeCachedDocument('users', $profile->getId());
if ($membership->getAttribute('confirm')) { // Count only confirmed members
Authorization::skip(fn () => $dbForProject->decreaseDocumentAttribute('teams', $team->getId(), 'total', 1, 0));
}
$queueForEvents
->setParam('userId', $user->getId())
->setParam('teamId', $team->getId())
->setParam('userId', $profile->getId())
->setParam('membershipId', $membership->getId())
->setPayload($response->output($membership, Response::MODEL_MEMBERSHIP))
;
+16 -16
View File
@@ -140,7 +140,7 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e
Permission::delete(Role::user($user->getId())),
],
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'userInternalId' => $user->getSequence(),
'providerType' => 'email',
'identifier' => $email,
]));
@@ -164,7 +164,7 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e
Permission::delete(Role::user($user->getId())),
],
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'userInternalId' => $user->getSequence(),
'providerType' => 'sms',
'identifier' => $phone,
]));
@@ -564,10 +564,10 @@ App::post('/v1/users/:userId/targets')
Permission::delete(Role::user($user->getId())),
],
'providerId' => empty($provider->getId()) ? null : $provider->getId(),
'providerInternalId' => $provider->isEmpty() ? null : $provider->getInternalId(),
'providerInternalId' => $provider->isEmpty() ? null : $provider->getSequence(),
'providerType' => $providerType,
'userId' => $userId,
'userInternalId' => $user->getInternalId(),
'userInternalId' => $user->getSequence(),
'identifier' => $identifier,
'name' => ($name !== '') ? $name : null,
]));
@@ -846,7 +846,7 @@ App::get('/v1/users/:userId/memberships')
}
// Set internal queries
$queries[] = Query::equal('userInternalId', [$user->getInternalId()]);
$queries[] = Query::equal('userInternalId', [$user->getSequence()]);
$memberships = array_map(function ($membership) use ($dbForProject, $user) {
$team = $dbForProject->getDocument('teams', $membership->getAttribute('teamId'));
@@ -910,7 +910,7 @@ App::get('/v1/users/:userId/logs')
$audit = new Audit($dbForProject);
$logs = $audit->getLogsByUser($user->getInternalId(), $queries);
$logs = $audit->getLogsByUser($user->getSequence(), $queries);
$output = [];
@@ -957,7 +957,7 @@ App::get('/v1/users/:userId/logs')
}
$response->dynamic(new Document([
'total' => $audit->countLogsByUser($user->getInternalId(), $queries),
'total' => $audit->countLogsByUser($user->getSequence(), $queries),
'logs' => $output,
]), Response::MODEL_LOG_LIST);
});
@@ -980,7 +980,7 @@ App::get('/v1/users/:userId/targets')
]
))
->param('userId', '', new UID(), 'User ID.')
->param('queries', [], new Targets(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Users::ALLOWED_ATTRIBUTES), true)
->param('queries', [], new Targets(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Targets::ALLOWED_ATTRIBUTES), true)
->inject('response')
->inject('dbForProject')
->action(function (string $userId, array $queries, Response $response, Database $dbForProject) {
@@ -1396,7 +1396,7 @@ App::patch('/v1/users/:userId/email')
// Makes sure this email is not already used in another identity
$identityWithMatchingEmail = $dbForProject->findOne('identities', [
Query::equal('providerEmail', [$email]),
Query::notEqual('userInternalId', $user->getInternalId()),
Query::notEqual('userInternalId', $user->getSequence()),
]);
if (!$identityWithMatchingEmail->isEmpty()) {
throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS);
@@ -1440,7 +1440,7 @@ App::patch('/v1/users/:userId/email')
Permission::delete(Role::user($user->getId())),
],
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'userInternalId' => $user->getSequence(),
'providerType' => 'email',
'identifier' => $email,
]));
@@ -1529,7 +1529,7 @@ App::patch('/v1/users/:userId/phone')
Permission::delete(Role::user($user->getId())),
],
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'userInternalId' => $user->getSequence(),
'providerType' => 'sms',
'identifier' => $number,
]));
@@ -1711,7 +1711,7 @@ App::patch('/v1/users/:userId/targets/:targetId')
$target
->setAttribute('providerId', $provider->getId())
->setAttribute('providerInternalId', $provider->getInternalId());
->setAttribute('providerInternalId', $provider->getSequence());
}
if ($name) {
@@ -2051,7 +2051,7 @@ App::post('/v1/users/:userId/sessions')
[
'$id' => ID::unique(),
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'userInternalId' => $user->getSequence(),
'provider' => Auth::SESSION_PROVIDER_SERVER,
'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak
'userAgent' => $request->getUserAgent('UNKNOWN'),
@@ -2131,7 +2131,7 @@ App::post('/v1/users/:userId/tokens')
$token = new Document([
'$id' => ID::unique(),
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'userInternalId' => $user->getSequence(),
'type' => Auth::TOKEN_TYPE_GENERIC,
'secret' => Auth::hash($secret),
'expire' => $expire,
@@ -2293,8 +2293,8 @@ App::delete('/v1/users/:userId')
$clone = clone $user;
$dbForProject->deleteDocument('users', $userId);
DeleteIdentities::delete($dbForProject, Query::equal('userInternalId', [$user->getInternalId()]));
DeleteTargets::delete($dbForProject, Query::equal('userInternalId', [$user->getInternalId()]));
DeleteIdentities::delete($dbForProject, Query::equal('userInternalId', [$user->getSequence()]));
DeleteTargets::delete($dbForProject, Query::equal('userInternalId', [$user->getSequence()]));
$queueForDeletes
->setType(DELETE_TYPE_DOCUMENT)
+30 -23
View File
@@ -78,11 +78,11 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
$resourceCollection = $resourceType === "function" ? 'functions' : 'sites';
$resourceId = $repository->getAttribute('resourceId');
$resource = Authorization::skip(fn () => $dbForProject->getDocument($resourceCollection, $resourceId));
$resourceInternalId = $resource->getInternalId();
$resourceInternalId = $resource->getSequence();
$deploymentId = ID::unique();
$repositoryId = $repository->getId();
$repositoryInternalId = $repository->getInternalId();
$repositoryInternalId = $repository->getSequence();
$providerRepositoryId = $repository->getAttribute('providerRepositoryId');
$installationId = $repository->getAttribute('installationId');
$installationInternalId = $repository->getAttribute('installationInternalId');
@@ -157,7 +157,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
],
'installationInternalId' => $installationInternalId,
'installationId' => $installationId,
'projectInternalId' => $project->getInternalId(),
'projectInternalId' => $project->getSequence(),
'projectId' => $project->getId(),
'providerRepositoryId' => $providerRepositoryId,
'providerBranch' => $providerBranch,
@@ -252,13 +252,12 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
'providerCommitUrl' => $providerCommitUrl,
'providerCommentId' => \strval($latestCommentId),
'providerBranch' => $providerBranch,
'search' => implode(' ', [$deploymentId, $resource->getAttribute('entrypoint', '')]),
'activate' => $activate,
])));
$resource = $resource
->setAttribute('latestDeploymentId', $deployment->getId())
->setAttribute('latestDeploymentInternalId', $deployment->getInternalId())
->setAttribute('latestDeploymentInternalId', $deployment->getSequence())
->setAttribute('latestDeploymentCreatedAt', $deployment->getCreatedAt())
->setAttribute('latestDeploymentStatus', $deployment->getAttribute('status', ''));
Authorization::skip(fn () => $dbForProject->updateDocument($resource->getCollection(), $resource->getId(), $resource));
@@ -274,12 +273,12 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
fn () => $dbForPlatform->createDocument('rules', new Document([
'$id' => $ruleId,
'projectId' => $project->getId(),
'projectInternalId' => $project->getInternalId(),
'projectInternalId' => $project->getSequence(),
'domain' => $domain,
'type' => 'deployment',
'trigger' => 'deployment',
'deploymentId' => $deployment->getId(),
'deploymentInternalId' => $deployment->getInternalId(),
'deploymentInternalId' => $deployment->getSequence(),
'deploymentResourceType' => 'site',
'deploymentResourceId' => $resourceId,
'deploymentResourceInternalId' => $resourceInternalId,
@@ -294,19 +293,25 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
// VCS branch preview
if (!empty($providerBranch)) {
$domain = "branch-{$providerBranch}-{$resource->getId()}-{$project->getId()}.{$sitesDomain}";
$branchPrefix = substr($providerBranch, 0, 16);
if (strlen($providerBranch) > 16) {
$remainingChars = substr($providerBranch, 16);
$branchPrefix .= '-' . substr(hash('sha256', $remainingChars), 0, 7);
}
$resourceProjectHash = substr(hash('sha256', $resource->getId() . $project->getId()), 0, 7);
$domain = "branch-{$branchPrefix}-{$resourceProjectHash}.{$sitesDomain}";
$ruleId = md5($domain);
try {
Authorization::skip(
fn () => $dbForPlatform->createDocument('rules', new Document([
'$id' => $ruleId,
'projectId' => $project->getId(),
'projectInternalId' => $project->getInternalId(),
'projectInternalId' => $project->getSequence(),
'domain' => $domain,
'type' => 'deployment',
'trigger' => 'deployment',
'deploymentId' => $deployment->getId(),
'deploymentInternalId' => $deployment->getInternalId(),
'deploymentInternalId' => $deployment->getSequence(),
'deploymentResourceType' => 'site',
'deploymentResourceId' => $resourceId,
'deploymentResourceInternalId' => $resourceInternalId,
@@ -325,19 +330,19 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
// VCS commit preview
if (!empty($providerCommitHash)) {
$domain = "commit-{$providerCommitHash}-{$resource->getId()}-{$project->getId()}.{$sitesDomain}";
$domain = "commit-" . substr($providerCommitHash, 0, 16) . ".{$sitesDomain}";
$ruleId = md5($domain);
try {
Authorization::skip(
fn () => $dbForPlatform->createDocument('rules', new Document([
'$id' => $ruleId,
'projectId' => $project->getId(),
'projectInternalId' => $project->getInternalId(),
'projectInternalId' => $project->getSequence(),
'domain' => $domain,
'type' => 'deployment',
'trigger' => 'deployment',
'deploymentId' => $deployment->getId(),
'deploymentInternalId' => $deployment->getInternalId(),
'deploymentInternalId' => $deployment->getSequence(),
'deploymentResourceType' => 'site',
'deploymentResourceId' => $resourceId,
'deploymentResourceInternalId' => $resourceInternalId,
@@ -504,7 +509,7 @@ App::get('/v1/vcs/github/callback')
$github->initializeVariables($providerInstallationId, $privateKey, $githubAppId);
$owner = $github->getOwnerName($providerInstallationId) ?? '';
$projectInternalId = $project->getInternalId();
$projectInternalId = $project->getSequence();
$installation = $dbForPlatform->findOne('installations', [
Query::equal('providerInstallationId', [$providerInstallationId]),
@@ -600,11 +605,12 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories/:pro
->param('installationId', '', new Text(256), 'Installation Id')
->param('providerRepositoryId', '', new Text(256), 'Repository Id')
->param('providerRootDirectory', '', new Text(256, 0), 'Path to get contents of nested directory', true)
->param('providerReference', '', new Text(256, 0), 'Git reference (branch, tag, commit) to get contents from', true)
->inject('gitHub')
->inject('response')
->inject('project')
->inject('dbForPlatform')
->action(function (string $installationId, string $providerRepositoryId, string $providerRootDirectory, GitHub $github, Response $response, Document $project, Database $dbForPlatform) {
->action(function (string $installationId, string $providerRepositoryId, string $providerRootDirectory, string $providerReference, GitHub $github, Response $response, Document $project, Database $dbForPlatform) {
$installation = $dbForPlatform->getDocument('installations', $installationId);
if ($installation->isEmpty()) {
@@ -626,7 +632,7 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories/:pro
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
}
$contents = $github->listRepositoryContents($owner, $repositoryName, $providerRootDirectory);
$contents = $github->listRepositoryContents($owner, $repositoryName, $providerRootDirectory, $providerReference);
$vcsContents = [];
foreach ($contents as $content) {
@@ -1000,7 +1006,7 @@ App::post('/v1/vcs/github/installations/:installationId/providerRepositories')
if (empty($accessToken) || empty($refreshToken) || empty($accessTokenExpiry)) {
$identity = $dbForPlatform->findOne('identities', [
Query::equal('provider', ['github']),
Query::equal('userInternalId', [$user->getInternalId()]),
Query::equal('userInternalId', [$user->getSequence()]),
]);
if ($identity->isEmpty()) {
throw new Exception(Exception::USER_IDENTITY_NOT_FOUND);
@@ -1210,6 +1216,7 @@ App::post('/v1/vcs/github/events')
if ($event == $github::EVENT_PUSH) {
$providerBranchCreated = $parsedPayload["branchCreated"] ?? false;
$providerBranchDeleted = $parsedPayload["branchDeleted"] ?? false;
$providerBranch = $parsedPayload["branch"] ?? '';
$providerBranchUrl = $parsedPayload["branchUrl"] ?? '';
$providerRepositoryId = $parsedPayload["repositoryId"] ?? '';
@@ -1231,8 +1238,8 @@ App::post('/v1/vcs/github/events')
Query::limit(100),
]));
// create new deployment only on push and not when branch is created
if (!$providerBranchCreated) {
// 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);
}
} elseif ($event == $github::EVENT_INSTALLATION) {
@@ -1247,7 +1254,7 @@ App::post('/v1/vcs/github/events')
foreach ($installations as $installation) {
$repositories = Authorization::skip(fn () => $dbForPlatform->find('repositories', [
Query::equal('installationInternalId', [$installation->getInternalId()]),
Query::equal('installationInternalId', [$installation->getSequence()]),
Query::limit(1000)
]));
@@ -1350,7 +1357,7 @@ App::get('/v1/vcs/installations')
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
}
$queries[] = Query::equal('projectInternalId', [$project->getInternalId()]);
$queries[] = Query::equal('projectInternalId', [$project->getSequence()]);
if (!empty($search)) {
$queries[] = Query::search('search', $search);
@@ -1423,7 +1430,7 @@ App::get('/v1/vcs/installations/:installationId')
throw new Exception(Exception::INSTALLATION_NOT_FOUND);
}
if ($installation->getAttribute('projectInternalId') !== $project->getInternalId()) {
if ($installation->getAttribute('projectInternalId') !== $project->getSequence()) {
throw new Exception(Exception::INSTALLATION_NOT_FOUND);
}
@@ -1506,7 +1513,7 @@ App::patch('/v1/vcs/github/installations/:installationId/repositories/:repositor
}
$repository = Authorization::skip(fn () => $dbForPlatform->getDocument('repositories', $repositoryId, [
Query::equal('projectInternalId', [$project->getInternalId()])
Query::equal('projectInternalId', [$project->getSequence()])
]));
if ($repository->isEmpty()) {
+48 -38
View File
@@ -391,9 +391,9 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
$execution = new Document([
'$id' => $executionId,
'$permissions' => [],
'resourceInternalId' => $resource->getInternalId(),
'resourceInternalId' => $resource->getSequence(),
'resourceId' => $resource->getId(),
'deploymentInternalId' => $deployment->getInternalId(),
'deploymentInternalId' => $deployment->getSequence(),
'deploymentId' => $deployment->getId(),
'responseStatusCode' => 0,
'responseHeaders' => [],
@@ -452,16 +452,33 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
$endpoint = $protocol . '://' . $hostname . "/v1";
// Appwrite vars
if ($type === 'function') {
$vars = \array_merge($vars, [
'APPWRITE_FUNCTION_API_ENDPOINT' => $endpoint,
'APPWRITE_FUNCTION_ID' => $resource->getId(),
'APPWRITE_FUNCTION_NAME' => $resource->getAttribute('name'),
'APPWRITE_FUNCTION_DEPLOYMENT' => $deployment->getId(),
'APPWRITE_FUNCTION_PROJECT_ID' => $project->getId(),
'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'] ?? '',
'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'] ?? '',
'APPWRITE_FUNCTION_CPUS' => $spec['cpus'] ?? APP_COMPUTE_CPUS_DEFAULT,
'APPWRITE_FUNCTION_MEMORY' => $spec['memory'] ?? APP_COMPUTE_MEMORY_DEFAULT,
]);
} elseif ($type === 'site') {
$vars = \array_merge($vars, [
'APPWRITE_SITE_API_ENDPOINT' => $endpoint,
'APPWRITE_SITE_ID' => $resource->getId(),
'APPWRITE_SITE_NAME' => $resource->getAttribute('name'),
'APPWRITE_SITE_DEPLOYMENT' => $deployment->getId(),
'APPWRITE_SITE_PROJECT_ID' => $project->getId(),
'APPWRITE_SITE_RUNTIME_NAME' => $runtime['name'] ?? '',
'APPWRITE_SITE_RUNTIME_VERSION' => $runtime['version'] ?? '',
'APPWRITE_SITE_CPUS' => $spec['cpus'] ?? APP_COMPUTE_CPUS_DEFAULT,
'APPWRITE_SITE_MEMORY' => $spec['memory'] ?? APP_COMPUTE_MEMORY_DEFAULT,
]);
}
$vars = \array_merge($vars, [
'APPWRITE_FUNCTION_API_ENDPOINT' => $endpoint,
'APPWRITE_FUNCTION_ID' => $resource->getId(),
'APPWRITE_FUNCTION_NAME' => $resource->getAttribute('name'),
'APPWRITE_FUNCTION_DEPLOYMENT' => $deployment->getId(),
'APPWRITE_FUNCTION_PROJECT_ID' => $project->getId(),
'APPWRITE_FUNCTION_RUNTIME_NAME' => $runtime['name'] ?? '',
'APPWRITE_FUNCTION_RUNTIME_VERSION' => $runtime['version'] ?? '',
'APPWRITE_FUNCTION_CPUS' => $spec['cpus'] ?? APP_COMPUTE_CPUS_DEFAULT,
'APPWRITE_FUNCTION_MEMORY' => $spec['memory'] ?? APP_COMPUTE_MEMORY_DEFAULT,
'APPWRITE_VERSION' => APP_VERSION_STABLE,
'APPWRITE_REGION' => $project->getAttribute('region'),
'APPWRITE_DEPLOYMENT_TYPE' => $deployment->getAttribute('type', ''),
@@ -494,28 +511,27 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
'function' => $deployment->getAttribute('entrypoint', ''),
'site' => '',
};
$source = $deployment->getAttribute('buildPath', '');
$extension = str_ends_with($source, '.tar') ? 'tar' : 'tar.gz';
if ($type === 'function') {
$runtimeEntrypoint = match ($version) {
'v2' => '',
default => 'cp /tmp/code.tar.gz /mnt/code/code.tar.gz && nohup helpers/start.sh "' . $runtime['startCommand'] . '"'
};
} elseif ($type === 'site') {
$startCommand = $runtime['startCommand'];
if ($type === 'site') {
$frameworks = Config::getParam('frameworks', []);
$framework = $frameworks[$resource->getAttribute('framework', '')] ?? null;
$startCommand = $runtime['startCommand'];
if (!is_null($framework)) {
$adapter = ($framework['adapters'] ?? [])[$deployment->getAttribute('adapter', '')] ?? null;
if (!is_null($adapter) && isset($adapter['startCommand'])) {
$startCommand = $adapter['startCommand'];
}
}
$runtimeEntrypoint = 'cp /tmp/code.tar.gz /mnt/code/code.tar.gz && nohup helpers/start.sh "' . $startCommand . '"';
}
$runtimeEntrypoint = match ($version) {
'v2' => '',
default => "cp /tmp/code.$extension /mnt/code/code.$extension && nohup helpers/start.sh \"$startCommand\"",
};
$entrypoint = match ($type) {
'function' => $deployment->getAttribute('entrypoint', ''),
'site' => '',
@@ -528,7 +544,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
variables: $vars,
timeout: $resource->getAttribute('timeout', 30),
image: $runtime['image'],
source: $deployment->getAttribute('buildPath', ''),
source: $source,
entrypoint: $entrypoint,
version: $version,
path: $path,
@@ -675,11 +691,11 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
}
$metricTypeExecutions = str_replace(['{resourceType}'], [$deployment->getAttribute('resourceType')], METRIC_RESOURCE_TYPE_EXECUTIONS);
$metricTypeIdExecutions = str_replace(['{resourceType}', '{resourceInternalId}'], [$deployment->getAttribute('resourceType'), $resource->getInternalId()], METRIC_RESOURCE_TYPE_ID_EXECUTIONS);
$metricTypeIdExecutions = str_replace(['{resourceType}', '{resourceInternalId}'], [$deployment->getAttribute('resourceType'), $resource->getSequence()], METRIC_RESOURCE_TYPE_ID_EXECUTIONS);
$metricTypeExecutionsCompute = str_replace(['{resourceType}'], [$deployment->getAttribute('resourceType')], METRIC_RESOURCE_TYPE_EXECUTIONS_COMPUTE);
$metricTypeIdExecutionsCompute = str_replace(['{resourceType}', '{resourceInternalId}'], [$deployment->getAttribute('resourceType'), $resource->getInternalId()], METRIC_RESOURCE_TYPE_ID_EXECUTIONS_COMPUTE);
$metricTypeIdExecutionsCompute = str_replace(['{resourceType}', '{resourceInternalId}'], [$deployment->getAttribute('resourceType'), $resource->getSequence()], METRIC_RESOURCE_TYPE_ID_EXECUTIONS_COMPUTE);
$metricTypeExecutionsMbSeconds = str_replace(['{resourceType}'], [$deployment->getAttribute('resourceType')], METRIC_RESOURCE_TYPE_EXECUTIONS_MB_SECONDS);
$metricTypeIdExecutionsMBSeconds = str_replace(['{resourceType}', '{resourceInternalId}'], [$deployment->getAttribute('resourceType'), $resource->getInternalId()], METRIC_RESOURCE_TYPE_ID_EXECUTIONS_MB_SECONDS);
$metricTypeIdExecutionsMBSeconds = str_replace(['{resourceType}', '{resourceInternalId}'], [$deployment->getAttribute('resourceType'), $resource->getSequence()], METRIC_RESOURCE_TYPE_ID_EXECUTIONS_MB_SECONDS);
if ($deployment->getAttribute('resourceType') === 'sites') {
$queueForStatsUsage
->disableMetric(METRIC_NETWORK_REQUESTS)
@@ -702,9 +718,9 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
->addMetric(METRIC_SITES_REQUESTS, 1)
->addMetric(METRIC_SITES_INBOUND, $request->getSize() + $fileSize)
->addMetric(METRIC_SITES_OUTBOUND, $response->getSize())
->addMetric(str_replace('{siteInternalId}', $resource->getInternalId(), METRIC_SITES_ID_REQUESTS), 1)
->addMetric(str_replace('{siteInternalId}', $resource->getInternalId(), METRIC_SITES_ID_INBOUND), $request->getSize() + $fileSize)
->addMetric(str_replace('{siteInternalId}', $resource->getInternalId(), METRIC_SITES_ID_OUTBOUND), $response->getSize())
->addMetric(str_replace('{siteInternalId}', $resource->getSequence(), METRIC_SITES_ID_REQUESTS), 1)
->addMetric(str_replace('{siteInternalId}', $resource->getSequence(), METRIC_SITES_ID_INBOUND), $request->getSize() + $fileSize)
->addMetric(str_replace('{siteInternalId}', $resource->getSequence(), METRIC_SITES_ID_OUTBOUND), $response->getSize())
;
}
@@ -732,12 +748,6 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
return false;
} elseif ($type === 'redirect') {
$url = $rule->getAttribute('redirectUrl', '');
$query = ($swooleRequest->server['query_string'] ?? '');
if (!empty($query)) {
$url .= '?' . $query;
}
$response->redirect($url, \intval($rule->getAttribute('redirectStatusCode', 301)));
return true;
} else {
@@ -897,7 +907,7 @@ App::init()
'type' => 'api',
'status' => 'verifying',
'projectId' => $console->getId(),
'projectInternalId' => $console->getInternalId(),
'projectInternalId' => $console->getSequence(),
'search' => implode(' ', [$ruleId, $domain->get()]),
'owner' => $owner,
'region' => $console->getAttribute('region')
@@ -947,7 +957,7 @@ App::init()
)[0] ?? new Document();
}
if (!$rule->isEmpty() && $rule->getAttribute('projectInternalId') === $project->getInternalId()) {
if (!$rule->isEmpty() && $rule->getAttribute('projectInternalId') === $project->getSequence()) {
$refDomainOrigin = $origin;
}
}
@@ -1030,7 +1040,7 @@ App::init()
->addHeader('Server', 'Appwrite')
->addHeader('X-Content-Type-Options', 'nosniff')
->addHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE')
->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-Appwrite-Timeout, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, X-Appwrite-Timestamp, Content-Range, Range, Cache-Control, Expires, Pragma, X-Forwarded-For, X-Forwarded-User-Agent')
->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Dev-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-Appwrite-Timeout, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, X-Appwrite-Timestamp, Content-Range, Range, Cache-Control, Expires, Pragma, X-Forwarded-For, X-Forwarded-User-Agent')
->addHeader('Access-Control-Expose-Headers', 'X-Appwrite-Session, X-Fallback-Cookies')
->addHeader('Access-Control-Allow-Origin', $refDomain)
->addHeader('Access-Control-Allow-Credentials', 'true');
@@ -1093,7 +1103,7 @@ App::options()
$response
->addHeader('Server', 'Appwrite')
->addHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE')
->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-Appwrite-Timeout, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, X-Appwrite-Timestamp, Content-Range, Range, Cache-Control, Expires, Pragma, X-Appwrite-Session, X-Fallback-Cookies, X-Forwarded-For, X-Forwarded-User-Agent')
->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Dev-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-Appwrite-Timeout, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, X-Appwrite-Timestamp, Content-Range, Range, Cache-Control, Expires, Pragma, X-Appwrite-Session, X-Fallback-Cookies, X-Forwarded-For, X-Forwarded-User-Agent')
->addHeader('Access-Control-Expose-Headers', 'X-Appwrite-Session, X-Fallback-Cookies')
->addHeader('Access-Control-Allow-Origin', $origin)
->addHeader('Access-Control-Allow-Credentials', 'true')
+2 -2
View File
@@ -185,7 +185,7 @@ App::post('/v1/mock/api-key-unprefixed')
Permission::update(Role::any()),
Permission::delete(Role::any()),
],
'projectInternalId' => $project->getInternalId(),
'projectInternalId' => $project->getSequence(),
'projectId' => $project->getId(),
'name' => 'Outdated key',
'scopes' => $scopes,
@@ -235,7 +235,7 @@ App::get('/v1/mock/github/callback')
$github->initializeVariables($providerInstallationId, $privateKey, $githubAppId);
$owner = $github->getOwnerName($providerInstallationId) ?? '';
$projectInternalId = $project->getInternalId();
$projectInternalId = $project->getSequence();
$teamId = $project->getAttribute('teamId', '');
+4 -4
View File
@@ -574,7 +574,7 @@ App::init()
$bucketId = $parts[1] ?? null;
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
$isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getInternalId();
$isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getSequence();
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
@@ -593,12 +593,12 @@ App::init()
$fileId = $parts[1] ?? null;
if ($fileSecurity && !$valid && !$isToken) {
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
$file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId);
} else {
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId));
}
if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getInternalId()) {
if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getSequence()) {
throw new Exception(Exception::USER_UNAUTHORIZED);
}
+9 -14
View File
@@ -15,9 +15,11 @@ use Utopia\Audit\Audit;
use Utopia\CLI\Console;
use Utopia\Compression\Compression;
use Utopia\Config\Config;
use Utopia\Database\Adapter\Pool as DatabasePool;
use Utopia\Database\Database;
use Utopia\Database\DateTime;
use Utopia\Database\Document;
use Utopia\Database\Exception\Duplicate as DuplicateException;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Helpers\Permission;
use Utopia\Database\Helpers\Role;
@@ -170,7 +172,7 @@ function createDatabase(App $app, string $resourceKey, string $dbName, array $co
$sleep = 1;
$attempts = 0;
do {
while (true) {
try {
$attempts++;
$resource = $app->getResource($resourceKey);
@@ -179,13 +181,12 @@ function createDatabase(App $app, string $resourceKey, string $dbName, array $co
break; // exit loop on success
} catch (\Exception $e) {
Console::warning(" └── Database not ready. Retrying connection ({$attempts})...");
$pools->reclaim();
if ($attempts >= $max) {
throw new \Exception(' └── Failed to connect to database: ' . $e->getMessage());
}
sleep($sleep);
}
} while ($attempts < $max);
}
Console::success("[Setup] - $dbName database init started...");
@@ -308,7 +309,7 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg
'orders' => $index['orders'],
]), $files['indexes']);
$dbForPlatform->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes);
$dbForPlatform->createCollection('bucket_' . $bucket->getSequence(), $attributes, $indexes);
}
if (Authorization::skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots')->isEmpty())) {
@@ -356,7 +357,7 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg
'orders' => $index['orders'],
]), $files['indexes']);
Authorization::skip(fn () => $dbForPlatform->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes));
Authorization::skip(fn () => $dbForPlatform->createCollection('bucket_' . $bucket->getSequence(), $attributes, $indexes));
}
});
@@ -368,11 +369,7 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg
$cache = $app->getResource('cache');
foreach ($sharedTablesV2 as $hostname) {
$adapter = $pools
->get($hostname)
->pop()
->getResource();
$adapter = new DatabasePool($pools->get($hostname));
$dbForProject = (new Database($adapter, $cache))
->setDatabase('appwrite')
->setSharedTables(true)
@@ -382,7 +379,7 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg
try {
Console::success('[Setup] - Creating project database: ' . $hostname . '...');
$dbForProject->create();
} catch (Duplicate) {
} catch (DuplicateException) {
Console::success('[Setup] - Skip: metadata table already exists');
}
@@ -408,7 +405,6 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg
}
}
$pools->reclaim();
Console::success('[Setup] - Server database init completed...');
});
@@ -523,6 +519,7 @@ $http->on(Constant::EVENT_REQUEST, function (SwooleRequest $swooleRequest, Swool
Console::error('[Error] Message: ' . $th->getMessage());
Console::error('[Error] File: ' . $th->getFile());
Console::error('[Error] Line: ' . $th->getLine());
Console::error('[Error] Trace: ' . $th->getTraceAsString());
$swooleResponse->setStatusCode(500);
@@ -540,8 +537,6 @@ $http->on(Constant::EVENT_REQUEST, function (SwooleRequest $swooleRequest, Swool
];
$swooleResponse->end(\json_encode($output));
} finally {
$pools->reclaim();
}
});
+2
View File
@@ -2,6 +2,8 @@
use Utopia\Config\Config;
require_once __DIR__ . '/../config/storage/resource_limits.php';
Config::load('template-runtimes', __DIR__ . '/../config/template-runtimes.php');
Config::load('events', __DIR__ . '/../config/events.php');
Config::load('auth', __DIR__ . '/../config/auth.php');
+3 -2
View File
@@ -37,8 +37,8 @@ const APP_PROJECT_ACCESS = 24 * 60 * 60; // 24 hours
const APP_RESOURCE_TOKEN_ACCESS = 24 * 60 * 60; // 24 hours
const APP_FILE_ACCESS = 24 * 60 * 60; // 24 hours
const APP_CACHE_UPDATE = 24 * 60 * 60; // 24 hours
const APP_CACHE_BUSTER = 4319;
const APP_VERSION_STABLE = '1.7.0';
const APP_CACHE_BUSTER = 4320;
const APP_VERSION_STABLE = '1.7.4';
const APP_DATABASE_ATTRIBUTE_EMAIL = 'email';
const APP_DATABASE_ATTRIBUTE_ENUM = 'enum';
const APP_DATABASE_ATTRIBUTE_IP = 'ip';
@@ -51,6 +51,7 @@ const APP_DATABASE_TIMEOUT_MILLISECONDS_API = 15 * 1000; // 15 seconds
const APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER = 300 * 1000; // 5 minutes
const APP_DATABASE_TIMEOUT_MILLISECONDS_TASK = 300 * 1000; // 5 minutes
const APP_DATABASE_QUERY_MAX_VALUES = 500;
const APP_DATABASE_ENCRYPT_SIZE_MIN = 150;
const APP_STORAGE_UPLOADS = '/storage/uploads';
const APP_STORAGE_SITES = '/storage/sites';
const APP_STORAGE_FUNCTIONS = '/storage/functions';
+30 -21
View File
@@ -71,18 +71,27 @@ Database::addFilter(
},
function (mixed $value, Document $document, Database $database) {
$attributes = $database->find('attributes', [
Query::equal('collectionInternalId', [$document->getInternalId()]),
Query::equal('collectionInternalId', [$document->getSequence()]),
Query::equal('databaseInternalId', [$document->getAttribute('databaseInternalId')]),
Query::limit($database->getLimitForAttributes()),
]);
foreach ($attributes as $attribute) {
if ($attribute->getAttribute('type') === Database::VAR_RELATIONSHIP) {
$options = $attribute->getAttribute('options');
foreach ($options as $key => $value) {
$attribute->setAttribute($key, $value);
}
$attribute->removeAttribute('options');
$attributeType = $attribute->getAttribute('type');
switch ($attributeType) {
case Database::VAR_RELATIONSHIP:
$options = $attribute->getAttribute('options');
foreach ($options as $key => $value) {
$attribute->setAttribute($key, $value);
}
$attribute->removeAttribute('options');
break;
case Database::VAR_STRING:
$filters = $attribute->getAttribute('filters', []);
$attribute->setAttribute('encrypt', in_array('encrypt', $filters));
break;
}
}
@@ -98,7 +107,7 @@ Database::addFilter(
function (mixed $value, Document $document, Database $database) {
return $database
->find('indexes', [
Query::equal('collectionInternalId', [$document->getInternalId()]),
Query::equal('collectionInternalId', [$document->getSequence()]),
Query::equal('databaseInternalId', [$document->getAttribute('databaseInternalId')]),
Query::limit($database->getLimitForIndexes()),
]);
@@ -113,7 +122,7 @@ Database::addFilter(
function (mixed $value, Document $document, Database $database) {
return $database
->find('platforms', [
Query::equal('projectInternalId', [$document->getInternalId()]),
Query::equal('projectInternalId', [$document->getSequence()]),
Query::limit(APP_LIMIT_SUBQUERY),
]);
}
@@ -127,7 +136,7 @@ Database::addFilter(
function (mixed $value, Document $document, Database $database) {
return $database
->find('keys', [
Query::equal('projectInternalId', [$document->getInternalId()]),
Query::equal('projectInternalId', [$document->getSequence()]),
Query::limit(APP_LIMIT_SUBQUERY),
]);
}
@@ -141,7 +150,7 @@ Database::addFilter(
function (mixed $value, Document $document, Database $database) {
return $database
->find('devKeys', [
Query::equal('projectInternalId', [$document->getInternalId()]),
Query::equal('projectInternalId', [$document->getSequence()]),
Query::limit(APP_LIMIT_SUBQUERY),
]);
}
@@ -155,7 +164,7 @@ Database::addFilter(
function (mixed $value, Document $document, Database $database) {
return $database
->find('webhooks', [
Query::equal('projectInternalId', [$document->getInternalId()]),
Query::equal('projectInternalId', [$document->getSequence()]),
Query::limit(APP_LIMIT_SUBQUERY),
]);
}
@@ -168,7 +177,7 @@ Database::addFilter(
},
function (mixed $value, Document $document, Database $database) {
return Authorization::skip(fn () => $database->find('sessions', [
Query::equal('userInternalId', [$document->getInternalId()]),
Query::equal('userInternalId', [$document->getSequence()]),
Query::limit(APP_LIMIT_SUBQUERY),
]));
}
@@ -182,7 +191,7 @@ Database::addFilter(
function (mixed $value, Document $document, Database $database) {
return Authorization::skip(fn () => $database
->find('tokens', [
Query::equal('userInternalId', [$document->getInternalId()]),
Query::equal('userInternalId', [$document->getSequence()]),
Query::limit(APP_LIMIT_SUBQUERY),
]));
}
@@ -196,7 +205,7 @@ Database::addFilter(
function (mixed $value, Document $document, Database $database) {
return Authorization::skip(fn () => $database
->find('challenges', [
Query::equal('userInternalId', [$document->getInternalId()]),
Query::equal('userInternalId', [$document->getSequence()]),
Query::limit(APP_LIMIT_SUBQUERY),
]));
}
@@ -210,7 +219,7 @@ Database::addFilter(
function (mixed $value, Document $document, Database $database) {
return Authorization::skip(fn () => $database
->find('authenticators', [
Query::equal('userInternalId', [$document->getInternalId()]),
Query::equal('userInternalId', [$document->getSequence()]),
Query::limit(APP_LIMIT_SUBQUERY),
]));
}
@@ -224,7 +233,7 @@ Database::addFilter(
function (mixed $value, Document $document, Database $database) {
return Authorization::skip(fn () => $database
->find('memberships', [
Query::equal('userInternalId', [$document->getInternalId()]),
Query::equal('userInternalId', [$document->getSequence()]),
Query::limit(APP_LIMIT_SUBQUERY),
]));
}
@@ -238,7 +247,7 @@ Database::addFilter(
function (mixed $value, Document $document, Database $database) {
return $database
->find('variables', [
Query::equal('resourceInternalId', [$document->getInternalId()]),
Query::equal('resourceInternalId', [$document->getSequence()]),
Query::equal('resourceType', ['function', 'site']),
Query::limit(APP_LIMIT_SUBQUERY),
]);
@@ -316,7 +325,7 @@ Database::addFilter(
function (mixed $value, Document $document, Database $database) {
return Authorization::skip(fn () => $database
->find('targets', [
Query::equal('userInternalId', [$document->getInternalId()]),
Query::equal('userInternalId', [$document->getSequence()]),
Query::limit(APP_LIMIT_SUBQUERY)
]));
}
@@ -331,13 +340,13 @@ Database::addFilter(
$targetIds = Authorization::skip(fn () => \array_map(
fn ($document) => $document->getAttribute('targetInternalId'),
$database->find('subscribers', [
Query::equal('topicInternalId', [$document->getInternalId()]),
Query::equal('topicInternalId', [$document->getSequence()]),
Query::limit(APP_LIMIT_SUBSCRIBERS_SUBQUERY)
])
));
if (\count($targetIds) > 0) {
return $database->skipValidation(fn () => $database->find('targets', [
Query::equal('$internalId', $targetIds)
Query::equal('$sequence', $targetIds)
]));
}
return [];
+2 -2
View File
@@ -216,13 +216,13 @@ $register->set('pools', function () {
'mysql',
'mariadb' => function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase) {
return new PDOProxy(function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase) {
return new PDO("mysql:host={$dsnHost};port={$dsnPort};dbname={$dsnDatabase};charset=utf8mb4", $dsnUser, $dsnPass, array(
return new PDO("mysql:host={$dsnHost};port={$dsnPort};dbname={$dsnDatabase};charset=utf8mb4", $dsnUser, $dsnPass, [
\PDO::ATTR_TIMEOUT => 3, // Seconds
\PDO::ATTR_PERSISTENT => false,
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
\PDO::ATTR_EMULATE_PREPARES => true,
\PDO::ATTR_STRINGIFY_FETCHES => true
));
]);
});
},
'redis' => function () use ($dsnHost, $dsnPort, $dsnPass) {
+54 -69
View File
@@ -24,10 +24,12 @@ use Appwrite\Utopia\Request;
use Executor\Executor;
use Utopia\Abuse\Adapters\TimeLimit\Redis as TimeLimitRedis;
use Utopia\App;
use Utopia\Cache\Adapter\Pool as CachePool;
use Utopia\Cache\Adapter\Sharding;
use Utopia\Cache\Cache;
use Utopia\CLI\Console;
use Utopia\Config\Config;
use Utopia\Database\Adapter\Pool as DatabasePool;
use Utopia\Database\Database;
use Utopia\Database\DateTime as DatabaseDateTime;
use Utopia\Database\Document;
@@ -38,6 +40,7 @@ use Utopia\DSN\DSN;
use Utopia\Locale\Locale;
use Utopia\Logger\Log;
use Utopia\Pools\Group;
use Utopia\Queue\Broker\Pool as BrokerPool;
use Utopia\Queue\Publisher;
use Utopia\Storage\Device;
use Utopia\Storage\Device\AWS;
@@ -74,10 +77,10 @@ App::setResource('localeCodes', function () {
// Queues
App::setResource('publisher', function (Group $pools) {
return $pools->get('publisher')->pop()->getResource();
return new BrokerPool(publisher: $pools->get('publisher'));
}, ['pools']);
App::setResource('consumer', function (Group $pools) {
return $pools->get('consumer')->pop()->getResource();
return new BrokerPool(consumer: $pools->get('consumer'));
}, ['pools']);
App::setResource('queueForMessaging', function (Publisher $publisher) {
return new Messaging($publisher);
@@ -331,12 +334,8 @@ App::setResource('dbForProject', function (Group $pools, Database $dbForPlatform
$dsn = new DSN('mysql://' . $project->getAttribute('database'));
}
$dbAdapter = $pools
->get($dsn->getHost())
->pop()
->getResource();
$database = new Database($dbAdapter, $cache);
$adapter = new DatabasePool($pools->get($dsn->getHost()));
$database = new Database($adapter, $cache);
$database
->setMetadata('host', \gethostname())
@@ -349,25 +348,21 @@ App::setResource('dbForProject', function (Group $pools, Database $dbForPlatform
if (\in_array($dsn->getHost(), $sharedTables)) {
$database
->setSharedTables(true)
->setTenant($project->getInternalId())
->setTenant($project->getSequence())
->setNamespace($dsn->getParam('namespace'));
} else {
$database
->setSharedTables(false)
->setTenant(null)
->setNamespace('_' . $project->getInternalId());
->setNamespace('_' . $project->getSequence());
}
return $database;
}, ['pools', 'dbForPlatform', 'cache', 'project']);
App::setResource('dbForPlatform', function (Group $pools, Cache $cache) {
$dbAdapter = $pools
->get('console')
->pop()
->getResource();
$database = new Database($dbAdapter, $cache);
$adapter = new DatabasePool($pools->get('console'));
$database = new Database($adapter, $cache);
$database
->setNamespace('_console')
@@ -380,7 +375,7 @@ App::setResource('dbForPlatform', function (Group $pools, Cache $cache) {
}, ['pools', 'cache']);
App::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform, $cache) {
$databases = []; // TODO: @Meldiron This should probably be responsibility of utopia-php/pools
$databases = [];
return function (Document $project) use ($pools, $dbForPlatform, $cache, &$databases) {
if ($project->isEmpty() || $project->getId() === 'console') {
@@ -406,13 +401,13 @@ App::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform
if (\in_array($dsn->getHost(), $sharedTables)) {
$database
->setSharedTables(true)
->setTenant($project->getInternalId())
->setTenant($project->getSequence())
->setNamespace($dsn->getParam('namespace'));
} else {
$database
->setSharedTables(false)
->setTenant(null)
->setNamespace('_' . $project->getInternalId());
->setNamespace('_' . $project->getSequence());
}
});
@@ -422,12 +417,8 @@ App::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform
return $database;
}
$dbAdapter = $pools
->get($dsn->getHost())
->pop()
->getResource();
$database = new Database($dbAdapter, $cache);
$adapter = new DatabasePool($pools->get($dsn->getHost()));
$database = new Database($adapter, $cache);
$databases[$dsn->getHost()] = $database;
$configure($database);
@@ -437,21 +428,15 @@ App::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform
App::setResource('getLogsDB', function (Group $pools, Cache $cache) {
$database = null;
return function (?Document $project = null) use ($pools, $cache, $database) {
return function (?Document $project = null) use ($pools, $cache, &$database) {
if ($database !== null && $project !== null && !$project->isEmpty() && $project->getId() !== 'console') {
$database->setTenant($project->getInternalId());
$database->setTenant($project->getSequence());
return $database;
}
$dbAdapter = $pools
->get('logs')
->pop()
->getResource();
$database = new Database(
$dbAdapter,
$cache
);
$adapter = new DatabasePool($pools->get('logs'));
$database = new Database($adapter, $cache);
$database
->setSharedTables(true)
@@ -461,7 +446,7 @@ App::setResource('getLogsDB', function (Group $pools, Cache $cache) {
// set tenant
if ($project !== null && !$project->isEmpty() && $project->getId() !== 'console') {
$database->setTenant($project->getInternalId());
$database->setTenant($project->getSequence());
}
return $database;
@@ -470,19 +455,18 @@ App::setResource('getLogsDB', function (Group $pools, Cache $cache) {
App::setResource('telemetry', fn () => new NoTelemetry());
App::setResource('cache', function (Group $pools) {
App::setResource('cache', function (Group $pools, Telemetry $telemetry) {
$list = Config::getParam('pools-cache', []);
$adapters = [];
foreach ($list as $value) {
$adapters[] = $pools
->get($value)
->pop()
->getResource();
$adapters[] = new CachePool($pools->get($value));
}
return new Cache(new Sharding($adapters));
}, ['pools']);
$cache = new Cache(new Sharding($adapters));
$cache->setTelemetry($telemetry);
return $cache;
}, ['pools', 'telemetry']);
App::setResource('redis', function () {
$host = System::getEnv('_APP_REDIS_HOST', 'localhost');
@@ -506,24 +490,23 @@ App::setResource('timelimit', function (\Redis $redis) {
}, ['redis']);
App::setResource('deviceForLocal', function (Telemetry $telemetry) {
return new Local();
return new Device\Telemetry($telemetry, new Local());
}, ['telemetry']);
App::setResource('deviceForFiles', function ($project) {
return getDevice(APP_STORAGE_UPLOADS . '/app-' . $project->getId());
}, ['project']);
App::setResource('deviceForSites', function ($project) {
return getDevice(APP_STORAGE_SITES . '/app-' . $project->getId());
}, ['project']);
App::setResource('deviceForImports', function ($project) {
return getDevice(APP_STORAGE_IMPORTS . '/app-' . $project->getId());
}, ['project']);
App::setResource('deviceForFunctions', function ($project) {
return getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $project->getId());
}, ['project']);
App::setResource('deviceForBuilds', function ($project) {
return getDevice(APP_STORAGE_BUILDS . '/app-' . $project->getId());
}, ['project']);
App::setResource('deviceForFiles', function ($project, Telemetry $telemetry) {
return new Device\Telemetry($telemetry, getDevice(APP_STORAGE_UPLOADS . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
App::setResource('deviceForSites', function ($project, Telemetry $telemetry) {
return new Device\Telemetry($telemetry, getDevice(APP_STORAGE_SITES . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
App::setResource('deviceForImports', function ($project, Telemetry $telemetry) {
return new Device\Telemetry($telemetry, getDevice(APP_STORAGE_IMPORTS . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
App::setResource('deviceForFunctions', function ($project, Telemetry $telemetry) {
return new Device\Telemetry($telemetry, getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
App::setResource('deviceForBuilds', function ($project, Telemetry $telemetry) {
return new Device\Telemetry($telemetry, getDevice(APP_STORAGE_BUILDS . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
function getDevice(string $root, string $connection = ''): Device
{
@@ -552,7 +535,8 @@ function getDevice(string $root, string $connection = ''): Device
switch ($device) {
case Storage::DEVICE_S3:
if (!empty($url)) {
return new S3($root, $accessKey, $accessSecret, $url, $region, $acl);
$bucketRoot = (!empty($bucket) ? $bucket . '/' : '') . \ltrim($root, '/');
return new S3($bucketRoot, $accessKey, $accessSecret, $url, $region, $acl);
} else {
return new AWS($root, $accessKey, $accessSecret, $bucket, $region, $acl);
}
@@ -584,7 +568,8 @@ function getDevice(string $root, string $connection = ''): Device
$s3Acl = 'private';
$s3EndpointUrl = System::getEnv('_APP_STORAGE_S3_ENDPOINT', '');
if (!empty($s3EndpointUrl)) {
return new S3($root, $s3AccessKey, $s3SecretKey, $s3EndpointUrl, $s3Region, $s3Acl);
$bucketRoot = (!empty($s3Bucket) ? $s3Bucket . '/' : '') . \ltrim($root, '/');
return new S3($bucketRoot, $s3AccessKey, $s3SecretKey, $s3EndpointUrl, $s3Region, $s3Acl);
} else {
return new AWS($root, $s3AccessKey, $s3SecretKey, $s3Bucket, $s3Region, $s3Acl);
}
@@ -854,7 +839,7 @@ App::setResource('team', function (Document $project, Database $dbForPlatform, A
$team = Authorization::skip(function () use ($dbForPlatform, $teamInternalId) {
return $dbForPlatform->findOne('teams', [
Query::equal('$internalId', [$teamInternalId]),
Query::equal('$sequence', [$teamInternalId]),
]);
});
@@ -895,7 +880,7 @@ App::setResource('apiKey', function (Request $request, Document $project): ?Key
return Key::decode($project, $key);
}, ['request', 'project']);
App::setResource('executor', fn () => new Executor(fn (string $projectId, string $deploymentId) => System::getEnv('_APP_EXECUTOR_HOST')));
App::setResource('executor', fn () => new Executor());
App::setResource('resourceToken', function ($project, $dbForProject, $request) {
$tokenJWT = $request->getParam('token');
@@ -933,10 +918,10 @@ App::setResource('resourceToken', function ($project, $dbForProject, $request) {
return match ($token->getAttribute('resourceType')) {
TOKENS_RESOURCE_TYPE_FILES => (function () use ($token, $dbForProject) {
$internalIds = explode(':', $token->getAttribute('resourceInternalId'));
$sequences = explode(':', $token->getAttribute('resourceInternalId'));
$ids = explode(':', $token->getAttribute('resourceId'));
if (count($internalIds) !== 2 || count($ids) !== 2) {
if (count($sequences) !== 2 || count($ids) !== 2) {
return new Document([]);
}
@@ -949,8 +934,8 @@ App::setResource('resourceToken', function ($project, $dbForProject, $request) {
return new Document([
'bucketId' => $ids[0],
'fileId' => $ids[1],
'bucketInternalId' => $internalIds[0],
'fileInternalId' => $internalIds[1],
'bucketInternalId' => $sequences[0],
'fileInternalId' => $sequences[1],
]);
})(),
+67 -47
View File
@@ -5,6 +5,7 @@ use Appwrite\Extend\Exception;
use Appwrite\Extend\Exception as AppwriteException;
use Appwrite\Messaging\Adapter\Realtime;
use Appwrite\Network\Validator\Origin;
use Appwrite\PubSub\Adapter\Pool as PubSubPool;
use Appwrite\Utopia\Request;
use Appwrite\Utopia\Response;
use Swoole\Http\Request as SwooleRequest;
@@ -15,10 +16,12 @@ use Swoole\Timer;
use Utopia\Abuse\Abuse;
use Utopia\Abuse\Adapters\TimeLimit\Redis as TimeLimitRedis;
use Utopia\App;
use Utopia\Cache\Adapter\Pool as CachePool;
use Utopia\Cache\Adapter\Sharding;
use Utopia\Cache\Cache;
use Utopia\CLI\Console;
use Utopia\Config\Config;
use Utopia\Database\Adapter\Pool as DatabasePool;
use Utopia\Database\Database;
use Utopia\Database\DateTime;
use Utopia\Database\Document;
@@ -28,13 +31,15 @@ use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\DSN\DSN;
use Utopia\Logger\Log;
use Utopia\Pools\Group;
use Utopia\Registry\Registry;
use Utopia\System\System;
use Utopia\Telemetry\Adapter\None as NoTelemetry;
use Utopia\WebSocket\Adapter;
use Utopia\WebSocket\Server;
/**
* @var \Utopia\Registry\Registry $register
* @var Registry $register
*/
require_once __DIR__ . '/init.php';
@@ -46,17 +51,17 @@ if (!function_exists('getConsoleDB')) {
{
global $register;
/** @var \Utopia\Pools\Group $pools */
static $database = null;
if ($database !== null) {
return $database;
}
/** @var Group $pools */
$pools = $register->get('pools');
$dbAdapter = $pools
->get('console')
->pop()
->getResource()
;
$database = new Database($dbAdapter, getCache());
$adapter = new DatabasePool($pools->get('console'));
$database = new Database($adapter, getCache());
$database
->setNamespace('_console')
->setMetadata('host', \gethostname())
@@ -72,7 +77,13 @@ if (!function_exists('getProjectDB')) {
{
global $register;
/** @var \Utopia\Pools\Group $pools */
static $databases = [];
if (isset($databases[$project->getSequence()])) {
return $databases[$project->getSequence()];
}
/** @var Group $pools */
$pools = $register->get('pools');
if ($project->isEmpty() || $project->getId() === 'console') {
@@ -86,11 +97,7 @@ if (!function_exists('getProjectDB')) {
$dsn = new DSN('mysql://' . $project->getAttribute('database'));
}
$adapter = $pools
->get($dsn->getHost())
->pop()
->getResource();
$adapter = new DatabasePool($pools->get($dsn->getHost()));
$database = new Database($adapter, getCache());
$sharedTables = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES', ''));
@@ -98,20 +105,20 @@ if (!function_exists('getProjectDB')) {
if (\in_array($dsn->getHost(), $sharedTables)) {
$database
->setSharedTables(true)
->setTenant($project->getInternalId())
->setTenant($project->getSequence())
->setNamespace($dsn->getParam('namespace'));
} else {
$database
->setSharedTables(false)
->setTenant(null)
->setNamespace('_' . $project->getInternalId());
->setNamespace('_' . $project->getSequence());
}
$database
->setMetadata('host', \gethostname())
->setMetadata('project', $project->getId());
return $database;
return $databases[$project->getSequence()] = $database;
}
}
@@ -121,20 +128,22 @@ if (!function_exists('getCache')) {
{
global $register;
$pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */
static $cache = null;
if ($cache !== null) {
return $cache;
}
$pools = $register->get('pools'); /** @var Group $pools */
$list = Config::getParam('pools-cache', []);
$adapters = [];
foreach ($list as $value) {
$adapters[] = $pools
->get($value)
->pop()
->getResource()
;
$adapters[] = new CachePool($pools->get($value));
}
return new Cache(new Sharding($adapters));
return $cache = new Cache(new Sharding($adapters));
}
}
@@ -142,6 +151,12 @@ if (!function_exists('getCache')) {
if (!function_exists('getRedis')) {
function getRedis(): \Redis
{
static $redis = null;
if ($redis !== null) {
return $redis;
}
$host = System::getEnv('_APP_REDIS_HOST', 'localhost');
$port = System::getEnv('_APP_REDIS_PORT', 6379);
$pass = System::getEnv('_APP_REDIS_PASS', '');
@@ -160,21 +175,39 @@ if (!function_exists('getRedis')) {
if (!function_exists('getTimelimit')) {
function getTimelimit(): TimeLimitRedis
{
return new TimeLimitRedis("", 0, 1, getRedis());
static $timelimit = null;
if ($timelimit !== null) {
return $timelimit;
}
return $timelimit = new TimeLimitRedis("", 0, 1, getRedis());
}
}
if (!function_exists('getRealtime')) {
function getRealtime(): Realtime
{
return new Realtime();
static $realtime = null;
if ($realtime !== null) {
return $realtime;
}
return $realtime = new Realtime();
}
}
if (!function_exists('getTelemetry')) {
function getTelemetry(int $workerId): Utopia\Telemetry\Adapter
{
return new NoTelemetry();
static $telemetry = null;
if ($telemetry !== null) {
return $telemetry;
}
return $telemetry = new NoTelemetry();
}
}
@@ -273,7 +306,6 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume
sleep(DATABASE_RECONNECT_SLEEP);
}
} while (true);
$register->get('pools')->reclaim();
});
/**
@@ -299,9 +331,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume
Authorization::skip(fn () => $database->updateDocument('realtime', $statsDocument->getId(), $statsDocument));
} catch (Throwable $th) {
call_user_func($logError, $th, "updateWorkerDocument");
} finally {
$register->get('pools')->reclaim();
$logError($th, "updateWorkerDocument");
}
});
}
@@ -370,8 +400,6 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
'data' => $event['data']
]));
}
$register->get('pools')->reclaim();
}
}
/**
@@ -407,8 +435,8 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
}
$start = time();
/** @var \Appwrite\PubSub\Adapter $pubsub */
$pubsub = $register->get('pools')->get('pubsub')->pop()->getResource();
$pubsub = new PubSubPool($register->get('pools')->get('pubsub'));
if ($pubsub->ping(true)) {
$attempts = 0;
Console::success('Pub/sub connection established (worker: ' . $workerId . ')');
@@ -436,8 +464,6 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
$realtime->unsubscribe($connection);
$realtime->subscribe($projectId, $connection, $roles, $channels);
$register->get('pools')->reclaim();
}
}
@@ -463,14 +489,12 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
}
});
} catch (Throwable $th) {
call_user_func($logError, $th, "pubSubConnection");
$logError($th, "pubSubConnection");
Console::error('Pub/sub error: ' . $th->getMessage());
$attempts++;
sleep(DATABASE_RECONNECT_SLEEP);
continue;
} finally {
$register->get('pools')->reclaim();
}
}
@@ -572,7 +596,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
$stats->incr($project->getId(), 'connections');
$stats->incr($project->getId(), 'connectionsTotal');
} catch (Throwable $th) {
call_user_func($logError, $th, "initServer");
$logError($th, "initServer");
// Handle SQL error code is 'HY000'
$code = $th->getCode();
@@ -596,8 +620,6 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
Console::error('[Error] Code: ' . $response['data']['code']);
Console::error('[Error] Message: ' . $response['data']['message']);
}
} finally {
$register->get('pools')->reclaim();
}
});
@@ -696,8 +718,6 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
if ($th->getCode() === 1008) {
$server->close($connection, $th->getCode());
}
} finally {
$register->get('pools')->reclaim();
}
});
-31
View File
@@ -151,37 +151,6 @@
<div class="center"><a href="/"><button>Go to homepage</button></a></div>
</div>
</div>
<div class="brand">
<p>Powered by</p>
<svg class="logo-dark" width="110" height="20" viewBox="0 0 110 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M31.8649 16.2461C33.6492 16.2461 34.5511 15.3184 34.9433 14.6867H35.1197C35.1981 15.3578 35.6687 15.9895 36.5903 15.9895H38.3353V14.0156H37.8843C37.5706 14.0156 37.4138 13.838 37.4138 13.5617V5.64661H35.1001V6.90986H34.9236C34.4727 6.27823 33.5315 5.39001 31.8061 5.39001C29.0611 5.39001 27.022 7.67965 27.022 10.818C27.022 13.9564 29.1003 16.2461 31.8649 16.2461ZM32.2767 13.9959C30.6493 13.9959 29.3748 12.7919 29.3748 10.8378C29.3748 8.92316 30.6101 7.62044 32.2571 7.62044C33.8256 7.62044 35.1393 8.78499 35.1393 10.8378C35.1393 12.5945 34.0217 13.9959 32.2767 13.9959Z" fill="#EDEDF0" />
<path d="M39.7013 20H42.0149V14.6867H42.1914C42.6227 15.3184 43.5443 16.2461 45.3677 16.2461C48.1127 16.2461 50.1127 13.9169 50.1127 10.818C50.1127 7.69939 47.9755 5.39001 45.2109 5.39001C43.4462 5.39001 42.5835 6.35719 42.1718 6.89012H41.9953V5.64661H39.7013V20ZM44.8776 14.0551C43.2894 14.0551 41.9757 12.8708 41.9757 10.818C41.9757 9.06133 43.0933 7.58096 44.8383 7.58096C46.4657 7.58096 47.7402 8.86395 47.7402 10.818C47.7402 12.7326 46.5049 14.0551 44.8776 14.0551Z" fill="#EDEDF0" />
<path d="M51.3065 20H53.6202V14.6867H53.7966C54.228 15.3184 55.1495 16.2461 56.973 16.2461C59.718 16.2461 61.5273 13.9169 61.5273 10.818C61.5273 7.69939 59.5807 5.39001 56.8161 5.39001C55.0515 5.39001 54.1888 6.35719 53.777 6.89012H53.6005V5.64661H51.3065V20ZM56.4828 14.0551C54.8946 14.0551 53.5809 12.8708 53.5809 10.818C53.5809 9.06133 54.6985 7.58096 56.4436 7.58096C58.071 7.58096 59.3454 8.86395 59.3454 10.818C59.3454 12.7326 58.1102 14.0551 56.4828 14.0551Z" fill="#EDEDF0" />
<path d="M64.5857 16.2296H67.8601L69.7227 8.11721H69.8404L71.7031 16.2296H74.9579L77.5642 5.88678H75.2323L73.3697 14.0189H73.1932L71.3305 5.88678H68.2522L66.3699 14.0189H66.1935L64.3504 5.88678H61.8799L64.5857 16.2296Z" fill="#EDEDF0" />
<path d="M78.7363 16.2296H81.0499V11.1174C81.0499 9.16334 81.9519 7.9593 83.6381 7.9593H84.6576V5.63019H83.893C82.5793 5.63019 81.5793 6.53815 81.1872 7.40663H81.0303V5.88678H78.7363V16.2296Z" fill="#EDEDF0" />
<path d="M96.1391 16.2296H97.943V14.1571H96.1587C95.4529 14.1571 95.1588 13.8413 95.1588 13.111V7.93956H98.0606V5.88678H95.1588V2.98526H92.9628V5.88678H91.0413V7.93956H92.8255V13.1307C92.8255 15.3217 94.1392 16.2296 96.1391 16.2296Z" fill="#EDEDF0" />
<path d="M104.15 16.2461C106.287 16.2461 108.17 15.1802 108.836 13.0287L106.719 12.5155C106.346 13.6603 105.268 14.2525 104.13 14.2525C102.444 14.2525 101.327 13.1472 101.307 11.4102H109.091V10.7588C109.091 7.67965 107.189 5.39001 104.052 5.39001C101.287 5.39001 98.915 7.58096 98.915 10.8378C98.915 13.9959 101.013 16.2461 104.15 16.2461ZM101.327 9.71269C101.464 8.46918 102.581 7.42305 104.052 7.42305C105.464 7.42305 106.621 8.31128 106.738 9.71269H101.327Z" fill="#EDEDF0" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M90.0125 16.2296H87.6989V7.93956H85.895V5.88678H90.0125V16.2296Z" fill="#EDEDF0" />
<path d="M88.6834 4.45145C89.5265 4.45145 90.154 3.81983 90.154 2.99082C90.154 2.18155 89.5265 1.54993 88.6834 1.54993C87.8403 1.54993 87.2129 2.18155 87.2129 2.99082C87.2129 3.81983 87.8403 4.45145 88.6834 4.45145Z" fill="#EDEDF0" />
<path d="M20.2007 13.6935V18.258H8.88588C5.5894 18.258 2.71111 16.4222 1.17116 13.6935C0.947288 13.2968 0.751353 12.8806 0.586995 12.4486C0.26435 11.6021 0.0615332 10.6938 0 9.74603V8.51195C0.0133592 8.30074 0.03441 8.09119 0.0619381 7.88413C0.118209 7.45921 0.203222 7.04343 0.314953 6.63926C1.37195 2.80758 4.8089 0 8.88588 0C12.9629 0 16.3994 2.80758 17.4564 6.63926H12.6184C11.8241 5.39025 10.4493 4.5645 8.88588 4.5645C7.32245 4.5645 5.94767 5.39025 5.15341 6.63926C4.91132 7.01895 4.72349 7.43764 4.60042 7.88413C4.49112 8.27999 4.43282 8.69744 4.43282 9.12899C4.43282 10.4373 4.96962 11.6166 5.83027 12.4486C6.62778 13.2209 7.70299 13.6935 8.88588 13.6935H20.2007Z" fill="#FD366E" />
<path d="M20.2006 7.88412V12.4486H11.9414C12.8021 11.6166 13.3389 10.4373 13.3389 9.12899C13.3389 8.69744 13.2806 8.27999 13.1713 7.88412H20.2006Z" fill="#FD366E" />
</svg>
<svg class="logo-light" width="110" height="20" viewBox="0 0 110 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M31.8648 16.2461C33.649 16.2461 34.5509 15.3184 34.9431 14.6867H35.1195C35.198 15.3578 35.6685 15.9895 36.5901 15.9895H38.3351V14.0156H37.8841C37.5704 14.0156 37.4136 13.838 37.4136 13.5617V5.64661H35.0999V6.90986H34.9235C34.4725 6.27823 33.5314 5.39001 31.8059 5.39001C29.0609 5.39001 27.0218 7.67965 27.0218 10.818C27.0218 13.9564 29.1001 16.2461 31.8648 16.2461ZM32.2765 13.9959C30.6491 13.9959 29.3746 12.7919 29.3746 10.8378C29.3746 8.92316 30.6099 7.62044 32.2569 7.62044C33.8255 7.62044 35.1391 8.78499 35.1391 10.8378C35.1391 12.5945 34.0215 13.9959 32.2765 13.9959Z" fill="#2D2D31" />
<path d="M39.7011 20H42.0147V14.6867H42.1912C42.6226 15.3184 43.5441 16.2461 45.3676 16.2461C48.1126 16.2461 50.1125 13.9169 50.1125 10.818C50.1125 7.69939 47.9753 5.39001 45.2107 5.39001C43.4461 5.39001 42.5833 6.35719 42.1716 6.89012H41.9951V5.64661H39.7011V20ZM44.8774 14.0551C43.2892 14.0551 41.9755 12.8708 41.9755 10.818C41.9755 9.06133 43.0931 7.58096 44.8382 7.58096C46.4656 7.58096 47.74 8.86395 47.74 10.818C47.74 12.7326 46.5048 14.0551 44.8774 14.0551Z" fill="#2D2D31" />
<path d="M51.3063 20H53.62V14.6867H53.7964C54.2278 15.3184 55.1493 16.2461 56.9728 16.2461C59.7178 16.2461 61.5271 13.9169 61.5271 10.818C61.5271 7.69939 59.5805 5.39001 56.8159 5.39001C55.0513 5.39001 54.1886 6.35719 53.7768 6.89012H53.6004V5.64661H51.3063V20ZM56.4826 14.0551C54.8944 14.0551 53.5808 12.8708 53.5808 10.818C53.5808 9.06133 54.6984 7.58096 56.4434 7.58096C58.0708 7.58096 59.3453 8.86395 59.3453 10.818C59.3453 12.7326 58.11 14.0551 56.4826 14.0551Z" fill="#2D2D31" />
<path d="M64.5855 16.2296H67.8599L69.7226 8.11721H69.8402L71.7029 16.2296H74.9577L77.564 5.88678H75.2322L73.3695 14.0189H73.193L71.3303 5.88678H68.252L66.3697 14.0189H66.1933L64.3502 5.88678H61.8797L64.5855 16.2296Z" fill="#2D2D31" />
<path d="M78.7361 16.2296H81.0498V11.1174C81.0498 9.16334 81.9517 7.9593 83.6379 7.9593H84.6575V5.63019H83.8928C82.5791 5.63019 81.5791 6.53815 81.187 7.40663H81.0301V5.88678H78.7361V16.2296Z" fill="#2D2D31" />
<path d="M96.1389 16.2296H97.9428V14.1571H96.1585C95.4527 14.1571 95.1586 13.8413 95.1586 13.111V7.93956H98.0604V5.88678H95.1586V2.98526H92.9626V5.88678H91.0411V7.93956H92.8253V13.1307C92.8253 15.3217 94.139 16.2296 96.1389 16.2296Z" fill="#2D2D31" />
<path d="M104.15 16.2461C106.287 16.2461 108.169 15.1802 108.836 13.0287L106.718 12.5155C106.346 13.6603 105.268 14.2525 104.13 14.2525C102.444 14.2525 101.326 13.1472 101.307 11.4102H109.091V10.7588C109.091 7.67965 107.189 5.39001 104.052 5.39001C101.287 5.39001 98.9148 7.58096 98.9148 10.8378C98.9148 13.9959 101.013 16.2461 104.15 16.2461ZM101.326 9.71269C101.464 8.46918 102.581 7.42305 104.052 7.42305C105.464 7.42305 106.62 8.31128 106.738 9.71269H101.326Z" fill="#2D2D31" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M90.0123 16.2296H87.6987V7.93956H85.8948V5.88678H90.0123V16.2296Z" fill="#2D2D31" />
<path d="M88.6835 4.45145C89.5266 4.45145 90.154 3.81983 90.154 2.99082C90.154 2.18155 89.5266 1.54993 88.6835 1.54993C87.8404 1.54993 87.213 2.18155 87.213 2.99082C87.213 3.81983 87.8404 4.45145 88.6835 4.45145Z" fill="#2D2D31" />
<path d="M20.2007 13.6935V18.258H8.88588C5.5894 18.258 2.71111 16.4222 1.17116 13.6935C0.947288 13.2968 0.751353 12.8806 0.586995 12.4486C0.26435 11.6021 0.0615332 10.6938 0 9.74603V8.51195C0.0133592 8.30074 0.03441 8.09119 0.0619381 7.88413C0.118209 7.45921 0.203222 7.04343 0.314953 6.63926C1.37195 2.80758 4.8089 0 8.88588 0C12.9629 0 16.3994 2.80758 17.4564 6.63926H12.6184C11.8241 5.39025 10.4493 4.5645 8.88588 4.5645C7.32245 4.5645 5.94767 5.39025 5.15341 6.63926C4.91132 7.01895 4.72349 7.43764 4.60042 7.88413C4.49112 8.27999 4.43282 8.69744 4.43282 9.12899C4.43282 10.4373 4.96962 11.6166 5.83027 12.4486C6.62778 13.2209 7.70299 13.6935 8.88588 13.6935H20.2007Z" fill="#FD366E" />
<path d="M20.2007 7.88412V12.4486H11.9415C12.8022 11.6166 13.339 10.4373 13.339 9.12899C13.339 8.69744 13.2807 8.27999 13.1714 7.88412H20.2007Z" fill="#FD366E" />
</svg>
</div>
</body>
</html>
+28 -56
View File
@@ -479,67 +479,39 @@ switch ($type) {
</div>
</div>
<div x-show="page === 'trace'" class="error-trace">
<button class="back-button" x-on:click="page = 'error'">
Back
</button>
<div class="trace-grid-header">Error trace</div>
<?php foreach ($trace as $index => $traceItem): ?>
<div class="trace-grid">
<?php if (isset($traceItem['file'])): ?>
<div class="trace-label">file</div>
<div class="trace-value"><?php echo $this->print($traceItem['file']); ?></div>
<?php endif; ?>
<?php if ($development) : ?>
<div x-show="page === 'trace'" class="error-trace">
<button class="back-button" x-on:click="page = 'error'">
Back
</button>
<div class="trace-grid-header">Error trace</div>
<?php foreach ($trace as $index => $traceItem): ?>
<div class="trace-grid">
<?php if (isset($traceItem['file'])): ?>
<div class="trace-label">file</div>
<div class="trace-value"><?php echo $this->print($traceItem['file']); ?></div>
<?php endif; ?>
<?php if (isset($traceItem['line'])): ?>
<div class="trace-label">line</div>
<div class="trace-value"><?php echo $this->print($traceItem['line']); ?></div>
<?php endif; ?>
<?php if (isset($traceItem['line'])): ?>
<div class="trace-label">line</div>
<div class="trace-value"><?php echo $this->print($traceItem['line']); ?></div>
<?php endif; ?>
<?php if (isset($traceItem['function'])): ?>
<div class="trace-label">function</div>
<div class="trace-value"><?php echo $this->print($traceItem['function']); ?></div>
<?php endif; ?>
<?php if (isset($traceItem['function'])): ?>
<div class="trace-label">function</div>
<div class="trace-value"><?php echo $this->print($traceItem['function']); ?></div>
<?php endif; ?>
<?php if (isset($traceItem['args'])): ?>
<div class="trace-label">args</div>
<div class="trace-args"><pre><?php echo $this->print(\var_export($traceItem['args'], true)); ?></pre></div>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
<?php if (isset($traceItem['args'])): ?>
<div class="trace-label">args</div>
<div class="trace-args"><pre><?php echo $this->print(\var_export($traceItem['args'], true)); ?></pre></div>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<div x-show="page === 'error'" class="brand">
<p>Powered by</p>
<svg class="logo-dark" width="110" height="20" viewBox="0 0 110 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M31.8649 16.2461C33.6492 16.2461 34.5511 15.3184 34.9433 14.6867H35.1197C35.1981 15.3578 35.6687 15.9895 36.5903 15.9895H38.3353V14.0156H37.8843C37.5706 14.0156 37.4138 13.838 37.4138 13.5617V5.64661H35.1001V6.90986H34.9236C34.4727 6.27823 33.5315 5.39001 31.8061 5.39001C29.0611 5.39001 27.022 7.67965 27.022 10.818C27.022 13.9564 29.1003 16.2461 31.8649 16.2461ZM32.2767 13.9959C30.6493 13.9959 29.3748 12.7919 29.3748 10.8378C29.3748 8.92316 30.6101 7.62044 32.2571 7.62044C33.8256 7.62044 35.1393 8.86395 35.1393 10.8378C35.1393 12.5945 34.0217 13.9959 32.2767 13.9959Z" fill="#EDEDF0" />
<path d="M39.7013 20H42.0149V14.6867H42.1914C42.6227 15.3184 43.5443 16.2461 45.3677 16.2461C48.1127 16.2461 50.1127 13.9169 50.1127 10.818C50.1127 7.69939 47.9755 5.39001 45.2109 5.39001C43.4462 5.39001 42.5835 6.35719 42.1718 6.89012H41.9953V5.63019H39.7013V20ZM44.8776 14.0551C43.2894 14.0551 41.9757 12.8708 41.9757 10.818C41.9757 9.06133 43.0933 7.58096 44.8383 7.58096C46.4657 7.58096 47.7402 8.86395 47.7402 10.818C47.7402 12.7326 46.5049 14.0551 44.8776 14.0551Z" fill="#EDEDF0" />
<path d="M51.3065 20H53.6202V14.6867H53.7966C54.228 15.3184 55.1495 16.2461 56.973 16.2461C59.718 16.2461 61.5273 13.9169 61.5273 10.818C61.5273 7.69939 59.5807 5.39001 56.8161 5.39001C55.0515 5.39001 54.1888 6.35719 53.777 6.89012H53.6005V5.64661H51.3065V20ZM56.4828 14.0551C54.8946 14.0551 53.5809 12.8708 53.5809 10.818C53.5809 9.06133 54.6985 7.58096 56.4436 7.58096C58.071 7.58096 59.3454 8.86395 59.3454 10.818C59.3454 12.7326 58.1102 14.0551 56.4828 14.0551Z" fill="#EDEDF0" />
<path d="M64.5857 16.2296H67.8601L69.7227 8.11721H69.8404L71.7031 16.2296H74.9579L77.5642 5.88678H75.2323L73.3697 14.0189H73.1932L71.3305 5.88678H68.2522L66.3699 14.0189H66.1935L64.3504 5.88678H61.8799L64.5857 16.2296Z" fill="#EDEDF0" />
<path d="M78.7363 16.2296H81.0499V11.1174C81.0499 9.16334 81.9519 7.9593 83.6381 7.9593H84.6576V5.63019H83.893C82.5793 5.63019 81.5793 6.53815 81.1872 7.40663H81.0303V5.88678H78.7363V16.2296Z" fill="#EDEDF0" />
<path d="M96.1391 16.2296H97.943V14.1571H96.1587C95.4529 14.1571 95.1588 13.8413 95.1588 13.111V7.93956H98.0606V5.88678H95.1588V2.98526H92.9628V5.88678H91.0413V7.93956H92.8255V13.1307C92.8255 15.3217 94.1392 16.2296 96.1391 16.2296Z" fill="#EDEDF0" />
<path d="M104.15 16.2461C106.287 16.2461 108.17 15.1802 108.836 13.0287L106.719 12.5155C106.346 13.6603 105.268 14.2525 104.13 14.2525C102.444 14.2525 101.327 13.1472 101.307 11.4102H109.091V10.7588C109.091 7.67965 107.189 5.39001 104.052 5.39001C101.287 5.39001 98.915 7.58096 98.915 10.8378C98.915 13.9959 101.013 16.2461 104.15 16.2461ZM101.327 9.71269C101.464 8.46918 102.581 7.42305 104.052 7.42305C105.464 7.42305 106.621 8.31128 106.738 9.71269H101.327Z" fill="#EDEDF0" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M90.0125 16.2296H87.6989V7.93956H85.895V5.88678H90.0125V16.2296Z" fill="#EDEDF0" />
<path d="M88.6834 4.45145C89.5265 4.45145 90.154 3.81983 90.154 2.99082C90.154 2.18155 89.5265 1.54993 88.6834 1.54993C87.8403 1.54993 87.2129 2.18155 87.2129 2.99082C87.2129 3.81983 87.8403 4.45145 88.6834 4.45145Z" fill="#EDEDF0" />
<path d="M20.2007 13.6935V18.258H8.88588C5.5894 18.258 2.71111 16.4222 1.17116 13.6935C0.947288 13.2968 0.751353 12.8806 0.586995 12.4486C0.26435 11.6021 0.0615332 10.6938 0 9.74603V8.51195C0.0133592 8.30074 0.03441 8.09119 0.0619381 7.88413C0.118209 7.45921 0.203222 7.04343 0.314953 6.63926C1.37195 2.80758 4.8089 0 8.88588 0C12.9629 0 16.3994 2.80758 17.4564 6.63926H12.6184C11.8241 5.39025 10.4493 4.5645 8.88588 4.5645C7.32245 4.5645 5.94767 5.39025 5.15341 6.63926C4.91132 7.01895 4.72349 7.43764 4.60042 7.88413C4.49112 8.27999 4.43282 8.69744 4.43282 9.12899C4.43282 10.4373 4.96962 11.6166 5.83027 12.4486C6.62778 13.2209 7.70299 13.6935 8.88588 13.6935H20.2007Z" fill="#FD366E" />
<path d="M20.2006 7.88412V12.4486H11.9414C12.8021 11.6166 13.3389 10.4373 13.3389 9.12899C13.3389 8.69744 13.2806 8.27999 13.1713 7.88412H20.2006Z" fill="#FD366E" />
</svg>
<svg class="logo-light" width="110" height="20" viewBox="0 0 110 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M31.8648 16.2461C33.649 16.2461 34.5509 15.3184 34.9431 14.6867H35.1195C35.198 15.3578 35.6685 15.9895 36.5901 15.9895H38.3351V14.0156H37.8841C37.5704 14.0156 37.4136 13.838 37.4136 13.5617V5.64661H35.0999V6.90986H34.9235C34.4725 6.27823 33.5314 5.39001 31.8059 5.39001C29.0609 5.39001 27.0218 7.67965 27.0218 10.818C27.0218 13.9564 29.1001 16.2461 31.8648 16.2461ZM32.2765 13.9959C30.6491 13.9959 29.3746 12.7919 29.3746 10.8378C29.3746 8.92316 30.6099 7.62044 32.2569 7.62044C33.8255 7.62044 35.1391 8.78499 35.1391 10.8378C35.1391 12.5945 34.0215 13.9959 32.2765 13.9959Z" fill="#2D2D31" />
<path d="M39.7011 20H42.0147V14.6867H42.1912C42.6226 15.3184 43.5441 16.2461 45.3676 16.2461C48.1126 16.2461 50.1125 13.9169 50.1125 10.818C50.1125 7.69939 47.9753 5.39001 45.2107 5.39001C43.4461 5.39001 42.5833 6.35719 42.1716 6.89012H41.9951V5.64661H39.7011V20ZM44.8774 14.0551C43.2892 14.0551 41.9755 12.8708 41.9755 10.818C41.9755 9.06133 43.0931 7.58096 44.8382 7.58096C46.4656 7.58096 47.74 8.86395 47.74 10.818C47.74 12.7326 46.5048 14.0551 44.8774 14.0551Z" fill="#2D2D31" />
<path d="M51.3063 20H53.62V14.6867H53.7964C54.2278 15.3184 55.1493 16.2461 56.9728 16.2461C59.7178 16.2461 61.5271 13.9169 61.5271 10.818C61.5271 7.69939 59.5805 5.39001 56.8159 5.39001C55.0513 5.39001 54.1886 6.35719 53.7768 6.89012H53.6004V5.64661H51.3063V20ZM56.4826 14.0551C54.8944 14.0551 53.5808 12.8708 53.5808 10.818C53.5808 9.06133 54.6984 7.58096 56.4434 7.58096C58.0708 7.58096 59.3453 8.86395 59.3453 10.818C59.3453 12.7326 58.11 14.0551 56.4826 14.0551Z" fill="#2D2D31" />
<path d="M64.5855 16.2296H67.8599L69.7226 8.11721H69.8402L71.7029 16.2296H74.9577L77.564 5.88678H75.2322L73.3695 14.0189H73.193L71.3303 5.88678H68.252L66.3697 14.0189H66.1933L64.3502 5.88678H61.8797L64.5855 16.2296Z" fill="#2D2D31" />
<path d="M78.7361 16.2296H81.0498V11.1174C81.0498 9.16334 81.9517 7.9593 83.6379 7.9593H84.6575V5.63019H83.8928C82.5791 5.63019 81.5791 6.53815 81.187 7.40663H81.0301V5.88678H78.7361V16.2296Z" fill="#2D2D31" />
<path d="M96.1389 16.2296H97.9428V14.1571H96.1585C95.4527 14.1571 95.1586 13.8413 95.1586 13.111V7.93956H98.0604V5.88678H95.1586V2.98526H92.9626V5.88678H91.0411V7.93956H92.8253V13.1307C92.8253 15.3217 94.139 16.2296 96.1389 16.2296Z" fill="#2D2D31" />
<path d="M104.15 16.2461C106.287 16.2461 108.169 15.1802 108.836 13.0287L106.718 12.5155C106.346 13.6603 105.268 14.2525 104.13 14.2525C102.444 14.2525 101.326 13.1472 101.307 11.4102H109.091V10.7588C109.091 7.67965 107.189 5.39001 104.052 5.39001C101.287 5.39001 98.9148 7.58096 98.9148 10.8378C98.9148 13.9959 101.013 16.2461 104.15 16.2461ZM101.326 9.71269C101.464 8.46918 102.581 7.42305 104.052 7.42305C105.464 7.42305 106.62 8.31128 106.738 9.71269H101.326Z" fill="#2D2D31" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M90.0123 16.2296H87.6987V7.93956H85.8948V5.88678H90.0123V16.2296Z" fill="#2D2D31" />
<path d="M88.6835 4.45145C89.5266 4.45145 90.154 3.81983 90.154 2.99082C90.154 2.18155 89.5266 1.54993 88.6835 1.54993C87.8404 1.54993 87.213 2.18155 87.213 2.99082C87.213 3.81983 87.8404 4.45145 88.6835 4.45145Z" fill="#2D2D31" />
<path d="M20.2007 13.6935V18.258H8.88588C5.5894 18.258 2.71111 16.4222 1.17116 13.6935C0.947288 13.2968 0.751353 12.8806 0.586995 12.4486C0.26435 11.6021 0.0615332 10.6938 0 9.74603V8.51195C0.0133592 8.30074 0.03441 8.09119 0.0619381 7.88413C0.118209 7.45921 0.203222 7.04343 0.314953 6.63926C1.37195 2.80758 4.8089 0 8.88588 0C12.9629 0 16.3994 2.80758 17.4564 6.63926H12.6184C11.8241 5.39025 10.4493 4.5645 8.88588 4.5645C7.32245 4.5645 5.94767 5.39025 5.15341 6.63926C4.91132 7.01895 4.72349 7.43764 4.60042 7.88413C4.49112 8.27999 4.43282 8.69744 4.43282 9.12899C4.43282 10.4373 4.96962 11.6166 5.83027 12.4486C6.62778 13.2209 7.70299 13.6935 8.88588 13.6935H20.2007Z" fill="#FD366E" />
<path d="M20.2007 7.88412V12.4486H11.9415C12.8022 11.6166 13.339 10.4373 13.339 9.12899C13.339 8.69744 13.2807 8.27999 13.1714 7.88412H20.2007Z" fill="#FD366E" />
</svg>
</div>
</body>
</html>
+3 -3
View File
@@ -177,7 +177,7 @@ $image = $this->getParam('image', '');
appwrite-console:
<<: *x-logging
container_name: appwrite-console
image: <?php echo $organization; ?>/console:6.0.1
image: <?php echo $organization; ?>/console:6.0.13
restart: unless-stopped
networks:
- appwrite
@@ -841,7 +841,7 @@ $image = $this->getParam('image', '');
- _APP_DB_PASS
appwrite-assistant:
image: appwrite/assistant:0.4.0
image: appwrite/assistant:0.8.3
container_name: appwrite-assistant
<<: *x-logging
restart: unless-stopped
@@ -864,7 +864,7 @@ $image = $this->getParam('image', '');
<<: *x-logging
restart: unless-stopped
stop_signal: SIGINT
image: openruntimes/executor:0.7.14
image: openruntimes/executor:0.7.20
networks:
- appwrite
- runtimes
+58 -81
View File
@@ -18,12 +18,16 @@ use Appwrite\Event\StatsUsage;
use Appwrite\Event\Webhook;
use Appwrite\Platform\Appwrite;
use Executor\Executor;
use Swoole\Process;
use Swoole\Runtime;
use Swoole\Timer;
use Utopia\Abuse\Adapters\TimeLimit\Redis as TimeLimitRedis;
use Utopia\Cache\Adapter\Pool as CachePool;
use Utopia\Cache\Adapter\Sharding;
use Utopia\Cache\Cache;
use Utopia\CLI\Console;
use Utopia\Config\Config;
use Utopia\Database\Adapter\Pool as DatabasePool;
use Utopia\Database\Database;
use Utopia\Database\DateTime;
use Utopia\Database\Document;
@@ -33,29 +37,28 @@ use Utopia\Logger\Log;
use Utopia\Logger\Logger;
use Utopia\Platform\Service;
use Utopia\Pools\Group;
use Utopia\Queue\Broker\Pool as BrokerPool;
use Utopia\Queue\Message;
use Utopia\Queue\Publisher;
use Utopia\Queue\Server;
use Utopia\Registry\Registry;
use Utopia\Storage\Device\Telemetry as TelemetryDevice;
use Utopia\System\System;
use Utopia\Telemetry\Adapter as Telemetry;
use Utopia\Telemetry\Adapter\None as NoTelemetry;
Authorization::disable();
Runtime::enableCoroutine(SWOOLE_HOOK_ALL);
Runtime::enableCoroutine();
Server::setResource('register', fn () => $register);
Server::setResource('dbForPlatform', function (Cache $cache, Registry $register) {
$pools = $register->get('pools');
$database = $pools
->get('console')
->pop()
->getResource();
$adapter = new DatabasePool($pools->get('console'));
$dbForPlatform = new Database($adapter, $cache);
$dbForPlatform->setNamespace('_console');
$adapter = new Database($database, $cache);
$adapter->setNamespace('_console');
return $adapter;
return $dbForPlatform;
}, ['cache', 'register']);
Server::setResource('project', function (Message $message, Database $dbForPlatform) {
@@ -83,32 +86,21 @@ Server::setResource('dbForProject', function (Cache $cache, Registry $register,
$dsn = new DSN('mysql://' . $project->getAttribute('database'));
}
$adapter = $pools
->get($dsn->getHost())
->pop()
->getResource();
$adapter = new DatabasePool($pools->get($dsn->getHost()));
$database = new Database($adapter, $cache);
try {
$dsn = new DSN($project->getAttribute('database'));
} catch (\InvalidArgumentException) {
// TODO: Temporary until all projects are using shared tables
$dsn = new DSN('mysql://' . $project->getAttribute('database'));
}
$sharedTables = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES', ''));
if (\in_array($dsn->getHost(), $sharedTables)) {
$database
->setSharedTables(true)
->setTenant($project->getInternalId())
->setTenant($project->getSequence())
->setNamespace($dsn->getParam('namespace'));
} else {
$database
->setSharedTables(false)
->setTenant(null)
->setNamespace('_' . $project->getInternalId());
->setNamespace('_' . $project->getSequence());
}
$database->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER);
@@ -139,24 +131,20 @@ Server::setResource('getProjectDB', function (Group $pools, Database $dbForPlatf
if (\in_array($dsn->getHost(), $sharedTables)) {
$database
->setSharedTables(true)
->setTenant($project->getInternalId())
->setTenant($project->getSequence())
->setNamespace($dsn->getParam('namespace'));
} else {
$database
->setSharedTables(false)
->setTenant(null)
->setNamespace('_' . $project->getInternalId());
->setNamespace('_' . $project->getSequence());
}
return $database;
}
$dbAdapter = $pools
->get($dsn->getHost())
->pop()
->getResource();
$database = new Database($dbAdapter, $cache);
$adapter = new DatabasePool($pools->get($dsn->getHost()));
$database = new Database($adapter, $cache);
$databases[$dsn->getHost()] = $database;
@@ -165,13 +153,13 @@ Server::setResource('getProjectDB', function (Group $pools, Database $dbForPlatf
if (\in_array($dsn->getHost(), $sharedTables)) {
$database
->setSharedTables(true)
->setTenant($project->getInternalId())
->setTenant($project->getSequence())
->setNamespace($dsn->getParam('namespace'));
} else {
$database
->setSharedTables(false)
->setTenant(null)
->setNamespace('_' . $project->getInternalId());
->setNamespace('_' . $project->getSequence());
}
$database->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER);
@@ -184,19 +172,12 @@ Server::setResource('getLogsDB', function (Group $pools, Cache $cache) {
$database = null;
return function (?Document $project = null) use ($pools, $cache, $database) {
if ($database !== null && $project !== null && !$project->isEmpty() && $project->getId() !== 'console') {
$database->setTenant($project->getInternalId());
$database->setTenant($project->getSequence());
return $database;
}
$dbAdapter = $pools
->get('logs')
->pop()
->getResource();
$database = new Database(
$dbAdapter,
$cache
);
$adapter = new DatabasePool($pools->get('logs'));
$database = new Database($adapter, $cache);
$database
->setSharedTables(true)
@@ -206,7 +187,7 @@ Server::setResource('getLogsDB', function (Group $pools, Cache $cache) {
// set tenant
if ($project !== null && !$project->isEmpty() && $project->getId() !== 'console') {
$database->setTenant($project->getInternalId());
$database->setTenant($project->getSequence());
}
return $database;
@@ -234,11 +215,7 @@ Server::setResource('cache', function (Registry $register) {
$adapters = [];
foreach ($list as $value) {
$adapters[] = $pools
->get($value)
->pop()
->getResource()
;
$adapters[] = new CachePool($pools->get($value));
}
return new Cache(new Sharding($adapters));
@@ -267,12 +244,13 @@ Server::setResource('timelimit', function (\Redis $redis) {
Server::setResource('log', fn () => new Log());
Server::setResource('publisher', function (Group $pools) {
return $pools->get('publisher')->pop()->getResource();
return new BrokerPool(publisher: $pools->get('publisher'));
}, ['pools']);
Server::setResource('consumer', function (Group $pools) {
return $pools->get('consumer')->pop()->getResource();
return new BrokerPool(consumer: $pools->get('consumer'));
}, ['pools']);
Server::setResource('queueForStatsUsage', function (Publisher $publisher) {
@@ -337,29 +315,29 @@ Server::setResource('pools', function (Registry $register) {
Server::setResource('telemetry', fn () => new NoTelemetry());
Server::setResource('deviceForSites', function (Document $project) {
return getDevice(APP_STORAGE_SITES . '/app-' . $project->getId());
}, ['project']);
Server::setResource('deviceForSites', function (Document $project, Telemetry $telemetry) {
return new TelemetryDevice($telemetry, getDevice(APP_STORAGE_SITES . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
Server::setResource('deviceForImports', function (Document $project) {
return getDevice(APP_STORAGE_IMPORTS . '/app-' . $project->getId());
}, ['project']);
Server::setResource('deviceForImports', function (Document $project, Telemetry $telemetry) {
return new TelemetryDevice($telemetry, getDevice(APP_STORAGE_IMPORTS . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
Server::setResource('deviceForFunctions', function (Document $project) {
return getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $project->getId());
}, ['project']);
Server::setResource('deviceForFunctions', function (Document $project, Telemetry $telemetry) {
return new TelemetryDevice($telemetry, getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
Server::setResource('deviceForFiles', function (Document $project) {
return getDevice(APP_STORAGE_UPLOADS . '/app-' . $project->getId());
}, ['project']);
Server::setResource('deviceForFiles', function (Document $project, Telemetry $telemetry) {
return new TelemetryDevice($telemetry, getDevice(APP_STORAGE_UPLOADS . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
Server::setResource('deviceForBuilds', function (Document $project) {
return getDevice(APP_STORAGE_BUILDS . '/app-' . $project->getId());
}, ['project']);
Server::setResource('deviceForBuilds', function (Document $project, Telemetry $telemetry) {
return new TelemetryDevice($telemetry, getDevice(APP_STORAGE_BUILDS . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
Server::setResource('deviceForCache', function (Document $project) {
return getDevice(APP_STORAGE_CACHE . '/app-' . $project->getId());
}, ['project']);
Server::setResource('deviceForCache', function (Document $project, Telemetry $telemetry) {
return new TelemetryDevice($telemetry, getDevice(APP_STORAGE_CACHE . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
Server::setResource(
'isResourceBlocked',
@@ -424,7 +402,7 @@ Server::setResource('logError', function (Registry $register, Document $project)
};
}, ['register', 'project']);
Server::setResource('executor', fn () => new Executor(fn (string $projectId, string $deploymentId) => System::getEnv('_APP_EXECUTOR_HOST')));
Server::setResource('executor', fn () => new Executor());
$pools = $register->get('pools');
$platform = new Appwrite();
@@ -463,13 +441,6 @@ try {
$worker = $platform->getWorker();
$worker
->shutdown()
->inject('pools')
->action(function (Group $pools) {
$pools->reclaim();
});
$worker
->error()
->inject('error')
@@ -477,8 +448,7 @@ $worker
->inject('log')
->inject('pools')
->inject('project')
->action(function (Throwable $error, ?Logger $logger, Log $log, Group $pools, Document $project) use ($queueName) {
$pools->reclaim();
->action(function (Throwable $error, ?Logger $logger, Log $log, Group $pools, Document $project) use ($worker, $queueName) {
$version = System::getEnv('_APP_VERSION', 'UNKNOWN');
if ($logger) {
@@ -514,8 +484,15 @@ $worker
});
$worker->workerStart()
->action(function () use ($workerName) {
Console::info("Worker $workerName started");
->action(function () use ($worker, $workerName) {
Console::info("Worker $workerName started");
Process::signal(SIGTERM, function () use ($worker, $workerName) {
Console::info("Stopping worker $workerName.");
$worker->stop();
Timer::clearAll();
});
});
$worker->start();
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php doctor $@
exec php /usr/src/code/app/cli.php doctor $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php install $@
exec php /usr/src/code/app/cli.php install $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php maintenance $@
exec php /usr/src/code/app/cli.php maintenance $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php migrate $@
exec php /usr/src/code/app/cli.php migrate $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php queue-count --type=failed $@
exec php /usr/src/code/app/cli.php queue-count --type=failed $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php queue-count --type=processing $@
exec php /usr/src/code/app/cli.php queue-count --type=processing $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php queue-count --type=success $@
exec php /usr/src/code/app/cli.php queue-count --type=success $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php queue-retry $@
exec php /usr/src/code/app/cli.php queue-retry $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/realtime.php $@
exec php /usr/src/code/app/realtime.php $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php schedule-executions $@
exec php /usr/src/code/app/cli.php schedule-executions $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php schedule-functions $@
exec php /usr/src/code/app/cli.php schedule-functions $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php schedule-messages $@
exec php /usr/src/code/app/cli.php schedule-messages $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php screenshot $@
exec php /usr/src/code/app/cli.php screenshot $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php sdks $@
exec php /usr/src/code/app/cli.php sdks $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php specs $@
exec php /usr/src/code/app/cli.php specs $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php ssl $@
exec php /usr/src/code/app/cli.php ssl $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php stats-resources $@
exec php /usr/src/code/app/cli.php stats-resources $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
/usr/src/code/vendor/bin/phpunit --configuration /usr/src/code/phpunit.xml $@
exec /usr/src/code/vendor/bin/phpunit --configuration /usr/src/code/phpunit.xml $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php upgrade $@
exec php /usr/src/code/app/cli.php upgrade $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php vars $@
exec php /usr/src/code/app/cli.php vars $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/worker.php audits $@
exec php /usr/src/code/app/worker.php audits $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/worker.php builds $@
exec php /usr/src/code/app/worker.php builds $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/worker.php certificates $@
exec php /usr/src/code/app/worker.php certificates $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/worker.php databases $@
exec php /usr/src/code/app/worker.php databases $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/worker.php deletes $@
exec php /usr/src/code/app/worker.php deletes $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/worker.php functions $@
exec php /usr/src/code/app/worker.php functions $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/worker.php mails $@
exec php /usr/src/code/app/worker.php mails $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/worker.php messaging $@
exec php /usr/src/code/app/worker.php messaging $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/worker.php migrations $@
exec php /usr/src/code/app/worker.php migrations $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/worker.php stats-resources $@
exec php /usr/src/code/app/worker.php stats-resources $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/worker.php stats-usage $@
exec php /usr/src/code/app/worker.php stats-usage $@
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
php /usr/src/code/app/worker.php webhooks $@
exec php /usr/src/code/app/worker.php webhooks $@
+10 -10
View File
@@ -52,22 +52,22 @@
"utopia-php/cache": "0.13.*",
"utopia-php/cli": "0.15.*",
"utopia-php/config": "0.2.*",
"utopia-php/database": "0.71.*",
"utopia-php/detector": "0.1.*",
"utopia-php/database": "0.69.*",
"utopia-php/domains": "0.5.*",
"utopia-php/domains": "0.8.*",
"utopia-php/dsn": "0.2.1",
"utopia-php/framework": "0.33.*",
"utopia-php/fetch": "0.4.*",
"utopia-php/image": "0.8.*",
"utopia-php/locale": "0.4.*",
"utopia-php/logger": "0.6.*",
"utopia-php/messaging": "0.17.*",
"utopia-php/migration": "0.9.*",
"utopia-php/messaging": "0.18.*",
"utopia-php/migration": "0.10.*",
"utopia-php/orchestration": "0.9.*",
"utopia-php/platform": "0.7.*",
"utopia-php/pools": "0.8.*",
"utopia-php/preloader": "0.2.*",
"utopia-php/queue": "0.9.*",
"utopia-php/queue": "0.11.*",
"utopia-php/registry": "0.5.*",
"utopia-php/storage": "0.18.*",
"utopia-php/swoole": "0.8.*",
@@ -76,17 +76,17 @@
"utopia-php/vcs": "0.10.*",
"utopia-php/websocket": "0.3.*",
"matomo/device-detector": "6.1.*",
"dragonmantank/cron-expression": "3.3.2",
"phpmailer/phpmailer": "6.9.1",
"chillerlan/php-qrcode": "4.3.4",
"adhocore/jwt": "1.1.2",
"dragonmantank/cron-expression": "3.3.*",
"phpmailer/phpmailer": "6.9.*",
"chillerlan/php-qrcode": "4.3.*",
"adhocore/jwt": "1.1.*",
"spomky-labs/otphp": "^10.0",
"webonyx/graphql-php": "14.11.*",
"league/csv": "9.14.*"
},
"require-dev": {
"ext-fileinfo": "*",
"appwrite/sdk-generator": "0.40.*",
"appwrite/sdk-generator": "0.41.*",
"phpunit/phpunit": "9.*",
"swoole/ide-helper": "5.1.2",
"phpstan/phpstan": "1.8.*",
Generated
+220 -227
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -213,7 +213,7 @@ services:
appwrite-console:
<<: *x-logging
container_name: appwrite-console
image: appwrite/console:6.0.1
image: appwrite/console:6.0.41
restart: unless-stopped
networks:
- appwrite
@@ -934,7 +934,7 @@ services:
appwrite-assistant:
container_name: appwrite-assistant
image: appwrite/assistant:0.7.0
image: appwrite/assistant:0.8.3
networks:
- appwrite
environment:
@@ -951,7 +951,7 @@ services:
hostname: exc1
<<: *x-logging
stop_signal: SIGINT
image: openruntimes/executor:0.7.14
image: openruntimes/executor:0.7.20
restart: unless-stopped
networks:
- appwrite
@@ -0,0 +1,24 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Databases;
Client client = new Client(context)
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
.setKey(""); //
Databases databases = new Databases(client);
databases.createDocuments(
"<DATABASE_ID>", // databaseId
"<COLLECTION_ID>", // collectionId
listOf(), // documents
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,26 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Databases;
Client client = new Client(context)
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
.setProject("<YOUR_PROJECT_ID>"); // Your project ID
Databases databases = new Databases(client);
databases.upsertDocument(
"<DATABASE_ID>", // databaseId
"<COLLECTION_ID>", // collectionId
"<DOCUMENT_ID>", // documentId
mapOf( "a" to "b" ), // data
listOf("read("any")"), // permissions (optional)
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,15 @@
import io.appwrite.Client
import io.appwrite.coroutines.CoroutineCallback
import io.appwrite.services.Databases
val client = Client(context)
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
.setKey("") //
val databases = Databases(client)
val result = databases.createDocuments(
databaseId = "<DATABASE_ID>",
collectionId = "<COLLECTION_ID>",
documents = listOf(),
)

Some files were not shown because too many files have changed in this diff Show More