Compare commits

...
Author SHA1 Message Date
Vincent (Wen Yu) Ge 03bfed4e25 Update create-document description and improve error message for unknown attribute. 2023-04-24 22:54:01 +00:00
Torsten DittmannandGitHub 495a17a290 Merge pull request #5405 from appwrite/feat-ci-release
ci: release action
2023-04-21 12:05:33 +02:00
Torsten Dittmann 097030c348 fix:: adapt to review 2023-04-21 11:58:59 +02:00
Torsten Dittmann 725ebfcd44 fix: ci version numbers 2023-04-20 22:15:29 +02:00
Torsten Dittmann ba1e5a7159 ci: use proper versions 2023-04-20 21:46:29 +02:00
Torsten Dittmann 7d119aa68c ci: try sharing console build for all 2023-04-19 14:03:23 +02:00
Torsten Dittmann 590ae9cfe4 update tags 2023-04-19 13:55:05 +02:00
Torsten Dittmann a769a18ba0 update tags 2023-04-19 13:54:48 +02:00
Torsten DittmannandGitHub 08e5dc1c40 Update release.yml 2023-04-19 13:25:12 +02:00
Torsten Dittmann 85b8728e71 fix: change name 2023-04-19 13:23:14 +02:00
Torsten Dittmann b3c2273780 ci: release action 2023-04-19 13:22:13 +02:00
Christy JacobandGitHub 62bdc77b93 Merge pull request #5377 from appwrite/fix-function-timeout-desc
Update description for _APP_FUNCTIONS_INACTIVE_THRESHOLD
2023-04-17 22:55:14 +04:00
Vincent (Wen Yu) GeandGitHub b6c43e2ccf Update app/config/variables.php 2023-04-17 14:02:11 -04:00
Vincent (Wen Yu) GeandGitHub 166b446fe7 Update description for _APP_FUNCTIONS_INACTIVE_THRESHOLD 2023-04-14 14:31:22 -04:00
Torsten DittmannandGitHub e5fa4883b2 Merge pull request #5358 from appwrite/1.3.x
1.3.x sync
2023-04-12 19:01:02 +02:00
Torsten DittmannandGitHub 7f377f8d32 Merge pull request #5355 from appwrite/fix-relationship-attr-link
Fix link in Learn more about relationship attributes
2023-04-12 19:00:17 +02:00
Torsten DittmannandGitHub 35b76a9597 Merge pull request #5357 from appwrite/chore-prepare-1-3-1
chore: prepare 1.3.1 release
2023-04-12 18:56:31 +02:00
Torsten Dittmann 7ca70b2ab9 Merge branch 'master' of https://github.com/appwrite/appwrite into chore-prepare-1-3-1 2023-04-12 18:51:00 +02:00
Torsten DittmannandGitHub 7cec672a63 Merge pull request #5356 from appwrite/fix-migration-v18
fix: migration for 1.3.x
2023-04-12 18:27:20 +02:00
Torsten Dittmann 8872d9db17 feat: upgrade to console 2.3.3 2023-04-12 18:23:09 +02:00
Torsten Dittmann d2b2d18134 chore: prepare 1.3.1 release 2023-04-12 18:13:49 +02:00
Torsten Dittmann 34d27fb4d0 fix: prefs for teams 2023-04-12 18:03:08 +02:00
Torsten Dittmann 52d7dcf082 fix: update prefs endpoints to not fallback to stdClass 2023-04-12 18:02:43 +02:00
Torsten Dittmann 3009168350 fix: migration for 1.3.x 2023-04-12 17:48:36 +02:00
Vincent (Wen Yu) Ge 07017e0835 Updated specs for storage links 2023-04-12 11:32:25 -04:00
Vincent (Wen Yu) Ge f952d57c88 Fix link in storage specs 2023-04-12 11:27:56 -04:00
Vincent (Wen Yu) Ge c96b32d7b6 Update specs 2023-04-12 11:18:55 -04:00
Vincent (Wen Yu) Ge 472ddd190c fix links for relationship attribute 2023-04-12 15:11:10 +00:00
Christy JacobandGitHub af7cbef024 Merge pull request #5353 from appwrite/update-1.3-blog-link-readme
Fix: Update Appwrite 1.3 blog link in Readme
2023-04-12 13:58:30 +04:00
Aditya Oberai be609f4ee2 Update Appwrite 1.3 blog link in Readme 2023-04-12 09:55:36 +00:00
Jake BarnbyandGitHub f2ea043c3b Merge pull request #5350 from appwrite/1.3.x
1.3.x
2023-04-12 19:50:21 +12:00
Jake BarnbyandGitHub ceadcbf113 Merge pull request #5352 from appwrite/feat-review-fixes
Feat review fixes
2023-04-12 19:22:28 +12:00
Jake Barnby f39e52e1d5 Update console 2023-04-12 19:11:58 +12:00
Jake Barnby 211f1bb117 Update versions 2023-04-12 19:02:36 +12:00
Jake BarnbyandGitHub 7ea990e1d9 Merge pull request #5351 from appwrite/feat-review-fixes
Update versions
2023-04-12 18:23:06 +12:00
Jake Barnby 15080fee1b Update changelogs 2023-04-12 18:18:04 +12:00
Jake Barnby 979fa36b02 Update versions 2023-04-12 17:59:43 +12:00
Jake BarnbyandGitHub 927c2a2988 Merge pull request #5347 from appwrite/fix-mock-file-upload
Skip validation for mock file upload
2023-04-12 17:15:35 +12:00
Jake Barnby d63ce7319c Update changelogs 2023-04-12 17:13:02 +12:00
Jake Barnby e2a0b8dcc1 Merge remote-tracking branch 'origin/master' into fix-mock-file-upload 2023-04-12 17:10:40 +12:00
Jake Barnby 98bab42414 Merge remote-tracking branch 'origin/master' into fix-mock-file-upload 2023-04-12 17:09:38 +12:00
Jake Barnby 924b7b90a4 Update specs 2023-04-12 17:09:19 +12:00
Jake BarnbyandGitHub 02c5df1676 Merge pull request #5259 from appwrite/feat-sync-master-12x
Bring 1.2.x to master
2023-04-12 17:08:51 +12:00
Jake Barnby 683aa8a325 Update SDK generator 2023-04-12 16:46:53 +12:00
Jake Barnby 3c6f8d2326 Skip validation for mock file upload 2023-04-12 14:53:35 +12:00
Damodar LohaniandGitHub d050ae40a7 Merge branch 'master' into feat-sync-master-12x 2023-04-12 07:31:23 +05:45
Christy JacobandGitHub d47bea764c Merge pull request #5336 from appwrite/1.3.x
1.3.x
2023-04-12 03:30:22 +04:00
Christy JacobandGitHub 3b4b412733 Merge pull request #5346 from appwrite/fix-console-service
fix: console server duplicate key
2023-04-11 23:35:10 +04:00
Torsten Dittmann ed702d0bc1 chore: update to new console 2023-04-11 21:33:48 +02:00
Torsten Dittmann d47b32856b fix: console server duplicate key 2023-04-11 20:57:27 +02:00
Christy JacobandGitHub 72330d0869 Merge pull request #5345 from appwrite/update-console
feat: update console version
2023-04-11 22:06:24 +04:00
Christy JacobandGitHub ce64bdb7f7 Merge pull request #5344 from appwrite/update-readme
feat: update readme
2023-04-11 22:06:09 +04:00
Christy Jacob 67be2c10eb feat: update console version 2023-04-11 18:01:37 +00:00
Christy JacobandGitHub 871f158bb6 Update README.md 2023-04-11 23:19:10 +05:30
Christy Jacob 641a47f195 feat: remove support for 0.15.x 2023-04-11 17:21:26 +00:00
Christy Jacob 7f14db493d feat: update security file 2023-04-11 17:00:22 +00:00
Christy Jacob f4a77fcf11 feat: update readme 2023-04-11 16:52:38 +00:00
Jake BarnbyandGitHub 3670b5e9ad Merge pull request #5342 from appwrite/feat-review-fixes
Feat review fixes
2023-04-12 03:56:22 +12:00
Jake Barnby d86d604624 Reviews fixes 2023-04-12 03:32:14 +12:00
Jake BarnbyandGitHub 2a8911011b Merge pull request #5341 from appwrite/feat-db-update-migrations
Add options key to attributes
2023-04-12 03:01:11 +12:00
Jake Barnby f869252d90 Remove redundant import 2023-04-12 03:00:09 +12:00
Jake Barnby 26eaddee82 Update comment 2023-04-12 02:59:45 +12:00
Jake Barnby 71b96452c6 Update platforms 2023-04-12 02:58:59 +12:00
Jake Barnby bafcfcfbb9 Update cache buster 2023-04-12 02:56:48 +12:00
Jake Barnby a01dd3fc41 Add options key to attributes 2023-04-12 02:49:47 +12:00
Jake BarnbyandGitHub 07b8f0fe3f Merge pull request #5339 from appwrite/feat-add-version
Add versioned specs and examples
2023-04-12 01:56:29 +12:00
Jake BarnbyandGitHub 117e416b80 Merge pull request #5334 from appwrite/feat-db-update-migrations
Feat db update migrations
2023-04-12 01:31:25 +12:00
Jake BarnbyandGitHub 69b5fae3bf Merge pull request #5338 from appwrite/feat-update-sdk-generator
Update SDK generator for 1.3.x support
2023-04-12 01:28:48 +12:00
Jake Barnby ffb91eca68 Merge remote-tracking branch 'origin/1.3.x' into feat-update-sdk-generator
# Conflicts:
#	composer.json
#	composer.lock
2023-04-12 01:24:50 +12:00
Jake Barnby 6b497a31c8 Add versioned specs and examples 2023-04-12 01:23:29 +12:00
Christy JacobandGitHub e3b8f0b302 Merge pull request #5337 from appwrite/sync-master
Sync master
2023-04-11 18:53:01 +05:30
Jake Barnby 9b7d032eda Update SDK generator for 1.3.x support 2023-04-12 00:58:12 +12:00
Jake Barnby 7fe14ca10b Merge remote-tracking branch 'origin/master' into sync-master
# Conflicts:
#	app/config/specs/open-api3-latest-client.json
#	app/config/specs/open-api3-latest-console.json
#	app/config/specs/open-api3-latest-server.json
#	app/config/specs/swagger2-latest-client.json
#	app/config/specs/swagger2-latest-console.json
#	app/config/specs/swagger2-latest-server.json
#	app/console
#	app/controllers/api/storage.php
#	composer.lock
2023-04-12 00:50:31 +12:00
Jake Barnby 9a76507185 Merge remote-tracking branch 'origin/1.3.x' into feat-db-update-migrations
# Conflicts:
#	CHANGES.md
2023-04-12 00:39:18 +12:00
Jake BarnbyandGitHub aa20b685a7 Merge pull request #5335 from appwrite/fix-organization-delete
fix: deletes worker deleting projects with console team
2023-04-12 00:38:38 +12:00
Jake Barnby bf73b1a55f Update changelog 2023-04-12 00:38:07 +12:00
Jake Barnby de2ea95099 Update changelog 2023-04-12 00:34:29 +12:00
Jake Barnby 43946cade5 Add teams migration 2023-04-12 00:33:29 +12:00
Jake Barnby b0a6190394 Only iterate attributes once 2023-04-12 00:05:19 +12:00
Jake Barnby d46f3092e5 Remove redis and unused imports 2023-04-12 00:04:53 +12:00
Torsten Dittmann fdd18fdc7d fix: update changelog 2023-04-11 13:52:01 +02:00
Torsten Dittmann 700abb3e47 fix: deletes worker deleting projects with console team 2023-04-11 13:49:45 +02:00
Jake Barnby a2cb3c135f Fix migration of floats 2023-04-11 23:42:06 +12:00
Jake Barnby 0f1c1fda9e Quote attribute name 2023-04-11 22:30:45 +12:00
Jake Barnby c60d7764e4 Fix cache key 2023-04-11 22:27:49 +12:00
Jake Barnby 28a9a373b1 Fix binding 2023-04-11 22:27:29 +12:00
Jake Barnby f6bd9d4150 Merge remote-tracking branch 'origin/1.3.x' into feat-db-update-migrations 2023-04-11 22:15:32 +12:00
Jake BarnbyandGitHub c077636d40 Merge pull request #5300 from appwrite/doc-auth-1.3
Update auth doc links for 1.3
2023-04-11 22:08:40 +12:00
Jake Barnby 2157acd63f Merge branch '1.3.x' into doc-auth-1.3
# Conflicts:
#	composer.lock
2023-04-11 21:22:32 +12:00
Jake BarnbyandGitHub 655ae89423 Merge pull request #5333 from appwrite/fix-user-model-response
Fix user model response for SDKs
2023-04-11 21:15:08 +12:00
Christy JacobandGitHub 45e636ab2d Merge pull request #5154 from appwrite/update-cli-1.2.1
feat: upgrade CLI to 1.2.1
2023-04-11 14:31:41 +05:30
Jake Barnby 5cbb08d6f1 Fix response model types for update password + update status 2023-04-11 20:41:24 +12:00
Christy Jacob 391e114cdd feat: update docs examples 2023-04-11 08:27:36 +00:00
Christy Jacob 4a314c0a58 Merge branch 'master' of https://github.com/appwrite/appwrite into update-cli-1.2.1 2023-04-11 08:14:52 +00:00
Jake Barnby 58ba41a9c5 Make password, hash and hashOptions optional so that they are optional in SDKs, and nulled when returning from the account service 2023-04-11 19:36:14 +12:00
Christy JacobandGitHub 01b066e317 Merge pull request #5330 from appwrite/docs-inputfile
Link to InputFile Docs
2023-04-11 13:02:31 +05:30
Jake BarnbyandGitHub dc626ea336 Merge pull request #5238 from appwrite/feat-relations-2
Feat relations 2
2023-04-11 18:26:10 +12:00
Jake Barnby 9604cd1d94 Update to tagged release 2023-04-11 17:41:21 +12:00
Jake Barnby f00bd7dac7 Merge remote-tracking branch 'origin/1.3.x' into feat-relations-2
# Conflicts:
#	composer.lock
2023-04-11 17:25:26 +12:00
Jake BarnbyandGitHub 87864d2365 Merge pull request #5301 from appwrite/doc-db-relationships
Updates links for query page
2023-04-11 17:16:12 +12:00
Jake Barnby 84f4c757c3 Fix test 2023-04-11 16:21:22 +12:00
Jake Barnby 7f8f34793e Merge remote-tracking branch 'origin/1.3.x' into doc-db-relationships
# Conflicts:
#	composer.lock
2023-04-11 15:57:35 +12:00
d58ce741f3 Apply suggestions from code review
Co-authored-by: Vincent (Wen Yu) Ge <vincent@appwrite.io>
2023-04-11 15:49:36 +12:00
Jake Barnby 5485346b5e Fail validation on nested attribute query 2023-04-11 15:40:14 +12:00
Vincent (Wen Yu) Ge 6e9e6aa6b3 relink to inputfile docs 2023-04-10 22:18:07 +00:00
fogelito acbdb06b3c Add .md files 2023-04-10 23:15:18 +03:00
Vincent (Wen Yu) GeandGitHub 5354e5ee44 Merge branch '1.3.x' into doc-auth-1.3 2023-04-10 16:03:36 -04:00
Jake Barnby 93a994a95d Update console + database 2023-04-10 21:48:50 +12:00
Jake Barnby e123188b0a Fix list document total 2023-04-10 20:51:38 +12:00
Christy JacobandGitHub 8d3c96d7eb Merge pull request #5325 from appwrite/fix-email-template-path
Fix email-base.tpl path in certificates worker
2023-04-10 13:05:19 +05:30
a91ee7e80f Apply suggestions from code review
Co-authored-by: Vincent (Wen Yu) Ge <vincent@appwrite.io>
2023-04-10 15:05:58 +12:00
b39b018a10 Update Dockerfile
Co-authored-by: Christy Jacob <christyjacob4@gmail.com>
2023-04-09 16:46:05 -04:00
StevenandGitHub 577ba9b0ec Fix email-base.tpl path in certificates worker 2023-04-06 13:48:52 -07:00
Jake Barnby d44f69df09 Delete collection relationships from deletes worker 2023-04-06 15:40:39 +12:00
Jake Barnby deb2751cbf Fix copy error 2023-04-06 02:57:37 +12:00
Jake Barnby bb9ae6f326 Update database 2023-04-06 02:43:06 +12:00
Jake Barnby b252fe847f Add custom delete restricted error 2023-04-06 00:54:44 +12:00
Torsten DittmannandGitHub 9e11e00c6d Merge pull request #5313 from appwrite/feat-console-service
feat: console service
2023-04-05 14:45:07 +02:00
Jake Barnby 6591778f90 Fix query tests 2023-04-05 23:04:12 +12:00
Jake Barnby 08b013353b Update database 2023-04-05 21:13:28 +12:00
Jake Barnby 1bf15a7cc2 Update database + console 2023-04-05 20:13:51 +12:00
Jake Barnby 599a0d0781 Catch, clear cache and re-throw for unhandled exceptions on attribute create 2023-04-05 18:48:57 +12:00
4624241d32 Update app/controllers/api/databases.php
Co-authored-by: Christy Jacob <christyjacob4@gmail.com>
2023-04-05 18:19:40 +12:00
2153f65893 Update app/controllers/api/databases.php
Co-authored-by: Christy Jacob <christyjacob4@gmail.com>
2023-04-05 18:19:25 +12:00
Jake Barnby 72f203b365 Update console 2023-04-03 22:49:29 +12:00
Jake Barnby ed8911e0a6 Remap internal attributes when updating existing document 2023-04-03 22:45:10 +12:00
Jake Barnby 6aba92bf8b Add missing instanceof checks 2023-04-03 22:39:31 +12:00
Jake Barnby 13c77b6927 Update database 2023-04-03 21:12:13 +12:00
Jake Barnby 460d52f948 Add unique ID when no ID passed for nested documents 2023-04-03 20:21:28 +12:00
Jake Barnby 6664377fb8 Merge remote-tracking branch 'origin/test-update-attributes' into feat-relations-2
# Conflicts:
#	app/controllers/api/databases.php
2023-04-03 16:10:09 +12:00
Jake Barnby af890a4e4b Merge remote-tracking branch 'origin/1.3.x' into feat-relations-2
# Conflicts:
#	composer.lock
2023-04-03 15:55:17 +12:00
Jake Barnby 3d95f7e129 Fix cache invalidation when deleting database 2023-04-03 15:51:44 +12:00
Jake Barnby 3cfbdf07b7 Fix cache invalidation when updating attributes 2023-04-03 15:43:14 +12:00
Jake BarnbyandGitHub cbcf110560 Merge pull request #5311 from appwrite/chore-update-abuse
Update abuse
2023-04-03 13:29:18 +12:00
Torsten DittmannandGitHub bd7d28f7d1 fix: steven review 2023-03-31 22:48:34 +02:00
Torsten Dittmann 28758d4794 fix: typo 2023-03-31 18:47:00 +02:00
Torsten DittmannandGitHub e8b6ff2bb3 Merge pull request #5210 from appwrite/fix-debugger
Fix yasd so that the debugger works
2023-03-31 18:43:13 +02:00
Torsten Dittmann 42df2435ec fix: sdk.auth for console service 2023-03-31 17:17:30 +02:00
Torsten Dittmann 3860602697 feat: console service 2023-03-31 17:14:59 +02:00
Torsten Dittmann f9adffc569 tests: add tests for cache on updating attributes 2023-03-31 14:56:38 +02:00
Jake Barnby dd2f980539 Fix worker warning 2023-03-31 23:15:48 +13:00
Jake Barnby eb8258d548 Fix tests 2023-03-31 21:29:02 +13:00
Jake Barnby 9010320cd9 Update abuse 2023-03-31 20:57:47 +13:00
Jake Barnby fec374fe59 Delete two way relationship attributes on collection delete 2023-03-31 19:56:35 +13:00
Jake Barnby bcf5b4bfab Update related two way attribute 2023-03-31 18:38:37 +13:00
Jake Barnby 3bbe6d4da8 Disallow updating two-way 2023-03-31 18:19:46 +13:00
Jake Barnby cf122054aa Update DB and console 2023-03-31 18:07:36 +13:00
Jake Barnby 578d4d1619 Disallow index creation on relationship attributes 2023-03-31 18:06:50 +13:00
Jake Barnby c7201cc417 Remove HTML from API error messages 2023-03-31 18:05:45 +13:00
Jake Barnby 939a0c5591 Add missing instanceof check 2023-03-31 17:56:25 +13:00
Jake Barnby bf4e2df45b Allow 'unique()' for nested document IDs 2023-03-31 17:33:21 +13:00
fogelito 05d7badd60 Delete related on 2 way 2023-03-30 20:36:24 +03:00
Jake Barnby 2f709a2e89 Fix test 2023-03-30 22:05:35 +13:00
Jake Barnby bd64ace713 Allow int for float filter queries 2023-03-30 21:02:33 +13:00
Jake Barnby 39acf18bc3 Handle document arrays when filtering documents 2023-03-30 20:54:45 +13:00
Jake Barnby 07d90aa4c4 Manually add the side to the attributes table 2023-03-30 20:41:18 +13:00
Jake Barnby ed54d9861f Add back validation for fulltext index on search queries 2023-03-30 19:57:56 +13:00
Steven Nguyen a86c1c0a2b Fix yasd so that the debugger works
* Update the base image since the yasd extension wasn't installed correctly
* Fix the path to the yasd_init.php file
* Use `host.docker.internal` as the remote host because that should always work inside docker
* Mount the dev folder into the appwrite container so the yasd_init.php file is picked up.
2023-03-29 18:04:24 -07:00
Jake Barnby 72d090f196 Update console 2023-03-30 13:33:40 +13:00
Jake Barnby 4de45bf9a7 Delete related cache on finally 2023-03-30 13:28:06 +13:00
Jake Barnby a7a3d85bcb Clear related collection cache 2023-03-30 13:24:44 +13:00
Jake Barnby 9468c238de Remove conflicts 2023-03-30 13:01:58 +13:00
Jake Barnby 9025f97939 Merge branch 'feat-relations-2' of github.com:appwrite/appwrite into feat-relations-2 2023-03-30 11:39:43 +13:00
fogelito e2d3c95fa6 add relations into attributes collection 2023-03-29 23:37:22 +03:00
fogelito 5aff6969db add relations into attributes collection 2023-03-29 23:31:49 +03:00
Vincent (Wen Yu) Ge 19d5ea03b9 Updates links for query page 2023-03-29 19:38:39 +00:00
Vincent (Wen Yu) Ge 7b35d3739b Update auth doc links for 1.3 2023-03-29 18:58:55 +00:00
fogelito 0638fec40d related attributes call tests 2023-03-29 18:43:54 +03:00
fogelito 1af33d1af7 related attributes call tests 2023-03-29 18:34:49 +03:00
Jake Barnby bfc54c4590 Delete original attribute if two-way attribute creation fails 2023-03-29 20:28:59 +13:00
Jake Barnby 161eb0b66f Create two-way attribute on related collection 2023-03-29 19:26:58 +13:00
Jake Barnby f25bfa805b Fix more name collisions 2023-03-29 16:30:47 +13:00
Jake Barnby d23a2e2040 Database side permission check for list document count 2023-03-29 16:05:53 +13:00
Jake Barnby 1958cef3d2 Merge remote-tracking branch 'origin/feat-relations-2' into feat-relations-2 2023-03-29 14:43:09 +13:00
Jake Barnby c09ab6cc9d Remove duplicate dependency 2023-03-29 14:42:19 +13:00
Jake Barnby 970ae8d0ad Reset array keys for list documents 2023-03-29 14:38:43 +13:00
Jake Barnby 96e1440ee6 Fix name collision 2023-03-29 14:37:56 +13:00
Jake Barnby ecaca00463 Force arrays for relation permissions checks 2023-03-29 14:33:53 +13:00
Jake Barnby e80d13076f Consistent attribute ordering 2023-03-29 13:37:51 +13:00
Jake Barnby 15d1badafb Update param desc 2023-03-29 13:37:03 +13:00
ac82726364 Update app/controllers/api/databases.php
Co-authored-by: Torsten Dittmann <torsten.dittmann@googlemail.com>
2023-03-29 13:33:27 +13:00
fogelito 3c9cb0ab80 Strict WhiteList options 2023-03-28 16:24:18 +03:00
Jake Barnby 505ffc91ae Fix existing tests 2023-03-28 22:08:36 +13:00
Jake Barnby f69d222a5a Inline permissions checks 2023-03-28 22:02:49 +13:00
Jake Barnby 5f7f44f939 Reduce nesting and handle arrays for nested ID set 2023-03-28 16:10:12 +13:00
fogelito 18be424fc0 Test list attributes 2023-03-27 18:24:02 +03:00
Jake Barnby fa64cc33ea Add missing check for update 2023-03-27 20:08:02 +13:00
Jake Barnby 948f04e71c Lint 2023-03-27 19:26:27 +13:00
Jake Barnby 1cf25199ab Recurse through nested documents to set collection ID 2023-03-27 19:03:00 +13:00
Jake Barnby 0465fb2268 Lint..? 2023-03-27 15:56:11 +13:00
Jake Barnby 275c6bb3a0 Set databaseId for all nested documents 2023-03-27 15:42:36 +13:00
Jake Barnby 64ee75e80d Revert "Extract $options on get attributes list"
This reverts commit 0ef6f32a10.
2023-03-27 12:18:47 +13:00
Jake Barnby 9ac08b496b Merge remote-tracking branch 'origin/feat-relations-2' into feat-relations-2 2023-03-27 12:18:29 +13:00
fogelito 0ef6f32a10 Extract $options on get attributes list 2023-03-26 19:39:26 +03:00
fogelito 276b1de2b0 Disable 2 way for ManyToOne relation test 2023-03-26 16:27:07 +03:00
Jake Barnby 79c8ed3ce4 Remove $collection and $internalId for nested documents 2023-03-25 17:11:19 +13:00
Jake Barnby 07c383e17a Review updates 2023-03-25 16:36:20 +13:00
Jake Barnby ac8d4fcb2a Add relationships to attribute response model tests 2023-03-25 16:29:40 +13:00
Jake Barnby d76d573e7c Update attribute subquery to flatten relationship attributes 2023-03-25 16:28:07 +13:00
Jake Barnby 0797df8414 Merge remote-tracking branch 'origin/1.3.x' into feat-relations-2
# Conflicts:
#	app/config/specs/open-api3-latest-client.json
#	app/config/specs/open-api3-latest-console.json
#	app/config/specs/open-api3-latest-server.json
#	app/config/specs/swagger2-latest-client.json
#	app/config/specs/swagger2-latest-console.json
#	app/config/specs/swagger2-latest-server.json
2023-03-25 15:32:55 +13:00
Christy JacobandGitHub ca186543ca Merge pull request #5274 from appwrite/update-readme
feat: update readme
2023-03-25 01:52:23 +05:30
Christy Jacob 8578985515 feat: update readme 2023-03-24 20:16:20 +00:00
Torsten DittmannandGitHub b8b6ac75fc Merge pull request #5196 from appwrite/feat-team-prefs
feat: team preferences
2023-03-24 12:33:55 +01:00
Jake Barnby daa5c7e59f Merge remote-tracking branch 'origin/1.3.x' into feat-relations-2
# Conflicts:
#	composer.json
#	composer.lock
2023-03-24 23:50:26 +13:00
Jake BarnbyandGitHub d43d0cf293 Merge pull request #5143 from appwrite/feat-remove-limits
Remove count, limit and offset limitations for queries
2023-03-24 23:48:32 +13:00
Jake Barnby 47586fedb5 Remove invalid test 2023-03-24 23:09:49 +13:00
Jake Barnby 702000ac2f Remove redundant test 2023-03-24 22:28:39 +13:00
Jake Barnby c65800b3a3 Merge remote-tracking branch 'origin/1.3.x' into feat-remove-limits
# Conflicts:
#	composer.json
#	composer.lock
2023-03-24 21:03:18 +13:00
Jake Barnby 0071b9d885 Generate specs 2023-03-24 20:59:12 +13:00
Jake Barnby 48b018fd9d Merge remote-tracking branch 'origin/1.3.x' into feat-relations-2 2023-03-24 20:53:41 +13:00
Jake Barnby 6cddb38290 Fix for count 2023-03-24 20:30:41 +13:00
Jake Barnby c4b11afd08 Disable stop on failure 2023-03-24 18:59:26 +13:00
Jake BarnbyandGitHub f6aa4a4ab1 Merge pull request #5271 from appwrite/feat-realtions-jake
Feat relations updates
2023-03-24 18:58:25 +13:00
Jake Barnby a48ce855c7 Move tests 2023-03-24 18:56:49 +13:00
Jake Barnby 1885f9e87c Add graphql tests 2023-03-24 18:08:50 +13:00
Jake Barnby 24d1163703 Fix params 2023-03-24 16:57:56 +13:00
Jake Barnby 2775a92cdf Add more tests 2023-03-24 16:48:50 +13:00
Jake Barnby b6cfe43681 Clean up 2023-03-24 16:46:02 +13:00
Jake Barnby 947ad20bad Pass attribute to select validator 2023-03-24 16:44:28 +13:00
Jake Barnby c310434eeb Update dependencies 2023-03-24 16:39:35 +13:00
fogelito e62e5c405a Select from parent and related 2023-03-23 18:34:49 +02:00
fogelito 3a7d00519f some tests assertArrayHasKey 2023-03-23 18:05:22 +02:00
fogelito d6a7e26678 FilterTest.php 2023-03-23 17:51:30 +02:00
fogelito 671888d975 Unit test SelectTest.php 2023-03-23 16:33:11 +02:00
fogelito 6539f15178 Fix return on test 2023-03-23 16:23:14 +02:00
fogelito 617a2c5fc8 New Queries Activation 2023-03-23 16:13:50 +02:00
fogelito fad9ecd389 New Queries Activation 2023-03-23 16:11:02 +02:00
fogelito 969cff5e41 New Queries Activation 2023-03-23 16:08:38 +02:00
Torsten Dittmann 0b9526fc50 tests: add graphql tests 2023-03-23 13:54:12 +01:00
Torsten Dittmann 7020c85f78 tests: fix teams tests 2023-03-23 13:06:48 +01:00
Torsten Dittmann c1ba898cec feat: rename update team sdk method 2023-03-23 13:04:16 +01:00
Torsten Dittmann 10cd97e978 Merge branch '1.3.x' of https://github.com/appwrite/appwrite into feat-team-prefs 2023-03-23 13:03:50 +01:00
Torsten DittmannandGitHub e8583d9387 Merge pull request #5164 from appwrite/feat-database-update-attribute
feat: database update attribute endpoints
2023-03-23 13:01:05 +01:00
Torsten Dittmann 75b687786d chore: run formatter 2023-03-23 11:28:31 +01:00
Torsten Dittmann 0fc4d5f49a chore: generate specs 2023-03-23 11:28:15 +01:00
Torsten Dittmann 010481bafc feat: change url for updating attributes 2023-03-23 11:25:40 +01:00
Torsten Dittmann 818d111068 fix: wrong team event descriptions 2023-03-23 10:52:43 +01:00
Jake Barnby f43ff0d2e9 Update dependencies 2023-03-23 18:40:05 +13:00
Jake Barnby 588d6651a2 Update tests 2023-03-23 18:34:13 +13:00
Jake Barnby c18af032ae Remove redundant model attributes 2023-03-23 18:20:15 +13:00
Jake Barnby 035180c4da Allow other filter query types 2023-03-23 18:09:38 +13:00
Jake Barnby 7a089f8861 Use specific document validator for select queries on get document 2023-03-23 17:59:23 +13:00
Jake Barnby 2e44434ab8 Parse queries after validation 2023-03-23 17:55:31 +13:00
Jake Barnby f974477ecc Use plain param to allow validating against collection attributes 2023-03-23 17:32:44 +13:00
Jake Barnby f9f7af8759 Worker fix 2023-03-23 17:20:08 +13:00
Jake Barnby 0643a94b12 Update signatures 2023-03-23 16:58:41 +13:00
Jake Barnby 18bdb6ae3e Revert "Trigger workflow"
This reverts commit 5f965e6dad.
2023-03-23 15:16:24 +13:00
Jake Barnby 5f965e6dad Trigger workflow 2023-03-23 15:15:57 +13:00
Jake Barnby 2b1e35659c Merge remote-tracking branch 'origin/1.3.x' into feat-remove-limits
# Conflicts:
#	composer.json
#	composer.lock
2023-03-23 15:08:35 +13:00
Jake Barnby 5689d47d41 Merge remote-tracking branch 'origin/1.3.x' into feat-db-update-migrations
# Conflicts:
#	src/Appwrite/Migration/Version/V18.php
2023-03-23 15:05:35 +13:00
fogelito 60c54e2d10 Select Validator 2023-03-22 23:10:47 +02:00
Christy JacobandGitHub 6122a25e56 Merge pull request #5188 from singhbhaskar/feat-5159-improve-error-when-creating-custom-domain
Updated the error to 501 error code for custom domain when _APP_DOMAIN and _APP_DOMAIN_TARGET is setup incorrectly
2023-03-22 23:15:50 +05:30
fogelito 319698dab4 libraries 2023-03-22 19:14:41 +02:00
fogelito 34467de87d Update relationship get Attribute 2023-03-22 18:44:12 +02:00
Christy Jacob c31d60dc1f feat: sync with master 2023-03-22 20:38:59 +04:00
Christy Jacob 4c52458684 Merge branch 'master' of github.com:appwrite/appwrite into update-cli-1.2.1 2023-03-22 20:34:21 +04:00
fogelito a824b46df0 Update relationship 2023-03-22 17:49:08 +02:00
fogelito 433b3be9ed $oneToMany tests 2023-03-21 19:52:25 +02:00
Eldad A. FuxandGitHub 53dc3a9dee Merge pull request #5202 from appwrite/fix-cache-flush
Prevent cache from being flushed on start
2023-03-21 17:31:00 +02:00
Bhaskar SinghandGitHub 5c2c968933 Merge branch 'appwrite:master' into feat-5159-improve-error-when-creating-custom-domain 2023-03-21 20:35:22 +05:30
Bhaskar Singh 8b5e0e1f1a Updating the exception variable name for easy
readability
2023-03-21 20:33:42 +05:30
fogelito e06e890279 query validators ignore nested 2023-03-21 14:32:05 +02:00
Jake BarnbyandGitHub a3ddfd98d8 Merge pull request #5243 from appwrite/fix-migration
Update migration V18.php
2023-03-21 19:54:01 +13:00
Damodar Lohani 48065033b5 composer update 2023-03-21 05:59:21 +00:00
Damodar Lohani 8e987112b9 Merge remote-tracking branch 'origin/master' into 1.2.x 2023-03-21 05:55:07 +00:00
Eldad A. FuxandGitHub b77967dc1f Merge pull request #5131 from appwrite/feat-sdk-releases
For SDK release
2023-03-21 07:32:48 +02:00
Christy Jacob 66f18a494b Merge branch 'update-cli-1.2.1' of github.com:appwrite/appwrite into update-cli-1.2.1 2023-03-20 17:00:40 +05:30
Christy Jacob e114da1d9a Merge branch 'master' of github.com:appwrite/appwrite into update-cli-1.2.1 2023-03-20 16:55:02 +05:30
fogelito a5f3af62bd Extract model options 2023-03-20 13:20:24 +02:00
f7c9e9c650 Update app/workers/databases.php
Co-authored-by: Jake Barnby <jakeb994@gmail.com>
2023-03-20 11:23:01 +02:00
Torsten Dittmann d59b4d17bb fix: update attribute review 2023-03-20 10:13:23 +01:00
Christy Jacob 232dc7aef7 feat: update console 2023-03-20 07:14:16 +00:00
Christy Jacob 6640c52849 Merge branch 'master' of https://github.com/appwrite/appwrite into update-cli-1.2.1 2023-03-20 06:56:35 +00:00
fogelito 0c6f9bdb01 delete relation attribute 2023-03-19 19:31:15 +02:00
fogelito eee29940bb Some tests 2023-03-19 19:09:17 +02:00
Torsten Dittmann 644832f0b3 fix: mock endpoint for nullable params 2023-03-17 10:31:36 +01:00
Torsten Dittmann 841a8d3fae chore: generate specs 2023-03-17 10:27:56 +01:00
Torsten Dittmann a40dba1b49 tests: add nullable mock endpoint 2023-03-17 10:19:39 +01:00
Damodar LohaniandGitHub c094a40a53 Update Migration.php 2023-03-17 07:09:50 +05:45
Damodar LohaniandGitHub 6e4592dab4 Update migration V18.php 2023-03-17 07:08:47 +05:45
fogelito 038f4fc073 Some relation tests 2023-03-16 18:28:08 +02:00
fogelito 00c1418246 Update response Model.php 2023-03-16 13:48:27 +02:00
fogelito 79bfa025cb Merge branch 'feat-database-update-attribute' of github.com:appwrite/appwrite into feat-relations-2
 Conflicts:
	app/controllers/api/databases.php
	composer.json
	composer.lock
2023-03-16 12:14:37 +02:00
fogelito 28af0669f6 docker-compose.yml temp mount 2023-03-16 11:11:04 +02:00
fogelito 44de884ee5 convert relatedOptions to options 2023-03-16 09:31:48 +02:00
348c2d4ffe Update app/config/events.php
Co-authored-by: Christy Jacob <christyjacob4@gmail.com>
2023-03-15 12:11:46 +01:00
Torsten Dittmann 08d588aeb1 fix: remove unnecessary owner check 2023-03-15 11:55:21 +01:00
fogelito c1bce185fd composer framework update 2023-03-15 10:04:02 +02:00
Steven Nguyen 137c2d663e Prevent cache from being flushed on start
We shouldn't clear the cache because scheduled functions are also
in the cache and we don't want to lose them.
2023-03-14 16:09:14 -07:00
fogelito 31fad24603 collections.php 2023-03-14 15:20:56 +02:00
fogelito 40152fbd6c Model relationshipOptions 2023-03-14 15:18:30 +02:00
fogelito 6306ec59ba Model relationship 2023-03-14 10:32:49 +02:00
fogelito f255484fd4 Model relationship 2023-03-14 10:24:53 +02:00
Torsten Dittmann bfdb7830d0 fix: update team prefs endpoint 2023-03-14 04:40:17 +05:30
fogelito adcbb08374 deleteRelationship worker 2023-03-13 17:32:51 +02:00
fogelito 341830b3d7 deleteRelationship worker 2023-03-13 17:19:24 +02:00
fogelito 9c4b269669 update collections.php with options 2023-03-13 12:59:01 +02:00
Torsten Dittmann ea1c0d0a1f chore: generate specs 2023-03-13 15:54:55 +05:30
Torsten Dittmann 2f1dda891b fix: specs generation for nullable params 2023-03-13 15:54:49 +05:30
fogelito b1cc4ada4c relationType 2023-03-13 12:11:38 +02:00
Eldad A. FuxandGitHub 8b79438755 Merge pull request #5126 from appwrite/feat-reset-sdk-account-model
switch SDK response model from account to user
2023-03-13 11:46:44 +02:00
fogelito f5f51c4fc9 Worker $relatedCollection 2023-03-13 11:46:03 +02:00
fogelito 5fc3f5bc3a Worker 2023-03-13 11:34:41 +02:00
fogelito b6c279b576 add relatedCollectionInternalId 2023-03-13 10:45:54 +02:00
fogelito b116d24486 Document options 2023-03-13 10:33:07 +02:00
fogelito ba6439375c create attribute function 2023-03-13 10:22:01 +02:00
fogelito f525104963 create relationship 2023-03-12 17:06:56 +02:00
fogelito ca3efdf562 create relation 2023-03-12 16:04:18 +02:00
Torsten Dittmann 10150aad3e feat: only owners are allowed to update attributes 2023-03-10 21:57:13 +05:30
Torsten Dittmann 2178bfc126 Merge branch '1.3.x' of https://github.com/appwrite/appwrite into feat-database-update-attribute 2023-03-10 18:39:11 +05:30
Torsten Dittmann f568f9f1ad style: fix formatting 2023-03-10 18:37:16 +05:30
Torsten Dittmann 7b1853eb96 feat: graphql support 2023-03-10 18:36:46 +05:30
Torsten Dittmann 077ad544b6 fix: database responses 2023-03-10 18:36:34 +05:30
Torsten Dittmann cb065e4228 fix: openapi specification 2023-03-10 15:36:10 +05:30
Bhaskar Singh 31a903d144 Updated the error message for target check fails
in custom domain creation
2023-03-10 00:24:33 +05:30
Torsten Dittmann fcd9b060fd chore: generate specs 2023-03-09 16:49:11 +05:30
Torsten Dittmann 01edc57806 Merge branch '1.3.x' of https://github.com/appwrite/appwrite into feat-team-prefs 2023-03-09 16:04:20 +05:30
Damodar LohaniandGitHub ad8ae92a6d Merge branch '1.3.x' into feat-reset-sdk-account-model 2023-03-09 07:06:24 +05:45
Torsten Dittmann 64244d9f8f docs: update teams get prefs 2023-03-09 02:11:10 +05:30
4f08d8e82a Apply suggestions from code review
Co-authored-by: Vincent (Wen Yu) Ge <vincent@appwrite.io>
2023-03-09 02:09:03 +05:30
Eldad A. FuxandGitHub 9ea3f0317f Merge pull request #5024 from appwrite/feat-x-appwrite-timestamp-header
Update Update Document API to check X-Appwrite-Timestamp header
2023-03-08 18:32:24 +02:00
Bhaskar Singh b16c789282 Fixing the bracket 2023-03-08 17:23:15 +05:30
Bhaskar Singh 7a4cea9f79 Removed ENV_VARIABLE_INCORRECT_SETUP 2023-03-08 17:21:37 +05:30
Bhaskar Singh 7f3000439a Updated ENV_VARIABLE_INCORRECT_SETUP to DOMAIN_VARIABLE_INCORRECT 2023-03-08 17:15:55 +05:30
Steven Nguyen 85a2d623a6 Update APIs to check X-Appwrite-Timestamp header
Appwrite will refer to the X-Appwrite-Timestamp header for when the
request was originally sent and reject the request if the Timestamp
is older than the updatedAt timestamp of the document.
2023-03-07 10:54:52 -08:00
Damodar Lohani 0121a95cee update sdk versions 2023-03-07 06:15:01 +00:00
Damodar Lohani e11ef18f1e update sdk generator 2023-03-07 06:14:34 +00:00
Damodar Lohani cbc365a702 update changelog 2023-03-07 06:14:24 +00:00
Torsten Dittmann 496da61cd9 feat: team preferences 2023-03-06 19:54:02 +05:30
Bhaskar Singh eaf31fdb78 Updated the error to 501 error code for custom
domain when _APP_DOMAIN and _APP_DOMAIN_TARGET is setup incorrectly
2023-03-05 14:35:47 +05:30
Torsten Dittmann df9f1ee4c4 tests: fix update attribute status code 2023-03-02 14:01:35 +05:30
Torsten Dittmann 5df53e3e76 fix: http status codes for udpating attributes 2023-03-02 12:15:10 +05:30
Torsten Dittmann bfd23665cb fix: graphql 2023-03-01 18:13:34 +05:30
Torsten Dittmann 0dd666c227 tests: fix functions tests 2023-03-01 17:30:54 +05:30
Torsten Dittmann 6e5b8fab4b fix: implement new framework changes 2023-03-01 17:30:36 +05:30
Jake BarnbyandGitHub d2c55afdcf Merge pull request #5145 from appwrite/feat-remove-index-requirements
Remove indexed attribute query requirement
2023-03-01 21:42:29 +13:00
Torsten DittmannandGitHub 861e980420 Merge pull request #5173 from appwrite/chore-release-1-3-console-sdk
chore: 1.3.x console sdk
2023-03-01 12:56:21 +05:30
Torsten Dittmann 41277864fd sdks: fix version number for console sdk 2023-02-28 15:26:37 +05:30
Torsten Dittmann 86134768fc chore: generate specs 2023-02-28 15:07:30 +05:30
Torsten Dittmann ae32536be2 Merge branch 'master' of https://github.com/appwrite/appwrite into chore-release-1-3-console-sdk 2023-02-28 14:45:34 +05:30
Torsten Dittmann d5449cb498 fix: console sdk package name 2023-02-28 14:43:36 +05:30
Torsten Dittmann 7372983c9d docs: update attributes 2023-02-28 13:55:06 +05:30
Jake Barnby c06b38773c Merge remote-tracking branch 'origin/1.3.x' into feat-db-update-migrations
# Conflicts:
#	src/Appwrite/Migration/Migration.php
#	src/Appwrite/Migration/Version/V18.php
2023-02-28 16:59:14 +13:00
Jake Barnby a28eaa80cf Add test asserting indexes not required 2023-02-28 16:52:11 +13:00
Jake Barnby 66a7b652e6 Update lock 2023-02-28 16:48:27 +13:00
Jake Barnby 84f4813135 Revert "Remove count, limit and offset limitations"
This reverts commit ae3535de0d.

# Conflicts:
#	composer.lock
2023-02-28 16:42:21 +13:00
Jake Barnby 04c1d3ca7f Revert "Remove redundant test"
This reverts commit b2fc7cc25a.
2023-02-28 16:40:52 +13:00
Jake Barnby 73a47b5624 Revert "Remove redundant test"
This reverts commit 8c5220f455.
2023-02-28 16:40:25 +13:00
Torsten Dittmann c4a27c79ab chore: run linter 2023-02-27 13:56:45 +05:30
Torsten Dittmann 18d938ce54 tests: add tests for update attributes on non existing resources 2023-02-27 13:29:37 +05:30
Torsten Dittmann 4023a4bb2f tests: rename import for AppwriteException 2023-02-27 13:17:20 +05:30
Torsten Dittmann 454fd1cd43 revert: remove unused imports 2023-02-27 13:16:35 +05:30
Torsten Dittmann c5953d1e1b tests: add tests for updating attributes 2023-02-27 13:15:21 +05:30
Torsten Dittmann fb3a7bc0e9 fix: update attribute endpoints params 2023-02-27 13:15:11 +05:30
Torsten Dittmann acd18b4d9d tests: update attributes 2023-02-26 21:15:42 +05:30
Torsten Dittmann ec7e28b3e7 fix: databases update attributes events 2023-02-26 21:14:22 +05:30
Torsten Dittmann 5a2bbd0976 docs: update attributes 2023-02-26 21:13:27 +05:30
Torsten Dittmann 740e1956b5 revert: style changes 2023-02-26 18:07:44 +05:30
Torsten Dittmann 8ae974e6dd feat: database update attribute endpoints 2023-02-26 18:03:18 +05:30
Eldad A. FuxandGitHub f1fd44cee3 Merge pull request #5142 from appwrite/feat-13x-master-sync
Feat 13x master sync
2023-02-26 10:32:27 +02:00
Damodar LohaniandGitHub dd9eab65c8 Merge branch 'master' into feat-reset-sdk-account-model 2023-02-26 10:46:07 +05:45
Christy Jacob 941cb173c3 feat: upgrade CLI to 1.2.1 2023-02-22 11:22:14 +05:30
Christy Jacob b8efa441fb feat: upgrade CLI to 1.2.1 2023-02-22 11:06:21 +05:30
Jake Barnby 8c5220f455 Remove redundant test 2023-02-21 19:43:59 +13:00
Damodar Lohani 0b07fb2060 fix error 2023-02-21 05:18:41 +00:00
Jake Barnby b2fc7cc25a Remove redundant test 2023-02-21 17:59:10 +13:00
Damodar LohaniandGitHub 6b6f9edbd6 Merge branch '1.3.x' into feat-13x-master-sync 2023-02-21 07:38:46 +05:45
Jake Barnby 32fd00031d Update audit 2023-02-21 14:21:23 +13:00
Jake Barnby b8c11a5643 Fix test 2023-02-21 13:38:19 +13:00
Eldad A. FuxandGitHub 6540749559 Merge pull request #4866 from appwrite/feat-password-history
feat: check password history
2023-02-20 12:48:55 +02:00
Eldad A. FuxandGitHub cf0b039653 Merge pull request #4906 from appwrite/feat-password-dictionary
password dictionary
2023-02-20 11:42:42 +02:00
Damodar Lohani 104d99e636 fix default value error 2023-02-20 07:08:27 +00:00
Jake Barnby 6635ebf27f Remove indexed attribute query requirement 2023-02-20 19:29:25 +13:00
Jake Barnby 17fec2690a Add back param 2023-02-20 19:26:17 +13:00
Jake Barnby 94c58c367b Add back configurable limit for offset/limit 2023-02-20 19:18:19 +13:00
Jake Barnby ae3535de0d Remove count, limit and offset limitations 2023-02-20 19:03:15 +13:00
Damodar Lohani 1b9ee249be Merge remote-tracking branch 'origin/1.3.x' into feat-password-history 2023-02-20 04:02:23 +00:00
Damodar Lohani 81add700c6 fix error 2023-02-20 04:01:08 +00:00
Damodar Lohani c990f686dd Merge remote-tracking branch 'origin/1.3.x' into feat-password-dictionary 2023-02-20 03:56:48 +00:00
Damodar Lohani 4948aedfb5 Merge remote-tracking branch 'origin/master' into 1.3.x 2023-02-20 03:51:54 +00:00
Damodar LohaniandGitHub 9f3e815167 Merge branch 'feat-password-history' into feat-password-dictionary 2023-02-20 07:56:17 +05:45
Damodar Lohani e1cf464bcb Merge branch 'feat-password-history' of https://github.com/appwrite/appwrite into feat-password-history 2023-02-20 02:09:59 +00:00
Damodar Lohani 5863ba6285 update changes 2023-02-20 02:08:28 +00:00
Damodar Lohani 4e1a4b961c update attribute errors 2023-02-20 01:51:56 +00:00
Damodar Lohani 1904e3df81 fix formatting 2023-02-20 01:38:57 +00:00
Damodar Lohani 7e055c585d formatting fix 2023-02-20 01:37:33 +00:00
Damodar Lohani 452ee5c086 update dictonary validator 2023-02-20 01:34:05 +00:00
Eldad A. FuxandGitHub ed8c0ac02b Merge pull request #4973 from appwrite/feat-team-invite-improvements
Team Invite Improvements
2023-02-19 09:22:21 +02:00
Damodar Lohani a730d1ddc7 fix changelog 2023-02-16 07:31:24 +00:00
Damodar Lohani 8eb4c1dd7f update flutter version 2023-02-16 07:29:57 +00:00
b43ca1a539 Update app/config/platforms.php
Co-authored-by: Jake Barnby <jakeb994@gmail.com>
2023-02-16 11:55:10 +05:45
Damodar Lohani e1af86af98 update flutter changelog 2023-02-16 06:04:45 +00:00
Damodar Lohani 92f597cd49 update version numbers 2023-02-16 06:03:06 +00:00
Damodar Lohani 66beaf2cca remove space 2023-02-16 06:00:35 +00:00
Damodar Lohani c0968c9002 upgrade sdk generator 2023-02-16 06:00:24 +00:00
Jake Barnby 650d1af339 Merge remote-tracking branch 'origin/master' into feat-db-update-migrations 2023-02-15 20:35:32 +13:00
Jake Barnby d543705a54 Migration for database update 2023-02-15 20:35:24 +13:00
Damodar Lohani 2d702b62b2 switch SDK response model from account to user 2023-02-15 00:10:54 +00:00
Damodar Lohani 9e4f66cac4 update migration 2023-01-31 06:52:40 +00:00
Damodar Lohani 45bc0f4066 fix migration 2023-01-31 06:51:43 +00:00
Damodar Lohani 8149405207 exception constant not needed 2023-01-30 06:08:56 +00:00
Damodar Lohani daa121262b fix boolean param 2023-01-30 06:06:52 +00:00
Damodar Lohani 91abc2b079 fix SDK method 2023-01-30 06:06:05 +00:00
Damodar Lohani 2070cccd54 update description 2023-01-30 06:05:32 +00:00
Damodar LohaniandGitHub 31b4c73b16 use variable 2023-01-29 15:30:39 +05:45
f15dd063fd Update src/Appwrite/Migration/Version/V18.php
Co-authored-by: Matej Bačo <matejbacocom@gmail.com>
2023-01-29 15:11:42 +05:45
Damodar LohaniandGitHub b3481e08d3 Merge pull request #5014 from appwrite/gewenyu99-patch-team-invite-doc 2023-01-23 14:02:17 +05:45
1466e7b770 Update app/controllers/api/teams.php
Co-authored-by: Vincent (Wen Yu) Ge <vincent@appwrite.io>
2023-01-18 09:33:47 +05:45
Vincent (Wen Yu) GeandGitHub 33dab2ea46 Update create-team-membership.md 2023-01-17 10:18:50 -05:00
Vincent (Wen Yu) GeandGitHub 60bfae7e00 Update create-team-membership.md 2023-01-17 10:14:32 -05:00
Damodar LohaniandGitHub 2c23f7f149 update doc 2023-01-17 07:17:08 +05:45
Damodar Lohani 309d67066e Merge branch 'feat-password-history' of https://github.com/appwrite/appwrite into feat-password-dictionary 2023-01-16 09:55:12 +00:00
Damodar Lohani 7f3a2dcce7 fix model 2023-01-16 09:46:53 +00:00
Damodar Lohani aefe59a437 Merge branch 'feat-password-history' of https://github.com/appwrite/appwrite into feat-password-dictionary 2023-01-16 06:42:16 +00:00
Damodar Lohani 92e020b209 fix migration name 2023-01-16 06:41:44 +00:00
Damodar Lohani b7683364dd update changelog 2023-01-16 05:12:26 +00:00
Damodar Lohani 4f35353289 Merge branch 'feat-password-history' of https://github.com/appwrite/appwrite into feat-password-dictionary 2023-01-16 05:09:55 +00:00
Damodar Lohani 16b80e1ef8 new migration 2023-01-16 05:04:35 +00:00
Damodar Lohani fe472e5b36 Merge branch '1.3.x' of https://github.com/appwrite/appwrite into feat-password-history 2023-01-16 05:04:13 +00:00
Damodar Lohani afaa64b54b fix invitation after merge 2023-01-13 06:05:16 +00:00
Damodar LohaniandGitHub 3146ec363d Merge branch 'master' into feat-team-invite-improvements 2023-01-13 11:39:20 +05:45
Damodar Lohani b06ce91297 fix formatting 2023-01-09 11:11:55 +00:00
Damodar Lohani 8d40220114 remove var dumps 2023-01-09 11:10:50 +00:00
Damodar Lohani 11b3739360 fix when either email or phone were empty 2023-01-09 11:10:02 +00:00
Damodar Lohani a2642ecc67 send phone invite only if email is empty 2023-01-09 10:59:28 +00:00
Damodar Lohani 34b2280207 fix format 2023-01-09 09:18:13 +00:00
Damodar Lohani 5088c9ea99 simple test 2023-01-09 09:17:45 +00:00
Damodar Lohani 8f351ad7b2 set email and phone attribute once user found 2023-01-09 09:17:39 +00:00
Damodar Lohani bc7b98821a fix error 2023-01-09 08:56:18 +00:00
Damodar Lohani 32b8a1edfe fix param order in action 2023-01-09 08:44:02 +00:00
Damodar Lohani 29ef377b60 refactor privileged/app user check 2023-01-09 08:29:33 +00:00
Damodar Lohani 63a981591d fix error and param order 2023-01-09 08:25:15 +00:00
Damodar Lohani a812bfb686 format fix 2023-01-09 05:55:07 +00:00
Damodar Lohani 2e154c06bc different test and messaging integration as well 2023-01-09 05:46:02 +00:00
Damodar Lohani a0a08b3588 fix make password optional 2022-12-27 07:13:39 +00:00
Damodar Lohani 62dd5c275d fix explode 2022-12-27 06:16:19 +00:00
Damodar Lohani 8927c71b69 fix formatting 2022-12-26 10:34:41 +00:00
Damodar Lohani 96cf2e6330 password dictionary test 2022-12-26 10:27:04 +00:00
Damodar Lohani 0760ea90d6 use dictionary validator 2022-12-26 10:22:49 +00:00
Damodar Lohani 5649bc8060 load password dictionary as array 2022-12-26 10:22:38 +00:00
Damodar Lohani f03035451f fix test 2022-12-26 10:22:25 +00:00
Damodar Lohani a9078cded5 rename resource 2022-12-26 09:24:51 +00:00
50a5329b30 Update app/init.php
Co-authored-by: Eldad A. Fux <eldad.fux@gmail.com>
2022-12-26 15:04:06 +05:45
Damodar Lohani 87b3df919f clear cache after migration 2022-12-26 08:20:16 +00:00
Damodar Lohani abde948b43 fix typo 2022-12-26 06:03:43 +00:00
Damodar Lohani 44082a92f7 fix resonse model 2022-12-26 05:58:16 +00:00
Damodar Lohani 276032b3f7 error fix 2022-12-26 05:55:02 +00:00
Damodar Lohani 574ffa4d4b check dictionary is enabled before checking password 2022-12-26 05:52:49 +00:00
Damodar Lohani e9710bdb76 formatting fix 2022-12-26 05:47:20 +00:00
Damodar Lohani 124403b804 test for password discionary 2022-12-26 05:46:35 +00:00
Damodar Lohani 3bcb1f846e password disctionary endpont and project model 2022-12-26 05:31:49 +00:00
Damodar Lohani 1ff8ce2382 check against passwords dictionary 2022-12-26 05:24:26 +00:00
Damodar Lohani 2603f91a6a use password history on account create and update password 2022-12-23 07:19:35 +00:00
Damodar Lohani 5d61ff5fab password dictionary 2022-12-23 07:19:11 +00:00
Damodar Lohani eb9e7c737e fixed forgotten break 2022-12-22 04:56:17 +00:00
Damodar Lohani 772481451c test to set password history limit above 20 2022-12-21 06:42:27 +00:00
Damodar Lohani 1388f58b59 fix: formatting 2022-12-21 06:16:36 +00:00
Damodar Lohani ba5e0b4ae4 bump version 2022-12-21 05:43:10 +00:00
Damodar Lohani 82d20233e2 feat: add migration for password history 2022-12-21 05:41:16 +00:00
Damodar Lohani 679fd66507 add to changelog 2022-12-19 08:35:02 +00:00
Damodar Lohani 2019deb454 Merge branch 'feat-password-history' of https://github.com/appwrite/appwrite into feat-password-history 2022-12-19 08:28:30 +00:00
Damodar Lohani b35e5a04be fix users endpoint test 2022-12-19 08:28:02 +00:00
f72d075c40 Update src/Appwrite/Utopia/Response/Model/Project.php
Co-authored-by: Eldad A. Fux <eldad.fux@gmail.com>
2022-12-19 10:54:56 +05:45
Damodar Lohani 5b1c54c440 fix suggestions 2022-12-19 05:07:41 +00:00
95791c85ff Update app/controllers/api/projects.php
Co-authored-by: Eldad A. Fux <eldad.fux@gmail.com>
2022-12-19 10:49:18 +05:45
Damodar Lohani 28ac6c9355 fix validator 2022-12-18 09:37:13 +00:00
Damodar Lohani 30ece2d36a validator for password history 2022-12-18 09:08:51 +00:00
Damodar Lohani f7dd37a9d1 format fix 2022-12-18 08:54:53 +00:00
Damodar Lohani 7a9b9f2710 remove test 2022-12-18 08:53:01 +00:00
Damodar Lohani d098c8c698 use array slice 2022-12-18 08:47:02 +00:00
Damodar Lohani 3f26e66d26 not add random password to history 2022-12-18 08:35:12 +00:00
Damodar Lohani 15f52b933b fix excaping 2022-12-18 08:34:57 +00:00
9114a61fb2 Update src/Appwrite/Utopia/Response/Model/Project.php
Co-authored-by: Eldad A. Fux <eldad.fux@gmail.com>
2022-12-18 14:08:45 +05:45
ba77b35f05 Update app/controllers/api/projects.php
Co-authored-by: Eldad A. Fux <eldad.fux@gmail.com>
2022-12-18 14:05:55 +05:45
Damodar Lohani 4abc30eed1 refactor: fix formatting issues 2022-12-18 06:31:14 +00:00
Damodar Lohani 6612e6edf0 fix: password verify 2022-12-18 06:28:19 +00:00
Damodar Lohani 0eae73e7b8 fix: password comparison 2022-12-18 06:27:41 +00:00
Damodar Lohani 51ad9c6479 fix: get history limit before adding password to history 2022-12-18 04:38:27 +00:00
Damodar Lohani 0b1b7b8170 feat: check history limit 2022-12-16 10:47:08 +00:00
Damodar Lohani cfd5a91c43 feat: project endpoint to set password history limit 2022-12-16 10:37:49 +00:00
Damodar Lohani 61e03eeedf add new password to the history 2022-12-16 10:29:20 +00:00
Damodar Lohani 8e7b89ec03 feat: check password history 2022-12-16 10:22:39 +00:00
2846 changed files with 59279 additions and 895 deletions
+53
View File
@@ -0,0 +1,53 @@
name: "Release"
on:
release:
types: [published]
jobs:
tests:
name: Unit & E2E
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
# Fetch submodules
submodules: recursive
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v4
with:
images: appwrite/appwrite
tags: |
type=semver,pattern={{major}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}.{{minor}}.{{patch}}
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
platforms: linux/amd64,linux/arm64
build-args: |
VERSION=${{ steps.meta.outputs.version }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
+1 -1
View File
@@ -1,4 +1,4 @@
[submodule "app/console"]
path = app/console
url = https://github.com/appwrite/console
branch = 2.2.0
branch = 2.3.3
+24 -2
View File
@@ -1,6 +1,28 @@
# Version TBD
- Fix expire to formatTz in create account session [#4985](https://github.com/appwrite/appwrite/pull/4985)
# Version 1.3.1
## Bugs
- Fixed Migration issue regarding 500 error [4906](https://github.com/appwrite/appwrite/pull/5356)
# Version 1.3.0
## Features
- Password dictionary setting allows to compare user's password against command password database [4906](https://github.com/appwrite/appwrite/pull/4906)
- Password history setting allows to save user's last used password so that it may not be used again. Maximum number of history saved is 20, which can be configured. Minimum is 0 which means disabled. [#4866](https://github.com/appwrite/appwrite/pull/4866)
- Update APIs to check X-Appwrite-Timestamp header [#5024](https://github.com/appwrite/appwrite/pull/5024)
- Database relationships [#5238](https://github.com/appwrite/appwrite/pull/5238)
- New query operators [#5238](https://github.com/appwrite/appwrite/pull/5238)
- Team preferences [#5196](https://github.com/appwrite/appwrite/pull/5196)
- Update attribute metadata [#5164](https://github.com/appwrite/appwrite/pull/5164)
## Bugs
- Fix not storing function's response on response codes 5xx [#4610](https://github.com/appwrite/appwrite/pull/4610)
- Fix expire to formatTz in create account session [#4985](https://github.com/appwrite/appwrite/pull/4985)
- Fix deleting projects when organization is deleted [#5335](https://github.com/appwrite/appwrite/pull/5335)
- Fix deleting collections from a project [#4983](https://github.com/appwrite/appwrite/pull/4983)
- Fix cleaning up project databases [#4984](https://github.com/appwrite/appwrite/pull/4984)
- Fix creating documents with attributes with special characters [#246](https://github.com/utopia-php/database/pull/246)
- Fix deleting attribute not deleting metadata index [#246](https://github.com/utopia-php/database/pull/246)
- Fix create attribute event payload [#246](https://github.com/utopia-php/database/pull/246)
# Version 1.2.1
## Changes
+9 -2
View File
@@ -346,8 +346,7 @@ If you are in PHP Storm you don't need any plugin. Below are the settings requir
1. Create an init file.
2. Duplicate **dev/yasd_init.php.stub** file and name it **dev/yasd_init.php**.
3. Change the IP address to your development machine's IP. Without the proper IP address, the debugger won't connect.
4. Set **DEBUG** build arg in **appwrite** service in **docker-compose.yml** file.
3. Set **DEBUG** build arg in **appwrite** service in **docker-compose.yml** file.
### VS Code Launch Configuration
@@ -436,6 +435,14 @@ composer lint
composer lint <your file path>
```
## Clearing the Cache
If you need to clear the cache, you can do so by running the following command:
```bash
docker compose exec redis redis-cli FLUSHALL
```
## Tutorials
From time to time, our team will add tutorials that will help contributors find their way in the Appwrite source code. Below is a list of currently available tutorials:
+3 -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 node:16.14.2-alpine3.15 as node
FROM --platform=$BUILDPLATFORM node:16.14.2-alpine3.15 as node
COPY app/console /usr/local/src/console
@@ -29,7 +29,7 @@ ENV VITE_APPWRITE_GROWTH_ENDPOINT=$VITE_APPWRITE_GROWTH_ENDPOINT
RUN npm ci
RUN npm run build
FROM appwrite/base:0.2.0 as final
FROM appwrite/base:0.2.2 as final
LABEL maintainer="team@appwrite.io"
@@ -182,7 +182,7 @@ RUN chmod +x /usr/local/bin/doctor && \
RUN mkdir -p /etc/letsencrypt/live/ && chmod -Rf 755 /etc/letsencrypt/live/
# Enable Extensions
RUN if [ "$DEBUG" == "true" ]; then printf "zend_extension=yasd \nyasd.debug_mode=remote \nyasd.init_file=/usr/local/dev/yasd_init.php \nyasd.remote_port=9005 \nyasd.log_level=-1" >> /usr/local/etc/php/conf.d/yasd.ini; fi
RUN if [ "$DEBUG" == "true" ]; then printf "zend_extension=yasd \nyasd.debug_mode=remote \nyasd.init_file=/usr/src/code/dev/yasd_init.php \nyasd.remote_port=9005 \nyasd.log_level=-1" >> /usr/local/etc/php/conf.d/yasd.ini; fi
RUN if [ "$DEBUG" == "true" ]; then echo "opcache.enable=0" >> /usr/local/etc/php/conf.d/appwrite.ini; fi
RUN echo "opcache.preload_user=www-data" >> /usr/local/etc/php/conf.d/appwrite.ini
+5 -5
View File
@@ -12,7 +12,7 @@
</p>
<!-- [![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=friendly&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)
@@ -24,7 +24,7 @@
[English](README.md) | 简体中文
[**我们发布了 Appwrite Console 2.0 版本,点击这里了解更多!**](https://medium.com/appwrite-io/announcing-console-2-0-2e0e96891cb0?source=friends_link&sk=7a82b4069778e3adc165dc026e960fe1)
[**宣布带有数据库关系的 Appwrite 1.3!了解最新消息!**](https://dev.to/appwrite/join-celebrations-appwrite-13-ships-relationships-57fc)
Appwrite是一个基于Docker的端到端开发者平台,其容器化的微服务库可应用于网页端,移动端,以及后端。Appwrite 通过视觉化界面简化了从零开始编写 API 的繁琐过程,在保证软件安全的前提下为开发者创造了一个高效的开发环境。
@@ -67,7 +67,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.2.1
appwrite/appwrite:1.3.1
```
### Windows
@@ -79,7 +79,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.2.1
appwrite/appwrite:1.3.1
```
#### PowerShell
@@ -89,7 +89,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.2.1
appwrite/appwrite:1.3.1
```
运行后,可以在浏览器上访问 http://localhost 找到 Appwrite 控制台。在非 Linux 的本机主机上完成安装后,服务器可能需要几分钟才能启动。
+5 -4
View File
@@ -14,6 +14,7 @@
<!-- [![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)
@@ -25,7 +26,7 @@
English | [简体中文](README-CN.md)
[**Announcing Appwrite 1.2 with GraphQL support! Learn what's new!**](https://appwrite.io/graphql)
[**Announcing Appwrite 1.3 with Database Relationships! Learn what's new!**](https://dev.to/appwrite/join-celebrations-appwrite-13-ships-relationships-57fc)
Appwrite is an end-to-end backend server for Web, Mobile, Native, or Backend apps packaged as a set of Docker<nobr> microservices. Appwrite abstracts the complexity and repetitiveness required to build a modern backend API from scratch and allows you to build secure apps faster.
@@ -75,7 +76,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.2.1
appwrite/appwrite:1.3.1
```
### Windows
@@ -87,7 +88,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.2.1
appwrite/appwrite:1.3.1
```
#### PowerShell
@@ -97,7 +98,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.2.1
appwrite/appwrite:1.3.1
```
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.
+2 -2
View File
@@ -4,11 +4,11 @@
| Version | Supported |
| --------- | ------------------ |
| <= 0.14.x | :x: |
| 0.15.x | :white_check_mark: |
| <= 0.15.x | :x: |
| 1.0.x | :white_check_mark: |
| 1.1.x | :white_check_mark: |
| 1.2.x | :white_check_mark: |
| 1.3.x | :white_check_mark: |
## Reporting a Vulnerability
File diff suppressed because it is too large Load Diff
+32
View File
@@ -346,6 +346,16 @@ $collections = [
'array' => true,
'filters' => [],
],
[
'$id' => ID::custom('options'),
'type' => Database::VAR_STRING,
'size' => 16384,
'signed' => false,
'required' => false,
'default' => null,
'array' => false,
'filters' => ['json'],
],
],
'indexes' => [
[
@@ -1234,6 +1244,17 @@ $collections = [
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('passwordHistory'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16384,
'signed' => true,
'required' => false,
'default' => null,
'array' => true,
'filters' => [],
],
[
'$id' => ID::custom('password'),
'type' => Database::VAR_STRING,
@@ -1854,6 +1875,17 @@ $collections = [
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('prefs'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 65535,
'signed' => true,
'required' => false,
'default' => new \stdClass(),
'array' => false,
'filters' => ['json'],
],
],
'indexes' => [
[
+23 -3
View File
@@ -408,6 +408,16 @@ return [
'description' => 'Document with the requested ID already exists.',
'code' => 409,
],
Exception::DOCUMENT_UPDATE_CONFLICT => [
'name' => Exception::DOCUMENT_UPDATE_CONFLICT,
'description' => 'Remote document is newer than local.',
'code' => 409,
],
Exception::DOCUMENT_DELETE_RESTRICTED => [
'name' => Exception::DOCUMENT_DELETE_RESTRICTED,
'description' => 'Document cannot be deleted because it is referenced by another document.',
'code' => 403,
],
/** Attributes */
Exception::ATTRIBUTE_NOT_FOUND => [
@@ -417,12 +427,12 @@ return [
],
Exception::ATTRIBUTE_UNKNOWN => [
'name' => Exception::ATTRIBUTE_UNKNOWN,
'description' => 'The attribute required for the index could not be found. Please confirm all your attributes are in the <span class="tag">available</span> state.',
'description' => 'The attribute required for the index could not be found. Please confirm all your attributes are in the available state.',
'code' => 400,
],
Exception::ATTRIBUTE_NOT_AVAILABLE => [
'name' => Exception::ATTRIBUTE_NOT_AVAILABLE,
'description' => 'The requested attribute is not yet <span class="tag">available</span>. Please try again later.',
'description' => 'The requested attribute is not yet available. Please try again later.',
'code' => 400,
],
Exception::ATTRIBUTE_FORMAT_UNSUPPORTED => [
@@ -432,7 +442,7 @@ return [
],
Exception::ATTRIBUTE_DEFAULT_UNSUPPORTED => [
'name' => Exception::ATTRIBUTE_DEFAULT_UNSUPPORTED,
'description' => 'Default values cannot be set for <span class="tag">array</span> and <span class="tag">required</span> attributes.',
'description' => 'Default values cannot be set for array or required attributes.',
'code' => 400,
],
Exception::ATTRIBUTE_ALREADY_EXISTS => [
@@ -450,6 +460,11 @@ return [
'description' => 'The attribute value is invalid. Please check the type, range and value of the attribute.',
'code' => 400,
],
Exception::ATTRIBUTE_TYPE_INVALID => [
'name' => Exception::ATTRIBUTE_TYPE_INVALID,
'description' => 'The attribute type is invalid.',
'code' => 400,
],
/** Indexes */
Exception::INDEX_NOT_FOUND => [
@@ -549,6 +564,11 @@ return [
'description' => 'Domain verification for the requested domain has failed.',
'code' => 401,
],
Exception::DOMAIN_TARGET_INVALID => [
'name' => Exception::DOMAIN_TARGET_INVALID,
'description' => 'Your Appwrite instance is not publicly accessible. Please check the _APP_DOMAIN_TARGET environment variable of your Appwrite server.',
'code' => 501,
],
Exception::GRAPHQL_NO_QUERY => [
'name' => Exception::GRAPHQL_NO_QUERY,
'description' => 'Param "query" is not optional.',
+6 -3
View File
@@ -183,13 +183,16 @@ return [
],
],
'create' => [
'$description' => 'This event triggers when a bucket is created.'
'$description' => 'This event triggers when a team is created.'
],
'delete' => [
'$description' => 'This event triggers when a bucket is deleted.',
'$description' => 'This event triggers when a team is deleted.',
],
'update' => [
'$description' => 'This event triggers when a bucket is updated.',
'$description' => 'This event triggers when a team is updated.',
'prefs' => [
'$description' => 'This event triggers when a team\'s preferences are updated.',
],
]
],
'functions' => [
+17 -17
View File
@@ -15,7 +15,7 @@ return [
[
'key' => 'web',
'name' => 'Web',
'version' => '10.2.0',
'version' => '11.0.0',
'url' => 'https://github.com/appwrite/sdk-for-web',
'package' => 'https://www.npmjs.com/package/appwrite',
'enabled' => true,
@@ -63,7 +63,7 @@ return [
[
'key' => 'flutter',
'name' => 'Flutter',
'version' => '8.2.0',
'version' => '9.0.0',
'url' => 'https://github.com/appwrite/sdk-for-flutter',
'package' => 'https://pub.dev/packages/appwrite',
'enabled' => true,
@@ -81,7 +81,7 @@ return [
[
'key' => 'apple',
'name' => 'Apple',
'version' => '1.2.0',
'version' => '2.0.0',
'url' => 'https://github.com/appwrite/sdk-for-apple',
'package' => 'https://github.com/appwrite/sdk-for-apple',
'enabled' => true,
@@ -116,7 +116,7 @@ return [
[
'key' => 'android',
'name' => 'Android',
'version' => '1.2.0',
'version' => '2.0.0',
'url' => 'https://github.com/appwrite/sdk-for-android',
'package' => 'https://search.maven.org/artifact/io.appwrite/sdk-for-android',
'enabled' => true,
@@ -185,7 +185,7 @@ return [
[
'key' => 'web',
'name' => 'Console',
'version' => '0.0.1',
'version' => '0.1.0',
'url' => 'https://github.com/appwrite/sdk-for-console',
'package' => '',
'enabled' => true,
@@ -203,7 +203,7 @@ return [
[
'key' => 'cli',
'name' => 'Command Line',
'version' => '1.1.1',
'version' => '2.0.0',
'url' => 'https://github.com/appwrite/sdk-for-cli',
'package' => 'https://www.npmjs.com/package/appwrite-cli',
'enabled' => true,
@@ -231,7 +231,7 @@ return [
[
'key' => 'nodejs',
'name' => 'Node.js',
'version' => '8.2.0',
'version' => '9.0.0',
'url' => 'https://github.com/appwrite/sdk-for-node',
'package' => 'https://www.npmjs.com/package/node-appwrite',
'enabled' => true,
@@ -249,7 +249,7 @@ return [
[
'key' => 'deno',
'name' => 'Deno',
'version' => '6.2.0',
'version' => '7.0.0',
'url' => 'https://github.com/appwrite/sdk-for-deno',
'package' => 'https://deno.land/x/appwrite',
'enabled' => true,
@@ -267,7 +267,7 @@ return [
[
'key' => 'php',
'name' => 'PHP',
'version' => '7.2.0',
'version' => '8.0.0',
'url' => 'https://github.com/appwrite/sdk-for-php',
'package' => 'https://packagist.org/packages/appwrite/appwrite',
'enabled' => true,
@@ -285,7 +285,7 @@ return [
[
'key' => 'python',
'name' => 'Python',
'version' => '1.2.0',
'version' => '2.0.0',
'url' => 'https://github.com/appwrite/sdk-for-python',
'package' => 'https://pypi.org/project/appwrite/',
'enabled' => true,
@@ -303,7 +303,7 @@ return [
[
'key' => 'ruby',
'name' => 'Ruby',
'version' => '7.2.0',
'version' => '8.0.0',
'url' => 'https://github.com/appwrite/sdk-for-ruby',
'package' => 'https://rubygems.org/gems/appwrite',
'enabled' => true,
@@ -321,7 +321,7 @@ return [
[
'key' => 'go',
'name' => 'Go',
'version' => '1.2.0',
'version' => '2.0.0',
'url' => 'https://github.com/appwrite/sdk-for-go',
'package' => '',
'enabled' => false,
@@ -339,7 +339,7 @@ return [
[
'key' => 'java',
'name' => 'Java',
'version' => '1.2.0',
'version' => '2.0.0',
'url' => 'https://github.com/appwrite/sdk-for-java',
'package' => '',
'enabled' => false,
@@ -357,7 +357,7 @@ return [
[
'key' => 'dotnet',
'name' => '.NET',
'version' => '1.2.0',
'version' => '2.0.0',
'url' => 'https://github.com/appwrite/sdk-for-dotnet',
'package' => 'https://www.nuget.org/packages/Appwrite',
'enabled' => false,
@@ -375,7 +375,7 @@ return [
[
'key' => 'dart',
'name' => 'Dart',
'version' => '7.2.0',
'version' => '8.0.0',
'url' => 'https://github.com/appwrite/sdk-for-dart',
'package' => 'https://pub.dev/packages/dart_appwrite',
'enabled' => true,
@@ -393,7 +393,7 @@ return [
[
'key' => 'kotlin',
'name' => 'Kotlin',
'version' => '1.2.0',
'version' => '2.0.0',
'url' => 'https://github.com/appwrite/sdk-for-kotlin',
'package' => 'https://search.maven.org/artifact/io.appwrite/sdk-for-kotlin',
'enabled' => true,
@@ -415,7 +415,7 @@ return [
[
'key' => 'swift',
'name' => 'Swift',
'version' => '1.2.0',
'version' => '2.0.0',
'url' => 'https://github.com/appwrite/sdk-for-swift',
'package' => 'https://github.com/appwrite/sdk-for-swift',
'enabled' => true,
+18 -5
View File
@@ -1,9 +1,9 @@
<?php
return [
'/' => [
'key' => 'homepage',
'name' => 'Homepage',
'web/home' => [
'key' => 'web/home',
'name' => 'Home',
'subtitle' => '',
'description' => '',
'controller' => 'web/home.php',
@@ -14,8 +14,8 @@ return [
'optional' => false,
'icon' => '',
],
'console' => [
'key' => 'console',
'web/console' => [
'key' => 'web/console',
'name' => 'Console',
'subtitle' => '',
'description' => '',
@@ -186,4 +186,17 @@ return [
'optional' => true,
'icon' => '/images/services/graphql.png',
],
'console' => [
'key' => 'console',
'name' => 'Console',
'subtitle' => 'The Console service allows you to interact with console relevant informations.',
'description' => '',
'controller' => 'api/console.php',
'sdk' => true,
'docs' => true,
'docsUrl' => '',
'tests' => false,
'optional' => false,
'icon' => '',
],
];
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -764,7 +764,7 @@ return [
],
[
'name' => '_APP_FUNCTIONS_INACTIVE_THRESHOLD',
'description' => 'The minimum time a function can be inactive before it\'s container is shutdown and put to sleep. The default value is 60 seconds',
'description' => 'The minimum time a function must be inactive before it can be shut down and cleaned up. This feature is intended to clean up unused containers. Containers may remain active for longer than the interval before being shut down, as Appwrite only cleans up unused containers every hour. If no value is provided, the default is 60 seconds.',
'introduction' => '0.13.0',
'default' => '60',
'required' => false,
+78 -38
View File
@@ -40,6 +40,8 @@ use Utopia\Validator\ArrayList;
use Utopia\Validator\Assoc;
use Utopia\Validator\Text;
use Utopia\Validator\WhiteList;
use Appwrite\Auth\Validator\PasswordHistory;
use Appwrite\Auth\Validator\PasswordDictionary;
$oauthDefaultSuccess = '/auth/oauth2/success';
$oauthDefaultFailure = '/auth/oauth2/failure';
@@ -60,11 +62,11 @@ App::post('/v1/account')
->label('sdk.description', '/docs/references/account/create.md')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_ACCOUNT)
->label('sdk.response.model', Response::MODEL_USER)
->label('abuse-limit', 10)
->param('userId', '', new CustomId(), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
->param('email', '', new Email(), 'User email.')
->param('password', '', new Password(), 'User password. Must be at least 8 chars.')
->param('password', '', fn ($project, $passwordsDictionary) => new PasswordDictionary($passwordsDictionary, $project->getAttribute('auths', [])['passwordDictionary'] ?? false), 'New user password. Must be at least 8 chars.', false, ['project', 'passwordsDictionary'])
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
->inject('request')
->inject('response')
@@ -72,7 +74,6 @@ App::post('/v1/account')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $email, string $password, string $name, Request $request, Response $response, Document $project, Database $dbForProject, Event $events) {
$email = \strtolower($email);
if ('console' === $project->getId()) {
$whitelistEmails = $project->getAttribute('authWhitelistEmails');
@@ -97,6 +98,8 @@ App::post('/v1/account')
}
}
$passwordHistory = $project->getAttribute('auths', [])['passwordHistory'] ?? 0;
$password = Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS);
try {
$userId = $userId == 'unique()' ? ID::unique() : $userId;
$user = Authorization::skip(fn() => $dbForProject->createDocument('users', new Document([
@@ -109,10 +112,11 @@ App::post('/v1/account')
'email' => $email,
'emailVerification' => false,
'status' => true,
'password' => Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS),
'password' => $password,
'passwordHistory' => $passwordHistory > 0 ? [$password] : [],
'passwordUpdate' => DateTime::now(),
'hash' => Auth::DEFAULT_ALGO,
'hashOptions' => Auth::DEFAULT_ALGO_OPTIONS,
'passwordUpdate' => DateTime::now(),
'registration' => DateTime::now(),
'reset' => false,
'name' => $name,
@@ -501,8 +505,11 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
}
}
$passwordHistory = $project->getAttribute('auths', [])['passwordHistory'] ?? 0;
try {
$userId = ID::unique();
$password = Auth::passwordHash(Auth::passwordGenerator(), Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS);
$user = Authorization::skip(fn() => $dbForProject->createDocument('users', new Document([
'$id' => $userId,
'$permissions' => [
@@ -513,7 +520,8 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
'email' => $email,
'emailVerification' => true,
'status' => true, // Email should already be authenticated by OAuth2 provider
'password' => Auth::passwordHash(Auth::passwordGenerator(), Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS),
'passwordHistory' => $passwordHistory > 0 ? [$password] : null,
'password' => $password,
'hash' => Auth::DEFAULT_ALGO,
'hashOptions' => Auth::DEFAULT_ALGO_OPTIONS,
'passwordUpdate' => null,
@@ -1320,7 +1328,7 @@ App::get('/v1/account')
->label('sdk.description', '/docs/references/account/get.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_ACCOUNT)
->label('sdk.response.model', Response::MODEL_USER)
->label('sdk.offline.model', '/account')
->label('sdk.offline.key', 'current')
->inject('response')
@@ -1348,7 +1356,7 @@ App::get('/v1/account/prefs')
->inject('user')
->action(function (Response $response, Document $user) {
$prefs = $user->getAttribute('prefs', new \stdClass());
$prefs = $user->getAttribute('prefs', []);
$response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES);
});
@@ -1403,7 +1411,7 @@ App::get('/v1/account/logs')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_LOG_LIST)
->param('queries', [], new Queries(new Limit(), new Offset()), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Only supported methods are limit and offset', true)
->param('queries', [], new Queries(new Limit(), new Offset()), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
->inject('response')
->inject('user')
->inject('locale')
@@ -1512,19 +1520,22 @@ App::patch('/v1/account/name')
->label('sdk.description', '/docs/references/account/update-name.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_ACCOUNT)
->label('sdk.response.model', Response::MODEL_USER)
->label('sdk.offline.model', '/account')
->label('sdk.offline.key', 'current')
->param('name', '', new Text(128), 'User name. Max length: 128 chars.')
->inject('requestTimestamp')
->inject('response')
->inject('user')
->inject('dbForProject')
->inject('events')
->action(function (string $name, Response $response, Document $user, Database $dbForProject, Event $events) {
->action(function (string $name, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $events) {
$user = $dbForProject->updateDocument('users', $user->getId(), $user
$user
->setAttribute('name', $name)
->setAttribute('search', implode(' ', [$user->getId(), $name, $user->getAttribute('email', ''), $user->getAttribute('phone', '')])));
->setAttribute('search', implode(' ', [$user->getId(), $name, $user->getAttribute('email', ''), $user->getAttribute('phone', '')]));
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
$events->setParam('userId', $user->getId());
@@ -1546,27 +1557,46 @@ App::patch('/v1/account/password')
->label('sdk.description', '/docs/references/account/update-password.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_ACCOUNT)
->label('sdk.response.model', Response::MODEL_USER)
->label('sdk.offline.model', '/account')
->label('sdk.offline.key', 'current')
->param('password', '', new Password(), 'New user password. Must be at least 8 chars.')
->param('password', '', fn ($project, $passwordsDictionary) => new PasswordDictionary($passwordsDictionary, $project->getAttribute('auths', [])['passwordDictionary'] ?? false), 'New user password. Must be at least 8 chars.', false, ['project', 'passwordsDictionary'])
->param('oldPassword', '', new Password(), 'Current user password. Must be at least 8 chars.', true)
->inject('requestTimestamp')
->inject('response')
->inject('user')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $password, string $oldPassword, Response $response, Document $user, Database $dbForProject, Event $events) {
->action(function (string $password, string $oldPassword, ?\DateTime $requestTimestamp, Response $response, Document $user, Document $project, Database $dbForProject, Event $events) {
// Check old password only if its an existing user.
if (!empty($user->getAttribute('passwordUpdate')) && !Auth::passwordVerify($oldPassword, $user->getAttribute('password'), $user->getAttribute('hash'), $user->getAttribute('hashOptions'))) { // Double check user password
throw new Exception(Exception::USER_INVALID_CREDENTIALS);
}
$user = $dbForProject->updateDocument('users', $user->getId(), $user
->setAttribute('password', Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS))
->setAttribute('hash', Auth::DEFAULT_ALGO)
->setAttribute('hashOptions', Auth::DEFAULT_ALGO_OPTIONS)
->setAttribute('passwordUpdate', DateTime::now()));
$newPassword = Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS);
$historyLimit = $project->getAttribute('auths', [])['passwordHistory'] ?? 0;
$history = [];
if ($historyLimit > 0) {
$history = $user->getAttribute('passwordHistory', []);
$validator = new PasswordHistory($history, $user->getAttribute('hash'), $user->getAttribute('hashOptions'));
if (!$validator->isValid($password)) {
throw new Exception(Exception::USER_PASSWORD_RECENTLY_USED, 'The password was recently used', 409);
}
$history[] = $newPassword;
array_slice($history, (count($history) - $historyLimit), $historyLimit);
}
$user
->setAttribute('password', $newPassword)
->setAttribute('passwordHistory', $history)
->setAttribute('passwordUpdate', DateTime::now())
->setAttribute('hash', Auth::DEFAULT_ALGO)
->setAttribute('hashOptions', Auth::DEFAULT_ALGO_OPTIONS);
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
$events->setParam('userId', $user->getId());
@@ -1588,16 +1618,17 @@ App::patch('/v1/account/email')
->label('sdk.description', '/docs/references/account/update-email.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_ACCOUNT)
->label('sdk.response.model', Response::MODEL_USER)
->label('sdk.offline.model', '/account')
->label('sdk.offline.key', 'current')
->param('email', '', new Email(), 'User email.')
->param('password', '', new Password(), 'User password. Must be at least 8 chars.')
->inject('requestTimestamp')
->inject('response')
->inject('user')
->inject('dbForProject')
->inject('events')
->action(function (string $email, string $password, Response $response, Document $user, Database $dbForProject, Event $events) {
->action(function (string $email, string $password, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $events) {
$isAnonymousUser = Auth::isAnonymousUser($user); // Check if request is from an anonymous account for converting
if (
@@ -1618,7 +1649,7 @@ App::patch('/v1/account/email')
->setAttribute('search', implode(' ', [$user->getId(), $user->getAttribute('name', ''), $email, $user->getAttribute('phone', '')]));
try {
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
} catch (Duplicate $th) {
throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS);
}
@@ -1643,16 +1674,17 @@ App::patch('/v1/account/phone')
->label('sdk.description', '/docs/references/account/update-phone.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_ACCOUNT)
->label('sdk.response.model', Response::MODEL_USER)
->label('sdk.offline.model', '/account')
->label('sdk.offline.key', 'current')
->param('phone', '', new Phone(), 'Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.')
->param('password', '', new Password(), 'User password. Must be at least 8 chars.')
->inject('requestTimestamp')
->inject('response')
->inject('user')
->inject('dbForProject')
->inject('events')
->action(function (string $phone, string $password, Response $response, Document $user, Database $dbForProject, Event $events) {
->action(function (string $phone, string $password, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $events) {
$isAnonymousUser = Auth::isAnonymousUser($user); // Check if request is from an anonymous account for converting
@@ -1669,7 +1701,7 @@ App::patch('/v1/account/phone')
->setAttribute('search', implode(' ', [$user->getId(), $user->getAttribute('name', ''), $user->getAttribute('email', ''), $phone]));
try {
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
} catch (Duplicate $th) {
throw new Exception(Exception::USER_PHONE_ALREADY_EXISTS);
}
@@ -1694,17 +1726,20 @@ App::patch('/v1/account/prefs')
->label('sdk.description', '/docs/references/account/update-prefs.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_ACCOUNT)
->label('sdk.response.model', Response::MODEL_USER)
->label('sdk.offline.model', '/account/prefs')
->label('sdk.offline.key', 'current')
->param('prefs', [], new Assoc(), 'Prefs key-value JSON object.')
->inject('requestTimestamp')
->inject('response')
->inject('user')
->inject('dbForProject')
->inject('events')
->action(function (array $prefs, Response $response, Document $user, Database $dbForProject, Event $events) {
->action(function (array $prefs, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $events) {
$user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('prefs', $prefs));
$user->setAttribute('prefs', $prefs);
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
$events->setParam('userId', $user->getId());
@@ -1726,15 +1761,17 @@ App::patch('/v1/account/status')
->label('sdk.description', '/docs/references/account/update-status.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_ACCOUNT)
->inject('request')
->label('sdk.response.model', Response::MODEL_USER)
->inject('requestTimestamp')
->inject('response')
->inject('user')
->inject('dbForProject')
->inject('events')
->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Event $events) {
->action(function (?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $events) {
$user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('status', false));
$user->setAttribute('status', false);
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
$events
->setParam('userId', $user->getId())
@@ -1764,6 +1801,7 @@ App::delete('/v1/account/sessions/:sessionId')
->label('sdk.response.model', Response::MODEL_NONE)
->label('abuse-limit', 100)
->param('sessionId', '', new UID(), 'Session ID. Use the string \'current\' to delete the current device session.')
->inject('requestTimestamp')
->inject('request')
->inject('response')
->inject('user')
@@ -1771,7 +1809,7 @@ App::delete('/v1/account/sessions/:sessionId')
->inject('locale')
->inject('events')
->inject('project')
->action(function (?string $sessionId, Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Event $events, Document $project) {
->action(function (?string $sessionId, ?\DateTime $requestTimestamp, Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Event $events, Document $project) {
$protocol = $request->getProtocol();
$authDuration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG;
@@ -1783,9 +1821,11 @@ App::delete('/v1/account/sessions/:sessionId')
foreach ($sessions as $key => $session) {/** @var Document $session */
if ($sessionId == $session->getId()) {
unset($sessions[$key]);
$dbForProject->withRequestTimestamp($requestTimestamp, function () use ($dbForProject, $session) {
return $dbForProject->deleteDocument('sessions', $session->getId());
});
$dbForProject->deleteDocument('sessions', $session->getId());
unset($sessions[$key]);
$session->setAttribute('current', false);
@@ -2146,9 +2186,9 @@ App::put('/v1/account/recovery')
$profile = $dbForProject->updateDocument('users', $profile->getId(), $profile
->setAttribute('password', Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS))
->setAttribute('passwordUpdate', DateTime::now())
->setAttribute('hash', Auth::DEFAULT_ALGO)
->setAttribute('hashOptions', Auth::DEFAULT_ALGO_OPTIONS)
->setAttribute('passwordUpdate', DateTime::now())
->setAttribute('emailVerification', true));
$recoveryDocument = $dbForProject->getDocument('tokens', $recovery);
+40
View File
@@ -0,0 +1,40 @@
<?php
use Appwrite\Extend\Exception;
use Appwrite\Utopia\Response;
use Utopia\App;
use Utopia\Database\Document;
App::init()
->groups(['console'])
->inject('project')
->action(function (Document $project) {
if ($project->getId() !== 'console') {
throw new Exception(Exception::GENERAL_ACCESS_FORBIDDEN);
}
});
App::get('/v1/console/variables')
->desc('Get Variables')
->groups(['api', 'projects'])
->label('scope', 'projects.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'console')
->label('sdk.method', 'variables')
->label('sdk.description', '/docs/references/console/variables.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_CONSOLE_VARIABLES)
->inject('response')
->action(function (Response $response) {
$variables = new Document([
'_APP_DOMAIN_TARGET' => App::getEnv('_APP_DOMAIN_TARGET'),
'_APP_STORAGE_LIMIT' => +App::getEnv('_APP_STORAGE_LIMIT'),
'_APP_FUNCTIONS_SIZE_LIMIT' => +App::getEnv('_APP_FUNCTIONS_SIZE_LIMIT'),
'_APP_USAGE_STATS' => App::getEnv('_APP_USAGE_STATS'),
]);
$response->dynamic($variables, Response::MODEL_CONSOLE_VARIABLES);
});
File diff suppressed because it is too large Load Diff
+9 -11
View File
@@ -25,7 +25,6 @@ use Appwrite\Task\Validator\Cron;
use Appwrite\Utopia\Database\Validator\Queries\Deployments;
use Appwrite\Utopia\Database\Validator\Queries\Executions;
use Appwrite\Utopia\Database\Validator\Queries\Functions;
use Appwrite\Utopia\Database\Validator\Queries\Variables;
use Utopia\App;
use Utopia\Database\Database;
use Utopia\Database\Document;
@@ -33,7 +32,6 @@ use Utopia\Database\DateTime;
use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Assoc;
use Utopia\Validator\Text;
use Utopia\Validator\Range;
use Utopia\Validator\WhiteList;
@@ -63,7 +61,7 @@ App::post('/v1/functions')
->label('sdk.response.model', Response::MODEL_FUNCTION)
->param('functionId', '', new CustomId(), 'Function ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
->param('name', '', new Text(128), 'Function name. Max length: 128 chars.')
->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.')
->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.', true)
->param('runtime', '', new WhiteList(array_keys(Config::getParam('runtimes')), true), 'Execution runtime.')
->param('events', [], new ArrayList(new ValidatorEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.', true)
->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true)
@@ -125,7 +123,7 @@ App::get('/v1/functions')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_FUNCTION_LIST)
->param('queries', [], new Functions(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Functions::ALLOWED_ATTRIBUTES), true)
->param('queries', [], new Functions(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Functions::ALLOWED_ATTRIBUTES), true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('response')
->inject('dbForProject')
@@ -440,7 +438,7 @@ App::put('/v1/functions/:functionId')
->label('sdk.response.model', Response::MODEL_FUNCTION)
->param('functionId', '', new UID(), 'Function ID.')
->param('name', '', new Text(128), 'Function name. Max length: 128 chars.')
->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.')
->param('execute', [], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings with execution roles. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.', true)
->param('events', [], new ArrayList(new ValidatorEvent(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.', true)
->param('schedule', '', new Cron(), 'Schedule CRON syntax.', true)
->param('timeout', 15, new Range(1, (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)), 'Maximum execution time in seconds.', true)
@@ -601,8 +599,8 @@ App::post('/v1/functions/:functionId/deployments')
->label('sdk.response.model', Response::MODEL_DEPLOYMENT)
->param('functionId', '', new UID(), 'Function ID.')
->param('entrypoint', '', new Text('1028'), 'Entrypoint File.')
->param('code', [], new File(), 'Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.', false)
->param('activate', false, new Boolean(true), 'Automatically activate the deployment when it is finished building.', false)
->param('code', [], new File(), 'Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.', skipValidation: true)
->param('activate', false, new Boolean(true), 'Automatically activate the deployment when it is finished building.')
->inject('request')
->inject('response')
->inject('dbForProject')
@@ -791,7 +789,7 @@ App::get('/v1/functions/:functionId/deployments')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_DEPLOYMENT_LIST)
->param('functionId', '', new UID(), 'Function ID.')
->param('queries', [], new Deployments(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Deployments::ALLOWED_ATTRIBUTES), true)
->param('queries', [], new Deployments(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Deployments::ALLOWED_ATTRIBUTES), true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('response')
->inject('dbForProject')
@@ -1223,7 +1221,7 @@ App::get('/v1/functions/:functionId/executions')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_EXECUTION_LIST)
->param('functionId', '', new UID(), 'Function ID.')
->param('queries', [], new Executions(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Executions::ALLOWED_ATTRIBUTES), true)
->param('queries', [], new Executions(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Executions::ALLOWED_ATTRIBUTES), true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('response')
->inject('dbForProject')
@@ -1348,7 +1346,7 @@ App::post('/v1/functions/:functionId/variables')
->label('sdk.response.model', Response::MODEL_VARIABLE)
->param('functionId', '', new UID(), 'Function unique ID.', false)
->param('key', null, new Text(Database::LENGTH_KEY), 'Variable key. Max length: ' . Database::LENGTH_KEY . ' chars.', false)
->param('value', null, new Text(8192), 'Variable value. Max length: 8192 chars.', false)
->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', false)
->inject('response')
->inject('dbForProject')
->action(function (string $functionId, string $key, string $value, Response $response, Database $dbForProject) {
@@ -1464,7 +1462,7 @@ App::put('/v1/functions/:functionId/variables/:variableId')
->param('functionId', '', new UID(), 'Function unique ID.', false)
->param('variableId', '', new UID(), 'Variable unique ID.', false)
->param('key', null, new Text(255), 'Variable key. Max length: 255 chars.', false)
->param('value', null, new Text(8192), 'Variable value. Max length: 8192 chars.', true)
->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', true)
->inject('response')
->inject('dbForProject')
->action(function (string $functionId, string $variableId, string $key, ?string $value, Response $response, Database $dbForProject) {
+1 -1
View File
@@ -30,7 +30,7 @@ App::get('/v1/graphql')
->label('sdk.response.model', Response::MODEL_ANY)
->label('abuse-limit', 60)
->label('abuse-time', 60)
->param('query', '', new Text(0), 'The query to execute.')
->param('query', '', new Text(0, 0), 'The query to execute.')
->param('operationName', '', new Text(256), 'The name of the operation to execute.', true)
->param('variables', '', new Text(0), 'The JSON encoded variables to use in the query.', true)
->inject('request')
+66 -4
View File
@@ -23,7 +23,7 @@ use Utopia\Database\Helpers\Permission;
use Utopia\Database\Query;
use Utopia\Database\Helpers\Role;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\DatetimeValidator;
use Utopia\Database\Validator\Datetime as DatetimeValidator;
use Utopia\Database\Validator\UID;
use Utopia\Domains\Domain;
use Utopia\Registry\Registry;
@@ -80,7 +80,7 @@ App::post('/v1/projects')
}
$auth = Config::getParam('auth', []);
$auths = ['limit' => 0, 'maxSessions' => APP_LIMIT_USER_SESSIONS_DEFAULT, 'duration' => Auth::TOKEN_EXPIRATION_LOGIN_LONG];
$auths = ['limit' => 0, 'maxSessions' => APP_LIMIT_USER_SESSIONS_DEFAULT, 'passwordHistory' => 0, 'passwordDictionary' => false, 'duration' => Auth::TOKEN_EXPIRATION_LOGIN_LONG];
foreach ($auth as $index => $method) {
$auths[$method['key'] ?? ''] = true;
}
@@ -184,7 +184,7 @@ App::get('/v1/projects')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT_LIST)
->param('queries', [], new Projects(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Projects::ALLOWED_ATTRIBUTES), true)
->param('queries', [], new Projects(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Projects::ALLOWED_ATTRIBUTES), true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('response')
->inject('dbForConsole')
@@ -575,6 +575,68 @@ App::patch('/v1/projects/:projectId/auth/:method')
$response->dynamic($project, Response::MODEL_PROJECT);
});
App::patch('/v1/projects/:projectId/auth/password-history')
->desc('Update authentication password history. Use this endpoint to set the number of password history to save and 0 to disable password history.')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateAuthPasswordHistory')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT)
->param('projectId', '', new UID(), 'Project unique ID.')
->param('limit', 0, new Range(0, APP_LIMIT_USER_PASSWORD_HISTORY), 'Set the max number of passwords to store in user history. User can\'t choose a new password that is already stored in the password history list. Max number of passwords allowed in history is' . APP_LIMIT_USER_PASSWORD_HISTORY . '. Default value is 0')
->inject('response')
->inject('dbForConsole')
->action(function (string $projectId, int $limit, Response $response, Database $dbForConsole) {
$project = $dbForConsole->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
$auths = $project->getAttribute('auths', []);
$auths['passwordHistory'] = $limit;
$dbForConsole->updateDocument('projects', $project->getId(), $project
->setAttribute('auths', $auths));
$response->dynamic($project, Response::MODEL_PROJECT);
});
App::patch('/v1/projects/:projectId/auth/password-dictionary')
->desc('Update authentication password disctionary status. Use this endpoint to enable or disable the dicitonary check for user password')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateAuthPasswordDictionary')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT)
->param('projectId', '', new UID(), 'Project unique ID.')
->param('enabled', false, new Boolean(false), 'Set whether or not to enable checking user\'s password against most commonly used passwords. Default is false.')
->inject('response')
->inject('dbForConsole')
->action(function (string $projectId, bool $enabled, Response $response, Database $dbForConsole) {
$project = $dbForConsole->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
$auths = $project->getAttribute('auths', []);
$auths['passwordDictionary'] = $enabled;
$dbForConsole->updateDocument('projects', $project->getId(), $project
->setAttribute('auths', $auths));
$response->dynamic($project, Response::MODEL_PROJECT);
});
App::patch('/v1/projects/:projectId/auth/max-sessions')
->desc('Update Project user sessions limit')
->groups(['api', 'projects'])
@@ -1340,7 +1402,7 @@ App::post('/v1/projects/:projectId/domains')
$target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', ''));
if (!$target->isKnown() || $target->isTest()) {
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Unreachable CNAME target (' . $target->get() . '), please use a domain with a public suffix.');
throw new Exception(Exception::DOMAIN_TARGET_INVALID, 'Unreachable CNAME target (' . $target->get() . '). Please check the _APP_DOMAIN_TARGET environment variable of your Appwrite server.');
}
$domain = new Domain($domain);
+5 -5
View File
@@ -63,7 +63,7 @@ App::post('/v1/storage/buckets')
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](/docs/permissions).', true)
->param('fileSecurity', false, new Boolean(true), 'Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](/docs/permissions).', true)
->param('enabled', true, new Boolean(true), 'Is bucket enabled?', true)
->param('maximumFileSize', (int) App::getEnv('_APP_STORAGE_LIMIT', 0), new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human(App::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '. For self-hosted setups you can change the max limit by changing the `_APP_STORAGE_LIMIT` environment variable. [Learn more about storage environment variables](docs/environment-variables#storage)', true)
->param('maximumFileSize', (int) App::getEnv('_APP_STORAGE_LIMIT', 0), new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human(App::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '. For self-hosted setups you can change the max limit by changing the `_APP_STORAGE_LIMIT` environment variable. [Learn more about storage environment variables](/docs/environment-variables#storage)', true)
->param('allowedFileExtensions', [], new ArrayList(new Text(64), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Allowed file extensions. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' extensions are allowed, each 64 characters long.', true)
->param('compression', COMPRESSION_TYPE_NONE, new WhiteList([COMPRESSION_TYPE_NONE, COMPRESSION_TYPE_GZIP, COMPRESSION_TYPE_ZSTD]), 'Compression algorithm choosen for compression. Can be one of ' . COMPRESSION_TYPE_NONE . ', [' . COMPRESSION_TYPE_GZIP . '](https://en.wikipedia.org/wiki/Gzip), or [' . COMPRESSION_TYPE_ZSTD . '](https://en.wikipedia.org/wiki/Zstd), For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' compression is skipped even if it\'s enabled', true)
->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' encryption is skipped even if it\'s enabled', true)
@@ -154,7 +154,7 @@ App::get('/v1/storage/buckets')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_BUCKET_LIST)
->param('queries', [], new Buckets(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Buckets::ALLOWED_ATTRIBUTES), true)
->param('queries', [], new Buckets(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Buckets::ALLOWED_ATTRIBUTES), true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('response')
->inject('dbForProject')
@@ -235,7 +235,7 @@ App::put('/v1/storage/buckets/:bucketId')
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](/docs/permissions).', true)
->param('fileSecurity', false, new Boolean(true), 'Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](/docs/permissions).', true)
->param('enabled', true, new Boolean(true), 'Is bucket enabled?', true)
->param('maximumFileSize', null, new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human((int)App::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '. For self hosted version you can change the limit by changing _APP_STORAGE_LIMIT environment variable. [Learn more about storage environment variables](docs/environment-variables#storage)', true)
->param('maximumFileSize', null, new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human((int)App::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '. For self hosted version you can change the limit by changing _APP_STORAGE_LIMIT environment variable. [Learn more about storage environment variables](/docs/environment-variables#storage)', true)
->param('allowedFileExtensions', [], new ArrayList(new Text(64), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Allowed file extensions. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' extensions are allowed, each 64 characters long.', true)
->param('compression', COMPRESSION_TYPE_NONE, new WhiteList([COMPRESSION_TYPE_NONE, COMPRESSION_TYPE_GZIP, COMPRESSION_TYPE_ZSTD]), 'Compression algorithm choosen for compression. Can be one of ' . COMPRESSION_TYPE_NONE . ', [' . COMPRESSION_TYPE_GZIP . '](https://en.wikipedia.org/wiki/Gzip), or [' . COMPRESSION_TYPE_ZSTD . '](https://en.wikipedia.org/wiki/Zstd), For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' compression is skipped even if it\'s enabled', true)
->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' encryption is skipped even if it\'s enabled', true)
@@ -348,7 +348,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
->label('sdk.response.model', Response::MODEL_FILE)
->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
->param('fileId', '', new CustomId(), 'File ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
->param('file', [], new File(), 'Binary file.', false)
->param('file', [], new File(), 'Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](/docs/storage#file-input).', skipValidation: true)
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE]), 'An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](/docs/permissions).', true)
->inject('request')
->inject('response')
@@ -680,7 +680,7 @@ App::get('/v1/storage/buckets/:bucketId/files')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_FILE_LIST)
->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
->param('queries', [], new Files(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Files::ALLOWED_ATTRIBUTES), true)
->param('queries', [], new Files(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Files::ALLOWED_ATTRIBUTES), true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('response')
->inject('dbForProject')
+168 -64
View File
@@ -1,10 +1,12 @@
<?php
use Appwrite\Auth\Auth;
use Appwrite\Auth\Validator\Phone;
use Appwrite\Detector\Detector;
use Appwrite\Event\Delete;
use Appwrite\Event\Event;
use Appwrite\Event\Mail;
use Appwrite\Event\Phone as EventPhone;
use Appwrite\Extend\Exception;
use Appwrite\Network\Validator\Email;
use Utopia\Validator\Host;
@@ -20,7 +22,6 @@ use Appwrite\Utopia\Response;
use MaxMind\Db\Reader;
use Utopia\App;
use Utopia\Audit\Audit;
use Utopia\CLI\Console;
use Utopia\Config\Config;
use Utopia\Database\Database;
use Utopia\Database\Document;
@@ -35,10 +36,9 @@ use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Locale\Locale;
use Utopia\Validator\Text;
use Utopia\Validator\Range;
use Utopia\Validator\ArrayList;
use Utopia\Validator\WhiteList;
use Utopia\Validator\Assoc;
use Utopia\Validator\Text;
App::post('/v1/teams')
->desc('Create Team')
@@ -76,6 +76,7 @@ App::post('/v1/teams')
],
'name' => $name,
'total' => ($isPrivilegedUser || $isAppUser) ? 0 : 1,
'prefs' => new \stdClass(),
'search' => implode(' ', [$teamId, $name]),
])));
@@ -134,7 +135,7 @@ App::get('/v1/teams')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_TEAM_LIST)
->label('sdk.offline.model', '/teams')
->param('queries', [], new Teams(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Teams::ALLOWED_ATTRIBUTES), true)
->param('queries', [], new Teams(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Teams::ALLOWED_ATTRIBUTES), true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('response')
->inject('dbForProject')
@@ -199,28 +200,22 @@ App::get('/v1/teams/:teamId')
$response->dynamic($team, Response::MODEL_TEAM);
});
App::put('/v1/teams/:teamId')
->desc('Update Team')
App::get('/v1/teams/:teamId/prefs')
->desc('Get Team Preferences')
->groups(['api', 'teams'])
->label('event', 'teams.[teamId].update')
->label('scope', 'teams.write')
->label('audits.event', 'team.update')
->label('audits.resource', 'team/{response.$id}')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('scope', 'teams.read')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'teams')
->label('sdk.method', 'update')
->label('sdk.description', '/docs/references/teams/update-team.md')
->label('sdk.method', 'getPrefs')
->label('sdk.description', '/docs/references/teams/get-team-prefs.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_TEAM)
->label('sdk.offline.model', '/teams')
->label('sdk.offline.key', '{teamId}')
->label('sdk.response.model', Response::MODEL_PREFERENCES)
->label('sdk.offline.model', '/teams/{teamId}/prefs')
->param('teamId', '', new UID(), 'Team ID.')
->param('name', null, new Text(128), 'New team name. Max length: 128 chars.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $teamId, string $name, Response $response, Database $dbForProject, Event $events) {
->action(function (string $teamId, Response $response, Database $dbForProject) {
$team = $dbForProject->getDocument('teams', $teamId);
@@ -228,15 +223,90 @@ App::put('/v1/teams/:teamId')
throw new Exception(Exception::TEAM_NOT_FOUND);
}
$team = $dbForProject->updateDocument('teams', $team->getId(), $team
$prefs = $team->getAttribute('prefs', []);
$response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES);
});
App::put('/v1/teams/:teamId')
->desc('Update Name')
->groups(['api', 'teams'])
->label('event', 'teams.[teamId].update')
->label('scope', 'teams.write')
->label('audits.event', 'team.update')
->label('audits.resource', 'team/{response.$id}')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'teams')
->label('sdk.method', 'updateName')
->label('sdk.description', '/docs/references/teams/update-team-name.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_TEAM)
->label('sdk.offline.model', '/teams')
->label('sdk.offline.key', '{teamId}')
->param('teamId', '', new UID(), 'Team ID.')
->param('name', null, new Text(128), 'New team name. Max length: 128 chars.')
->inject('requestTimestamp')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $teamId, string $name, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Event $events) {
$team = $dbForProject->getDocument('teams', $teamId);
if ($team->isEmpty()) {
throw new Exception(Exception::TEAM_NOT_FOUND);
}
$team
->setAttribute('name', $name)
->setAttribute('search', implode(' ', [$teamId, $name])));
->setAttribute('search', implode(' ', [$teamId, $name]));
$team = $dbForProject->withRequestTimestamp($requestTimestamp, function () use ($dbForProject, $team) {
return $dbForProject->updateDocument('teams', $team->getId(), $team);
});
$events->setParam('teamId', $team->getId());
$response->dynamic($team, Response::MODEL_TEAM);
});
App::put('/v1/teams/:teamId/prefs')
->desc('Update Preferences')
->groups(['api', 'teams'])
->label('event', 'teams.[teamId].update.prefs')
->label('scope', 'teams.write')
->label('audits.event', 'team.update')
->label('audits.resource', 'team/{response.$id}')
->label('audits.userId', '{response.$id}')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'teams')
->label('sdk.method', 'updatePrefs')
->label('sdk.description', '/docs/references/teams/update-team-prefs.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PREFERENCES)
->label('sdk.offline.model', '/teams/{teamId}/prefs')
->param('teamId', '', new UID(), 'Team ID.')
->param('prefs', '', new Assoc(), 'Prefs key-value JSON object.')
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $teamId, array $prefs, Response $response, Database $dbForProject, Event $events) {
$team = $dbForProject->getDocument('teams', $teamId);
if ($team->isEmpty()) {
throw new Exception(Exception::TEAM_NOT_FOUND);
}
$team = $dbForProject->updateDocument('teams', $team->getId(), $team->setAttribute('prefs', $prefs));
$events->setParam('teamId', $team->getId());
$response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES);
});
App::delete('/v1/teams/:teamId')
->desc('Delete Team')
->groups(['api', 'teams'])
@@ -309,7 +379,9 @@ App::post('/v1/teams/:teamId/memberships')
->label('sdk.response.model', Response::MODEL_MEMBERSHIP)
->label('abuse-limit', 10)
->param('teamId', '', new UID(), 'Team ID.')
->param('email', '', new Email(), 'Email of the new team member.')
->param('email', '', new Email(), 'Email of the new team member.', true)
->param('userId', '', new UID(), 'ID of the user to be added to a team.', true)
->param('phone', '', new Phone(), 'Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true)
->param('roles', [], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.')
->param('url', '', fn($clients) => new Host($clients), 'URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', false, ['clients']) // TODO add our own built-in confirm page
->param('name', '', new Text(128), 'Name of the new team member. Max length: 128 chars.', true)
@@ -319,9 +391,13 @@ App::post('/v1/teams/:teamId/memberships')
->inject('dbForProject')
->inject('locale')
->inject('mails')
->inject('messaging')
->inject('events')
->action(function (string $teamId, string $email, array $roles, string $url, string $name, Response $response, Document $project, Document $user, Database $dbForProject, Locale $locale, Mail $mails, Event $events) {
->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 $mails, EventPhone $messaging, Event $events) {
if (empty($userId) && empty($email) && empty($phone)) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'At least one of userId, email, or phone is required');
}
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
$isAppUser = Auth::isAppUser(Authorization::getRoles());
@@ -336,8 +412,31 @@ App::post('/v1/teams/:teamId/memberships')
if ($team->isEmpty()) {
throw new Exception(Exception::TEAM_NOT_FOUND);
}
$invitee = $dbForProject->findOne('users', [Query::equal('email', [$email])]); // Get user by email address
if (!empty($userId)) {
$invitee = $dbForProject->getDocument('users', $userId);
if ($invitee->isEmpty()) {
throw new Exception(Exception::USER_NOT_FOUND, 'User with given userId doesn\'t exist.', 404);
}
if (!empty($email) && $invitee->getAttribute('email', '') !== $email) {
throw new Exception(Exception::USER_ALREADY_EXISTS, 'Given userId and email doesn\'t match', 409);
}
if (!empty($phone) && $invitee->getAttribute('phone', '') !== $phone) {
throw new Exception(Exception::USER_ALREADY_EXISTS, 'Given userId and phone doesn\'t match', 409);
}
$email = $invitee->getAttribute('email', '');
$phone = $invitee->getAttribute('phone', '');
$name = empty($name) ? $invitee->getAttribute('name', '') : $name;
} elseif (!empty($email)) {
$invitee = $dbForProject->findOne('users', [Query::equal('email', [$email])]); // Get user by email address
if (!empty($invitee) && !empty($phone) && $invitee->getAttribute('phone', '') !== $phone) {
throw new Exception(Exception::USER_ALREADY_EXISTS, 'Given email and phone doesn\'t match', 409);
}
} elseif (!empty($phone)) {
$invitee = $dbForProject->findOne('users', [Query::equal('phone', [$phone])]);
if (!empty($invitee) && !empty($email) && $invitee->getAttribute('email', '') !== $email) {
throw new Exception(Exception::USER_ALREADY_EXISTS, 'Given phone and email doesn\'t match', 409);
}
}
if (empty($invitee)) { // Create new user if no user with same email found
$limit = $project->getAttribute('auths', [])['limit'] ?? 0;
@@ -360,7 +459,8 @@ App::post('/v1/teams/:teamId/memberships')
Permission::update(Role::user($userId)),
Permission::delete(Role::user($userId)),
],
'email' => $email,
'email' => empty($email) ? null : $email,
'phone' => empty($phone) ? null : $phone,
'emailVerification' => false,
'status' => true,
'password' => Auth::passwordHash(Auth::passwordGenerator(), Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS),
@@ -432,46 +532,50 @@ App::post('/v1/teams/:teamId/memberships')
} catch (Duplicate $th) {
throw new Exception(Exception::TEAM_INVITE_ALREADY_EXISTS);
}
}
$url = Template::parseURL($url);
$url['query'] = Template::mergeQuery(((isset($url['query'])) ? $url['query'] : ''), ['membershipId' => $membership->getId(), 'userId' => $invitee->getId(), 'secret' => $secret, 'teamId' => $teamId]);
$url = Template::unParseURL($url);
$url = Template::parseURL($url);
$url['query'] = Template::mergeQuery(((isset($url['query'])) ? $url['query'] : ''), ['membershipId' => $membership->getId(), 'userId' => $invitee->getId(), 'secret' => $secret, 'teamId' => $teamId]);
$url = Template::unParseURL($url);
if (!empty($email)) {
$projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]');
if (!$isPrivilegedUser && !$isAppUser) { // No need of confirmation when in admin or app mode
$projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]');
$from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $projectName);
$body = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base.tpl');
$subject = \sprintf($locale->getText("emails.invitation.subject"), $team->getAttribute('name'), $projectName);
$body->setParam('{{owner}}', $user->getAttribute('name'));
$body->setParam('{{team}}', $team->getAttribute('name'));
$from = $project->isEmpty() || $project->getId() === 'console' ? '' : \sprintf($locale->getText('emails.sender'), $projectName);
$body = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base.tpl');
$subject = \sprintf($locale->getText("emails.invitation.subject"), $team->getAttribute('name'), $projectName);
$body->setParam('{{owner}}', $user->getAttribute('name'));
$body->setParam('{{team}}', $team->getAttribute('name'));
$body
->setParam('{{subject}}', $subject)
->setParam('{{hello}}', $locale->getText("emails.invitation.hello"))
->setParam('{{name}}', $user->getAttribute('name'))
->setParam('{{body}}', $locale->getText("emails.invitation.body"))
->setParam('{{redirect}}', $url)
->setParam('{{footer}}', $locale->getText("emails.invitation.footer"))
->setParam('{{thanks}}', $locale->getText("emails.invitation.thanks"))
->setParam('{{signature}}', $locale->getText("emails.invitation.signature"))
->setParam('{{project}}', $projectName)
->setParam('{{direction}}', $locale->getText('settings.direction'))
->setParam('{{bg-body}}', '#f7f7f7')
->setParam('{{bg-content}}', '#ffffff')
->setParam('{{text-content}}', '#000000');
$body
->setParam('{{subject}}', $subject)
->setParam('{{hello}}', $locale->getText("emails.invitation.hello"))
->setParam('{{name}}', $user->getAttribute('name'))
->setParam('{{body}}', $locale->getText("emails.invitation.body"))
->setParam('{{redirect}}', $url)
->setParam('{{footer}}', $locale->getText("emails.invitation.footer"))
->setParam('{{thanks}}', $locale->getText("emails.invitation.thanks"))
->setParam('{{signature}}', $locale->getText("emails.invitation.signature"))
->setParam('{{project}}', $projectName)
->setParam('{{direction}}', $locale->getText('settings.direction'))
->setParam('{{bg-body}}', '#f7f7f7')
->setParam('{{bg-content}}', '#ffffff')
->setParam('{{text-content}}', '#000000');
$body = $body->render();
$body = $body->render();
$mails
->setSubject($subject)
->setBody($body)
->setFrom($from)
->setRecipient($invitee->getAttribute('email'))
->setName($invitee->getAttribute('name'))
->trigger()
;
$mails
->setSubject($subject)
->setBody($body)
->setFrom($from)
->setRecipient($invitee->getAttribute('email'))
->setName($invitee->getAttribute('name'))
->trigger()
;
} elseif (!empty($phone)) {
$messaging
->setRecipient($phone)
->setMessage($url)
->trigger();
}
}
$events
@@ -503,7 +607,7 @@ App::get('/v1/teams/:teamId/memberships')
->label('sdk.response.model', Response::MODEL_MEMBERSHIP_LIST)
->label('sdk.offline.model', '/teams/{teamId}/memberships')
->param('teamId', '', new UID(), 'Team ID.')
->param('queries', [], new Memberships(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Memberships::ALLOWED_ATTRIBUTES), true)
->param('queries', [], new Memberships(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Memberships::ALLOWED_ATTRIBUTES), true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('response')
->inject('dbForProject')
@@ -898,7 +1002,7 @@ App::get('/v1/teams/:teamId/logs')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_LOG_LIST)
->param('teamId', '', new UID(), 'Team ID.')
->param('queries', [], new Queries(new Limit(), new Offset()), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Only supported methods are limit and offset', true)
->param('queries', [], new Queries(new Limit(), new Offset()), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
->inject('response')
->inject('dbForProject')
->inject('locale')
+59 -28
View File
@@ -34,11 +34,14 @@ use Utopia\Validator\Text;
use Utopia\Validator\Boolean;
use MaxMind\Db\Reader;
use Utopia\Validator\Integer;
use Appwrite\Auth\Validator\PasswordHistory;
use Appwrite\Auth\Validator\PasswordDictionary;
/** TODO: Remove function when we move to using utopia/platform */
function createUser(string $hash, mixed $hashOptions, string $userId, ?string $email, ?string $password, ?string $phone, string $name, Database $dbForProject, Event $events): Document
function createUser(string $hash, mixed $hashOptions, string $userId, ?string $email, ?string $password, ?string $phone, string $name, Document $project, Database $dbForProject, Event $events): Document
{
$hashOptionsObject = (\is_string($hashOptions)) ? \json_decode($hashOptions, true) : $hashOptions; // Cast to JSON array
$passwordHistory = $project->getAttribute('auths', [])['passwordHistory'] ?? 0;
if (!empty($email)) {
$email = \strtolower($email);
@@ -49,6 +52,7 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e
? ID::unique()
: ID::custom($userId);
$password = (!empty($password)) ? ($hash === 'plaintext' ? Auth::passwordHash($password, $hash, $hashOptionsObject) : $password) : null;
$user = $dbForProject->createDocument('users', new Document([
'$id' => $userId,
'$permissions' => [
@@ -61,10 +65,11 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e
'phone' => $phone,
'phoneVerification' => false,
'status' => true,
'password' => (!empty($password)) ? ($hash === 'plaintext' ? Auth::passwordHash($password, $hash, $hashOptionsObject) : $password) : null,
'password' => $password,
'passwordHistory' => is_null($password) && $passwordHistory === 0 ? [] : [$password],
'passwordUpdate' => (!empty($password)) ? DateTime::now() : null,
'hash' => $hash === 'plaintext' ? Auth::DEFAULT_ALGO : $hash,
'hashOptions' => $hash === 'plaintext' ? Auth::DEFAULT_ALGO_OPTIONS : $hashOptionsObject + ['type' => $hash],
'passwordUpdate' => (!empty($password)) ? DateTime::now() : null,
'registration' => DateTime::now(),
'reset' => false,
'name' => $name,
@@ -101,13 +106,15 @@ App::post('/v1/users')
->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
->param('email', null, new Email(), 'User email.', true)
->param('phone', null, new Phone(), 'Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true)
->param('password', null, new Password(), 'Plain text user password. Must be at least 8 chars.', true)
->param('password', '', fn ($project, $passwordsDictionary) => new PasswordDictionary($passwordsDictionary, $project->getAttribute('auths', [])['passwordDictionary'] ?? false), 'Plain text user password. Must be at least 8 chars.', true, ['project', 'passwordsDictionary'])
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, ?string $email, ?string $phone, ?string $password, string $name, Response $response, Database $dbForProject, Event $events) {
$user = createUser('plaintext', '{}', $userId, $email, $password, $phone, $name, $dbForProject, $events);
->action(function (string $userId, ?string $email, ?string $phone, ?string $password, string $name, Response $response, Document $project, Database $dbForProject, Event $events) {
$user = createUser('plaintext', '{}', $userId, $email, $password, $phone, $name, $project, $dbForProject, $events);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -134,10 +141,11 @@ App::post('/v1/users/bcrypt')
->param('password', '', new Password(), 'User password hashed using Bcrypt.')
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $email, string $password, string $name, Response $response, Database $dbForProject, Event $events) {
$user = createUser('bcrypt', '{}', $userId, $email, $password, null, $name, $dbForProject, $events);
->action(function (string $userId, string $email, string $password, string $name, Response $response, Document $project, Database $dbForProject, Event $events) {
$user = createUser('bcrypt', '{}', $userId, $email, $password, null, $name, $project, $dbForProject, $events);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -164,10 +172,11 @@ App::post('/v1/users/md5')
->param('password', '', new Password(), 'User password hashed using MD5.')
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $email, string $password, string $name, Response $response, Database $dbForProject, Event $events) {
$user = createUser('md5', '{}', $userId, $email, $password, null, $name, $dbForProject, $events);
->action(function (string $userId, string $email, string $password, string $name, Response $response, Document $project, Database $dbForProject, Event $events) {
$user = createUser('md5', '{}', $userId, $email, $password, null, $name, $project, $dbForProject, $events);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -194,10 +203,11 @@ App::post('/v1/users/argon2')
->param('password', '', new Password(), 'User password hashed using Argon2.')
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $email, string $password, string $name, Response $response, Database $dbForProject, Event $events) {
$user = createUser('argon2', '{}', $userId, $email, $password, null, $name, $dbForProject, $events);
->action(function (string $userId, string $email, string $password, string $name, Response $response, Document $project, Database $dbForProject, Event $events) {
$user = createUser('argon2', '{}', $userId, $email, $password, null, $name, $project, $dbForProject, $events);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -225,16 +235,17 @@ App::post('/v1/users/sha')
->param('passwordVersion', '', new WhiteList(['sha1', 'sha224', 'sha256', 'sha384', 'sha512/224', 'sha512/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512']), "Optional SHA version used to hash password. Allowed values are: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512/224', 'sha512/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512'", true)
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $email, string $password, string $passwordVersion, string $name, Response $response, Database $dbForProject, Event $events) {
->action(function (string $userId, string $email, string $password, string $passwordVersion, string $name, Response $response, Document $project, Database $dbForProject, Event $events) {
$options = '{}';
if (!empty($passwordVersion)) {
$options = '{"version":"' . $passwordVersion . '"}';
}
$user = createUser('sha', $options, $userId, $email, $password, null, $name, $dbForProject, $events);
$user = createUser('sha', $options, $userId, $email, $password, null, $name, $project, $dbForProject, $events);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -261,10 +272,11 @@ App::post('/v1/users/phpass')
->param('password', '', new Password(), 'User password hashed using PHPass.')
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $email, string $password, string $name, Response $response, Database $dbForProject, Event $events) {
$user = createUser('phpass', '{}', $userId, $email, $password, null, $name, $dbForProject, $events);
->action(function (string $userId, string $email, string $password, string $name, Response $response, Document $project, Database $dbForProject, Event $events) {
$user = createUser('phpass', '{}', $userId, $email, $password, null, $name, $project, $dbForProject, $events);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -296,9 +308,10 @@ App::post('/v1/users/scrypt')
->param('passwordLength', 64, new Integer(), 'Optional hash length used to hash password.')
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $email, string $password, string $passwordSalt, int $passwordCpu, int $passwordMemory, int $passwordParallel, int $passwordLength, string $name, Response $response, Database $dbForProject, Event $events) {
->action(function (string $userId, string $email, string $password, string $passwordSalt, int $passwordCpu, int $passwordMemory, int $passwordParallel, int $passwordLength, string $name, Response $response, Document $project, Database $dbForProject, Event $events) {
$options = [
'salt' => $passwordSalt,
'costCpu' => $passwordCpu,
@@ -307,7 +320,7 @@ App::post('/v1/users/scrypt')
'length' => $passwordLength
];
$user = createUser('scrypt', \json_encode($options), $userId, $email, $password, null, $name, $dbForProject, $events);
$user = createUser('scrypt', \json_encode($options), $userId, $email, $password, null, $name, $project, $dbForProject, $events);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -337,10 +350,11 @@ App::post('/v1/users/scrypt-modified')
->param('passwordSignerKey', '', new Text(128), 'Signer key used to hash password.')
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $email, string $password, string $passwordSalt, string $passwordSaltSeparator, string $passwordSignerKey, string $name, Response $response, Database $dbForProject, Event $events) {
$user = createUser('scryptMod', '{"signerKey":"' . $passwordSignerKey . '","saltSeparator":"' . $passwordSaltSeparator . '","salt":"' . $passwordSalt . '"}', $userId, $email, $password, null, $name, $dbForProject, $events);
->action(function (string $userId, string $email, string $password, string $passwordSalt, string $passwordSaltSeparator, string $passwordSignerKey, string $name, Response $response, Document $project, Database $dbForProject, Event $events) {
$user = createUser('scryptMod', '{"signerKey":"' . $passwordSignerKey . '","saltSeparator":"' . $passwordSaltSeparator . '","salt":"' . $passwordSalt . '"}', $userId, $email, $password, null, $name, $project, $dbForProject, $events);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -359,7 +373,7 @@ App::get('/v1/users')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER_LIST)
->param('queries', [], new Users(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Users::ALLOWED_ATTRIBUTES), true)
->param('queries', [], new Users(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Users::ALLOWED_ATTRIBUTES), true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('response')
->inject('dbForProject')
@@ -443,7 +457,7 @@ App::get('/v1/users/:userId/prefs')
throw new Exception(Exception::USER_NOT_FOUND);
}
$prefs = $user->getAttribute('prefs', new \stdClass());
$prefs = $user->getAttribute('prefs', []);
$response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES);
});
@@ -543,7 +557,7 @@ App::get('/v1/users/:userId/logs')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_LOG_LIST)
->param('userId', '', new UID(), 'User ID.')
->param('queries', [], new Queries(new Limit(), new Offset()), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Only supported methods are limit and offset', true)
->param('queries', [], new Queries(new Limit(), new Offset()), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
->inject('response')
->inject('dbForProject')
->inject('locale')
@@ -779,11 +793,12 @@ App::patch('/v1/users/:userId/password')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER)
->param('userId', '', new UID(), 'User ID.')
->param('password', '', new Password(), 'New user password. Must be at least 8 chars.')
->param('password', '', fn ($project, $passwordsDictionary) => new PasswordDictionary($passwordsDictionary, $project->getAttribute('auths', [])['passwordDictionary'] ?? false), 'New user password. Must be at least 8 chars.', false, ['project', 'passwordsDictionary'])
->inject('response')
->inject('project')
->inject('dbForProject')
->inject('events')
->action(function (string $userId, string $password, Response $response, Database $dbForProject, Event $events) {
->action(function (string $userId, string $password, Response $response, Document $project, Database $dbForProject, Event $events) {
$user = $dbForProject->getDocument('users', $userId);
@@ -791,11 +806,27 @@ App::patch('/v1/users/:userId/password')
throw new Exception(Exception::USER_NOT_FOUND);
}
$newPassword = Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS);
$historyLimit = $project->getAttribute('auths', [])['passwordHistory'] ?? 0;
$history = [];
if ($historyLimit > 0) {
$history = $user->getAttribute('passwordHistory', []);
$validator = new PasswordHistory($history, $user->getAttribute('hash'), $user->getAttribute('hashOptions'));
if (!$validator->isValid($password)) {
throw new Exception(Exception::USER_PASSWORD_RECENTLY_USED, 'The password was recently used', 409);
}
$history[] = $newPassword;
array_slice($history, (count($history) - $historyLimit), $historyLimit);
}
$user
->setAttribute('password', Auth::passwordHash($password, Auth::DEFAULT_ALGO, Auth::DEFAULT_ALGO_OPTIONS))
->setAttribute('password', $newPassword)
->setAttribute('passwordHistory', $history)
->setAttribute('passwordUpdate', DateTime::now())
->setAttribute('hash', Auth::DEFAULT_ALGO)
->setAttribute('hashOptions', Auth::DEFAULT_ALGO_OPTIONS)
->setAttribute('passwordUpdate', DateTime::now());
->setAttribute('hashOptions', Auth::DEFAULT_ALGO_OPTIONS);
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
+7 -3
View File
@@ -233,7 +233,7 @@ App::init()
->addHeader('Server', 'Appwrite')
->addHeader('X-Content-Type-Options', 'nosniff')
->addHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE')
->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, Content-Range, Range, Cache-Control, Expires, Pragma')
->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, X-Appwrite-Timestamp, Content-Range, Range, Cache-Control, Expires, Pragma')
->addHeader('Access-Control-Expose-Headers', 'X-Fallback-Cookies')
->addHeader('Access-Control-Allow-Origin', $refDomain)
->addHeader('Access-Control-Allow-Credentials', 'true')
@@ -384,7 +384,7 @@ App::options()
$response
->addHeader('Server', 'Appwrite')
->addHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE')
->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, Content-Range, Range, Cache-Control, Expires, Pragma, X-Fallback-Cookies')
->addHeader('Access-Control-Allow-Headers', 'Origin, Cookie, Set-Cookie, X-Requested-With, Content-Type, Access-Control-Allow-Origin, Access-Control-Request-Headers, Accept, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-Appwrite-ID, X-Appwrite-Timestamp, Content-Range, Range, Cache-Control, Expires, Pragma, X-Fallback-Cookies')
->addHeader('Access-Control-Expose-Headers', 'X-Fallback-Cookies')
->addHeader('Access-Control-Allow-Origin', $origin)
->addHeader('Access-Control-Allow-Credentials', 'true')
@@ -485,6 +485,10 @@ App::error()
$error->setType(AppwriteException::GENERAL_ROUTE_NOT_FOUND);
break;
}
} elseif ($error instanceof Utopia\Database\Exception\Conflict) {
$error = new AppwriteException(AppwriteException::DOCUMENT_UPDATE_CONFLICT, null, null, $error);
$code = $error->getCode();
$message = $error->getMessage();
}
/** Wrap all exceptions inside Appwrite\Extend\Exception */
@@ -590,7 +594,7 @@ App::get('/.well-known/acme-challenge')
$uriChunks = \explode('/', $request->getURI());
$token = $uriChunks[\count($uriChunks) - 1];
$validator = new Text(100, [
$validator = new Text(100, allowList: [
...Text::NUMBERS,
...Text::ALPHABET_LOWER,
...Text::ALPHABET_UPPER,
+17 -1
View File
@@ -15,6 +15,7 @@ use Utopia\Validator\Text;
use Utopia\Storage\Validator\File;
use Utopia\Validator\WhiteList;
use Utopia\Database\Helpers\ID;
use Utopia\Validator\Nullable;
App::get('/v1/mock/tests/foo')
->desc('Get Foo')
@@ -267,7 +268,7 @@ App::post('/v1/mock/tests/general/upload')
->param('x', '', new Text(100), 'Sample string param')
->param('y', '', new Integer(true), 'Sample numeric param')
->param('z', null, new ArrayList(new Text(256), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Sample array param')
->param('file', [], new File(), 'Sample file param', false)
->param('file', [], new File(), 'Sample file param', skipValidation: true)
->inject('request')
->inject('response')
->action(function (string $x, int $y, array $z, mixed $file, Request $request, Response $response) {
@@ -428,6 +429,21 @@ App::get('/v1/mock/tests/general/empty')
$response->noContent();
});
App::post('/v1/mock/tests/general/nullable')
->desc('Nullable Test')
->groups(['mock'])
->label('scope', 'public')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'general')
->label('sdk.method', 'nullable')
->label('sdk.description', 'Mock a nullable parameter.')
->label('sdk.mock', true)
->param('required', '', new Text(100), 'Sample string param')
->param('nullable', '', new Nullable(new Text(100)), 'Sample string param')
->param('optional', '', new Text(100), 'Sample string param', true)
->action(function (string $required, string $nullable, ?string $optional) {
});
/** Endpoint to test if required headers are sent from the SDK */
App::get('/v1/mock/tests/general/headers')
->desc('Get headers')
-2
View File
@@ -5,7 +5,6 @@ use Appwrite\Event\Audit;
use Appwrite\Event\Database as EventDatabase;
use Appwrite\Event\Delete;
use Appwrite\Event\Event;
use Appwrite\Event\Mail;
use Appwrite\Extend\Exception;
use Appwrite\Messaging\Adapter\Realtime;
use Appwrite\Usage\Stats;
@@ -16,7 +15,6 @@ use Utopia\Abuse\Abuse;
use Utopia\Abuse\Adapters\TimeLimit;
use Utopia\Cache\Adapter\Filesystem;
use Utopia\Cache\Cache;
use Utopia\CLI\Console;
use Utopia\Database\Database;
use Utopia\Database\DateTime;
use Utopia\Database\Document;
+3 -3
View File
@@ -165,14 +165,14 @@ App::post('/v1/runtimes')
->desc("Create a new runtime server")
->param('runtimeId', '', new Text(64), 'Unique runtime ID.')
->param('source', '', new Text(0), 'Path to source files.')
->param('destination', '', new Text(0), 'Destination folder to store build files into.', true)
->param('destination', '', new Text(0, 0), 'Destination folder to store build files into.', true)
->param('vars', [], new Assoc(), 'Environment Variables required for the build.')
->param('commands', [], new ArrayList(new Text(1024), 100), 'Commands required to build the container. Maximum of 100 commands are allowed, each 1024 characters long.')
->param('runtime', '', new Text(128), 'Runtime for the cloud function.')
->param('baseImage', '', new Text(128), 'Base image name of the runtime.')
->param('entrypoint', '', new Text(256), 'Entrypoint of the code file.', true)
->param('remove', false, new Boolean(), 'Remove a runtime after execution.')
->param('workdir', '', new Text(256), 'Working directory.', true)
->param('workdir', '', new Text(256, 0), 'Working directory.', true)
->inject('orchestrationPool')
->inject('activeRuntimes')
->inject('response')
@@ -459,7 +459,7 @@ App::post('/v1/execution')
->desc('Create an execution')
->param('runtimeId', '', new Text(64), 'The runtimeID to execute.')
->param('vars', [], new Assoc(), 'Environment variables required for the build.')
->param('data', '', new Text(8192), 'Data to be forwarded to the function, this is user specified.', true)
->param('data', '', new Text(8192, 0), 'Data to be forwarded to the function, this is user specified.', true)
->param('timeout', 15, new Range(1, (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)), 'Function maximum execution time in seconds.')
->inject('activeRuntimes')
->inject('response')
+1 -2
View File
@@ -92,7 +92,6 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
$collections = Config::getParam('collections', []);
try {
$redis->flushAll();
Console::success('[Setup] - Creating database: appwrite...');
$dbForConsole->create();
} catch (\Exception $e) {
@@ -296,7 +295,7 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
$log->addExtra('line', $th->getLine());
$log->addExtra('trace', $th->getTraceAsString());
$log->addExtra('detailedTrace', $th->getTrace());
$log->addExtra('roles', Authorization::$roles);
$log->addExtra('roles', Authorization::getRoles());
$action = $route->getLabel("sdk.namespace", "UNKNOWN_NAMESPACE") . '.' . $route->getLabel("sdk.method", "UNKNOWN_METHOD");
$log->setAction($action);
+46 -9
View File
@@ -53,7 +53,7 @@ use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\DatetimeValidator;
use Utopia\Database\Validator\Datetime as DatetimeValidator;
use Utopia\Database\Validator\Structure;
use Utopia\Locale\Locale;
use Utopia\Messaging\Adapters\SMS\Mock;
@@ -86,6 +86,7 @@ const APP_MODE_ADMIN = 'admin';
const APP_PAGING_LIMIT = 12;
const APP_LIMIT_COUNT = 5000;
const APP_LIMIT_USERS = 10000;
const APP_LIMIT_USER_PASSWORD_HISTORY = 20;
const APP_LIMIT_USER_SESSIONS_MAX = 100;
const APP_LIMIT_USER_SESSIONS_DEFAULT = 10;
const APP_LIMIT_ANTIVIRUS = 20000000; //20MB
@@ -99,8 +100,8 @@ const APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT = 60; // Default maximum write rate pe
const APP_LIMIT_LIST_DEFAULT = 25; // Default maximum number of items to return in list API calls
const APP_KEY_ACCCESS = 24 * 60 * 60; // 24 hours
const APP_CACHE_UPDATE = 24 * 60 * 60; // 24 hours
const APP_CACHE_BUSTER = 501;
const APP_VERSION_STABLE = '1.2.1';
const APP_CACHE_BUSTER = 503;
const APP_VERSION_STABLE = '1.3.1';
const APP_DATABASE_ATTRIBUTE_EMAIL = 'email';
const APP_DATABASE_ATTRIBUTE_ENUM = 'enum';
const APP_DATABASE_ATTRIBUTE_IP = 'ip';
@@ -284,12 +285,23 @@ Database::addFilter(
return null;
},
function (mixed $value, Document $document, Database $database) {
return $database
->find('attributes', [
Query::equal('collectionInternalId', [$document->getInternalId()]),
Query::equal('databaseInternalId', [$document->getAttribute('databaseInternalId')]),
Query::limit($database->getLimitForAttributes()),
]);
$attributes = $database->find('attributes', [
Query::equal('collectionInternalId', [$document->getInternalId()]),
Query::equal('databaseInternalId', [$document->getAttribute('databaseInternalId')]),
Query::limit($database->getLimitForAttributes()),
]);
foreach ($attributes as $attribute) {
if ($attribute->getAttribute('type') === Database::VAR_RELATIONSHIP) {
$options = $attribute->getAttribute('options');
foreach ($options as $key => $value) {
$attribute->setAttribute($key, $value);
}
$attribute->removeAttribute('options');
}
}
return $attributes;
}
);
@@ -607,6 +619,12 @@ $register->set('smtp', function () {
$register->set('geodb', function () {
return new Reader(__DIR__ . '/assets/dbip/dbip-country-lite-2023-01.mmdb');
});
$register->set('passwordsDictionary', function () {
$content = \file_get_contents(__DIR__ . '/assets/security/10k-common-passwords');
$content = explode("\n", $content);
$content = array_flip($content);
return $content;
});
$register->set('db', function () {
// This is usually for our workers or CLI commands scope
$dbHost = App::getEnv('_APP_DB_HOST', '');
@@ -1027,6 +1045,11 @@ App::setResource('geodb', function ($register) {
return $register->get('geodb');
}, ['register']);
App::setResource('passwordsDictionary', function ($register) {
/** @var Utopia\Registry\Registry $register */
return $register->get('passwordsDictionary');
}, ['register']);
App::setResource('sms', function () {
$dsn = new DSN(App::getEnv('_APP_SMS_PROVIDER'));
$user = $dsn->getUser();
@@ -1143,3 +1166,17 @@ App::setResource('schema', function ($utopia, $dbForProject) {
$params,
);
}, ['utopia', 'dbForProject']);
App::setResource('requestTimestamp', function ($request) {
//TODO: Move this to the Request class itself
$timestampHeader = $request->getHeader('x-appwrite-timestamp');
$requestTimestamp = null;
if (!empty($timestampHeader)) {
try {
$requestTimestamp = new \DateTime($timestampHeader);
} catch (\Throwable $e) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Invalid X-Appwrite-Timestamp header value');
}
}
return $requestTimestamp;
}, ['request']);
+2 -1
View File
@@ -85,10 +85,11 @@ $cli
try {
$migration
->setProject($project, $projectDB, $consoleDB)
->setPDO($register->get('db'))
->execute();
} catch (\Throwable $th) {
throw $th;
Console::error('Failed to update project ("' . $project->getId() . '") version with error: ' . $th->getMessage());
throw $th;
}
clearProjectsCache($redis, $project);
+1 -1
View File
@@ -33,7 +33,7 @@ $cli
$production = ($git) ? (Console::confirm('Type "Appwrite" to push code to production git repos') == 'Appwrite') : false;
$message = ($git) ? Console::confirm('Please enter your commit message:') : '';
if (!in_array($version, ['0.6.x', '0.7.x', '0.8.x', '0.9.x', '0.10.x', '0.11.x', '0.12.x', '0.13.x', '0.14.x', '0.15.x', '1.0.x', '1.1.x', '1.2.x', 'latest'])) {
if (!in_array($version, ['0.6.x', '0.7.x', '0.8.x', '0.9.x', '0.10.x', '0.11.x', '0.12.x', '0.13.x', '0.14.x', '0.15.x', '1.0.x', '1.1.x', '1.2.x', '1.3.x', 'latest'])) {
throw new Exception('Unknown version given');
}
+1 -1
View File
@@ -383,7 +383,7 @@ class CertificatesV1 extends Worker
$locale->setDefault('en');
}
$body = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-base.tpl');
$body = Template::fromFile(__DIR__ . '/../config/locale/templates/email-base.tpl');
$subject = \sprintf($locale->getText("emails.certificate.subject"), $domain);
$body->setParam('{{domain}}', $domain);
+79 -7
View File
@@ -1,10 +1,13 @@
<?php
use Appwrite\Event\Event;
use Appwrite\Extend\Exception;
use Appwrite\Messaging\Adapter\Realtime;
use Appwrite\Resque\Worker;
use Utopia\CLI\Console;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Helpers\ID;
require_once __DIR__ . '/../init.php';
@@ -89,16 +92,51 @@ class DatabaseV1 extends Worker
$format = $attribute->getAttribute('format', '');
$formatOptions = $attribute->getAttribute('formatOptions', []);
$filters = $attribute->getAttribute('filters', []);
$options = $attribute->getAttribute('options', []);
$project = $dbForConsole->getDocument('projects', $projectId);
try {
if (!$dbForProject->createAttribute('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key, $type, $size, $required, $default, $signed, $array, $format, $formatOptions, $filters)) {
throw new Exception('Failed to create Attribute');
switch ($type) {
case Database::VAR_RELATIONSHIP:
$relatedCollection = $dbForProject->getDocument('database_' . $database->getInternalId(), $options['relatedCollection']);
if ($relatedCollection->isEmpty()) {
throw new Exception('Collection not found');
}
if (
!$dbForProject->createRelationship(
collection: 'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(),
relatedCollection: 'database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId(),
type: $options['relationType'],
twoWay: $options['twoWay'],
id: $key,
twoWayKey: $options['twoWayKey'],
onDelete: $options['onDelete'],
)
) {
throw new Exception('Failed to create Attribute');
}
if ($options['twoWay']) {
$relatedAttribute = $dbForProject->getDocument('attributes', $database->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $options['twoWayKey']);
$dbForProject->updateDocument('attributes', $relatedAttribute->getId(), $relatedAttribute->setAttribute('status', 'available'));
}
break;
default:
if (!$dbForProject->createAttribute('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key, $type, $size, $required, $default, $signed, $array, $format, $formatOptions, $filters)) {
throw new Exception('Failed to create Attribute');
}
}
$dbForProject->updateDocument('attributes', $attribute->getId(), $attribute->setAttribute('status', 'available'));
} catch (\Throwable $th) {
Console::error($th->getMessage());
$dbForProject->updateDocument('attributes', $attribute->getId(), $attribute->setAttribute('status', 'failed'));
if ($type === Database::VAR_RELATIONSHIP && $options['twoWay']) {
$relatedAttribute = $dbForProject->getDocument('attributes', $database->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $options['twoWayKey']);
$dbForProject->updateDocument('attributes', $relatedAttribute->getId(), $relatedAttribute->setAttribute('status', 'failed'));
}
} finally {
$target = Realtime::fromPayload(
// Pass first, most verbose event pattern
@@ -121,6 +159,10 @@ class DatabaseV1 extends Worker
);
}
if ($type === Database::VAR_RELATIONSHIP && $options['twoWay']) {
$dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $relatedCollection->getId());
}
$dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $collectionId);
}
@@ -129,6 +171,7 @@ class DatabaseV1 extends Worker
* @param Document $collection
* @param Document $attribute
* @param string $projectId
* @throws Throwable
*/
protected function deleteAttribute(Document $database, Document $collection, Document $attribute, string $projectId): void
{
@@ -143,19 +186,43 @@ class DatabaseV1 extends Worker
$collectionId = $collection->getId();
$key = $attribute->getAttribute('key', '');
$status = $attribute->getAttribute('status', '');
$type = $attribute->getAttribute('type', '');
$project = $dbForConsole->getDocument('projects', $projectId);
$options = $attribute->getAttribute('options', []);
$relatedAttribute = new Document();
$relatedCollection = new Document();
// possible states at this point:
// - available: should not land in queue; controller flips these to 'deleting'
// - processing: hasn't finished creating
// - deleting: was available, in deletion queue for first time
// - failed: attribute was never created
// - stuck: attribute was available but cannot be removed
try {
if ($status !== 'failed' && !$dbForProject->deleteAttribute('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key)) {
throw new Exception('Failed to delete Attribute');
if ($status !== 'failed') {
if ($type === Database::VAR_RELATIONSHIP) {
if ($options['twoWay']) {
$relatedCollection = $dbForProject->getDocument('database_' . $database->getInternalId(), $options['relatedCollection']);
if ($relatedCollection->isEmpty()) {
throw new Exception(Exception::COLLECTION_NOT_FOUND);
}
$relatedAttribute = $dbForProject->getDocument('attributes', $database->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $options['twoWayKey']);
}
if (!$dbForProject->deleteRelationship('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key)) {
$dbForProject->updateDocument('attributes', $relatedAttribute->getId(), $relatedAttribute->setAttribute('status', 'stuck'));
throw new Exception('Failed to delete Relationship');
}
} elseif (!$dbForProject->deleteAttribute('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key)) {
throw new Exception('Failed to delete Attribute');
}
}
$dbForProject->deleteDocument('attributes', $attribute->getId());
if (!$relatedAttribute->isEmpty()) {
$dbForProject->deleteDocument('attributes', $relatedAttribute->getId());
}
} catch (\Throwable $th) {
Console::error($th->getMessage());
$dbForProject->updateDocument('attributes', $attribute->getId(), $attribute->setAttribute('status', 'stuck'));
@@ -199,8 +266,8 @@ class DatabaseV1 extends Worker
// array_values wraps array_diff to reindex array keys
// when found attribute is removed from array
$attributes = \array_values(\array_diff($attributes, [$attributes[$found]]));
$lengths = \array_values(\array_diff($lengths, [$lengths[$found]]));
$orders = \array_values(\array_diff($orders, [$orders[$found]]));
$lengths = \array_values(\array_diff($lengths, isset($lengths[$found]) ? [$lengths[$found]] : []));
$orders = \array_values(\array_diff($orders, isset($orders[$found]) ? [$orders[$found]] : []));
if (empty($attributes)) {
$dbForProject->deleteDocument('indexes', $index->getId());
@@ -235,6 +302,11 @@ class DatabaseV1 extends Worker
$dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $collectionId);
$dbForProject->deleteCachedCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId());
if (!$relatedCollection->isEmpty() && !$relatedAttribute->isEmpty()) {
$dbForProject->deleteCachedDocument('database_' . $database->getInternalId(), $relatedCollection->getId());
$dbForProject->deleteCachedCollection('database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId());
}
}
/**
+36
View File
@@ -58,6 +58,9 @@ class DeletesV1 extends Worker
break;
case DELETE_TYPE_TEAMS:
$this->deleteMemberships($document, $project->getId());
if ($project->getId() === 'console') {
$this->deleteProjectsByTeam($document);
}
break;
case DELETE_TYPE_BUCKETS:
$this->deleteBucket($document, $project->getId());
@@ -203,6 +206,21 @@ class DeletesV1 extends Worker
$dbForProject = $this->getProjectDB($projectId);
$relationships = \array_filter(
$document->getAttribute('attributes'),
fn ($attribute) => $attribute['type'] === Database::VAR_RELATIONSHIP
);
foreach ($relationships as $relationship) {
if (!$relationship['twoWay']) {
continue;
}
$relatedCollection = $dbForProject->getDocument('database_' . $databaseInternalId, $relationship['relatedCollection']);
$dbForProject->deleteDocument('attributes', $databaseInternalId . '_' . $relatedCollection->getInternalId() . '_' . $relationship['twoWayKey']);
$dbForProject->deleteCachedDocument('database_' . $databaseInternalId, $relatedCollection->getId());
$dbForProject->deleteCachedCollection('database_' . $databaseInternalId . '_collection_' . $relatedCollection->getInternalId());
}
$dbForProject->deleteCollection('database_' . $databaseInternalId . '_collection_' . $document->getInternalId());
$this->deleteByGroup('attributes', [
@@ -248,6 +266,24 @@ class DeletesV1 extends Worker
], $this->getProjectDB($projectId));
}
/**
* @param \Utopia\Database\Document $document
* @return void
* @throws \Exception
*/
protected function deleteProjectsByTeam(Document $document): void
{
$dbForConsole = $this->getConsoleDB();
$projects = $dbForConsole->find('projects', [
Query::equal('teamInternalId', [$document->getInternalId()])
]);
foreach ($projects as $project) {
$this->deleteProject($project);
}
}
/**
* @param Document $document project document
* @throws Exception
+7 -7
View File
@@ -43,27 +43,27 @@
"ext-sockets": "*",
"appwrite/php-clamav": "1.1.*",
"appwrite/php-runtimes": "0.11.*",
"utopia-php/abuse": "0.18.*",
"utopia-php/abuse": "0.24.*",
"utopia-php/analytics": "0.2.*",
"utopia-php/audit": "0.20.*",
"utopia-php/audit": "0.25.*",
"utopia-php/cache": "0.8.*",
"utopia-php/cli": "0.13.*",
"utopia-php/config": "0.2.*",
"utopia-php/database": "0.30.*",
"utopia-php/preloader": "0.2.*",
"utopia-php/database": "0.35.*",
"utopia-php/domains": "1.1.*",
"utopia-php/framework": "0.26.*",
"utopia-php/framework": "0.28.*",
"utopia-php/image": "0.5.*",
"utopia-php/locale": "0.4.*",
"utopia-php/logger": "0.3.*",
"utopia-php/messaging": "0.1.*",
"utopia-php/orchestration": "0.6.*",
"utopia-php/preloader": "0.2.*",
"utopia-php/registry": "0.5.*",
"utopia-php/storage": "0.14.*",
"utopia-php/swoole": "0.5.*",
"utopia-php/websocket": "0.1.*",
"resque/php-resque": "1.3.6",
"matomo/device-detector": "6.0.0",
"matomo/device-detector": "6.0.*",
"dragonmantank/cron-expression": "3.3.1",
"influxdb/influxdb-php": "1.15.2",
"phpmailer/phpmailer": "6.6.0",
@@ -79,7 +79,7 @@
}
],
"require-dev": {
"appwrite/sdk-generator": "0.29.*",
"appwrite/sdk-generator": "0.32.*",
"ext-fileinfo": "*",
"phpunit/phpunit": "9.5.20",
"squizlabs/php_codesniffer": "^3.6",
Generated
+177 -85
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "3b088b0f09093a6f094f65f73b96bf91",
"content-hash": "87de4ea3130e576470a63b21628e30fb",
"packages": [
{
"name": "adhocore/jwt",
@@ -1000,16 +1000,16 @@
},
{
"name": "matomo/device-detector",
"version": "6.0.0",
"version": "6.0.6",
"source": {
"type": "git",
"url": "https://github.com/matomo-org/device-detector.git",
"reference": "7fc2af3af62bd69e6e3404d561e371a83c112be9"
"reference": "ce5ef5e6776c16af306d38e20674973f072e05ed"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/matomo-org/device-detector/zipball/7fc2af3af62bd69e6e3404d561e371a83c112be9",
"reference": "7fc2af3af62bd69e6e3404d561e371a83c112be9",
"url": "https://api.github.com/repos/matomo-org/device-detector/zipball/ce5ef5e6776c16af306d38e20674973f072e05ed",
"reference": "ce5ef5e6776c16af306d38e20674973f072e05ed",
"shasum": ""
},
"require": {
@@ -1065,7 +1065,7 @@
"source": "https://github.com/matomo-org/matomo",
"wiki": "https://dev.matomo.org/"
},
"time": "2022-04-11T09:58:17+00:00"
"time": "2023-01-16T08:18:02+00:00"
},
{
"name": "mongodb/mongodb",
@@ -1265,21 +1265,21 @@
},
{
"name": "psr/http-client",
"version": "1.0.1",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-client.git",
"reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621"
"reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
"reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
"url": "https://api.github.com/repos/php-fig/http-client/zipball/0955afe48220520692d2d09f7ab7e0f93ffd6a31",
"reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31",
"shasum": ""
},
"require": {
"php": "^7.0 || ^8.0",
"psr/http-message": "^1.0"
"psr/http-message": "^1.0 || ^2.0"
},
"type": "library",
"extra": {
@@ -1299,7 +1299,7 @@
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for HTTP clients",
@@ -1311,27 +1311,27 @@
"psr-18"
],
"support": {
"source": "https://github.com/php-fig/http-client/tree/master"
"source": "https://github.com/php-fig/http-client/tree/1.0.2"
},
"time": "2020-06-29T06:28:15+00:00"
"time": "2023-04-10T20:12:12+00:00"
},
{
"name": "psr/http-factory",
"version": "1.0.1",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-factory.git",
"reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be"
"reference": "e616d01114759c4c489f93b099585439f795fe35"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
"reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35",
"reference": "e616d01114759c4c489f93b099585439f795fe35",
"shasum": ""
},
"require": {
"php": ">=7.0.0",
"psr/http-message": "^1.0"
"psr/http-message": "^1.0 || ^2.0"
},
"type": "library",
"extra": {
@@ -1351,7 +1351,7 @@
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interfaces for PSR-7 HTTP message factories",
@@ -1366,31 +1366,31 @@
"response"
],
"support": {
"source": "https://github.com/php-fig/http-factory/tree/master"
"source": "https://github.com/php-fig/http-factory/tree/1.0.2"
},
"time": "2019-04-30T12:38:16+00:00"
"time": "2023-04-10T20:10:41+00:00"
},
{
"name": "psr/http-message",
"version": "1.0.1",
"version": "1.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
"reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
"reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
"php": "^7.2 || ^8.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
"dev-master": "1.1.x-dev"
}
},
"autoload": {
@@ -1419,9 +1419,9 @@
"response"
],
"support": {
"source": "https://github.com/php-fig/http-message/tree/master"
"source": "https://github.com/php-fig/http-message/tree/1.1"
},
"time": "2016-08-06T14:39:51+00:00"
"time": "2023-04-04T09:50:52+00:00"
},
{
"name": "psr/log",
@@ -1808,29 +1808,28 @@
},
{
"name": "utopia-php/abuse",
"version": "0.18.0",
"version": "0.24.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/abuse.git",
"reference": "8496401234f73a49f8c4259d3e89ab4a7c1f9ecf"
"reference": "403641f16a53b81ac40b91111a86e5672da49e8c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/8496401234f73a49f8c4259d3e89ab4a7c1f9ecf",
"reference": "8496401234f73a49f8c4259d3e89ab4a7c1f9ecf",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/403641f16a53b81ac40b91111a86e5672da49e8c",
"reference": "403641f16a53b81ac40b91111a86e5672da49e8c",
"shasum": ""
},
"require": {
"ext-curl": "*",
"ext-pdo": "*",
"php": ">=8.0",
"utopia-php/database": "0.30.*"
"utopia-php/database": "0.35.*"
},
"require-dev": {
"laravel/pint": "1.2.*",
"phpstan/phpstan": "1.9.x-dev",
"phpunit/phpunit": "^9.4",
"vimeo/psalm": "4.0.1"
"phpstan/phpstan": "^1.9",
"phpunit/phpunit": "^9.4"
},
"type": "library",
"autoload": {
@@ -1852,9 +1851,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/abuse/issues",
"source": "https://github.com/utopia-php/abuse/tree/0.18.0"
"source": "https://github.com/utopia-php/abuse/tree/0.24.0"
},
"time": "2023-02-14T09:56:04+00:00"
"time": "2023-04-11T05:31:55+00:00"
},
{
"name": "utopia-php/analytics",
@@ -1913,28 +1912,26 @@
},
{
"name": "utopia-php/audit",
"version": "0.20.0",
"version": "0.25.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/audit.git",
"reference": "3fce3f4ad3ea9dfcb39b79668abd76331412a5ed"
"reference": "adc209f2e16878e5468f0b9cfd9f7f7ab497db31"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/3fce3f4ad3ea9dfcb39b79668abd76331412a5ed",
"reference": "3fce3f4ad3ea9dfcb39b79668abd76331412a5ed",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/adc209f2e16878e5468f0b9cfd9f7f7ab497db31",
"reference": "adc209f2e16878e5468f0b9cfd9f7f7ab497db31",
"shasum": ""
},
"require": {
"ext-pdo": "*",
"php": ">=8.0",
"utopia-php/database": "0.30.*"
"utopia-php/database": "0.35.*"
},
"require-dev": {
"laravel/pint": "1.2.*",
"phpstan/phpstan": "^1.8",
"phpunit/phpunit": "^9.3",
"vimeo/psalm": "4.0.1"
"phpunit/phpunit": "^9.3"
},
"type": "library",
"autoload": {
@@ -1956,9 +1953,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/audit/issues",
"source": "https://github.com/utopia-php/audit/tree/0.20.0"
"source": "https://github.com/utopia-php/audit/tree/0.25.0"
},
"time": "2023-02-14T09:46:54+00:00"
"time": "2023-04-11T05:31:15+00:00"
},
{
"name": "utopia-php/cache",
@@ -2115,33 +2112,37 @@
},
{
"name": "utopia-php/database",
"version": "0.30.1",
"version": "0.35.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/database.git",
"reference": "1cea72c1217357bf0747ae4f28ebef57e9dc0e65"
"reference": "f162c142fd61753c4b413b15c3c4041f3cd00bb2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/database/zipball/1cea72c1217357bf0747ae4f28ebef57e9dc0e65",
"reference": "1cea72c1217357bf0747ae4f28ebef57e9dc0e65",
"url": "https://api.github.com/repos/utopia-php/database/zipball/f162c142fd61753c4b413b15c3c4041f3cd00bb2",
"reference": "f162c142fd61753c4b413b15c3c4041f3cd00bb2",
"shasum": ""
},
"require": {
"ext-pdo": "*",
"php": ">=8.0",
"utopia-php/cache": "0.8.*",
"utopia-php/framework": "0.*.*",
"utopia-php/mongo": "0.0.2"
"utopia-php/mongo": "0.2.*"
},
"require-dev": {
"ext-mongodb": "*",
"ext-redis": "*",
"fakerphp/faker": "^1.14",
"laravel/pint": "1.4.*",
"mongodb/mongodb": "1.8.0",
"pcov/clobber": "^2.0",
"phpstan/phpstan": "1.10.*",
"phpunit/phpunit": "^9.4",
"rregeer/phpunit-coverage-check": "^0.3.1",
"swoole/ide-helper": "4.8.0",
"utopia-php/cli": "^0.14.0",
"vimeo/psalm": "4.0.1"
"utopia-php/cli": "^0.14.0"
},
"type": "library",
"autoload": {
@@ -2153,7 +2154,7 @@
"license": [
"MIT"
],
"description": "A simple library to manage application persistency using multiple database adapters",
"description": "A simple library to manage application persistence using multiple database adapters",
"keywords": [
"database",
"framework",
@@ -2163,9 +2164,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/database/issues",
"source": "https://github.com/utopia-php/database/tree/0.30.1"
"source": "https://github.com/utopia-php/database/tree/0.35.0"
},
"time": "2023-02-14T06:25:03+00:00"
"time": "2023-04-11T04:02:22+00:00"
},
{
"name": "utopia-php/domains",
@@ -2223,16 +2224,16 @@
},
{
"name": "utopia-php/framework",
"version": "0.26.0",
"version": "0.28.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/framework.git",
"reference": "e8da5576370366d3bf9c574ec855f8c96fe4f34e"
"reference": "7f22c556fc5991e54e5811a68fb39809b21bda55"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/framework/zipball/e8da5576370366d3bf9c574ec855f8c96fe4f34e",
"reference": "e8da5576370366d3bf9c574ec855f8c96fe4f34e",
"url": "https://api.github.com/repos/utopia-php/framework/zipball/7f22c556fc5991e54e5811a68fb39809b21bda55",
"reference": "7f22c556fc5991e54e5811a68fb39809b21bda55",
"shasum": ""
},
"require": {
@@ -2261,9 +2262,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/framework/issues",
"source": "https://github.com/utopia-php/framework/tree/0.26.0"
"source": "https://github.com/utopia-php/framework/tree/0.28.1"
},
"time": "2023-01-13T08:14:43+00:00"
"time": "2023-03-02T08:16:01+00:00"
},
{
"name": "utopia-php/image",
@@ -2471,16 +2472,16 @@
},
{
"name": "utopia-php/mongo",
"version": "0.0.2",
"version": "0.2.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/mongo.git",
"reference": "62f9a9c0201af91b6d0dd4f0aa8a335ec9b56a1e"
"reference": "b6dfb31b93c07c59b8bbd62a3b52e3b97a407c09"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/mongo/zipball/62f9a9c0201af91b6d0dd4f0aa8a335ec9b56a1e",
"reference": "62f9a9c0201af91b6d0dd4f0aa8a335ec9b56a1e",
"url": "https://api.github.com/repos/utopia-php/mongo/zipball/b6dfb31b93c07c59b8bbd62a3b52e3b97a407c09",
"reference": "b6dfb31b93c07c59b8bbd62a3b52e3b97a407c09",
"shasum": ""
},
"require": {
@@ -2525,9 +2526,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/mongo/issues",
"source": "https://github.com/utopia-php/mongo/tree/0.0.2"
"source": "https://github.com/utopia-php/mongo/tree/0.2.0"
},
"time": "2022-11-08T11:58:46+00:00"
"time": "2023-03-22T10:44:29+00:00"
},
{
"name": "utopia-php/orchestration",
@@ -3036,16 +3037,16 @@
"packages-dev": [
{
"name": "appwrite/sdk-generator",
"version": "0.29.4",
"version": "0.32.1",
"source": {
"type": "git",
"url": "https://github.com/appwrite/sdk-generator.git",
"reference": "35ec927d1de1854bebe8894e16b1646c3fdd5567"
"reference": "ba1d7afd57e3baef06c04ce6abc26f79310146df"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/35ec927d1de1854bebe8894e16b1646c3fdd5567",
"reference": "35ec927d1de1854bebe8894e16b1646c3fdd5567",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/ba1d7afd57e3baef06c04ce6abc26f79310146df",
"reference": "ba1d7afd57e3baef06c04ce6abc26f79310146df",
"shasum": ""
},
"require": {
@@ -3081,9 +3082,52 @@
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
"support": {
"issues": "https://github.com/appwrite/sdk-generator/issues",
"source": "https://github.com/appwrite/sdk-generator/tree/0.29.4"
"source": "https://github.com/appwrite/sdk-generator/tree/0.32.1"
},
"time": "2023-02-03T05:44:59+00:00"
"time": "2023-04-12T04:43:07+00:00"
},
{
"name": "doctrine/deprecations",
"version": "v1.0.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/deprecations.git",
"reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
"reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
"shasum": ""
},
"require": {
"php": "^7.1|^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^9",
"phpunit/phpunit": "^7.5|^8.5|^9.5",
"psr/log": "^1|^2|^3"
},
"suggest": {
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
},
"type": "library",
"autoload": {
"psr-4": {
"Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
"homepage": "https://www.doctrine-project.org/",
"support": {
"issues": "https://github.com/doctrine/deprecations/issues",
"source": "https://github.com/doctrine/deprecations/tree/v1.0.0"
},
"time": "2022-05-02T15:47:09+00:00"
},
{
"name": "doctrine/instantiator",
@@ -3617,24 +3661,27 @@
},
{
"name": "phpdocumentor/type-resolver",
"version": "1.6.2",
"version": "1.7.1",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d"
"reference": "dfc078e8af9c99210337325ff5aa152872c98714"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/48f445a408c131e38cab1c235aa6d2bb7a0bb20d",
"reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/dfc078e8af9c99210337325ff5aa152872c98714",
"reference": "dfc078e8af9c99210337325ff5aa152872c98714",
"shasum": ""
},
"require": {
"doctrine/deprecations": "^1.0",
"php": "^7.4 || ^8.0",
"phpdocumentor/reflection-common": "^2.0"
"phpdocumentor/reflection-common": "^2.0",
"phpstan/phpdoc-parser": "^1.13"
},
"require-dev": {
"ext-tokenizer": "*",
"phpbench/phpbench": "^1.2",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.8",
"phpstan/phpstan-phpunit": "^1.1",
@@ -3666,9 +3713,9 @@
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.2"
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.1"
},
"time": "2022-10-14T12:47:21+00:00"
"time": "2023-03-27T19:02:04+00:00"
},
{
"name": "phpspec/prophecy",
@@ -3738,6 +3785,51 @@
},
"time": "2023-02-02T15:41:36+00:00"
},
{
"name": "phpstan/phpdoc-parser",
"version": "1.18.1",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git",
"reference": "22dcdfd725ddf99583bfe398fc624ad6c5004a0f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/22dcdfd725ddf99583bfe398fc624ad6c5004a0f",
"reference": "22dcdfd725ddf99583bfe398fc624ad6c5004a0f",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"require-dev": {
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "^1.5",
"phpstan/phpstan-phpunit": "^1.1",
"phpstan/phpstan-strict-rules": "^1.0",
"phpunit/phpunit": "^9.5",
"symfony/process": "^5.2"
},
"type": "library",
"autoload": {
"psr-4": {
"PHPStan\\PhpDocParser\\": [
"src/"
]
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.18.1"
},
"time": "2023-04-07T11:51:11+00:00"
},
{
"name": "phpunit/php-code-coverage",
"version": "9.2.26",
+1 -1
View File
@@ -1,4 +1,4 @@
<?php
echo 'execute init_file success' . PHP_EOL;
Yasd\Api\setRemoteHost('127.0.0.1'); //Set your development machine's IP
Yasd\Api\setRemoteHost('host.docker.internal'); //Set your development machine's IP
+2 -1
View File
@@ -83,6 +83,7 @@ services:
- ./docs:/usr/src/code/docs
- ./public:/usr/src/code/public
- ./src:/usr/src/code/src
- ./dev:/usr/src/code/dev
depends_on:
- mariadb
- redis
@@ -343,7 +344,6 @@ services:
volumes:
- ./app:/usr/src/code/app
- ./src:/usr/src/code/src
#- ./vendor/utopia-php/database:/usr/src/code/vendor/utopia-php/database
depends_on:
- redis
- mariadb
@@ -473,6 +473,7 @@ services:
- /var/run/docker.sock:/var/run/docker.sock
- ./app:/usr/src/code/app
- ./src:/usr/src/code/src
- ./dev:/usr/src/code/dev
- appwrite-functions:/storage/functions:rw
- appwrite-builds:/storage/builds:rw
- /tmp:/tmp:rw
@@ -0,0 +1 @@
appwrite console variables
@@ -0,0 +1,18 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.createAnonymousSession(new CoroutineCallback<>((result, error) -> {
if (error != null)
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
}));
@@ -0,0 +1,22 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.createEmailSession(
"email@example.com",
"password"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,18 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.createJWT(new CoroutineCallback<>((result, error) -> {
if (error != null)
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
}));
@@ -0,0 +1,22 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.createMagicURLSession(
"[USER_ID]",
"email@example.com",
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,21 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.createOAuth2Session(
"amazon",
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,22 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.createPhoneSession(
"[USER_ID]",
"+12065550100"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,18 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.createPhoneVerification(new CoroutineCallback<>((result, error) -> {
if (error != null)
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
}));
@@ -0,0 +1,22 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.createRecovery(
"email@example.com",
"https://example.com"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,21 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.createVerification(
"https://example.com"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,23 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.create(
"[USER_ID]",
"email@example.com",
"",
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,21 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.deleteSession(
"[SESSION_ID]"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,18 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.deleteSessions(new CoroutineCallback<>((result, error) -> {
if (error != null)
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
}));
@@ -0,0 +1,18 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.getPrefs(new CoroutineCallback<>((result, error) -> {
if (error != null)
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
}));
@@ -0,0 +1,21 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.getSession(
"[SESSION_ID]"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,18 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.get(new CoroutineCallback<>((result, error) -> {
if (error != null)
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
}));
@@ -0,0 +1,20 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.listLogs(
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,18 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.listSessions(new CoroutineCallback<>((result, error) -> {
if (error != null)
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
}));
@@ -0,0 +1,22 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.updateEmail(
"email@example.com",
"password"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,22 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.updateMagicURLSession(
"[USER_ID]",
"[SECRET]"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,21 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.updateName(
"[NAME]"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,21 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.updatePassword(
"",
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,22 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.updatePhoneSession(
"[USER_ID]",
"[SECRET]"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,22 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.updatePhoneVerification(
"[USER_ID]",
"[SECRET]"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,22 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.updatePhone(
"+12065550100",
"password"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,21 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.updatePrefs(
mapOf( "a" to "b" )
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,24 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.updateRecovery(
"[USER_ID]",
"[SECRET]",
"password",
"password"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,21 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.updateSession(
"[SESSION_ID]"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,18 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.updateStatus(new CoroutineCallback<>((result, error) -> {
if (error != null)
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
}));
@@ -0,0 +1,22 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
account.updateVerification(
"[USER_ID]",
"[SECRET]"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,21 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Avatars;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Avatars avatars = new Avatars(client);
avatars.getBrowser(
"aa",
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,21 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Avatars;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Avatars avatars = new Avatars(client);
avatars.getCreditCard(
"amex",
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,21 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Avatars;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Avatars avatars = new Avatars(client);
avatars.getFavicon(
"https://example.com"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,21 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Avatars;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Avatars avatars = new Avatars(client);
avatars.getFlag(
"af",
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,21 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Avatars;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Avatars avatars = new Avatars(client);
avatars.getImage(
"https://example.com",
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,20 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Avatars;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Avatars avatars = new Avatars(client);
avatars.getInitials(
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,21 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Avatars;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Avatars avatars = new Avatars(client);
avatars.getQR(
"[TEXT]",
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,24 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Databases;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Databases databases = new Databases(client);
databases.createDocument(
"[DATABASE_ID]",
"[COLLECTION_ID]",
"[DOCUMENT_ID]",
mapOf( "a" to "b" ),
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,23 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Databases;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Databases databases = new Databases(client);
databases.deleteDocument(
"[DATABASE_ID]",
"[COLLECTION_ID]",
"[DOCUMENT_ID]"
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,23 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Databases;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Databases databases = new Databases(client);
databases.getDocument(
"[DATABASE_ID]",
"[COLLECTION_ID]",
"[DOCUMENT_ID]",
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,22 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Databases;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Databases databases = new Databases(client);
databases.listDocuments(
"[DATABASE_ID]",
"[COLLECTION_ID]",
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);
@@ -0,0 +1,23 @@
import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Databases;
Client client = new Client(context)
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Databases databases = new Databases(client);
databases.updateDocument(
"[DATABASE_ID]",
"[COLLECTION_ID]",
"[DOCUMENT_ID]",
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}
Log.d("Appwrite", result.toString());
})
);

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