Compare commits

...
Author SHA1 Message Date
Khushboo Verma 8a4c5bec27 Revert /deployments from function logs 2025-03-13 18:58:56 +05:30
Khushboo Verma 97acbd42ba Fix github comment 2025-03-13 17:58:05 +05:30
Matej Bačo 79e066a4d7 Post-merge fixes 2025-03-13 12:04:20 +01:00
Matej Bačo 725dff7f0f Merge branch '1.7.x' into feat-sites 2025-03-13 11:41:28 +01:00
Matej Bačo 358e096301 Merge branch '1.6.x' into 1.7.x 2025-03-13 11:34:14 +01:00
Matej Bačo 74c050ffb6 Improve tests 2025-03-13 11:19:55 +01:00
Matej Bačo 8376b176cb Support commit type 2025-03-13 11:17:10 +01:00
Matej Bačo 69ed3bb776 New deployment status while queued 2025-03-13 10:53:25 +01:00
Matej Bačo 262b2e6cff Fix error messag coloring 2025-03-13 10:53:15 +01:00
Matej Bačo acb9548e85 Fix preview deicison-maker; speed-up tests 2025-03-13 10:33:28 +01:00
Matej Bačo ee1ee7ecfe Fix ping 5xx error 2025-03-13 10:20:45 +01:00
Matej BačoandGitHub b14d76af0d Merge pull request #9500 from appwrite/chore-improve-readability
Improve params readability
2025-03-13 09:56:11 +01:00
Khushboo Verma f2ba319e6e Improve params readability 2025-03-13 12:16:17 +05:30
Steven NguyenandGitHub 6e0c8724ce Merge pull request #9498 from appwrite/chore-regenerate-examples
Regenerate examples
2025-03-12 22:05:52 -07:00
Steven NguyenandGitHub 8f6d45b207 Merge pull request #9497 from appwrite/chore-regenerate-specs
Regenerate specs
2025-03-12 21:49:16 -07:00
Chirag AggarwalandGitHub 1d53cb41de Merge branch '1.6.x' into chore-regenerate-examples 2025-03-13 10:07:50 +05:30
Chirag AggarwalandGitHub dc073b8298 Merge branch '1.6.x' into chore-regenerate-specs 2025-03-13 10:07:13 +05:30
Steven NguyenandGitHub 8c3aebf735 Merge pull request #9499 from appwrite/feat-1.6.2-release-prep
Prepare 1.6.2 release
2025-03-12 21:26:09 -07:00
Jake BarnbyandGitHub b0d6ffa582 Merge pull request #9487 from appwrite/feat-bulk-audit-delete
Feat bulk audit delete
2025-03-13 12:53:57 +13:00
Steven Nguyen 556f7338c1 Bump appwrite version to 1.6.2 2025-03-12 15:52:29 -07:00
Steven Nguyen 301471354e chore: regenerated 1.6.x examples
To ensure we didn't have anything extra, I deleted the 1.6.x folder and
then regenerated the examples via the sdk command.
2025-03-12 15:45:40 -07:00
Steven Nguyen 5bce1e17cb chore: regenerate latest and 1.6.x specs 2025-03-12 15:34:38 -07:00
Damodar LohaniandGitHub 4b1e4008a9 Merge pull request #9494 from appwrite/fix-delete-usage-stats
chore: update initializing dbForLogs
2025-03-12 18:24:15 +05:45
Matej Bačo f1877476d0 Upgrade console 2025-03-12 13:36:16 +01:00
Chirag Aggarwal 46693faa67 chore: prevent console project to queue for delete stats 2025-03-12 12:35:56 +00:00
Matej BačoandGitHub 75b3e78098 Merge pull request #9492 from appwrite/chore-add-invalid-ssr-site-test
Throw build error for adapter mismatch
2025-03-12 13:10:27 +01:00
Matej Bačo 82e16e6d9e Merge branch 'feat-sites' of github.com:appwrite/appwrite into feat-sites 2025-03-12 13:07:37 +01:00
Matej Bačo 63710e8ff8 Fix response filter version 2025-03-12 13:07:15 +01:00
Chirag Aggarwal ae00a69592 chore: update initializing dbForLogs 2025-03-12 11:58:06 +00:00
Khushboo Verma 794329be82 Updated check 2025-03-12 17:25:39 +05:30
Khushboo Verma 5549cd8900 Merge branch 'feat-sites' into chore-add-invalid-ssr-site-test 2025-03-12 17:16:03 +05:30
Matej BačoandGitHub a840d9de20 Merge pull request #9490 from appwrite/chore-avoid-repetition-in-workers
Avoid code repetition in workers and tasks
2025-03-12 12:40:29 +01:00
Matej Bačo 1a90c8aab5 Add Vite framework 2025-03-12 12:39:33 +01:00
Matej Bačo 7f2fdf623c Update specs 2025-03-12 12:27:15 +01:00
Khushboo Verma 39699d16ba Simplify callback syntax in tasks 2025-03-12 16:55:48 +05:30
Matej BačoandGitHub 8f391db39a Merge pull request #9484 from appwrite/chore-attribute-conistency
Chore: Attribute name consistency
2025-03-12 12:23:56 +01:00
Khushboo Verma 2f9802afa2 Use empty check 2025-03-12 16:50:20 +05:30
Khushboo Verma 3af1910cf9 Throw build error for adapter mismatch 2025-03-12 16:43:46 +05:30
Matej Bačo 796a845bcf Setup request & response filters 2025-03-12 12:10:10 +01:00
Matej BačoandGitHub 56736a79e2 Merge pull request #9485 from appwrite/feat-opr-v5
Feat: OPR v5
2025-03-12 11:44:07 +01:00
Damodar LohaniandGitHub 7f76bfed11 Merge pull request #9491 from appwrite/feat-add-timings-to-stats-resources
Feat: calculate and log time taken for each project
2025-03-12 16:28:11 +05:45
Matej Bačo 536319b440 PR review changes 2025-03-12 11:32:43 +01:00
Damodar Lohani 81159e82d5 show time in seconds 2025-03-12 10:29:07 +00:00
Damodar Lohani 5c25b58351 Fix date format 2025-03-12 10:19:55 +00:00
Matej Bačo ea35b6226d Fix flutter screenshots 2025-03-12 11:16:55 +01:00
Damodar Lohani d77940d22f Feat: calculate and log time taken for each project 2025-03-12 10:00:07 +00:00
Khushboo Verma 42cd1df77d Remove duplication from workers 2025-03-12 15:24:52 +05:30
Jake Barnby 2052fb975b Use bulk deletes for audit cleanup 2025-03-12 16:53:08 +13:00
Matej Bačo 994e2faa42 OPR v5 + Flutter starter 2025-03-11 18:19:25 +01:00
Matej Bačo ba26dd6df5 Apply consistency of attributes 2025-03-11 16:26:49 +01:00
Matej BačoandGitHub 0170b4c9e8 Merge pull request #9483 from appwrite/chore-add-template-tests-to-sites
Add get and list template tests for sites
2025-03-11 14:56:24 +01:00
Matej Bačo ab7041d653 Merge branch 'feat-sites' into chore-add-template-tests-to-sites 2025-03-11 14:17:40 +01:00
Matej Bačo 1a56be197c Fix failing tests 2025-03-11 14:17:23 +01:00
Matej Bačo b79b320414 Tempaltes: Fix react native, add Angular 2025-03-11 14:16:27 +01:00
Khushboo Verma 1b04ae6d96 Add get and list template tests for sites 2025-03-11 17:21:28 +05:30
Matej Bačo 95e96b3bfb Fix missing deployment domains 2025-03-11 11:53:26 +01:00
Matej Bačo 18e4be2eab Add JS template 2025-03-11 11:49:31 +01:00
Matej Bačo 7f05a74b31 Increase rate limit for 0.5s debounce in UI 2025-03-11 10:27:08 +01:00
Matej Bačo 733c5ad97d Add enforced minimal specs 2025-03-11 10:24:18 +01:00
Matej Bačo 71b56fc504 Remove log/execution search 2025-03-11 10:22:28 +01:00
Matej Bačo 62eb159e6a Merge branch 'feat-sites' of github.com:appwrite/appwrite into feat-sites 2025-03-11 10:08:47 +01:00
Christy JacobandGitHub d4dd7fb757 Merge pull request #9462 from appwrite/pla-2550
chore: added logsdb for deletes worker
2025-03-11 14:30:40 +05:30
Matej Bačo f61db29498 Rename config to follow folder pattern 2025-03-11 09:50:02 +01:00
Christy JacobandGitHub 1971126e7b Merge pull request #9481 from appwrite/audits-timestamp-update
Update audit timestamp origin
2025-03-11 14:16:53 +05:30
Matej BačoandGitHub d8418a222c Merge pull request #9433 from appwrite/chore-truncate-git-commit-message
Truncate commit message to 252 characters
2025-03-11 09:42:21 +01:00
shimon 141f0fc376 linter 2025-03-11 10:27:23 +02:00
shimon b387823d63 Update audit timestamp origin 2025-03-11 09:17:28 +02:00
Christy JacobandGitHub acf86e47e2 Merge pull request #9479 from appwrite/pla-2567
chore: queue console project for maintenance delete
2025-03-10 22:40:26 +05:30
Matej Bačo 63c7f4c8bc Fix remix detection false postive 2025-03-10 15:33:11 +01:00
Matej Bačo b11ad4b1c9 Fix a bug 2025-03-10 15:16:47 +01:00
Matej Bačo 93510d170e Quality fixes 2025-03-10 14:53:44 +01:00
Matej Bačo be3d18ab41 Fix test 2025-03-10 12:56:20 +01:00
Matej Bačo efc5b9e353 Add frameworks 2025-03-10 12:32:12 +01:00
Chirag Aggarwal 61377ceb6e chore: shift initialization of console project to config 2025-03-10 10:48:44 +00:00
Chirag Aggarwal 6a6d99a9d0 chore: queue console project for maintenance delete 2025-03-10 08:54:20 +00:00
Jake BarnbyandGitHub 078f953e32 Merge pull request #9467 from appwrite/fix-logging-config
Fix logging config
2025-03-10 14:10:41 +13:00
Matej Bačo d86cf7b437 Fix 5xx error on authroization 2025-03-09 18:51:49 +01:00
Matej Bačo aabee0ac37 Fix order of site commands 2025-03-09 16:15:08 +01:00
Matej Bačo 4e1168654d Fix tests 2025-03-09 15:42:17 +01:00
Matej Bačo 254018071a Fix tests; upgrade console 2025-03-09 15:33:06 +01:00
Matej Bačo e904ab6232 Fix path issue 2025-03-09 15:07:25 +01:00
Matej Bačo fed6cefa81 Fix cors issues 2025-03-09 14:50:45 +01:00
Matej Bačo 640f09c49b Fix specs 2025-03-09 13:57:19 +01:00
Matej Bačo 06bb001d0b Improve enums 2025-03-09 00:35:55 +01:00
Matej Bačo 3730ff4895 Fix SDK generation 2025-03-09 00:19:54 +01:00
Matej Bačo 05771c46d6 Update specs 2025-03-09 00:02:39 +01:00
Matej BačoandGitHub 4ff0b6283a Merge pull request #9474 from appwrite/fix-sites-tests
Fix: site tests
2025-03-08 23:57:59 +01:00
Matej Bačo 852a16d01b Remove leftovers 2025-03-08 23:34:37 +01:00
Matej Bačo 084b6c799a Revert "Simplify tests further"
This reverts commit 7e460f6155.
2025-03-08 23:33:37 +01:00
Matej Bačo eddeac6e4f Revert temp changes 2025-03-08 23:33:33 +01:00
Matej Bačo 874f60dce6 Upgrade detection lib 2025-03-08 23:26:25 +01:00
Matej Bačo d21814c51f Improve logs 2025-03-08 23:04:32 +01:00
Matej Bačo 65bcf7898e Improve CI/CD logs 2025-03-08 22:56:16 +01:00
Matej Bačo 7e460f6155 Simplify tests further 2025-03-08 22:43:35 +01:00
Matej Bačo 1a271ff272 Temporarly simplify CI/CD 2025-03-08 22:26:04 +01:00
Matej Bačo 5963631c70 Fix site tests 2025-03-08 22:25:52 +01:00
Matej BačoandGitHub 0fa5460a7e Merge pull request #9461 from appwrite/chore-rules-rehaul
Chore: 2nd rules rehaul
2025-03-08 21:52:47 +01:00
Matej Bačo 12e3d70032 Post-merge fixes 2025-03-08 21:33:43 +01:00
Matej Bačo 5f766f6a13 Merge branch 'feat-sites' into chore-rules-rehaul 2025-03-08 21:33:13 +01:00
Matej BačoandGitHub 7d27ceef43 Merge pull request #9315 from appwrite/feat-add-detection-logic
Integrate detection library with Appwrite
2025-03-08 21:30:19 +01:00
Matej BačoandGitHub 9c3cfc4f83 Merge pull request #9357 from appwrite/feat-authroized-previews
Feat: Authorized previews
2025-03-08 21:04:25 +01:00
Matej BačoandGitHub b4d366eea1 Merge pull request #9457 from appwrite/chore-remove-builds-collection
Chore Remove builds collection
2025-03-08 20:45:10 +01:00
Matej Bačo 8a4954d4e8 PR review changes 2025-03-08 20:44:54 +01:00
Matej Bačo 1943e00e40 Fix tests 2025-03-08 19:58:54 +01:00
Matej Bačo f75acfa503 Remove deploymentUpdatePolicy, add trigger 2025-03-08 19:19:05 +01:00
Matej Bačo b69c40345f Improve docs 2025-03-08 18:45:38 +01:00
Matej Bačo 83dd6a9897 FIx tests 2025-03-08 18:39:13 +01:00
Matej Bačo 75f543c6b0 Upgrade lib version 2025-03-08 18:01:50 +01:00
Matej Bačo 232f99c6c9 Finalize PR, review changes, fix tests 2025-03-08 16:50:39 +01:00
Matej Bačo faa1b0a59b Merge branch 'feat-sites' into feat-add-detection-logic 2025-03-08 14:58:49 +01:00
Matej Bačo fe210e0cf0 Merge branch 'feat-sites' into feat-authroized-previews 2025-03-08 13:04:00 +01:00
Matej Bačo f85bf337b7 Migrate authorize endpoint to http lib 2025-03-08 13:03:23 +01:00
Matej Bačo 06020e2b62 Add preview auth tests, finish todos, improve quality 2025-03-08 12:57:55 +01:00
Matej BačoandGitHub 8ff4d60dbb Merge pull request #9469 from appwrite/feat-site-specifications
Feat: Merge specs
2025-03-08 10:58:49 +01:00
Matej Bačo 43cd7ac8b3 Linter fix 2025-03-07 23:45:19 +01:00
Matej Bačo 393c4012d9 Merge branch 'feat-sites' into feat-authroized-previews 2025-03-07 23:44:52 +01:00
Matej Bačo c6a862a0a3 Specifications test, fix failures 2025-03-07 23:17:15 +01:00
Matej Bačo 1d983a949e Merge site & function specs 2025-03-07 22:36:13 +01:00
Steven Nguyen 59a8172e96 fix: prevent "Failed to initialize logging provider" errors
If the _APP_EXPERIMENT_LOGGING_CONFIG env var isn't set, every 4XX error
outputs this warning:

Failed to initialize logging provider: Unable to parse DSN: scheme is
required

To reduce this unnecessary clutter when _APP_EXPERIMENT_LOGGING_CONFIG
isn't set, this PR adds a check to only attempt to initialize the
logging provider if the env var is set.
2025-03-07 12:59:11 -08:00
Steven Nguyen 0fbd2c6425 fix: prevent warning if no logging config is set
If no logging config is set, there's a warning saying:

> Using deprecated logging configuration.

However, if they didn't set any config, it's not deprecated.
2025-03-07 12:54:53 -08:00
Matej Bačo 5e30fc5350 Fix graphQL test 2025-03-07 21:20:37 +01:00
Matej Bačo a5457da91c Linter fix 2025-03-07 21:12:13 +01:00
Matej Bačo a37a6d9d7c Merge branch 'feat-sites' into chore-remove-builds-collection 2025-03-07 21:05:15 +01:00
Matej Bačo c1ee2f2b41 Failing test fixes 2025-03-07 21:04:24 +01:00
Matej Bačo 6a584c83c1 Attribute renaming 2025-03-07 20:14:11 +01:00
Matej Bačo 777fb3fcdd Update proxy rule tests 2025-03-07 18:00:20 +01:00
Matej BačoandGitHub 6ea20659e6 Merge branch 'feat-sites' into chore-rules-rehaul 2025-03-07 17:34:37 +01:00
Matej BačoandGitHub dade177af2 Merge pull request #9463 from appwrite/feat-reuse-node
Feat: Reuse Node runtime
2025-03-07 16:03:56 +01:00
Matej Bačo 97ffbbc44b Remove need for ssr runtime 2025-03-07 15:46:49 +01:00
Chirag Aggarwal 493f536a6e chore: added logsdb for deletes worker 2025-03-07 14:04:52 +00:00
Christy JacobandGitHub 3af7f0aa3d Merge pull request #9412 from appwrite/chore-bump-cache-0.12.x
chore: bump cache 0.12.x
2025-03-07 17:31:20 +05:30
loks0n b791e59672 chore: bump composer 2025-03-07 10:59:16 +00:00
loks0n c50a0de627 Merge branch '1.6.x' of https://github.com/appwrite/appwrite into chore-bump-cache-0.12.x 2025-03-07 10:58:31 +00:00
Matej Bačo f07c351c94 Linter fix 2025-03-07 11:22:13 +01:00
Matej Bačo a42522feaa Fix test failures 2025-03-07 11:11:32 +01:00
Matej Bačo 9400fdbbe5 Leftover bugs after rework 2025-03-07 10:43:54 +01:00
Matej Bačo 92b696ea21 Introduce type-relevant attributes to rules 2025-03-07 10:14:45 +01:00
Matej Bačo 50ec55d595 Fix site tests 2025-03-06 18:35:57 +01:00
Matej Bačo a7fc8cf84b Fix functions 2025-03-06 18:17:01 +01:00
Matej Bačo 794c6536fb Fixbugs 2025-03-06 17:55:53 +01:00
Matej Bačo 2e30c1ba1f Reapply "Remove builds collection"
This reverts commit 654d178cf2.
2025-03-06 15:34:06 +01:00
Matej Bačo 654d178cf2 Revert "Remove builds collection"
This reverts commit 02e740f8b0.
2025-03-06 15:33:48 +01:00
Matej Bačo 02e740f8b0 Remove builds collection 2025-03-06 15:32:23 +01:00
Matej BačoandGitHub 62b639ce48 Merge pull request #9455 from appwrite/chore-migrate-cancel-deployment-endpoint
Chore: Move cancel build to update deployment status
2025-03-06 14:04:35 +01:00
Matej Bačo 825e9639b1 Move cancel build to deployment endpoint 2025-03-06 12:20:08 +01:00
Matej Bačo 9a8a2b5a49 Upgrade http lib 2025-03-06 09:32:05 +01:00
Matej BačoandGitHub 4428ed1f7d Merge pull request #9445 from appwrite/chore-rename-redeploy-endpoint
Chore: Migrate redeploy endpoint
2025-03-06 09:29:38 +01:00
Christy JacobandGitHub 205024657a Merge pull request #9438 from appwrite/activities-multi-writes
Activities batch writes
2025-03-06 11:40:34 +05:30
Steven NguyenandGitHub fab43a5f83 Merge pull request #9447 from appwrite/pla-2607
Fix blocking of phone sessions when disabled on console
2025-03-05 11:13:40 -08:00
Chirag Aggarwal 36b0475298 chore: update tests 2025-03-05 18:40:41 +00:00
Chirag Aggarwal 0ce4555f70 chore: added auth group to create phone token 2025-03-05 17:42:43 +00:00
Khushboo Verma de5f33f206 keep truncation only during create document 2025-03-05 22:45:48 +05:30
Khushboo Verma 9a44e8130f Add tests for framework, runtime and rendering detection 2025-03-05 22:35:49 +05:30
Matej Bačo 2f3c43d0db Fix failing tests 2025-03-05 13:00:06 +01:00
Matej Bačo 77d27bdd20 Post-merge formatting 2025-03-05 12:33:32 +01:00
Matej Bačo 87a9d72523 Merge branch 'feat-sites' into chore-rename-redeploy-endpoint 2025-03-05 12:33:17 +01:00
Matej Bačo f6674f07e4 Add redeploy tests 2025-03-05 12:29:27 +01:00
Matej Bačo 049ad14121 Fix tests 2025-03-05 11:47:51 +01:00
Matej Bačo a0a82b86dc Migrate redeploy endpoint 2025-03-05 11:29:43 +01:00
Matej BačoandGitHub 326e62334f Merge pull request #9436 from appwrite/chore-rename-activate-endpoint
Chore: Rename deployment activate endpoint
2025-03-05 11:26:00 +01:00
Matej Bačo b29b5da006 Improve code quality 2025-03-05 10:48:26 +01:00
Matej Bačo 46039ded2f Fix rule updating 2025-03-05 10:35:01 +01:00
Matej Bačo dfce78c421 Merge branch 'feat-sites' into chore-rename-activate-endpoint 2025-03-05 10:01:54 +01:00
Matej Bačo ce3bff13dd upgrade http lib 2025-03-05 10:01:50 +01:00
Matej BačoandGitHub a031682596 Merge pull request #9432 from appwrite/chore-add-resource-type-to-sites
Add resource type label in sites endpoints
2025-03-05 09:35:30 +01:00
Khushboo Verma 9b8dd02a88 Don't throw exception from list repos detection 2025-03-05 13:48:44 +05:30
Khushboo Verma bbf37e0a0e Update length to 255 2025-03-05 13:40:15 +05:30
Christy JacobandGitHub a734cadba1 Merge pull request #9443 from appwrite/feat-database-storage-in-stats-resources
Feat: calculate database storage in stats-resources
2025-03-05 12:06:56 +05:30
Khushboo Verma 826b034cd2 Re-add files deleted by mistake 2025-03-05 11:46:31 +05:30
Khushboo Verma 9ee9a8e0ed Resolve merge conflicts 2025-03-05 11:38:28 +05:30
Damodar Lohani 2afb8a14ac Skip in dual writing 2025-03-05 05:27:56 +00:00
Damodar Lohani 6024d01e7b Feat: calculate database storage in stats-resources
- Calculate database storage in stats-resources worker
2025-03-05 05:25:50 +00:00
Christy JacobandGitHub f250f454f7 Merge pull request #9442 from appwrite/fix-model-image-trans
fix: model for image transformations in usage project
2025-03-05 10:21:05 +05:30
Chirag Aggarwal 2c6f731a38 fix: description 2025-03-05 04:49:34 +00:00
Chirag Aggarwal 1d2883f472 chore: fix model for image transformations in usage project 2025-03-05 04:46:06 +00:00
Jake BarnbyandGitHub 8c1a1604a8 Merge pull request #9387 from appwrite/pla-2526
chore: make min/max params optional for attribute update
2025-03-05 16:13:59 +13:00
Jake BarnbyandGitHub ea2fd4b995 Merge pull request #9426 from appwrite/pla-2584
chore: added timeout to deployment builds in tests
2025-03-05 16:11:47 +13:00
Matej Bačo dfc2e87170 Upgrade http library 2025-03-04 21:56:51 +01:00
shimon f2ad3a501e updating audits workers var scope 2025-03-04 20:34:56 +02:00
shimon c443c8fdab updating audits workers var scope 2025-03-04 19:49:37 +02:00
shimon 1838b9c4e8 updating audits workers var scope 2025-03-04 19:49:10 +02:00
shimon 09aa383cf3 updating audits workers var scope 2025-03-04 19:15:00 +02:00
shimon ce054e7088 updating audits workers var scope 2025-03-04 19:12:20 +02:00
shimon 76dc8c29d5 updating audits workers var scope 2025-03-04 19:07:45 +02:00
shimon f761829d60 updating audits workers var scope 2025-03-04 18:49:31 +02:00
shimon 8b4bc7e4a6 updating audits workers var scope 2025-03-04 18:19:23 +02:00
Matej Bačo 520b96f0d9 Finish tests 2025-03-04 16:12:57 +01:00
Matej Bačo ea30d976a8 Fix wrong path, implement tests 2025-03-04 16:04:37 +01:00
Matej Bačo 9b8e4dd862 Rename active deployment path 2025-03-04 15:22:20 +01:00
Matej Bačo ef7b9537f7 Upgrade executor 2025-03-04 15:17:01 +01:00
Matej BačoandGitHub 03c9e57773 Merge pull request #9434 from appwrite/chore-combine-download-endpoints
Chore: Combine download endpoints
2025-03-04 15:10:24 +01:00
Matej Bačo 54413f4c5e Fix bug 2025-03-04 14:31:00 +01:00
Matej Bačo a2abd982cf Backwards compatibility 2025-03-04 14:13:47 +01:00
Matej BačoandGitHub f5a0008445 Merge pull request #9417 from appwrite/feat-screenshot-task
Feat: Screenshot task for templates
2025-03-04 13:56:59 +01:00
Matej Bačo 64183f2946 Fix tests, remove leftovers 2025-03-04 13:45:44 +01:00
Matej Bačo d9eb942e8c Merge deployment download endpoints 2025-03-04 13:43:13 +01:00
Khushboo Verma 84e1b050a9 Truncate commit message to 252 characters 2025-03-04 17:28:06 +05:30
Khushboo Verma e94438927e Add resource type label in sites endpoints 2025-03-04 17:05:09 +05:30
Christy JacobandGitHub 52ba87e77e Merge pull request #9393 from appwrite/add-file-transformation-endpoints
chore: add image transformation stats to usage endpoint
2025-03-04 14:46:14 +05:30
Khushboo Verma 20ad91a906 Simplify logic to fetch versionedRuntime 2025-03-04 13:45:56 +05:30
Chirag Aggarwal 239bebfe2e Merge branch '1.6.x' into add-file-transformation-endpoints 2025-03-04 07:34:43 +00:00
Christy JacobandGitHub eff58459ef Merge pull request #9425 from appwrite/disable-admin-transformedAt
Disable transformedAt update for console users
2025-03-04 12:21:28 +05:30
Christy JacobandGitHub 85456696b8 Merge pull request #9429 from appwrite/fix-dual-writing
Fix: disable dual writing
2025-03-04 11:55:00 +05:30
Damodar Lohani 0659dce935 Fix: disable dual writing 2025-03-04 06:22:58 +00:00
Christy JacobandGitHub d5ab989891 Merge pull request #9339 from appwrite/feat-remove-deprecated-usage-stuff
Remove usage and usage dump in favor of stats-usage and stats-usage-dump
2025-03-04 11:23:29 +05:30
Christy JacobandGitHub 9b18a031d9 Merge pull request #9428 from appwrite/fix-stats-date
Fix: use receivedAt date when available
2025-03-04 11:22:12 +05:30
Damodar Lohani 4d5d30ba7b Fix default value 2025-03-04 05:50:21 +00:00
Damodar Lohani dd5dd4cc43 Same for database metrics 2025-03-04 05:34:02 +00:00
Damodar Lohani 5d61544444 Fix: use receivedAt date when available 2025-03-04 05:31:35 +00:00
Chirag Aggarwal 9a6de87f7d chore: usagetest and migrationsbase 2025-03-03 16:31:41 +00:00
Chirag Aggarwal fe7aeefabf chore: remove redundant param 2025-03-03 16:20:32 +00:00
Chirag Aggarwal fc05a4f1e3 chore: updated to use assertEventually 2025-03-03 16:07:33 +00:00
Matej Bačo 2ae61164d4 Merge branch 'feat-sites' into feat-screenshot-task 2025-03-03 16:45:49 +01:00
Matej BačoandGitHub 774a6af333 Merge pull request #9421 from appwrite/chore-ssr-log-tests
Chore: Add SSR logs test
2025-03-03 16:45:23 +01:00
Matej Bačo 8e03db6c9e Fix tests 2025-03-03 16:42:29 +01:00
Matej Bačo 5dd4348d5c Remove leftover 2025-03-03 16:16:02 +01:00
Matej Bačo 64e2f904c5 Merge branch 'feat-sites' into feat-screenshot-task 2025-03-03 16:05:19 +01:00
Matej Bačo 07ceb1991d Linter fix 2025-03-03 16:04:28 +01:00
Matej Bačo 60f34ced91 Merge branch 'feat-sites' into chore-ssr-log-tests 2025-03-03 15:52:22 +01:00
Matej Bačo 084dcdffd9 Fix tests 2025-03-03 15:52:11 +01:00
Chirag Aggarwal e865ca74d7 chore: added timeout to webhooks base test 2025-03-03 14:41:11 +00:00
Chirag Aggarwal c6b8e649fe chore: added maxtimeout to testChannelExecutions 2025-03-03 14:34:10 +00:00
shimon b314ae8208 disable transformedAt update for console users 2025-03-03 15:19:49 +02:00
Matej Bačo c303aa57ce Fix template CORS 2025-03-03 12:59:36 +01:00
Matej Bačo 2384113a04 Fix flaky tests 2025-03-03 12:44:28 +01:00
Christy JacobandGitHub 32329ef3f9 Merge pull request #9424 from appwrite/revert-9411-lohanidamodar-patch-2
Revert "Fix: stats resources only queue projects accessed in last 3 hours"
2025-03-03 16:25:34 +05:30
Damodar LohaniandGitHub 5becd0a5dc Revert "Fix: stats resources only queue projects accessed in last 3 hours" 2025-03-03 16:04:31 +05:45
Khushboo Verma ef37139592 Resolve merge conflicts 2025-03-03 13:57:29 +05:30
Khushboo Verma 8b8f632abe Add providerRepository model and extend it for framework and runtime 2025-03-03 13:54:07 +05:30
Jake BarnbyandGitHub d85b28aabc Merge pull request #9325 from appwrite/pla-1883
refactor: migrate Realtime::send calls to queueForRealtime
2025-03-03 21:23:55 +13:00
Chirag AggarwalandGitHub 88c8d2aa4c Merge branch '1.6.x' into pla-1883 2025-03-03 13:37:05 +05:30
Chirag Aggarwal 9849e7b232 Merge branch '1.6.x' into add-file-transformation-endpoints 2025-03-01 19:41:25 +00:00
Chirag Aggarwal 6900b717da chore: updated to use logsdb 2025-03-01 17:45:20 +00:00
Chirag Aggarwal aaee99e08b chore: generate specs 2025-03-01 17:19:55 +00:00
Chirag Aggarwal 712c33064a chore: fix sending of transformation stats 2025-03-01 17:18:44 +00:00
Matej Bačo 7e00bc493c Add SSR tests 2025-02-28 18:29:17 +01:00
Matej Bačo 8d47d62d7a Upgrade executor 2025-02-28 17:12:17 +01:00
Matej Bačo ef030f4a08 Improve flaky test 2025-02-28 16:06:11 +01:00
Matej Bačo 580204912c Leftover 2025-02-28 15:20:38 +01:00
Chirag Aggarwal 02de0d2432 chore: fix stats count 2025-02-28 13:29:32 +00:00
Chirag Aggarwal df37462716 chore: fix typing and tests 2025-02-28 13:20:55 +00:00
Matej BačoandGitHub f91e8be136 Merge pull request #9419 from appwrite/feat-function-download
Feat: Build download endpoint in Functions
2025-02-28 12:31:39 +01:00
d75b601a7b Update src/Appwrite/Platform/Modules/Functions/Http/Deployments/Builds/Download/Get.php
Co-authored-by: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com>
2025-02-28 12:10:24 +01:00
Matej Bačo 72d2ba0159 Add missing download endpoints, ensure with tests 2025-02-28 12:04:17 +01:00
Khushboo Verma dc71c50123 Resolve merge conflicts 2025-02-28 16:20:24 +05:30
Matej Bačo d6e7db8900 Fix persistent screenshot 2025-02-28 11:29:42 +01:00
Matej BačoandGitHub 559396295f Merge pull request #9416 from appwrite/feat-move-functions-endpoints-to-modules
Move function endpoints from controller to modules
2025-02-28 10:54:03 +01:00
Matej Bačo dc6143c773 Improve tests 2025-02-28 10:47:48 +01:00
Matej Bačo a1c621fab2 Fix static sites 2025-02-28 10:40:28 +01:00
Matej Bačo 2510cb9687 Avoid 404 race condition during screenshot 2025-02-28 10:18:06 +01:00
Chirag Aggarwal d5cfdc570f chore: updated specs 2025-02-28 08:41:53 +00:00
Matej Bačo 4efa0a7231 Leftover 2025-02-28 09:32:40 +01:00
Chirag Aggarwal e9d8d13fbd chore: added imageTransformations to project usage 2025-02-28 08:28:21 +00:00
Khushboo Verma 4afd9771c6 Remove functions.php 2025-02-27 23:42:43 +05:30
Matej Bačo dd75081609 Formatting fix 2025-02-27 17:46:47 +01:00
Matej Bačo a3c176a2bd Finalize PR 2025-02-27 17:46:41 +01:00
Matej Bačo 8081759c5c Fix failing templates 2025-02-27 17:28:25 +01:00
Matej Bačo bf3b21cdb1 Implement screenshot task and initial run 2025-02-27 15:58:33 +01:00
Khushboo Verma 26a822e4b2 Move all function endpoints to modules structure 2025-02-27 18:53:11 +05:30
Khushboo Verma cede07b520 Add more endpoints to modules 2025-02-27 18:11:47 +05:30
Matej Bačo 92daef51f0 Fix screenshot security 2025-02-27 12:44:22 +01:00
Khushboo Verma 0dbb9dadf6 Move function endpoints from controller to modules 2025-02-27 17:01:15 +05:30
Matej Bačo 496cfa92bc Fix QA instance setup 2025-02-27 10:55:49 +01:00
Chirag Aggarwal f31acd214e chore: remove plan blocking 2025-02-27 09:52:27 +00:00
Matej Bačo ac51fcbf4e Preps for Console SDK 2025-02-27 10:04:11 +01:00
Chirag Aggarwal 388affa3d0 chore: updated naming for subscribers 2025-02-27 07:23:13 +00:00
loks0n 0bbcdf8268 chore: bump cache 0.12.x 2025-02-26 22:05:09 +00:00
loks0n 02e5b935fe Merge branch 'chore-bump-cache-0.12.x' of https://github.com/appwrite/appwrite into chore-bump-cache-0.12.x 2025-02-26 22:03:04 +00:00
loks0n 611f2cad6a chore: bump cache 0.12.x 2025-02-26 22:02:55 +00:00
Luke B. SilverandGitHub b9d5621bde Merge branch '1.6.x' into chore-bump-cache-0.12.x 2025-02-26 21:57:58 +00:00
Chirag Aggarwal c79ed286b1 chore: update tests 2025-02-26 17:35:06 +00:00
Chirag Aggarwal 28896081d7 chore: fix forloop 2025-02-26 16:50:12 +00:00
Chirag Aggarwal 7687784515 chore: added fallback to old values in update 2025-02-26 16:41:26 +00:00
loks0n 31d6fe2423 chore: bump cache 0.12.x 2025-02-26 16:40:19 +00:00
loks0n f5947de508 chore: bump cache 0.12.x 2025-02-26 16:38:05 +00:00
Chirag Aggarwal 0ddcb9b14c chore: refactor adapter 2025-02-26 16:24:05 +00:00
Christy JacobandGitHub 1c8ec7ba1f Merge pull request #9406 from appwrite/bump-base-image
chore: bump docker-base
2025-02-26 18:49:25 +05:30
Christy JacobandGitHub e7eedcdeb7 Merge pull request #9397 from appwrite/track-options-requests
Track options requests
2025-02-26 18:48:50 +05:30
Chirag Aggarwal bb5ed1ccc6 chore: bump base to 0.10.1 2025-02-26 10:14:32 +00:00
Chirag Aggarwal ae78e793dd chore: added blocking to file preview endpoint 2025-02-26 08:52:06 +00:00
Christy JacobandGitHub 24613c2e9f Merge pull request #9243 from appwrite/fix-smtp
Fix: email (smtp) to multiple recipients
2025-02-26 12:57:23 +05:30
Christy JacobandGitHub 718e44adce Merge branch '1.6.x' into track-options-requests 2025-02-26 10:40:10 +05:30
Damodar LohaniandGitHub 1816fae5a3 Merge pull request #9411 from appwrite/lohanidamodar-patch-2
Fix: stats resources only queue projects accessed in last 3 hours
2025-02-26 09:05:22 +05:45
Damodar LohaniandGitHub 7ea108f015 Fix: stats resources only queue projects accessed in last 3 hours 2025-02-26 08:37:36 +05:45
Jake BarnbyandGitHub 69c00d428a Merge pull request #9410 from appwrite/batch-per-project
Batch per project
2025-02-26 14:02:24 +13:00
Jake BarnbyandGitHub e998474b97 Merge branch '1.6.x' into batch-per-project 2025-02-26 14:02:01 +13:00
Jake Barnby 6e82bfe8e7 Update date 2025-02-26 14:00:16 +13:00
Jake Barnby 34d91a6518 Revert "Test increase batch"
This reverts commit 7dfa3193c9.
2025-02-26 13:51:41 +13:00
Jake Barnby 7dfa3193c9 Test increase batch 2025-02-26 13:45:49 +13:00
Matej BačoandGitHub 93d00abfe1 Merge pull request #9314 from appwrite/feat-spa
Feat: SPA support
2025-02-25 22:15:40 +01:00
Matej Bačo d79ab99202 Test fix after merge 2025-02-25 18:22:40 +01:00
Matej Bačo 1e111294df Merge branch 'feat-sites' into feat-spa 2025-02-25 17:57:14 +01:00
Matej BačoandGitHub 1752e8ed83 Merge pull request #9407 from appwrite/fix-sites-device
Fix: deviceForSites
2025-02-25 17:55:49 +01:00
Matej Bačo 22598ae41d Leftover 2025-02-25 17:34:28 +01:00
Matej Bačo a89f591f63 Use deviceForSites properly 2025-02-25 16:42:25 +01:00
Matej BačoandGitHub ac9ac3e279 Merge pull request #9395 from appwrite/fix-apex-rules
Feat: Enhance rules
2025-02-25 15:34:24 +01:00
Matej Bačo 859a9c72e1 Update ProxyCustomServerTest.php 2025-02-25 15:22:24 +01:00
Matej Bačo 19928bd7dc Add delete worker tests for rules 2025-02-25 15:13:59 +01:00
88b3791a24 Update src/Appwrite/Utopia/Response/Model/Rule.php
Co-authored-by: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com>
2025-02-25 14:37:54 +01:00
Matej Bačo 765a0fa891 Merge branch 'feat-sites' into fix-apex-rules 2025-02-25 14:05:08 +01:00
Matej BačoandGitHub fac42f7ad5 Merge pull request #9405 from appwrite/chore-remove-subquery
Chore: Remove subquery
2025-02-25 13:59:25 +01:00
Matej Bačo d7c163be95 PR review changes 2025-02-25 13:52:51 +01:00
Chirag Aggarwal 542e34bc94 chore: bump docker-base 2025-02-25 12:28:05 +00:00
Matej Bačo 16934af49f Fix flaky test 2025-02-25 13:14:33 +01:00
Matej Bačo 29f660cfd6 leftover 2025-02-25 13:04:18 +01:00
Matej Bačo 743ded1e79 Remove domain from deployment model 2025-02-25 13:03:44 +01:00
Matej Bačo 88ae06af57 Improve formatting 2025-02-25 12:53:12 +01:00
Khushboo Verma a54f84fce8 Resolve merge conflicts 2025-02-25 16:20:58 +05:30
Khushboo Verma f830918c7c Add logic to detect rendering strategy and fallback file 2025-02-25 16:19:30 +05:30
Chirag Aggarwal 9f7ba3d4ca Merge branch '1.6.x' into fix-smtp 2025-02-25 09:48:21 +00:00
Matej Bačo 2ba84bf93f Rule search param fix 2025-02-25 10:47:47 +01:00
Jake BarnbyandGitHub 66dc3adb98 Merge pull request #9403 from appwrite/batch-per-project
Log batches per project
2025-02-25 21:46:33 +13:00
Jake Barnby 3a2babc906 Update date 2025-02-25 21:34:46 +13:00
Jake Barnby 03f0e382f4 Fix dates 2025-02-25 21:03:37 +13:00
Jake Barnby b272a8b1e7 Pass queries 2025-02-25 20:26:00 +13:00
Chirag Aggarwal 676431c355 chore: shifted to logsDb 2025-02-25 07:16:42 +00:00
Jake Barnby 2924f408b3 Reapply "Remove blocks"
This reverts commit f49346485a.
2025-02-25 19:21:35 +13:00
Jake Barnby b0547015a9 Add temp log date skip 2025-02-25 18:51:11 +13:00
Jake Barnby f49346485a Revert "Remove blocks"
This reverts commit 6f854b5eb6.
2025-02-25 18:39:12 +13:00
Jake Barnby 6f854b5eb6 Remove blocks 2025-02-25 18:18:25 +13:00
Chirag Aggarwal ab6c5c9f8d chore: bump utopia messaging 2025-02-25 04:47:35 +00:00
Chirag Aggarwal 7ac4a5bf27 chore: update naming 2025-02-25 04:43:44 +00:00
Jake Barnby 1f560d896f Fix plural 2025-02-25 16:58:30 +13:00
Jake Barnby 5efd231861 Allow validator to read logs collections from base 2025-02-25 16:56:13 +13:00
Jake Barnby 3f8e1cbedb Fix loop unset 2025-02-25 15:57:04 +13:00
Jake Barnby 08f4ed2b50 Log batches per project 2025-02-25 15:50:10 +13:00
Matej Bačo 474e04479f Linter fix 2025-02-24 18:44:11 +01:00
Matej Bačo 40beecdddc Fix tests 2025-02-24 18:42:20 +01:00
Matej Bačo 427e781b5b Add git domains, improve tests 2025-02-24 16:22:23 +01:00
Matej Bačo 9e909ee3fc Specs update 2025-02-24 12:15:50 +01:00
Matej Bačo eb7daf3edd Finalize rules overhauls 2025-02-24 11:55:59 +01:00
Matej Bačo a56086f8bf Basics of rules rework 2025-02-23 21:34:14 +01:00
Eldad A. FuxandGitHub 392b33ef26 Merge pull request #9398 from appwrite/disable-logs-display
disable logs display
2025-02-23 20:08:55 +01:00
shimon 6bd14d548f composer 2025-02-23 20:58:02 +02:00
shimon 06d22f910c disable logs display 2025-02-23 20:51:38 +02:00
Matej Bačo ae835f6cf0 Fix tests 2025-02-23 17:08:12 +01:00
Christy Jacob 8958070327 chore: linter 2025-02-23 15:48:33 +05:30
Christy Jacob 3f50532c91 chore: remove sleep in functions tests 2025-02-23 15:42:53 +05:30
Christy Jacob 4c49272389 chore: enable assistant 2025-02-23 15:40:54 +05:30
Christy Jacob f25df67002 chore: remove sleep() for usage stats, since batch size is now 1 2025-02-23 15:39:37 +05:30
Christy Jacob 94108e6f3f chore: remove sleep() for usage stats, since batch size is now 1 2025-02-23 15:23:34 +05:30
Christy Jacob f682e4ac6f chore: remoove sleep() for usage stats, since batch size is now 1 2025-02-23 14:56:15 +05:30
Christy Jacob cf41d44de4 fix: general tests 2025-02-23 14:47:57 +05:30
Christy Jacob 30327f86fd feat: enable assistant 2025-02-23 11:39:18 +05:30
Christy Jacob 2359c1adb6 feat: enable assistant 2025-02-23 11:38:59 +05:30
Christy Jacob 12b494982b feat: compute usage for OPTIONS and 4XX errors 2025-02-23 11:37:54 +05:30
Christy Jacob 65dd5fe9b3 feat: compute usage for OPTIONS and 4XX errors 2025-02-23 11:34:28 +05:30
Matej Bačo 666e8f3ec9 Separate proxy rule creation 2025-02-22 18:56:51 +01:00
Matej Bačo aeebdadae1 Add nameservers variable 2025-02-22 18:32:10 +01:00
Matej Bačo 0a25463b8d Apex domain exception + proxy tests 2025-02-22 18:26:51 +01:00
Matej Bačo 7e3b693216 Disable internal httpx 2025-02-21 23:45:45 +01:00
Matej Bačo a5fc9463c7 Support for deployment screenshots 2025-02-21 22:35:05 +01:00
Matej Bačo 08ec153585 update specs 2025-02-21 22:14:02 +01:00
Matej BačoandGitHub c8f4667b6a Merge pull request #9366 from appwrite/feat-site-screenshots
Feat: Site screenshots
2025-02-21 22:11:03 +01:00
Matej Bačo f9bc5d0cce Fix tests 2025-02-21 22:10:39 +01:00
Matej Bačo 7397d52c0c Fix tests 2025-02-21 21:41:39 +01:00
Matej Bačo 8661ae6840 Disable banner for screenshots 2025-02-21 20:50:43 +01:00
Matej Bačo 498c1456ed Merge branch 'feat-sites' into feat-site-screenshots 2025-02-21 20:22:50 +01:00
Matej Bačo 2917c66202 Remove unnessessary complexity 2025-02-21 20:21:13 +01:00
Matej Bačo 26c99dca84 Add onelink template 2025-02-21 18:55:59 +01:00
Chirag Aggarwal 0e0bab4c40 chore: updated test 2025-02-21 13:28:49 +00:00
Chirag Aggarwal 4ed4c660d5 chore: added tests for file transformations 2025-02-21 12:53:17 +00:00
Matej Bačo 67d6404c70 Add further templates 2025-02-21 12:46:44 +01:00
Chirag Aggarwal b1629b24ad chore: added file transformation stats to usage endpoint for bucket 2025-02-21 11:44:04 +00:00
Christy JacobandGitHub 9fa13ddfd8 Merge pull request #9391 from appwrite/fix-null-error-on-invite
chore: fix null errors on team invite
2025-02-21 16:09:43 +05:30
Khushboo Verma 1394b4349c Separate response models for list repos 2025-02-21 15:22:15 +05:30
Matej Bačo ede068d5f4 Add react native, vue template 2025-02-21 10:51:53 +01:00
Matej Bačo 1c6204118f PR code review 2025-02-21 10:09:35 +01:00
Matej Bačo cdc3cb23ec React starter template 2025-02-21 09:58:24 +01:00
Khushboo Verma 9d4806c792 Merge branch 'feat-sites' into feat-add-detection-logic 2025-02-21 11:39:06 +05:30
Chirag Aggarwal d6c2dfb915 chore: updated name 2025-02-21 03:27:46 +00:00
Steven NguyenandGitHub f402262ffc Merge pull request #9390 from appwrite/pla-2142
chore: bump utopia-php/image to 0.8.0
2025-02-20 10:44:54 -08:00
Chirag Aggarwal 9d9e44a14f chore: remove redundant check 2025-02-20 17:36:42 +00:00
Chirag Aggarwal 397a6a34ed chore: fix null errors on team invite 2025-02-20 17:30:26 +00:00
Matej Bačo 54d877fe3e PR review fixes 2025-02-20 16:49:20 +01:00
Chirag Aggarwal c660b9d858 chore: fix tests 2025-02-20 14:56:23 +00:00
Chirag Aggarwal f9cc7882aa chore: fix tests 2025-02-20 14:43:21 +00:00
Chirag Aggarwal 4e71e85b5b chore: bump utopia-php/image version 2025-02-20 14:32:34 +00:00
Chirag Aggarwal 077fe10d80 chore: fix tests 2025-02-20 14:12:14 +00:00
Chirag Aggarwal b0ced9b351 chore: updated tests 2025-02-20 13:37:13 +00:00
Matej Bačo c3df0a71e3 Address leftover 2025-02-20 14:34:59 +01:00
Matej Bačo 732e74f114 Finalize screenshot tests 2025-02-20 14:22:30 +01:00
Matej Bačo d941d18e8c WIP: screenshot tests 2025-02-20 13:44:31 +01:00
Matej Bačo 3ccd49e4a5 Rework screenshots to use api key resource from recent 1.6.x merge 2025-02-20 13:44:22 +01:00
Christy JacobandGitHub 6cbcd695d1 Merge pull request #9388 from appwrite/fix-audits-v2
Fix removed audits for shared v2
2025-02-20 18:05:25 +05:30
Matej Bačo 2d761b48d8 Merge branch 'feat-sites' into feat-site-screenshots 2025-02-20 13:17:23 +01:00
Matej BačoandGitHub 556bcbf33b Merge pull request #9382 from appwrite/fix-flaky-tests-sites
Fix: Improve tests OPR setup
2025-02-20 12:57:04 +01:00
Jake Barnby b6166063db Add back remove shared v2 2025-02-21 00:51:29 +13:00
Matej Bačo e6a53a8c15 Enable sites on non-shared tables 2025-02-20 12:33:00 +01:00
Matej Bačo f5f37d6a79 Simplify OPR startup check 2025-02-20 12:25:13 +01:00
Matej Bačo f0d8c7382b Simplify YML file 2025-02-20 12:19:32 +01:00
Chirag Aggarwal ccb7dfa839 chore: added test cases 2025-02-20 11:15:05 +00:00
Chirag Aggarwal 6235a1c729 chore: make min/max params optional for attribute update 2025-02-20 10:33:58 +00:00
Matej Bačo fb19f8d6a6 Run sites in non-shared mode tests 2025-02-20 09:13:50 +01:00
Khushboo Verma 68de687bdf Resolve merge conflicts 2025-02-20 12:57:18 +05:30
Khushboo Verma a7c1bd94ed Add framework detection to list repos 2025-02-20 12:54:26 +05:30
Christy JacobandGitHub 7319b12b51 Merge pull request #9353 from appwrite/feat-messaging-metrics
Feat messaging metrics
2025-02-20 12:25:14 +05:30
Matej Bačo 95aab45cc2 Fix merge issue 2025-02-19 16:01:05 +01:00
Matej Bačo 4a0d33213a Fix tests 2025-02-19 15:50:16 +01:00
Matej Bačo 322b726196 Fix test 2025-02-19 15:37:43 +01:00
Matej Bačo cd25a79694 Improve tests OPR setup 2025-02-19 15:29:42 +01:00
Matej Bačo 47395c5442 Fix failing tests regarding specs and failed builds 2025-02-19 14:58:59 +01:00
Matej Bačo d13e8641fd Allow inactive vcs deployments 2025-02-19 13:39:11 +01:00
Matej Bačo acd1dd2479 Formatting fix 2025-02-19 12:56:27 +01:00
Matej Bačo 3cc1fb6fb4 Post-merge update 2025-02-19 12:55:39 +01:00
Matej Bačo 3932b8bdc1 Merge branch '1.7.x' into feat-sites 2025-02-19 12:54:05 +01:00
Khushboo Verma 3bb4fde7e6 Merge branch 'feat-sites' into feat-add-detection-logic 2025-02-19 17:12:45 +05:30
Matej Bačo 165caef9ab Merge branch '1.6.x' into 1.7.x 2025-02-19 12:40:07 +01:00
Matej BačoandGitHub 055411fbe4 Merge pull request #9380 from appwrite/feat-add-createVcsDeployment
Add createVcsDeployment endpoints for sites and functions
2025-02-19 12:31:25 +01:00
Matej Bačo 63a91e30fa Add reference params 2025-02-19 11:50:25 +01:00
Khushboo Verma f7749bbbef Add createVcsDeployment endpoints for sites and functions 2025-02-19 14:55:44 +05:30
Khushboo Verma c0b574fe9b Update detector library version 2025-02-19 12:19:41 +05:30
Khushboo Verma 34b8453666 Merge branch 'feat-sites' into feat-add-detection-logic 2025-02-18 20:19:11 +05:30
Chirag Aggarwal 55e7633bd1 chore: shift targets to realtime 2025-02-18 14:04:59 +00:00
Chirag Aggarwal 88a6616cf8 chore: fix naming 2025-02-18 13:05:50 +00:00
Chirag Aggarwal 9f7aaf7029 chore: fix warning in database worker 2025-02-18 12:51:19 +00:00
Chirag Aggarwal 235a357ca3 chore: initialized queueForWebhooks in worker init 2025-02-18 11:37:36 +00:00
Chirag AggarwalandGitHub b99d2c3c8c Merge branch '1.6.x' into pla-1883 2025-02-18 16:31:41 +05:30
Christy JacobandGitHub d59d6f70a5 Merge pull request #9303 from appwrite/pla-2428
Add support endpoint url for S3
2025-02-18 16:28:44 +05:30
Chirag Aggarwal ac84de7645 chore: updated variable descriptions 2025-02-18 10:38:13 +00:00
Christy JacobandGitHub 27d2cc9f00 Merge pull request #9348 from ChiragAgg5k/pla-2470
Fix resend team invite if already accepted
2025-02-18 15:10:11 +05:30
Matej Bačo ae1eb53e31 Update specs 2025-02-18 09:31:56 +01:00
Matej BačoandGitHub 3b87b42dac Merge pull request #9352 from appwrite/feat-all-rules-in-proxy
Move rule creation to create rule
2025-02-18 09:28:39 +01:00
Chirag Aggarwal a74c6e0b10 chore: added targets to realtime, refactor webhook queues 2025-02-18 07:58:56 +00:00
Khushboo Verma db8010f7c6 Fix site tests 2025-02-18 13:03:57 +05:30
Khushboo Verma c24cebf6ce Fix site tests 2025-02-18 12:50:09 +05:30
Khushboo Verma 262b152cd9 Add more rule tests 2025-02-18 12:12:12 +05:30
Jake BarnbyandGitHub ae91869e76 Merge pull request #9336 from appwrite/feat-key-segmented-usage
Feat key segmented usage
2025-02-18 18:47:01 +13:00
Jake Barnby 2b29c792ad Merge remote-tracking branch 'origin/1.6.x' into feat-key-segmented-usage 2025-02-18 18:18:00 +13:00
Jake Barnby 3e02b830ac Fix inject 2025-02-18 18:17:52 +13:00
Christy JacobandGitHub f4e9b89195 Merge pull request #9373 from appwrite/pla-2503
Fix Self Hosting functions by adding missed config
2025-02-18 00:37:47 +05:30
Chirag Aggarwal 6ef4e76aa6 Merge branch '1.6.x' into pla-1883 2025-02-17 18:54:41 +00:00
Chirag Aggarwal 227f2c476d Merge branch '1.6.x' into pla-1883 2025-02-17 18:46:05 +00:00
Matej Bačo 2e4a8dec78 Fix CORS 2025-02-17 15:05:19 +01:00
Chirag Aggarwal c1b613e5bd chore: added migration script 2025-02-17 13:55:43 +00:00
Jake Barnby d6b9be8799 Merge remote-tracking branch 'origin/feat-key-segmented-usage' into feat-key-segmented-usage 2025-02-18 02:10:37 +13:00
Jake Barnby 0d79ae33ba Lint 2025-02-18 02:10:05 +13:00
Matej BačoandGitHub 685c141a59 Merge branch '1.6.x' into feat-key-segmented-usage 2025-02-17 14:06:40 +01:00
Jake Barnby ff09f1e62a Remove redundant check 2025-02-18 02:05:13 +13:00
Jake Barnby 07a6d60b01 Remove leftover 2025-02-18 02:02:29 +13:00
Jake Barnby 77e83d5cfb Remove unused injections 2025-02-18 01:49:51 +13:00
Khushboo Verma 2ea18c4761 Fix domain generation 2025-02-17 18:12:29 +05:30
Khushboo Verma 28ef7da231 Fix new site tests 2025-02-17 18:03:13 +05:30
Jake Barnby fe251c443f Remove leftover 2025-02-18 01:32:48 +13:00
Khushboo Verma 76b154bfce Add framework detection to list repos 2025-02-17 17:54:13 +05:30
Matej Bačo c2a60a8569 Screenshot deletion in worker 2025-02-17 13:03:56 +01:00
Khushboo Verma 71103b037f Make switch case simpler 2025-02-17 17:17:27 +05:30
Khushboo Verma 9459c87b50 Re-add correct project tests 2025-02-17 17:15:23 +05:30
Christy JacobandGitHub d0630eae79 Merge pull request #9361 from appwrite/pla-2492
Fix Model Platform is missing response key: store
2025-02-17 17:08:17 +05:30
Jake BarnbyandGitHub d1cf833f15 Merge pull request #9375 from appwrite/feat-worker-batch-delete
Use batch delete in worker
2025-02-18 00:08:26 +13:00
Matej Bačo e5e7c50ca4 previewHostname security 2025-02-17 11:54:07 +01:00
Jake Barnby 1fbfbbf482 Also update database worker delete by group 2025-02-17 23:53:43 +13:00
Jake Barnby ef8520ad2d Format 2025-02-17 23:14:17 +13:00
Jake Barnby 36ce381325 Use batch delete in worker 2025-02-17 22:36:55 +13:00
Matej Bačo 30cb7e8ff2 Todos 2025-02-17 09:47:38 +01:00
Matej Bačo 2f2a743a7f Merge branch 'feat-sites' into feat-all-rules-in-proxy 2025-02-17 09:47:33 +01:00
Khushboo Verma feffab137f Resolve merge conflicts 2025-02-17 14:00:30 +05:30
Khushboo Verma 6155fad3e0 Resolve merge conflicts 2025-02-17 14:00:05 +05:30
Chirag Aggarwal 0dba22c606 chore: updated installations collection 2025-02-17 05:57:30 +00:00
Jake Barnby 6653972e11 Fix disabled metric check 2025-02-17 17:29:12 +13:00
Jake Barnby 390cdaa6a5 Merge remote-tracking branch 'origin/1.6.x' into feat-key-segmented-usage
# Conflicts:
#	composer.lock
2025-02-17 17:12:45 +13:00
Damodar LohaniandGitHub b3067f562f Merge pull request #9370 from appwrite/fix-image-trnasformation-metrics
Fix image trnasformation metrics
2025-02-16 17:29:13 +05:45
Damodar Lohani 3e5e545304 Fix: image transformations metrics 2025-02-16 11:31:46 +00:00
Matej Bačo d1978b102f Dark screenshot, upgrade screnshot image, fix redeploy missing domain 2025-02-15 22:27:16 +01:00
Khushboo Verma b1854fee10 Add helper methods in functionBase 2025-02-15 23:23:02 +05:30
Matej BačoandGitHub 62b1c19357 Merge pull request #9364 from appwrite/feat-template-deployment
Feat: Template deployments
2025-02-15 15:15:13 +01:00
Matej Bačo e1dedd2fbb Remove unnessessary check 2025-02-15 04:41:36 +01:00
Matej Bačo 51e89f5110 Revert "Initial branch rule implementation"
This reverts commit 81a7ba536c.
2025-02-15 04:38:21 +01:00
Matej Bačo 81a7ba536c Initial branch rule implementation 2025-02-15 04:36:38 +01:00
Matej Bačo fb2649ab41 Add leftover 2025-02-15 03:44:40 +01:00
Matej Bačo b746642979 Fix missing response 2025-02-15 02:01:11 +01:00
Matej Bačo a6bcc3ce97 Fix bugs 2025-02-15 01:57:41 +01:00
Matej Bačo b30d9eb8ad Initial screenshot implementation 2025-02-15 01:19:21 +01:00
Matej Bačo 28339f0ed7 createTemplateDeployment for sites and deployments 2025-02-15 00:36:46 +01:00
Matej Bačo da9d442473 Re-add starter templates 2025-02-15 00:34:43 +01:00
Matej Bačo 47a6168137 Update console and templates 2025-02-14 21:42:39 +01:00
Chirag Aggarwal 51438631da chore: added console check to ping 2025-02-14 15:40:08 +00:00
Steven NguyenandGitHub 993c07d7c6 Merge pull request #9360 from appwrite/fix-build-memory-limits
Fix build memory specifications
2025-02-14 07:36:34 -08:00
Matej BačoandGitHub 9222fec7f8 Merge pull request #9359 from appwrite/fix-site-cors
Fix: Site CORS
2025-02-14 12:40:37 +01:00
Matej Bačo 94f3cf7baf Merge branch 'feat-sites' into fix-site-cors 2025-02-14 12:05:21 +01:00
Matej Bačo 399afa1b14 Merge branch 'feat-sites' of github.com:appwrite/appwrite into feat-sites 2025-02-14 12:04:31 +01:00
Matej Bačo 410388a587 Upgrade Console 2025-02-14 12:03:59 +01:00
Matej BačoandGitHub 4bd08642be Merge pull request #9326 from appwrite/feat-preview-branding
Feat: preview branding
2025-02-14 12:03:33 +01:00
Matej Bačo 3ab8503f61 Code quality fixes 2025-02-14 10:36:34 +01:00
Matej Bačo 75320db428 Update transformation lib structure 2025-02-14 10:01:27 +01:00
Matej Bačo 43f0dc0846 Add CORS tests 2025-02-14 09:47:37 +01:00
Bradley Schofield 0f873792ba Fix build memory and add tests to prevent future regressions 2025-02-14 17:16:40 +09:00
Chirag Aggarwal 4c7917687d Merge branch '1.6.x' into pla-1883 2025-02-14 07:16:43 +00:00
Chirag AggarwalandGitHub 9ebb4b9626 Merge branch '1.6.x' into pla-2428 2025-02-14 09:04:30 +05:30
Matej Bačo a10882d7ee Update general.php 2025-02-13 19:59:29 +01:00
Matej Bačo ec05a3d668 Enable CORS for sites 2025-02-13 19:57:41 +01:00
Khushboo Verma 3531d223e2 Fix general tests 2025-02-13 20:27:25 +05:30
Chirag Aggarwal 2457485230 chore: removed redundant exception 2025-02-13 13:16:29 +00:00
Khushboo Verma e87fe7467e Merge branch 'feat-sites' into feat-all-rules-in-proxy 2025-02-13 16:54:12 +05:30
Matej Bačo f6fbc253f7 Update Console 2025-02-13 11:33:22 +01:00
Matej Bačo 313444cb12 Fix envCommands set too late 2025-02-13 11:14:08 +01:00
Jake BarnbyandGitHub 7143bef111 Merge pull request #9356 from appwrite/catch-invalid-index
Fix patch index validation
2025-02-13 22:56:28 +13:00
fogelito e4ae0d463d assertStringContainsString 2025-02-13 11:37:12 +02:00
fogelito 8778e2e666 lint 2025-02-13 11:35:16 +02:00
fogelito 8f212ccd30 in_array 2025-02-13 11:24:13 +02:00
fogelito e8a306253b Fix test 2025-02-13 11:22:40 +02:00
fogelito 4592a1cc36 Merge branch '1.6.x' of https://github.com/appwrite/appwrite into catch-invalid-index 2025-02-13 11:20:52 +02:00
Christy JacobandGitHub 608a2cc67b Merge pull request #9354 from appwrite/fix-image-transformation-metric-time
Fix: metric time was not being written to DB
2025-02-13 14:41:52 +05:30
Khushboo Verma bd58ba32c8 Remove older test 2025-02-13 14:21:52 +05:30
Matej Bačo 80241e37c3 Update tempalte auto-values 2025-02-13 09:47:37 +01:00
fogelito 6abf8ce727 Fix index length test 2025-02-13 10:44:27 +02:00
Jake BarnbyandGitHub ed51a059ba Merge pull request #9355 from appwrite/chore-update-migrations
Chore: Update migrations
2025-02-13 20:59:33 +13:00
Bradley Schofield 43d8374c5c Update migrations 2025-02-13 16:57:32 +09:00
Damodar Lohani d4599e6884 Fix, time was not being written to DB 2025-02-13 06:43:49 +00:00
Damodar Lohani 1e446948e8 Fix error 2025-02-13 05:24:00 +00:00
Damodar Lohani 503b8a0cde spacing 2025-02-13 04:58:14 +00:00
Damodar Lohani 745947621f Feat: count for targets 2025-02-13 04:54:29 +00:00
Damodar Lohani 721b9b9aea remove old events 2025-02-13 00:52:20 +00:00
Damodar LohaniandGitHub 29ffd703db Merge branch '1.6.x' into feat-remove-deprecated-usage-stuff 2025-02-13 06:28:48 +05:45
Khushboo Verma 4b909ed7dc Create rule in function logging test 2025-02-13 00:23:13 +05:30
Khushboo Verma f9ce932ac1 Create site rule 2025-02-13 00:11:43 +05:30
Khushboo Verma f67870925f Resolve merge conflicts 2025-02-13 00:01:18 +05:30
Khushboo Verma f416e39098 Move create rule to module 2025-02-12 23:58:25 +05:30
Christy JacobandGitHub 88c2fe2dd2 Merge pull request #9347 from appwrite/update-audit-logging
feat: batch create abuse logs
2025-02-12 22:35:34 +05:30
Christy Jacob a0482aca7a chore: revert package.json 2025-02-12 22:04:48 +05:30
Christy Jacob 9989137ed4 chore: use private variables for aggregation 2025-02-12 22:01:28 +05:30
Matej BačoandGitHub c4142565aa Merge pull request #8970 from appwrite/feat-console-availability-endpoint
Add new console endpoint to check resource availability
2025-02-12 17:17:05 +01:00
Christy JacobandGitHub 933e762284 Merge pull request #9332 from appwrite/PLA-896
feat(builds): check if function is blocked before building
2025-02-12 21:23:10 +05:30
Matej BačoandGitHub 81bfa5c48d Merge branch 'feat-sites' into feat-preview-branding 2025-02-12 16:35:31 +01:00
Matej Bačo e0369ec14f Avoid JS link 2025-02-12 14:09:32 +01:00
Jake BarnbyandGitHub 2e3a1cf82c Merge branch '1.6.x' into feat-key-segmented-usage 2025-02-13 01:30:51 +13:00
Jake Barnby 3fe1147194 Filter in prepare 2025-02-13 01:07:10 +13:00
Damodar LohaniandGitHub 8922d676c6 Merge pull request #9350 from appwrite/fix-image-metric
Fix: missing periodic metric
2025-02-12 17:25:15 +05:45
Jake Barnby 6dbc8c5464 Allow disabling specific metrics in hooks via keys 2025-02-13 00:19:51 +13:00
Damodar Lohani d2cc5ea932 Fix: missing periodic metric 2025-02-12 10:58:51 +00:00
Chirag Aggarwal d259f21c65 refactor: tests to match the new membership logic 2025-02-12 10:48:32 +00:00
Matej Bačo 6415009f07 Add SvelteKit Appwrite template 2025-02-12 11:01:26 +01:00
Chirag Aggarwal e435e457de chore: added check for team membership exists 2025-02-12 09:50:13 +00:00
Jake BarnbyandGitHub 4c452417d1 Merge pull request #9338 from appwrite/feat-improve-tests
Only run all table mode tests on db update
2025-02-12 22:34:01 +13:00
Jake Barnby 2449b76676 Format 2025-02-12 21:25:53 +13:00
Jake Barnby 9427b07580 Add expired property directly to key 2025-02-12 21:22:08 +13:00
Christy Jacob 2dffcb29b0 chore: add comment about the unit 2025-02-12 13:09:31 +05:30
Jake BarnbyandGitHub dd03a04d58 Merge branch '1.6.x' into feat-improve-tests 2025-02-12 20:35:13 +13:00
Jake Barnby 775e6ec9cf Fix role setting 2025-02-12 20:34:38 +13:00
Christy Jacob 294f6818fa chore: review comments 2025-02-12 12:23:20 +05:30
Christy Jacob 48525ce755 chore: linter 2025-02-12 11:34:39 +05:30
Christy Jacob 978284b36f feat: use smaller batch size on development environments 2025-02-12 11:33:17 +05:30
Jake Barnby 5780ec9547 Make sure key has app role before continuing checks 2025-02-12 18:45:06 +13:00
Christy Jacob 7f706fce5d feat: linter & console logs 2025-02-12 11:09:24 +05:30
Christy Jacob df27e8950b feat: update composer 2025-02-12 11:02:29 +05:30
Christy Jacob 00473d4744 feat: batch create abuse logs 2025-02-12 10:57:43 +05:30
Jake Barnby da2e27650c Merge remote-tracking branch 'origin/1.6.x' into feat-key-segmented-usage 2025-02-12 18:20:28 +13:00
Jake Barnby d4c659f88d Fix key usage default 2025-02-12 18:17:47 +13:00
Jake BarnbyandGitHub c22ece068f Merge pull request #9346 from appwrite/fix-drop-abuse
Fix drop abuse on shared table project delete
2025-02-12 17:41:40 +13:00
Jake Barnby e394532bcd Fix drop abuse on shared table project delete 2025-02-12 17:03:37 +13:00
Christy JacobandGitHub e140603890 Merge pull request #9342 from appwrite/lohanidamodar-patch-2
Fix: missing call for image transformations counting
2025-02-11 22:13:15 +05:30
Christy Jacob 2189ca1469 chore: linter 2025-02-11 16:40:17 +00:00
Matej Bačo 084b62116f Convert to library approach 2025-02-11 14:26:49 +01:00
Damodar LohaniandGitHub f6aff786f1 Fix: missing call for image transformations counting 2025-02-11 17:59:48 +05:45
Fabian Gruber 8324b789c5 chore(review): remove http status codes from exceptions 2025-02-11 11:00:28 +01:00
Damodar Lohani f2fc45da02 fix format 2025-02-11 09:46:00 +00:00
Fabian Gruber f2ae6e07cb feat(builds): check if function is blocked before building 2025-02-11 10:45:26 +01:00
Jake Barnby 61e65e1eda Skip shared jobs entirely 2025-02-11 22:37:57 +13:00
Damodar LohaniandGitHub 2b2be60e77 Merge branch '1.6.x' into feat-remove-deprecated-usage-stuff 2025-02-11 15:20:23 +05:45
Jake Barnby abaa5c7f48 Only run shared tables tests if database library version changed compared to base 2025-02-11 22:26:39 +13:00
Jake Barnby 704437b5e8 Format 2025-02-11 22:04:52 +13:00
Jake Barnby bed7ab321e Add unit test 2025-02-11 22:02:20 +13:00
Jake Barnby d04a5cab0d Merge remote-tracking branch 'origin/1.6.x' into feat-key-segmented-usage
# Conflicts:
#	composer.lock
2025-02-11 21:33:34 +13:00
Jake Barnby 0634a7eac3 Fix injections 2025-02-11 21:13:01 +13:00
Jake Barnby 1c91604c80 Only disable database reads/writes and network stats 2025-02-11 20:56:39 +13:00
Damodar Lohani 940f4d12af Remove usage and usage dump in favor of stats-usage and stats-usage-dump 2025-02-11 07:52:37 +00:00
Jake BarnbyandGitHub 2902b1bde8 Merge pull request #9329 from appwrite/catch-invalid-index
Catch invalid index
2025-02-11 20:34:10 +13:00
Chirag Aggarwal 5076303c33 chore: refactor realtime queueing in builds worker 2025-02-11 06:06:43 +00:00
Chirag Aggarwal 532160705f chore: refactor realtime queueing in functions worker 2025-02-11 05:50:30 +00:00
Jake Barnby 7490240397 Fix name shadowing 2025-02-11 18:29:42 +13:00
Chirag Aggarwal f666e18154 chore: fix databases worker realtime queueing 2025-02-11 05:00:45 +00:00
Jake Barnby e5a3866065 Fix imports 2025-02-11 17:53:40 +13:00
Jake Barnby 30bc70b9b1 Abstract key decoding and check if usage is enabled 2025-02-11 17:49:22 +13:00
Chirag Aggarwal bcdae7f4e3 chore: refactor certificate realtime, fix database 2025-02-11 04:21:36 +00:00
Chirag Aggarwal 47fbb777ed chore: refactor migrations realtime queue 2025-02-11 04:03:02 +00:00
Chirag Aggarwal 2c4c42de05 docs: fix database worker 2025-02-11 03:53:18 +00:00
Chirag Aggarwal 375f643214 refactor: triggering realtime events with queueForRealtime 2025-02-11 03:29:32 +00:00
Christy JacobandGitHub 2f95b0e2e0 Merge pull request #9272 from appwrite/feat-logs-db
Feat: logs DB
2025-02-10 23:49:48 +05:30
Christy Jacob bfc0b53163 chore: add simple toggle for dual writing 2025-02-10 23:05:34 +05:30
Matej Bačo 7be0fbf616 Implementation of authorized previews 2025-02-10 15:07:01 +01:00
fogelito c77ca64fc0 Merge branch '1.6.x' of https://github.com/appwrite/appwrite into catch-invalid-index 2025-02-10 15:41:50 +02:00
fogelito 8c3a243a5d Typo 2025-02-10 15:40:45 +02:00
fogelito 7a8688932c Add test 2025-02-10 15:40:21 +02:00
fogelito 7caab2f9ff IndexException 2025-02-10 10:55:37 +02:00
fogelito 33f55c73a7 Revert cast Index 2025-02-10 10:42:29 +02:00
fogelito edbe0fb72f Bump Database version 0.58.5 2025-02-10 10:40:12 +02:00
fogelito 23a9b519f6 Merge branch '1.6.x' of https://github.com/appwrite/appwrite into catch-invalid-index 2025-02-10 10:37:05 +02:00
Matej Bačo aec9d91a68 Formatting fix 2025-02-10 09:17:59 +01:00
Matej Bačo 950255fab9 Merge branch 'feat-sites' into feat-spa 2025-02-10 09:17:28 +01:00
fogelito a032540b3c IndexException 2025-02-10 10:11:52 +02:00
fogelito 27709e7683 IndexException 2025-02-10 10:04:51 +02:00
fogelito 5b786e2a68 Catch index exception 2025-02-10 09:19:56 +02:00
Christy JacobandGitHub 42a4fe2efc Merge branch '1.6.x' into feat-logs-db 2025-02-10 10:18:09 +05:30
fogelito 3092e765cc indexException 2025-02-09 18:34:41 +02:00
Damodar Lohani e8faf2a859 fix worker 2025-02-09 08:52:07 +00:00
Damodar Lohani ec9045b488 add stats-resources health queue 2025-02-09 06:36:59 +00:00
55e30a0ef4 Update src/Appwrite/Platform/Workers/StatsUsageDump.php
Co-authored-by: Christy Jacob <christyjacob4@gmail.com>
2025-02-09 12:19:16 +05:45
Damodar Lohani abd899186d Merge remote-tracking branch 'origin/1.6.x' into feat-logs-db 2025-02-09 05:20:10 +00:00
Damodar Lohani 59516408af revert env update 2025-02-09 05:15:26 +00:00
Matej Bačo 5c286c3334 Implement preview branding 2025-02-08 15:53:55 +01:00
Matej Bačo 5e2abc539f Add helper for site domain 2025-02-08 12:16:25 +01:00
Matej BačoandGitHub e269614a51 Update tests/e2e/Services/Sites/SitesCustomServerTest.php 2025-02-08 10:48:49 +01:00
Matej Bačo 21c224709f Finish SPA integration 2025-02-08 10:36:11 +01:00
Chirag Aggarwal 20c01d0e73 chore: added env variable to compose.phtml 2025-02-07 07:57:29 +00:00
Chirag AggarwalandGitHub 989bbbc261 Merge branch '1.6.x' into pla-2428 2025-02-07 13:25:15 +05:30
Khushboo Verma 0a3f284e14 Update composer.json 2025-02-07 11:18:07 +05:30
Khushboo Verma 11ed6b8f47 Resolve merge conflicts 2025-02-07 11:16:30 +05:30
Khushboo Verma 8dd99b7d2a Add framework detection to Appwrite 2025-02-06 23:59:43 +05:30
Luke B. SilverandGitHub e6efe5b27e Merge branch '1.6.x' into pla-2428 2025-02-06 13:58:58 +00:00
Matej Bačo f2445c2a37 Add SPA tests 2025-02-06 14:22:35 +01:00
Damodar LohaniandGitHub 9e988747d8 Merge branch '1.6.x' into feat-logs-db 2025-02-06 16:02:41 +05:45
Damodar Lohani cd45177558 fix pool empty 2025-02-06 08:06:15 +00:00
Damodar Lohani f6b2d9d937 remove old collections - we only need it in production temporarily 2025-02-06 07:02:07 +00:00
Damodar Lohani c48146b699 fix builds worker 2025-02-06 06:05:53 +00:00
Damodar Lohani c27c3499aa fix endpoint and add test 2025-02-06 04:48:40 +00:00
Damodar Lohani 0a6ebe6661 Merge remote-tracking branch 'origin/1.6.x' into feat-logs-db 2025-02-06 04:40:05 +00:00
Damodar Lohani ae9d3f4703 fix dual writing 2025-02-06 04:40:01 +00:00
Damodar Lohani 2efe1ed9dc new health endpoint 2025-02-06 04:24:04 +00:00
Damodar Lohani c3495dde35 fix key 2025-02-06 04:17:49 +00:00
Damodar Lohani 8da5bfccb6 fix format and test 2025-02-06 03:58:46 +00:00
Damodar Lohani 89aa61b17c fix duplicate constant 2025-02-06 03:37:01 +00:00
Damodar Lohani 87b3f535bd fix renaming 2025-02-06 03:36:53 +00:00
Damodar Lohani 68c3aa3078 update to use publisher 2025-02-05 09:53:29 +00:00
Damodar Lohani 3e778c0094 update environment variable 2025-02-05 09:53:23 +00:00
Damodar Lohani cf66bee925 Merge remote-tracking branch 'origin/1.6.x' into feat-logs-db 2025-02-05 09:49:11 +00:00
Damodar Lohani 966fc47e25 fix classname 2025-02-05 09:28:44 +00:00
Damodar Lohani 99f23ff25a refactor 2025-02-05 09:27:36 +00:00
Damodar Lohani 6b930129e5 add DAU and WAU metric 2025-02-05 09:26:00 +00:00
Damodar Lohani 292e859133 rename metric 2025-02-05 09:17:27 +00:00
Damodar Lohani 5052fd8528 get latest usageDump and dual write 2025-02-05 09:11:03 +00:00
Damodar Lohani 5b91b5cec1 env to configure dual write 2025-02-05 09:10:45 +00:00
Damodar Lohani 4d43b41482 Merge remote-tracking branch 'origin/1.6.x' into feat-logs-db 2025-02-05 08:17:46 +00:00
Chirag Aggarwal bfb4cb4a04 chore: added empty check for s3 creds 2025-02-04 09:58:12 +00:00
Chirag Aggarwal deb556242e chore: update test 2025-02-04 08:35:26 +00:00
Chirag Aggarwal 6be805fe6e Merge branch '1.6.x' into pla-2428 2025-02-04 08:15:44 +00:00
Chirag Aggarwal fcfef4d474 Merge branch '1.6.x' into pla-2428 2025-02-04 08:12:42 +00:00
Damodar LohaniandGitHub 63c07a456f Merge branch '1.6.x' into feat-logs-db 2025-02-02 07:08:25 +05:45
Damodar Lohani 978f22b56d rename transformed metric 2025-01-30 07:15:24 +00:00
Damodar Lohani 71c265d4e8 fix wrong comment 2025-01-30 07:12:15 +00:00
Damodar Lohani d31a358392 Temp: everything to be removed 2025-01-30 07:07:10 +00:00
Damodar Lohani 95845f8c0e update env name 2025-01-30 06:42:57 +00:00
Damodar Lohani 6eb4d3f021 reset dockerfile 2025-01-30 06:40:49 +00:00
Damodar Lohani 074f4417ff image transformations metrics and batch writes 2025-01-30 06:24:10 +00:00
Damodar Lohani da7a234038 update 2025-01-30 05:28:45 +00:00
Damodar Lohani f94d1a5d82 update compose.phtml 2025-01-30 05:24:30 +00:00
Damodar Lohani d0724812d7 fix 2025-01-30 05:05:05 +00:00
Damodar Lohani 6fedefdeda fix 2025-01-30 05:03:41 +00:00
Damodar Lohani cb31e7954e refactor rename 2025-01-30 04:53:53 +00:00
Damodar Lohani 0da3f870f9 refactor: rename 2025-01-30 04:43:16 +00:00
Damodar Lohani 469dbf0a31 reset usage 2025-01-30 04:33:42 +00:00
Damodar Lohani 3fde465dfa Update stats resources task container 2025-01-30 04:15:03 +00:00
Damodar Lohani c2ce273065 update stats resources task to use new queue 2025-01-30 04:10:35 +00:00
Damodar Lohani a05d774370 queue resources to cli 2025-01-30 04:07:44 +00:00
Damodar Lohani e78020d45a stats resources evenet 2025-01-30 04:06:57 +00:00
Damodar Lohani 22ab23d009 feat: Stats resources worker 2025-01-30 04:05:51 +00:00
Damodar Lohani 31ddb6e48f rename collection 2025-01-30 03:51:17 +00:00
Damodar Lohani 21097041f0 refactor: rename usage count to stats resources 2025-01-30 03:50:27 +00:00
Damodar Lohani fb5aeb1476 skip some metrics override 2025-01-28 07:19:27 +00:00
Damodar Lohani d84f6e4ee0 reset database listeners 2025-01-28 06:40:20 +00:00
Damodar Lohani a85499a4ec Merge remote-tracking branch 'origin/1.6.x' into feat-logs-db 2025-01-28 02:11:01 +00:00
Damodar Lohani 7b588219f9 fix dual writing internal ID conflict 2025-01-27 08:19:03 +00:00
Damodar Lohani 05f99dcdf0 fix wrong arg 2025-01-27 07:46:54 +00:00
Damodar Lohani 3124554403 remove db listeners as counters are now done separately by usage worker 2025-01-27 07:39:33 +00:00
Damodar Lohani 336b0a7c02 rename collection 2025-01-27 07:22:50 +00:00
Damodar Lohani f593498c07 dual writing 2025-01-27 07:15:06 +00:00
Damodar Lohani 55cbab6270 fix format 2025-01-27 06:15:59 +00:00
Damodar Lohani 5d5547c6b9 periodic metric 2025-01-27 06:11:58 +00:00
Damodar Lohani 066273d0db update usage worker for usage count 2025-01-27 04:33:41 +00:00
Damodar Lohani 9955b6b61c usage count container and events 2025-01-27 04:33:33 +00:00
Damodar Lohani 5685c8ac25 refactor create collection and create logs db 2025-01-27 02:51:01 +00:00
Damodar Lohani c6360cce06 logs collection config 2025-01-27 02:50:50 +00:00
Damodar Lohani 187ea93f81 Get logs db resource 2025-01-27 02:26:06 +00:00
Marton SchneiderandGitHub 1683fe0a98 Merge branch 'main' into main 2025-01-21 22:57:53 +01:00
Christy JacobandGitHub 7ecba8c0f2 Merge pull request #9105 from gewenyu99/docs-create-document
Docs-create-document
2024-12-13 15:52:31 +04:00
Vincent (Wen Yu) Ge 46038c9fef update PR fix quote 2024-12-12 21:27:04 +00:00
Vincent (Wen Yu) Ge bb3143128f Merge branch 'main' into docs-create-document 2024-12-12 21:26:23 +00:00
Marton Schneider eb2e9eadd7 fix docker-compose.yml 2024-12-11 21:10:21 +01:00
Marton SchneiderandGitHub aaf5ab1948 Merge branch 'appwrite:main' into main 2024-12-11 21:06:52 +01:00
Christy JacobandGitHub f3d6eb09dd Merge pull request #5769 from appwrite/lohanidamodar-patch-2
fix doc comment for filter method
2024-12-11 23:25:51 +04:00
Christy JacobandGitHub a735e969ec Merge pull request #5445 from appwrite/cloud-update-install-link
Add Appwrite Cloud to read me.
2024-12-11 23:10:39 +04:00
Christy JacobandGitHub 3ca1f3065f Merge pull request #7042 from mishmanners/patch-4
Add accessibility features
2024-12-11 23:00:10 +04:00
Christy Jacob 2c9da8a1c4 chore: update PR 2024-12-11 18:59:46 +00:00
Christy Jacob f5f549b520 chore: update PR 2024-12-11 18:58:54 +00:00
Christy Jacob 5da1dd26bc chore: update PR 2024-12-11 18:55:46 +00:00
Christy JacobandGitHub fef9b6dfd3 Merge pull request #5278 from gofenix/readme-cn
update readme-cn some doc
2024-12-11 21:53:32 +04:00
Christy JacobandGitHub 1483e08754 Merge pull request #4848 from olitomas/patch-1
🇮🇸 Added missing Icelandic translations for email strings.
2024-12-11 21:53:13 +04:00
Christy JacobandGitHub 740baec56a Merge pull request #5046 from Yavnik/patch-4
Added RuPay Credit Card Icon in Avatars Service
2024-12-11 21:52:58 +04:00
Christy Jacob c92217afb9 chore: remove console 2024-12-11 17:25:12 +00:00
Christy Jacob db5c29742d Merge branch 'main' of https://github.com/appwrite/appwrite into readme-cn 2024-12-11 17:22:23 +00:00
Christy Jacob 816a203e73 chore: update Chinese readme 2024-12-11 17:21:02 +00:00
Christy JacobandGitHub 363011ee32 Merge branch 'main' into patch-4 2024-12-11 21:08:19 +04:00
Christy JacobandGitHub 51e5b50ae7 Merge branch 'main' into patch-1 2024-12-11 21:07:53 +04:00
Christy JacobandGitHub 342b9f2910 Merge pull request #4313 from tusharxoxoxo/patch-2
Update add-oauth2-provider.md
2024-12-11 21:07:19 +04:00
Christy Jacob 71c21a7bd8 chore: linter 2024-12-11 16:46:24 +00:00
Christy Jacob f8c22a6700 Merge branch 'main' of https://github.com/appwrite/appwrite into patch-4 2024-12-11 16:45:42 +00:00
Christy JacobandGitHub 01465f5c8d Merge branch 'main' into patch-1 2024-12-11 20:36:14 +04:00
Christy JacobandGitHub 7301704762 Merge branch 'main' into patch-2 2024-12-11 20:25:57 +04:00
Christy JacobandGitHub f8b89b2294 Merge pull request #3728 from sashashura/patch-1
GitHub Workflows security hardening
2024-12-11 20:25:22 +04:00
Marton Schneider 3c1e422bb9 change the env var name from _APP_STORAGE_S3_ENDPOINT_URL to _APP_STORAGE_S3_ENDPOINT 2024-11-22 18:21:44 +01:00
Marton Schneider 4d90ff06fd Merge remote-tracking branch 'upstream/main' 2024-11-22 18:16:44 +01:00
Marton Schneider 5a2f06fb83 add support endpoint URL for S3 2023-11-18 13:02:47 +01:00
Michelle "MishManners®™" ManneringandGitHub 3211867f6a Accessibility for README-CN
Add accessibility features based on: https://github.blog/2023-10-26-5-tips-for-making-your-github-profile-page-accessible/
2023-10-30 10:46:17 +11:00
Michelle "MishManners®™" ManneringandGitHub d1c5ec4585 Add accessibility to CONTRIBUTING
Add accessibility features based on: https://github.blog/2023-10-26-5-tips-for-making-your-github-profile-page-accessible/
2023-10-30 10:44:24 +11:00
Michelle "MishManners®™" ManneringandGitHub f90034a510 Add accessibility to README
Add accessibility features based on: https://github.blog/2023-10-26-5-tips-for-making-your-github-profile-page-accessible/
2023-10-30 10:39:46 +11:00
Damodar LohaniandGitHub 701f0bbd4d fix doc comment for filter method 2023-07-05 11:51:45 +05:45
Vincent (Wen Yu) Ge c0bea3d833 change links from install -> self-hosting 2023-04-27 19:08:12 +00:00
Vincent (Wen Yu) Ge 53a9c87f42 Update links in readme to include appwrite cloud 2023-04-27 19:01:01 +00:00
Vincent (Wen Yu) Ge 03bfed4e25 Update create-document description and improve error message for unknown attribute. 2023-04-24 22:54:01 +00:00
zhenfeng-zhu 96359b8f6a update readme-cn some doc 2023-03-25 18:03:01 +08:00
Tushar DahiyaandGitHub 16c7aa230d Merge branch 'appwrite:master' into patch-2 2023-03-09 22:27:09 +05:30
Yavnik SharmaandGitHub 5ea1268107 Added rupay.png 2023-02-03 18:24:17 +05:30
Yavnik SharmaandGitHub c856ffef45 Delete old rupay.png 2023-02-03 18:23:41 +05:30
Yavnik SharmaandGitHub 6509f19773 Merge branch 'appwrite:master' into patch-4 2023-02-03 18:08:06 +05:30
Yavnik SharmaandGitHub 8ec13eb221 Added Rupay in Get Credit Card Icon Documentation 2023-01-26 17:53:58 +05:30
Yavnik SharmaandGitHub 19f965befe Added Rupay in Get Credit Card Icon Documentation 2023-01-26 17:53:32 +05:30
Yavnik SharmaandGitHub 4077dc48b4 Added Rupay in Get Credit Card Icon Documentation 2023-01-26 17:53:04 +05:30
Yavnik SharmaandGitHub 14f38343f5 Added Rupay in Get Credit Card Icon Documentation 2023-01-26 17:52:36 +05:30
Yavnik SharmaandGitHub dd04c005aa Added Rupay in Get Credit Card Icon Documentation 2023-01-26 17:52:01 +05:30
Yavnik SharmaandGitHub 0328134cbc Added Rupay in Get Credit Card Icon Documentation 2023-01-26 17:51:33 +05:30
Yavnik SharmaandGitHub a65f3b1f4a Added rupay.png file 2023-01-26 17:50:49 +05:30
Yavnik SharmaandGitHub 11c93f800f Added rupay 2023-01-26 17:49:11 +05:30
Óli TómasandGitHub c673662a34 🇮🇸 Added missing Icelandic translations for email strings. 2022-12-12 19:19:36 +00:00
Tushar DahiyaandGitHub 092322ff4e Update add-oauth2-provider.md 2022-10-07 09:27:56 +05:30
AlexandGitHub e4d8d38c6e Update codeql-analysis.yml
Signed-off-by: sashashura <93376818+sashashura@users.noreply.github.com>
2022-08-29 11:34:32 +01:00
389 changed files with 23748 additions and 11868 deletions
+6 -3
View File
@@ -23,7 +23,7 @@ _APP_OPENSSL_KEY_V1=your-secret-key
_APP_DOMAIN=traefik
_APP_DOMAIN_FUNCTIONS=functions.localhost
_APP_DOMAIN_SITES=sites.localhost
_APP_DOMAIN_TARGET=localhost
_APP_DOMAIN_TARGET=test.appwrite.io
_APP_RULES_FORMAT=md5
_APP_REDIS_HOST=redis
_APP_REDIS_PORT=6379
@@ -40,6 +40,7 @@ _APP_STORAGE_S3_ACCESS_KEY=
_APP_STORAGE_S3_SECRET=
_APP_STORAGE_S3_REGION=us-east-1
_APP_STORAGE_S3_BUCKET=
_APP_STORAGE_S3_ENDPOINT=
_APP_STORAGE_DO_SPACES_ACCESS_KEY=
_APP_STORAGE_DO_SPACES_SECRET=
_APP_STORAGE_DO_SPACES_REGION=us-east-1
@@ -80,8 +81,8 @@ _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,ssr-22,flutter-3.24
_APP_SITES_FRAMEWORKS=sveltekit,nextjs,nuxt,astro,remix,flutter,other # TODO: Angular
_APP_SITES_RUNTIMES=static-1,node-22,flutter-3.29
_APP_SITES_FRAMEWORKS=sveltekit,nextjs,nuxt,astro,remix,flutter,other,react,vue,analog,angular,vite
_APP_MAINTENANCE_INTERVAL=86400
_APP_MAINTENANCE_DELAY=
_APP_MAINTENANCE_RETENTION_CACHE=2592000
@@ -89,6 +90,7 @@ _APP_MAINTENANCE_RETENTION_EXECUTION=1209600
_APP_MAINTENANCE_RETENTION_ABUSE=86400
_APP_MAINTENANCE_RETENTION_AUDIT=1209600
_APP_USAGE_AGGREGATION_INTERVAL=30
_APP_STATS_RESOURCES_INTERVAL=3600
_APP_MAINTENANCE_RETENTION_USAGE_HOURLY=8640000
_APP_MAINTENANCE_RETENTION_SCHEDULES=86400
_APP_USAGE_STATS=enabled
@@ -113,3 +115,4 @@ _APP_MESSAGE_PUSH_TEST_DSN=
_APP_WEBHOOK_MAX_FAILED_ATTEMPTS=10
_APP_PROJECT_REGIONS=default
_APP_FUNCTIONS_CREATION_ABUSE_LIMIT=5000
_APP_STATS_USAGE_DUAL_WRITING_DBS=database_db_main
+5
View File
@@ -13,8 +13,13 @@ on:
schedule:
- cron: '0 16 * * 0'
permissions:
contents: read
jobs:
analyze:
permissions:
security-events: write
name: Analyze
runs-on: ubuntu-latest
+16
View File
@@ -0,0 +1,16 @@
name: "Static code analysis"
on: [pull_request]
jobs:
lint:
name: CodeQL
runs-on: ubuntu-latest
steps:
- name: Check out the repo
uses: actions/checkout@v2
- name: Run CodeQL
run: |
docker run --rm -v $PWD:/app composer:2.6 sh -c \
"composer install --profile --ignore-platform-reqs && composer check"
+102 -11
View File
@@ -8,9 +8,33 @@ env:
IMAGE: appwrite-dev
CACHE_KEY: appwrite-dev-${{ github.event.pull_request.head.sha }}
on: [pull_request]
on: [ pull_request ]
jobs:
check_database_changes:
name: Check if utopia-php/database changed
runs-on: ubuntu-latest
outputs:
database_changed: ${{ steps.check.outputs.database_changed }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Fetch base branch
run: git fetch origin ${{ github.event.pull_request.base.ref }}
- name: Check for utopia-php/database changes
id: check
run: |
if git diff origin/${{ github.event.pull_request.base.ref }} HEAD -- composer.lock | grep -q '"name": "utopia-php/database"'; then
echo "Database version changed, going to run all mode tests."
echo "database_changed=true" >> "$GITHUB_ENV"
echo "database_changed=true" >> "$GITHUB_OUTPUT"
else
echo "database_changed=false" >> "$GITHUB_ENV"
echo "database_changed=false" >> "$GITHUB_OUTPUT"
fi
setup:
name: Setup & Build Appwrite Image
runs-on: ubuntu-latest
@@ -106,6 +130,72 @@ jobs:
name: E2E Service Test
runs-on: ubuntu-latest
needs: setup
strategy:
fail-fast: false
matrix:
service: [
Account,
Avatars,
Console,
Databases,
Functions,
FunctionsSchedule,
GraphQL,
Health,
Locale,
Projects,
Realtime,
Sites,
Proxy,
Storage,
Teams,
Users,
Webhooks,
VCS,
Messaging,
Migrations
]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Load Cache
uses: actions/cache@v4
with:
key: ${{ env.CACHE_KEY }}
path: /tmp/${{ env.IMAGE }}.tar
fail-on-cache-miss: true
- name: Load and Start Appwrite
run: |
docker load --input /tmp/${{ env.IMAGE }}.tar
docker compose up -d
sleep 30
- name: Wait for Open Runtimes
timeout-minutes: 3
run: |
while ! docker compose logs openruntimes-executor | grep -q "Executor is ready."; do
echo "Waiting for Executor to come online"
sleep 1
done
- name: Run ${{ matrix.service }} tests with Project table mode
run: |
echo "Using project tables"
export _APP_DATABASE_SHARED_TABLES=
export _APP_DATABASE_SHARED_TABLES_V1=
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
e2e_shared_mode_test:
name: E2E Shared Mode Service Test
runs-on: ubuntu-latest
needs: [ setup, check_database_changes ]
if: needs.check_database_changes.outputs.database_changed == 'true'
strategy:
fail-fast: false
matrix:
@@ -123,6 +213,7 @@ jobs:
Projects,
Realtime,
Sites,
Proxy,
Storage,
Teams,
Users,
@@ -132,7 +223,6 @@ jobs:
Migrations
]
tables-mode: [
'Project',
'Shared V1',
'Shared V2',
]
@@ -152,7 +242,15 @@ jobs:
run: |
docker load --input /tmp/${{ env.IMAGE }}.tar
docker compose up -d
sleep 60
sleep 30
- name: Wait for Open Runtimes
timeout-minutes: 3
run: |
while ! docker compose logs openruntimes-executor | grep -q "Executor is ready."; do
echo "Waiting for Executor to come online"
sleep 1
done
- name: Run ${{ matrix.service }} tests with ${{ matrix.tables-mode }} table mode
run: |
@@ -164,14 +262,7 @@ jobs:
echo "Using shared tables V2"
export _APP_DATABASE_SHARED_TABLES=database_db_main
export _APP_DATABASE_SHARED_TABLES_V1=
else
echo "Using project tables"
export _APP_DATABASE_SHARED_TABLES=
export _APP_DATABASE_SHARED_TABLES_V1=
fi
echo 'Sleep 1 minute, as temporary fix for v4rc executor startup (image pulling)'
sleep 60
docker compose exec -T \
-e _APP_DATABASE_SHARED_TABLES \
@@ -258,4 +349,4 @@ jobs:
comment-id: ${{ steps.fc.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
body-path: benchmark.txt
edit-mode: replace
edit-mode: replace
+13 -13
View File
@@ -1,6 +1,6 @@
# Contributing
We would ❤️ you to contribute to Appwrite and help make it better! We want contributing to Appwrite to be fun, enjoyable, and educational for anyone and everyone. All contributions are welcome, including issues, and new docs, as well as updates and tweaks, blog posts, workshops, and more.
We would :heart: you to contribute to Appwrite and help make it better! We want contributing to Appwrite to be fun, enjoyable, and educational for anyone and everyone. All contributions are welcome, including issues, and new docs, as well as updates and tweaks, blog posts, workshops, and more.
## Here for Hacktoberfest?
If you're here to contribute during Hacktoberfest, we're so happy to see you here. Appwrite has been a long-time participant of Hacktoberfest and we welcome you, whatever your experience level. This year, we're **only taking contributions for issues tagged** `hacktoberfest`, so we can focus our resources to support your contributions.
@@ -9,13 +9,13 @@ You can [find issues using this query](https://github.com/search?q=org%3Aappwrit
## How to Start?
If you are worried or dont know where to start, check out the next section that explains what kind of help we could use and where you can get involved. You can send your questions to [@appwrite](https://twitter.com/appwrite) on Twitter or to anyone from the [Appwrite team on Discord](https://appwrite.io/discord). You can also submit an issue, and a maintainer can guide you!
If you are worried or dont know where to start, check out the next section that explains what kind of help we could use and where you can get involved. You can send your questions to [@appwrite on Twitter](https://twitter.com/appwrite) or to anyone from the [Appwrite team on Discord](https://appwrite.io/discord). You can also submit an issue, and a maintainer can guide you!
## Code of Conduct
Help us keep Appwrite open and inclusive. Please read and follow our [Code of Conduct](https://github.com/appwrite/.github/blob/main/CODE_OF_CONDUCT.md).
## Submit a Pull Request 🚀
## Submit a Pull Request :rocket:
Branch naming convention is as following
@@ -65,13 +65,13 @@ Now, go a step further by running the linter using the following command to manu
composer lint <your file path>
```
This will give you a list of errors to rectify. If you need more information on the errors, you can pass in additional command line arguments to get more verbose information. More lists of available arguments can be found [here](https://github.com/squizlabs/PHP_CodeSniffer/wiki/Usage). A very useful command line argument is `--report=diff`. This will give you the expected changes by the linter for easy fixing of formatting issues.
This will give you a list of errors to rectify. If you need more information on the errors, you can pass in additional command line arguments to get more verbose information. More lists of available arguments can be found [on PHP_Codesniffer usage Wiki](https://github.com/squizlabs/PHP_CodeSniffer/wiki/Usage). A very useful command line argument is `--report=diff`. This will give you the expected changes by the linter for easy fixing of formatting issues.
```bash
composer lint --report=diff <your file path>
```
5. Push changes to GitHub.
5. Push changes to GitHub
```
$ git push origin [name_of_your_new_branch]
@@ -323,7 +323,7 @@ Adding a new dependency should have vital value for the product with minimum pos
## Introducing New Features
We would 💖 you to contribute to Appwrite, but we also want to ensure Appwrite is loyal to its vision and mission statement 🙏.
We would :sparkling_heart: you to contribute to Appwrite, but we also want to ensure Appwrite is loyal to its vision and mission statement :pray:.
For us to find the right balance, please open an issue explaining your ideas before introducing a new pull request.
@@ -389,7 +389,7 @@ In file `app/controllers/shared/api.php` On the database listener, add to an exi
```php
case $document->getCollection() === 'teams':
$queueForUsage
$queueForStatsUsage
->addMetric(METRIC_TEAMS, $value); // per project
break;
```
@@ -401,10 +401,10 @@ In that case you need also to handle children removal using addReduce() method c
```php
case $document->getCollection() === 'buckets': //buckets
$queueForUsage
$queueForStatsUsage
->addMetric(METRIC_BUCKETS, $value); // per project
if ($event === Database::EVENT_DOCUMENT_DELETE) {
$queueForUsage
$queueForStatsUsage
->addReduce($document);
}
break;
@@ -450,16 +450,16 @@ public function __construct()
->inject('dbForProject')
->inject('queueForFunctions')
->inject('queueForEvents')
->inject('queueForUsage')
->inject('queueForStatsUsage')
->inject('log')
->callback(fn (Message $message, Database $dbForProject, Func $queueForFunctions, Event $queueForEvents, Usage $queueForUsage, Log $log) => $this->action($message, $dbForProject, $queueForFunctions, $queueForEvents, $queueForUsage, $log));
->callback(fn (Message $message, Database $dbForProject, Func $queueForFunctions, Event $queueForEvents, StatsUsage $queueForStatsUsage, Log $log) => $this->action($message, $dbForProject, $queueForFunctions, $queueForEvents, $queueForStatsUsage, $log));
}
```
and then trigger the queue with the new metric like so:
```php
$queueForUsage
$queueForStatsUsage
->addMetric(METRIC_BUILDS, 1)
->addMetric(METRIC_BUILDS_STORAGE, $build->getAttribute('size', 0))
->addMetric(METRIC_BUILDS_COMPUTE, (int)$build->getAttribute('duration', 0) * 1000)
@@ -662,7 +662,7 @@ Pull requests are great, but there are many other ways you can help Appwrite.
### Blogging & Speaking
Blogging, speaking about, or creating tutorials about one of Appwrites many features are great ways to get the word out about Appwrite. Mention [@appwrite](https://twitter.com/appwrite) on Twitter and/or [email team@appwrite.io](mailto:team@appwrite.io) so we can give pointers and tips and help you spread the word by promoting your content on the different Appwrite communication channels. Please add your blog posts and videos of talks to our [Awesome Appwrite](https://github.com/appwrite/awesome-appwrite) repo on GitHub.
Blogging, speaking about, or creating tutorials about one of Appwrites many features are great ways to get the word out about Appwrite. Mention [@appwrite on Twitter](https://twitter.com/appwrite) and/or [email team@appwrite.io](mailto:team@appwrite.io) so we can give pointers and tips and help you spread the word by promoting your content on the different Appwrite communication channels. Please add your blog posts and videos of talks to our [Awesome Appwrite](https://github.com/appwrite/awesome-appwrite) repo on GitHub.
### Presenting at Meetups
+6 -3
View File
@@ -12,7 +12,7 @@ RUN composer install --ignore-platform-reqs --optimize-autoloader \
--no-plugins --no-scripts --prefer-dist \
`if [ "$TESTING" != "true" ]; then echo "--no-dev"; fi`
FROM appwrite/base:0.9.5 AS final
FROM appwrite/base:0.10.1 AS final
LABEL maintainer="team@appwrite.io"
@@ -68,6 +68,7 @@ RUN chmod +x /usr/local/bin/doctor && \
chmod +x /usr/local/bin/sdks && \
chmod +x /usr/local/bin/specs && \
chmod +x /usr/local/bin/ssl && \
chmod +x /usr/local/bin/screenshot && \
chmod +x /usr/local/bin/test && \
chmod +x /usr/local/bin/upgrade && \
chmod +x /usr/local/bin/vars && \
@@ -85,8 +86,10 @@ RUN chmod +x /usr/local/bin/doctor && \
chmod +x /usr/local/bin/worker-messaging && \
chmod +x /usr/local/bin/worker-migrations && \
chmod +x /usr/local/bin/worker-webhooks && \
chmod +x /usr/local/bin/worker-usage && \
chmod +x /usr/local/bin/worker-usage-dump
chmod +x /usr/local/bin/worker-stats-usage && \
chmod +x /usr/local/bin/worker-stats-usage-dump && \
chmod +x /usr/local/bin/stats-resources && \
chmod +x /usr/local/bin/worker-stats-resources
# Letsencrypt Permissions
RUN mkdir -p /etc/letsencrypt/live/ && chmod -Rf 755 /etc/letsencrypt/live/
+61 -25
View File
@@ -1,8 +1,8 @@
> 好消息!Appwrite 云现已进入公开测试版!立即访问 cloud.appwrite.io 注册,体验无忧的托管服务。今天就加入我们的云端吧!☁️🎉
> 好消息!Appwrite 云现已进入公开测试版!立即访问 cloud.appwrite.io 注册,体验无忧的托管服务。今天就加入我们的云端吧!:cloud: :tada:
<br />
<p align="center">
<a href="https://appwrite.io" target="_blank"><img src="./public/images/banner.png" alt="Appwrite Logo"></a>
<a href="https://appwrite.io" target="_blank"><img src="./public/images/banner.png" alt="Appwrite banner with logo and slogan build like a team of hundreds""></a>
<br />
<br />
<b>适用于[Flutter/Vue/Angular/React/iOS/Android/* 等等平台 *]的完整后端服务</b>
@@ -36,6 +36,8 @@ Appwrite 可以提供给开发者用户验证,外部授权,用户数据读
内容:
- [开始](#开始)
- [安装](#安装)
- [Unix](#unix)
- [Windows](#windows)
@@ -54,6 +56,9 @@ Appwrite 可以提供给开发者用户验证,外部授权,用户数据读
- [订阅我们](#订阅我们)
- [版权说明](#版权说明)
## 开始
要轻松开始使用Appwrite,您可以[**免费注册Appwrite Cloud**](https://cloud.appwrite.io/)。在Appwrite Cloud公开测试版期间,您可以完全免费使用Appwrite,而且我们不会收集您的信用卡信息。
## 安装
Appwrite 的容器化服务器只需要一行指令就可以运行。您可以使用 docker-compose 在本地主机上运行 Appwrite,也可以在任何其他容器化工具(如 [Kubernetes](https://kubernetes.io/docs/home/)、[Docker Swarm](https://docs.docker.com/engine/swarm/) 或 [Rancher](https://rancher.com/docs/))上运行 Appwrite。
@@ -67,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.6.1
appwrite/appwrite:1.6.2
```
### Windows
@@ -79,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.6.1
appwrite/appwrite:1.6.2
```
#### PowerShell
@@ -89,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.6.1
appwrite/appwrite:1.6.2
```
运行后,可以在浏览器上访问 http://localhost 找到 Appwrite 控制台。在非 Linux 的本机主机上完成安装后,服务器可能需要几分钟才能启动。
@@ -98,7 +103,42 @@ docker run -it --rm `
### 从旧版本升级
如果您从旧版本升级 Appwrite 服务器,则应在设置完成后使用 Appwrite 迁移工具。有关这方面的更多信息,请查看 [安装文档](https://appwrite.io/docs/installation)。
如果您从旧版本升级 Appwrite 服务器,则应在设置完成后使用 Appwrite 迁移工具。有关这方面的更多信息,请查看 [安装文档](https://appwrite.io/docs/self-hosting)。
## 一键配置
除了在本地运行 Appwrite,您还可以使用预配置的设置启动 Appwrite。这样可以让您快速启动并运行 Appwrite,而无需在本地计算机上安装 Docker。
请从以下提供商中选择一个:
<table border="0">
<tr>
<td align="center" width="100" height="100">
<a href="https://marketplace.digitalocean.com/apps/appwrite">
<img width="50" height="39" src="public/images/integrations/digitalocean-logo.svg" alt="DigitalOcean Logo" />
<br /><sub><b>DigitalOcean</b></sub></a>
</a>
</td>
<td align="center" width="100" height="100">
<a href="https://gitpod.io/#https://github.com/appwrite/integration-for-gitpod">
<img width="50" height="39" src="public/images/integrations/gitpod-logo.svg" alt="Gitpod Logo" />
<br /><sub><b>Gitpod</b></sub></a>
</a>
</td>
<td align="center" width="100" height="100">
<a href="https://www.linode.com/marketplace/apps/appwrite/appwrite/">
<img width="50" height="39" src="public/images/integrations/akamai-logo.svg" alt="Akamai Logo" />
<br /><sub><b>Akamai Compute</b></sub></a>
</a>
</td>
<td align="center" width="100" height="100">
<a href="https://aws.amazon.com/marketplace/pp/prodview-2hiaeo2px4md6">
<img width="50" height="39" src="public/images/integrations/aws-logo.svg" alt="AWS Logo" />
<br /><sub><b>AWS Marketplace</b></sub></a>
</a>
</td>
</tr>
</table>
## 入门
@@ -146,29 +186,25 @@ docker run -it --rm `
以下是当前支持的平台和语言列表。如果您想帮助我们为您选择的平台添加支持,您可以访问我们的 [SDK 生成器](https://github.com/appwrite/sdk-generator) 项目并查看我们的 [贡献指南](https://github.com/appwrite/sdk-generator/blob/master/CONTRIBUTING.md)。
#### 客户端
- &nbsp; [Web](https://github.com/appwrite/sdk-for-web) (由 Appwrite 团队维护)
- &nbsp; [Flutter](https://github.com/appwrite/sdk-for-flutter) (由 Appwrite 团队维护)
- &nbsp; [Apple](https://github.com/appwrite/sdk-for-apple) (由 Appwrite 团队维护)
- ✅ &nbsp; [Android](https://github.com/appwrite/sdk-for-android) (由 Appwrite 团队维护)
- ✅ &nbsp; [React Native](https://github.com/appwrite/sdk-for-react-native) - **公测** (由 Appwrite 团队维护)
* :white_check_mark: &nbsp; [Web](https://github.com/appwrite/sdk-for-web) (由 Appwrite 团队维护)
* :white_check_mark: &nbsp; [Flutter](https://github.com/appwrite/sdk-for-flutter) (由 Appwrite 团队维护)
* :white_check_mark: &nbsp; [Apple](https://github.com/appwrite/sdk-for-apple) - **公测** (由 Appwrite 团队维护)
* :white_check_mark: &nbsp; [Android](https://github.com/appwrite/sdk-for-android) (由 Appwrite 团队维护)
#### 服务器
- &nbsp; [NodeJS](https://github.com/appwrite/sdk-for-node) (由 Appwrite 团队维护)
- &nbsp; [PHP](https://github.com/appwrite/sdk-for-php) (由 Appwrite 团队维护)
- &nbsp; [Dart](https://github.com/appwrite/sdk-for-dart) (由 Appwrite 团队维护)
- &nbsp; [Deno](https://github.com/appwrite/sdk-for-deno) (由 Appwrite 团队维护)
- &nbsp; [Ruby](https://github.com/appwrite/sdk-for-ruby) (由 Appwrite 团队维护)
- &nbsp; [Python](https://github.com/appwrite/sdk-for-python) (由 Appwrite 团队维护)
- &nbsp; [Kotlin](https://github.com/appwrite/sdk-for-kotlin) (由 Appwrite 团队维护)
- &nbsp; [Swift](https://github.com/appwrite/sdk-for-swift) (由 Appwrite 团队维护)
- ✅ &nbsp; [.NET](https://github.com/appwrite/sdk-for-dotnet) - **公测** (由 Appwrite 团队维护)
* :white_check_mark: &nbsp; [NodeJS](https://github.com/appwrite/sdk-for-node) (由 Appwrite 团队维护)
* :white_check_mark: &nbsp; [PHP](https://github.com/appwrite/sdk-for-php) (由 Appwrite 团队维护)
* :white_check_mark: &nbsp; [Dart](https://github.com/appwrite/sdk-for-dart) - (由 Appwrite 团队维护)
* :white_check_mark: &nbsp; [Deno](https://github.com/appwrite/sdk-for-deno) - **公测** (由 Appwrite 团队维护)
* :white_check_mark: &nbsp; [Ruby](https://github.com/appwrite/sdk-for-ruby) (由 Appwrite 团队维护)
* :white_check_mark: &nbsp; [Python](https://github.com/appwrite/sdk-for-python) (由 Appwrite 团队维护)
* :white_check_mark: &nbsp; [Kotlin](https://github.com/appwrite/sdk-for-kotlin) - **公测** (由 Appwrite 团队维护)
* :white_check_mark: &nbsp; [Apple](https://github.com/appwrite/sdk-for-apple) - **公测** (由 Appwrite 团队维护)
* :white_check_mark: &nbsp; [.NET](https://github.com/appwrite/sdk-for-dotnet) - **公测** (由 Appwrite 团队维护)
#### 开发者社区
- ✅ &nbsp; [Appcelerator Titanium](https://github.com/m1ga/ti.appwrite) (维护者 [Michael Gangolf](https://github.com/m1ga/))
- ✅ &nbsp; [Godot Engine](https://github.com/GodotNuts/appwrite-sdk) (维护者 [fenix-hub @GodotNuts](https://github.com/fenix-hub))
* :white_check_mark: &nbsp; [Appcelerator Titanium](https://github.com/m1ga/ti.appwrite) (维护者 [Michael Gangolf](https://github.com/m1ga/))
* :white_check_mark: &nbsp; [Godot Engine](https://github.com/GodotNuts/appwrite-sdk) (维护者 [fenix-hub @GodotNuts](https://github.com/fenix-hub))
找不到需要的的 SDK? - 欢迎通过发起 PR 来帮助我们完善 Appwrite 的软件生态环境 [SDK 生成器](https://github.com/appwrite/sdk-generator)!
+38 -34
View File
@@ -1,8 +1,8 @@
> Appwrite Init has concluded! You can check out all the latest announcements [on our Init website](https://appwrite.io/init) 🚀
> Appwrite Init has concluded! You can check out all the latest announcements [on our Init website](https://appwrite.io/init) :rocket:
<br />
<p align="center">
<a href="https://appwrite.io" target="_blank"><img src="./public/images/banner.png" alt="Appwrite Logo"></a>
<a href="https://appwrite.io" target="_blank"><img src="./public/images/banner.png" alt="Appwrite banner, with logo and text saying "Build Like a Team of Hundreds"></a>
<br />
<br />
<b>Appwrite is a backend platform for developing Web, Mobile, and Flutter applications. Built with the open source community and optimized for developer experience in the coding languages you love.</b>
@@ -12,11 +12,11 @@
<!-- [![Build Status](https://img.shields.io/travis/com/appwrite/appwrite?style=flat-square)](https://travis-ci.com/appwrite/appwrite) -->
[![We're Hiring](https://img.shields.io/static/v1?label=We're&message=Hiring&color=blue&style=flat-square)](https://appwrite.io/company/careers)
[![Hacktoberfest](https://img.shields.io/static/v1?label=hacktoberfest&message=ready&color=191120&style=flat-square)](https://hacktoberfest.appwrite.io)
[![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord?r=Github)
[![Build Status](https://img.shields.io/github/actions/workflow/status/appwrite/appwrite/tests.yml?branch=master&label=tests&style=flat-square)](https://github.com/appwrite/appwrite/actions)
[![X Account](https://img.shields.io/twitter/follow/appwrite?color=00acee&label=twitter&style=flat-square)](https://twitter.com/appwrite)
[![We're Hiring label](https://img.shields.io/static/v1?label=We're&message=Hiring&color=blue&style=flat-square)](https://appwrite.io/company/careers)
[![Hacktoberfest label](https://img.shields.io/static/v1?label=hacktoberfest&message=ready&color=191120&style=flat-square)](https://hacktoberfest.appwrite.io)
[![Discord label](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord?r=Github)
[![Build Status label](https://img.shields.io/github/actions/workflow/status/appwrite/appwrite/tests.yml?branch=master&label=tests&style=flat-square)](https://github.com/appwrite/appwrite/actions)
[![X Account label](https://img.shields.io/twitter/follow/appwrite?color=00acee&label=twitter&style=flat-square)](https://twitter.com/appwrite)
<!-- [![Docker Pulls](https://img.shields.io/docker/pulls/appwrite/appwrite?color=f02e65&style=flat-square)](https://hub.docker.com/r/appwrite/appwrite) -->
<!-- [![Translate](https://img.shields.io/badge/translate-f02e65?style=flat-square)](docs/tutorials/add-translations.md) -->
@@ -37,13 +37,14 @@ Using Appwrite, you can easily integrate your app with user authentication and m
<br />
</p>
![Appwrite](public/images/github.png)
![Appwrite project dashboard showing various Appwrite features](public/images/github.png)
Find out more at: [https://appwrite.io](https://appwrite.io)
Find out more at: [https://appwrite.io](https://appwrite.io).
Table of Contents:
- [Installation](#installation)
- [Getting Started](#getting-started)
- [Self-Hosting](#self-hosting)
- [Unix](#unix)
- [Windows](#windows)
- [CMD](#cmd)
@@ -62,11 +63,14 @@ Table of Contents:
- [Follow Us](#follow-us)
- [License](#license)
## Installation
## Getting Started
The easiest way to get started with Appwrite is by [signing up for Appwrite Cloud](https://cloud.appwrite.io/). While Appwrite Cloud is in public beta, you can build with Appwrite completely free, and we won't collect you credit card information.
## Self-Hosting
Appwrite is designed to run in a containerized environment. Running your server is as easy as running one command from your terminal. You can either run Appwrite on your localhost using docker-compose or on any other container orchestration tool, such as [Kubernetes](https://kubernetes.io/docs/home/), [Docker Swarm](https://docs.docker.com/engine/swarm/), or [Rancher](https://rancher.com/docs/).
The easiest way to start running your Appwrite server is by running our docker-compose file. Before running the installation command, make sure you have [Docker](https://www.docker.com/products/docker-desktop) installed on your machine:
Before running the installation command, make sure you have [Docker](https://www.docker.com/products/docker-desktop) installed on your machine:
### Unix
@@ -75,7 +79,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.6.1
appwrite/appwrite:1.6.2
```
### Windows
@@ -87,7 +91,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.6.1
appwrite/appwrite:1.6.2
```
#### PowerShell
@@ -97,7 +101,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.6.1
appwrite/appwrite:1.6.2
```
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.
@@ -106,7 +110,7 @@ For advanced production and custom installation, check out our Docker [environme
### Upgrade from an Older Version
If you are upgrading your Appwrite server from an older version, you should use the Appwrite migration tool once your setup is completed. For more information regarding this, check out the [Installation Docs](https://appwrite.io/docs/installation).
If you are upgrading your Appwrite server from an older version, you should use the Appwrite migration tool once your setup is completed. For more information regarding this, check out the [Installation Docs](https://appwrite.io/docs/self-hosting).
## One-Click Setups
@@ -192,34 +196,34 @@ Below is a list of currently supported platforms and languages. If you would lik
#### Client
- &nbsp; [Web](https://github.com/appwrite/sdk-for-web) (Maintained by the Appwrite Team)
- &nbsp; [Flutter](https://github.com/appwrite/sdk-for-flutter) (Maintained by the Appwrite Team)
- &nbsp; [Apple](https://github.com/appwrite/sdk-for-apple) (Maintained by the Appwrite Team)
- &nbsp; [Android](https://github.com/appwrite/sdk-for-android) (Maintained by the Appwrite Team)
- &nbsp; [React Native](https://github.com/appwrite/sdk-for-react-native) - **Beta** (Maintained by the Appwrite Team)
- :white_check_mark: &nbsp; [Web](https://github.com/appwrite/sdk-for-web) (Maintained by the Appwrite Team)
- :white_check_mark: &nbsp; [Flutter](https://github.com/appwrite/sdk-for-flutter) (Maintained by the Appwrite Team)
- :white_check_mark: &nbsp; [Apple](https://github.com/appwrite/sdk-for-apple) (Maintained by the Appwrite Team)
- :white_check_mark: &nbsp; [Android](https://github.com/appwrite/sdk-for-android) (Maintained by the Appwrite Team)
- :white_check_mark: &nbsp; [React Native](https://github.com/appwrite/sdk-for-react-native) - **Beta** (Maintained by the Appwrite Team)
#### Server
- &nbsp; [NodeJS](https://github.com/appwrite/sdk-for-node) (Maintained by the Appwrite Team)
- &nbsp; [PHP](https://github.com/appwrite/sdk-for-php) (Maintained by the Appwrite Team)
- &nbsp; [Dart](https://github.com/appwrite/sdk-for-dart) (Maintained by the Appwrite Team)
- &nbsp; [Deno](https://github.com/appwrite/sdk-for-deno) (Maintained by the Appwrite Team)
- &nbsp; [Ruby](https://github.com/appwrite/sdk-for-ruby) (Maintained by the Appwrite Team)
- &nbsp; [Python](https://github.com/appwrite/sdk-for-python) (Maintained by the Appwrite Team)
- &nbsp; [Kotlin](https://github.com/appwrite/sdk-for-kotlin) (Maintained by the Appwrite Team)
- &nbsp; [Swift](https://github.com/appwrite/sdk-for-swift) (Maintained by the Appwrite Team)
- &nbsp; [.NET](https://github.com/appwrite/sdk-for-dotnet) - **Beta** (Maintained by the Appwrite Team)
- :white_check_mark: &nbsp; [NodeJS](https://github.com/appwrite/sdk-for-node) (Maintained by the Appwrite Team)
- :white_check_mark: &nbsp; [PHP](https://github.com/appwrite/sdk-for-php) (Maintained by the Appwrite Team)
- :white_check_mark: &nbsp; [Dart](https://github.com/appwrite/sdk-for-dart) (Maintained by the Appwrite Team)
- :white_check_mark: &nbsp; [Deno](https://github.com/appwrite/sdk-for-deno) (Maintained by the Appwrite Team)
- :white_check_mark: &nbsp; [Ruby](https://github.com/appwrite/sdk-for-ruby) (Maintained by the Appwrite Team)
- :white_check_mark: &nbsp; [Python](https://github.com/appwrite/sdk-for-python) (Maintained by the Appwrite Team)
- :white_check_mark: &nbsp; [Kotlin](https://github.com/appwrite/sdk-for-kotlin) (Maintained by the Appwrite Team)
- :white_check_mark: &nbsp; [Swift](https://github.com/appwrite/sdk-for-swift) (Maintained by the Appwrite Team)
- :white_check_mark: &nbsp; [.NET](https://github.com/appwrite/sdk-for-dotnet) - **Beta** (Maintained by the Appwrite Team)
#### Community
- &nbsp; [Appcelerator Titanium](https://github.com/m1ga/ti.appwrite) (Maintained by [Michael Gangolf](https://github.com/m1ga/))
- &nbsp; [Godot Engine](https://github.com/GodotNuts/appwrite-sdk) (Maintained by [fenix-hub @GodotNuts](https://github.com/fenix-hub))
- :white_check_mark: &nbsp; [Appcelerator Titanium](https://github.com/m1ga/ti.appwrite) (Maintained by [Michael Gangolf](https://github.com/m1ga/))
- :white_check_mark: &nbsp; [Godot Engine](https://github.com/GodotNuts/appwrite-sdk) (Maintained by [fenix-hub @GodotNuts](https://github.com/fenix-hub))
Looking for more SDKs? - Help us by contributing a pull request to our [SDK Generator](https://github.com/appwrite/sdk-generator)!
## Architecture
![Appwrite Architecture](docs/specs/overview.drawio.svg)
![Appwrite Architecture showing how Appwrite is built and the services and tools it uses](docs/specs/overview.drawio.svg)
Appwrite uses a microservices architecture that was designed for easy scaling and delegation of responsibilities. In addition, Appwrite supports multiple APIs, such as REST, WebSocket, and GraphQL to allow you to interact with your resources by leveraging your existing knowledge and protocols of choice.
@@ -229,7 +233,7 @@ The Appwrite API layer was designed to be extremely fast by leveraging in-memory
All code contributions, including those of people having commit access, must go through a pull request and be approved by a core developer before being merged. This is to ensure a proper review of all the code.
We truly ❤️ pull requests! If you wish to help, you can learn more about how you can contribute to this project in the [contribution guide](CONTRIBUTING.md).
We truly :heart: pull requests! If you wish to help, you can learn more about how you can contribute to this project in the [contribution guide](CONTRIBUTING.md).
## Security
+46 -1
View File
@@ -5,6 +5,8 @@ require_once __DIR__ . '/init.php';
use Appwrite\Event\Certificate;
use Appwrite\Event\Delete;
use Appwrite\Event\Func;
use Appwrite\Event\StatsResources;
use Appwrite\Event\StatsUsage;
use Appwrite\Platform\Appwrite;
use Appwrite\Runtimes\Runtimes;
use Utopia\Cache\Adapter\Sharding;
@@ -24,7 +26,7 @@ use Utopia\Registry\Registry;
use Utopia\System\System;
// overwriting runtimes to be architectur agnostic for CLI
Config::setParam('runtimes', (new Runtimes('v4rc'))->getAll(supported: false));
Config::setParam('runtimes', (new Runtimes('v5'))->getAll(supported: false));
// require controllers after overwriting runtimes
require_once __DIR__ . '/controllers/general.php';
@@ -97,6 +99,10 @@ CLI::setResource('dbForPlatform', function ($pools, $cache) {
return $dbForPlatform;
}, ['pools', 'cache']);
CLI::setResource('console', function () {
return new Document(Config::getParam('console'));
}, []);
CLI::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform, $cache) {
$databases = []; // TODO: @Meldiron This should probably be responsibility of utopia-php/pools
@@ -160,6 +166,45 @@ CLI::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform
};
}, ['pools', 'dbForPlatform', 'cache']);
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());
return $database;
}
$dbAdapter = $pools
->get('logs')
->pop()
->getResource();
$database = new Database(
$dbAdapter,
$cache
);
$database
->setSharedTables(true)
->setNamespace('logsV1')
->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS)
->setMaxQueryValues(APP_DATABASE_QUERY_MAX_VALUES);
// set tenant
if ($project !== null && !$project->isEmpty() && $project->getId() !== 'console') {
$database->setTenant($project->getInternalId());
}
return $database;
};
}, ['pools', 'cache']);
CLI::setResource('queueForStatsUsage', function (Connection $publisher) {
return new StatsUsage($publisher);
}, ['publisher']);
CLI::setResource('queueForStatsResources', function (Publisher $publisher) {
return new StatsResources($publisher);
}, ['publisher']);
CLI::setResource('publisher', function (Group $pools) {
return $pools->get('publisher')->pop()->getResource();
}, ['pools']);
+2 -1
View File
@@ -16,5 +16,6 @@ return [
'union-china-pay' => ['name' => 'Union China Pay', 'path' => __DIR__ . '/credit-cards/union-china-pay.png'],
'visa' => ['name' => 'Visa', 'path' => __DIR__ . '/credit-cards/visa.png'],
'mir' => ['name' => 'MIR', 'path' => __DIR__ . '/credit-cards/mir.png'],
'maestro' => ['name' => 'Maestro', 'path' => __DIR__ . '/credit-cards/maestro.png']
'maestro' => ['name' => 'Maestro', 'path' => __DIR__ . '/credit-cards/maestro.png'],
'rupay' => ['name' => 'Rupay', 'path' => __DIR__ . '/credit-cards/rupay.png']
];
Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

+2
View File
@@ -5,6 +5,7 @@ $common = include __DIR__ . '/collections/common.php';
$projects = include __DIR__ . '/collections/projects.php';
$databases = include __DIR__ . '/collections/databases.php';
$platform = include __DIR__ . '/collections/platform.php';
$logs = include __DIR__ . '/collections/logs.php';
// see - http.php#245
// $collections['buckets']['files'];
@@ -27,6 +28,7 @@ $collections = [
'databases' => $databases,
'projects' => array_merge($projects, $common),
'console' => array_merge($platform, $common),
'logs' => $logs,
];
return $collections;
+94
View File
@@ -0,0 +1,94 @@
<?php
use Utopia\Database\Database;
use Utopia\Database\Helpers\ID;
$logsCollection = [];
$logsCollection['stats'] = [
'$collection' => ID::custom(Database::METADATA),
'$id' => ID::custom('stats'),
'name' => 'stats',
'attributes' => [
[
'$id' => ID::custom('metric'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 255,
'signed' => true,
'required' => true,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('region'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 255,
'signed' => true,
'required' => true,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('value'),
'type' => Database::VAR_INTEGER,
'format' => '',
'size' => 8,
'signed' => true,
'required' => true,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('time'),
'type' => Database::VAR_DATETIME,
'format' => '',
'size' => 0,
'signed' => false,
'required' => false,
'default' => null,
'array' => false,
'filters' => ['datetime'],
],
[
'$id' => ID::custom('period'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 4,
'signed' => true,
'required' => true,
'default' => null,
'array' => false,
'filters' => [],
],
],
'indexes' => [
[
'$id' => ID::custom('_key_time'),
'type' => Database::INDEX_KEY,
'attributes' => ['time'],
'lengths' => [],
'orders' => [Database::ORDER_DESC],
],
[
'$id' => ID::custom('_key_period_time'),
'type' => Database::INDEX_KEY,
'attributes' => ['period', 'time'],
'lengths' => [],
'orders' => [Database::ORDER_ASC],
],
[
'$id' => ID::custom('_key_metric_period_time'),
'type' => Database::INDEX_UNIQUE,
'attributes' => ['metric', 'period', 'time'],
'lengths' => [],
'orders' => [Database::ORDER_DESC],
],
],
];
return $logsCollection;
+144 -14
View File
@@ -1013,10 +1013,10 @@ return [
'filters' => [],
],
[
'$id' => ID::custom('resourceType'),
'$id' => ID::custom('type'), // 'api', 'redirect', 'deployment' (site or function)
'type' => Database::VAR_STRING,
'format' => '',
'size' => 100,
'size' => 32,
'signed' => true,
'required' => true,
'default' => null,
@@ -1024,10 +1024,32 @@ return [
'filters' => [],
],
[
'$id' => ID::custom('resourceInternalId'),
'$id' => ID::custom('trigger'), // 'manual', 'deployment', '' (empty)
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'size' => 32,
'signed' => true,
'required' => false,
'default' => '',
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('redirectUrl'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 2048,
'signed' => true,
'required' => false,
'default' => '',
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('redirectStatusCode'),
'type' => Database::VAR_INTEGER,
'format' => '',
'size' => 0,
'signed' => true,
'required' => false,
'default' => null,
@@ -1035,13 +1057,68 @@ return [
'filters' => [],
],
[
'$id' => ID::custom('resourceId'),
'$id' => ID::custom('deploymentResourceType'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 32,
'signed' => true,
'required' => false,
'default' => '',
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('deploymentId'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'default' => '',
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('deploymentInternalId'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => '',
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('deploymentResourceId'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => '',
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('deploymentResourceInternalId'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => '',
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('deploymentVcsProviderBranch'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => '',
'array' => false,
'filters' => [],
],
@@ -1066,9 +1143,27 @@ return [
'default' => null,
'array' => false,
'filters' => [],
]
],
[
'$id' => ID::custom('search'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16384,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
],
'indexes' => [
[
'$id' => ID::custom('_key_search'),
'type' => Database::INDEX_FULLTEXT,
'attributes' => ['search'],
'lengths' => [],
'orders' => [],
],
[
'$id' => ID::custom('_key_domain'),
'type' => Database::INDEX_UNIQUE,
@@ -1091,24 +1186,59 @@ return [
'orders' => [Database::ORDER_ASC],
],
[
'$id' => '_key_resourceInternalId',
'$id' => '_key_type',
'type' => Database::INDEX_KEY,
'attributes' => ['resourceInternalId'],
'attributes' => ['type'],
'lengths' => [32],
'orders' => [Database::ORDER_ASC],
],
[
'$id' => '_key_trigger',
'type' => Database::INDEX_KEY,
'attributes' => ['trigger'],
'lengths' => [32],
'orders' => [Database::ORDER_ASC],
],
[
'$id' => '_key_deploymentResourceType',
'type' => Database::INDEX_KEY,
'attributes' => ['deploymentResourceType'],
'lengths' => [32],
'orders' => [Database::ORDER_ASC],
],
[
'$id' => '_key_deploymentResourceId',
'type' => Database::INDEX_KEY,
'attributes' => ['deploymentResourceId'],
'lengths' => [Database::LENGTH_KEY],
'orders' => [Database::ORDER_ASC],
],
[
'$id' => '_key_resourceId',
'$id' => '_key_deploymentResourceInternalId',
'type' => Database::INDEX_KEY,
'attributes' => ['resourceId'],
'attributes' => ['deploymentResourceInternalId'],
'lengths' => [Database::LENGTH_KEY],
'orders' => [Database::ORDER_ASC],
],
[
'$id' => '_key_resourceType',
'$id' => '_key_deploymentId',
'type' => Database::INDEX_KEY,
'attributes' => ['resourceType'],
'lengths' => [],
'attributes' => ['deploymentId'],
'lengths' => [Database::LENGTH_KEY],
'orders' => [Database::ORDER_ASC],
],
[
'$id' => '_key_deploymentInternalId',
'type' => Database::INDEX_KEY,
'attributes' => ['deploymentInternalId'],
'lengths' => [Database::LENGTH_KEY],
'orders' => [Database::ORDER_ASC],
],
[
'$id' => '_key_deploymentVcsProviderBranch',
'type' => Database::INDEX_KEY,
'attributes' => ['deploymentVcsProviderBranch'],
'lengths' => [Database::LENGTH_KEY],
'orders' => [Database::ORDER_ASC],
],
],
+132 -225
View File
@@ -569,7 +569,7 @@ return [
'filters' => [],
],
[
'$id' => ID::custom('deployment'),
'$id' => ID::custom('deploymentId'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
@@ -674,7 +674,7 @@ return [
'size' => 8,
'signed' => true,
'required' => false,
'default' => 'v4',
'default' => 'v5',
'array' => false,
'filters' => [],
],
@@ -788,9 +788,9 @@ return [
'orders' => [Database::ORDER_ASC],
],
[
'$id' => ID::custom('_key_deployment'),
'$id' => ID::custom('_key_deploymentId'),
'type' => Database::INDEX_KEY,
'attributes' => ['deployment'],
'attributes' => ['deploymentId'],
'lengths' => [],
'orders' => [Database::ORDER_ASC],
]
@@ -1154,7 +1154,6 @@ return [
]
],
],
'deployments' => [
'$collection' => ID::custom(Database::METADATA),
'$id' => ID::custom('deployments'),
@@ -1193,28 +1192,6 @@ return [
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('buildInternalId'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('buildId'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'array' => false,
'$id' => ID::custom('entrypoint'),
@@ -1228,18 +1205,7 @@ return [
],
[
'array' => false,
'$id' => ID::custom('commands'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 2048,
'signed' => true,
'required' => false,
'default' => null,
'filters' => [],
],
[
'array' => false,
'$id' => ID::custom('buildCommand'),
'$id' => ID::custom('buildCommands'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16384,
@@ -1250,7 +1216,7 @@ return [
],
[
'array' => false,
'$id' => ID::custom('installCommand'),
'$id' => ID::custom('buildOutput'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16384,
@@ -1260,18 +1226,7 @@ return [
'filters' => [],
],
[
'array' => false,
'$id' => ID::custom('outputDirectory'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16384,
'signed' => true,
'required' => false,
'default' => null,
'filters' => [],
],
[
'$id' => ID::custom('path'),
'$id' => ID::custom('sourcePath'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 2048,
@@ -1285,7 +1240,7 @@ return [
'$id' => ID::custom('type'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 2048,
'size' => 32,
'signed' => true,
'required' => true,
'default' => null,
@@ -1464,7 +1419,7 @@ return [
'array' => false,
],
[
'$id' => ID::custom('size'),
'$id' => ID::custom('sourceSize'),
'type' => Database::VAR_INTEGER,
'format' => '',
'size' => 0,
@@ -1475,7 +1430,7 @@ return [
'filters' => [],
],
[
'$id' => ID::custom('metadata'),
'$id' => ID::custom('sourceMetadata'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16384, // https://tools.ietf.org/html/rfc4288#section-4.2
@@ -1486,7 +1441,7 @@ return [
'filters' => ['json'],
],
[
'$id' => ID::custom('chunksTotal'),
'$id' => ID::custom('sourceChunksTotal'),
'type' => Database::VAR_INTEGER,
'format' => '',
'size' => 0,
@@ -1497,7 +1452,7 @@ return [
'filters' => [],
],
[
'$id' => ID::custom('chunksUploaded'),
'$id' => ID::custom('sourceChunksUploaded'),
'type' => Database::VAR_INTEGER,
'format' => '',
'size' => 0,
@@ -1528,6 +1483,105 @@ return [
'default' => false,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('screenshotLight'), // File ID from 'screenshots' Console bucket
'type' => Database::VAR_STRING,
'format' => '',
'size' => 32,
'signed' => false,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('screenshotDark'), // File ID from 'screenshots' Console bucket
'type' => Database::VAR_STRING,
'format' => '',
'size' => 32,
'signed' => false,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('buildStartAt'),
'type' => Database::VAR_DATETIME,
'format' => '',
'size' => 0,
'signed' => false,
'required' => false,
'default' => null,
'array' => false,
'filters' => ['datetime'],
],
[
'$id' => ID::custom('buildEndAt'),
'type' => Database::VAR_DATETIME,
'format' => '',
'size' => 0,
'signed' => false,
'required' => false,
'default' => null,
'array' => false,
'filters' => ['datetime'],
],
[
'$id' => ID::custom('buildDuration'),
'type' => Database::VAR_INTEGER,
'format' => '',
'size' => 0,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('buildSize'),
'type' => Database::VAR_INTEGER,
'format' => '',
'size' => 0,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('status'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16,
'signed' => true,
'required' => true,
'default' => 'waiting',
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('buildPath'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => '',
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('buildLogs'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 1000000,
'signed' => true,
'required' => false,
'default' => '',
'array' => false,
'filters' => [],
]
],
'indexes' => [
@@ -1553,16 +1607,23 @@ return [
'orders' => [],
],
[
'$id' => ID::custom('_key_size'),
'$id' => ID::custom('_key_sourceSize'),
'type' => Database::INDEX_KEY,
'attributes' => ['size'],
'attributes' => ['sourceSize'],
'lengths' => [],
'orders' => [Database::ORDER_ASC],
],
[
'$id' => ID::custom('_key_buildId'),
'$id' => ID::custom('_key_buildSize'),
'type' => Database::INDEX_KEY,
'attributes' => ['buildId'],
'attributes' => ['buildSize'],
'lengths' => [],
'orders' => [Database::ORDER_ASC],
],
[
'$id' => ID::custom('_key_buildDuration'),
'type' => Database::INDEX_KEY,
'attributes' => ['buildDuration'],
'lengths' => [],
'orders' => [Database::ORDER_ASC],
],
@@ -1573,155 +1634,19 @@ return [
'lengths' => [],
'orders' => [Database::ORDER_ASC],
],
],
],
'builds' => [
'$collection' => ID::custom(Database::METADATA),
'$id' => ID::custom('builds'),
'name' => 'Builds',
'attributes' => [
[
'$id' => ID::custom('startTime'),
'type' => Database::VAR_DATETIME,
'format' => '',
'size' => 0,
'signed' => false,
'required' => false,
'default' => null,
'array' => false,
'filters' => ['datetime'],
],
[
'$id' => ID::custom('endTime'),
'type' => Database::VAR_DATETIME,
'format' => '',
'size' => 0,
'signed' => false,
'required' => false,
'default' => null,
'array' => false,
'filters' => ['datetime'],
],
[
'$id' => ID::custom('duration'),
'type' => Database::VAR_INTEGER,
'format' => '',
'size' => 0,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('size'),
'type' => Database::VAR_INTEGER,
'format' => '',
'size' => 0,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('deploymentInternalId'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('deploymentId'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('runtime'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 2048,
'signed' => true,
'required' => true,
'default' => '',
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('status'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 256,
'signed' => true,
'required' => true,
'default' => 'processing',
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('path'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 2048,
'signed' => true,
'required' => false,
'default' => '',
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('logs'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 1000000,
'signed' => true,
'required' => false,
'default' => '',
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('sourceType'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 2048,
'signed' => true,
'required' => true,
'default' => 'local',
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('source'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 2048,
'signed' => true,
'required' => true,
'default' => '',
'array' => false,
'filters' => [],
]
],
'indexes' => [
[
'$id' => ID::custom('_key_deployment'),
'$id' => ID::custom('_key_type'),
'type' => Database::INDEX_KEY,
'attributes' => ['deploymentId'],
'lengths' => [Database::LENGTH_KEY],
'attributes' => ['type'],
'lengths' => [32],
'orders' => [Database::ORDER_ASC],
]
], [
'$id' => ID::custom('_key_status'),
'type' => Database::INDEX_KEY,
'attributes' => ['status'],
'lengths' => [16],
'orders' => [Database::ORDER_ASC],
],
],
],
@@ -1895,17 +1820,6 @@ return [
'array' => false,
'filters' => ['json'],
],
[
'$id' => ID::custom('search'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16384,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('scheduledAt'),
'type' => Database::VAR_DATETIME,
@@ -1948,13 +1862,6 @@ return [
'lengths' => [Database::LENGTH_KEY],
'orders' => [Database::ORDER_ASC],
],
[
'$id' => ID::custom('_fulltext_search'),
'type' => Database::INDEX_FULLTEXT,
'attributes' => ['search'],
'lengths' => [],
'orders' => [],
],
[
'$id' => ID::custom('_key_trigger'),
'type' => Database::INDEX_KEY,
+52
View File
@@ -0,0 +1,52 @@
<?php
/**
* Initializes console project document.
*/
use Appwrite\Auth\Auth;
use Appwrite\Network\Validator\Origin;
use Utopia\Database\Helpers\ID;
use Utopia\System\System;
$console = [
'$id' => ID::custom('console'),
'$internalId' => ID::custom('console'),
'name' => 'Appwrite',
'$collection' => ID::custom('projects'),
'description' => 'Appwrite core engine',
'logo' => '',
'teamId' => null,
'webhooks' => [],
'keys' => [],
'platforms' => [
[
'$collection' => ID::custom('platforms'),
'name' => 'Localhost',
'type' => Origin::CLIENT_TYPE_WEB,
'hostname' => 'localhost',
], // Current host is added on app init
],
'legalName' => '',
'legalCountry' => '',
'legalState' => '',
'legalCity' => '',
'legalAddress' => '',
'legalTaxId' => '',
'auths' => [
'mockNumbers' => [],
'invites' => System::getEnv('_APP_CONSOLE_INVITES', 'enabled') === 'enabled',
'limit' => (System::getEnv('_APP_CONSOLE_WHITELIST_ROOT', 'enabled') === 'enabled') ? 1 : 0, // limit signup to 1 user
'duration' => Auth::TOKEN_EXPIRATION_LOGIN_LONG, // 1 Year in seconds
'sessionAlerts' => System::getEnv('_APP_CONSOLE_SESSION_ALERTS', 'disabled') === 'enabled'
],
'authWhitelistEmails' => (!empty(System::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null))) ? \explode(',', System::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null)) : [],
'authWhitelistIPs' => (!empty(System::getEnv('_APP_CONSOLE_WHITELIST_IPS', null))) ? \explode(',', System::getEnv('_APP_CONSOLE_WHITELIST_IPS', null)) : [],
'oAuthProviders' => [
'githubEnabled' => true,
'githubSecret' => System::getEnv('_APP_CONSOLE_GITHUB_SECRET', ''),
'githubAppid' => System::getEnv('_APP_CONSOLE_GITHUB_APP_ID', '')
],
];
return $console;
+7 -2
View File
@@ -356,7 +356,7 @@ return [
],
Exception::TEAM_INVALID_SECRET => [
'name' => Exception::TEAM_INVALID_SECRET,
'description' => 'The team invitation secret is invalid. Please request a new invitation and try again.',
'description' => 'The team invitation secret is invalid. Please request a new invitation and try again.',
'code' => 401,
],
Exception::TEAM_MEMBERSHIP_MISMATCH => [
@@ -527,7 +527,7 @@ return [
'code' => 404,
],
Exception::FUNCTION_ENTRYPOINT_MISSING => [
'name' => Exception::FUNCTION_RUNTIME_UNSUPPORTED,
'name' => Exception::FUNCTION_ENTRYPOINT_MISSING,
'description' => 'Entrypoint for your Appwrite Function is missing. Please specify it when making deployment or update the entrypoint under your function\'s "Settings" > "Configuration" > "Entrypoint".',
'code' => 404,
],
@@ -541,6 +541,11 @@ return [
'description' => 'Function Template with the requested ID could not be found.',
'code' => 404,
],
Exception::FUNCTION_RUNTIME_NOT_DETECTED => [
'name' => Exception::FUNCTION_RUNTIME_NOT_DETECTED,
'description' => 'Function runtime could not be detected.',
'code' => 400,
],
/** Sites */
Exception::SITE_NOT_FOUND => [
+114 -33
View File
@@ -4,8 +4,6 @@
* List of Appwrite Sites supported frameworks
*/
// TODO: @Meldiron Angular
use Utopia\Config\Config;
$templateRuntimes = Config::getParam('template-runtimes');
@@ -18,11 +16,63 @@ function getVersions(array $versions, string $prefix)
}
return [
'analog' => [
'key' => 'analog',
'name' => 'Analog',
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'bundleCommand' => 'sh /usr/local/server/helpers/analog/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/analog/env.sh',
'adapters' => [
'ssr' => [
'key' => 'ssr',
'buildCommand' => 'npm run build',
'installCommand' => 'npm install',
'outputDirectory' => './dist/analog',
'startCommand' => 'sh helpers/analog/server.sh',
],
'static' => [
'key' => 'static',
'buildCommand' => 'npm run build',
'installCommand' => 'npm install',
'outputDirectory' => './dist/analog/public',
'startCommand' => 'sh helpers/server.sh',
'fallbackFile' => 'index.html'
]
]
],
'angular' => [
'key' => 'angular',
'name' => 'Angular',
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'bundleCommand' => 'sh /usr/local/server/helpers/angular/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/angular/env.sh',
'adapters' => [
'ssr' => [
'key' => 'ssr',
'buildCommand' => 'npm run build',
'installCommand' => 'npm install',
'outputDirectory' => './dist/angular',
'startCommand' => 'sh helpers/angular/server.sh',
],
'static' => [
'key' => 'static',
'buildCommand' => 'npm run build',
'installCommand' => 'npm install',
'outputDirectory' => './dist/angular/browser',
'startCommand' => 'sh helpers/server.sh',
'fallbackFile' => 'index.csr.html'
]
]
],
'nextjs' => [
'key' => 'nextjs',
'name' => 'Next.js',
'buildRuntime' => 'ssr-22',
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'bundleCommand' => 'sh /usr/local/server/helpers/next-js/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/next-js/env.sh',
'adapters' => [
'ssr' => [
'key' => 'ssr',
@@ -30,8 +80,6 @@ return [
'installCommand' => 'npm install',
'outputDirectory' => './.next',
'startCommand' => 'sh helpers/next-js/server.sh',
'bundleCommand' => 'sh /usr/local/server/helpers/next-js/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/next-js/env.sh',
],
'static' => [
'key' => 'static',
@@ -39,16 +87,32 @@ return [
'installCommand' => 'npm install',
'outputDirectory' => './out',
'startCommand' => 'sh helpers/server.sh',
'bundleCommand' => '',
'envCommand' => '',
]
]
],
'react' => [
'key' => 'react',
'name' => 'React',
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'adapters' => [
'static' => [
'key' => 'static',
'buildCommand' => 'npm run build',
'installCommand' => 'npm install',
'outputDirectory' => './dist',
'startCommand' => 'sh helpers/server.sh',
'fallbackFile' => 'index.html'
]
]
],
'nuxt' => [
'key' => 'nuxt',
'name' => 'Nuxt',
'buildRuntime' => 'ssr-22',
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'bundleCommand' => 'sh /usr/local/server/helpers/nuxt/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/nuxt/env.sh',
'adapters' => [
'ssr' => [
'key' => 'ssr',
@@ -56,25 +120,39 @@ return [
'installCommand' => 'npm install',
'outputDirectory' => './.output',
'startCommand' => 'sh helpers/nuxt/server.sh',
'bundleCommand' => 'sh /usr/local/server/helpers/nuxt/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/nuxt/env.sh',
],
'static' => [
'key' => 'static',
'buildCommand' => 'npm run generate',
'installCommand' => 'npm install',
'outputDirectory' => './output/public',
'startCommand' => 'sh helpers/server.sh',
]
]
],
'vue' => [
'key' => 'vue',
'name' => 'Vue.js',
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'adapters' => [
'static' => [
'key' => 'static',
'buildCommand' => 'npm run build',
'installCommand' => 'npm install',
'outputDirectory' => './dist',
'startCommand' => 'sh helpers/server.sh',
'bundleCommand' => '',
'envCommand' => '',
'fallbackFile' => 'index.html'
]
]
],
'sveltekit' => [
'key' => 'sveltekit',
'name' => 'SvelteKit',
'buildRuntime' => 'ssr-22',
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'bundleCommand' => 'sh /usr/local/server/helpers/sveltekit/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/sveltekit/env.sh',
'adapters' => [
'ssr' => [
'key' => 'ssr',
@@ -82,8 +160,6 @@ return [
'installCommand' => 'npm install',
'outputDirectory' => './build',
'startCommand' => 'sh helpers/sveltekit/server.sh',
'bundleCommand' => 'sh /usr/local/server/helpers/sveltekit/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/sveltekit/env.sh',
],
'static' => [
'key' => 'static',
@@ -91,16 +167,16 @@ return [
'installCommand' => 'npm install',
'outputDirectory' => './build',
'startCommand' => 'sh helpers/server.sh',
'bundleCommand' => '',
'envCommand' => '',
]
]
],
'astro' => [
'key' => 'astro',
'name' => 'Astro',
'buildRuntime' => 'ssr-22',
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'bundleCommand' => 'sh /usr/local/server/helpers/astro/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/astro/env.sh',
'adapters' => [
'ssr' => [
'key' => 'ssr',
@@ -108,8 +184,6 @@ return [
'installCommand' => 'npm install',
'outputDirectory' => './dist',
'startCommand' => 'sh helpers/astro/server.sh',
'bundleCommand' => 'sh /usr/local/server/helpers/astro/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/astro/env.sh',
],
'static' => [
'key' => 'static',
@@ -117,16 +191,16 @@ return [
'installCommand' => 'npm install',
'outputDirectory' => './dist',
'startCommand' => 'sh helpers/server.sh',
'bundleCommand' => '',
'envCommand' => '',
]
]
],
'remix' => [
'key' => 'remix',
'name' => 'Remix',
'buildRuntime' => 'ssr-22',
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'bundleCommand' => 'sh /usr/local/server/helpers/remix/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/remix/env.sh',
'adapters' => [
'ssr' => [
'key' => 'ssr',
@@ -134,8 +208,6 @@ return [
'installCommand' => 'npm install',
'outputDirectory' => './build',
'startCommand' => 'sh helpers/remix/server.sh',
'bundleCommand' => 'sh /usr/local/server/helpers/remix/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/remix/env.sh',
],
'static' => [
'key' => 'static',
@@ -143,15 +215,13 @@ return [
'installCommand' => 'npm install',
'outputDirectory' => './build/client',
'startCommand' => 'sh helpers/server.sh',
'bundleCommand' => '',
'envCommand' => '',
]
]
],
'flutter' => [
'key' => 'flutter',
'name' => 'Flutter',
'buildRuntime' => 'flutter-3.24',
'buildRuntime' => 'flutter-3.29',
'runtimes' => getVersions($templateRuntimes['FLUTTER']['versions'], 'flutter'),
'adapters' => [
'static' => [
@@ -160,15 +230,28 @@ return [
'installCommand' => '',
'outputDirectory' => './build/web',
'startCommand' => 'sh helpers/server.sh',
'bundleCommand' => '',
'envCommand' => '',
],
],
],
'vite' => [
'key' => 'vite',
'name' => 'Vite',
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'adapters' => [
'static' => [
'key' => 'static',
'buildCommand' => 'npm run build',
'installCommand' => 'npm install',
'outputDirectory' => './dist',
'startCommand' => 'sh helpers/server.sh',
],
]
],
'other' => [
'key' => 'other',
'name' => 'Other',
'buildRuntime' => 'ssr-22',
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'adapters' => [
'static' => [
@@ -177,8 +260,6 @@ return [
'installCommand' => '',
'outputDirectory' => './',
'startCommand' => 'sh helpers/server.sh',
'bundleCommand' => '',
'envCommand' => '',
],
]
],
+1 -1
View File
@@ -6,4 +6,4 @@
use Appwrite\Runtimes\Runtimes;
return (new Runtimes('v4rc'))->getAll();
return (new Runtimes('v5'))->getAll();
-51
View File
@@ -1,51 +0,0 @@
<?php
use Appwrite\Functions\Specification;
return [
Specification::S_05VCPU_512MB => [
'slug' => Specification::S_05VCPU_512MB,
'memory' => 512,
'cpus' => 0.5
],
Specification::S_1VCPU_512MB => [
'slug' => Specification::S_1VCPU_512MB,
'memory' => 512,
'cpus' => 1
],
Specification::S_1VCPU_1GB => [
'slug' => Specification::S_1VCPU_1GB,
'memory' => 1024,
'cpus' => 1
],
Specification::S_2VCPU_2GB => [
'slug' => Specification::S_2VCPU_2GB,
'memory' => 2048,
'cpus' => 2
],
Specification::S_2VCPU_4GB => [
'slug' => Specification::S_2VCPU_4GB,
'memory' => 4096,
'cpus' => 2
],
Specification::S_4VCPU_4GB => [
'slug' => Specification::S_4VCPU_4GB,
'memory' => 4096,
'cpus' => 4
],
Specification::S_4VCPU_8GB => [
'slug' => Specification::S_4VCPU_8GB,
'memory' => 8192,
'cpus' => 4
],
Specification::S_8VCPU_4GB => [
'slug' => Specification::S_8VCPU_4GB,
'memory' => 4096,
'cpus' => 8
],
Specification::S_8VCPU_8GB => [
'slug' => Specification::S_8VCPU_8GB,
'memory' => 8192,
'cpus' => 8
]
];
+1 -1
View File
@@ -191,7 +191,7 @@ return [
'name' => 'Functions',
'subtitle' => 'The Functions Service allows you view, create and manage your Cloud Functions.',
'description' => '/docs/services/functions.md',
'controller' => 'api/functions.php',
'controller' => '', // Uses modules
'sdk' => true,
'docs' => true,
'docsUrl' => 'https://appwrite.io/docs/functions',
-181
View File
@@ -1,181 +0,0 @@
<?php
/**
* List of Appwrite Sites templates
*/
// TODO: @Meldiron Angular
const TEMPLATE_FRAMEWORKS = [
'SVELTEKIT' => [
'key' => 'sveltekit',
'name' => 'SvelteKit',
'installCommand' => 'npm install',
'buildCommand' => 'npm run build',
'outputDirectory' => './build',
'buildRuntime' => 'ssr-22',
'adapter' => 'ssr',
'fallbackFile' => null,
],
'NEXTJS' => [
'key' => 'nextjs',
'name' => 'Next.js',
'installCommand' => 'npm install',
'buildCommand' => 'npm run build',
'outputDirectory' => './.next',
'buildRuntime' => 'ssr-22',
'adapter' => 'ssr',
'fallbackFile' => null,
],
'NUXT' => [
'key' => 'nuxt',
'name' => 'Nuxt',
'installCommand' => 'npm install',
'buildCommand' => 'npm run build',
'outputDirectory' => './.output',
'buildRuntime' => 'ssr-22',
'adapter' => 'ssr',
'fallbackFile' => null,
],
'REMIX' => [
'key' => 'remix',
'name' => 'Remix',
'installCommand' => 'npm install',
'buildCommand' => 'npm run build',
'outputDirectory' => './build',
'buildRuntime' => 'ssr-22',
'adapter' => 'ssr',
'fallbackFile' => null,
],
'ASTRO' => [
'key' => 'astro',
'name' => 'Astro',
'installCommand' => 'npm install',
'buildCommand' => 'npm run build',
'outputDirectory' => './dist',
'buildRuntime' => 'ssr-22',
'adapter' => 'ssr',
'fallbackFile' => null,
],
'FLUTTER' => [
'key' => 'flutter',
'name' => 'Flutter',
'installCommand' => '',
'buildCommand' => 'flutter build web',
'outputDirectory' => './build/web',
'buildRuntime' => 'flutter-3.24',
'adapter' => 'static',
'fallbackFile' => null,
],
];
function getFramework(string $frameworkEnum, array $overrides)
{
$settings = \array_merge(TEMPLATE_FRAMEWORKS[$frameworkEnum], $overrides);
return $settings;
}
return [
[
'key' => 'nextjs-starter',
'name' => 'Next.js starter website',
'useCases' => ['starter'],
'demoUrl' => 'https://nextjs-starter.sites.qa17.appwrite.org/',
'demoImage' => 'https://qa17.appwrite.org/console/images/sites/templates/nextjs-starter.png',
'frameworks' => [
getFramework('NEXTJS', [
'providerRootDirectory' => './nextjs/starter',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.2.*',
'variables' => [],
],
[
'key' => 'nuxt-starter',
'name' => 'Nuxt starter website',
'useCases' => ['starter'],
'demoUrl' => 'https://nuxt-starter.sites.qa17.appwrite.org/',
'demoImage' => 'https://qa17.appwrite.org/console/images/sites/templates/nuxt-starter.png',
'frameworks' => [
getFramework('NUXT', [
'providerRootDirectory' => './nuxt/starter',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.2.*',
'variables' => [],
],
[
'key' => 'sveltekit-starter',
'name' => 'SvelteKit starter website',
'useCases' => ['starter'],
'demoUrl' => 'https://sveltekit-starter.sites.qa17.appwrite.org/',
'demoImage' => 'https://qa17.appwrite.org/console/images/sites/templates/sveltekit-starter.png',
'frameworks' => [
getFramework('SVELTEKIT', [
'providerRootDirectory' => './sveltekit/starter',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.2.*',
'variables' => [],
],
[
'key' => 'astro-starter',
'name' => 'Astro starter website',
'useCases' => ['starter'],
'demoUrl' => 'https://astro-starter.sites.qa17.appwrite.org/',
'demoImage' => 'https://qa17.appwrite.org/console/images/sites/templates/astro-starter.png',
'frameworks' => [
getFramework('ASTRO', [
'providerRootDirectory' => './astro/starter',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.2.*',
'variables' => [],
],
[
'key' => 'remix-starter',
'name' => 'Remix starter website',
'useCases' => ['starter'],
'demoUrl' => 'https://remix-starter.sites.qa17.appwrite.org/',
'demoImage' => 'https://qa17.appwrite.org/console/images/sites/templates/remix-starter.png',
'frameworks' => [
getFramework('REMIX', [
'providerRootDirectory' => './remix/starter',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.2.*',
'variables' => [],
],
[
'key' => 'flutter-starter',
'name' => 'Flutter starter website',
'useCases' => ['starter'],
'demoUrl' => 'https://flutter-starter.sites.qa17.appwrite.org/',
'demoImage' => 'https://qa17.appwrite.org/console/images/sites/templates/flutter-starter.png',
'frameworks' => [
getFramework('FLUTTER', [
'providerRootDirectory' => './flutter/starter',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.2.*',
'variables' => [],
],
];
@@ -1,6 +1,6 @@
<?php
use Appwrite\Sites\Specification;
use Appwrite\Platform\Modules\Compute\Specification;
return [
Specification::S_05VCPU_512MB => [
+6 -4
View File
@@ -3383,7 +3383,7 @@
"parameters": [
{
"name": "code",
"description": "Credit Card Code. Possible values: amex, argencard, cabal, cencosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.",
"description": "Credit Card Code. Possible values: amex, argencard, cabal, cencosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro, rupay.",
"required": true,
"schema": {
"type": "string",
@@ -3404,7 +3404,8 @@
"union-china-pay",
"visa",
"mir",
"maestro"
"maestro",
"rupay"
],
"x-enum-name": "CreditCard",
"x-enum-keys": [
@@ -3423,7 +3424,8 @@
"Union China Pay",
"Visa",
"MIR",
"Maestro"
"Maestro",
"Rupay"
]
},
"in": "path"
@@ -4365,7 +4367,7 @@
"tags": [
"databases"
],
"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.",
"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.\n",
"responses": {
"201": {
"description": "Document",
+133 -89
View File
@@ -3387,7 +3387,7 @@
"parameters": [
{
"name": "code",
"description": "Credit Card Code. Possible values: amex, argencard, cabal, cencosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.",
"description": "Credit Card Code. Possible values: amex, argencard, cabal, cencosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro, rupay.",
"required": true,
"schema": {
"type": "string",
@@ -3408,7 +3408,8 @@
"union-china-pay",
"visa",
"mir",
"maestro"
"maestro",
"rupay"
],
"x-enum-name": "CreditCard",
"x-enum-keys": [
@@ -3427,7 +3428,8 @@
"Union China Pay",
"Visa",
"MIR",
"Maestro"
"Maestro",
"Rupay"
]
},
"in": "path"
@@ -6407,8 +6409,6 @@
},
"required": [
"required",
"min",
"max",
"default"
]
}
@@ -6644,8 +6644,6 @@
},
"required": [
"required",
"min",
"max",
"default"
]
}
@@ -7823,7 +7821,7 @@
"tags": [
"databases"
],
"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.",
"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.\n",
"responses": {
"201": {
"description": "Document",
@@ -11585,7 +11583,7 @@
},
"x-appwrite": {
"method": "getCertificate",
"weight": 134,
"weight": 133,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11692,7 +11690,7 @@
},
"x-appwrite": {
"method": "getPubSub",
"weight": 130,
"weight": 129,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11718,54 +11716,6 @@
]
}
},
"\/health\/queue": {
"get": {
"summary": "Get queue",
"operationId": "healthGetQueue",
"tags": [
"health"
],
"description": "Check the Appwrite queue messaging servers are up and connection is successful.",
"responses": {
"200": {
"description": "Health Status",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/healthStatus"
}
}
}
}
},
"x-appwrite": {
"method": "getQueue",
"weight": 129,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "health\/get-queue.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue.md",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "health.read",
"platforms": [
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Key": []
}
]
}
},
"\/health\/queue\/builds": {
"get": {
"summary": "Get builds queue",
@@ -11788,7 +11738,7 @@
},
"x-appwrite": {
"method": "getQueueBuilds",
"weight": 136,
"weight": 135,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11849,7 +11799,7 @@
},
"x-appwrite": {
"method": "getQueueCertificates",
"weight": 135,
"weight": 134,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11910,7 +11860,7 @@
},
"x-appwrite": {
"method": "getQueueDatabases",
"weight": 137,
"weight": 136,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11982,7 +11932,7 @@
},
"x-appwrite": {
"method": "getQueueDeletes",
"weight": 138,
"weight": 137,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12081,8 +12031,9 @@
"v1-audits",
"v1-mails",
"v1-functions",
"v1-usage",
"v1-usage-dump",
"v1-stats-resources",
"v1-stats-usage",
"v1-stats-usage-dump",
"v1-webhooks",
"v1-certificates",
"v1-builds",
@@ -12130,7 +12081,7 @@
},
"x-appwrite": {
"method": "getQueueFunctions",
"weight": 142,
"weight": 141,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12191,7 +12142,7 @@
},
"x-appwrite": {
"method": "getQueueLogs",
"weight": 133,
"weight": 132,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12252,7 +12203,7 @@
},
"x-appwrite": {
"method": "getQueueMails",
"weight": 139,
"weight": 138,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12313,7 +12264,7 @@
},
"x-appwrite": {
"method": "getQueueMessaging",
"weight": 140,
"weight": 139,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12374,7 +12325,7 @@
},
"x-appwrite": {
"method": "getQueueMigrations",
"weight": 141,
"weight": 140,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12413,14 +12364,14 @@
]
}
},
"\/health\/queue\/usage": {
"\/health\/queue\/stats-resources": {
"get": {
"summary": "Get usage queue",
"operationId": "healthGetQueueUsage",
"summary": "Get stats resources queue",
"operationId": "healthGetQueueStatsResources",
"tags": [
"health"
],
"description": "Get the number of metrics that are waiting to be processed in the Appwrite internal queue server.",
"description": "Get the number of metrics that are waiting to be processed in the Appwrite stats resources queue.",
"responses": {
"200": {
"description": "Health Queue",
@@ -12434,13 +12385,13 @@
}
},
"x-appwrite": {
"method": "getQueueUsage",
"weight": 143,
"method": "getQueueStatsResources",
"weight": 142,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "health\/get-queue-usage.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-usage.md",
"demo": "health\/get-queue-stats-resources.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-stats-resources.md",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
@@ -12474,10 +12425,71 @@
]
}
},
"\/health\/queue\/usage-dump": {
"\/health\/queue\/stats-usage": {
"get": {
"summary": "Get stats usage queue",
"operationId": "healthGetQueueUsage",
"tags": [
"health"
],
"description": "Get the number of metrics that are waiting to be processed in the Appwrite internal queue server.",
"responses": {
"200": {
"description": "Health Queue",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/healthQueue"
}
}
}
}
},
"x-appwrite": {
"method": "getQueueUsage",
"weight": 143,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "health\/get-queue-usage.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-stats-usage.md",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "health.read",
"platforms": [
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Key": []
}
],
"parameters": [
{
"name": "threshold",
"description": "Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.",
"required": false,
"schema": {
"type": "integer",
"format": "int32",
"default": 5000
},
"in": "query"
}
]
}
},
"\/health\/queue\/stats-usage-dump": {
"get": {
"summary": "Get usage dump queue",
"operationId": "healthGetQueueUsageDump",
"operationId": "healthGetQueueStatsUsageDump",
"tags": [
"health"
],
@@ -12495,13 +12507,13 @@
}
},
"x-appwrite": {
"method": "getQueueUsageDump",
"method": "getQueueStatsUsageDump",
"weight": 144,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "health\/get-queue-usage-dump.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-usage-dump.md",
"demo": "health\/get-queue-stats-usage-dump.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-stats-usage-dump.md",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
@@ -12557,7 +12569,7 @@
},
"x-appwrite": {
"method": "getQueueWebhooks",
"weight": 132,
"weight": 131,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12714,7 +12726,7 @@
},
"x-appwrite": {
"method": "getTime",
"weight": 131,
"weight": 130,
"cookies": false,
"type": "",
"deprecated": false,
@@ -17609,17 +17621,17 @@
},
"endpoint": {
"type": "string",
"description": "Source's Appwrite Endpoint",
"description": "Source Appwrite endpoint",
"x-example": "https:\/\/example.com"
},
"projectId": {
"type": "string",
"description": "Source's Project ID",
"description": "Source Project ID",
"x-example": "<PROJECT_ID>"
},
"apiKey": {
"type": "string",
"description": "Source's API Key",
"description": "Source API Key",
"x-example": "<API_KEY>"
}
},
@@ -36052,6 +36064,20 @@
"$ref": "#\/components\/schemas\/metric"
},
"x-example": []
},
"imageTransformations": {
"type": "array",
"description": "Aggregated number of files transformations per period.",
"items": {
"$ref": "#\/components\/schemas\/metric"
},
"x-example": []
},
"imageTransformationsTotal": {
"type": "integer",
"description": "Total aggregated number of files transformations.",
"x-example": 0,
"format": "int32"
}
},
"required": [
@@ -36059,7 +36085,9 @@
"filesTotal",
"filesStorageTotal",
"files",
"storage"
"storage",
"imageTransformations",
"imageTransformationsTotal"
]
},
"usageFunctions": {
@@ -36597,6 +36625,20 @@
"$ref": "#\/components\/schemas\/metric"
},
"x-example": []
},
"imageTransformations": {
"type": "array",
"description": "An array of aggregated number of image transformations.",
"items": {
"$ref": "#\/components\/schemas\/metric"
},
"x-example": []
},
"imageTransformationsTotal": {
"type": "integer",
"description": "Total aggregated number of image transformations.",
"x-example": 0,
"format": "int32"
}
},
"required": [
@@ -36628,7 +36670,9 @@
"authPhoneEstimate",
"authPhoneCountryBreakdown",
"databasesReads",
"databasesWrites"
"databasesWrites",
"imageTransformations",
"imageTransformationsTotal"
]
},
"headers": {
+97 -85
View File
@@ -3077,7 +3077,7 @@
"parameters": [
{
"name": "code",
"description": "Credit Card Code. Possible values: amex, argencard, cabal, cencosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.",
"description": "Credit Card Code. Possible values: amex, argencard, cabal, cencosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro, rupay.",
"required": true,
"schema": {
"type": "string",
@@ -3098,7 +3098,8 @@
"union-china-pay",
"visa",
"mir",
"maestro"
"maestro",
"rupay"
],
"x-enum-name": "CreditCard",
"x-enum-keys": [
@@ -3117,7 +3118,8 @@
"Union China Pay",
"Visa",
"MIR",
"Maestro"
"Maestro",
"Rupay"
]
},
"in": "path"
@@ -5951,8 +5953,6 @@
},
"required": [
"required",
"min",
"max",
"default"
]
}
@@ -6190,8 +6190,6 @@
},
"required": [
"required",
"min",
"max",
"default"
]
}
@@ -7381,7 +7379,7 @@
"tags": [
"databases"
],
"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.",
"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.\n",
"responses": {
"201": {
"description": "Document",
@@ -10461,7 +10459,7 @@
},
"x-appwrite": {
"method": "getCertificate",
"weight": 134,
"weight": 133,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10570,7 +10568,7 @@
},
"x-appwrite": {
"method": "getPubSub",
"weight": 130,
"weight": 129,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10597,55 +10595,6 @@
]
}
},
"\/health\/queue": {
"get": {
"summary": "Get queue",
"operationId": "healthGetQueue",
"tags": [
"health"
],
"description": "Check the Appwrite queue messaging servers are up and connection is successful.",
"responses": {
"200": {
"description": "Health Status",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/healthStatus"
}
}
}
}
},
"x-appwrite": {
"method": "getQueue",
"weight": 129,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "health\/get-queue.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue.md",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "health.read",
"platforms": [
"server"
],
"packaging": false,
"auth": {
"Project": [],
"Key": []
}
},
"security": [
{
"Project": [],
"Key": []
}
]
}
},
"\/health\/queue\/builds": {
"get": {
"summary": "Get builds queue",
@@ -10668,7 +10617,7 @@
},
"x-appwrite": {
"method": "getQueueBuilds",
"weight": 136,
"weight": 135,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10730,7 +10679,7 @@
},
"x-appwrite": {
"method": "getQueueCertificates",
"weight": 135,
"weight": 134,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10792,7 +10741,7 @@
},
"x-appwrite": {
"method": "getQueueDatabases",
"weight": 137,
"weight": 136,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10865,7 +10814,7 @@
},
"x-appwrite": {
"method": "getQueueDeletes",
"weight": 138,
"weight": 137,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10966,8 +10915,9 @@
"v1-audits",
"v1-mails",
"v1-functions",
"v1-usage",
"v1-usage-dump",
"v1-stats-resources",
"v1-stats-usage",
"v1-stats-usage-dump",
"v1-webhooks",
"v1-certificates",
"v1-builds",
@@ -11015,7 +10965,7 @@
},
"x-appwrite": {
"method": "getQueueFunctions",
"weight": 142,
"weight": 141,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11077,7 +11027,7 @@
},
"x-appwrite": {
"method": "getQueueLogs",
"weight": 133,
"weight": 132,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11139,7 +11089,7 @@
},
"x-appwrite": {
"method": "getQueueMails",
"weight": 139,
"weight": 138,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11201,7 +11151,7 @@
},
"x-appwrite": {
"method": "getQueueMessaging",
"weight": 140,
"weight": 139,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11263,7 +11213,7 @@
},
"x-appwrite": {
"method": "getQueueMigrations",
"weight": 141,
"weight": 140,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11303,14 +11253,14 @@
]
}
},
"\/health\/queue\/usage": {
"\/health\/queue\/stats-resources": {
"get": {
"summary": "Get usage queue",
"operationId": "healthGetQueueUsage",
"summary": "Get stats resources queue",
"operationId": "healthGetQueueStatsResources",
"tags": [
"health"
],
"description": "Get the number of metrics that are waiting to be processed in the Appwrite internal queue server.",
"description": "Get the number of metrics that are waiting to be processed in the Appwrite stats resources queue.",
"responses": {
"200": {
"description": "Health Queue",
@@ -11324,13 +11274,13 @@
}
},
"x-appwrite": {
"method": "getQueueUsage",
"weight": 143,
"method": "getQueueStatsResources",
"weight": 142,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "health\/get-queue-usage.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-usage.md",
"demo": "health\/get-queue-stats-resources.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-stats-resources.md",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
@@ -11365,10 +11315,72 @@
]
}
},
"\/health\/queue\/usage-dump": {
"\/health\/queue\/stats-usage": {
"get": {
"summary": "Get stats usage queue",
"operationId": "healthGetQueueUsage",
"tags": [
"health"
],
"description": "Get the number of metrics that are waiting to be processed in the Appwrite internal queue server.",
"responses": {
"200": {
"description": "Health Queue",
"content": {
"application\/json": {
"schema": {
"$ref": "#\/components\/schemas\/healthQueue"
}
}
}
}
},
"x-appwrite": {
"method": "getQueueUsage",
"weight": 143,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "health\/get-queue-usage.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-stats-usage.md",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "health.read",
"platforms": [
"server"
],
"packaging": false,
"auth": {
"Project": [],
"Key": []
}
},
"security": [
{
"Project": [],
"Key": []
}
],
"parameters": [
{
"name": "threshold",
"description": "Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.",
"required": false,
"schema": {
"type": "integer",
"format": "int32",
"default": 5000
},
"in": "query"
}
]
}
},
"\/health\/queue\/stats-usage-dump": {
"get": {
"summary": "Get usage dump queue",
"operationId": "healthGetQueueUsageDump",
"operationId": "healthGetQueueStatsUsageDump",
"tags": [
"health"
],
@@ -11386,13 +11398,13 @@
}
},
"x-appwrite": {
"method": "getQueueUsageDump",
"method": "getQueueStatsUsageDump",
"weight": 144,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "health\/get-queue-usage-dump.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-usage-dump.md",
"demo": "health\/get-queue-stats-usage-dump.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-stats-usage-dump.md",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
@@ -11449,7 +11461,7 @@
},
"x-appwrite": {
"method": "getQueueWebhooks",
"weight": 132,
"weight": 131,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11609,7 +11621,7 @@
},
"x-appwrite": {
"method": "getTime",
"weight": 131,
"weight": 130,
"cookies": false,
"type": "",
"deprecated": false,
+107 -116
View File
@@ -43,7 +43,7 @@
},
"x-appwrite": {
"method": "get",
"weight": 9,
"weight": 10,
"cookies": false,
"type": "",
"deprecated": false,
@@ -91,7 +91,7 @@
},
"x-appwrite": {
"method": "create",
"weight": 8,
"weight": 9,
"cookies": false,
"type": "",
"deprecated": false,
@@ -175,7 +175,7 @@
},
"x-appwrite": {
"method": "updateEmail",
"weight": 34,
"weight": 35,
"cookies": false,
"type": "",
"deprecated": false,
@@ -250,7 +250,7 @@
},
"x-appwrite": {
"method": "listIdentities",
"weight": 57,
"weight": 58,
"cookies": false,
"type": "",
"deprecated": false,
@@ -308,7 +308,7 @@
},
"x-appwrite": {
"method": "deleteIdentity",
"weight": 58,
"weight": 59,
"cookies": false,
"type": "",
"deprecated": false,
@@ -370,7 +370,7 @@
},
"x-appwrite": {
"method": "createJWT",
"weight": 29,
"weight": 30,
"cookies": false,
"type": "",
"deprecated": false,
@@ -418,7 +418,7 @@
},
"x-appwrite": {
"method": "listLogs",
"weight": 31,
"weight": 32,
"cookies": false,
"type": "",
"deprecated": false,
@@ -483,7 +483,7 @@
},
"x-appwrite": {
"method": "updateMFA",
"weight": 44,
"weight": 45,
"cookies": false,
"type": "",
"deprecated": false,
@@ -552,7 +552,7 @@
},
"x-appwrite": {
"method": "createMfaAuthenticator",
"weight": 46,
"weight": 47,
"cookies": false,
"type": "",
"deprecated": false,
@@ -617,7 +617,7 @@
},
"x-appwrite": {
"method": "updateMfaAuthenticator",
"weight": 47,
"weight": 48,
"cookies": false,
"type": "",
"deprecated": false,
@@ -694,7 +694,7 @@
},
"x-appwrite": {
"method": "deleteMfaAuthenticator",
"weight": 51,
"weight": 52,
"cookies": false,
"type": "",
"deprecated": false,
@@ -761,7 +761,7 @@
},
"x-appwrite": {
"method": "createMfaChallenge",
"weight": 52,
"weight": 53,
"cookies": false,
"type": "",
"deprecated": false,
@@ -834,7 +834,7 @@
},
"x-appwrite": {
"method": "updateMfaChallenge",
"weight": 53,
"weight": 54,
"cookies": false,
"type": "",
"deprecated": false,
@@ -909,7 +909,7 @@
},
"x-appwrite": {
"method": "listMfaFactors",
"weight": 45,
"weight": 46,
"cookies": false,
"type": "",
"deprecated": false,
@@ -959,7 +959,7 @@
},
"x-appwrite": {
"method": "getMfaRecoveryCodes",
"weight": 50,
"weight": 51,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1007,7 +1007,7 @@
},
"x-appwrite": {
"method": "createMfaRecoveryCodes",
"weight": 48,
"weight": 49,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1055,7 +1055,7 @@
},
"x-appwrite": {
"method": "updateMfaRecoveryCodes",
"weight": 49,
"weight": 50,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1105,7 +1105,7 @@
},
"x-appwrite": {
"method": "updateName",
"weight": 32,
"weight": 33,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1174,7 +1174,7 @@
},
"x-appwrite": {
"method": "updatePassword",
"weight": 33,
"weight": 34,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1248,7 +1248,7 @@
},
"x-appwrite": {
"method": "updatePhone",
"weight": 35,
"weight": 36,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1323,7 +1323,7 @@
},
"x-appwrite": {
"method": "getPrefs",
"weight": 30,
"weight": 31,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1371,7 +1371,7 @@
},
"x-appwrite": {
"method": "updatePrefs",
"weight": 36,
"weight": 37,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1440,7 +1440,7 @@
},
"x-appwrite": {
"method": "createRecovery",
"weight": 38,
"weight": 39,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1516,7 +1516,7 @@
},
"x-appwrite": {
"method": "updateRecovery",
"weight": 39,
"weight": 40,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1597,7 +1597,7 @@
},
"x-appwrite": {
"method": "listSessions",
"weight": 11,
"weight": 12,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1638,7 +1638,7 @@
},
"x-appwrite": {
"method": "deleteSessions",
"weight": 12,
"weight": 13,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1688,7 +1688,7 @@
},
"x-appwrite": {
"method": "createAnonymousSession",
"weight": 17,
"weight": 18,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1736,7 +1736,7 @@
},
"x-appwrite": {
"method": "createEmailPasswordSession",
"weight": 16,
"weight": 17,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1809,7 +1809,7 @@
},
"x-appwrite": {
"method": "updateMagicURLSession",
"weight": 26,
"weight": 27,
"cookies": false,
"type": "",
"deprecated": true,
@@ -1875,7 +1875,7 @@
},
"x-appwrite": {
"method": "createOAuth2Session",
"weight": 19,
"weight": 20,
"cookies": false,
"type": "webAuth",
"deprecated": false,
@@ -2015,7 +2015,7 @@
},
"x-appwrite": {
"method": "updatePhoneSession",
"weight": 27,
"weight": 28,
"cookies": false,
"type": "",
"deprecated": true,
@@ -2088,7 +2088,7 @@
},
"x-appwrite": {
"method": "createSession",
"weight": 18,
"weight": 19,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2161,7 +2161,7 @@
},
"x-appwrite": {
"method": "getSession",
"weight": 13,
"weight": 14,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2221,7 +2221,7 @@
},
"x-appwrite": {
"method": "updateSession",
"weight": 15,
"weight": 16,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2274,7 +2274,7 @@
},
"x-appwrite": {
"method": "deleteSession",
"weight": 14,
"weight": 15,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2336,7 +2336,7 @@
},
"x-appwrite": {
"method": "updateStatus",
"weight": 37,
"weight": 38,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2386,7 +2386,7 @@
},
"x-appwrite": {
"method": "createPushTarget",
"weight": 54,
"weight": 55,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2464,7 +2464,7 @@
},
"x-appwrite": {
"method": "updatePushTarget",
"weight": 55,
"weight": 56,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2534,7 +2534,7 @@
},
"x-appwrite": {
"method": "deletePushTarget",
"weight": 56,
"weight": 57,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2594,7 +2594,7 @@
},
"x-appwrite": {
"method": "createEmailToken",
"weight": 25,
"weight": 26,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2672,7 +2672,7 @@
},
"x-appwrite": {
"method": "createMagicURLToken",
"weight": 24,
"weight": 25,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2751,7 +2751,7 @@
},
"x-appwrite": {
"method": "createOAuth2Token",
"weight": 23,
"weight": 24,
"cookies": false,
"type": "webAuth",
"deprecated": false,
@@ -2891,7 +2891,7 @@
},
"x-appwrite": {
"method": "createPhoneToken",
"weight": 28,
"weight": 29,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2967,7 +2967,7 @@
},
"x-appwrite": {
"method": "createVerification",
"weight": 40,
"weight": 41,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3034,7 +3034,7 @@
},
"x-appwrite": {
"method": "updateVerification",
"weight": 41,
"weight": 42,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3109,7 +3109,7 @@
},
"x-appwrite": {
"method": "createPhoneVerification",
"weight": 42,
"weight": 43,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3160,7 +3160,7 @@
},
"x-appwrite": {
"method": "updatePhoneVerification",
"weight": 43,
"weight": 44,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3228,7 +3228,7 @@
},
"x-appwrite": {
"method": "getBrowser",
"weight": 60,
"weight": 61,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -3353,7 +3353,7 @@
},
"x-appwrite": {
"method": "getCreditCard",
"weight": 59,
"weight": 60,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -3383,7 +3383,7 @@
"parameters": [
{
"name": "code",
"description": "Credit Card Code. Possible values: amex, argencard, cabal, cencosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.",
"description": "Credit Card Code. Possible values: amex, argencard, cabal, cencosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro, rupay.",
"required": true,
"schema": {
"type": "string",
@@ -3404,7 +3404,8 @@
"union-china-pay",
"visa",
"mir",
"maestro"
"maestro",
"rupay"
],
"x-enum-name": "CreditCard",
"x-enum-keys": [
@@ -3423,7 +3424,8 @@
"Union China Pay",
"Visa",
"MIR",
"Maestro"
"Maestro",
"Rupay"
]
},
"in": "path"
@@ -3482,7 +3484,7 @@
},
"x-appwrite": {
"method": "getFavicon",
"weight": 63,
"weight": 64,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -3539,7 +3541,7 @@
},
"x-appwrite": {
"method": "getFlag",
"weight": 61,
"weight": 62,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4026,7 +4028,7 @@
},
"x-appwrite": {
"method": "getImage",
"weight": 62,
"weight": 63,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4107,7 +4109,7 @@
},
"x-appwrite": {
"method": "getInitials",
"weight": 65,
"weight": 66,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4198,7 +4200,7 @@
},
"x-appwrite": {
"method": "getQR",
"weight": 64,
"weight": 65,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4296,7 +4298,7 @@
},
"x-appwrite": {
"method": "listDocuments",
"weight": 109,
"weight": 110,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4365,7 +4367,7 @@
"tags": [
"databases"
],
"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.",
"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.\n",
"responses": {
"201": {
"description": "Document",
@@ -4380,7 +4382,7 @@
},
"x-appwrite": {
"method": "createDocument",
"weight": 108,
"weight": 109,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4486,7 +4488,7 @@
},
"x-appwrite": {
"method": "getDocument",
"weight": 110,
"weight": 111,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4580,7 +4582,7 @@
},
"x-appwrite": {
"method": "updateDocument",
"weight": 112,
"weight": 113,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4678,7 +4680,7 @@
},
"x-appwrite": {
"method": "deleteDocument",
"weight": 113,
"weight": 114,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4746,7 +4748,7 @@
"tags": [
"functions"
],
"description": "Get a list of all the current user function execution logs. You can use the query params to filter your results.",
"description": "",
"responses": {
"200": {
"description": "Executions List",
@@ -4761,12 +4763,12 @@
},
"x-appwrite": {
"method": "listExecutions",
"weight": 300,
"weight": 383,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "functions\/list-executions.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-executions.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a list of all the current user function execution logs. You can use the query params to filter your results.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
@@ -4811,17 +4813,6 @@
"default": []
},
"in": "query"
},
{
"name": "search",
"description": "Search term to filter your list results. Max length: 256 chars.",
"required": false,
"schema": {
"type": "string",
"x-example": "<SEARCH>",
"default": ""
},
"in": "query"
}
]
},
@@ -4831,7 +4822,7 @@
"tags": [
"functions"
],
"description": "Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.",
"description": "",
"responses": {
"201": {
"description": "Execution",
@@ -4846,12 +4837,12 @@
},
"x-appwrite": {
"method": "createExecution",
"weight": 299,
"weight": 381,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "functions\/create-execution.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-execution.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterTrigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
@@ -4945,7 +4936,7 @@
"tags": [
"functions"
],
"description": "Get a function execution log by its unique ID.",
"description": "",
"responses": {
"200": {
"description": "Execution",
@@ -4960,12 +4951,12 @@
},
"x-appwrite": {
"method": "getExecution",
"weight": 301,
"weight": 382,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "functions\/get-execution.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-execution.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a function execution log by its unique ID.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
@@ -5033,7 +5024,7 @@
},
"x-appwrite": {
"method": "query",
"weight": 326,
"weight": 303,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -5084,7 +5075,7 @@
},
"x-appwrite": {
"method": "mutation",
"weight": 325,
"weight": 302,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -5135,7 +5126,7 @@
},
"x-appwrite": {
"method": "get",
"weight": 117,
"weight": 118,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5186,7 +5177,7 @@
},
"x-appwrite": {
"method": "listCodes",
"weight": 118,
"weight": 119,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5237,7 +5228,7 @@
},
"x-appwrite": {
"method": "listContinents",
"weight": 122,
"weight": 123,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5288,7 +5279,7 @@
},
"x-appwrite": {
"method": "listCountries",
"weight": 119,
"weight": 120,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5339,7 +5330,7 @@
},
"x-appwrite": {
"method": "listCountriesEU",
"weight": 120,
"weight": 121,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5390,7 +5381,7 @@
},
"x-appwrite": {
"method": "listCountriesPhones",
"weight": 121,
"weight": 122,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5441,7 +5432,7 @@
},
"x-appwrite": {
"method": "listCurrencies",
"weight": 123,
"weight": 124,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5492,7 +5483,7 @@
},
"x-appwrite": {
"method": "listLanguages",
"weight": 124,
"weight": 125,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5543,7 +5534,7 @@
},
"x-appwrite": {
"method": "createSubscriber",
"weight": 371,
"weight": 348,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5625,7 +5616,7 @@
},
"x-appwrite": {
"method": "deleteSubscriber",
"weight": 375,
"weight": 352,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5699,7 +5690,7 @@
},
"x-appwrite": {
"method": "listFiles",
"weight": 207,
"weight": 209,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5784,7 +5775,7 @@
},
"x-appwrite": {
"method": "createFile",
"weight": 206,
"weight": 208,
"cookies": false,
"type": "upload",
"deprecated": false,
@@ -5881,7 +5872,7 @@
},
"x-appwrite": {
"method": "getFile",
"weight": 208,
"weight": 210,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5952,7 +5943,7 @@
},
"x-appwrite": {
"method": "updateFile",
"weight": 213,
"weight": 215,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6040,7 +6031,7 @@
},
"x-appwrite": {
"method": "deleteFile",
"weight": 214,
"weight": 216,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6106,7 +6097,7 @@
},
"x-appwrite": {
"method": "getFileDownload",
"weight": 210,
"weight": 212,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6172,7 +6163,7 @@
},
"x-appwrite": {
"method": "getFilePreview",
"weight": 209,
"weight": 211,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6388,7 +6379,7 @@
},
"x-appwrite": {
"method": "getFileView",
"weight": 211,
"weight": 213,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6461,7 +6452,7 @@
},
"x-appwrite": {
"method": "list",
"weight": 218,
"weight": 220,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6536,7 +6527,7 @@
},
"x-appwrite": {
"method": "create",
"weight": 217,
"weight": 219,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6620,7 +6611,7 @@
},
"x-appwrite": {
"method": "get",
"weight": 219,
"weight": 221,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6681,7 +6672,7 @@
},
"x-appwrite": {
"method": "updateName",
"weight": 221,
"weight": 223,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6754,7 +6745,7 @@
},
"x-appwrite": {
"method": "delete",
"weight": 223,
"weight": 225,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6817,7 +6808,7 @@
},
"x-appwrite": {
"method": "listMemberships",
"weight": 225,
"weight": 227,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6902,7 +6893,7 @@
},
"x-appwrite": {
"method": "createMembership",
"weight": 224,
"weight": 226,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7012,7 +7003,7 @@
},
"x-appwrite": {
"method": "getMembership",
"weight": 226,
"weight": 228,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7083,7 +7074,7 @@
},
"x-appwrite": {
"method": "updateMembership",
"weight": 227,
"weight": 229,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7169,7 +7160,7 @@
},
"x-appwrite": {
"method": "deleteMembership",
"weight": 229,
"weight": 231,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7242,7 +7233,7 @@
},
"x-appwrite": {
"method": "updateMembershipStatus",
"weight": 228,
"weight": 230,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7339,7 +7330,7 @@
},
"x-appwrite": {
"method": "getPrefs",
"weight": 220,
"weight": 222,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7399,7 +7390,7 @@
},
"x-appwrite": {
"method": "updatePrefs",
"weight": 222,
"weight": 224,
"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
+6 -4
View File
@@ -3557,7 +3557,7 @@
"parameters": [
{
"name": "code",
"description": "Credit Card Code. Possible values: amex, argencard, cabal, cencosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.",
"description": "Credit Card Code. Possible values: amex, argencard, cabal, cencosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro, rupay.",
"required": true,
"type": "string",
"x-example": "amex",
@@ -3577,7 +3577,8 @@
"union-china-pay",
"visa",
"mir",
"maestro"
"maestro",
"rupay"
],
"x-enum-name": "CreditCard",
"x-enum-keys": [
@@ -3596,7 +3597,8 @@
"Union China Pay",
"Visa",
"MIR",
"Maestro"
"Maestro",
"Rupay"
],
"in": "path"
},
@@ -4547,7 +4549,7 @@
"tags": [
"databases"
],
"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.",
"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.\n",
"responses": {
"201": {
"description": "Document",
+135 -91
View File
@@ -3577,7 +3577,7 @@
"parameters": [
{
"name": "code",
"description": "Credit Card Code. Possible values: amex, argencard, cabal, cencosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.",
"description": "Credit Card Code. Possible values: amex, argencard, cabal, cencosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro, rupay.",
"required": true,
"type": "string",
"x-example": "amex",
@@ -3597,7 +3597,8 @@
"union-china-pay",
"visa",
"mir",
"maestro"
"maestro",
"rupay"
],
"x-enum-name": "CreditCard",
"x-enum-keys": [
@@ -3616,7 +3617,8 @@
"Union China Pay",
"Visa",
"MIR",
"Maestro"
"Maestro",
"Rupay"
],
"in": "path"
},
@@ -6607,8 +6609,6 @@
},
"required": [
"required",
"min",
"max",
"default"
]
}
@@ -6845,8 +6845,6 @@
},
"required": [
"required",
"min",
"max",
"default"
]
}
@@ -8012,7 +8010,7 @@
"tags": [
"databases"
],
"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.",
"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.\n",
"responses": {
"201": {
"description": "Document",
@@ -11810,7 +11808,7 @@
},
"x-appwrite": {
"method": "getCertificate",
"weight": 134,
"weight": 133,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11919,7 +11917,7 @@
},
"x-appwrite": {
"method": "getPubSub",
"weight": 130,
"weight": 129,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11945,56 +11943,6 @@
]
}
},
"\/health\/queue": {
"get": {
"summary": "Get queue",
"operationId": "healthGetQueue",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"health"
],
"description": "Check the Appwrite queue messaging servers are up and connection is successful.",
"responses": {
"200": {
"description": "Health Status",
"schema": {
"$ref": "#\/definitions\/healthStatus"
}
}
},
"x-appwrite": {
"method": "getQueue",
"weight": 129,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "health\/get-queue.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue.md",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "health.read",
"platforms": [
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Key": []
}
]
}
},
"\/health\/queue\/builds": {
"get": {
"summary": "Get builds queue",
@@ -12019,7 +11967,7 @@
},
"x-appwrite": {
"method": "getQueueBuilds",
"weight": 136,
"weight": 135,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12080,7 +12028,7 @@
},
"x-appwrite": {
"method": "getQueueCertificates",
"weight": 135,
"weight": 134,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12141,7 +12089,7 @@
},
"x-appwrite": {
"method": "getQueueDatabases",
"weight": 137,
"weight": 136,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12211,7 +12159,7 @@
},
"x-appwrite": {
"method": "getQueueDeletes",
"weight": 138,
"weight": 137,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12309,8 +12257,9 @@
"v1-audits",
"v1-mails",
"v1-functions",
"v1-usage",
"v1-usage-dump",
"v1-stats-resources",
"v1-stats-usage",
"v1-stats-usage-dump",
"v1-webhooks",
"v1-certificates",
"v1-builds",
@@ -12357,7 +12306,7 @@
},
"x-appwrite": {
"method": "getQueueFunctions",
"weight": 142,
"weight": 141,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12418,7 +12367,7 @@
},
"x-appwrite": {
"method": "getQueueLogs",
"weight": 133,
"weight": 132,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12479,7 +12428,7 @@
},
"x-appwrite": {
"method": "getQueueMails",
"weight": 139,
"weight": 138,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12540,7 +12489,7 @@
},
"x-appwrite": {
"method": "getQueueMessaging",
"weight": 140,
"weight": 139,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12601,7 +12550,7 @@
},
"x-appwrite": {
"method": "getQueueMigrations",
"weight": 141,
"weight": 140,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12638,10 +12587,10 @@
]
}
},
"\/health\/queue\/usage": {
"\/health\/queue\/stats-resources": {
"get": {
"summary": "Get usage queue",
"operationId": "healthGetQueueUsage",
"summary": "Get stats resources queue",
"operationId": "healthGetQueueStatsResources",
"consumes": [
"application\/json"
],
@@ -12651,7 +12600,7 @@
"tags": [
"health"
],
"description": "Get the number of metrics that are waiting to be processed in the Appwrite internal queue server.",
"description": "Get the number of metrics that are waiting to be processed in the Appwrite stats resources queue.",
"responses": {
"200": {
"description": "Health Queue",
@@ -12661,13 +12610,13 @@
}
},
"x-appwrite": {
"method": "getQueueUsage",
"weight": 143,
"method": "getQueueStatsResources",
"weight": 142,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "health\/get-queue-usage.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-usage.md",
"demo": "health\/get-queue-stats-resources.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-stats-resources.md",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
@@ -12699,10 +12648,71 @@
]
}
},
"\/health\/queue\/usage-dump": {
"\/health\/queue\/stats-usage": {
"get": {
"summary": "Get stats usage queue",
"operationId": "healthGetQueueUsage",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"health"
],
"description": "Get the number of metrics that are waiting to be processed in the Appwrite internal queue server.",
"responses": {
"200": {
"description": "Health Queue",
"schema": {
"$ref": "#\/definitions\/healthQueue"
}
}
},
"x-appwrite": {
"method": "getQueueUsage",
"weight": 143,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "health\/get-queue-usage.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-stats-usage.md",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "health.read",
"platforms": [
"server"
],
"packaging": false,
"auth": {
"Project": []
}
},
"security": [
{
"Project": [],
"Key": []
}
],
"parameters": [
{
"name": "threshold",
"description": "Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.",
"required": false,
"type": "integer",
"format": "int32",
"default": 5000,
"in": "query"
}
]
}
},
"\/health\/queue\/stats-usage-dump": {
"get": {
"summary": "Get usage dump queue",
"operationId": "healthGetQueueUsageDump",
"operationId": "healthGetQueueStatsUsageDump",
"consumes": [
"application\/json"
],
@@ -12722,13 +12732,13 @@
}
},
"x-appwrite": {
"method": "getQueueUsageDump",
"method": "getQueueStatsUsageDump",
"weight": 144,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "health\/get-queue-usage-dump.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-usage-dump.md",
"demo": "health\/get-queue-stats-usage-dump.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-stats-usage-dump.md",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
@@ -12784,7 +12794,7 @@
},
"x-appwrite": {
"method": "getQueueWebhooks",
"weight": 132,
"weight": 131,
"cookies": false,
"type": "",
"deprecated": false,
@@ -12945,7 +12955,7 @@
},
"x-appwrite": {
"method": "getTime",
"weight": 131,
"weight": 130,
"cookies": false,
"type": "",
"deprecated": false,
@@ -18070,19 +18080,19 @@
},
"endpoint": {
"type": "string",
"description": "Source's Appwrite Endpoint",
"description": "Source Appwrite endpoint",
"default": null,
"x-example": "https:\/\/example.com"
},
"projectId": {
"type": "string",
"description": "Source's Project ID",
"description": "Source Project ID",
"default": null,
"x-example": "<PROJECT_ID>"
},
"apiKey": {
"type": "string",
"description": "Source's API Key",
"description": "Source API Key",
"default": null,
"x-example": "<API_KEY>"
}
@@ -36608,6 +36618,21 @@
"$ref": "#\/definitions\/metric"
},
"x-example": []
},
"imageTransformations": {
"type": "array",
"description": "Aggregated number of files transformations per period.",
"items": {
"type": "object",
"$ref": "#\/definitions\/metric"
},
"x-example": []
},
"imageTransformationsTotal": {
"type": "integer",
"description": "Total aggregated number of files transformations.",
"x-example": 0,
"format": "int32"
}
},
"required": [
@@ -36615,7 +36640,9 @@
"filesTotal",
"filesStorageTotal",
"files",
"storage"
"storage",
"imageTransformations",
"imageTransformationsTotal"
]
},
"usageFunctions": {
@@ -37185,6 +37212,21 @@
"$ref": "#\/definitions\/metric"
},
"x-example": []
},
"imageTransformations": {
"type": "array",
"description": "An array of aggregated number of image transformations.",
"items": {
"type": "object",
"$ref": "#\/definitions\/metric"
},
"x-example": []
},
"imageTransformationsTotal": {
"type": "integer",
"description": "Total aggregated number of image transformations.",
"x-example": 0,
"format": "int32"
}
},
"required": [
@@ -37216,7 +37258,9 @@
"authPhoneEstimate",
"authPhoneCountryBreakdown",
"databasesReads",
"databasesWrites"
"databasesWrites",
"imageTransformations",
"imageTransformationsTotal"
]
},
"headers": {
+97 -87
View File
@@ -3261,7 +3261,7 @@
"parameters": [
{
"name": "code",
"description": "Credit Card Code. Possible values: amex, argencard, cabal, cencosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.",
"description": "Credit Card Code. Possible values: amex, argencard, cabal, cencosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro, rupay.",
"required": true,
"type": "string",
"x-example": "amex",
@@ -3281,7 +3281,8 @@
"union-china-pay",
"visa",
"mir",
"maestro"
"maestro",
"rupay"
],
"x-enum-name": "CreditCard",
"x-enum-keys": [
@@ -3300,7 +3301,8 @@
"Union China Pay",
"Visa",
"MIR",
"Maestro"
"Maestro",
"Rupay"
],
"in": "path"
},
@@ -6133,8 +6135,6 @@
},
"required": [
"required",
"min",
"max",
"default"
]
}
@@ -6373,8 +6373,6 @@
},
"required": [
"required",
"min",
"max",
"default"
]
}
@@ -7552,7 +7550,7 @@
"tags": [
"databases"
],
"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.",
"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.\n",
"responses": {
"201": {
"description": "Document",
@@ -10689,7 +10687,7 @@
},
"x-appwrite": {
"method": "getCertificate",
"weight": 134,
"weight": 133,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10800,7 +10798,7 @@
},
"x-appwrite": {
"method": "getPubSub",
"weight": 130,
"weight": 129,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10827,57 +10825,6 @@
]
}
},
"\/health\/queue": {
"get": {
"summary": "Get queue",
"operationId": "healthGetQueue",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"health"
],
"description": "Check the Appwrite queue messaging servers are up and connection is successful.",
"responses": {
"200": {
"description": "Health Status",
"schema": {
"$ref": "#\/definitions\/healthStatus"
}
}
},
"x-appwrite": {
"method": "getQueue",
"weight": 129,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "health\/get-queue.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue.md",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "health.read",
"platforms": [
"server"
],
"packaging": false,
"auth": {
"Project": [],
"Key": []
}
},
"security": [
{
"Project": [],
"Key": []
}
]
}
},
"\/health\/queue\/builds": {
"get": {
"summary": "Get builds queue",
@@ -10902,7 +10849,7 @@
},
"x-appwrite": {
"method": "getQueueBuilds",
"weight": 136,
"weight": 135,
"cookies": false,
"type": "",
"deprecated": false,
@@ -10964,7 +10911,7 @@
},
"x-appwrite": {
"method": "getQueueCertificates",
"weight": 135,
"weight": 134,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11026,7 +10973,7 @@
},
"x-appwrite": {
"method": "getQueueDatabases",
"weight": 137,
"weight": 136,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11097,7 +11044,7 @@
},
"x-appwrite": {
"method": "getQueueDeletes",
"weight": 138,
"weight": 137,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11197,8 +11144,9 @@
"v1-audits",
"v1-mails",
"v1-functions",
"v1-usage",
"v1-usage-dump",
"v1-stats-resources",
"v1-stats-usage",
"v1-stats-usage-dump",
"v1-webhooks",
"v1-certificates",
"v1-builds",
@@ -11245,7 +11193,7 @@
},
"x-appwrite": {
"method": "getQueueFunctions",
"weight": 142,
"weight": 141,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11307,7 +11255,7 @@
},
"x-appwrite": {
"method": "getQueueLogs",
"weight": 133,
"weight": 132,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11369,7 +11317,7 @@
},
"x-appwrite": {
"method": "getQueueMails",
"weight": 139,
"weight": 138,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11431,7 +11379,7 @@
},
"x-appwrite": {
"method": "getQueueMessaging",
"weight": 140,
"weight": 139,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11493,7 +11441,7 @@
},
"x-appwrite": {
"method": "getQueueMigrations",
"weight": 141,
"weight": 140,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11531,10 +11479,10 @@
]
}
},
"\/health\/queue\/usage": {
"\/health\/queue\/stats-resources": {
"get": {
"summary": "Get usage queue",
"operationId": "healthGetQueueUsage",
"summary": "Get stats resources queue",
"operationId": "healthGetQueueStatsResources",
"consumes": [
"application\/json"
],
@@ -11544,7 +11492,7 @@
"tags": [
"health"
],
"description": "Get the number of metrics that are waiting to be processed in the Appwrite internal queue server.",
"description": "Get the number of metrics that are waiting to be processed in the Appwrite stats resources queue.",
"responses": {
"200": {
"description": "Health Queue",
@@ -11554,13 +11502,13 @@
}
},
"x-appwrite": {
"method": "getQueueUsage",
"weight": 143,
"method": "getQueueStatsResources",
"weight": 142,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "health\/get-queue-usage.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-usage.md",
"demo": "health\/get-queue-stats-resources.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-stats-resources.md",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
@@ -11593,10 +11541,72 @@
]
}
},
"\/health\/queue\/usage-dump": {
"\/health\/queue\/stats-usage": {
"get": {
"summary": "Get stats usage queue",
"operationId": "healthGetQueueUsage",
"consumes": [
"application\/json"
],
"produces": [
"application\/json"
],
"tags": [
"health"
],
"description": "Get the number of metrics that are waiting to be processed in the Appwrite internal queue server.",
"responses": {
"200": {
"description": "Health Queue",
"schema": {
"$ref": "#\/definitions\/healthQueue"
}
}
},
"x-appwrite": {
"method": "getQueueUsage",
"weight": 143,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "health\/get-queue-usage.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-stats-usage.md",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
"scope": "health.read",
"platforms": [
"server"
],
"packaging": false,
"auth": {
"Project": [],
"Key": []
}
},
"security": [
{
"Project": [],
"Key": []
}
],
"parameters": [
{
"name": "threshold",
"description": "Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.",
"required": false,
"type": "integer",
"format": "int32",
"default": 5000,
"in": "query"
}
]
}
},
"\/health\/queue\/stats-usage-dump": {
"get": {
"summary": "Get usage dump queue",
"operationId": "healthGetQueueUsageDump",
"operationId": "healthGetQueueStatsUsageDump",
"consumes": [
"application\/json"
],
@@ -11616,13 +11626,13 @@
}
},
"x-appwrite": {
"method": "getQueueUsageDump",
"method": "getQueueStatsUsageDump",
"weight": 144,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "health\/get-queue-usage-dump.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-usage-dump.md",
"demo": "health\/get-queue-stats-usage-dump.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/health\/get-queue-stats-usage-dump.md",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
@@ -11679,7 +11689,7 @@
},
"x-appwrite": {
"method": "getQueueWebhooks",
"weight": 132,
"weight": 131,
"cookies": false,
"type": "",
"deprecated": false,
@@ -11843,7 +11853,7 @@
},
"x-appwrite": {
"method": "getTime",
"weight": 131,
"weight": 130,
"cookies": false,
"type": "",
"deprecated": false,
+107 -114
View File
@@ -87,7 +87,7 @@
},
"x-appwrite": {
"method": "get",
"weight": 9,
"weight": 10,
"cookies": false,
"type": "",
"deprecated": false,
@@ -137,7 +137,7 @@
},
"x-appwrite": {
"method": "create",
"weight": 8,
"weight": 9,
"cookies": false,
"type": "",
"deprecated": false,
@@ -227,7 +227,7 @@
},
"x-appwrite": {
"method": "updateEmail",
"weight": 34,
"weight": 35,
"cookies": false,
"type": "",
"deprecated": false,
@@ -306,7 +306,7 @@
},
"x-appwrite": {
"method": "listIdentities",
"weight": 57,
"weight": 58,
"cookies": false,
"type": "",
"deprecated": false,
@@ -367,7 +367,7 @@
},
"x-appwrite": {
"method": "deleteIdentity",
"weight": 58,
"weight": 59,
"cookies": false,
"type": "",
"deprecated": false,
@@ -429,7 +429,7 @@
},
"x-appwrite": {
"method": "createJWT",
"weight": 29,
"weight": 30,
"cookies": false,
"type": "",
"deprecated": false,
@@ -479,7 +479,7 @@
},
"x-appwrite": {
"method": "listLogs",
"weight": 31,
"weight": 32,
"cookies": false,
"type": "",
"deprecated": false,
@@ -545,7 +545,7 @@
},
"x-appwrite": {
"method": "updateMFA",
"weight": 44,
"weight": 45,
"cookies": false,
"type": "",
"deprecated": false,
@@ -617,7 +617,7 @@
},
"x-appwrite": {
"method": "createMfaAuthenticator",
"weight": 46,
"weight": 47,
"cookies": false,
"type": "",
"deprecated": false,
@@ -682,7 +682,7 @@
},
"x-appwrite": {
"method": "updateMfaAuthenticator",
"weight": 47,
"weight": 48,
"cookies": false,
"type": "",
"deprecated": false,
@@ -760,7 +760,7 @@
},
"x-appwrite": {
"method": "deleteMfaAuthenticator",
"weight": 51,
"weight": 52,
"cookies": false,
"type": "",
"deprecated": false,
@@ -827,7 +827,7 @@
},
"x-appwrite": {
"method": "createMfaChallenge",
"weight": 52,
"weight": 53,
"cookies": false,
"type": "",
"deprecated": false,
@@ -903,7 +903,7 @@
},
"x-appwrite": {
"method": "updateMfaChallenge",
"weight": 53,
"weight": 54,
"cookies": false,
"type": "",
"deprecated": false,
@@ -982,7 +982,7 @@
},
"x-appwrite": {
"method": "listMfaFactors",
"weight": 45,
"weight": 46,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1034,7 +1034,7 @@
},
"x-appwrite": {
"method": "getMfaRecoveryCodes",
"weight": 50,
"weight": 51,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1084,7 +1084,7 @@
},
"x-appwrite": {
"method": "createMfaRecoveryCodes",
"weight": 48,
"weight": 49,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1134,7 +1134,7 @@
},
"x-appwrite": {
"method": "updateMfaRecoveryCodes",
"weight": 49,
"weight": 50,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1186,7 +1186,7 @@
},
"x-appwrite": {
"method": "updateName",
"weight": 32,
"weight": 33,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1258,7 +1258,7 @@
},
"x-appwrite": {
"method": "updatePassword",
"weight": 33,
"weight": 34,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1336,7 +1336,7 @@
},
"x-appwrite": {
"method": "updatePhone",
"weight": 35,
"weight": 36,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1415,7 +1415,7 @@
},
"x-appwrite": {
"method": "getPrefs",
"weight": 30,
"weight": 31,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1465,7 +1465,7 @@
},
"x-appwrite": {
"method": "updatePrefs",
"weight": 36,
"weight": 37,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1537,7 +1537,7 @@
},
"x-appwrite": {
"method": "createRecovery",
"weight": 38,
"weight": 39,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1617,7 +1617,7 @@
},
"x-appwrite": {
"method": "updateRecovery",
"weight": 39,
"weight": 40,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1703,7 +1703,7 @@
},
"x-appwrite": {
"method": "listSessions",
"weight": 11,
"weight": 12,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1748,7 +1748,7 @@
},
"x-appwrite": {
"method": "deleteSessions",
"weight": 12,
"weight": 13,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1800,7 +1800,7 @@
},
"x-appwrite": {
"method": "createAnonymousSession",
"weight": 17,
"weight": 18,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1850,7 +1850,7 @@
},
"x-appwrite": {
"method": "createEmailPasswordSession",
"weight": 16,
"weight": 17,
"cookies": false,
"type": "",
"deprecated": false,
@@ -1927,7 +1927,7 @@
},
"x-appwrite": {
"method": "updateMagicURLSession",
"weight": 26,
"weight": 27,
"cookies": false,
"type": "",
"deprecated": true,
@@ -2001,7 +2001,7 @@
},
"x-appwrite": {
"method": "createOAuth2Session",
"weight": 19,
"weight": 20,
"cookies": false,
"type": "webAuth",
"deprecated": false,
@@ -2136,7 +2136,7 @@
},
"x-appwrite": {
"method": "updatePhoneSession",
"weight": 27,
"weight": 28,
"cookies": false,
"type": "",
"deprecated": true,
@@ -2213,7 +2213,7 @@
},
"x-appwrite": {
"method": "createSession",
"weight": 18,
"weight": 19,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2290,7 +2290,7 @@
},
"x-appwrite": {
"method": "getSession",
"weight": 13,
"weight": 14,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2350,7 +2350,7 @@
},
"x-appwrite": {
"method": "updateSession",
"weight": 15,
"weight": 16,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2405,7 +2405,7 @@
},
"x-appwrite": {
"method": "deleteSession",
"weight": 14,
"weight": 15,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2467,7 +2467,7 @@
},
"x-appwrite": {
"method": "updateStatus",
"weight": 37,
"weight": 38,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2519,7 +2519,7 @@
},
"x-appwrite": {
"method": "createPushTarget",
"weight": 54,
"weight": 55,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2602,7 +2602,7 @@
},
"x-appwrite": {
"method": "updatePushTarget",
"weight": 55,
"weight": 56,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2673,7 +2673,7 @@
},
"x-appwrite": {
"method": "deletePushTarget",
"weight": 56,
"weight": 57,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2733,7 +2733,7 @@
},
"x-appwrite": {
"method": "createEmailToken",
"weight": 25,
"weight": 26,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2816,7 +2816,7 @@
},
"x-appwrite": {
"method": "createMagicURLToken",
"weight": 24,
"weight": 25,
"cookies": false,
"type": "",
"deprecated": false,
@@ -2905,7 +2905,7 @@
},
"x-appwrite": {
"method": "createOAuth2Token",
"weight": 23,
"weight": 24,
"cookies": false,
"type": "webAuth",
"deprecated": false,
@@ -3040,7 +3040,7 @@
},
"x-appwrite": {
"method": "createPhoneToken",
"weight": 28,
"weight": 29,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3120,7 +3120,7 @@
},
"x-appwrite": {
"method": "createVerification",
"weight": 40,
"weight": 41,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3190,7 +3190,7 @@
},
"x-appwrite": {
"method": "updateVerification",
"weight": 41,
"weight": 42,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3269,7 +3269,7 @@
},
"x-appwrite": {
"method": "createPhoneVerification",
"weight": 42,
"weight": 43,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3322,7 +3322,7 @@
},
"x-appwrite": {
"method": "updatePhoneVerification",
"weight": 43,
"weight": 44,
"cookies": false,
"type": "",
"deprecated": false,
@@ -3401,7 +3401,7 @@
},
"x-appwrite": {
"method": "getBrowser",
"weight": 60,
"weight": 61,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -3527,7 +3527,7 @@
},
"x-appwrite": {
"method": "getCreditCard",
"weight": 59,
"weight": 60,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -3557,7 +3557,7 @@
"parameters": [
{
"name": "code",
"description": "Credit Card Code. Possible values: amex, argencard, cabal, cencosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro.",
"description": "Credit Card Code. Possible values: amex, argencard, cabal, cencosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, union-china-pay, visa, mir, maestro, rupay.",
"required": true,
"type": "string",
"x-example": "amex",
@@ -3577,7 +3577,8 @@
"union-china-pay",
"visa",
"mir",
"maestro"
"maestro",
"rupay"
],
"x-enum-name": "CreditCard",
"x-enum-keys": [
@@ -3596,7 +3597,8 @@
"Union China Pay",
"Visa",
"MIR",
"Maestro"
"Maestro",
"Rupay"
],
"in": "path"
},
@@ -3657,7 +3659,7 @@
},
"x-appwrite": {
"method": "getFavicon",
"weight": 63,
"weight": 64,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -3721,7 +3723,7 @@
},
"x-appwrite": {
"method": "getFlag",
"weight": 61,
"weight": 62,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4209,7 +4211,7 @@
},
"x-appwrite": {
"method": "getImage",
"weight": 62,
"weight": 63,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4293,7 +4295,7 @@
},
"x-appwrite": {
"method": "getInitials",
"weight": 65,
"weight": 66,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4385,7 +4387,7 @@
},
"x-appwrite": {
"method": "getQR",
"weight": 64,
"weight": 65,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -4477,7 +4479,7 @@
},
"x-appwrite": {
"method": "listDocuments",
"weight": 109,
"weight": 110,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4547,7 +4549,7 @@
"tags": [
"databases"
],
"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.",
"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.\n",
"responses": {
"201": {
"description": "Document",
@@ -4558,7 +4560,7 @@
},
"x-appwrite": {
"method": "createDocument",
"weight": 108,
"weight": 109,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4663,7 +4665,7 @@
},
"x-appwrite": {
"method": "getDocument",
"weight": 110,
"weight": 111,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4752,7 +4754,7 @@
},
"x-appwrite": {
"method": "updateDocument",
"weight": 112,
"weight": 113,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4848,7 +4850,7 @@
},
"x-appwrite": {
"method": "deleteDocument",
"weight": 113,
"weight": 114,
"cookies": false,
"type": "",
"deprecated": false,
@@ -4916,7 +4918,7 @@
"tags": [
"functions"
],
"description": "Get a list of all the current user function execution logs. You can use the query params to filter your results.",
"description": "",
"responses": {
"200": {
"description": "Executions List",
@@ -4927,12 +4929,12 @@
},
"x-appwrite": {
"method": "listExecutions",
"weight": 300,
"weight": 383,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "functions\/list-executions.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-executions.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a list of all the current user function execution logs. You can use the query params to filter your results.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
@@ -4974,15 +4976,6 @@
},
"default": [],
"in": "query"
},
{
"name": "search",
"description": "Search term to filter your list results. Max length: 256 chars.",
"required": false,
"type": "string",
"x-example": "<SEARCH>",
"default": "",
"in": "query"
}
]
},
@@ -4998,7 +4991,7 @@
"tags": [
"functions"
],
"description": "Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.",
"description": "",
"responses": {
"201": {
"description": "Execution",
@@ -5009,12 +5002,12 @@
},
"x-appwrite": {
"method": "createExecution",
"weight": 299,
"weight": 381,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "functions\/create-execution.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-execution.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterTrigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
@@ -5116,7 +5109,7 @@
"tags": [
"functions"
],
"description": "Get a function execution log by its unique ID.",
"description": "",
"responses": {
"200": {
"description": "Execution",
@@ -5127,12 +5120,12 @@
},
"x-appwrite": {
"method": "getExecution",
"weight": 301,
"weight": 382,
"cookies": false,
"type": "",
"deprecated": false,
"demo": "functions\/get-execution.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-execution.md",
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a function execution log by its unique ID.",
"rate-limit": 0,
"rate-time": 3600,
"rate-key": "url:{url},ip:{ip}",
@@ -5198,7 +5191,7 @@
},
"x-appwrite": {
"method": "query",
"weight": 326,
"weight": 303,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -5271,7 +5264,7 @@
},
"x-appwrite": {
"method": "mutation",
"weight": 325,
"weight": 302,
"cookies": false,
"type": "graphql",
"deprecated": false,
@@ -5344,7 +5337,7 @@
},
"x-appwrite": {
"method": "get",
"weight": 117,
"weight": 118,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5397,7 +5390,7 @@
},
"x-appwrite": {
"method": "listCodes",
"weight": 118,
"weight": 119,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5450,7 +5443,7 @@
},
"x-appwrite": {
"method": "listContinents",
"weight": 122,
"weight": 123,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5503,7 +5496,7 @@
},
"x-appwrite": {
"method": "listCountries",
"weight": 119,
"weight": 120,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5556,7 +5549,7 @@
},
"x-appwrite": {
"method": "listCountriesEU",
"weight": 120,
"weight": 121,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5609,7 +5602,7 @@
},
"x-appwrite": {
"method": "listCountriesPhones",
"weight": 121,
"weight": 122,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5662,7 +5655,7 @@
},
"x-appwrite": {
"method": "listCurrencies",
"weight": 123,
"weight": 124,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5715,7 +5708,7 @@
},
"x-appwrite": {
"method": "listLanguages",
"weight": 124,
"weight": 125,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5768,7 +5761,7 @@
},
"x-appwrite": {
"method": "createSubscriber",
"weight": 371,
"weight": 348,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5852,7 +5845,7 @@
},
"x-appwrite": {
"method": "deleteSubscriber",
"weight": 375,
"weight": 352,
"cookies": false,
"type": "",
"deprecated": false,
@@ -5924,7 +5917,7 @@
},
"x-appwrite": {
"method": "listFiles",
"weight": 207,
"weight": 209,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6006,7 +5999,7 @@
},
"x-appwrite": {
"method": "createFile",
"weight": 206,
"weight": 208,
"cookies": false,
"type": "upload",
"deprecated": false,
@@ -6097,7 +6090,7 @@
},
"x-appwrite": {
"method": "getFile",
"weight": 208,
"weight": 210,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6166,7 +6159,7 @@
},
"x-appwrite": {
"method": "updateFile",
"weight": 213,
"weight": 215,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6254,7 +6247,7 @@
},
"x-appwrite": {
"method": "deleteFile",
"weight": 214,
"weight": 216,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6325,7 +6318,7 @@
},
"x-appwrite": {
"method": "getFileDownload",
"weight": 210,
"weight": 212,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6396,7 +6389,7 @@
},
"x-appwrite": {
"method": "getFilePreview",
"weight": 209,
"weight": 211,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6595,7 +6588,7 @@
},
"x-appwrite": {
"method": "getFileView",
"weight": 211,
"weight": 213,
"cookies": false,
"type": "location",
"deprecated": false,
@@ -6666,7 +6659,7 @@
},
"x-appwrite": {
"method": "list",
"weight": 218,
"weight": 220,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6740,7 +6733,7 @@
},
"x-appwrite": {
"method": "create",
"weight": 217,
"weight": 219,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6831,7 +6824,7 @@
},
"x-appwrite": {
"method": "get",
"weight": 219,
"weight": 221,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6892,7 +6885,7 @@
},
"x-appwrite": {
"method": "updateName",
"weight": 221,
"weight": 223,
"cookies": false,
"type": "",
"deprecated": false,
@@ -6966,7 +6959,7 @@
},
"x-appwrite": {
"method": "delete",
"weight": 223,
"weight": 225,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7029,7 +7022,7 @@
},
"x-appwrite": {
"method": "listMemberships",
"weight": 225,
"weight": 227,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7111,7 +7104,7 @@
},
"x-appwrite": {
"method": "createMembership",
"weight": 224,
"weight": 226,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7225,7 +7218,7 @@
},
"x-appwrite": {
"method": "getMembership",
"weight": 226,
"weight": 228,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7294,7 +7287,7 @@
},
"x-appwrite": {
"method": "updateMembership",
"weight": 227,
"weight": 229,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7379,7 +7372,7 @@
},
"x-appwrite": {
"method": "deleteMembership",
"weight": 229,
"weight": 231,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7450,7 +7443,7 @@
},
"x-appwrite": {
"method": "updateMembershipStatus",
"weight": 228,
"weight": 230,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7545,7 +7538,7 @@
},
"x-appwrite": {
"method": "getPrefs",
"weight": 220,
"weight": 222,
"cookies": false,
"type": "",
"deprecated": false,
@@ -7605,7 +7598,7 @@
},
"x-appwrite": {
"method": "updatePrefs",
"weight": 222,
"weight": 224,
"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
+753
View File
@@ -0,0 +1,753 @@
<?php
use Utopia\System\System;
/**
* List of Appwrite Sites templates
*/
$protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') == 'disabled' ? 'http' : 'https';
$hostname = System::getEnv('_APP_DOMAIN');
// TODO: Development override
if (System::getEnv('_APP_ENV') === 'development') {
$hostname = 'localhost';
}
$url = $protocol . '://' . $hostname;
const TEMPLATE_FRAMEWORKS = [
'SVELTEKIT' => [
'key' => 'sveltekit',
'name' => 'SvelteKit',
'installCommand' => 'npm install',
'buildCommand' => 'npm run build',
'outputDirectory' => './build',
'buildRuntime' => 'node-22',
'adapter' => 'ssr',
'fallbackFile' => '',
],
'NEXTJS' => [
'key' => 'nextjs',
'name' => 'Next.js',
'installCommand' => 'npm install',
'buildCommand' => 'npm run build',
'outputDirectory' => './.next',
'buildRuntime' => 'node-22',
'adapter' => 'ssr',
'fallbackFile' => '',
],
'NUXT' => [
'key' => 'nuxt',
'name' => 'Nuxt',
'installCommand' => 'npm install',
'buildCommand' => 'npm run build',
'outputDirectory' => './.output',
'buildRuntime' => 'node-22',
'adapter' => 'ssr',
'fallbackFile' => '',
],
'REMIX' => [
'key' => 'remix',
'name' => 'Remix',
'installCommand' => 'npm install',
'buildCommand' => 'npm run build',
'outputDirectory' => './build',
'buildRuntime' => 'node-22',
'adapter' => 'ssr',
'fallbackFile' => '',
],
'ASTRO' => [
'key' => 'astro',
'name' => 'Astro',
'installCommand' => 'npm install',
'buildCommand' => 'npm run build',
'outputDirectory' => './dist',
'buildRuntime' => 'node-22',
'adapter' => 'ssr',
'fallbackFile' => '',
],
'FLUTTER' => [
'key' => 'flutter',
'name' => 'Flutter',
'installCommand' => '',
'buildCommand' => 'flutter build web',
'outputDirectory' => './build/web',
'buildRuntime' => 'flutter-3.29',
'adapter' => 'static',
'fallbackFile' => '',
],
'OTHER' => [
'key' => 'other',
'name' => 'Other',
'installCommand' => 'npm install',
'buildCommand' => 'npm run build',
'buildRuntime' => 'node-22',
'adapter' => 'static',
'fallbackFile' => 'index.html',
],
'VITE' => [
'key' => 'vite',
'name' => 'Vite',
'installCommand' => 'npm install',
'buildCommand' => 'npm run build',
'buildRuntime' => 'node-22',
'adapter' => 'static',
'outputDirectory' => './dist',
],
'REACT' => [
'key' => 'react',
'name' => 'React',
'installCommand' => 'npm install',
'buildCommand' => 'npm run build',
'buildRuntime' => 'node-22',
'adapter' => 'static',
'outputDirectory' => './dist',
'fallbackFile' => 'index.html',
],
'ANGULAR' => [
'key' => 'angular',
'name' => 'Angular',
'installCommand' => 'npm install',
'buildCommand' => 'npm run build',
'buildRuntime' => 'node-22',
'adapter' => 'static',
'outputDirectory' => './dist/angular/browser',
'fallbackFile' => 'index.html',
],
'VUE' => [
'key' => 'vue',
'name' => 'Vue.js',
'installCommand' => 'npm install',
'buildCommand' => 'npm run build',
'buildRuntime' => 'node-22',
'adapter' => 'static',
'outputDirectory' => './dist',
'fallbackFile' => 'index.html',
],
];
function getFramework(string $frameworkEnum, array $overrides)
{
$settings = \array_merge(TEMPLATE_FRAMEWORKS[$frameworkEnum], $overrides);
return $settings;
}
return [
[
'key' => 'template-for-onelink',
'name' => 'Onelink template',
'useCases' => ['starter'],
'screenshotDark' => $url . '/images/sites/templates/template-for-onelink-dark.png',
'screenshotLight' => $url . '/images/sites/templates/template-for-onelink-light.png',
'frameworks' => [
getFramework('NUXT', [
'providerRootDirectory' => './onelink',
'buildCommand' => 'npm run generate',
'outputDirectory' => './dist',
'adapter' => 'static',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'Meldiron',
'providerVersion' => '0.1.*',
'variables' => []
],
[
'key' => 'starter-for-flutter',
'name' => 'Flutter starter',
'useCases' => ['starter'],
'screenshotDark' => $url . '/images/sites/templates/starter-for-flutter-dark.png',
'screenshotLight' => $url . '/images/sites/templates/starter-for-flutter-light.png',
'frameworks' => [
getFramework('FLUTTER', [
'providerRootDirectory' => './',
'buildCommand' => 'sh build.sh',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'starter-for-flutter',
'providerOwner' => 'appwrite',
'providerVersion' => '0.1.*',
'variables' => [
[
'name' => 'APPWRITE_PUBLIC_ENDPOINT',
'description' => 'Endpoint of Appwrite server',
'value' => '{apiEndpoint}',
'placeholder' => '{apiEndpoint}',
'required' => true,
'type' => 'text'
],
[
'name' => 'APPWRITE_PROJECT_ID',
'description' => 'Your Appwrite project ID',
'value' => '{projectId}',
'placeholder' => '{projectId}',
'required' => true,
'type' => 'text'
],
[
'name' => 'APPWRITE_PROJECT_NAME',
'description' => 'Your Appwrite project name',
'value' => '{projectName}',
'placeholder' => '{projectName}',
'required' => true,
'type' => 'text'
],
]
],
[
'key' => 'starter-for-js',
'name' => 'JavaScript starter',
'useCases' => ['starter'],
'screenshotDark' => $url . '/images/sites/templates/starter-for-js-dark.png',
'screenshotLight' => $url . '/images/sites/templates/starter-for-js-light.png',
'frameworks' => [
getFramework('VITE', [
'providerRootDirectory' => './',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'starter-for-js',
'providerOwner' => 'appwrite',
'providerVersion' => '0.1.*',
'variables' => [
[
'name' => 'VITE_APPWRITE_ENDPOINT',
'description' => 'Endpoint of Appwrite server',
'value' => '{apiEndpoint}',
'placeholder' => '{apiEndpoint}',
'required' => true,
'type' => 'text'
],
[
'name' => 'VITE_APPWRITE_PROJECT_ID',
'description' => 'Your Appwrite project ID',
'value' => '{projectId}',
'placeholder' => '{projectId}',
'required' => true,
'type' => 'text'
],
[
'name' => 'VITE_APPWRITE_PROJECT_NAME',
'description' => 'Your Appwrite project name',
'value' => '{projectName}',
'placeholder' => '{projectName}',
'required' => true,
'type' => 'text'
],
]
],
[
'key' => 'starter-for-angular',
'name' => 'Angular starter',
'useCases' => ['starter'],
'screenshotDark' => $url . '/images/sites/templates/starter-for-angular-dark.png',
'screenshotLight' => $url . '/images/sites/templates/starter-for-angular-light.png',
'frameworks' => [
getFramework('ANGULAR', [
'providerRootDirectory' => './',
'outputDirectory' => './dist/angular-starter-kit-for-appwrite/browser',
'buildCommand' => 'sh prepare-env.sh && npm run build'
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'starter-for-angular',
'providerOwner' => 'appwrite',
'providerVersion' => '0.1.*',
'variables' => [
[
'name' => 'APPWRITE_ENDPOINT',
'description' => 'Endpoint of Appwrite server',
'value' => '{apiEndpoint}',
'placeholder' => '{apiEndpoint}',
'required' => true,
'type' => 'text'
],
[
'name' => 'APPWRITE_PROJECT_ID',
'description' => 'Your Appwrite project ID',
'value' => '{projectId}',
'placeholder' => '{projectId}',
'required' => true,
'type' => 'text'
],
[
'name' => 'APPWRITE_PROJECT_NAME',
'description' => 'Your Appwrite project name',
'value' => '{projectName}',
'placeholder' => '{projectName}',
'required' => true,
'type' => 'text'
],
]
],
[
'key' => 'starter-for-svelte',
'name' => 'Svelte starter',
'useCases' => ['starter'],
'screenshotDark' => $url . '/images/sites/templates/starter-for-svelte-dark.png',
'screenshotLight' => $url . '/images/sites/templates/starter-for-svelte-light.png',
'frameworks' => [
getFramework('SVELTEKIT', [
'providerRootDirectory' => './',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'starter-for-svelte',
'providerOwner' => 'appwrite',
'providerVersion' => '0.1.*',
'variables' => [
[
'name' => 'PUBLIC_APPWRITE_ENDPOINT',
'description' => 'Endpoint of Appwrite server',
'value' => '{apiEndpoint}',
'placeholder' => '{apiEndpoint}',
'required' => true,
'type' => 'text'
],
[
'name' => 'PUBLIC_APPWRITE_PROJECT_ID',
'description' => 'Your Appwrite project ID',
'value' => '{projectId}',
'placeholder' => '{projectId}',
'required' => true,
'type' => 'text'
],
[
'name' => 'PUBLIC_APPWRITE_PROJECT_NAME',
'description' => 'Your Appwrite project name',
'value' => '{projectName}',
'placeholder' => '{projectName}',
'required' => true,
'type' => 'text'
],
]
],
[
'key' => 'starter-for-react',
'name' => 'React starter',
'useCases' => ['starter'],
'screenshotDark' => $url . '/images/sites/templates/starter-for-react-dark.png',
'screenshotLight' => $url . '/images/sites/templates/starter-for-react-light.png',
'frameworks' => [
getFramework('REACT', [
'providerRootDirectory' => './',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'starter-for-react',
'providerOwner' => 'appwrite',
'providerVersion' => '0.1.*',
'variables' => [
[
'name' => 'VITE_APPWRITE_ENDPOINT',
'description' => 'Endpoint of Appwrite server',
'value' => '{apiEndpoint}',
'placeholder' => '{apiEndpoint}',
'required' => true,
'type' => 'text'
],
[
'name' => 'VITE_APPWRITE_PROJECT_ID',
'description' => 'Your Appwrite project ID',
'value' => '{projectId}',
'placeholder' => '{projectId}',
'required' => true,
'type' => 'text'
],
[
'name' => 'VITE_APPWRITE_PROJECT_NAME',
'description' => 'Your Appwrite project name',
'value' => '{projectName}',
'placeholder' => '{projectName}',
'required' => true,
'type' => 'text'
],
]
],
[
'key' => 'starter-for-vue',
'name' => 'Vue starter',
'useCases' => ['starter'],
'screenshotDark' => $url . '/images/sites/templates/starter-for-vue-dark.png',
'screenshotLight' => $url . '/images/sites/templates/starter-for-vue-light.png',
'frameworks' => [
getFramework('VUE', [
'providerRootDirectory' => './',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'starter-for-vue',
'providerOwner' => 'appwrite',
'providerVersion' => '0.1.*',
'variables' => [
[
'name' => 'VITE_APPWRITE_ENDPOINT',
'description' => 'Endpoint of Appwrite server',
'value' => '{apiEndpoint}',
'placeholder' => '{apiEndpoint}',
'required' => true,
'type' => 'text'
],
[
'name' => 'VITE_APPWRITE_PROJECT_ID',
'description' => 'Your Appwrite project ID',
'value' => '{projectId}',
'placeholder' => '{projectId}',
'required' => true,
'type' => 'text'
],
[
'name' => 'VITE_APPWRITE_PROJECT_NAME',
'description' => 'Your Appwrite project name',
'value' => '{projectName}',
'placeholder' => '{projectName}',
'required' => true,
'type' => 'text'
],
]
],
[
'key' => 'starter-for-react-native',
'name' => 'React Native starter',
'useCases' => ['starter'],
'screenshotDark' => $url . '/images/sites/templates/starter-for-react-native-dark.png',
'screenshotLight' => $url . '/images/sites/templates/starter-for-react-native-light.png',
'frameworks' => [
getFramework('REACT', [
'providerRootDirectory' => './',
'fallbackFile' => '+not-found.html',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'starter-for-react-native',
'providerOwner' => 'appwrite',
'providerVersion' => '0.1.*',
'variables' => [
[
'name' => 'EXPO_PUBLIC_APPWRITE_ENDPOINT',
'description' => 'Endpoint of Appwrite server',
'value' => '{apiEndpoint}',
'placeholder' => '{apiEndpoint}',
'required' => true,
'type' => 'text'
],
[
'name' => 'EXPO_PUBLIC_APPWRITE_PROJECT_ID',
'description' => 'Your Appwrite project ID',
'value' => '{projectId}',
'placeholder' => '{projectId}',
'required' => true,
'type' => 'text'
],
[
'name' => 'EXPO_PUBLIC_APPWRITE_PROJECT_NAME',
'description' => 'Your Appwrite project name',
'value' => '{projectName}',
'placeholder' => '{projectName}',
'required' => true,
'type' => 'text'
],
]
],
[
'key' => 'starter-for-nextjs',
'name' => 'Next.js starter',
'useCases' => ['starter'],
'screenshotDark' => $url . '/images/sites/templates/starter-for-nextjs-dark.png',
'screenshotLight' => $url . '/images/sites/templates/starter-for-nextjs-light.png',
'frameworks' => [
getFramework('NEXTJS', [
'providerRootDirectory' => './',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'starter-for-nextjs',
'providerOwner' => 'appwrite',
'providerVersion' => '0.1.*',
'variables' => [
[
'name' => 'NEXT_PUBLIC_APPWRITE_ENDPOINT',
'description' => 'Endpoint of Appwrite server',
'value' => '{apiEndpoint}',
'placeholder' => '{apiEndpoint}',
'required' => true,
'type' => 'text'
],
[
'name' => 'NEXT_PUBLIC_APPWRITE_PROJECT_ID',
'description' => 'Your Appwrite project ID',
'value' => '{projectId}',
'placeholder' => '{projectId}',
'required' => true,
'type' => 'text'
],
[
'name' => 'NEXT_PUBLIC_APPWRITE_PROJECT_NAME',
'description' => 'Your Appwrite project name',
'value' => '{projectName}',
'placeholder' => '{projectName}',
'required' => true,
'type' => 'text'
],
]
],
[
'key' => 'starter-for-nuxt',
'name' => 'Nuxt starter',
'useCases' => ['starter'],
'screenshotDark' => $url . '/images/sites/templates/starter-for-nuxt-dark.png',
'screenshotLight' => $url . '/images/sites/templates/starter-for-nuxt-light.png',
'frameworks' => [
getFramework('NUXT', [
'providerRootDirectory' => './',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'starter-for-nuxt',
'providerOwner' => 'appwrite',
'providerVersion' => '0.1.*',
'variables' => [
[
'name' => 'NUXT_PUBLIC_APPWRITE_ENDPOINT',
'description' => 'Endpoint of Appwrite server',
'value' => '{apiEndpoint}',
'placeholder' => '{apiEndpoint}',
'required' => true,
'type' => 'text'
],
[
'name' => 'NUXT_PUBLIC_APPWRITE_PROJECT_ID',
'description' => 'Your Appwrite project ID',
'value' => '{projectId}',
'placeholder' => '{projectId}',
'required' => true,
'type' => 'text'
],
[
'name' => 'NUXT_PUBLIC_APPWRITE_PROJECT_NAME',
'description' => 'Your Appwrite project name',
'value' => '{projectName}',
'placeholder' => '{projectName}',
'required' => true,
'type' => 'text'
],
]
],
[
'key' => 'template-for-event',
'name' => 'Event template',
'useCases' => ['starter'],
'screenshotDark' => $url . '/images/sites/templates/template-for-event-dark.png',
'screenshotLight' => $url . '/images/sites/templates/template-for-event-light.png',
'frameworks' => [
getFramework('NEXTJS', [
'providerRootDirectory' => './',
'installCommand' => 'pnpm install',
'buildCommand' => 'npm run build',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'template-for-event',
'providerOwner' => 'appwrite',
'providerVersion' => '0.1.*',
'variables' => [
[
'name' => 'NEXT_PUBLIC_APPWRITE_FUNCTION_PROJECT_ID',
'description' => 'Endpoint of Appwrite server',
'value' => '{apiEndpoint}',
'placeholder' => '{apiEndpoint}',
'required' => true,
'type' => 'text'
],
[
'name' => 'NEXT_PUBLIC_APPWRITE_FUNCTION_API_ENDPOINT',
'description' => 'Your Appwrite project ID',
'value' => '{projectId}',
'placeholder' => '{projectId}',
'required' => true,
'type' => 'text'
],
]
],
[
'key' => 'template-for-portfolio',
'name' => 'Portfolio template',
'useCases' => ['starter'],
'screenshotDark' => $url . '/images/sites/templates/template-for-portfolio-dark.png',
'screenshotLight' => $url . '/images/sites/templates/template-for-portfolio-light.png',
'frameworks' => [
getFramework('NEXTJS', [
'providerRootDirectory' => './',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'template-for-portfolio',
'providerOwner' => 'appwrite',
'providerVersion' => '0.1.*',
'variables' => []
],
[
'key' => 'template-for-store',
'name' => 'Store template',
'useCases' => ['starter'],
'screenshotDark' => $url . '/images/sites/templates/template-for-store-dark.png',
'screenshotLight' => $url . '/images/sites/templates/template-for-store-light.png',
'frameworks' => [
getFramework('SVELTEKIT', [
'providerRootDirectory' => './',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'template-for-store',
'providerOwner' => 'appwrite',
'providerVersion' => '0.1.*',
'variables' => [
[
'name' => 'STRIPE_SECRET_KEY',
'description' => 'Your Stripe secret key',
'value' => 'disabled',
'placeholder' => 'sk_.....',
'required' => false,
'type' => 'password'
],
[
'name' => 'PUBLIC_APPWRITE_ENDPOINT',
'description' => 'Endpoint of Appwrite server',
'value' => '{apiEndpoint}',
'placeholder' => '{apiEndpoint}',
'required' => true,
'type' => 'text'
],
[
'name' => 'PUBLIC_APPWRITE_PROJECT_ID',
'description' => 'Your Appwrite project ID',
'value' => '{projectId}',
'placeholder' => '{projectId}',
'required' => true,
'type' => 'text'
],
]
],
[
'key' => 'template-for-blog',
'name' => 'Blog template',
'useCases' => ['starter'],
'screenshotDark' => $url . '/images/sites/templates/template-for-blog-dark.png',
'screenshotLight' => $url . '/images/sites/templates/template-for-blog-light.png',
'frameworks' => [
getFramework('SVELTEKIT', [
'providerRootDirectory' => './',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'template-for-blog',
'providerOwner' => 'appwrite',
'providerVersion' => '0.1.*',
'variables' => []
],
[
'key' => 'astro-starter',
'name' => 'Astro starter',
'useCases' => ['starter'],
'screenshotDark' => $url . '/images/sites/templates/astro-starter-dark.png',
'screenshotLight' => $url . '/images/sites/templates/astro-starter-light.png',
'frameworks' => [
getFramework('ASTRO', [
'providerRootDirectory' => './astro/starter',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.2.*',
'variables' => [],
],
[
'key' => 'remix-starter',
'name' => 'Remix starter',
'useCases' => ['starter'],
'screenshotDark' => $url . '/images/sites/templates/remix-starter-dark.png',
'screenshotLight' => $url . '/images/sites/templates/remix-starter-light.png',
'frameworks' => [
getFramework('REMIX', [
'providerRootDirectory' => './remix/starter',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.2.*',
'variables' => [],
],
[
'key' => 'flutter-starter',
'name' => 'Flutter starter',
'useCases' => ['starter'],
'screenshotDark' => $url . '/images/sites/templates/flutter-starter-dark.png',
'screenshotLight' => $url . '/images/sites/templates/flutter-starter-light.png',
'frameworks' => [
getFramework('FLUTTER', [
'providerRootDirectory' => './flutter/starter',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.2.*',
'variables' => [],
],
[
'key' => 'nextjs-starter',
'name' => 'Next.js starter website',
'useCases' => ['starter'],
'screenshotDark' => $url . '/images/sites/templates/nextjs-starter-dark.png',
'screenshotLight' => $url . '/images/sites/templates/nextjs-starter-light.png',
'frameworks' => [
getFramework('NEXTJS', [
'providerRootDirectory' => './nextjs/starter',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.2.*',
'variables' => [],
],
[
'key' => 'nuxt-starter',
'name' => 'Nuxt starter website',
'useCases' => ['starter'],
'screenshotDark' => $url . '/images/sites/templates/nuxt-starter-dark.png',
'screenshotLight' => $url . '/images/sites/templates/nuxt-starter-light.png',
'frameworks' => [
getFramework('NUXT', [
'providerRootDirectory' => './nuxt/starter',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.2.*',
'variables' => [],
],
[
'key' => 'sveltekit-starter',
'name' => 'SvelteKit starter website',
'useCases' => ['starter'],
'screenshotDark' => $url . '/images/sites/templates/sveltekit-starter-dark.png',
'screenshotLight' => $url . '/images/sites/templates/sveltekit-starter-light.png',
'frameworks' => [
getFramework('SVELTEKIT', [
'providerRootDirectory' => './sveltekit/starter',
]),
],
'vcsProvider' => 'github',
'providerRepositoryId' => 'templates-for-sites',
'providerOwner' => 'appwrite',
'providerVersion' => '0.2.*',
'variables' => [],
],
];
+12 -4
View File
@@ -572,7 +572,7 @@ return [
],
[
'name' => '_APP_STORAGE_S3_ACCESS_KEY',
'description' => 'AWS S3 storage access key. Required when the storage adapter is set to S3. You can get your access key from your AWS console',
'description' => 'S3 storage access key. Required when the storage adapter is set to S3. You can get your access key from your S3 storage provider',
'introduction' => '0.13.0',
'default' => '',
'required' => false,
@@ -580,7 +580,7 @@ return [
],
[
'name' => '_APP_STORAGE_S3_SECRET',
'description' => 'AWS S3 storage secret key. Required when the storage adapter is set to S3. You can get your secret key from your AWS console.',
'description' => 'S3 storage secret key. Required when the storage adapter is set to S3. You can get your secret key from your S3 storage provider.',
'introduction' => '0.13.0',
'default' => '',
'required' => false,
@@ -588,7 +588,7 @@ return [
],
[
'name' => '_APP_STORAGE_S3_REGION',
'description' => 'AWS S3 storage region. Required when storage adapter is set to S3. You can find your region info for your bucket from AWS console.',
'description' => 'S3 storage region. Required when storage adapter is set to S3. You can find your region info for your bucket from your S3 storage provider.',
'introduction' => '0.13.0',
'default' => 'us-east-1',
'required' => false,
@@ -596,12 +596,20 @@ return [
],
[
'name' => '_APP_STORAGE_S3_BUCKET',
'description' => 'AWS S3 storage bucket. Required when storage adapter is set to S3. You can create buckets in your AWS console.',
'description' => 'S3 storage bucket. Required when storage adapter is set to S3. You can create buckets in your S3 storage provider.',
'introduction' => '0.13.0',
'default' => '',
'required' => false,
'question' => '',
],
[
'name' => '_APP_STORAGE_S3_ENDPOINT',
'description' => 'S3 storage endpoint. Required when using S3 storage providers other than AWS.',
'introduction' => '0.16.2',
'default' => '',
'required' => false,
'question' => '',
],
[
'name' => '_APP_STORAGE_DO_SPACES_ACCESS_KEY',
'description' => 'DigitalOcean spaces access key. Required when the storage adapter is set to DOSpaces. You can get your access key from your DigitalOcean console.',
+21 -19
View File
@@ -17,7 +17,7 @@ use Appwrite\Event\Delete;
use Appwrite\Event\Event;
use Appwrite\Event\Mail;
use Appwrite\Event\Messaging;
use Appwrite\Event\Usage;
use Appwrite\Event\StatsUsage;
use Appwrite\Extend\Exception;
use Appwrite\Hooks\Hooks;
use Appwrite\Network\Validator\Email;
@@ -2400,7 +2400,7 @@ App::put('/v1/account/sessions/phone')
App::post('/v1/account/tokens/phone')
->alias('/v1/account/sessions/phone')
->desc('Create phone token')
->groups(['api', 'account'])
->groups(['api', 'account', 'auth'])
->label('scope', 'sessions.write')
->label('auth.type', 'phone')
->label('audits.event', 'session.create')
@@ -2432,9 +2432,9 @@ App::post('/v1/account/tokens/phone')
->inject('queueForMessaging')
->inject('locale')
->inject('timelimit')
->inject('queueForUsage')
->inject('queueForStatsUsage')
->inject('plan')
->action(function (string $userId, string $phone, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Locale $locale, callable $timelimit, Usage $queueForUsage, array $plan) {
->action(function (string $userId, string $phone, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Locale $locale, callable $timelimit, StatsUsage $queueForStatsUsage, array $plan) {
if (empty(System::getEnv('_APP_SMS_PROVIDER'))) {
throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured');
}
@@ -2583,11 +2583,11 @@ App::post('/v1/account/tokens/phone')
$countryCode = $helper->parse($phone)->getCountryCode();
if (!empty($countryCode)) {
$queueForUsage
$queueForStatsUsage
->addMetric(str_replace('{countryCode}', $countryCode, METRIC_AUTH_METHOD_PHONE_COUNTRY_CODE), 1);
}
}
$queueForUsage
$queueForStatsUsage
->addMetric(METRIC_AUTH_METHOD_PHONE, 1)
->setProject($project)
->trigger();
@@ -2715,13 +2715,15 @@ App::get('/v1/account/logs')
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
}
$grouped = Query::groupByType($queries);
$limit = $grouped['limit'] ?? APP_LIMIT_COUNT;
$offset = $grouped['offset'] ?? 0;
// Temp fix for logs
$queries[] = Query::or([
Query::greaterThan('$createdAt', DateTime::format(new \DateTime('2025-02-26T01:30+00:00'))),
Query::lessThan('$createdAt', DateTime::format(new \DateTime('2025-02-13T00:00+00:00'))),
]);
$audit = new EventAudit($dbForProject);
$logs = $audit->getLogsByUser($user->getInternalId(), $limit, $offset);
$logs = $audit->getLogsByUser($user->getInternalId(), $queries);
$output = [];
@@ -2750,7 +2752,7 @@ App::get('/v1/account/logs')
}
$response->dynamic(new Document([
'total' => $audit->countLogsByUser($user->getInternalId()),
'total' => $audit->countLogsByUser($user->getInternalId(), $queries),
'logs' => $output,
]), Response::MODEL_LOG_LIST);
});
@@ -3678,9 +3680,9 @@ App::post('/v1/account/verification/phone')
->inject('project')
->inject('locale')
->inject('timelimit')
->inject('queueForUsage')
->inject('queueForStatsUsage')
->inject('plan')
->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Document $project, Locale $locale, callable $timelimit, Usage $queueForUsage, array $plan) {
->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Document $project, Locale $locale, callable $timelimit, StatsUsage $queueForStatsUsage, array $plan) {
if (empty(System::getEnv('_APP_SMS_PROVIDER'))) {
throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured');
}
@@ -3775,11 +3777,11 @@ App::post('/v1/account/verification/phone')
$countryCode = $helper->parse($phone)->getCountryCode();
if (!empty($countryCode)) {
$queueForUsage
$queueForStatsUsage
->addMetric(str_replace('{countryCode}', $countryCode, METRIC_AUTH_METHOD_PHONE_COUNTRY_CODE), 1);
}
}
$queueForUsage
$queueForStatsUsage
->addMetric(METRIC_AUTH_METHOD_PHONE, 1)
->setProject($project)
->trigger();
@@ -4310,9 +4312,9 @@ App::post('/v1/account/mfa/challenge')
->inject('queueForMessaging')
->inject('queueForMails')
->inject('timelimit')
->inject('queueForUsage')
->inject('queueForStatsUsage')
->inject('plan')
->action(function (string $factor, Response $response, Database $dbForProject, Document $user, Locale $locale, Document $project, Request $request, Event $queueForEvents, Messaging $queueForMessaging, Mail $queueForMails, callable $timelimit, Usage $queueForUsage, array $plan) {
->action(function (string $factor, Response $response, Database $dbForProject, Document $user, Locale $locale, Document $project, Request $request, Event $queueForEvents, Messaging $queueForMessaging, Mail $queueForMails, callable $timelimit, StatsUsage $queueForStatsUsage, array $plan) {
$expire = DateTime::addSeconds(new \DateTime(), Auth::TOKEN_EXPIRATION_CONFIRM);
$code = Auth::codeGenerator();
@@ -4383,11 +4385,11 @@ App::post('/v1/account/mfa/challenge')
$countryCode = $helper->parse($phone)->getCountryCode();
if (!empty($countryCode)) {
$queueForUsage
$queueForStatsUsage
->addMetric(str_replace('{countryCode}', $countryCode, METRIC_AUTH_METHOD_PHONE_COUNTRY_CODE), 1);
}
}
$queueForUsage
$queueForStatsUsage
->addMetric(METRIC_AUTH_METHOD_PHONE, 1)
->setProject($project)
->trigger();
+2 -1
View File
@@ -62,7 +62,8 @@ App::get('/v1/console/variables')
'_APP_DOMAIN_ENABLED' => $isDomainEnabled,
'_APP_ASSISTANT_ENABLED' => $isAssistantEnabled,
'_APP_DOMAIN_SITES' => System::getEnv('_APP_DOMAIN_SITES'),
'_APP_OPTIONS_FORCE_HTTPS' => System::getEnv('_APP_OPTIONS_FORCE_HTTPS')
'_APP_OPTIONS_FORCE_HTTPS' => System::getEnv('_APP_OPTIONS_FORCE_HTTPS'),
'_APP_DOMAINS_NAMESERVERS' => System::getEnv('_APP_DOMAINS_NAMESERVERS'),
]);
$response->dynamic($variables, Response::MODEL_CONSOLE_VARIABLES);
+73 -63
View File
@@ -4,7 +4,7 @@ use Appwrite\Auth\Auth;
use Appwrite\Detector\Detector;
use Appwrite\Event\Database as EventDatabase;
use Appwrite\Event\Event;
use Appwrite\Event\Usage;
use Appwrite\Event\StatsUsage;
use Appwrite\Extend\Exception;
use Appwrite\Network\Validator\Email;
use Appwrite\SDK\AuthType;
@@ -23,10 +23,12 @@ use Utopia\App;
use Utopia\Audit\Audit;
use Utopia\Config\Config;
use Utopia\Database\Database;
use Utopia\Database\DateTime;
use Utopia\Database\Document;
use Utopia\Database\Exception\Authorization as AuthorizationException;
use Utopia\Database\Exception\Conflict as ConflictException;
use Utopia\Database\Exception\Duplicate as DuplicateException;
use Utopia\Database\Exception\Index as IndexException;
use Utopia\Database\Exception\Limit as LimitException;
use Utopia\Database\Exception\NotFound as NotFoundException;
use Utopia\Database\Exception\Query as QueryException;
@@ -241,8 +243,8 @@ function updateAttribute(
string $filter = null,
string|bool|int|float $default = null,
bool $required = null,
int|float $min = null,
int|float $max = null,
int|float|null $min = null,
int|float|null $max = null,
array $elements = null,
array $options = [],
string $newKey = null,
@@ -298,6 +300,9 @@ function updateAttribute(
switch ($attribute->getAttribute('format')) {
case APP_DATABASE_ATTRIBUTE_INT_RANGE:
case APP_DATABASE_ATTRIBUTE_FLOAT_RANGE:
$min ??= $attribute->getAttribute('formatOptions')['min'];
$max ??= $attribute->getAttribute('formatOptions')['max'];
if ($min > $max) {
throw new Exception(Exception::ATTRIBUTE_VALUE_INVALID, 'Minimum value must be lesser than maximum value');
}
@@ -393,6 +398,8 @@ function updateAttribute(
throw new Exception(Exception::ATTRIBUTE_NOT_FOUND);
} catch (LimitException) {
throw new Exception(Exception::ATTRIBUTE_LIMIT_EXCEEDED);
} catch (IndexException $e) {
throw new Exception(Exception::INDEX_INVALID, $e->getMessage());
}
}
@@ -476,8 +483,8 @@ App::post('/v1/databases')
->inject('response')
->inject('dbForProject')
->inject('queueForEvents')
->inject('queueForUsage')
->action(function (string $databaseId, string $name, bool $enabled, Response $response, Database $dbForProject, Event $queueForEvents, Usage $queueForUsage) {
->inject('queueForStatsUsage')
->action(function (string $databaseId, string $name, bool $enabled, Response $response, Database $dbForProject, Event $queueForEvents, StatsUsage $queueForStatsUsage) {
$databaseId = $databaseId == 'unique()' ? ID::unique() : $databaseId;
@@ -527,7 +534,7 @@ App::post('/v1/databases')
}
$queueForEvents->setParam('databaseId', $database->getId());
$queueForUsage->addMetric(str_replace(['{databaseInternalId}'], [$database->getInternalId()], METRIC_DATABASE_ID_STORAGE), 1); // per database
$queueForStatsUsage->addMetric(str_replace(['{databaseInternalId}'], [$database->getInternalId()], METRIC_DATABASE_ID_STORAGE), 1); // per database
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -666,13 +673,15 @@ App::get('/v1/databases/:databaseId/logs')
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
}
$grouped = Query::groupByType($queries);
$limit = $grouped['limit'] ?? APP_LIMIT_COUNT;
$offset = $grouped['offset'] ?? 0;
// Temp fix for logs
$queries[] = Query::or([
Query::greaterThan('$createdAt', DateTime::format(new \DateTime('2025-02-26T01:30+00:00'))),
Query::lessThan('$createdAt', DateTime::format(new \DateTime('2025-02-13T00:00+00:00'))),
]);
$audit = new Audit($dbForProject);
$resource = 'database/' . $databaseId;
$logs = $audit->getLogsByResource($resource, $limit, $offset);
$logs = $audit->getLogsByResource($resource, $queries);
$output = [];
@@ -720,7 +729,7 @@ App::get('/v1/databases/:databaseId/logs')
}
$response->dynamic(new Document([
'total' => $audit->countLogsByResource($resource),
'total' => $audit->countLogsByResource($resource, $queries),
'logs' => $output,
]), Response::MODEL_LOG_LIST);
});
@@ -797,8 +806,8 @@ App::delete('/v1/databases/:databaseId')
->inject('dbForProject')
->inject('queueForDatabase')
->inject('queueForEvents')
->inject('queueForUsage')
->action(function (string $databaseId, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Usage $queueForUsage) {
->inject('queueForStatsUsage')
->action(function (string $databaseId, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, StatsUsage $queueForStatsUsage) {
$database = $dbForProject->getDocument('databases', $databaseId);
@@ -821,7 +830,7 @@ App::delete('/v1/databases/:databaseId')
->setParam('databaseId', $database->getId())
->setPayload($response->output($database, Response::MODEL_DATABASE));
$queueForUsage
$queueForStatsUsage
->addMetric(METRIC_DATABASES_STORAGE, 1); // Global, deletion forces full recalculation
$response->noContent();
@@ -1054,14 +1063,21 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/logs')
throw new Exception(Exception::COLLECTION_NOT_FOUND);
}
$queries = Query::parseQueries($queries);
$grouped = Query::groupByType($queries);
$limit = $grouped['limit'] ?? APP_LIMIT_COUNT;
$offset = $grouped['offset'] ?? 0;
try {
$queries = Query::parseQueries($queries);
} catch (QueryException $e) {
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
}
// Temp fix for logs
$queries[] = Query::or([
Query::greaterThan('$createdAt', DateTime::format(new \DateTime('2025-02-26T01:30+00:00'))),
Query::lessThan('$createdAt', DateTime::format(new \DateTime('2025-02-13T00:00+00:00'))),
]);
$audit = new Audit($dbForProject);
$resource = 'database/' . $databaseId . '/collection/' . $collectionId;
$logs = $audit->getLogsByResource($resource, $limit, $offset);
$logs = $audit->getLogsByResource($resource, $queries);
$output = [];
@@ -1109,7 +1125,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/logs')
}
$response->dynamic(new Document([
'total' => $audit->countLogsByResource($resource),
'total' => $audit->countLogsByResource($resource, $queries),
'logs' => $output,
]), Response::MODEL_LOG_LIST);
});
@@ -1547,8 +1563,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/intege
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?int $min, ?int $max, ?int $default, bool $array, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
// Ensure attribute default is within range
$min = \is_null($min) ? PHP_INT_MIN : $min;
$max = \is_null($max) ? PHP_INT_MAX : $max;
$min ??= PHP_INT_MIN;
$max ??= PHP_INT_MAX;
if ($min > $max) {
throw new Exception(Exception::ATTRIBUTE_VALUE_INVALID, 'Minimum value must be lesser than maximum value');
@@ -1624,8 +1640,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/float'
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?float $min, ?float $max, ?float $default, bool $array, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
// Ensure attribute default is within range
$min = \is_null($min) ? -PHP_FLOAT_MAX : $min;
$max = \is_null($max) ? PHP_FLOAT_MAX : $max;
$min ??= -PHP_FLOAT_MAX;
$max ??= PHP_FLOAT_MAX;
if ($min > $max) {
throw new Exception(Exception::ATTRIBUTE_VALUE_INVALID, 'Minimum value must be lesser than maximum value');
@@ -2336,8 +2352,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/integ
->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).')
->param('key', '', new Key(), 'Attribute Key.')
->param('required', null, new Boolean(), 'Is attribute required?')
->param('min', null, new Integer(), 'Minimum value to enforce on new documents')
->param('max', null, new Integer(), 'Maximum value to enforce on new documents')
->param('min', null, new Integer(), 'Minimum value to enforce on new documents', true)
->param('max', null, new Integer(), 'Maximum value to enforce on new documents', true)
->param('default', null, new Nullable(new Integer()), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
->param('newKey', null, new Key(), 'New attribute key.', true)
->inject('response')
@@ -2395,8 +2411,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/float
->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).')
->param('key', '', new Key(), 'Attribute Key.')
->param('required', null, new Boolean(), 'Is attribute required?')
->param('min', null, new FloatValidator(), 'Minimum value to enforce on new documents')
->param('max', null, new FloatValidator(), 'Maximum value to enforce on new documents')
->param('min', null, new FloatValidator(), 'Minimum value to enforce on new documents', true)
->param('max', null, new FloatValidator(), 'Maximum value to enforce on new documents', true)
->param('default', null, new Nullable(new FloatValidator()), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
->param('newKey', null, new Key(), 'New attribute key.', true)
->inject('response')
@@ -2618,8 +2634,8 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key
->inject('dbForProject')
->inject('queueForDatabase')
->inject('queueForEvents')
->inject('queueForUsage')
->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Usage $queueForUsage) {
->inject('queueForStatsUsage')
->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, StatsUsage $queueForStatsUsage) {
$db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
@@ -2716,7 +2732,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key
->setContext('database', $db)
->setPayload($response->output($attribute, $model));
$queueForUsage
$queueForStatsUsage
->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$db->getInternalId(), $collection->getInternalId()], METRIC_DATABASE_ID_COLLECTION_ID_STORAGE), 1); // per collection
$response->noContent();
@@ -2822,7 +2838,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes')
$attributeIndex = \array_search($attribute, array_column($oldAttributes, 'key'));
if ($attributeIndex === false) {
throw new Exception(Exception::ATTRIBUTE_UNKNOWN, 'Unknown attribute: ' . $attribute);
throw new Exception(Exception::ATTRIBUTE_UNKNOWN, 'Unknown attribute: ' . $attribute . '. Verify the attribute name or create the attribute.');
}
$attributeStatus = $oldAttributes[$attributeIndex]['status'];
@@ -3134,9 +3150,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
->inject('dbForProject')
->inject('user')
->inject('queueForEvents')
->inject('queueForUsage')
->inject('mode')
->action(function (string $databaseId, string $documentId, string $collectionId, string|array $data, ?array $permissions, Response $response, Database $dbForProject, Document $user, Event $queueForEvents, Usage $queueForUsage, string $mode) {
->inject('queueForStatsUsage')
->action(function (string $databaseId, string $documentId, string $collectionId, string|array $data, ?array $permissions, Response $response, Database $dbForProject, Document $user, Event $queueForEvents, StatsUsage $queueForStatsUsage) {
$data = (\is_string($data)) ? \json_decode($data, true) : $data; // Cast to JSON array
@@ -3339,7 +3354,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
$processDocument($collection, $document);
$queueForUsage
$queueForStatsUsage
->addMetric(METRIC_DATABASES_OPERATIONS_WRITES, $operations)
->addMetric(str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_OPERATIONS_WRITES), $operations)
->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$database->getInternalId(), $collection->getInternalId()], METRIC_DATABASE_ID_COLLECTION_ID_STORAGE), 1); // per collection
@@ -3391,9 +3406,8 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
->param('queries', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), '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.', true)
->inject('response')
->inject('dbForProject')
->inject('mode')
->inject('queueForUsage')
->action(function (string $databaseId, string $collectionId, array $queries, Response $response, Database $dbForProject, string $mode, Usage $queueForUsage) {
->inject('queueForStatsUsage')
->action(function (string $databaseId, string $collectionId, array $queries, Response $response, Database $dbForProject, StatsUsage $queueForStatsUsage) {
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
@@ -3505,10 +3519,9 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
$processDocument($collection, $document);
}
$queueForUsage
$queueForStatsUsage
->addMetric(METRIC_DATABASES_OPERATIONS_READS, $operations)
->addMetric(str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_OPERATIONS_READS), $operations)
;
->addMetric(str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_OPERATIONS_READS), $operations);
$response->addHeader('X-Debug-Operations', $operations);
@@ -3570,9 +3583,8 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen
->param('queries', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), '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.', true)
->inject('response')
->inject('dbForProject')
->inject('mode')
->inject('queueForUsage')
->action(function (string $databaseId, string $collectionId, string $documentId, array $queries, Response $response, Database $dbForProject, string $mode, Usage $queueForUsage) {
->inject('queueForStatsUsage')
->action(function (string $databaseId, string $collectionId, string $documentId, array $queries, Response $response, Database $dbForProject, StatsUsage $queueForStatsUsage) {
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
@@ -3648,10 +3660,9 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen
$processDocument($collection, $document);
$queueForUsage
$queueForStatsUsage
->addMetric(METRIC_DATABASES_OPERATIONS_READS, $operations)
->addMetric(str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_OPERATIONS_READS), $operations)
;
->addMetric(str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_OPERATIONS_READS), $operations);
$response->addHeader('X-Debug-Operations', $operations);
@@ -3711,13 +3722,15 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
}
$grouped = Query::groupByType($queries);
$limit = $grouped['limit'] ?? APP_LIMIT_COUNT;
$offset = $grouped['offset'] ?? 0;
// Temp fix for logs
$queries[] = Query::or([
Query::greaterThan('$createdAt', DateTime::format(new \DateTime('2025-02-26T01:30+00:00'))),
Query::lessThan('$createdAt', DateTime::format(new \DateTime('2025-02-13T00:00+00:00'))),
]);
$audit = new Audit($dbForProject);
$resource = 'database/' . $databaseId . '/collection/' . $collectionId . '/document/' . $document->getId();
$logs = $audit->getLogsByResource($resource, $limit, $offset);
$logs = $audit->getLogsByResource($resource, $queries);
$output = [];
@@ -3765,7 +3778,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen
}
$response->dynamic(new Document([
'total' => $audit->countLogsByResource($resource),
'total' => $audit->countLogsByResource($resource, $queries),
'logs' => $output,
]), Response::MODEL_LOG_LIST);
});
@@ -3804,9 +3817,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
->inject('response')
->inject('dbForProject')
->inject('queueForEvents')
->inject('mode')
->inject('queueForUsage')
->action(function (string $databaseId, string $collectionId, string $documentId, string|array $data, ?array $permissions, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Event $queueForEvents, string $mode, Usage $queueForUsage) {
->inject('queueForStatsUsage')
->action(function (string $databaseId, string $collectionId, string $documentId, string|array $data, ?array $permissions, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Event $queueForEvents, StatsUsage $queueForStatsUsage) {
$data = (\is_string($data)) ? \json_decode($data, true) : $data; // Cast to JSON array
@@ -3946,10 +3958,9 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
$setCollection($collection, $newDocument);
$queueForUsage
$queueForStatsUsage
->addMetric(METRIC_DATABASES_OPERATIONS_WRITES, $operations)
->addMetric(str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_OPERATIONS_WRITES), $operations)
;
->addMetric(str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_OPERATIONS_WRITES), $operations);
$response->addHeader('X-Debug-Operations', $operations);
@@ -4058,9 +4069,8 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
->inject('response')
->inject('dbForProject')
->inject('queueForEvents')
->inject('queueForUsage')
->inject('mode')
->action(function (string $databaseId, string $collectionId, string $documentId, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Event $queueForEvents, Usage $queueForUsage, string $mode) {
->inject('queueForStatsUsage')
->action(function (string $databaseId, string $collectionId, string $documentId, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Event $queueForEvents, StatsUsage $queueForStatsUsage) {
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
@@ -4129,7 +4139,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
$processDocument($collection, $document);
$queueForUsage
$queueForStatsUsage
->addMetric(METRIC_DATABASES_OPERATIONS_WRITES, 1)
->addMetric(str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_OPERATIONS_WRITES), 1)
->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$database->getInternalId(), $collection->getInternalId()], METRIC_DATABASE_ID_COLLECTION_ID_STORAGE), 1); // per collection
File diff suppressed because it is too large Load Diff
+48 -14
View File
@@ -692,15 +692,15 @@ App::get('/v1/health/queue/functions')
$response->dynamic(new Document([ 'size' => $size ]), Response::MODEL_HEALTH_QUEUE);
}, ['response']);
App::get('/v1/health/queue/usage')
->desc('Get usage queue')
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',
name: 'getQueueUsage',
description: '/docs/references/health/get-queue-usage.md',
name: 'getQueueStatsResources',
description: '/docs/references/health/get-queue-stats-resources.md',
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
@@ -715,7 +715,7 @@ App::get('/v1/health/queue/usage')
->action(function (int|string $threshold, Publisher $publisher, Response $response) {
$threshold = \intval($threshold);
$size = $publisher->getQueueSize(new Queue(Event::USAGE_QUEUE_NAME));
$size = $publisher->getQueueSize(new Queue(Event::STATS_RESOURCES_QUEUE_NAME));
if ($size >= $threshold) {
throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
@@ -724,15 +724,15 @@ App::get('/v1/health/queue/usage')
$response->dynamic(new Document([ 'size' => $size ]), Response::MODEL_HEALTH_QUEUE);
});
App::get('/v1/health/queue/usage-dump')
->desc('Get usage dump queue')
App::get('/v1/health/queue/stats-usage')
->desc('Get stats usage queue')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk', new Method(
auth: [AuthType::KEY],
namespace: 'health',
name: 'getQueueUsageDump',
description: '/docs/references/health/get-queue-usage-dump.md',
name: 'getQueueUsage',
description: '/docs/references/health/get-queue-stats-usage.md',
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
@@ -747,7 +747,39 @@ App::get('/v1/health/queue/usage-dump')
->action(function (int|string $threshold, Publisher $publisher, Response $response) {
$threshold = \intval($threshold);
$size = $publisher->getQueueSize(new Queue(Event::USAGE_DUMP_QUEUE_NAME));
$size = $publisher->getQueueSize(new Queue(Event::STATS_USAGE_QUEUE_NAME));
if ($size >= $threshold) {
throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
}
$response->dynamic(new Document([ 'size' => $size ]), Response::MODEL_HEALTH_QUEUE);
});
App::get('/v1/health/queue/stats-usage-dump')
->desc('Get usage dump queue')
->groups(['api', 'health'])
->label('scope', 'health.read')
->label('sdk', new Method(
auth: [AuthType::KEY],
namespace: 'health',
name: 'getQueueStatsUsageDump',
description: '/docs/references/health/get-queue-stats-usage-dump.md',
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_HEALTH_QUEUE,
)
],
contentType: ContentType::JSON
))
->param('threshold', 5000, new Integer(true), 'Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.', true)
->inject('publisher')
->inject('response')
->action(function (int|string $threshold, Publisher $publisher, Response $response) {
$threshold = \intval($threshold);
$size = $publisher->getQueueSize(new Queue(Event::STATS_USAGE_DUMP_QUEUE_NAME));
if ($size >= $threshold) {
throw new Exception(Exception::HEALTH_QUEUE_SIZE_EXCEEDED, "Queue size threshold hit. Current size is {$size} and threshold is {$threshold}.");
@@ -825,9 +857,10 @@ App::get('/v1/health/storage')
->inject('response')
->inject('deviceForFiles')
->inject('deviceForFunctions')
->inject('deviceForSites')
->inject('deviceForBuilds')
->action(function (Response $response, Device $deviceForFiles, Device $deviceForFunctions, Device $deviceForBuilds) {
$devices = [$deviceForFiles, $deviceForFunctions, $deviceForBuilds];
->action(function (Response $response, Device $deviceForFiles, Device $deviceForFunctions, Device $deviceForSites, Device $deviceForBuilds) {
$devices = [$deviceForFiles, $deviceForFunctions, $deviceForSites, $deviceForBuilds];
$checkStart = \microtime(true);
foreach ($devices as $device) {
@@ -920,8 +953,9 @@ App::get('/v1/health/queue/failed/:name')
Event::AUDITS_QUEUE_NAME,
Event::MAILS_QUEUE_NAME,
Event::FUNCTIONS_QUEUE_NAME,
Event::USAGE_QUEUE_NAME,
Event::USAGE_DUMP_QUEUE_NAME,
Event::STATS_RESOURCES_QUEUE_NAME,
Event::STATS_USAGE_QUEUE_NAME,
Event::STATS_USAGE_DUMP_QUEUE_NAME,
Event::WEBHOOK_QUEUE_NAME,
Event::CERTIFICATES_QUEUE_NAME,
Event::BUILDS_QUEUE_NAME,
+28 -20
View File
@@ -994,13 +994,15 @@ App::get('/v1/messaging/providers/:providerId/logs')
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
}
$grouped = Query::groupByType($queries);
$limit = $grouped['limit'] ?? APP_LIMIT_COUNT;
$offset = $grouped['offset'] ?? 0;
// Temp fix for logs
$queries[] = Query::or([
Query::greaterThan('$createdAt', DateTime::format(new \DateTime('2025-02-26T01:30+00:00'))),
Query::lessThan('$createdAt', DateTime::format(new \DateTime('2025-02-13T00:00+00:00'))),
]);
$audit = new Audit($dbForProject);
$resource = 'provider/' . $providerId;
$logs = $audit->getLogsByResource($resource, $limit, $offset);
$logs = $audit->getLogsByResource($resource, $queries);
$output = [];
foreach ($logs as $i => &$log) {
@@ -1047,7 +1049,7 @@ App::get('/v1/messaging/providers/:providerId/logs')
}
$response->dynamic(new Document([
'total' => $audit->countLogsByResource($resource),
'total' => $audit->countLogsByResource($resource, $queries),
'logs' => $output,
]), Response::MODEL_LOG_LIST);
});
@@ -2222,13 +2224,15 @@ App::get('/v1/messaging/topics/:topicId/logs')
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
}
$grouped = Query::groupByType($queries);
$limit = $grouped['limit'] ?? APP_LIMIT_COUNT;
$offset = $grouped['offset'] ?? 0;
// Temp fix for logs
$queries[] = Query::or([
Query::greaterThan('$createdAt', DateTime::format(new \DateTime('2025-02-26T01:30+00:00'))),
Query::lessThan('$createdAt', DateTime::format(new \DateTime('2025-02-13T00:00+00:00'))),
]);
$audit = new Audit($dbForProject);
$resource = 'topic/' . $topicId;
$logs = $audit->getLogsByResource($resource, $limit, $offset);
$logs = $audit->getLogsByResource($resource, $queries);
$output = [];
@@ -2276,7 +2280,7 @@ App::get('/v1/messaging/topics/:topicId/logs')
}
$response->dynamic(new Document([
'total' => $audit->countLogsByResource($resource),
'total' => $audit->countLogsByResource($resource, $queries),
'logs' => $output,
]), Response::MODEL_LOG_LIST);
});
@@ -2632,13 +2636,15 @@ App::get('/v1/messaging/subscribers/:subscriberId/logs')
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
}
$grouped = Query::groupByType($queries);
$limit = $grouped['limit'] ?? APP_LIMIT_COUNT;
$offset = $grouped['offset'] ?? 0;
// Temp fix for logs
$queries[] = Query::or([
Query::greaterThan('$createdAt', DateTime::format(new \DateTime('2025-02-26T01:30+00:00'))),
Query::lessThan('$createdAt', DateTime::format(new \DateTime('2025-02-13T00:00+00:00'))),
]);
$audit = new Audit($dbForProject);
$resource = 'subscriber/' . $subscriberId;
$logs = $audit->getLogsByResource($resource, $limit, $offset);
$logs = $audit->getLogsByResource($resource, $queries);
$output = [];
@@ -2686,7 +2692,7 @@ App::get('/v1/messaging/subscribers/:subscriberId/logs')
}
$response->dynamic(new Document([
'total' => $audit->countLogsByResource($resource),
'total' => $audit->countLogsByResource($resource, $queries),
'logs' => $output,
]), Response::MODEL_LOG_LIST);
});
@@ -3397,13 +3403,15 @@ App::get('/v1/messaging/messages/:messageId/logs')
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
}
$grouped = Query::groupByType($queries);
$limit = $grouped['limit'] ?? APP_LIMIT_COUNT;
$offset = $grouped['offset'] ?? 0;
// Temp fix for logs
$queries[] = Query::or([
Query::greaterThan('$createdAt', DateTime::format(new \DateTime('2025-02-26T01:30+00:00'))),
Query::lessThan('$createdAt', DateTime::format(new \DateTime('2025-02-13T00:00+00:00'))),
]);
$audit = new Audit($dbForProject);
$resource = 'message/' . $messageId;
$logs = $audit->getLogsByResource($resource, $limit, $offset);
$logs = $audit->getLogsByResource($resource, $queries);
$output = [];
@@ -3451,7 +3459,7 @@ App::get('/v1/messaging/messages/:messageId/logs')
}
$response->dynamic(new Document([
'total' => $audit->countLogsByResource($resource),
'total' => $audit->countLogsByResource($resource, $queries),
'logs' => $output,
]), Response::MODEL_LOG_LIST);
});
+3 -3
View File
@@ -48,9 +48,9 @@ App::post('/v1/migrations/appwrite')
]
))
->param('resources', [], new ArrayList(new WhiteList(Appwrite::getSupportedResources())), 'List of resources to migrate')
->param('endpoint', '', new URL(), "Source's Appwrite Endpoint")
->param('projectId', '', new UID(), "Source's Project ID")
->param('apiKey', '', new Text(512), "Source's API Key")
->param('endpoint', '', new URL(), 'Source Appwrite endpoint')
->param('projectId', '', new UID(), 'Source Project ID')
->param('apiKey', '', new Text(512), 'Source API Key')
->inject('response')
->inject('dbForProject')
->inject('project')
+16 -4
View File
@@ -41,14 +41,18 @@ App::get('/v1/project/usage')
->param('endDate', '', new DateTimeValidator(), 'End date for the usage')
->param('period', '1d', new WhiteList(['1h', '1d']), 'Period used', true)
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('getLogsDB')
->inject('smsRates')
->action(function (string $startDate, string $endDate, string $period, Response $response, Database $dbForProject, array $smsRates) {
->action(function (string $startDate, string $endDate, string $period, Response $response, Document $project, Database $dbForProject, callable $getLogsDB, array $smsRates) {
$stats = $total = $usage = [];
$format = 'Y-m-d 00:00:00';
$firstDay = (new DateTime($startDate))->format($format);
$lastDay = (new DateTime($endDate))->format($format);
$dbForLogs = call_user_func($getLogsDB, $project);
$metrics = [
'total' => [
METRIC_EXECUTIONS,
@@ -64,6 +68,7 @@ App::get('/v1/project/usage')
METRIC_BUILDS_STORAGE,
METRIC_DATABASES_OPERATIONS_READS,
METRIC_DATABASES_OPERATIONS_WRITES,
METRIC_FILES_IMAGES_TRANSFORMED,
],
'period' => [
METRIC_NETWORK_REQUESTS,
@@ -76,6 +81,7 @@ App::get('/v1/project/usage')
METRIC_BUILDS_MB_SECONDS,
METRIC_DATABASES_OPERATIONS_READS,
METRIC_DATABASES_OPERATIONS_WRITES,
METRIC_FILES_IMAGES_TRANSFORMED,
]
];
@@ -94,9 +100,11 @@ App::get('/v1/project/usage')
'1d' => 'Y-m-d\T00:00:00.000P',
};
Authorization::skip(function () use ($dbForProject, $firstDay, $lastDay, $period, $metrics, $limit, &$total, &$stats) {
Authorization::skip(function () use ($dbForProject, $dbForLogs, $firstDay, $lastDay, $period, $metrics, $limit, &$total, &$stats) {
foreach ($metrics['total'] as $metric) {
$result = $dbForProject->findOne('stats', [
$db = ($metric === METRIC_FILES_IMAGES_TRANSFORMED) ? $dbForLogs : $dbForProject;
$result = $db->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
]);
@@ -104,7 +112,9 @@ App::get('/v1/project/usage')
}
foreach ($metrics['period'] as $metric) {
$results = $dbForProject->find('stats', [
$db = ($metric === METRIC_FILES_IMAGES_TRANSFORMED) ? $dbForLogs : $dbForProject;
$results = $db->find('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', [$period]),
Query::greaterThanEqual('time', $firstDay),
@@ -364,6 +374,8 @@ App::get('/v1/project/usage')
'authPhoneTotal' => $authPhoneTotal,
'authPhoneEstimate' => $authPhoneEstimate,
'authPhoneCountryBreakdown' => $authPhoneCountryBreakdown,
'imageTransformations' => $usage[METRIC_FILES_IMAGES_TRANSFORMED],
'imageTransformationsTotal' => $total[METRIC_FILES_IMAGES_TRANSFORMED],
]), Response::MODEL_USAGE_PROJECT);
});
-194
View File
@@ -15,176 +15,13 @@ use Utopia\App;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Exception\Query as QueryException;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Query;
use Utopia\Database\Validator\Query\Cursor;
use Utopia\Database\Validator\UID;
use Utopia\Domains\Domain;
use Utopia\Logger\Log;
use Utopia\System\System;
use Utopia\Validator\Domain as ValidatorDomain;
use Utopia\Validator\Text;
use Utopia\Validator\WhiteList;
App::post('/v1/proxy/rules')
->groups(['api', 'proxy'])
->desc('Create rule')
->label('scope', 'rules.write')
->label('event', 'rules.[ruleId].create')
->label('audits.event', 'rule.create')
->label('audits.resource', 'rule/{response.$id}')
->label('sdk', new Method(
namespace: 'proxy',
name: 'createRule',
description: '/docs/references/proxy/create-rule.md',
auth: [AuthType::ADMIN],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_CREATED,
model: Response::MODEL_PROXY_RULE,
)
]
))
->param('domain', null, new ValidatorDomain(), 'Domain name.')
->param('resourceType', null, new WhiteList(['api', 'function', 'site']), 'Action definition for the rule. Possible values are "api", "function" and "site"')
->param('resourceId', '', new UID(), 'ID of resource for the action type. If resourceType is "api", leave empty. If resourceType is "function", provide ID of the function.', true)
->inject('response')
->inject('project')
->inject('queueForCertificates')
->inject('queueForEvents')
->inject('dbForPlatform')
->inject('dbForProject')
->action(function (string $domain, string $resourceType, string $resourceId, Response $response, Document $project, Certificate $queueForCertificates, Event $queueForEvents, Database $dbForPlatform, Database $dbForProject) {
$mainDomain = System::getEnv('_APP_DOMAIN', '');
if ($domain === $mainDomain) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'You cannot assign your main domain to specific resource. Please use subdomain or a different domain.');
}
$sitesDomain = System::getEnv('_APP_DOMAIN_SITES', '');
$functionsDomain = System::getEnv('_APP_DOMAIN_FUNCTIONS', '');
if (
($functionsDomain !== '' && str_ends_with($domain, $functionsDomain)) ||
($sitesDomain !== '' && str_ends_with($domain, $sitesDomain))
) {
// TODO: Refactor later
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'You cannot assign your functions or sites domain or their subdomains to a specific resource. Please use a different domain.');
}
if ($domain === 'localhost' || $domain === APP_HOSTNAME_INTERNAL) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'This domain name is not allowed. Please pick another one.');
}
// TODO: @christyjacob remove once we migrate the rules in 1.7.x
if (System::getEnv('_APP_RULES_FORMAT') === 'md5') {
$document = $dbForPlatform->getDocument('rules', md5($domain));
} else {
$document = $dbForPlatform->findOne('rules', [
Query::equal('domain', [$domain]),
]);
}
if (!$document->isEmpty()) {
if ($document->getAttribute('projectId') === $project->getId()) {
$resourceType = $document->getAttribute('resourceType');
$resourceId = $document->getAttribute('resourceId');
$message = "Domain already assigned to '{$resourceType}' service";
if (!empty($resourceId)) {
$message .= " with ID '{$resourceId}'";
}
$message .= '.';
} else {
$message = 'Domain already assigned to different project.';
}
throw new Exception(Exception::RULE_ALREADY_EXISTS, $message);
}
$resourceInternalId = '';
switch ($resourceType) {
case 'function':
if (empty($resourceId)) {
throw new Exception(Exception::FUNCTION_NOT_FOUND);
}
$function = $dbForProject->getDocument('functions', $resourceId);
if ($function->isEmpty()) {
throw new Exception(Exception::RULE_RESOURCE_NOT_FOUND);
}
$resourceInternalId = $function->getInternalId();
break;
case 'site':
if (empty($resourceId)) {
throw new Exception(Exception::SITE_NOT_FOUND);
}
$site = $dbForProject->getDocument('sites', $resourceId);
if ($site->isEmpty()) {
throw new Exception(Exception::RULE_RESOURCE_NOT_FOUND);
}
$resourceInternalId = $site->getInternalId();
break;
}
try {
$domain = new Domain($domain);
} catch (\Throwable) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Domain may not start with http:// or https://.');
}
// TODO: @christyjacob remove once we migrate the rules in 1.7.x
$ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5($domain->get()) : ID::unique();
$rule = new Document([
'$id' => $ruleId,
'projectId' => $project->getId(),
'projectInternalId' => $project->getInternalId(),
'domain' => $domain->get(),
'resourceType' => $resourceType,
'resourceId' => $resourceId,
'resourceInternalId' => $resourceInternalId,
'certificateId' => '',
]);
$status = 'created';
if (\str_ends_with($domain->get(), $functionsDomain) || \str_ends_with($domain->get(), $sitesDomain)) {
$status = 'verified';
}
if ($status === 'created') {
$target = new Domain(System::getEnv('_APP_DOMAIN_TARGET', ''));
$validator = new CNAME($target->get()); // Verify Domain with DNS records
if ($validator->isValid($domain->get())) {
$status = 'verifying';
$queueForCertificates
->setDomain(new Document([
'domain' => $rule->getAttribute('domain')
]))
->trigger();
}
}
$rule->setAttribute('status', $status);
$rule = $dbForPlatform->createDocument('rules', $rule);
$queueForEvents->setParam('ruleId', $rule->getId());
$rule->setAttribute('logs', '');
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->dynamic($rule, Response::MODEL_PROXY_RULE);
});
App::get('/v1/proxy/rules')
->groups(['api', 'proxy'])
@@ -411,34 +248,3 @@ App::patch('/v1/proxy/rules/:ruleId/verification')
$response->dynamic($rule, Response::MODEL_PROXY_RULE);
});
App::get('/v1/proxy/subdomains')
->desc('Check if subdomain is available')
->groups(['api', 'proxy'])
->label('scope', 'rules.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'proxy')
->label('sdk.method', 'checkSubdomain')
->label('sdk.description', '/docs/references/proxy/check-subdomain.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_NONE)
->param('resourceType', null, new WhiteList(['function', 'site']), 'Action definition for the rule. Possible values are "function" and "site"')
->param('subdomain', '', new Text(256), 'Subdomain name.')
->inject('response')
->inject('dbForPlatform')
->action(function (string $resourceType, string $subdomain, Response $response, Database $dbForPlatform) {
//TODO: Add tests for this endpoint
$resourceDomain = $resourceType === 'site' ? System::getEnv('_APP_DOMAIN_SITES', '') : System::getEnv('_APP_DOMAIN_FUNCTIONS', '');
$domain = $subdomain . '.' . $resourceDomain;
$document = $dbForPlatform->findOne('rules', [
Query::equal('domain', [$domain]),
]);
if ($document && !$document->isEmpty()) {
throw new Exception(Exception::RULE_ALREADY_EXISTS, 'Subdomain already assigned to different project.');
}
$response->noContent();
});
+23 -22
View File
@@ -6,7 +6,6 @@ use Appwrite\Auth\Auth;
use Appwrite\ClamAV\Network;
use Appwrite\Event\Delete;
use Appwrite\Event\Event;
use Appwrite\Event\Usage;
use Appwrite\Extend\Exception;
use Appwrite\OpenSSL\OpenSSL;
use Appwrite\SDK\AuthType;
@@ -935,15 +934,11 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
->param('rotation', 0, new Range(-360, 360), 'Preview image rotation in degrees. Pass an integer between -360 and 360.', true)
->param('background', '', new HexColor(), 'Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.', true)
->param('output', '', new WhiteList(\array_keys(Config::getParam('storage-outputs')), true), 'Output format type (jpeg, jpg, png, gif and webp).', true)
->inject('request')
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('mode')
->inject('deviceForFiles')
->inject('deviceForLocal')
->inject('queueForUsage')
->action(function (string $bucketId, string $fileId, int $width, int $height, string $gravity, int $quality, int $borderWidth, string $borderColor, int $borderRadius, float $opacity, int $rotation, string $background, string $output, Request $request, Response $response, Document $project, Database $dbForProject, string $mode, Device $deviceForFiles, Device $deviceForLocal, Usage $queueForUsage) {
->action(function (string $bucketId, string $fileId, int $width, int $height, string $gravity, int $quality, int $borderWidth, string $borderColor, int $borderRadius, float $opacity, int $rotation, string $background, string $output, Response $response, Database $dbForProject, Device $deviceForFiles, Device $deviceForLocal) {
if (!\extension_loaded('imagick')) {
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Imagick extension is missing');
@@ -1071,22 +1066,19 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
$contentType = (\array_key_exists($output, $outputs)) ? $outputs[$output] : $outputs['jpg'];
$queueForUsage
->addMetric(METRIC_FILES_TRANSFORMATIONS, 1)
->addMetric(str_replace('{bucketInternalId}', $bucket->getInternalId(), METRIC_BUCKET_ID_FILES_TRANSFORMATIONS), 1)
;
$transformedAt = $file->getAttribute('transformedAt', '');
if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $transformedAt) {
$file->setAttribute('transformedAt', DateTime::now());
Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $file->getAttribute('bucketInternalId'), $file->getId(), $file));
//Do not update transformedAt if it's a console user
if (!Auth::isPrivilegedUser(Authorization::getRoles())) {
$transformedAt = $file->getAttribute('transformedAt', '');
if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $transformedAt) {
$file->setAttribute('transformedAt', DateTime::now());
Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $file->getAttribute('bucketInternalId'), $file->getId(), $file));
}
}
$response
->addHeader('Cache-Control', 'private, max-age=2592000') // 30 days
->setContentType($contentType)
->file($data)
;
->file($data);
unset($image);
});
@@ -1879,9 +1871,12 @@ App::get('/v1/storage/:bucketId/usage')
->param('bucketId', '', new UID(), 'Bucket ID.')
->param('range', '30d', new WhiteList(['24h', '30d', '90d'], true), 'Date range.', true)
->inject('response')
->inject('project')
->inject('dbForProject')
->action(function (string $bucketId, string $range, Response $response, Database $dbForProject) {
->inject('getLogsDB')
->action(function (string $bucketId, string $range, Response $response, Document $project, Database $dbForProject, callable $getLogsDB) {
$dbForLogs = call_user_func($getLogsDB, $project);
$bucket = $dbForProject->getDocument('buckets', $bucketId);
if ($bucket->isEmpty()) {
@@ -1894,12 +1889,16 @@ App::get('/v1/storage/:bucketId/usage')
$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),
];
Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats, &$total) {
Authorization::skip(function () use ($dbForProject, $dbForLogs, $bucket, $days, $metrics, &$stats) {
foreach ($metrics as $metric) {
$result = $dbForProject->findOne('stats', [
$db = ($metric === str_replace('{bucketInternalId}', $bucket->getInternalId(), METRIC_BUCKET_ID_FILES_IMAGES_TRANSFORMED))
? $dbForLogs
: $dbForProject;
$result = $db->findOne('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', ['inf'])
]);
@@ -1907,7 +1906,7 @@ App::get('/v1/storage/:bucketId/usage')
$stats[$metric]['total'] = $result['value'] ?? 0;
$limit = $days['limit'];
$period = $days['period'];
$results = $dbForProject->find('stats', [
$results = $db->find('stats', [
Query::equal('metric', [$metric]),
Query::equal('period', [$period]),
Query::limit($limit),
@@ -1948,5 +1947,7 @@ App::get('/v1/storage/:bucketId/usage')
'filesStorageTotal' => $usage[$metrics[1]]['total'],
'files' => $usage[$metrics[0]]['data'],
'storage' => $usage[$metrics[1]]['data'],
'imageTransformations' => $usage[$metrics[2]]['data'],
'imageTransformationsTotal' => $usage[$metrics[2]]['total'],
]), Response::MODEL_USAGE_BUCKETS);
});
+20 -17
View File
@@ -8,7 +8,7 @@ use Appwrite\Event\Delete;
use Appwrite\Event\Event;
use Appwrite\Event\Mail;
use Appwrite\Event\Messaging;
use Appwrite\Event\Usage;
use Appwrite\Event\StatsUsage;
use Appwrite\Extend\Exception;
use Appwrite\Network\Validator\Email;
use Appwrite\Platform\Workers\Deletes;
@@ -466,9 +466,9 @@ App::post('/v1/teams/:teamId/memberships')
->inject('queueForMessaging')
->inject('queueForEvents')
->inject('timelimit')
->inject('queueForUsage')
->inject('queueForStatsUsage')
->inject('plan')
->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $queueForMails, Messaging $queueForMessaging, Event $queueForEvents, callable $timelimit, Usage $queueForUsage, array $plan) {
->action(function (string $teamId, string $email, string $userId, string $phone, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $queueForMails, Messaging $queueForMessaging, Event $queueForEvents, callable $timelimit, StatsUsage $queueForStatsUsage, array $plan) {
$isAppUser = Auth::isAppUser(Authorization::getRoles());
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
@@ -488,7 +488,7 @@ App::post('/v1/teams/:teamId/memberships')
}
$email = \strtolower($email);
$name = (empty($name)) ? $email : $name;
$name = empty($name) ? $email : $name;
$team = $dbForProject->getDocument('teams', $teamId);
if ($team->isEmpty()) {
@@ -507,7 +507,7 @@ App::post('/v1/teams/:teamId/memberships')
}
$email = $invitee->getAttribute('email', '');
$phone = $invitee->getAttribute('phone', '');
$name = empty($name) ? $invitee->getAttribute('name', '') : $name;
$name = $invitee->getAttribute('name', '') ?: $name;
} elseif (!empty($email)) {
$invitee = $dbForProject->findOne('users', [Query::equal('email', [$email])]); // Get user by email address
if (!$invitee->isEmpty() && !empty($phone) && $invitee->getAttribute('phone', '') !== $phone) {
@@ -588,9 +588,8 @@ App::post('/v1/teams/:teamId/memberships')
Query::equal('teamInternalId', [$team->getInternalId()]),
]);
$secret = Auth::tokenGenerator();
if ($membership->isEmpty()) {
$secret = Auth::tokenGenerator();
$membershipId = ID::unique();
$membership = new Document([
'$id' => $membershipId,
@@ -618,7 +617,8 @@ App::post('/v1/teams/:teamId/memberships')
$dbForProject->createDocument('memberships', $membership);
Authorization::skip(fn () => $dbForProject->increaseDocumentAttribute('teams', $team->getId(), 'total', 1));
} else {
} elseif ($membership->getAttribute('confirm') === false) {
$membership->setAttribute('secret', Auth::hash($secret));
$membership->setAttribute('invited', DateTime::now());
if ($isPrivilegedUser || $isAppUser) {
@@ -629,9 +629,10 @@ App::post('/v1/teams/:teamId/memberships')
$membership = ($isPrivilegedUser || $isAppUser) ?
Authorization::skip(fn () => $dbForProject->updateDocument('memberships', $membership->getId(), $membership)) :
$dbForProject->updateDocument('memberships', $membership->getId(), $membership);
} else {
throw new Exception(Exception::MEMBERSHIP_ALREADY_CONFIRMED);
}
if ($isPrivilegedUser || $isAppUser) {
$dbForProject->purgeCachedDocument('users', $invitee->getId());
} else {
@@ -714,7 +715,7 @@ App::post('/v1/teams/:teamId/memberships')
->setSubject($subject)
->setBody($body)
->setRecipient($invitee->getAttribute('email'))
->setName($invitee->getAttribute('name'))
->setName($invitee->getAttribute('name', ''))
->setVariables($emailVariables)
->trigger();
@@ -757,11 +758,11 @@ App::post('/v1/teams/:teamId/memberships')
$countryCode = $helper->parse($phone)->getCountryCode();
if (!empty($countryCode)) {
$queueForUsage
$queueForStatsUsage
->addMetric(str_replace('{countryCode}', $countryCode, METRIC_AUTH_METHOD_PHONE_COUNTRY_CODE), 1);
}
}
$queueForUsage
$queueForStatsUsage
->addMetric(METRIC_AUTH_METHOD_PHONE, 1)
->setProject($project)
->trigger();
@@ -1361,13 +1362,15 @@ App::get('/v1/teams/:teamId/logs')
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
}
$grouped = Query::groupByType($queries);
$limit = $grouped['limit'] ?? APP_LIMIT_COUNT;
$offset = $grouped['offset'] ?? 0;
// Temp fix for logs
$queries[] = Query::or([
Query::greaterThan('$createdAt', DateTime::format(new \DateTime('2025-02-26T01:30+00:00'))),
Query::lessThan('$createdAt', DateTime::format(new \DateTime('2025-02-13T00:00+00:00'))),
]);
$audit = new Audit($dbForProject);
$resource = 'team/' . $team->getId();
$logs = $audit->getLogsByResource($resource, $limit, $offset);
$logs = $audit->getLogsByResource($resource, $queries);
$output = [];
@@ -1414,7 +1417,7 @@ App::get('/v1/teams/:teamId/logs')
}
}
$response->dynamic(new Document([
'total' => $audit->countLogsByResource($resource),
'total' => $audit->countLogsByResource($resource, $queries),
'logs' => $output,
]), Response::MODEL_LOG_LIST);
});
+7 -5
View File
@@ -862,13 +862,15 @@ App::get('/v1/users/:userId/logs')
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
}
$grouped = Query::groupByType($queries);
$limit = $grouped['limit'] ?? APP_LIMIT_COUNT;
$offset = $grouped['offset'] ?? 0;
// Temp fix for logs
$queries[] = Query::or([
Query::greaterThan('$createdAt', DateTime::format(new \DateTime('2025-02-26T01:30+00:00'))),
Query::lessThan('$createdAt', DateTime::format(new \DateTime('2025-02-13T00:00+00:00'))),
]);
$audit = new Audit($dbForProject);
$logs = $audit->getLogsByUser($user->getInternalId(), $limit, $offset);
$logs = $audit->getLogsByUser($user->getInternalId(), $queries);
$output = [];
@@ -915,7 +917,7 @@ App::get('/v1/users/:userId/logs')
}
$response->dynamic(new Document([
'total' => $audit->countLogsByUser($user->getInternalId()),
'total' => $audit->countLogsByUser($user->getInternalId(), $queries),
'logs' => $output,
]), Response::MODEL_LOG_LIST);
});
+300 -83
View File
@@ -14,11 +14,11 @@ use Appwrite\Utopia\Request;
use Appwrite\Utopia\Response;
use Appwrite\Vcs\Comment;
use Utopia\App;
use Utopia\CLI\Console;
use Utopia\Config\Config;
use Utopia\Database\Database;
use Utopia\Database\DateTime;
use Utopia\Database\Document;
use Utopia\Database\Exception\Duplicate;
use Utopia\Database\Exception\Query as QueryException;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Helpers\Permission;
@@ -26,22 +26,35 @@ use Utopia\Database\Helpers\Role;
use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\Query\Cursor;
use Utopia\Detector\Adapter\Bun;
use Utopia\Detector\Adapter\CPP;
use Utopia\Detector\Adapter\Dart;
use Utopia\Detector\Adapter\Deno;
use Utopia\Detector\Adapter\Dotnet;
use Utopia\Detector\Adapter\Java;
use Utopia\Detector\Adapter\JavaScript;
use Utopia\Detector\Adapter\PHP;
use Utopia\Detector\Adapter\Python;
use Utopia\Detector\Adapter\Ruby;
use Utopia\Detector\Adapter\Swift;
use Utopia\Detector\Detector;
use Utopia\Detector\Detection\Framework\Astro;
use Utopia\Detector\Detection\Framework\Flutter;
use Utopia\Detector\Detection\Framework\NextJs;
use Utopia\Detector\Detection\Framework\Nuxt;
use Utopia\Detector\Detection\Framework\Remix;
use Utopia\Detector\Detection\Framework\SvelteKit;
use Utopia\Detector\Detection\Packager\NPM;
use Utopia\Detector\Detection\Packager\PNPM;
use Utopia\Detector\Detection\Packager\Yarn;
use Utopia\Detector\Detection\Runtime\Bun;
use Utopia\Detector\Detection\Runtime\CPP;
use Utopia\Detector\Detection\Runtime\Dart;
use Utopia\Detector\Detection\Runtime\Deno;
use Utopia\Detector\Detection\Runtime\Dotnet;
use Utopia\Detector\Detection\Runtime\Java;
use Utopia\Detector\Detection\Runtime\Node;
use Utopia\Detector\Detection\Runtime\PHP;
use Utopia\Detector\Detection\Runtime\Python;
use Utopia\Detector\Detection\Runtime\Ruby;
use Utopia\Detector\Detection\Runtime\Swift;
use Utopia\Detector\Detector\Framework;
use Utopia\Detector\Detector\Packager;
use Utopia\Detector\Detector\Runtime;
use Utopia\Detector\Detector\Strategy;
use Utopia\System\System;
use Utopia\Validator\Boolean;
use Utopia\Validator\Host;
use Utopia\Validator\Text;
use Utopia\Validator\WhiteList;
use Utopia\VCS\Adapter\Git\GitHub;
use Utopia\VCS\Exception\RepositoryNotFound;
@@ -195,6 +208,17 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
$providerRepositoryOwner = $pullRequestResponse['head']['repo']['name'];
}
$commands = [];
if (!empty($resource->getAttribute('installCommand', ''))) {
$commands[] = $resource->getAttribute('installCommand', '');
}
if (!empty($resource->getAttribute('buildCommand', ''))) {
$commands[] = $resource->getAttribute('buildCommand', '');
}
if (!empty($resource->getAttribute('commands', ''))) {
$commands[] = $resource->getAttribute('commands', '');
}
$deployment = $dbForProject->createDocument('deployments', new Document([
'$id' => $deploymentId,
'$permissions' => [
@@ -206,10 +230,8 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
'resourceInternalId' => $resourceInternalId,
'resourceType' => $resourceCollection,
'entrypoint' => $resource->getAttribute('entrypoint', ''),
'commands' => $resource->getAttribute('commands', ''),
'installCommand' => $resource->getAttribute('installCommand', ''),
'buildCommand' => $resource->getAttribute('buildCommand', ''),
'outputDirectory' => $resource->getAttribute('outputDirectory', ''),
'buildCommands' => \implode(' && ', $commands),
'buildOutput' => $resource->getAttribute('outputDirectory', ''),
'type' => 'vcs',
'installationId' => $installationId,
'installationInternalId' => $installationInternalId,
@@ -223,7 +245,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
'providerCommitHash' => $providerCommitHash,
'providerCommitAuthorUrl' => $providerCommitAuthorUrl,
'providerCommitAuthor' => $providerCommitAuthor,
'providerCommitMessage' => $providerCommitMessage,
'providerCommitMessage' => mb_strimwidth($providerCommitMessage, 0, 255, '...'),
'providerCommitUrl' => $providerCommitUrl,
'providerCommentId' => \strval($latestCommentId),
'providerBranch' => $providerBranch,
@@ -231,27 +253,90 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
'activate' => $activate,
]));
// Preview deployments for sites
if ($resource->getCollection() === 'sites') {
$projectId = $project->getId();
// Deployment preview
$sitesDomain = System::getEnv('_APP_DOMAIN_SITES', '');
$domain = "{$deploymentId}-{$projectId}.{$sitesDomain}";
$domain = ID::unique() . "." . $sitesDomain;
$ruleId = md5($domain);
$rule = Authorization::skip(
Authorization::skip(
fn () => $dbForPlatform->createDocument('rules', new Document([
'$id' => $ruleId,
'projectId' => $project->getId(),
'projectInternalId' => $project->getInternalId(),
'domain' => $domain,
'resourceType' => 'deployment',
'resourceId' => $deploymentId,
'resourceInternalId' => $deployment->getInternalId(),
'type' => 'deployment',
'trigger' => 'deployment',
'deploymentId' => $deployment->getId(),
'deploymentInternalId' => $deployment->getInternalId(),
'deploymentResourceType' => 'site',
'deploymentResourceId' => $resourceId,
'deploymentResourceInternalId' => $resourceInternalId,
'deploymentVcsProviderBranch' => $providerBranch,
'status' => 'verified',
'certificateId' => '',
'search' => implode(' ', [$ruleId, $domain]),
]))
);
// VCS branch preview
if (!empty($providerBranch)) {
$domain = "branch-{$providerBranch}-{$resource->getId()}-{$project->getId()}.{$sitesDomain}";
$ruleId = md5($domain);
try {
Authorization::skip(
fn () => $dbForPlatform->createDocument('rules', new Document([
'$id' => $ruleId,
'projectId' => $project->getId(),
'projectInternalId' => $project->getInternalId(),
'domain' => $domain,
'type' => 'deployment',
'trigger' => 'deployment',
'deploymentId' => $deployment->getId(),
'deploymentInternalId' => $deployment->getInternalId(),
'deploymentResourceType' => 'site',
'deploymentResourceId' => $resourceId,
'deploymentResourceInternalId' => $resourceInternalId,
'deploymentVcsProviderBranch' => $providerBranch,
'status' => 'verified',
'certificateId' => '',
'search' => implode(' ', [$ruleId, $domain]),
]))
);
} catch (Duplicate $err) {
// Ignore, rule already exists; will be updated by builds worker
}
}
// VCS commit preview
if (!empty($providerCommitHash)) {
$domain = "commit-{$providerCommitHash}-{$resource->getId()}-{$project->getId()}.{$sitesDomain}";
$ruleId = md5($domain);
try {
Authorization::skip(
fn () => $dbForPlatform->createDocument('rules', new Document([
'$id' => $ruleId,
'projectId' => $project->getId(),
'projectInternalId' => $project->getInternalId(),
'domain' => $domain,
'type' => 'deployment',
'trigger' => 'deployment',
'deploymentId' => $deployment->getId(),
'deploymentInternalId' => $deployment->getInternalId(),
'deploymentResourceType' => 'site',
'deploymentResourceId' => $resourceId,
'deploymentResourceInternalId' => $resourceInternalId,
'deploymentVcsProviderBranch' => $providerBranch,
'status' => 'verified',
'certificateId' => '',
'search' => implode(' ', [$ruleId, $domain]),
]))
);
} catch (Duplicate $err) {
// Ignore, rule already exists; will be updated by builds worker
}
}
}
if (!empty($providerCommitHash) && $resource->getAttribute('providerSilentMode', false) === false) {
@@ -544,8 +629,9 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories/:pro
]), Response::MODEL_VCS_CONTENT_LIST);
});
App::post('/v1/vcs/github/installations/:installationId/providerRepositories/:providerRepositoryId/detection')
->desc('Detect runtime settings from source code')
App::post('/v1/vcs/github/installations/:installationId/detections')
->alias('/v1/vcs/github/installations/:installationId/providerRepositories/:providerRepositoryId/detection')
->desc('Create repository detection')
->groups(['api', 'vcs'])
->label('scope', 'vcs.write')
->label('sdk', new Method(
@@ -556,18 +642,22 @@ App::post('/v1/vcs/github/installations/:installationId/providerRepositories/:pr
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_DETECTION,
model: Response::MODEL_DETECTION_RUNTIME,
),
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_DETECTION_FRAMEWORK,
)
]
))
->param('installationId', '', new Text(256), 'Installation Id')
->param('providerRepositoryId', '', new Text(256), 'Repository Id')
->param('type', '', new WhiteList(['runtime', 'framework']), 'Detector type. Must be one of the following: runtime, framework')
->param('providerRootDirectory', '', new Text(256, 0), 'Path to Root Directory', 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 $type, string $providerRootDirectory, GitHub $github, Response $response, Database $dbForPlatform) {
$installation = $dbForPlatform->getDocument('installations', $installationId);
if ($installation->isEmpty()) {
@@ -593,32 +683,108 @@ App::post('/v1/vcs/github/installations/:installationId/providerRepositories/:pr
$files = \array_column($files, 'name');
$languages = $github->listRepositoryLanguages($owner, $repositoryName);
$detectorFactory = new Detector($files, $languages);
$detector = new Packager($files);
$detector
->addOption(new Yarn())
->addOption(new PNPM())
->addOption(new NPM());
$detection = $detector->detect();
$detectorFactory
->addDetector(new JavaScript())
->addDetector(new Bun())
->addDetector(new PHP())
->addDetector(new Python())
->addDetector(new Dart())
->addDetector(new Swift())
->addDetector(new Ruby())
->addDetector(new Java())
->addDetector(new CPP())
->addDetector(new Deno())
->addDetector(new Dotnet());
$packager = !\is_null($detection) ? $detection->getName() : 'npm';
$runtime = $detectorFactory->detect();
if ($type === 'framework') {
$output = new Document([
'framework' => '',
'installCommand' => '',
'buildCommand' => '',
'outputDirectory' => '',
]);
$runtimes = Config::getParam('runtimes');
$runtimeDetail = \array_reverse(\array_filter(\array_keys($runtimes), function ($key) use ($runtime, $runtimes) {
return $runtimes[$key]['key'] === $runtime;
}))[0] ?? '';
$detector = new Framework($files, $packager);
$detector
->addOption(new Flutter())
->addOption(new Nuxt())
->addOption(new Astro())
->addOption(new SvelteKit())
->addOption(new NextJs())
->addOption(new Remix());
$detection = [];
$detection['runtime'] = $runtimeDetail;
$framework = $detector->detect();
$response->dynamic(new Document($detection), Response::MODEL_DETECTION);
if (!\is_null($framework)) {
$output->setAttribute('installCommand', $framework->getInstallCommand());
$output->setAttribute('buildCommand', $framework->getBuildCommand());
$output->setAttribute('outputDirectory', $framework->getOutputDirectory());
$framework = $framework->getName();
} else {
$framework = 'other';
$output->setAttribute('installCommand', '');
$output->setAttribute('buildCommand', '');
$output->setAttribute('outputDirectory', '');
}
$frameworks = Config::getParam('frameworks');
if (!\in_array($framework, array_keys($frameworks), true)) {
$framework = 'other';
}
$output->setAttribute('framework', $framework);
} else {
$output = new Document([
'runtime' => '',
'commands' => '',
'entrypoint' => '',
]);
$strategies = [
new Strategy(Strategy::FILEMATCH),
new Strategy(Strategy::LANGUAGES),
new Strategy(Strategy::EXTENSION),
];
foreach ($strategies as $strategy) {
$detector = new Runtime($strategy === Strategy::LANGUAGES ? $languages : $files, $strategy, $packager);
$detector
->addOption(new Node())
->addOption(new Bun())
->addOption(new Deno())
->addOption(new PHP())
->addOption(new Python())
->addOption(new Dart())
->addOption(new Swift())
->addOption(new Ruby())
->addOption(new Java())
->addOption(new CPP())
->addOption(new Dotnet());
$runtime = $detector->detect();
if (!\is_null($runtime)) {
$output->setAttribute('commands', $runtime->getCommands());
$output->setAttribute('entrypoint', $runtime->getEntrypoint());
$runtime = $runtime->getName();
break;
}
}
if (!empty($runtime)) {
$runtimes = Config::getParam('runtimes');
$runtimeWithVersion = '';
foreach ($runtimes as $runtimeKey => $runtimeConfig) {
if ($runtimeConfig['key'] === $runtime) {
$runtimeWithVersion = $runtimeKey;
}
}
if (empty($runtimeWithVersion)) {
throw new Exception(Exception::FUNCTION_RUNTIME_NOT_DETECTED);
}
$output->setAttribute('runtime', $runtimeWithVersion);
} else {
throw new Exception(Exception::FUNCTION_RUNTIME_NOT_DETECTED);
}
}
$response->dynamic($output, $type === 'framework' ? Response::MODEL_DETECTION_FRAMEWORK : Response::MODEL_DETECTION_RUNTIME);
});
App::get('/v1/vcs/github/installations/:installationId/providerRepositories')
@@ -633,17 +799,21 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories')
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_PROVIDER_REPOSITORY_LIST,
model: Response::MODEL_PROVIDER_REPOSITORY_RUNTIME_LIST,
),
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_PROVIDER_REPOSITORY_FRAMEWORK_LIST,
)
]
))
->param('installationId', '', new Text(256), 'Installation Id')
->param('type', '', new WhiteList(['runtime', 'framework']), 'Detector type. Must be one of the following: runtime, framework')
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('gitHub')
->inject('response')
->inject('project')
->inject('dbForPlatform')
->action(function (string $installationId, string $search, GitHub $github, Response $response, Document $project, Database $dbForPlatform) {
->action(function (string $installationId, string $type, string $search, GitHub $github, Response $response, Database $dbForPlatform) {
if (empty($search)) {
$search = "";
}
@@ -673,39 +843,86 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories')
return $repo;
}, $repos);
$repos = batch(\array_map(function ($repo) use ($github) {
return function () use ($repo, $github) {
try {
$files = $github->listRepositoryContents($repo['organization'], $repo['name'], '');
$files = \array_column($files, 'name');
$repos = batch(\array_map(function ($repo) use ($type, $github) {
return function () use ($repo, $type, $github) {
$files = $github->listRepositoryContents($repo['organization'], $repo['name'], '');
$files = \array_column($files, 'name');
$detector = new Packager($files);
$detector
->addOption(new Yarn())
->addOption(new PNPM())
->addOption(new NPM());
$detection = $detector->detect();
$packager = !\is_null($detection) ? $detection->getName() : 'npm';
if ($type === 'framework') {
$frameworkDetector = new Framework($files, $packager);
$frameworkDetector
->addOption(new Flutter())
->addOption(new Nuxt())
->addOption(new Astro())
->addOption(new SvelteKit())
->addOption(new NextJs())
->addOption(new Remix());
$detectedFramework = $frameworkDetector->detect();
if (!\is_null($detectedFramework)) {
$framework = $detectedFramework->getName();
} else {
$framework = 'other';
}
$frameworks = Config::getParam('frameworks');
if (!\in_array($framework, array_keys($frameworks), true)) {
$framework = 'other';
}
$repo['framework'] = $framework;
} else {
$languages = $github->listRepositoryLanguages($repo['organization'], $repo['name']);
$detectorFactory = new Detector($files, $languages);
$strategies = [
new Strategy(Strategy::FILEMATCH),
new Strategy(Strategy::LANGUAGES),
new Strategy(Strategy::EXTENSION),
];
$detectorFactory
->addDetector(new JavaScript())
->addDetector(new Bun())
->addDetector(new PHP())
->addDetector(new Python())
->addDetector(new Dart())
->addDetector(new Swift())
->addDetector(new Ruby())
->addDetector(new Java())
->addDetector(new CPP())
->addDetector(new Deno())
->addDetector(new Dotnet());
foreach ($strategies as $strategy) {
$detector = new Runtime($strategy === Strategy::LANGUAGES ? $languages : $files, $strategy, $packager);
$detector
->addOption(new Node())
->addOption(new Bun())
->addOption(new Deno())
->addOption(new PHP())
->addOption(new Python())
->addOption(new Dart())
->addOption(new Swift())
->addOption(new Ruby())
->addOption(new Java())
->addOption(new CPP())
->addOption(new Dotnet());
$runtime = $detectorFactory->detect();
$runtime = $detector->detect();
$runtimes = Config::getParam('runtimes');
$runtimeDetail = \array_reverse(\array_filter(\array_keys($runtimes), function ($key) use ($runtime, $runtimes) {
return $runtimes[$key]['key'] === $runtime;
}))[0] ?? '';
if (!\is_null($runtime)) {
$runtime = $runtime->getName();
break;
}
}
$repo['runtime'] = $runtimeDetail;
} catch (Throwable $error) {
$repo['runtime'] = "";
Console::warning("Runtime not detected for " . $repo['organization'] . "/" . $repo['name']);
if (!empty($runtime)) {
$runtimes = Config::getParam('runtimes');
$runtimeWithVersion = '';
foreach ($runtimes as $runtimeKey => $runtimeConfig) {
if ($runtimeConfig['key'] === $runtime) {
$runtimeWithVersion = $runtimeKey;
}
}
$repo['runtime'] = $runtimeWithVersion ?? '';
}
}
return $repo;
};
@@ -716,9 +933,9 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories')
}, $repos);
$response->dynamic(new Document([
'providerRepositories' => $repos,
$type === 'framework' ? 'frameworkProviderRepositories' : 'runtimeProviderRepositories' => $repos,
'total' => \count($repos),
]), Response::MODEL_PROVIDER_REPOSITORY_LIST);
]), ($type === 'framework') ? Response::MODEL_PROVIDER_REPOSITORY_FRAMEWORK_LIST : Response::MODEL_PROVIDER_REPOSITORY_RUNTIME_LIST);
});
App::post('/v1/vcs/github/installations/:installationId/providerRepositories')
+291 -162
View File
@@ -3,26 +3,30 @@
require_once __DIR__ . '/../init.php';
use Ahc\Jwt\JWT;
use Ahc\Jwt\JWTException;
use Appwrite\Auth\Auth;
use Appwrite\Auth\Key;
use Appwrite\Event\Certificate;
use Appwrite\Event\Event;
use Appwrite\Event\Func;
use Appwrite\Event\Usage;
use Appwrite\Event\StatsUsage;
use Appwrite\Extend\Exception as AppwriteException;
use Appwrite\Network\Validator\Origin;
use Appwrite\Platform\Appwrite;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Transformation\Adapter\Preview;
use Appwrite\Transformation\Transformation;
use Appwrite\Utopia\Request;
use Appwrite\Utopia\Request\Filters\V16 as RequestV16;
use Appwrite\Utopia\Request\Filters\V17 as RequestV17;
use Appwrite\Utopia\Request\Filters\V18 as RequestV18;
use Appwrite\Utopia\Request\Filters\V19 as RequestV19;
use Appwrite\Utopia\Response;
use Appwrite\Utopia\Response\Filters\V16 as ResponseV16;
use Appwrite\Utopia\Response\Filters\V17 as ResponseV17;
use Appwrite\Utopia\Response\Filters\V18 as ResponseV18;
use Appwrite\Utopia\Response\Filters\V19 as ResponseV19;
use Appwrite\Utopia\View;
use Executor\Executor;
use MaxMind\Db\Reader;
@@ -52,7 +56,7 @@ Config::setParam('domainVerification', false);
Config::setParam('cookieDomain', 'localhost');
Config::setParam('cookieSamesite', Response::COOKIE_SAMESITE_NONE);
function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, SwooleRequest $swooleRequest, Request $request, Response $response, Event $queueForEvents, Usage $queueForUsage, Func $queueForFunctions, Reader $geodb, callable $isResourceBlocked, string $previewHostname)
function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, SwooleRequest $swooleRequest, Request $request, Response $response, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey)
{
$utopia->getRoute()?->label('error', __DIR__ . '/../views/general/error.phtml');
@@ -120,43 +124,11 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
return false;
}
$type = $rule->getAttribute('resourceType');
if ($type === 'function' || $type === 'site' || $type === 'deployment') {
$resourceCollection = match($type) {
'function' => 'functions',
'site' => 'sites',
'deployment' => 'deployments',
};
}
if ($type === 'function' || $type === 'site' || $type === 'deployment') {
$method = $utopia->getRoute()?->getLabel('sdk', null);
if (empty($method)) {
$utopia->getRoute()?->label('sdk', new Method(
namespace: 'functions',
name: 'createExecution',
description: '/docs/references/functions/create-execution.md',
auth: [AuthType::SESSION, AuthType::KEY, AuthType::JWT],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_CREATED,
model: Response::MODEL_EXECUTION,
)
],
contentType: ContentType::MULTIPART,
requestType: 'application/json',
));
} else {
/** @var Method $method */
$method->setNamespace('functions');
$method->setMethodName('createExecution');
$utopia->getRoute()?->label('sdk', $method);
}
$type = $rule->getAttribute('type', '');
if ($type === 'deployment') {
if (System::getEnv('_APP_OPTIONS_COMPUTE_FORCE_HTTPS', 'disabled') === 'enabled') { // Force HTTPS
if ($request->getProtocol() !== 'https') {
if ($request->getProtocol() !== 'https' && $request->getHostname() !== APP_HOSTNAME_INTERNAL) {
if ($request->getMethod() !== Request::METHOD_GET) {
throw new AppwriteException(AppwriteException::GENERAL_PROTOCOL_UNSUPPORTED, 'Method unsupported over HTTP. Please use HTTPS instead.');
}
@@ -164,8 +136,22 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
}
}
$resourceId = $rule->getAttribute('resourceId');
$projectId = $rule->getAttribute('projectId');
/** @var Database $dbForProject */
$dbForProject = $getProjectDB($project);
$deployment = Authorization::skip(fn () => $dbForProject->getDocument('deployments', $rule->getAttribute('deploymentId')));
if ($deployment->getAttribute('resourceType', '') === 'functions') {
$type = 'function';
} elseif ($deployment->getAttribute('resourceType', '') === 'sites') {
$type = 'site';
}
$resource = $type === 'function' ?
Authorization::skip(fn () => $dbForProject->getDocument('functions', $deployment->getAttribute('resourceId', ''))) :
Authorization::skip(fn () => $dbForProject->getDocument('sites', $deployment->getAttribute('resourceId', '')));
$isPreview = $type === 'function' ? false : ($rule->getAttribute('trigger', '') !== 'manual');
$path = ($swooleRequest->server['request_uri'] ?? '/');
$query = ($swooleRequest->server['query_string'] ?? '');
@@ -173,47 +159,108 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
$path .= '?' . $query;
}
$protocol = $request->getProtocol();
/**
Ensure preview authorization
- Authorization is skippable for tests, and build screenshot
- If cookie is not sent by client -> not authorized
- If JWT in cookie is invalid or expired -> not authorized
- If user is blocked or removed -> not authorized
- If user's session is removed or expired -> not authorized
- If user is not member of team of this deployment -> not authorized
- If not authorized, redirect to Console redirect UI
- If authorized, continue as if auth was not required
*/
$requirePreview = \is_null($apiKey) || !$apiKey->isPreviewAuthDisabled();
if ($isPreview && $requirePreview) {
$cookie = $request->getCookie(Auth::$cookieNamePreview, '');
$authorized = false;
// Security checks to mark authorized true
if (!empty($cookie)) {
$jwt = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 3600, 0);
$payload = [];
try {
$payload = $jwt->decode($cookie);
} catch (JWTException $error) {
// Authorized remains false
}
$userExists = false;
$userId = $payload['userId'] ?? '';
if (!empty($userId)) {
$user = Authorization::skip(fn () => $dbForPlatform->getDocument('users', $userId));
if (!$user->isEmpty() && $user->getAttribute('status', false)) {
$userExists = true;
}
}
$sessionExists = false;
$jwtSessionId = $payload['sessionId'] ?? '';
if (!empty($jwtSessionId) && !empty($user->find('$id', $jwtSessionId, 'sessions'))) {
$sessionExists = true;
}
$membershipExists = false;
$project = Authorization::skip(fn () => $dbForPlatform->getDocument('projects', $projectId));
if (!$project->isEmpty() && isset($user)) {
$teamId = $project->getAttribute('teamId', '');
$membership = $user->find('teamId', $teamId, 'memberships');
if (!empty($membership)) {
$membershipExists = true;
}
}
if ($userExists && $sessionExists && $membershipExists) {
$authorized = true;
}
}
if (!$authorized) {
$url = (System::getEnv('_APP_OPTIONS_FORCE_HTTPS') == 'disabled' ? 'http' : 'https') . "://" . System::getEnv('_APP_DOMAIN');
$response
->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
->addHeader('Pragma', 'no-cache')
->redirect($url . '/console/auth/preview?'
. \http_build_query([
'projectId' => $projectId,
'origin' => $protocol . '://' . $host,
'path' => $path
]));
return true;
}
}
$body = $swooleRequest->getContent() ?? '';
$method = $swooleRequest->server['request_method'];
$requestHeaders = $request->getHeaders();
$project = Authorization::skip(fn () => $dbForPlatform->getDocument('projects', $projectId));
/** @var Database $dbForProject */
$dbForProject = $getProjectDB($project);
if ($resourceCollection === 'deployments') {
$subResource = Authorization::skip(fn () => $dbForProject->getDocument($resourceCollection, $resourceId));
$resource = Authorization::skip(fn () => $dbForProject->getDocument($subResource->getAttribute('resourceType'), $subResource->getAttribute('resourceId')));
} else {
$resource = Authorization::skip(fn () => $dbForProject->getDocument($resourceCollection, $resourceId));
}
if ($resource->isEmpty() || !$resource->getAttribute('enabled')) {
throw new AppwriteException(AppwriteException::FUNCTION_NOT_FOUND);
}
if ($isResourceBlocked($project, RESOURCE_TYPE_FUNCTIONS, $resourceId)) {
if ($isResourceBlocked($project, $type === 'function' ? RESOURCE_TYPE_FUNCTIONS : RESOURCE_TYPE_SITES, $resource->getId())) {
throw new AppwriteException(AppwriteException::GENERAL_RESOURCE_BLOCKED);
}
$version = match($type) {
$version = match ($type) {
'function' => $resource->getAttribute('version', 'v2'),
'site' => 'v4',
'deployment' => 'v4'
'site' => 'v5',
};
$runtimes = Config::getParam($version === 'v2' ? 'runtimes-v2' : 'runtimes', []);
$spec = Config::getParam('runtime-specifications')[$resource->getAttribute('specification', APP_COMPUTE_SPECIFICATION_DEFAULT)];
$spec = Config::getParam('specifications')[$resource->getAttribute('specification', APP_COMPUTE_SPECIFICATION_DEFAULT)];
$runtime = match($type) {
$runtime = match ($type) {
'function' => $runtimes[$resource->getAttribute('runtime')] ?? null,
'site' => $runtimes[$resource->getAttribute('buildRuntime')] ?? null,
'deployment' => $runtimes[$resource->getAttribute('buildRuntime')] ?? null,
default => null
};
// Static site enforced runtime
if ($resource->getAttribute('adapter', '') === 'static') {
$runtime = $runtimes['static-1'] ?? null;
}
@@ -222,36 +269,12 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
throw new AppwriteException(AppwriteException::FUNCTION_RUNTIME_UNSUPPORTED, 'Runtime "' . $resource->getAttribute('runtime', '') . '" is not supported');
}
$deploymentId = match($type) {
'function' => $resource->getAttribute('deployment', ''),
'site' => $resource->getAttribute('deploymentId', ''),
'deployment' => $subResource->getId()
};
$deployment = Authorization::skip(fn () => $dbForProject->getDocument('deployments', $deploymentId));
if ($deployment->getAttribute('resourceId') !== $resource->getId()) {
throw new AppwriteException(AppwriteException::DEPLOYMENT_NOT_FOUND, 'Deployment not found. Create a deployment before trying to execute a function');
}
if ($deployment->isEmpty()) {
throw new AppwriteException(AppwriteException::DEPLOYMENT_NOT_FOUND, 'Deployment not found. Create a deployment before trying to execute a function');
}
/** Check if build has completed */
$build = Authorization::skip(fn () => $dbForProject->getDocument('builds', $deployment->getAttribute('buildId', '')));
if ($build->isEmpty()) {
throw new AppwriteException(AppwriteException::BUILD_NOT_FOUND);
}
if ($build->getAttribute('status') !== 'ready') {
if ($deployment->getAttribute('status') !== 'ready') {
throw new AppwriteException(AppwriteException::BUILD_NOT_READY);
}
//todo: figure out for sites/functions
if ($type === 'function') {
$permissions = $resource->getAttribute('execute');
if (!(\in_array('any', $permissions)) && !(\in_array('guests', $permissions))) {
throw new AppwriteException(AppwriteException::USER_UNAUTHORIZED, 'To execute function using domain, execute permissions must include "any" or "guests"');
}
@@ -263,18 +286,15 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
$headers['x-appwrite-continent-code'] = '';
$headers['x-appwrite-continent-eu'] = 'false';
//todo: check if this would work for sites
if ($type === 'function') {
$jwtExpiry = $resource->getAttribute('timeout', 900);
$jwtObj = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', $jwtExpiry, 0);
$apiKey = $jwtObj->encode([
'projectId' => $project->getId(),
'scopes' => $resource->getAttribute('scopes', [])
]);
$headers['x-appwrite-key'] = API_KEY_DYNAMIC . '_' . $apiKey;
$headers['x-appwrite-trigger'] = 'http';
$headers['x-appwrite-user-jwt'] = '';
}
$jwtExpiry = $resource->getAttribute('timeout', 900);
$jwtObj = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', $jwtExpiry, 0);
$jwtKey = $jwtObj->encode([
'projectId' => $project->getId(),
'scopes' => $resource->getAttribute('scopes', [])
]);
$headers['x-appwrite-key'] = API_KEY_DYNAMIC . '_' . $jwtKey;
$headers['x-appwrite-trigger'] = 'http';
$headers['x-appwrite-user-jwt'] = '';
$ip = $headers['x-real-ip'] ?? '';
if (!empty($ip)) {
@@ -313,21 +333,25 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
'errors' => '',
'logs' => '',
'duration' => 0.0,
'search' => implode(' ', [$resourceId, $executionId]),
]);
if ($type === 'function') {
$execution->setAttribute('resourceType', 'functions');
$execution->setAttribute('trigger', 'http'); // http / schedule / event
$execution->setAttribute('status', 'processing'); // waiting / processing / completed / failed
$queueForEvents
->setParam('functionId', $resource->getId())
->setParam('executionId', $execution->getId())
->setContext('function', $resource);
} elseif ($type === 'site') {
$execution->setAttribute('resourceType', 'sites');
}
$queueForEvents
->setParam('functionId', $resource->getId())
->setParam('executionId', $execution->getId())
->setContext('function', $resource);
$queueForEvents
->setParam('siteId', $resource->getId())
->setParam('executionId', $execution->getId())
->setContext('site', $resource);
}
$durationStart = \microtime(true);
@@ -360,14 +384,14 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
// Appwrite vars
$vars = \array_merge($vars, [
'APPWRITE_FUNCTION_API_ENDPOINT' => $endpoint,
'APPWRITE_FUNCTION_ID' => $resourceId,
'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_COMPUTE_CPUS' => $spec['cpus'] ?? APP_COMPUTE_CPUS_DEFAULT,
'APPWRITE_COMPUTE_MEMORY' => $spec['memory'] ?? APP_COMPUTE_MEMORY_DEFAULT,
'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', ''),
@@ -385,18 +409,21 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
'APPWRITE_VCS_ROOT_DIRECTORY' => $deployment->getAttribute('providerRootDirectory', ''),
]);
// SPA fallbackFile override
if ($resource->getAttribute('adapter', '') === 'static' && $resource->getAttribute('fallbackFile', '') !== '') {
$vars['OPEN_RUNTIMES_STATIC_FALLBACK'] = $resource->getAttribute('fallbackFile', '');
}
/** Execute function */
$executor = new Executor(System::getEnv('_APP_EXECUTOR_HOST'));
try {
$version = match($type) {
$version = match ($type) {
'function' => $resource->getAttribute('version', 'v2'),
'site' => 'v4',
'deployment' => 'v4'
'site' => 'v5',
};
$entrypoint = match($type) {
$entrypoint = match ($type) {
'function' => $deployment->getAttribute('entrypoint', ''),
'site' => '',
'deployment' => ''
};
if ($type === 'function') {
@@ -404,7 +431,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
'v2' => '',
default => 'cp /tmp/code.tar.gz /mnt/code/code.tar.gz && nohup helpers/start.sh "' . $runtime['startCommand'] . '"'
};
} elseif ($type === 'site' || $type === 'deployment') {
} elseif ($type === 'site') {
$frameworks = Config::getParam('frameworks', []);
$framework = $frameworks[$resource->getAttribute('framework', '')] ?? null;
@@ -420,10 +447,9 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
$runtimeEntrypoint = 'cp /tmp/code.tar.gz /mnt/code/code.tar.gz && nohup helpers/start.sh "' . $startCommand . '"';
}
$entrypoint = match($type) {
$entrypoint = match ($type) {
'function' => $deployment->getAttribute('entrypoint', ''),
'site' => '',
'deployment' => ''
};
$executionResponse = $executor->createExecution(
@@ -433,7 +459,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
variables: $vars,
timeout: $resource->getAttribute('timeout', 30),
image: $runtime['image'],
source: $build->getAttribute('path', ''),
source: $deployment->getAttribute('buildPath', ''),
entrypoint: $entrypoint,
version: $version,
path: $path,
@@ -446,6 +472,30 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
requestTimeout: 30
);
// Branded 404 override
if ($executionResponse['statusCode'] === 404 && $resource->getAttribute('adapter', '') === 'static') {
$layout = new View(__DIR__ . '/../views/general/404.phtml');
$executionResponse['body'] = $layout->render();
$executionResponse['headers']['content-length'] = \strlen($executionResponse['body']);
}
// Branded banner for previews
if (\is_null($apiKey) || $apiKey->isBannerDisabled() === false) {
$transformation = new Transformation();
$transformation->addAdapter(new Preview());
$transformation->setInput($executionResponse['body']);
$transformation->setTraits($executionResponse['headers']);
if ($isPreview && $transformation->transform()) {
$executionResponse['body'] = $transformation->getOutput();
foreach ($executionResponse['headers'] as $key => $value) {
if (\strtolower($key) === 'content-length') {
$executionResponse['headers'][$key] = \strlen($executionResponse['body']);
}
}
}
}
$headersFiltered = [];
foreach ($executionResponse['headers'] as $key => $value) {
if (\in_array(\strtolower($key), FUNCTION_ALLOWLIST_HEADERS_RESPONSE)) {
@@ -455,9 +505,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
/** Update execution status */
$status = $executionResponse['statusCode'] >= 500 ? 'failed' : 'completed';
if ($type === 'function') {
$execution->setAttribute('status', $status);
}
$execution->setAttribute('status', $status);
$execution->setAttribute('logs', $executionResponse['logs']);
$execution->setAttribute('errors', $executionResponse['errors']);
$execution->setAttribute('responseStatusCode', $executionResponse['statusCode']);
@@ -472,8 +520,8 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
if ($type === 'function') {
$execution
->setAttribute('status', 'failed')
->setAttribute('errors', $th->getMessage() . '\nError Code: ' . $th->getCode());
->setAttribute('status', 'failed')
->setAttribute('errors', $th->getMessage() . '\nError Code: ' . $th->getCode());
}
Console::error($th->getMessage());
@@ -529,7 +577,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
$fileSize = (\is_array($file['size']) && isset($file['size'][0])) ? $file['size'][0] : $file['size'];
}
$queueForUsage
$queueForStatsUsage
->addMetric(METRIC_NETWORK_REQUESTS, 1)
->addMetric(METRIC_NETWORK_INBOUND, $request->getSize() + $fileSize)
->addMetric(METRIC_NETWORK_OUTBOUND, $response->getSize())
@@ -540,13 +588,22 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
->addMetric(METRIC_EXECUTIONS_MB_SECONDS, (int)(($spec['memory'] ?? APP_COMPUTE_MEMORY_DEFAULT) * $execution->getAttribute('duration', 0) * ($spec['cpus'] ?? APP_COMPUTE_CPUS_DEFAULT)))
->addMetric(str_replace('{functionInternalId}', $resource->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_MB_SECONDS), (int)(($spec['memory'] ?? APP_COMPUTE_MEMORY_DEFAULT) * $execution->getAttribute('duration', 0) * ($spec['cpus'] ?? APP_COMPUTE_CPUS_DEFAULT)))
->setProject($project)
->trigger()
;
->trigger();
return true;
} elseif ($type === 'api') {
$utopia->getRoute()?->label('error', '');
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 {
throw new AppwriteException(AppwriteException::GENERAL_SERVER_ERROR, 'Unknown resource type ' . $type);
}
@@ -555,7 +612,6 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
return false;
}
/*
App::init()
->groups(['api'])
->inject('project')
@@ -565,10 +621,9 @@ App::init()
throw new AppwriteException(AppwriteException::GENERAL_BAD_REQUEST, 'Admin mode is not allowed for console project');
}
});
*/
App::init()
->groups(['database', 'functions', 'storage', 'messaging'])
->groups(['database', 'functions', 'sites', 'messaging'])
->inject('project')
->inject('request')
->action(function (Document $project, Request $request) {
@@ -594,13 +649,14 @@ App::init()
->inject('localeCodes')
->inject('clients')
->inject('geodb')
->inject('queueForUsage')
->inject('queueForStatsUsage')
->inject('queueForEvents')
->inject('queueForCertificates')
->inject('queueForFunctions')
->inject('isResourceBlocked')
->inject('previewHostname')
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Document $console, Document $project, Database $dbForPlatform, callable $getProjectDB, Locale $locale, array $localeCodes, array $clients, Reader $geodb, Usage $queueForUsage, Event $queueForEvents, Certificate $queueForCertificates, Func $queueForFunctions, callable $isResourceBlocked, string $previewHostname) {
->inject('apiKey')
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Document $console, Document $project, Database $dbForPlatform, callable $getProjectDB, Locale $locale, array $localeCodes, array $clients, Reader $geodb, StatsUsage $queueForStatsUsage, Event $queueForEvents, Certificate $queueForCertificates, Func $queueForFunctions, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey) {
/*
* Appwrite Router
*/
@@ -608,9 +664,8 @@ App::init()
$mainDomain = System::getEnv('_APP_DOMAIN', '');
// Only run Router when external domain
if ($host !== $mainDomain || !empty($previewHostname)) {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForUsage, $queueForFunctions, $geodb, $isResourceBlocked, $previewHostname)) {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) {
$utopia->getRoute()?->label('router', true);
return;
}
}
@@ -637,6 +692,9 @@ App::init()
if (version_compare($requestFormat, '1.6.0', '<')) {
$request->addFilter(new RequestV18());
}
if (version_compare($requestFormat, '1.7.0', '<')) {
$request->addFilter(new RequestV19());
}
}
$domain = $request->getHostname();
@@ -679,14 +737,16 @@ App::init()
}
if ($domainDocument->isEmpty()) {
$ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5($domain->get()) : ID::unique();
$domainDocument = new Document([
// TODO: @christyjacob remove once we migrate the rules in 1.7.x
'$id' => System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5($domain->get()) : ID::unique(),
'$id' => $ruleId,
'domain' => $domain->get(),
'resourceType' => 'api',
'type' => 'api',
'status' => 'verifying',
'projectId' => 'console',
'projectInternalId' => 'console'
'projectInternalId' => 'console',
'search' => implode(' ', [$ruleId, $domain->get()]),
]);
$domainDocument = $dbForPlatform->createDocument('rules', $domainDocument);
@@ -720,6 +780,22 @@ App::init()
$validator = new Hostname($clients);
if ($validator->isValid($origin)) {
$refDomainOrigin = $origin;
} elseif (!empty($origin)) {
// Auto-allow domains with linked rule
if (System::getEnv('_APP_RULES_FORMAT') === 'md5') {
$rule = Authorization::skip(fn () => $dbForPlatform->getDocument('rules', md5($origin ?? '')));
} else {
$rule = Authorization::skip(
fn () => $dbForPlatform->find('rules', [
Query::equal('domain', [$origin]),
Query::limit(1)
])
)[0] ?? new Document();
}
if (!$rule->isEmpty() && $rule->getAttribute('projectInternalId') === $project->getInternalId()) {
$refDomainOrigin = $origin;
}
}
$refDomain = (!empty($protocol) ? $protocol : $request->getProtocol()) . '://' . $refDomainOrigin . (!empty($port) ? ':' . $port : '');
@@ -768,8 +844,11 @@ App::init()
if (version_compare($responseFormat, '1.6.0', '<')) {
$response->addFilter(new ResponseV18());
}
if (version_compare($responseFormat, '1.7.0', '<')) {
$response->addFilter(new ResponseV19());
}
if (version_compare($responseFormat, APP_VERSION_STABLE, '>')) {
$response->addHeader('X-Appwrite-Warning', "The current SDK is built for Appwrite " . $responseFormat . ". However, the current Appwrite server version is ". APP_VERSION_STABLE . ". Please downgrade your SDK to match the Appwrite version: https://appwrite.io/docs/sdks");
$response->addHeader('X-Appwrite-Warning', "The current SDK is built for Appwrite " . $responseFormat . ". However, the current Appwrite server version is " . APP_VERSION_STABLE . ". Please downgrade your SDK to match the Appwrite version: https://appwrite.io/docs/sdks");
}
}
@@ -828,12 +907,14 @@ App::options()
->inject('dbForPlatform')
->inject('getProjectDB')
->inject('queueForEvents')
->inject('queueForUsage')
->inject('queueForStatsUsage')
->inject('queueForFunctions')
->inject('geodb')
->inject('isResourceBlocked')
->inject('previewHostname')
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, Usage $queueForUsage, Func $queueForFunctions, Reader $geodb, callable $isResourceBlocked, string $previewHostname) {
->inject('project')
->inject('apiKey')
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Reader $geodb, callable $isResourceBlocked, string $previewHostname, Document $project, ?Key $apiKey) {
/*
* Appwrite Router
*/
@@ -841,9 +922,8 @@ App::options()
$mainDomain = System::getEnv('_APP_DOMAIN', '');
// Only run Router when external domain
if ($host !== $mainDomain || !empty($previewHostname)) {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForUsage, $queueForFunctions, $geodb, $isResourceBlocked, $previewHostname)) {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) {
$utopia->getRoute()?->label('router', true);
return;
}
}
@@ -857,6 +937,16 @@ App::options()
->addHeader('Access-Control-Allow-Origin', $origin)
->addHeader('Access-Control-Allow-Credentials', 'true')
->noContent();
/** OPTIONS requests in utopia do not execute shutdown handlers, as a result we need to track the OPTIONS requests explicitly
* @see https://github.com/utopia-php/http/blob/0.33.16/src/App.php#L825-L855
*/
$queueForStatsUsage
->addMetric(METRIC_NETWORK_REQUESTS, 1)
->addMetric(METRIC_NETWORK_INBOUND, $request->getSize())
->addMetric(METRIC_NETWORK_OUTBOUND, $response->getSize())
->setProject($project)
->trigger();
});
App::error()
@@ -867,8 +957,8 @@ App::error()
->inject('project')
->inject('logger')
->inject('log')
->inject('queueForUsage')
->action(function (Throwable $error, App $utopia, Request $request, Response $response, Document $project, ?Logger $logger, Log $log, Usage $queueForUsage) {
->inject('queueForStatsUsage')
->action(function (Throwable $error, App $utopia, Request $request, Response $response, Document $project, ?Logger $logger, Log $log, StatsUsage $queueForStatsUsage) {
$version = System::getEnv('_APP_VERSION', 'UNKNOWN');
$route = $utopia->getRoute();
$class = \get_class($error);
@@ -945,11 +1035,9 @@ App::error()
$publish = $error->getCode() === 0 || $error->getCode() >= 500;
}
if ($error->getCode() >= 400 && $error->getCode() < 500) {
$providerConfig = System::getEnv('_APP_EXPERIMENT_LOGGING_CONFIG', '');
if (!empty($providerConfig) && $error->getCode() >= 400 && $error->getCode() < 500) {
// Register error logger
$providerName = System::getEnv('_APP_EXPERIMENT_LOGGING_PROVIDER', '');
$providerConfig = System::getEnv('_APP_EXPERIMENT_LOGGING_CONFIG', '');
try {
$loggingProvider = new DSN($providerConfig ?? '');
$providerName = $loggingProvider->getScheme();
@@ -971,7 +1059,10 @@ App::error()
}
}
if ($publish && $project->getId() !== 'console') {
/**
* If its not a publishable error, track usage stats. Publishable errors are >= 500 or those explicitly marked as publish=true in errors.php
*/
if (!$publish && $project->getId() !== 'console') {
if (!Auth::isPrivilegedUser(Authorization::getRoles())) {
$fileSize = 0;
$file = $request->getFiles('file');
@@ -979,18 +1070,17 @@ App::error()
$fileSize = (\is_array($file['size']) && isset($file['size'][0])) ? $file['size'][0] : $file['size'];
}
$queueForUsage
$queueForStatsUsage
->addMetric(METRIC_NETWORK_REQUESTS, 1)
->addMetric(METRIC_NETWORK_INBOUND, $request->getSize() + $fileSize)
->addMetric(METRIC_NETWORK_OUTBOUND, $response->getSize());
}
$queueForUsage
$queueForStatsUsage
->setProject($project)
->trigger();
}
if ($logger && $publish) {
try {
/** @var Utopia\Database\Document $user */
@@ -1138,12 +1228,13 @@ App::get('/robots.txt')
->inject('dbForPlatform')
->inject('getProjectDB')
->inject('queueForEvents')
->inject('queueForUsage')
->inject('queueForStatsUsage')
->inject('queueForFunctions')
->inject('geodb')
->inject('isResourceBlocked')
->inject('previewHostname')
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, Usage $queueForUsage, Func $queueForFunctions, Reader $geodb, callable $isResourceBlocked, string $previewHostname) {
->inject('apiKey')
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey) {
$host = $request->getHostname() ?? '';
$mainDomain = System::getEnv('_APP_DOMAIN', '');
@@ -1151,7 +1242,7 @@ App::get('/robots.txt')
$template = new View(__DIR__ . '/../views/general/robots.phtml');
$response->text($template->render(false));
} else {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForUsage, $queueForFunctions, $geodb, $isResourceBlocked, $previewHostname)) {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) {
$utopia->getRoute()?->label('router', true);
}
}
@@ -1168,12 +1259,13 @@ App::get('/humans.txt')
->inject('dbForPlatform')
->inject('getProjectDB')
->inject('queueForEvents')
->inject('queueForUsage')
->inject('queueForStatsUsage')
->inject('queueForFunctions')
->inject('geodb')
->inject('isResourceBlocked')
->inject('previewHostname')
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, Usage $queueForUsage, Func $queueForFunctions, Reader $geodb, callable $isResourceBlocked, string $previewHostname) {
->inject('apiKey')
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey) {
$host = $request->getHostname() ?? '';
$mainDomain = System::getEnv('_APP_DOMAIN', '');
@@ -1181,7 +1273,7 @@ App::get('/humans.txt')
$template = new View(__DIR__ . '/../views/general/humans.phtml');
$response->text($template->render(false));
} else {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForUsage, $queueForFunctions, $geodb, $isResourceBlocked, $previewHostname)) {
if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $geodb, $isResourceBlocked, $previewHostname, $apiKey)) {
$utopia->getRoute()?->label('router', true);
}
}
@@ -1245,12 +1337,27 @@ App::get('/v1/ping')
->desc('Test the connection between the Appwrite and the SDK.')
->label('scope', 'global')
->label('event', 'projects.[projectId].ping')
->label('sdk', new Method(
namespace: 'ping',
name: 'get',
hide: true,
description: <<<EOT
Send a ping to project as part of onboarding.
EOT,
auth: [],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_ANY,
)
],
))
->inject('response')
->inject('project')
->inject('dbForPlatform')
->inject('queueForEvents')
->action(function (Response $response, Document $project, Database $dbForPlatform, Event $queueForEvents) {
if ($project->isEmpty()) {
if ($project->isEmpty() || $project->getId() === 'console') {
throw new AppwriteException(AppwriteException::PROJECT_NOT_FOUND);
}
@@ -1272,16 +1379,38 @@ App::get('/v1/ping')
$response->text('Pong!');
});
// Preview authorization
App::get('/_appwrite/authorize')
->inject('request')
->inject('response')
->inject('previewHostname')
->action(function (Request $request, Response $response, string $previewHostname) {
$host = $request->getHostname() ?? '';
if (!empty($previewHostname)) {
$host = $previewHostname;
}
$referrer = $request->getReferer();
$protocol = \parse_url($request->getOrigin($referrer), PHP_URL_SCHEME);
$jwt = $request->getParam('jwt', '');
$path = $request->getParam('path', '');
$duration = 60 * 60 * 24; // 1 day in seconds
$expire = DateTime::formatTz(DateTime::addSeconds(new \DateTime(), $duration));
$response
->addCookie(Auth::$cookieNamePreview, $jwt, (new \DateTime($expire))->getTimestamp(), '/', $host, ('https' === $protocol), true, null)
->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
->addHeader('Pragma', 'no-cache')
->redirect($protocol . '://' . $host . $path);
});
App::wildcard()
->groups(['api'])
->label('scope', 'global')
->inject('utopia')
->action(function (App $utopia) {
$handeledByRouter = $utopia->getRoute()?->getLabel('router', false);
if ($handeledByRouter === true) {
return;
}
->action(function () {
throw new AppwriteException(AppwriteException::GENERAL_ROUTE_NOT_FOUND);
});
+97 -144
View File
@@ -1,8 +1,7 @@
<?php
use Ahc\Jwt\JWT;
use Ahc\Jwt\JWTException;
use Appwrite\Auth\Auth;
use Appwrite\Auth\Key;
use Appwrite\Auth\MFA\Type\TOTP;
use Appwrite\Event\Audit;
use Appwrite\Event\Build;
@@ -12,10 +11,11 @@ use Appwrite\Event\Event;
use Appwrite\Event\Func;
use Appwrite\Event\Messaging;
use Appwrite\Event\Realtime;
use Appwrite\Event\Usage;
use Appwrite\Event\StatsUsage;
use Appwrite\Event\Webhook;
use Appwrite\Extend\Exception;
use Appwrite\Extend\Exception as AppwriteException;
use Appwrite\SDK\Method;
use Appwrite\Utopia\Request;
use Appwrite\Utopia\Response;
use Utopia\Abuse\Abuse;
@@ -90,7 +90,7 @@ $eventDatabaseListener = function (Document $project, Document $document, Respon
}
};
$usageDatabaseListener = function (string $event, Document $document, Usage $queueForUsage) {
$usageDatabaseListener = function (string $event, Document $document, StatsUsage $queueForStatsUsage) {
$value = 1;
if ($event === Database::EVENT_DOCUMENT_DELETE) {
$value = -1;
@@ -98,89 +98,81 @@ $usageDatabaseListener = function (string $event, Document $document, Usage $que
switch (true) {
case $document->getCollection() === 'teams':
$queueForUsage
->addMetric(METRIC_TEAMS, $value); // per project
$queueForStatsUsage->addMetric(METRIC_TEAMS, $value); // per project
break;
case $document->getCollection() === 'users':
$queueForUsage
->addMetric(METRIC_USERS, $value); // per project
$queueForStatsUsage->addMetric(METRIC_USERS, $value); // per project
if ($event === Database::EVENT_DOCUMENT_DELETE) {
$queueForUsage
->addReduce($document);
$queueForStatsUsage->addReduce($document);
}
break;
case $document->getCollection() === 'sessions': // sessions
$queueForUsage
->addMetric(METRIC_SESSIONS, $value); //per project
$queueForStatsUsage->addMetric(METRIC_SESSIONS, $value); //per project
break;
case $document->getCollection() === 'databases': // databases
$queueForUsage
->addMetric(METRIC_DATABASES, $value); // per project
$queueForStatsUsage->addMetric(METRIC_DATABASES, $value); // per project
if ($event === Database::EVENT_DOCUMENT_DELETE) {
$queueForUsage
->addReduce($document);
$queueForStatsUsage->addReduce($document);
}
break;
case str_starts_with($document->getCollection(), 'database_') && !str_contains($document->getCollection(), 'collection'): //collections
$parts = explode('_', $document->getCollection());
$databaseInternalId = $parts[1] ?? 0;
$queueForUsage
$queueForStatsUsage
->addMetric(METRIC_COLLECTIONS, $value) // per project
->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, METRIC_DATABASE_ID_COLLECTIONS), $value)
;
->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, METRIC_DATABASE_ID_COLLECTIONS), $value);
if ($event === Database::EVENT_DOCUMENT_DELETE) {
$queueForUsage
->addReduce($document);
$queueForStatsUsage->addReduce($document);
}
break;
case str_starts_with($document->getCollection(), 'database_') && str_contains($document->getCollection(), '_collection_'): //documents
$parts = explode('_', $document->getCollection());
$databaseInternalId = $parts[1] ?? 0;
$collectionInternalId = $parts[3] ?? 0;
$queueForUsage
$queueForStatsUsage
->addMetric(METRIC_DOCUMENTS, $value) // per project
->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, METRIC_DATABASE_ID_DOCUMENTS), $value) // per database
->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$databaseInternalId, $collectionInternalId], METRIC_DATABASE_ID_COLLECTION_ID_DOCUMENTS), $value); // per collection
break;
case $document->getCollection() === 'buckets': //buckets
$queueForUsage
$queueForStatsUsage
->addMetric(METRIC_BUCKETS, $value); // per project
if ($event === Database::EVENT_DOCUMENT_DELETE) {
$queueForUsage
$queueForStatsUsage
->addReduce($document);
}
break;
case str_starts_with($document->getCollection(), 'bucket_'): // files
$parts = explode('_', $document->getCollection());
$bucketInternalId = $parts[1];
$queueForUsage
$queueForStatsUsage
->addMetric(METRIC_FILES, $value) // per project
->addMetric(METRIC_FILES_STORAGE, $document->getAttribute('sizeOriginal') * $value) // per project
->addMetric(str_replace('{bucketInternalId}', $bucketInternalId, METRIC_BUCKET_ID_FILES), $value) // per bucket
->addMetric(str_replace('{bucketInternalId}', $bucketInternalId, METRIC_BUCKET_ID_FILES_STORAGE), $document->getAttribute('sizeOriginal') * $value); // per bucket
break;
case $document->getCollection() === 'functions':
$queueForUsage
$queueForStatsUsage
->addMetric(METRIC_FUNCTIONS, $value); // per project
if ($event === Database::EVENT_DOCUMENT_DELETE) {
$queueForUsage
$queueForStatsUsage
->addReduce($document);
}
break;
case $document->getCollection() === 'sites':
$queueForUsage
$queueForStatsUsage
->addMetric(METRIC_SITES, $value); // per project
if ($event === Database::EVENT_DOCUMENT_DELETE) {
$queueForUsage
$queueForStatsUsage
->addReduce($document);
}
break;
case $document->getCollection() === 'deployments':
$queueForUsage
$queueForStatsUsage
->addMetric(METRIC_DEPLOYMENTS, $value) // per project
->addMetric(METRIC_DEPLOYMENTS_STORAGE, $document->getAttribute('size') * $value) // per project
->addMetric(str_replace(['{resourceType}', '{resourceInternalId}'], [$document->getAttribute('resourceType'), $document->getAttribute('resourceInternalId')], METRIC_FUNCTION_ID_DEPLOYMENTS), $value) // per function
@@ -204,117 +196,79 @@ App::init()
->inject('servers')
->inject('mode')
->inject('team')
->action(function (App $utopia, Request $request, Database $dbForPlatform, Database $dbForProject, Audit $queueForAudits, Document $project, Document $user, ?Document $session, array $servers, string $mode, Document $team) {
->inject('apiKey')
->action(function (App $utopia, Request $request, Database $dbForPlatform, Database $dbForProject, Audit $queueForAudits, Document $project, Document $user, ?Document $session, array $servers, string $mode, Document $team, ?Key $apiKey) {
$route = $utopia->getRoute();
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
/** Default role */
$roles = Config::getParam('roles', []);
$role = ($user->isEmpty())
$role = $user->isEmpty()
? Role::guests()->toString()
: Role::users()->toString();
/** Allowed Scopes for the role */
$scopes = $roles[$role]['scopes'];
$apiKey = $request->getHeader('x-appwrite-key', '');
// API Key authentication
if (!empty($apiKey)) {
// Do not allow API key and session to be set at the same time
if (!$user->isEmpty()) {
throw new Exception(Exception::USER_API_KEY_AND_SESSION_SET);
}
// Remove after migration
if (!\str_contains($apiKey, '_')) {
$keyType = API_KEY_STANDARD;
$authKey = $apiKey;
} else {
[ $keyType, $authKey ] = \explode('_', $apiKey, 2);
if ($apiKey->isExpired()) {
throw new Exception(Exception::PROJECT_KEY_EXPIRED);
}
if ($keyType === API_KEY_DYNAMIC) {
// Dynamic key
$role = $apiKey->getRole();
$scopes = $apiKey->getScopes();
$jwtObj = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 86400, 0);
// Disable authorization checks for API keys
Authorization::setDefaultStatus(false);
try {
$payload = $jwtObj->decode($authKey);
} catch (JWTException $error) {
throw new Exception(Exception::API_KEY_EXPIRED);
}
if ($apiKey->getRole() === Auth::USER_ROLE_APPS) {
$user = new Document([
'$id' => '',
'status' => true,
'type' => Auth::ACTIVITY_TYPE_APP,
'email' => 'app.' . $project->getId() . '@service.' . $request->getHostname(),
'password' => '',
'name' => $apiKey->getName(),
]);
$projectId = $payload['projectId'] ?? '';
$tokenScopes = $payload['scopes'] ?? [];
$queueForAudits->setUser($user);
}
// JWT includes project ID for better security
if ($projectId === $project->getId()) {
$user = new Document([
'$id' => '',
'status' => true,
'type' => Auth::ACTIVITY_TYPE_APP,
'email' => 'app.' . $project->getId() . '@service.' . $request->getHostname(),
'password' => '',
'name' => 'Dynamic Key',
]);
if ($apiKey->getType() === API_KEY_STANDARD) {
$dbKey = $project->find(
key: 'secret',
find: $request->getHeader('x-appwrite-key', ''),
subject: 'keys'
);
$role = Auth::USER_ROLE_APPS;
$scopes = \array_merge($roles[$role]['scopes'], $tokenScopes);
if ($dbKey) {
$accessedAt = $dbKey->getAttribute('accessedAt', '');
Authorization::setRole(Auth::USER_ROLE_APPS);
Authorization::setDefaultStatus(false); // Cancel security segmentation for API keys.
$queueForAudits->setUser($user);
}
} elseif ($keyType === API_KEY_STANDARD) {
// No underline means no prefix. Backwards compatibility.
// Regular key
// Check if given key match project API keys
$key = $project->find('secret', $apiKey, 'keys');
if ($key) {
$user = new Document([
'$id' => '',
'status' => true,
'type' => Auth::ACTIVITY_TYPE_APP,
'email' => 'app.' . $project->getId() . '@service.' . $request->getHostname(),
'password' => '',
'name' => $key->getAttribute('name', 'UNKNOWN'),
]);
$role = Auth::USER_ROLE_APPS;
$scopes = \array_merge($roles[$role]['scopes'], $key->getAttribute('scopes', []));
$expire = $key->getAttribute('expire');
if (!empty($expire) && $expire < DateTime::formatTz(DateTime::now())) {
throw new Exception(Exception::PROJECT_KEY_EXPIRED);
}
Authorization::setRole(Auth::USER_ROLE_APPS);
Authorization::setDefaultStatus(false); // Cancel security segmentation for API keys.
$accessedAt = $key->getAttribute('accessedAt', '');
if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_KEY_ACCESS)) > $accessedAt) {
$key->setAttribute('accessedAt', DateTime::now());
$dbForPlatform->updateDocument('keys', $key->getId(), $key);
$dbKey->setAttribute('accessedAt', DateTime::now());
$dbForPlatform->updateDocument('keys', $dbKey->getId(), $dbKey);
$dbForPlatform->purgeCachedDocument('projects', $project->getId());
}
$sdkValidator = new WhiteList($servers, true);
$sdk = $request->getHeader('x-sdk-name', 'UNKNOWN');
if ($sdkValidator->isValid($sdk)) {
$sdks = $key->getAttribute('sdks', []);
$sdks = $dbKey->getAttribute('sdks', []);
if (!in_array($sdk, $sdks)) {
array_push($sdks, $sdk);
$key->setAttribute('sdks', $sdks);
$sdks[] = $sdk;
$dbKey->setAttribute('sdks', $sdks);
/** Update access time as well */
$key->setAttribute('accessedAt', Datetime::now());
$dbForPlatform->updateDocument('keys', $key->getId(), $key);
$dbKey->setAttribute('accessedAt', Datetime::now());
$dbForPlatform->updateDocument('keys', $dbKey->getId(), $dbKey);
$dbForPlatform->purgeCachedDocument('projects', $project->getId());
}
}
@@ -322,8 +276,7 @@ App::init()
$queueForAudits->setUser($user);
}
}
}
// Admin User Authentication
} // Admin User Authentication
elseif (($project->getId() === 'console' && !$team->isEmpty() && !$user->isEmpty()) || ($project->getId() !== 'console' && !$user->isEmpty() && $mode === APP_MODE_ADMIN)) {
$teamId = $team->getId();
$adminRoles = [];
@@ -339,7 +292,7 @@ App::init()
throw new Exception(Exception::USER_UNAUTHORIZED);
}
$scopes = []; // reset scope if admin
$scopes = []; // Reset scope if admin
foreach ($adminRoles as $role) {
$scopes = \array_merge($scopes, $roles[$role]['scopes']);
}
@@ -354,9 +307,7 @@ App::init()
Authorization::setRole($authRole);
}
/**
* Update project last activity
*/
// Update project last activity
if (!$project->isEmpty() && $project->getId() !== 'console') {
$accessedAt = $project->getAttribute('accessedAt', '');
if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $accessedAt) {
@@ -365,9 +316,7 @@ App::init()
}
}
/**
* Update user last activity
*/
// Update user last activity
if (!empty($user->getId())) {
$accessedAt = $user->getAttribute('accessedAt', '');
if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_USER_ACCESS)) > $accessedAt) {
@@ -381,18 +330,18 @@ App::init()
}
}
/** Do not allow access to disabled services */
/**
* @var ?\Appwrite\SDK\Method $method
* @var ?Method $method
*/
$method = $route->getLabel('sdk', false);
if (is_array($method)) {
if (\is_array($method)) {
$method = $method[0];
}
if (!empty($method)) {
$namespace = $method->getNamespace();
if (
array_key_exists($namespace, $project->getAttribute('services', []))
&& !$project->getAttribute('services', [])[$namespace]
@@ -402,13 +351,13 @@ App::init()
}
}
/** Do now allow access if scope is not allowed */
// Do now allow access if scope is not allowed
$scope = $route->getLabel('scope', 'none');
if (!\in_array($scope, $scopes)) {
throw new Exception(Exception::GENERAL_UNAUTHORIZED_SCOPE, $user->getAttribute('email', 'User') . ' (role: ' . \strtolower($roles[$role]['label']) . ') missing scope (' . $scope . ')');
}
/** Do not allow access to blocked accounts */
// Do not allow access to blocked accounts
if (false === $user->getAttribute('status')) { // Account is blocked
throw new Exception(Exception::USER_BLOCKED);
}
@@ -445,11 +394,12 @@ App::init()
->inject('queueForDeletes')
->inject('queueForDatabase')
->inject('queueForBuilds')
->inject('queueForUsage')
->inject('queueForStatsUsage')
->inject('dbForProject')
->inject('timelimit')
->inject('mode')
->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Publisher $publisher, Event $queueForEvents, Messaging $queueForMessaging, Audit $queueForAudits, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, Usage $queueForUsage, Database $dbForProject, callable $timelimit, string $mode) use ($usageDatabaseListener, $eventDatabaseListener) {
->inject('apiKey')
->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Publisher $publisher, Event $queueForEvents, Messaging $queueForMessaging, Audit $queueForAudits, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, StatsUsage $queueForStatsUsage, Database $dbForProject, callable $timelimit, string $mode, ?Key $apiKey) use ($usageDatabaseListener, $eventDatabaseListener) {
$route = $utopia->getRoute();
@@ -480,7 +430,7 @@ App::init()
->setParam('{ip}', $request->getIP())
->setParam('{url}', $request->getHostname() . $route->getPath())
->setParam('{method}', $request->getMethod())
->setParam('{chunkId}', (int) ($start / ($end + 1 - $start)));
->setParam('{chunkId}', (int)($start / ($end + 1 - $start)));
$timeLimitArray[] = $timeLimit;
}
@@ -546,6 +496,12 @@ App::init()
$queueForAudits->setUser($userClone);
}
if (!empty($apiKey) && !empty($apiKey->getDisabledMetrics())) {
foreach ($apiKey->getDisabledMetrics() as $key) {
$queueForStatsUsage->disableMetric($key);
}
}
$queueForDeletes->setProject($project);
$queueForDatabase->setProject($project);
$queueForBuilds->setProject($project);
@@ -559,8 +515,8 @@ App::init()
$queueForRealtime = new Realtime();
$dbForProject
->on(Database::EVENT_DOCUMENT_CREATE, 'calculate-usage', fn ($event, $document) => $usageDatabaseListener($event, $document, $queueForUsage))
->on(Database::EVENT_DOCUMENT_DELETE, 'calculate-usage', fn ($event, $document) => $usageDatabaseListener($event, $document, $queueForUsage))
->on(Database::EVENT_DOCUMENT_CREATE, 'calculate-usage', fn ($event, $document) => $usageDatabaseListener($event, $document, $queueForStatsUsage))
->on(Database::EVENT_DOCUMENT_DELETE, 'calculate-usage', fn ($event, $document) => $usageDatabaseListener($event, $document, $queueForStatsUsage))
->on(Database::EVENT_DOCUMENT_CREATE, 'create-trigger-events', fn ($event, $document) => $eventDatabaseListener(
$project,
$document,
@@ -587,12 +543,9 @@ App::init()
if ($type === 'bucket') {
$bucketId = $parts[1] ?? null;
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) {
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAppUser && !$isPrivilegedUser)) {
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
}
@@ -616,11 +569,13 @@ App::init()
if ($file->isEmpty()) {
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
}
$transformedAt = $file->getAttribute('transformedAt', '');
if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $transformedAt) {
$file->setAttribute('transformedAt', DateTime::now());
Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $file->getAttribute('bucketInternalId'), $file->getId(), $file));
//Do not update transformedAt if it's a console user
if (!Auth::isPrivilegedUser(Authorization::getRoles())) {
$transformedAt = $file->getAttribute('transformedAt', '');
if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_PROJECT_ACCESS)) > $transformedAt) {
$file->setAttribute('transformedAt', DateTime::now());
Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $file->getAttribute('bucketInternalId'), $file->getId(), $file));
}
}
}
@@ -634,8 +589,7 @@ App::init()
->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate')
->addHeader('Pragma', 'no-cache')
->addHeader('Expires', '0')
->addHeader('X-Appwrite-Cache', 'miss')
;
->addHeader('X-Appwrite-Cache', 'miss');
}
}
});
@@ -703,7 +657,7 @@ App::shutdown()
->inject('user')
->inject('queueForEvents')
->inject('queueForAudits')
->inject('queueForUsage')
->inject('queueForStatsUsage')
->inject('queueForDeletes')
->inject('queueForDatabase')
->inject('queueForBuilds')
@@ -712,7 +666,7 @@ App::shutdown()
->inject('queueForWebhooks')
->inject('queueForRealtime')
->inject('dbForProject')
->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $queueForEvents, Audit $queueForAudits, Usage $queueForUsage, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, Messaging $queueForMessaging, Func $queueForFunctions, Event $queueForWebhooks, Realtime $queueForRealtime, Database $dbForProject) use ($parseLabel) {
->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Event $queueForEvents, Audit $queueForAudits, StatsUsage $queueForStatsUsage, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, Messaging $queueForMessaging, Func $queueForFunctions, Event $queueForWebhooks, Realtime $queueForRealtime, Database $dbForProject) use ($parseLabel) {
$responsePayload = $response->getPayload();
@@ -796,6 +750,7 @@ App::shutdown()
foreach ($queueForEvents->getParams() as $key => $value) {
$queueForAudits->setParam($key, $value);
}
$queueForAudits->trigger();
}
@@ -815,9 +770,7 @@ App::shutdown()
$queueForMessaging->trigger();
}
/**
* Cache label
*/
// Cache label
$useCache = $route->getLabel('cache', false);
if ($useCache) {
$resource = $resourceType = null;
@@ -869,13 +822,13 @@ App::shutdown()
$fileSize = (\is_array($file['size']) && isset($file['size'][0])) ? $file['size'][0] : $file['size'];
}
$queueForUsage
$queueForStatsUsage
->addMetric(METRIC_NETWORK_REQUESTS, 1)
->addMetric(METRIC_NETWORK_INBOUND, $request->getSize() + $fileSize)
->addMetric(METRIC_NETWORK_OUTBOUND, $response->getSize());
}
$queueForUsage
$queueForStatsUsage
->setProject($project)
->trigger();
}
+184 -80
View File
@@ -13,11 +13,11 @@ use Swoole\Table;
use Utopia\App;
use Utopia\Audit\Audit;
use Utopia\CLI\Console;
use Utopia\Compression\Compression;
use Utopia\Config\Config;
use Utopia\Database\Database;
use Utopia\Database\DateTime;
use Utopia\Database\Document;
use Utopia\Database\Exception\Duplicate;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Helpers\Permission;
use Utopia\Database\Helpers\Role;
@@ -29,6 +29,8 @@ use Utopia\Pools\Group;
use Utopia\Swoole\Files;
use Utopia\System\System;
Files::load(__DIR__.'/../public');
const DOMAIN_SYNC_TIMER = 30; // 30 seconds
$domains = new Table(1_000_000); // 1 million rows
@@ -156,6 +158,79 @@ function dispatch(Server $server, int $fd, int $type, $data = null): int
include __DIR__ . '/controllers/general.php';
function createDatabase(App $app, string $resourceKey, string $dbName, array $collections, mixed $pools, callable $extraSetup = null): void
{
$max = 10;
$sleep = 1;
$attempts = 0;
do {
try {
$attempts++;
$resource = $app->getResource($resourceKey);
/* @var $database Database */
$database = is_callable($resource) ? $resource() : $resource;
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...");
// Attempt to create the database
try {
Console::info(" └── Creating database: $dbName...");
$database->create();
} catch (\Exception $e) {
Console::info(" └── Skip: metadata table already exists");
}
// Process collections
foreach ($collections as $key => $collection) {
if (($collection['$collection'] ?? '') !== Database::METADATA) {
continue;
}
if (!$database->getCollection($key)->isEmpty()) {
continue;
}
Console::info(" └── Creating collection: {$collection['$id']}...");
$attributes = array_map(fn ($attr) => new Document([
'$id' => ID::custom($attr['$id']),
'type' => $attr['type'],
'size' => $attr['size'],
'required' => $attr['required'],
'signed' => $attr['signed'],
'array' => $attr['array'],
'filters' => $attr['filters'],
'default' => $attr['default'] ?? null,
'format' => $attr['format'] ?? ''
]), $collection['attributes']);
$indexes = array_map(fn ($index) => new Document([
'$id' => ID::custom($index['$id']),
'type' => $index['type'],
'attributes' => $index['attributes'],
'lengths' => $index['lengths'],
'orders' => $index['orders'],
]), $collection['indexes']);
$database->createCollection($key, $attributes, $indexes);
}
if ($extraSetup) {
$extraSetup($database);
}
}
$http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $register) {
$app = new App('UTC');
@@ -164,94 +239,120 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg
/** @var Group $pools */
App::setResource('pools', fn () => $pools);
// wait for database to be ready
$attempts = 0;
$max = 10;
$sleep = 1;
do {
try {
$attempts++;
$dbForPlatform = $app->getResource('dbForPlatform');
/** @var Utopia\Database\Database $dbForPlatform */
break; // leave the do-while if successful
} catch (\Throwable $e) {
Console::warning("Database not ready. Retrying connection ({$attempts})...");
if ($attempts >= $max) {
throw new \Exception('Failed to connect to database: ' . $e->getMessage());
}
sleep($sleep);
}
} while ($attempts < $max);
Console::success('[Setup] - Server database init started...');
try {
Console::success('[Setup] - Creating console database...');
$dbForPlatform->create();
} catch (Duplicate) {
Console::success('[Setup] - Skip: metadata table already exists');
}
if ($dbForPlatform->getCollection(Audit::COLLECTION)->isEmpty()) {
$audit = new Audit($dbForPlatform);
$audit->setup();
}
/** @var array $collections */
$collections = Config::getParam('collections', []);
$consoleCollections = $collections['console'];
foreach ($consoleCollections as $key => $collection) {
if (($collection['$collection'] ?? '') !== Database::METADATA) {
continue;
}
if (!$dbForPlatform->getCollection($key)->isEmpty()) {
continue;
// create logs database first, `getLogsDB` is a callable.
createDatabase($app, 'getLogsDB', 'logs', $collections['logs'], $pools);
// create appwrite database, `dbForPlatform` is a direct access call.
createDatabase($app, 'dbForPlatform', 'appwrite', $collections['console'], $pools, function (Database $dbForPlatform) use ($collections) {
if ($dbForPlatform->getCollection(Audit::COLLECTION)->isEmpty()) {
$audit = new Audit($dbForPlatform);
$audit->setup();
}
Console::success('[Setup] - Creating console collection: ' . $collection['$id'] . '...');
if ($dbForPlatform->getDocument('buckets', 'default')->isEmpty()) {
Console::info(" └── Creating default bucket...");
$dbForPlatform->createDocument('buckets', new Document([
'$id' => ID::custom('default'),
'$collection' => ID::custom('buckets'),
'name' => 'Default',
'maximumFileSize' => (int) System::getEnv('_APP_STORAGE_LIMIT', 0),
'allowedFileExtensions' => [],
'enabled' => true,
'compression' => 'gzip',
'encryption' => true,
'antivirus' => true,
'fileSecurity' => true,
'$permissions' => [
Permission::create(Role::any()),
Permission::read(Role::any()),
Permission::update(Role::any()),
Permission::delete(Role::any()),
],
'search' => 'buckets Default',
]));
$attributes = \array_map(fn ($attribute) => new Document($attribute), $collection['attributes']);
$indexes = \array_map(fn (array $index) => new Document($index), $collection['indexes']);
$bucket = $dbForPlatform->getDocument('buckets', 'default');
$dbForPlatform->createCollection($key, $attributes, $indexes);
}
Console::info(" └── Creating files collection for default bucket...");
$files = $collections['buckets']['files'] ?? [];
if (empty($files)) {
throw new Exception('Files collection is not configured.');
}
if ($dbForPlatform->getDocument('buckets', 'default')->isEmpty() && !$dbForPlatform->exists($dbForPlatform->getDatabase(), 'bucket_1')) {
Console::success('[Setup] - Creating default bucket...');
$dbForPlatform->createDocument('buckets', new Document([
'$id' => ID::custom('default'),
'$collection' => ID::custom('buckets'),
'name' => 'Default',
'maximumFileSize' => (int) System::getEnv('_APP_STORAGE_LIMIT', 0), // 10MB
'allowedFileExtensions' => [],
'enabled' => true,
'compression' => 'gzip',
'encryption' => true,
'antivirus' => true,
'fileSecurity' => true,
'$permissions' => [
Permission::create(Role::any()),
Permission::read(Role::any()),
Permission::update(Role::any()),
Permission::delete(Role::any()),
],
'search' => 'buckets Default',
]));
$attributes = array_map(fn ($attr) => new Document([
'$id' => ID::custom($attr['$id']),
'type' => $attr['type'],
'size' => $attr['size'],
'required' => $attr['required'],
'signed' => $attr['signed'],
'array' => $attr['array'],
'filters' => $attr['filters'],
'default' => $attr['default'] ?? null,
'format' => $attr['format'] ?? ''
]), $files['attributes']);
$bucket = $dbForPlatform->getDocument('buckets', 'default');
$indexes = array_map(fn ($index) => new Document([
'$id' => ID::custom($index['$id']),
'type' => $index['type'],
'attributes' => $index['attributes'],
'lengths' => $index['lengths'],
'orders' => $index['orders'],
]), $files['indexes']);
Console::success('[Setup] - Creating files collection for default bucket...');
$files = $collections['buckets']['files'] ?? [];
if (empty($files)) {
throw new Exception('Files collection is not configured.');
$dbForPlatform->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes);
}
$attributes = \array_map(fn ($attribute) => new Document($attribute), $files['attributes']);
$indexes = \array_map(fn (array $index) => new Document($index), $files['indexes']);
if (Authorization::skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots')->isEmpty())) {
Console::info(" └── Creating screenshots bucket...");
Authorization::skip(fn () => $dbForPlatform->createDocument('buckets', new Document([
'$id' => ID::custom('screenshots'),
'$collection' => ID::custom('buckets'),
'name' => 'Screenshots',
'maximumFileSize' => 5000000, // ~5MB
'allowedFileExtensions' => [ 'png' ],
'enabled' => true,
'compression' => Compression::GZIP,
'encryption' => false,
'antivirus' => false,
'fileSecurity' => true,
'$permissions' => [],
'search' => 'buckets Screenshots',
])));
$dbForPlatform->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes);
}
$bucket = Authorization::skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots'));
Console::info(" └── Creating files collection for screenshots bucket...");
$files = $collections['buckets']['files'] ?? [];
if (empty($files)) {
throw new Exception('Files collection is not configured.');
}
$attributes = array_map(fn ($attr) => new Document([
'$id' => ID::custom($attr['$id']),
'type' => $attr['type'],
'size' => $attr['size'],
'required' => $attr['required'],
'signed' => $attr['signed'],
'array' => $attr['array'],
'filters' => $attr['filters'],
'default' => $attr['default'] ?? null,
'format' => $attr['format'] ?? ''
]), $files['attributes']);
$indexes = array_map(fn ($index) => new Document([
'$id' => ID::custom($index['$id']),
'type' => $index['type'],
'attributes' => $index['attributes'],
'lengths' => $index['lengths'],
'orders' => $index['orders'],
]), $files['indexes']);
Authorization::skip(fn () => $dbForPlatform->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes));
}
});
$projectCollections = $collections['projects'];
$sharedTables = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES', ''));
@@ -279,6 +380,11 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg
Console::success('[Setup] - Skip: metadata table already exists');
}
if ($dbForProject->getCollection(Audit::COLLECTION)->isEmpty()) {
$audit = new Audit($dbForProject);
$audit->setup();
}
foreach ($projectCollections as $key => $collection) {
if (($collection['$collection'] ?? '') !== Database::METADATA) {
continue;
@@ -297,7 +403,6 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg
}
$pools->reclaim();
Console::success('[Setup] - Server database init completed...');
});
@@ -459,7 +564,6 @@ $http->on('Task', function () use ($register, $domains) {
if ($lastSyncUpdate != null) {
$queries[] = Query::greaterThanEqual('$updatedAt', $lastSyncUpdate);
}
$queries[] = Query::equal('resourceType', ['function']);
$results = [];
try {
$results = Authorization::skip(fn () => $dbForPlatform->find('rules', $queries));
@@ -470,7 +574,7 @@ $http->on('Task', function () use ($register, $domains) {
$sum = count($results);
foreach ($results as $document) {
$domain = $document->getAttribute('domain');
if (str_ends_with($domain, System::getEnv('_APP_DOMAIN_FUNCTIONS'))) {
if (str_ends_with($domain, System::getEnv('_APP_DOMAIN_FUNCTIONS')) || str_ends_with($domain, System::getEnv('_APP_DOMAIN_SITES'))) {
continue;
}
$domains->set(md5($domain), ['value' => 1]);
+90 -55
View File
@@ -21,6 +21,7 @@ if (\file_exists(__DIR__ . '/../vendor/autoload.php')) {
use Ahc\Jwt\JWT;
use Ahc\Jwt\JWTException;
use Appwrite\Auth\Auth;
use Appwrite\Auth\Key;
use Appwrite\Event\Audit;
use Appwrite\Event\Build;
use Appwrite\Event\Certificate;
@@ -32,16 +33,16 @@ use Appwrite\Event\Mail;
use Appwrite\Event\Messaging;
use Appwrite\Event\Migration;
use Appwrite\Event\Realtime;
use Appwrite\Event\Usage;
use Appwrite\Event\StatsUsage;
use Appwrite\Event\Webhook;
use Appwrite\Extend\Exception;
use Appwrite\Functions\Specification;
use Appwrite\GraphQL\Promises\Adapter\Swoole;
use Appwrite\GraphQL\Schema;
use Appwrite\Hooks\Hooks;
use Appwrite\Network\Validator\Email;
use Appwrite\Network\Validator\Origin;
use Appwrite\OpenSSL\OpenSSL;
use Appwrite\Platform\Modules\Compute\Specification;
use Appwrite\PubSub\Adapter\Redis as PubSub;
use Appwrite\URL\URL as AppwriteURL;
use Appwrite\Utopia\Request;
@@ -239,8 +240,6 @@ const METRIC_WEBHOOKS_SENT = 'webhooks.events.sent';
const METRIC_WEBHOOKS_FAILED = 'webhooks.events.failed';
const METRIC_WEBHOOK_ID_SENT = '{webhookInternalId}.webhooks.events.sent';
const METRIC_WEBHOOK_ID_FAILED = '{webhookInternalId}.webhooks.events.failed';
const METRIC_AUTH_METHOD_PHONE = 'auth.method.phone';
const METRIC_AUTH_METHOD_PHONE_COUNTRY_CODE = METRIC_AUTH_METHOD_PHONE . '.{countryCode}';
const METRIC_MESSAGES = 'messages';
@@ -271,6 +270,8 @@ const METRIC_FILES = 'files';
const METRIC_FILES_STORAGE = 'files.storage';
const METRIC_FILES_TRANSFORMATIONS = 'files.transformations';
const METRIC_BUCKET_ID_FILES_TRANSFORMATIONS = '{bucketInternalId}.files.transformations';
const METRIC_FILES_IMAGES_TRANSFORMED = 'files.imagesTransformed';
const METRIC_BUCKET_ID_FILES_IMAGES_TRANSFORMED = '{bucketInternalId}.files.imagesTransformed';
const METRIC_BUCKET_ID_FILES = '{bucketInternalId}.files';
const METRIC_BUCKET_ID_FILES_STORAGE = '{bucketInternalId}.files.storage';
const METRIC_SITES = 'sites';
@@ -318,6 +319,20 @@ const METRIC_SITE_ID_BUILDS_MB_SECONDS = '{siteInternalId}.builds.mbSeconds';
const METRIC_NETWORK_REQUESTS = 'network.requests';
const METRIC_NETWORK_INBOUND = 'network.inbound';
const METRIC_NETWORK_OUTBOUND = 'network.outbound';
const METRIC_MAU = 'users.mau';
const METRIC_DAU = 'users.dau';
const METRIC_WAU = 'users.wau';
const METRIC_WEBHOOKS = 'webhooks';
const METRIC_PLATFORMS = 'platforms';
const METRIC_PROVIDERS = 'providers';
const METRIC_TOPICS = 'topics';
const METRIC_TARGETS = 'targets';
const METRIC_PROVIDER_TYPE_TARGETS = '{providerType}.targets';
const METRIC_KEYS = 'keys';
const METRIC_RESOURCE_TYPE_ID_BUILDS = '{resourceType}.{resourceInternalId}.builds';
const METRIC_RESOURCE_TYPE_ID_BUILDS_STORAGE = '{resourceType}.{resourceInternalId}.builds.storage';
const METRIC_RESOURCE_TYPE_ID_DEPLOYMENTS = '{resourceType}.{resourceInternalId}.deployments';
const METRIC_RESOURCE_TYPE_ID_DEPLOYMENTS_STORAGE = '{resourceType}.{resourceInternalId}.deployments.storage';
// Resource types
@@ -351,6 +366,7 @@ Config::load('apis', __DIR__ . '/config/apis.php'); // List of APIs
Config::load('errors', __DIR__ . '/config/errors.php');
Config::load('oAuthProviders', __DIR__ . '/config/oAuthProviders.php');
Config::load('platforms', __DIR__ . '/config/platforms.php');
Config::load('console', __DIR__ . '/config/console.php');
Config::load('collections', __DIR__ . '/config/collections.php');
Config::load('frameworks', __DIR__ . '/config/frameworks.php');
Config::load('runtimes', __DIR__ . '/config/runtimes.php');
@@ -376,10 +392,9 @@ Config::load('storage-logos', __DIR__ . '/config/storage/logos.php');
Config::load('storage-mimes', __DIR__ . '/config/storage/mimes.php');
Config::load('storage-inputs', __DIR__ . '/config/storage/inputs.php');
Config::load('storage-outputs', __DIR__ . '/config/storage/outputs.php');
Config::load('runtime-specifications', __DIR__ . '/config/runtimes/specifications.php');
Config::load('framework-specifications', __DIR__ . '/config/frameworks/specifications.php');
Config::load('function-templates', __DIR__ . '/config/function-templates.php');
Config::load('site-templates', __DIR__ . '/config/site-templates.php');
Config::load('specifications', __DIR__ . '/config/specifications.php');
Config::load('templates-function', __DIR__ . '/config/templates/function.php');
Config::load('templates-site', __DIR__ . '/config/templates/site.php');
/**
* New DB Filters
@@ -824,6 +839,10 @@ $register->set('logger', function () {
$providerName = System::getEnv('_APP_LOGGING_PROVIDER', '');
$providerConfig = System::getEnv('_APP_LOGGING_CONFIG', '');
if (empty($providerConfig)) {
return;
}
try {
$loggingProvider = new DSN($providerConfig ?? '');
@@ -1198,15 +1217,15 @@ App::setResource('queueForWebhooks', function (Queue\Publisher $publisher) {
App::setResource('queueForRealtime', function () {
return new Realtime();
}, []);
App::setResource('queueForStatsUsage', function (Queue\Publisher $publisher) {
return new StatsUsage($publisher);
}, ['publisher']);
App::setResource('queueForAudits', function (Queue\Publisher $publisher) {
return new Audit($publisher);
}, ['publisher']);
App::setResource('queueForFunctions', function (Queue\Publisher $publisher) {
return new Func($publisher);
}, ['publisher']);
App::setResource('queueForUsage', function (Queue\Publisher $publisher) {
return new Usage($publisher);
}, ['publisher']);
App::setResource('queueForCertificates', function (Queue\Publisher $publisher) {
return new Certificate($publisher);
}, ['publisher']);
@@ -1411,45 +1430,7 @@ App::setResource('session', function (Document $user) {
}, ['user']);
App::setResource('console', function () {
return new Document([
'$id' => ID::custom('console'),
'$internalId' => ID::custom('console'),
'name' => 'Appwrite',
'$collection' => ID::custom('projects'),
'description' => 'Appwrite core engine',
'logo' => '',
'teamId' => null,
'webhooks' => [],
'keys' => [],
'platforms' => [
[
'$collection' => ID::custom('platforms'),
'name' => 'Localhost',
'type' => Origin::CLIENT_TYPE_WEB,
'hostname' => 'localhost',
], // Current host is added on app init
],
'legalName' => '',
'legalCountry' => '',
'legalState' => '',
'legalCity' => '',
'legalAddress' => '',
'legalTaxId' => '',
'auths' => [
'mockNumbers' => [],
'invites' => System::getEnv('_APP_CONSOLE_INVITES', 'enabled') === 'enabled',
'limit' => (System::getEnv('_APP_CONSOLE_WHITELIST_ROOT', 'enabled') === 'enabled') ? 1 : 0, // limit signup to 1 user
'duration' => Auth::TOKEN_EXPIRATION_LOGIN_LONG, // 1 Year in seconds
'sessionAlerts' => System::getEnv('_APP_CONSOLE_SESSION_ALERTS', 'disabled') === 'enabled'
],
'authWhitelistEmails' => (!empty(System::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null))) ? \explode(',', System::getEnv('_APP_CONSOLE_WHITELIST_EMAILS', null)) : [],
'authWhitelistIPs' => (!empty(System::getEnv('_APP_CONSOLE_WHITELIST_IPS', null))) ? \explode(',', System::getEnv('_APP_CONSOLE_WHITELIST_IPS', null)) : [],
'oAuthProviders' => [
'githubEnabled' => true,
'githubSecret' => System::getEnv('_APP_CONSOLE_GITHUB_SECRET', ''),
'githubAppid' => System::getEnv('_APP_CONSOLE_GITHUB_APP_ID', '')
],
]);
return new Document(Config::getParam('console'));
}, []);
App::setResource('dbForProject', function (Group $pools, Database $dbForPlatform, Cache $cache, Document $project) {
@@ -1568,6 +1549,39 @@ App::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform
};
}, ['pools', 'dbForPlatform', 'cache']);
App::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());
return $database;
}
$dbAdapter = $pools
->get('logs')
->pop()
->getResource();
$database = new Database(
$dbAdapter,
$cache
);
$database
->setSharedTables(true)
->setNamespace('logsV1')
->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS)
->setMaxQueryValues(APP_DATABASE_QUERY_MAX_VALUES);
// set tenant
if ($project !== null && !$project->isEmpty() && $project->getId() !== 'console') {
$database->setTenant($project->getInternalId());
}
return $database;
};
}, ['pools', 'cache']);
App::setResource('cache', function (Group $pools) {
$list = Config::getParam('pools-cache', []);
$adapters = [];
@@ -1635,6 +1649,7 @@ function getDevice(string $root, string $connection = ''): Device
$accessSecret = '';
$bucket = '';
$region = '';
$url = App::getEnv('_APP_STORAGE_S3_ENDPOINT', '');
try {
$dsn = new DSN($connection);
@@ -1649,7 +1664,7 @@ function getDevice(string $root, string $connection = ''): Device
switch ($device) {
case Storage::DEVICE_S3:
return new S3($root, $accessKey, $accessSecret, $bucket, $region, $acl);
return new S3($root, $accessKey, $accessSecret, $bucket, $region, $acl, $url);
case STORAGE::DEVICE_DO_SPACES:
$device = new DOSpaces($root, $accessKey, $accessSecret, $bucket, $region, $acl);
$device->setHttpVersion(S3::HTTP_VERSION_1_1);
@@ -1675,7 +1690,8 @@ function getDevice(string $root, string $connection = ''): Device
$s3Region = System::getEnv('_APP_STORAGE_S3_REGION', '');
$s3Bucket = System::getEnv('_APP_STORAGE_S3_BUCKET', '');
$s3Acl = 'private';
return new S3($root, $s3AccessKey, $s3SecretKey, $s3Bucket, $s3Region, $s3Acl);
$s3EndpointUrl = App::getEnv('_APP_STORAGE_S3_ENDPOINT', '');
return new S3($root, $s3AccessKey, $s3SecretKey, $s3Bucket, $s3Region, $s3Acl, $s3EndpointUrl);
case Storage::DEVICE_DO_SPACES:
$doSpacesAccessKey = System::getEnv('_APP_STORAGE_DO_SPACES_ACCESS_KEY', '');
$doSpacesSecretKey = System::getEnv('_APP_STORAGE_DO_SPACES_SECRET', '');
@@ -1910,13 +1926,32 @@ App::setResource(
fn () => fn (Document $project, string $resourceType, ?string $resourceId) => false
);
App::setResource('previewHostname', function (Request $request) {
App::setResource('previewHostname', function (Request $request, ?Key $apiKey) {
$allowed = false;
if (App::isDevelopment()) {
$host = $request->getQuery('appwrite-hostname') ?? '';
$allowed = true;
} elseif (!\is_null($apiKey) && $apiKey->getHostnameOverride() === true) {
$allowed = true;
}
if ($allowed) {
$host = $request->getQuery('appwrite-hostname', $request->getHeader('x-appwrite-hostname', ''));
if (!empty($host)) {
return $host;
}
}
return '';
}, ['request']);
}, ['request', 'apiKey']);
App::setResource('apiKey', function (Request $request, Document $project): ?Key {
$key = $request->getHeader('x-appwrite-key');
if (empty($key)) {
return null;
}
return Key::decode($project, $key);
}, ['request', 'project']);
+185
View File
@@ -0,0 +1,185 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>404 Not Found</title>
<style>
* {
margin: 0;
padding: 0;
}
body {
background-color: #FFFFFF;
}
.main {
display: flex;
min-height: 100vh;
width: 100vw;
align-items: center;
justify-content: center;
}
.content {
margin-left: auto;
margin-right: auto;
max-width: 400px;
}
span {
padding: var(--space-1, 2px) var(--space-3, 6px);
border-radius: var(--border-radius-XS, 6px);
background: var(--color-overlay-on-neutral, rgba(0, 0, 0, 0.06));
color: var(--color-fgColor-neutral-secondary, #56565C);
text-align: center;
font-family: var(--font-family-sansSerif, Inter);
font-size: var(--font-size-S, 14px);
font-style: normal;
font-weight: 400;
line-height: 140%;
letter-spacing: -0.063px;
}
h1 {
color: var(--color-fgColor-neutral-primary, #2D2D31);
text-align: center;
font-family: var(--font-family-sansSerif, Inter);
font-size: var(--font-size-XXXL, 32px);
font-style: normal;
font-weight: 400;
line-height: 140%;
letter-spacing: -0.144px;
margin-top: 8px;
margin-bottom: 32px;
}
button {
border-radius: var(--border-radius-S, 8px);
font-family: var(--font-family-sansSerif, Inter);
font-size: var(--font-size-S, 14px);
font-style: normal;
font-weight: 500;
line-height: 140%;
letter-spacing: -0.063px;
padding: var(--space-3, 6px) var(--space-5, 10px);
cursor: pointer;
border: var(--border-width-S, 1px) solid var(--color-border-neutral-strong, #D8D8DB);
background: var(--color-bgColor-neutral-primary, #FFF);
color: var(--color-fgColor-neutral-secondary, #56565C);
}
.center {
display: flex;
justify-content: center;
}
.brand {
position: absolute;
width: 100%;
bottom: 32px;
display: flex;
justify-content: center;
align-items: center;
gap: 8px;
}
.brand p {
font-family: var(--font-family-monospace, "Aeonik Fono");
font-size: var(--font-size-XS, 12px);
font-style: normal;
font-weight: 400;
line-height: 130%;
letter-spacing: 0.96px;
text-transform: uppercase;
color: var(--color-fgColor-neutral-secondary, #56565C);
}
.brand svg {
height: 20px;
}
.logo-dark {
display: none;
}
@media (prefers-color-scheme: dark) {
body {
background-color: #1D1D21;
}
h1 {
color: var(--color-fgColor-neutral-primary, #EDEDF0);
}
button {
border: var(--border-width-S, 1px) solid var(--color-border-neutral-strong, #414146);
background: var(--color-bgColor-neutral-primary, #1D1D21);
color: var(--color-fgColor-neutral-secondary, #C3C3C6);
}
.brand p {
color: var(--color-fgColor-neutral-secondary, #C3C3C6);
}
span {
background: var(--color-overlay-on-neutral, rgba(255, 255, 255, 0.20));
color: var(--color-fgColor-neutral-secondary, #C3C3C6);
}
.logo-light {
display: none;
}
.logo-dark {
display: block;
}
}
</style>
</head>
<body>
<div class="main">
<div class="content">
<div class="center"><span>Page not found</span></div>
<h1>The page youre looking for doesnt exist.</h1>
<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>
+70 -6
View File
@@ -116,6 +116,7 @@ $image = $this->getParam('image', '');
- _APP_STORAGE_S3_SECRET
- _APP_STORAGE_S3_REGION
- _APP_STORAGE_S3_BUCKET
- _APP_STORAGE_S3_ENDPOINT
- _APP_STORAGE_DO_SPACES_ACCESS_KEY
- _APP_STORAGE_DO_SPACES_SECRET
- _APP_STORAGE_DO_SPACES_REGION
@@ -320,6 +321,7 @@ $image = $this->getParam('image', '');
- _APP_STORAGE_S3_SECRET
- _APP_STORAGE_S3_REGION
- _APP_STORAGE_S3_BUCKET
- _APP_STORAGE_S3_ENDPOINT
- _APP_STORAGE_DO_SPACES_ACCESS_KEY
- _APP_STORAGE_DO_SPACES_SECRET
- _APP_STORAGE_DO_SPACES_REGION
@@ -415,6 +417,7 @@ $image = $this->getParam('image', '');
- _APP_STORAGE_S3_SECRET
- _APP_STORAGE_S3_REGION
- _APP_STORAGE_S3_BUCKET
- _APP_STORAGE_S3_ENDPOINT
- _APP_STORAGE_DO_SPACES_ACCESS_KEY
- _APP_STORAGE_DO_SPACES_SECRET
- _APP_STORAGE_DO_SPACES_REGION
@@ -570,6 +573,7 @@ $image = $this->getParam('image', '');
- _APP_STORAGE_S3_SECRET
- _APP_STORAGE_S3_REGION
- _APP_STORAGE_S3_BUCKET
- _APP_STORAGE_S3_ENDPOINT
- _APP_STORAGE_DO_SPACES_ACCESS_KEY
- _APP_STORAGE_DO_SPACES_SECRET
- _APP_STORAGE_DO_SPACES_REGION
@@ -651,10 +655,69 @@ $image = $this->getParam('image', '');
- _APP_MAINTENANCE_RETENTION_USAGE_HOURLY
- _APP_MAINTENANCE_RETENTION_SCHEDULES
appwrite-worker-usage:
appwrite-task-stats-resources:
image: <?php echo $organization; ?>/<?php echo $image; ?>:<?php echo $version."\n"; ?>
entrypoint: worker-usage
container_name: appwrite-worker-usage
container_name: appwrite-task-stats-resources
entrypoint: stats-resources
<<: *x-logging
networks:
- appwrite
volumes:
- ./app:/usr/src/code/app
- ./src:/usr/src/code/src
depends_on:
- redis
- mariadb
environment:
- _APP_ENV
- _APP_WORKER_PER_CORE
- _APP_OPENSSL_KEY_V1
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
- _APP_REDIS_HOST
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
- _APP_USAGE_STATS
- _APP_LOGGING_CONFIG
- _APP_DATABASE_SHARED_TABLES
- _APP_STATS_RESOURCES_INTERVAL
appwrite-worker-stats-resources:
image: <?php echo $organization; ?>/<?php echo $image; ?>:<?php echo $version."\n"; ?>
entrypoint: worker-stats-resources
container_name: appwrite-worker-stats-resources
<<: *x-logging
restart: unless-stopped
networks:
- appwrite
depends_on:
- redis
- mariadb
environment:
- _APP_ENV
- _APP_WORKER_PER_CORE
- _APP_OPENSSL_KEY_V1
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
- _APP_REDIS_HOST
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
- _APP_USAGE_STATS
- _APP_LOGGING_CONFIG
- _APP_STATS_RESOURCES_INTERVAL
appwrite-worker-stats-usage:
image: <?php echo $organization; ?>/<?php echo $image; ?>:<?php echo $version."\n"; ?>
entrypoint: worker-stats-usage
container_name: appwrite-worker-stats-usage
<<: *x-logging
restart: unless-stopped
networks:
@@ -679,11 +742,11 @@ $image = $this->getParam('image', '');
- _APP_LOGGING_CONFIG
- _APP_USAGE_AGGREGATION_INTERVAL
appwrite-worker-usage-dump:
appwrite-worker-stats-usage-dump:
image: <?php echo $organization; ?>/<?php echo $image; ?>:<?php echo $version."\n"; ?>
entrypoint: worker-usage-dump
entrypoint: worker-stats-usage-dump
<<: *x-logging
container_name: appwrite-worker-usage-dump
container_name: appwrite-worker-stats-usage-dump
restart: unless-stopped
networks:
- appwrite
@@ -824,6 +887,7 @@ $image = $this->getParam('image', '');
- OPR_EXECUTOR_STORAGE_S3_SECRET=$_APP_STORAGE_S3_SECRET
- OPR_EXECUTOR_STORAGE_S3_REGION=$_APP_STORAGE_S3_REGION
- OPR_EXECUTOR_STORAGE_S3_BUCKET=$_APP_STORAGE_S3_BUCKET
- OPR_EXECUTOR_STORAGE_S3_ENDPOINT=$_APP_STORAGE_S3_ENDPOINT
- OPR_EXECUTOR_STORAGE_DO_SPACES_ACCESS_KEY=$_APP_STORAGE_DO_SPACES_ACCESS_KEY
- OPR_EXECUTOR_STORAGE_DO_SPACES_SECRET=$_APP_STORAGE_DO_SPACES_SECRET
- OPR_EXECUTOR_STORAGE_DO_SPACES_REGION=$_APP_STORAGE_DO_SPACES_REGION
+51 -6
View File
@@ -13,8 +13,12 @@ use Appwrite\Event\Func;
use Appwrite\Event\Mail;
use Appwrite\Event\Messaging;
use Appwrite\Event\Migration;
use Appwrite\Event\Usage;
use Appwrite\Event\UsageDump;
use Appwrite\Event\Realtime;
use Appwrite\Event\StatsUsage;
use Appwrite\Event\StatsUsageDump;
/** remove */
/** /remove */
use Appwrite\Event\Webhook;
use Appwrite\Platform\Appwrite;
use Swoole\Runtime;
use Utopia\Abuse\Adapters\TimeLimit\Redis as TimeLimitRedis;
@@ -173,6 +177,39 @@ Server::setResource('getProjectDB', function (Group $pools, Database $dbForPlatf
};
}, ['pools', 'dbForPlatform', 'cache']);
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());
return $database;
}
$dbAdapter = $pools
->get('logs')
->pop()
->getResource();
$database = new Database(
$dbAdapter,
$cache
);
$database
->setSharedTables(true)
->setNamespace('logsV1')
->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS)
->setMaxQueryValues(APP_DATABASE_QUERY_MAX_VALUES);
// set tenant
if ($project !== null && !$project->isEmpty() && $project->getId() !== 'console') {
$database->setTenant($project->getInternalId());
}
return $database;
};
}, ['pools', 'cache']);
Server::setResource('abuseRetention', function () {
return time() - (int) System::getEnv('_APP_MAINTENANCE_RETENTION_ABUSE', 86400);
});
@@ -232,12 +269,12 @@ Server::setResource('consumer', function (Group $pools) {
return $pools->get('consumer')->pop()->getResource();
}, ['pools']);
Server::setResource('queueForUsage', function (Publisher $publisher) {
return new Usage($publisher);
Server::setResource('queueForStatsUsage', function (Publisher $publisher) {
return new StatsUsage($publisher);
}, ['publisher']);
Server::setResource('queueForUsageDump', function (Publisher $publisher) {
return new UsageDump($publisher);
Server::setResource('queueForStatsUsageDump', function (Publisher $publisher) {
return new StatsUsageDump($publisher);
}, ['publisher']);
Server::setResource('queueForDatabase', function (Publisher $publisher) {
@@ -268,10 +305,18 @@ Server::setResource('queueForAudits', function (Publisher $publisher) {
return new Audit($publisher);
}, ['publisher']);
Server::setResource('queueForWebhooks', function (Publisher $publisher) {
return new Webhook($publisher);
}, ['publisher']);
Server::setResource('queueForFunctions', function (Publisher $publisher) {
return new Func($publisher);
}, ['publisher']);
Server::setResource('queueForRealtime', function () {
return new Realtime();
}, []);
Server::setResource('queueForCertificates', function (Publisher $publisher) {
return new Certificate($publisher);
}, ['publisher']);
Executable
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php screenshot $@
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php stats-resources $@
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
php /usr/src/code/app/worker.php stats-resources $@
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
php /usr/src/code/app/worker.php stats-usage $@
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
php /usr/src/code/app/worker.php stats-usage-dump $@
-3
View File
@@ -1,3 +0,0 @@
#!/bin/sh
php /usr/src/code/app/worker.php usage $@
-3
View File
@@ -1,3 +0,0 @@
#!/bin/sh
php /usr/src/code/app/worker.php usage-dump $@
+18 -15
View File
@@ -14,7 +14,8 @@
"test": "vendor/bin/phpunit",
"lint": "vendor/bin/pint --test",
"format": "vendor/bin/pint",
"bench": "vendor/bin/phpbench run --report=benchmark"
"bench": "vendor/bin/phpbench run --report=benchmark",
"check": "./vendor/bin/phpstan analyse -c phpstan.neon"
},
"autoload": {
"psr-4": {
@@ -43,23 +44,24 @@
"ext-openssl": "*",
"ext-zlib": "*",
"ext-sockets": "*",
"appwrite/php-runtimes": "0.17.*",
"appwrite/php-runtimes": "0.18.*",
"appwrite/php-clamav": "2.0.*",
"utopia-php/abuse": "0.49.*",
"utopia-php/abuse": "0.51.*",
"utopia-php/analytics": "0.10.*",
"utopia-php/audit": "0.49.*",
"utopia-php/cache": "0.11.*",
"utopia-php/audit": "0.54.0",
"utopia-php/cache": "0.12.*",
"utopia-php/cli": "0.15.*",
"utopia-php/config": "0.2.*",
"utopia-php/database": "0.58.4",
"utopia-php/detector": "0.1.*",
"utopia-php/database": "0.60.*",
"utopia-php/domains": "0.5.*",
"utopia-php/dsn": "0.2.1",
"utopia-php/framework": "dev-fix-prevent-duplicate-compression as 0.33.99",
"utopia-php/framework": "0.33.*",
"utopia-php/fetch": "0.3.*",
"utopia-php/image": "0.7.*",
"utopia-php/image": "0.8.*",
"utopia-php/locale": "0.4.*",
"utopia-php/logger": "0.6.*",
"utopia-php/messaging": "0.14.*",
"utopia-php/messaging": "0.16.*",
"utopia-php/migration": "0.6.*",
"utopia-php/orchestration": "0.9.*",
"utopia-php/platform": "0.7.3",
@@ -71,7 +73,7 @@
"utopia-php/swoole": "0.8.*",
"utopia-php/system": "0.9.*",
"utopia-php/telemetry": "0.1.*",
"utopia-php/vcs": "0.8.*",
"utopia-php/vcs": "0.9.*",
"utopia-php/websocket": "0.1.*",
"matomo/device-detector": "6.1.*",
"dragonmantank/cron-expression": "3.3.2",
@@ -84,12 +86,13 @@
},
"require-dev": {
"ext-fileinfo": "*",
"appwrite/sdk-generator": "0.39.32",
"phpunit/phpunit": "9.5.20",
"appwrite/sdk-generator": "0.40.*",
"phpunit/phpunit": "9.*",
"swoole/ide-helper": "5.1.2",
"textalk/websocket": "1.5.7",
"laravel/pint": "^1.14",
"phpbench/phpbench": "^1.2"
"phpstan/phpstan": "1.8.*",
"textalk/websocket": "1.5.*",
"laravel/pint": "1.*",
"phpbench/phpbench": "1.*"
},
"provide": {
"ext-phpiredis": "*"
Generated
+304 -554
View File
File diff suppressed because it is too large Load Diff
+90 -10
View File
@@ -76,6 +76,7 @@ services:
- appwrite-config:/storage/config:rw
- appwrite-certificates:/storage/certificates:rw
- appwrite-functions:/storage/functions:rw
- appwrite-sites:/storage/sites:rw
- appwrite-builds:/storage/builds:rw
- ./phpunit.xml:/usr/src/code/phpunit.xml
- ./tests:/usr/src/code/tests
@@ -141,6 +142,7 @@ services:
- _APP_STORAGE_S3_SECRET
- _APP_STORAGE_S3_REGION
- _APP_STORAGE_S3_BUCKET
- _APP_STORAGE_S3_ENDPOINT
- _APP_STORAGE_DO_SPACES_ACCESS_KEY
- _APP_STORAGE_DO_SPACES_SECRET
- _APP_STORAGE_DO_SPACES_REGION
@@ -204,7 +206,7 @@ services:
appwrite-console:
<<: *x-logging
container_name: appwrite-console
image: appwrite/console:5.3.0-sites-rc.5
image: appwrite/console:5.3.0-sites-rc.24
restart: unless-stopped
networks:
- appwrite
@@ -347,6 +349,7 @@ services:
- appwrite-uploads:/storage/uploads:rw
- appwrite-cache:/storage/cache:rw
- appwrite-functions:/storage/functions:rw
- appwrite-sites:/storage/sites:rw
- appwrite-builds:/storage/builds:rw
- appwrite-certificates:/storage/certificates:rw
- ./app:/usr/src/code/app
@@ -369,6 +372,7 @@ services:
- _APP_STORAGE_S3_SECRET
- _APP_STORAGE_S3_REGION
- _APP_STORAGE_S3_BUCKET
- _APP_STORAGE_S3_ENDPOINT
- _APP_STORAGE_DO_SPACES_ACCESS_KEY
- _APP_STORAGE_DO_SPACES_SECRET
- _APP_STORAGE_DO_SPACES_REGION
@@ -432,7 +436,9 @@ services:
- appwrite
volumes:
- appwrite-functions:/storage/functions:rw
- appwrite-sites:/storage/sites:rw
- appwrite-builds:/storage/builds:rw
- appwrite-uploads:/storage/uploads:rw
- ./app:/usr/src/code/app
- ./src:/usr/src/code/src
depends_on:
@@ -470,6 +476,7 @@ services:
- _APP_STORAGE_S3_SECRET
- _APP_STORAGE_S3_REGION
- _APP_STORAGE_S3_BUCKET
- _APP_STORAGE_S3_ENDPOINT
- _APP_STORAGE_DO_SPACES_ACCESS_KEY
- _APP_STORAGE_DO_SPACES_SECRET
- _APP_STORAGE_DO_SPACES_REGION
@@ -636,6 +643,7 @@ services:
- _APP_STORAGE_S3_SECRET
- _APP_STORAGE_S3_REGION
- _APP_STORAGE_S3_BUCKET
- _APP_STORAGE_S3_ENDPOINT
- _APP_STORAGE_DO_SPACES_ACCESS_KEY
- _APP_STORAGE_DO_SPACES_SECRET
- _APP_STORAGE_DO_SPACES_REGION
@@ -727,10 +735,72 @@ services:
- _APP_MAINTENANCE_DELAY
- _APP_DATABASE_SHARED_TABLES
appwrite-worker-usage:
entrypoint: worker-usage
appwrite-task-stats-resources:
container_name: appwrite-task-stats-resources
entrypoint: stats-resources
<<: *x-logging
container_name: appwrite-worker-usage
image: appwrite-dev
networks:
- appwrite
volumes:
- ./app:/usr/src/code/app
- ./src:/usr/src/code/src
depends_on:
- redis
- mariadb
environment:
- _APP_ENV
- _APP_WORKER_PER_CORE
- _APP_OPENSSL_KEY_V1
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
- _APP_REDIS_HOST
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
- _APP_USAGE_STATS
- _APP_LOGGING_CONFIG
- _APP_DATABASE_SHARED_TABLES
- _APP_STATS_RESOURCES_INTERVAL
appwrite-worker-stats-resources:
entrypoint: worker-stats-resources
<<: *x-logging
container_name: appwrite-worker-stats-resources
image: appwrite-dev
networks:
- appwrite
volumes:
- ./app:/usr/src/code/app
- ./src:/usr/src/code/src
depends_on:
- redis
- mariadb
environment:
- _APP_ENV
- _APP_WORKER_PER_CORE
- _APP_OPENSSL_KEY_V1
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
- _APP_REDIS_HOST
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
- _APP_USAGE_STATS
- _APP_LOGGING_CONFIG
- _APP_USAGE_AGGREGATION_INTERVAL
- _APP_DATABASE_SHARED_TABLES
appwrite-worker-stats-usage:
entrypoint: worker-stats-usage
<<: *x-logging
container_name: appwrite-worker-stats-usage
image: appwrite-dev
networks:
- appwrite
@@ -758,10 +828,10 @@ services:
- _APP_USAGE_AGGREGATION_INTERVAL
- _APP_DATABASE_SHARED_TABLES
appwrite-worker-usage-dump:
entrypoint: worker-usage-dump
appwrite-worker-stats-usage-dump:
entrypoint: worker-stats-usage-dump
<<: *x-logging
container_name: appwrite-worker-usage-dump
container_name: appwrite-worker-stats-usage-dump
image: appwrite-dev
networks:
- appwrite
@@ -788,7 +858,8 @@ services:
- _APP_LOGGING_CONFIG
- _APP_USAGE_AGGREGATION_INTERVAL
- _APP_DATABASE_SHARED_TABLES
- _APP_STATS_USAGE_DUAL_WRITING_DBS
appwrite-task-scheduler-functions:
entrypoint: schedule-functions
<<: *x-logging
@@ -880,12 +951,18 @@ services:
environment:
- _APP_ASSISTANT_OPENAI_API_KEY
appwrite-browser:
container_name: appwrite-browser
image: appwrite/browser:0.2.2
networks:
- appwrite
openruntimes-executor:
container_name: openruntimes-executor
hostname: exc1
<<: *x-logging
stop_signal: SIGINT
image: openruntimes/executor:0.7.4
image: openruntimes/executor:0.7.10
restart: unless-stopped
networks:
- appwrite
@@ -894,6 +971,7 @@ services:
- /var/run/docker.sock:/var/run/docker.sock
- appwrite-builds:/storage/builds:rw
- appwrite-functions:/storage/functions:rw
- appwrite-sites:/storage/sites:rw
# Host mount nessessary to share files between executor and runtimes.
# It's not possible to share mount file between 2 containers without host mount (copying is too slow)
- /tmp:/tmp:rw
@@ -907,13 +985,14 @@ services:
- OPR_EXECUTOR_ENV=$_APP_ENV
- OPR_EXECUTOR_RUNTIMES=$_APP_FUNCTIONS_RUNTIMES,$_APP_SITES_RUNTIMES
- OPR_EXECUTOR_SECRET=$_APP_EXECUTOR_SECRET
- OPR_EXECUTOR_RUNTIME_VERSIONS=v2,v4,v4rc
- OPR_EXECUTOR_RUNTIME_VERSIONS=v2,v5
- OPR_EXECUTOR_LOGGING_CONFIG=$_APP_LOGGING_CONFIG
- OPR_EXECUTOR_STORAGE_DEVICE=$_APP_STORAGE_DEVICE
- OPR_EXECUTOR_STORAGE_S3_ACCESS_KEY=$_APP_STORAGE_S3_ACCESS_KEY
- OPR_EXECUTOR_STORAGE_S3_SECRET=$_APP_STORAGE_S3_SECRET
- OPR_EXECUTOR_STORAGE_S3_REGION=$_APP_STORAGE_S3_REGION
- OPR_EXECUTOR_STORAGE_S3_BUCKET=$_APP_STORAGE_S3_BUCKET
- OPR_EXECUTOR_STORAGE_S3_ENDPOINT=$_APP_STORAGE_S3_ENDPOINT
- OPR_EXECUTOR_STORAGE_DO_SPACES_ACCESS_KEY=$_APP_STORAGE_DO_SPACES_ACCESS_KEY
- OPR_EXECUTOR_STORAGE_DO_SPACES_SECRET=$_APP_STORAGE_DO_SPACES_SECRET
- OPR_EXECUTOR_STORAGE_DO_SPACES_REGION=$_APP_STORAGE_DO_SPACES_REGION
@@ -1064,5 +1143,6 @@ volumes:
appwrite-uploads:
appwrite-certificates:
appwrite-functions:
appwrite-sites:
appwrite-builds:
appwrite-config:
@@ -1,23 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Functions;
Client client = new Client(context)
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("<YOUR_PROJECT_ID>"); // Your project ID
Functions functions = new Functions(client);
functions.getDeploymentDownload(
"<FUNCTION_ID>", // functionId
"<DEPLOYMENT_ID>", // deploymentId
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,22 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Functions;
Client client = new Client(context)
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("<YOUR_PROJECT_ID>"); // Your project ID
Functions functions = new Functions(client);
functions.getTemplate(
"<TEMPLATE_ID>", // templateId
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,25 +0,0 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Functions;
Client client = new Client(context)
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("<YOUR_PROJECT_ID>"); // Your project ID
Functions functions = new Functions(client);
functions.listTemplates(
listOf(), // runtimes (optional)
listOf(), // useCases (optional)
1, // limit (optional)
0, // offset (optional)
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -1,14 +0,0 @@
import io.appwrite.Client
import io.appwrite.coroutines.CoroutineCallback
import io.appwrite.services.Functions
val client = Client(context)
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("<YOUR_PROJECT_ID>") // Your project ID
val functions = Functions(client)
val result = functions.getDeploymentDownload(
functionId = "<FUNCTION_ID>",
deploymentId = "<DEPLOYMENT_ID>",
)
@@ -1,13 +0,0 @@
import io.appwrite.Client
import io.appwrite.coroutines.CoroutineCallback
import io.appwrite.services.Functions
val client = Client(context)
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("<YOUR_PROJECT_ID>") // Your project ID
val functions = Functions(client)
val result = functions.getTemplate(
templateId = "<TEMPLATE_ID>",
)
@@ -1,16 +0,0 @@
import io.appwrite.Client
import io.appwrite.coroutines.CoroutineCallback
import io.appwrite.services.Functions
val client = Client(context)
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("<YOUR_PROJECT_ID>") // Your project ID
val functions = Functions(client)
val result = functions.listTemplates(
runtimes = listOf(), // (optional)
useCases = listOf(), // (optional)
limit = 1, // (optional)
offset = 0, // (optional)
)
@@ -6,7 +6,7 @@ let client = Client()
let account = Account(client)
let result = try await account.updateMfaChallenge(
let session = try await account.updateMfaChallenge(
challengeId: "<CHALLENGE_ID>",
otp: "<OTP>"
)
@@ -1,13 +0,0 @@
import Appwrite
let client = Client()
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("<YOUR_PROJECT_ID>") // Your project ID
let functions = Functions(client)
let bytes = try await functions.getDeploymentDownload(
functionId: "<FUNCTION_ID>",
deploymentId: "<DEPLOYMENT_ID>"
)
@@ -1,12 +0,0 @@
import Appwrite
let client = Client()
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("<YOUR_PROJECT_ID>") // Your project ID
let functions = Functions(client)
let templateFunction = try await functions.getTemplate(
templateId: "<TEMPLATE_ID>"
)
@@ -1,15 +0,0 @@
import Appwrite
let client = Client()
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("<YOUR_PROJECT_ID>") // Your project ID
let functions = Functions(client)
let templateFunctionList = try await functions.listTemplates(
runtimes: [], // optional
useCases: [], // optional
limit: 1, // optional
offset: 0 // optional
)
@@ -6,7 +6,7 @@ Client client = Client()
Account account = Account(client);
result = await account.updateMfaChallenge(
Session result = await account.updateMfaChallenge(
challengeId: '<CHALLENGE_ID>',
otp: '<OTP>',
);
@@ -1,29 +0,0 @@
import 'package:appwrite/appwrite.dart';
Client client = Client()
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('<YOUR_PROJECT_ID>'); // Your project ID
Functions functions = Functions(client);
// Downloading file
UInt8List bytes = await functions.getDeploymentDownload(
functionId: '<FUNCTION_ID>',
deploymentId: '<DEPLOYMENT_ID>',
)
final file = File('path_to_file/filename.ext');
file.writeAsBytesSync(bytes);
// Displaying image preview
FutureBuilder(
future: functions.getDeploymentDownload(
functionId:'<FUNCTION_ID>' ,
deploymentId:'<DEPLOYMENT_ID>' ,
), // Works for both public file and private file, for private files you need to be logged in
builder: (context, snapshot) {
return snapshot.hasData && snapshot.data != null
? Image.memory(snapshot.data)
: CircularProgressIndicator();
}
);
@@ -1,11 +0,0 @@
import 'package:appwrite/appwrite.dart';
Client client = Client()
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('<YOUR_PROJECT_ID>'); // Your project ID
Functions functions = Functions(client);
TemplateFunction result = await functions.getTemplate(
templateId: '<TEMPLATE_ID>',
);
@@ -1,14 +0,0 @@
import 'package:appwrite/appwrite.dart';
Client client = Client()
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('<YOUR_PROJECT_ID>'); // Your project ID
Functions functions = Functions(client);
TemplateFunctionList result = await functions.listTemplates(
runtimes: [], // optional
useCases: [], // optional
limit: 1, // optional
offset: 0, // optional
);
@@ -3,6 +3,34 @@ mutation {
challengeId: "<CHALLENGE_ID>",
otp: "<OTP>"
) {
status
_id
_createdAt
_updatedAt
userId
expire
provider
providerUid
providerAccessToken
providerAccessTokenExpiry
providerRefreshToken
ip
osCode
osName
osVersion
clientType
clientCode
clientName
clientVersion
clientEngine
clientEngineVersion
deviceName
deviceBrand
deviceModel
countryCode
countryName
current
factors
secret
mfaUpdatedAt
}
}
@@ -1,8 +0,0 @@
query {
functionsGetDeploymentDownload(
functionId: "<FUNCTION_ID>",
deploymentId: "<DEPLOYMENT_ID>"
) {
status
}
}
@@ -1,35 +0,0 @@
query {
functionsGetTemplate(
templateId: "<TEMPLATE_ID>"
) {
icon
id
name
tagline
permissions
events
cron
timeout
useCases
runtimes {
name
commands
entrypoint
providerRootDirectory
}
instructions
vcsProvider
providerRepositoryId
providerOwner
providerVersion
variables {
name
description
value
placeholder
required
type
}
scopes
}
}
@@ -1,41 +0,0 @@
query {
functionsListTemplates(
runtimes: [],
useCases: [],
limit: 1,
offset: 0
) {
total
templates {
icon
id
name
tagline
permissions
events
cron
timeout
useCases
runtimes {
name
commands
entrypoint
providerRootDirectory
}
instructions
vcsProvider
providerRepositoryId
providerOwner
providerVersion
variables {
name
description
value
placeholder
required
type
}
scopes
}
}
}
@@ -1,14 +0,0 @@
import { Client, Functions } from "react-native-appwrite";
const client = new Client()
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('<YOUR_PROJECT_ID>'); // Your project ID
const functions = new Functions(client);
const result = functions.getDeploymentDownload(
'<FUNCTION_ID>', // functionId
'<DEPLOYMENT_ID>' // deploymentId
);
console.log(result);
@@ -1,13 +0,0 @@
import { Client, Functions } from "react-native-appwrite";
const client = new Client()
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('<YOUR_PROJECT_ID>'); // Your project ID
const functions = new Functions(client);
const result = await functions.getTemplate(
'<TEMPLATE_ID>' // templateId
);
console.log(result);
@@ -1,16 +0,0 @@
import { Client, Functions } from "react-native-appwrite";
const client = new Client()
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('<YOUR_PROJECT_ID>'); // Your project ID
const functions = new Functions(client);
const result = await functions.listTemplates(
[], // runtimes (optional)
[], // useCases (optional)
1, // limit (optional)
0 // offset (optional)
);
console.log(result);
@@ -1,8 +0,0 @@
GET /v1/functions/{functionId}/deployments/{deploymentId}/download HTTP/1.1
Host: cloud.appwrite.io
Content-Type: application/json
X-Appwrite-Response-Format: 1.6.0
X-Appwrite-Project: <YOUR_PROJECT_ID>
X-Appwrite-Session:
X-Appwrite-JWT: <YOUR_JWT>
@@ -1,6 +0,0 @@
GET /v1/functions/templates/{templateId} HTTP/1.1
Host: cloud.appwrite.io
Content-Type: application/json
X-Appwrite-Response-Format: 1.6.0
X-Appwrite-Project: <YOUR_PROJECT_ID>
@@ -1,6 +0,0 @@
GET /v1/functions/templates HTTP/1.1
Host: cloud.appwrite.io
Content-Type: application/json
X-Appwrite-Response-Format: 1.6.0
X-Appwrite-Project: <YOUR_PROJECT_ID>
@@ -1,14 +0,0 @@
import { Client, Functions } from "appwrite";
const client = new Client()
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('<YOUR_PROJECT_ID>'); // Your project ID
const functions = new Functions(client);
const result = functions.getDeploymentDownload(
'<FUNCTION_ID>', // functionId
'<DEPLOYMENT_ID>' // deploymentId
);
console.log(result);
@@ -1,13 +0,0 @@
import { Client, Functions } from "appwrite";
const client = new Client()
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('<YOUR_PROJECT_ID>'); // Your project ID
const functions = new Functions(client);
const result = await functions.getTemplate(
'<TEMPLATE_ID>' // templateId
);
console.log(result);
@@ -1,16 +0,0 @@
import { Client, Functions } from "appwrite";
const client = new Client()
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
.setProject('<YOUR_PROJECT_ID>'); // Your project ID
const functions = new Functions(client);
const result = await functions.listTemplates(
[], // runtimes (optional)
[], // useCases (optional)
1, // limit (optional)
0 // offset (optional)
);
console.log(result);
@@ -1,3 +0,0 @@
appwrite functions downloadDeployment \
--functionId <FUNCTION_ID> \
--deploymentId <DEPLOYMENT_ID>
@@ -1 +0,0 @@
appwrite functions getSpecifications
@@ -1,3 +0,0 @@
appwrite migrations createFirebaseOAuthMigration \
--resources one two three \
--projectId <PROJECT_ID>
@@ -1 +0,0 @@
appwrite migrations deleteFirebaseAuth
@@ -1,3 +0,0 @@
appwrite migrations getFirebaseReportOAuth \
--resources one two three \
--projectId <PROJECT_ID>

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