Compare commits

...
Author SHA1 Message Date
wess c710987909 implementing updated utopia-messaging in messaging worker 2023-08-17 10:56:20 -04:00
Eldad A. FuxandGitHub 96fa7362f3 Merge pull request #5698 from appwrite/fix-cache-delete-bug-master
Fix cache delete bug master
2023-08-15 14:57:33 +03:00
Eldad A. FuxandGitHub a7094310d7 Merge pull request #5550 from Suven-p/feat-5542-validate-x-appwrite-id-header-for-CreateFile
Validate value of x-appwrite-id header
2023-08-05 13:23:52 +03:00
Eldad A. FuxandGitHub a56f91b054 Merge branch 'master' into feat-5542-validate-x-appwrite-id-header-for-CreateFile 2023-08-05 06:36:21 +03:00
Eldad A. FuxandGitHub 06570a081a Merge pull request #5928 from safwanyp/fix-5517-fix-stale-team-memberships-on-user
Fixed bug where memberships remained after a team is deleted
2023-08-05 06:34:48 +03:00
Eldad A. FuxandGitHub 702424ed31 Merge pull request #5694 from Miguelii/fix-5693-portuguese-email-template-missing-word
Added missing word to portuguese email template
2023-08-05 06:32:11 +03:00
Safwan Parkar 4a9af13f16 run formatter and linter
Run the composer format and lint commands, which I forgot to run before.
2023-08-04 23:41:29 +04:00
Safwan Parkar 0295c6ec1b improve test by removing user creation loop
The CREATE TEAM MEMBERSHIP endpoint requires the email of the user to be added to the team. If the user does not exist in the project, a new user is created with the specified email and added to the team.

The first version of the test creates 5 users, and then adds them to the newly created team. This process is more streamlined now, by using the CREATE TEAM MEMBERSHIPS behaviour to create a user on the go and create a membership for them immediately after.

I also change the way I add user IDs to the array, by using the shorthand notation instead of the `array_push` function.
2023-08-04 23:17:41 +04:00
Safwan Parkar 451f4bee19 Fixed an incorrect test for team deletion
This commit contains changes in 3 places.

- First I changed the placement of an informative comment in the DELETE TEAM controller, and moved it outside of the loop. I did this when Steven pointed out that the behaviour I describe in the comment is for the whole loop.

- The second change is the removal of my first test. I was facing quite a few issues with creating users in the test, and ended up using the CREATE TEAM MEMBERSHIP to perform 2 actions at once -> create a new user if one doesn't exist with the provided email, and create a membership for the user. Before this approach, I had quite a bit of code that didn't work, and it seems like I removed some things that weren't supposed to be removed, and didn't change variable names where necessary. Anyway, I figured that the problem has something to do with the user being created on the client side, so I moved the test to the server side.

- The new test I implemented does the same thing as my previous failed test, but in more detailed and distinct steps. The test first creates 5 new users inside of a loop, and pushes each new user's ID to an array called 'new_users' if the response is as expected. Then a new team is created. The next step is to create memberships for all 5 users. If all these steps pass, the new team that was just created, is deleted, and we check to make sure the new users have 0 team memberships each.

Formatter and linter showed no errors. Tests were successful on localhost.
2023-08-04 15:40:42 +04:00
Safwan Parkar 06e1191063 added test 2023-08-04 00:34:01 +04:00
Safwan Parkar d142620c5e invalidate cached document of user
- cache caused stale data in memberships
2023-08-03 22:08:27 +04:00
Safwan Parkar a14d89eb3c remove error-causing condition 2023-08-03 21:39:18 +04:00
Safwan Parkar 2bc2061f09 fix showing of stale team memberships 2023-08-02 18:44:43 +04:00
Safwan Parkar c5233d9ece removed unnecessary code 2023-08-02 12:18:21 +04:00
Safwan Parkar a45c62ab24 run composer scripts 2023-08-01 23:24:46 +04:00
Safwan Parkar 0fe59d457b fixed stale team memberships on user 2023-08-01 22:57:59 +04:00
Christy JacobandGitHub fcd4a69ad1 Merge pull request #5924 from appwrite/christyjacob4-patch-1
fix: error in initialising the Exception constructor in api.php
2023-08-01 20:51:49 +04:00
f6d2df8115 Update app/controllers/shared/api.php
Co-authored-by: Christy Jacob <christyjacob4@gmail.com>
2023-08-01 12:21:34 -04:00
Christy JacobandGitHub 3b4255c457 fix: error in initialising the Exception constructor in api.php 2023-08-01 18:18:27 +05:30
Eldad A. FuxandGitHub 887abad190 Merge pull request #5707 from appwrite/docs-delete-session
Update delete session description to be actually correct
2023-07-26 02:10:00 +03:00
Eldad A. FuxandGitHub f6d96237e7 Merge pull request #5755 from mendelgordon/doc-fix-magic-session-typo
Fix small typo in docs
2023-07-25 22:09:31 +03:00
Christy JacobandGitHub 6cb80c346a Merge pull request #5846 from appwrite/change-use-find-instead-iterating-index-array
change to use find instead of iterating index array in Get Index route
2023-07-25 12:14:14 +04:00
Prateek Banga f7c02d9308 removes extra db call and uses document find method 2023-07-24 23:41:49 +05:30
Prateek Banga 7d412b4741 adds get db call and get collection call 2023-07-24 12:02:28 +05:30
Eldad A. FuxandGitHub 0a5d53ec35 Merge pull request #5857 from appwrite/feat-oauth-provider-name
Update Project providers to also include the provider key
2023-07-21 07:56:25 +03:00
Steven Nguyen 5be6d8e90b Update Project providers to also include the provider key
Pass the provider key and name back so that a nicely formatted name
can be shown in the Appwrite Console.
2023-07-20 16:53:33 -07:00
Prateek Banga d569c17764 Merge branch 'master' of https://github.com/appwrite/appwrite into change-use-find-instead-iterating-index-array 2023-07-21 00:49:15 +05:30
Eldad A. FuxandGitHub 7a02a1690a Merge pull request #5449 from appwrite/feat-4299-oidc-oauth2-provider
Add a generic OIDC OAuth2 provider
2023-07-20 20:44:03 +03:00
Prateek Banga b700336d45 fix get index route to use find 2023-07-20 14:52:05 +05:30
Eldad A. FuxandGitHub e12a5738aa Merge pull request #5853 from appwrite/fix-audit-user-internal-id
Fix audit user internal
2023-07-20 10:31:26 +03:00
Eldad A. FuxandGitHub 8633be26d4 Merge pull request #5854 from appwrite/feat-akamai-setup
Akamai setup in readme
2023-07-20 08:59:59 +03:00
Damodar LohaniandGitHub 2c2c7d9028 Create akamai-logo.svg 2023-07-20 11:36:40 +05:45
Damodar LohaniandGitHub 1e0158cdef Update README.md 2023-07-20 11:35:59 +05:45
StevenandSteven Nguyen 3f9cedcc44 Prepare 1.3.8 release 2023-07-19 22:49:51 -07:00
Steven Nguyen cd78706944 Update migration for audit collection
1. Remove the userInternalId attribute
2. Replace userId in audit documents with userInternalId and put
userId in data
2023-07-19 22:49:51 -07:00
Steven Nguyen 9908a9021f Update get logs by user to pass user internal id
The userId in audit is actually the userInternalId.
2023-07-19 22:49:51 -07:00
Steven Nguyen 187f3dc6ff Update get logs APIs to return userId from data
The audit userId is actually the internal id and the user id is in the
data attribute.
2023-07-19 22:49:51 -07:00
Steven Nguyen 58fa7546c1 Update Appwrite to save internal id as audit user id
It's important to use userInternalId so that if a user is recreated
with the same ID, lookups for the user will not return the data
of the old deleted user.

We will still store userId in data so that it can be pulled out and
returned for the log API calls.
2023-07-19 22:49:51 -07:00
Steven Nguyen 35a25cc2a7 Bump audit version to get rid of userInternalId attribute 2023-07-19 22:49:50 -07:00
Eldad A. FuxandGitHub 30fc5658e4 Merge pull request #5847 from appwrite/chore-upgrade-domains
Fix np TLD validation
2023-07-20 08:21:36 +03:00
StevenandGitHub cc42700299 Fix test after session expire format was updated 2023-07-19 23:52:33 +00:00
Steven 803d653e44 Upgrade utopia-php/domains
Version 1.1.0 was an incorrectly named git tag; it was equivalent to
0.2.0. This bump to 0.3.* is safe because it adds Registrar,
but it won't be used in Appwrite yet. Bumping to 0.3.* is necessary to
fix some bugs where valid domains were considered invalid.
2023-07-19 18:29:01 +00:00
Prateek Banga 8328dac86b lint issues 2023-07-19 14:08:02 +05:30
Prateek Banga 131e9658a5 change to use findOne instead of iterating index array 2023-07-19 14:04:35 +05:30
Eldad A. FuxandGitHub 9fafd39fef Merge pull request #5211 from Pranav2612000/fix-5095-trigger-email-subscription-on-email-verification
fix: trigger account subscription event on email verification
2023-07-19 00:24:33 +03:00
Eldad A. FuxandGitHub 7a2c789c6b Merge pull request #5745 from vaibhavagarwal220/fix-5220-handle-null-name
fixed null $name error for anonymous user
2023-07-19 00:21:09 +03:00
Eldad A. FuxandGitHub b2b1b6e2e4 Merge pull request #5562 from fanatic75/fix-4846-added-expiry-value-to-account-sessions
fix expire field in list account sessions api
2023-07-19 00:17:53 +03:00
Eldad A. FuxandGitHub bee246956c Merge pull request #5808 from jaivix/fix-5768-pull-request-to-return-team-id-conflict-error
fixed team creation response if teamId already exists
2023-07-18 23:00:31 +03:00
Eldad A. FuxandGitHub 6f499cfa26 Merge pull request #5567 from fanatic75/fix-4982-expire-sessions-format-for-multiple-api
fixed expire format for phone session, anonymous session, oauth session
2023-07-18 22:57:10 +03:00
Eldad A. FuxandGitHub d4ed77b5e8 Merge pull request #5568 from fanatic75/fix-5429-expire-format-fix-for-get-session
fix: expire format for get session api
2023-07-18 22:56:47 +03:00
Eldad A. FuxandGitHub 3a17f30374 Merge pull request #5566 from fanatic75/fix-5428-fixed-expire-format-for-magic-url-sessions
fix: expire format in magic url sessions
2023-07-18 22:56:35 +03:00
jaivikandGitHub 6380004678 Merge branch 'appwrite:master' into fix-5768-pull-request-to-return-team-id-conflict-error 2023-07-18 10:35:52 +05:30
Eldad A. FuxandGitHub 11c9066c4d Merge pull request #5402 from appwrite/fix-chunked-upload
content-range end should be 1 less than file size
2023-07-18 06:55:05 +03:00
Eldad A. FuxandGitHub ce5a689b5b Merge pull request #5565 from appwrite/fix-flutter-getting-started-1
Update Flutter GETTING_STARTED.md
2023-07-18 06:53:58 +03:00
Eldad A. FuxandGitHub c8689d1d41 Merge pull request #5639 from appwrite/fix-default-project
Fix default project
2023-07-16 21:13:57 +03:00
shimon ee6ddc89dc cache deleteById to deleteByGroup 2023-07-13 13:53:35 +03:00
shimon b7aab21698 cache deleteById to deleteByGroup 2023-07-13 13:36:14 +03:00
jaivix b78401923f test case minor fix 2023-07-13 12:10:52 +05:30
jaivix 4db919b42d linting and wording updates based on stnguyen90 feedback 2023-07-13 00:33:38 +05:30
Torsten DittmannandGitHub 73329ad219 Merge pull request #4758 from appwrite/add-console-headers
fix: add headers to console
2023-07-11 23:14:06 +02:00
Christy Jacob 8bf8c96b01 feat: update console 2023-07-11 18:43:28 +00:00
Christy Jacob e78e8d3929 Merge branch 'master' of https://github.com/appwrite/appwrite into add-console-headers 2023-07-11 18:37:12 +00:00
Christy JacobandGitHub 3f8551b41c Merge pull request #5797 from appwrite/1.3.x
1.3.x
2023-07-11 23:35:41 +05:30
shimon a37fee2d16 Merge branch 'master' of github.com:appwrite/appwrite into fix-cache-delete-bug-master 2023-07-11 18:48:07 +03:00
vaibhavagarwal220 48fc58d365 fixed linting errors 2023-07-11 09:33:02 +05:30
Christy Jacob 125c14d492 Merge branch 'master' of https://github.com/appwrite/appwrite into 1.3.x 2023-07-10 20:59:05 +00:00
Christy JacobandGitHub 42b66b938c Merge pull request #5796 from appwrite/update-dotnet-docs-examples
doc: Add .NET SDK docs examples
2023-07-11 02:15:05 +05:30
Christy JacobandGitHub 87ddafe911 Merge pull request #5795 from appwrite/update-python-version
feat: update python version
2023-07-11 02:14:24 +05:30
Christy Jacob da44f65f2c feat: update composer 2023-07-10 20:41:21 +00:00
Christy Jacob 7f5f6b352d Merge branch '1.3.x' of https://github.com/appwrite/appwrite into update-python-version 2023-07-10 20:38:56 +00:00
Aditya Oberai b4fea28787 Add .NET SDK docs examples 2023-07-11 00:15:46 +05:30
Christy JacobandGitHub a1519e263c Merge pull request #5785 from appwrite/update-dotnet-getting-started
doc: Update getting started examples for .NET SDK
2023-07-11 00:03:19 +05:30
Christy Jacob 5aefa88a50 feat: update python version 2023-07-10 21:36:17 +04:00
Christy JacobandGitHub 27adf0788f Merge pull request #5788 from appwrite/fix-relationship-update-two-way
fixed relationship update bug in two way type
2023-07-10 23:02:24 +05:30
Prateek Banga e1ba324196 fix formatting issues in comments according to feedback in PR. 2023-07-10 13:34:32 +05:30
jaivix a6671a5caa fixed team creation response if teamId already exists 2023-07-09 16:50:09 +05:30
Aditya Oberai a8bc9e6154 Update sdk-generator version 2023-07-07 20:02:51 +00:00
Prateek Banga a98248478f lint issues 2023-07-08 01:31:20 +05:30
Prateek Banga 4542ec34ae added test case to verify update of two way relationship 2023-07-08 01:28:24 +05:30
Aditya OberaiandGitHub a7dd5f617d Update .NET SDK version 2023-07-08 00:59:57 +05:30
Prateek Banga f24cf729c3 fixed relationship update bug in two way type 2023-07-07 23:50:06 +05:30
Aditya OberaiandGitHub c617f0e079 Remove unnecessary code 2023-07-07 20:04:01 +05:30
Aditya OberaiandGitHub b3915fb197 Update getting started examples 2023-07-07 18:27:44 +05:30
vaibhavagarwal220 4e24b7eb42 update e2e test for anonymous user verification 2023-07-07 00:20:13 +05:30
Mendel GordonandGitHub 70cebe4460 Update create-magic-url-session.md
Fix typo
2023-06-29 10:32:03 -04:00
vaibhavagarwal220 fecde6bdba fixed null $name error for anonymous user 2023-06-24 13:57:02 +05:30
Prateek BangaandGitHub c4ef7fddc0 Merge branch 'appwrite:master' into fix-4846-added-expiry-value-to-account-sessions 2023-06-23 08:04:38 +05:30
Christy JacobandGitHub 9f2bf844c7 Merge pull request #5580 from appwrite/fix-project-deletion-master
remove password required for project deletion
2023-06-22 22:52:59 +05:30
Jake BarnbyandGitHub aabe14474e Merge pull request #5718 from faisalill/fix-4436-fix-audit-activity-on-document-create
fixed incorrect audity activity on document create
2023-06-20 13:46:58 +12:00
faisalill 7e8f6f748a fixed incorrect audity activity on document create 2023-06-17 00:20:37 +05:30
Vincent (Wen Yu) Ge 57621de57d Damodar's comments 2023-06-15 18:38:15 +00:00
Vincent (Wen Yu) Ge 6edea596b4 Update delete session description to be actually correct 2023-06-14 17:49:52 +00:00
shimon f2b5607074 cache deletion bug fix 2023-06-13 17:06:47 +03:00
shimon 8e0457a307 cache deletion bug fix 2023-06-13 14:53:12 +03:00
shimon 7e95f529a6 cache deletion bug fix 2023-06-13 14:33:26 +03:00
shimon 13066c3dde cache deletion bug fix 2023-06-13 14:11:23 +03:00
Migueli 39ea3adc9d Added missing word to portuguese email template 2023-06-12 23:39:00 +01:00
Jake BarnbyandGitHub fd7a2cbfad Merge pull request #5671 from appwrite/feat-update-error-message
Update document missing params error message
2023-06-12 21:19:32 +12:00
Jake Barnby ed2c1139a7 Update messages 2023-06-09 13:03:19 +12:00
Jake Barnby b7f4f57521 Add new error message to differentiate between missing data and missing data + permissions for document updates 2023-06-07 13:51:24 +12:00
Steven Nguyen f7f14695f0 Don't default to console project
Defaulting to the console project leads to misleading error messages.
For example, you can get a CORS error saying you haven't configured
a platform yet, but the actual error is missing project ID.
2023-06-05 09:06:29 -07:00
Christy JacobandGitHub c696b7264b Merge pull request #5649 from appwrite/1.3.x
Sync master with 1.3.x
2023-06-04 00:43:03 +05:30
Christy JacobandGitHub 7844094b58 Merge pull request #5648 from appwrite/updates-for-1.3.7
Updates for 1.3.7
2023-06-03 21:13:34 +05:30
Christy Jacob 596998000b chore: update console 2023-06-03 20:15:40 +05:30
Christy Jacob a68f0826e7 chore: update changelog 2023-06-03 20:14:44 +05:30
Christy Jacob 9dcf164b2f chore: update composer 2023-06-03 20:14:11 +05:30
Christy Jacob 329b6b93bf chore: update changelog 2023-06-03 20:11:01 +05:30
Christy Jacob 9dee834637 chore: remove unrelated files 2023-06-03 20:06:27 +05:30
Christy Jacob 8b01c61de3 chore: update utopia-php/framework 2023-06-03 20:06:17 +05:30
Steven NguyenandChristy Jacob 092f0cfcaf Fix the routing for the default OAuth2 pages 2023-06-03 20:05:45 +05:30
Christy JacobandGitHub 73f410cc60 Merge pull request #5640 from appwrite/fix-oauth-routes 2023-06-03 12:51:41 +05:30
Steven Nguyen bd6b0dcc43 Fix the routing for the default OAuth2 pages 2023-06-02 14:22:28 -07:00
Torsten DittmannandGitHub 223663aa89 Merge pull request #5637 from appwrite/1.3.x
sync 1.3.x
2023-06-02 16:30:55 +02:00
Torsten Dittmann 92cda20448 chore: revert docker compose changes 2023-06-02 15:21:20 +02:00
Torsten Dittmann 21b41c475d chore: prepre 1.3.6 2023-06-02 15:21:05 +02:00
Torsten Dittmann a664363525 fix: trailing wildcards 2023-06-02 15:20:58 +02:00
Prateek Banga a524a40a8c Merge branch 'fix-4846-added-expiry-value-to-account-sessions' of https://github.com/fanatic75/appwrite into fix-4846-added-expiry-value-to-account-sessions 2023-06-02 15:29:02 +05:30
Prateek Banga 5dc65ea374 fix updated test case to check if expire is valid iso string or not 2023-06-02 15:15:06 +05:30
Prateek BangaandGitHub ea53fe9025 Merge branch 'appwrite:master' into fix-4846-added-expiry-value-to-account-sessions 2023-06-02 14:54:20 +05:30
Prateek Banga 1475497ffb Merge branch 'master' of https://github.com/fanatic75/appwrite into fix-4846-added-expiry-value-to-account-sessions 2023-06-02 14:53:26 +05:30
Christy JacobandGitHub bbc9bb823d Merge pull request #5611 from appwrite/1.3.x
1.3.x
2023-05-30 23:04:08 +05:30
Christy Jacob 9e1313d15a feat: update dependencies 2023-05-30 16:59:13 +00:00
Christy Jacob 44fd41d2ea Merge branch 'master' of https://github.com/appwrite/appwrite into 1.3.x 2023-05-30 16:58:22 +00:00
Christy JacobandGitHub 985064ebf1 Merge pull request #5610 from appwrite/chore-prepare-release
Chore prepare release
2023-05-30 22:23:48 +05:30
Christy Jacob 927c7c3359 feat: update composer 2023-05-30 16:16:43 +00:00
Christy Jacob a3474f8a3b feat: prepare 1.3.5 release 2023-05-30 16:15:13 +00:00
Jake BarnbyandGitHub e44e4e7766 Merge pull request #5603 from appwrite/hotfix-route-mismatch
Update framework to fix route mismatches
2023-05-30 23:33:17 +12:00
Jake BarnbyandGitHub 85fac1f5f5 Merge pull request #5606 from appwrite/backport-string-default-min-length
Set min length to 0 for default value when creating or updating a str…
2023-05-30 20:49:55 +12:00
Jake Barnby 225f21454c Update changelog 2023-05-30 19:44:13 +12:00
Jake Barnby d2bfe46fca Set min length to 0 for default value when creating or updating a string attribute
(cherry picked from commit c61e54f69b)
2023-05-30 19:42:13 +12:00
Jake Barnby 5f5ed7dc19 Fix graphql upload test path 2023-05-30 19:41:06 +12:00
Eldad A. FuxandGitHub 6011194826 Merge pull request #5602 from appwrite/fix-string-default-min-length
Set min length to 0 for default value for string attributes
2023-05-30 10:23:16 +03:00
Jake Barnby b101404eda Update to release version of framework 2023-05-30 18:53:58 +12:00
Jake Barnby bab804b8e1 Fix tests
(cherry picked from commit 0661f1f889)
2023-05-30 18:29:20 +12:00
Jake Barnby 3dd67cb17f Fix visibility
(cherry picked from commit b092405b04)
2023-05-30 18:29:13 +12:00
Jake Barnby c2e711b021 Update framework to fix route mismatches
(cherry picked from commit d42f6738a9)

# Conflicts:
#	composer.lock
2023-05-30 18:29:04 +12:00
Jake Barnby 2c59807bf5 Update changelog 2023-05-30 15:02:33 +12:00
Jake Barnby c61e54f69b Set min length to 0 for default value when creating or updating a string attribute 2023-05-30 14:52:59 +12:00
Jake BarnbyandGitHub f45905e545 Merge pull request #5553 from 2002Bishwajeet/feat-add-enable-param-db
Feat: Add enable param in Database and Collection
2023-05-29 20:35:33 +12:00
Jake BarnbyandGitHub 0372b0c590 Update tests/e2e/Services/Databases/DatabasesCustomServerTest.php 2023-05-29 20:34:41 +12:00
Bishwajeet Parhi 729eed25e5 chore: fix formatting 2023-05-29 13:12:55 +05:30
Suven-p 42b2587b6d Fix linting error 2023-05-27 22:54:00 +05:45
Bishwajeet Parhi 9d1d985d0d chore: Add new unit tests 2023-05-26 17:54:35 +05:30
Bishwajeet Parhi 68c56daba1 add extra check for admin modes 2023-05-26 17:08:09 +05:30
Damodar Lohani 237658f4e8 fix param 2023-05-25 05:33:06 +00:00
Damodar Lohani 6c38bcc270 fix typo 2023-05-25 01:26:13 +00:00
Damodar Lohani 6813d53e06 remove password required for project deletion 2023-05-25 00:32:49 +00:00
Bishwajeet Parhi b0656acf9c chore: Add unitTests DatabaseConsoleClientTest 2023-05-24 23:10:12 +05:30
Bishwajeet Parhi 2873918cc5 Update databases.php
fix: tests
2023-05-24 22:56:58 +05:30
Bishwajeet Parhi e496419572 remove formatting updates 2023-05-24 22:24:57 +05:30
Bishwajeet Parhi 6fc176d508 chore: add admin mode assertion for create collection 2023-05-24 17:58:40 +05:30
Bishwajeet Parhi 4706e6580d chore: add new checks 2023-05-24 15:39:08 +05:30
Bishwajeet Parhi 1a8729177f chore: formattin suggestion 2023-05-24 10:36:54 +05:30
Jake BarnbyandGitHub 181741d7a2 Merge pull request #5538 from appwrite/feat-dotnet-sdk
Feat dotnet sdk
2023-05-23 21:37:01 +12:00
4964b5c592 Update tests/e2e/Services/Databases/DatabasesCustomServerTest.php
Co-authored-by: Jake Barnby <jakeb994@gmail.com>
2023-05-23 13:30:48 +05:30
6e5ee27f7c Update tests/e2e/Services/Databases/DatabasesCustomServerTest.php
Co-authored-by: Jake Barnby <jakeb994@gmail.com>
2023-05-23 13:30:39 +05:30
Jake Barnby 772e730b67 Revert "Update SDK generator + examples" spec changes
This reverts commit 2eef1cfca5.
2023-05-23 16:26:07 +12:00
Eldad A. FuxandGitHub b86ce2d233 Merge pull request #5561 from appwrite/fix-delete-account
Update the Update Account Status API to clear the cookie
2023-05-22 23:06:02 +03:00
Steven Nguyen 09b4fbcc21 Update the error message for blocked users
Remove the "You can unblock the user from the Appwrite console." part
as it is not relevant for the person receiving the error.
2023-05-22 12:28:47 -07:00
Bishwajeet Parhi 45f5d932f6 Add more Tests 2023-05-22 20:10:09 +05:30
Prateek Banga 977279b679 fix: expire format for get session api 2023-05-22 18:34:51 +05:30
Prateek Banga 249bec5124 fixed expire format for phone session, anonymous session, oauth session 2023-05-22 18:18:52 +05:30
Prateek Banga 8673df4ac5 fix: expire format in magic url sessions 2023-05-22 17:52:25 +05:30
Suven-pandGitHub 5108ab7b06 Add test for x-appwrite-id = unique() 2023-05-21 15:43:26 +00:00
Damodar LohaniandGitHub 6858c5c26a Update GETTING_STARTED.md 2023-05-21 07:27:20 +05:45
Prateek Banga 19a3db69f8 fix updated expire format to iso format 2023-05-20 21:09:48 +05:30
Prateek Banga 5cb9cc9dfd fix expire field in list account sessions api 2023-05-20 02:36:45 +05:30
Steven Nguyen 9961609d71 Update the Update Account Status API to clear the cookie
After a user updates their status, their session no longer works
however, the cookie may still exist in their browser, preventing other
API calls from completing successfully.
2023-05-19 11:58:17 -07:00
Christy JacobandGitHub d630d8772b Merge pull request #5460 from appwrite/fix-create-project-error
fix: throw correct exception when project ID already exists
2023-05-19 22:48:02 +05:30
Bishwajeet Parhi 7fe1f56122 chore: add more test coverage 2023-05-19 18:18:26 +05:30
Bishwajeet Parhi c2a13b079e chore: lowercase 2023-05-19 12:54:07 +05:30
Bishwajeet Parhi e384a3d3a1 remove debug config 2023-05-18 18:58:29 +05:30
Bishwajeet Parhi 40f70faa89 Feat: Add enable param in Database and Collection 2023-05-18 18:55:22 +05:30
Suven-p 582698bd03 Validate value of x-appwrite-id header 2023-05-18 00:41:07 +05:45
Jake Barnby 2eef1cfca5 Update SDK generator + examples 2023-05-16 16:54:34 +12:00
Jake Barnby 67f1ae377c Update version 2023-05-16 14:40:55 +12:00
Jake Barnby 257c58f438 Merge remote-tracking branch 'origin/master' into feat-dotnet-sdk 2023-05-15 19:15:34 +12:00
Jake Barnby b9336bfc73 Update SDK generator 2023-05-15 19:15:01 +12:00
Jake Barnby ab7f4285d5 Add examples 2023-05-15 19:14:23 +12:00
Jake Barnby 67a7a217e8 Fix getting started 2023-05-15 19:13:20 +12:00
Eldad A. FuxandGitHub 953485299a Merge pull request #5513 from appwrite/fix-storage-file-hash
Fix- Original File Hash
2023-05-11 06:32:52 +01:00
Damodar Lohani 0592384d84 fix test 2023-05-10 06:31:12 +00:00
Torsten DittmannandGitHub 82c5a20ef3 Merge pull request #5469 from appwrite/feat-support-docker-override
Update install.php to not specify docker-compose.yml file
2023-05-09 17:09:07 +02:00
Torsten DittmannandGitHub f3856f446e Merge pull request #5446 from appwrite/fix-changes-team-prefs
Update CHANGES.md to include team prefs fix
2023-05-09 17:07:21 +02:00
Torsten DittmannandGitHub 1c815c8d99 Merge pull request #5166 from lucasctd/master
set correct value for logging drivers
2023-05-09 17:07:08 +02:00
Damodar LohaniandGitHub fc36120a51 get file hash before encryption and compression 2023-05-07 11:33:27 +05:45
Torsten DittmannandGitHub 6700f90ba1 Merge pull request #5503 from appwrite/1.3.x
Sync master with 1.3.x
2023-05-04 21:15:53 +02:00
Torsten DittmannandGitHub 67ad856490 Merge pull request #5497 from appwrite/fix-bucket-permissions
Fix bucket permissions
2023-05-04 19:32:44 +02:00
Torsten DittmannandGitHub 25b1eb0ab2 Merge pull request #5502 from appwrite/master
Sync 1.3.x with Master
2023-05-04 19:14:31 +02:00
Torsten DittmannandGitHub dcefe3f9b7 Merge pull request #5457 from appwrite/fix-release-workflow-name
Fix the release github action
2023-05-04 18:18:51 +02:00
Christy JacobandGitHub 60f51580a7 Merge pull request #5246 from singhbhaskar/fix-4960-Database-usage-screen-shows-500-error-when_APP_USAGE_STATS-is-disabled
Fix: Updated error when _APP_USAGE_STATS is disabled
2023-05-04 20:47:50 +05:30
Torsten DittmannandGitHub bb7891b5bf Merge pull request #5492 from appwrite/fix-update-document
Fix update document merging existing data after pre-processing
2023-05-04 15:28:05 +02:00
Steven Nguyen d7bbfb55ed Prepare 1.3.4 release 2023-05-03 13:39:05 -07:00
Steven Nguyen c46a02b496 Update CHANGES.md 2023-05-03 12:15:37 -07:00
Steven Nguyen 4dd6a7977e Update create and update bucket APIs
Ensure the permissions and document security are updated in the
metadata collection.
2023-05-03 12:15:37 -07:00
Steven Nguyen afd2c7a065 Update migration to set bucket permissions in metadata table 2023-05-03 12:15:37 -07:00
Jake Barnby db1fd42b0d Update platform 2023-05-03 21:54:38 +12:00
Steven Nguyen 9898005465 Fix the version passed into the docker build command
Change the order of the tags to ensure the version passed into the
docker build command is the full major.minor.patch version.
2023-05-02 17:43:39 -07:00
Bhaskar Singh a4299a69ef Refactored the condition for strict inequality 2023-05-02 23:47:50 +05:30
Christy JacobandGitHub 2fcd78d784 Merge pull request #5360 from Atsurak/master
fix : wrong links for getting started for web
2023-05-02 23:32:46 +05:30
Christy JacobandGitHub 6ad4401365 Merge pull request #5484 from appwrite/update-readme
Update README.md
2023-05-02 19:21:55 +05:30
Vincent (Wen Yu) GeandGitHub 17acfd5d1c Update README-CN.md 2023-05-02 09:49:55 -04:00
Jake Barnby 30237ccfb1 Add test for updating existing document with relationship 2023-05-02 20:27:09 +12:00
3c5bebc34e Update README.md
Co-authored-by: Eldad A. Fux <eldad.fux@gmail.com>
2023-05-02 14:02:57 +05:45
Damodar LohaniandGitHub 970457045f Update README.md 2023-05-02 13:47:40 +05:45
Damodar LohaniandGitHub 789198d523 Update README.md 2023-05-02 13:38:47 +05:45
Jake Barnby 2eafda4ee2 Fix update document merging existing data after pre-processing instead of before 2023-05-02 19:53:11 +12:00
Damodar LohaniandGitHub a5fa150c25 Update README.md 2023-05-02 12:55:40 +05:45
Damodar LohaniandGitHub 6e65178ad5 Update README.md 2023-05-02 12:54:20 +05:45
Christy JacobandGitHub e7303245b2 Merge pull request #5473 from appwrite/eldadfux-patch-1
Update README.md
2023-05-01 20:07:44 +05:30
Eldad A. FuxandGitHub cfd6eee0da Update README.md 2023-05-01 15:34:13 +01:00
StevenandGitHub 5d651b9e8a Update install.php not specify docker-compose.yml file
By not specifying a docker-compose.yml file, docker compose automatically uses the docker-compose.yml file in the project directory and a docker-compose.override.yml file if one is present.
2023-04-30 12:34:55 -07:00
Christy JacobandGitHub 33d2e94d1d Apply suggestions from code review 2023-04-30 01:54:45 +05:30
Christy JacobandGitHub 80dd3644f8 Merge pull request #5394 from appwrite/docs-cloud
Move reference to env-var to self-hosted docs.
2023-04-30 00:46:56 +05:30
Christy Jacob 3f61db57b9 chore: add tests 2023-04-29 13:13:33 +05:30
Christy Jacob 3451d3d800 chore: linter 2023-04-29 12:44:07 +05:30
Christy Jacob ac004acbc8 fix: throw correct exception when project custom ID already exists 2023-04-29 12:41:17 +05:30
Steven Nguyen a0297bfb8b Fix the release github action job name 2023-04-28 12:47:51 -07:00
Torsten DittmannandGitHub 84c06a8ece Merge pull request #5456 from appwrite/1.3.x
Sync master with 1.3.x
2023-04-28 21:42:32 +02:00
Torsten DittmannandGitHub ba24c0a843 Merge pull request #5455 from appwrite/fix-1.3.1-migration
Prevent migration from overriding existing data
2023-04-28 21:34:04 +02:00
Steven Nguyen 1e5dc3ad6f Bump version to 1.3.3 2023-04-28 12:29:46 -07:00
Steven Nguyen d0cfad9085 Prevent migration from overriding existing data
For users already on 1.3.1, after upgrading to 1.3.2, the migration
script would override existing auths, password history, team prefs, and
(relationship) attribute options with empty values. This commit fixes
the migration to set to an existing value if there was one.
2023-04-28 12:20:30 -07:00
Christy JacobandGitHub e311b6bd0e Merge pull request #5453 from appwrite/update-docs-for-beta
Update docs for beta
2023-04-28 20:29:15 +05:30
Christy Jacob f0d7f6c7ed feat: update endpoint for Appwrite 1.3.x 2023-04-28 19:40:24 +05:30
Christy Jacob 913571654a feat: update endpoint for Appwrite 1.2.x 2023-04-28 19:36:30 +05:30
Christy Jacob 77fcdb847d feat: update endpoint for Appwrite 1.1.x 2023-04-28 19:33:02 +05:30
Christy JacobandGitHub 7e40b59707 Merge pull request #5448 from appwrite/feat-bump-sdk-generator
Bump sdk-generator and specs
2023-04-28 09:54:46 +05:30
Steven Nguyen 518a37d294 Add a generic OIDC OAuth2 provider 2023-04-27 19:48:51 -07:00
Steven Nguyen 206553bac7 Bump sdk-generator and specs 2023-04-27 17:00:12 -07:00
StevenandGitHub 169b3c3605 Update CHANGES.md to include team prefs fix 2023-04-27 13:40:25 -07:00
Torsten DittmannandGitHub c3ad6a1260 Merge pull request #5443 from appwrite/1.3.x
Merge 1.3.x to Master
2023-04-27 21:49:39 +02:00
Torsten DittmannandGitHub b2c8e182a5 Merge pull request #5442 from appwrite/fix-project-deletion-leftovers
fix: project deletion leftovers
2023-04-27 20:19:09 +02:00
Torsten DittmannandGitHub ff5132867e Merge pull request #5444 from appwrite/feat-bump-abuse-audit-database
Feat bump abuse audit database
2023-04-27 20:16:39 +02:00
Steven Nguyen 11d523b050 Bump utopia abuse, audit, and database 2023-04-27 10:42:55 -07:00
Torsten DittmannandGitHub eac59e9d02 Merge pull request #5314 from appwrite/fix-specs-command
Update CONTRIBUTING.md to fix specs command
2023-04-27 18:22:58 +02:00
Torsten Dittmann e7c311044b chore: add changelog 2023-04-27 18:04:00 +02:00
Torsten Dittmann 7529f02bd6 fix: also delete webhooks on project deletion 2023-04-27 17:41:14 +02:00
Torsten Dittmann 31e65d954b fix: deletes worker for projects 2023-04-27 17:37:14 +02:00
Torsten Dittmann e1cf068652 fix: platforms query 2023-04-27 17:36:00 +02:00
Bhaskar Singh 7064f884aa Refactor usage init hook to remove unecessary
inject
2023-04-27 19:32:05 +05:30
Torsten Dittmann d45bc5e60f chore: upgrade console 2023-04-27 15:54:07 +02:00
Damodar Lohani edbc52403a update so that current SDK don't fail 2023-04-27 09:29:39 +00:00
Torsten DittmannandGitHub fb507ad83b Merge pull request #5432 from appwrite/chore-sync-1-3-x
chore: sync 1.3.x with master
2023-04-26 18:16:21 +02:00
Torsten Dittmann e9e83ae8ec Merge branch 'master' of https://github.com/appwrite/appwrite into chore-sync-1-3-x 2023-04-26 12:30:14 +02:00
Jake BarnbyandGitHub 4aa6ce3cfd Merge pull request #5426 from appwrite/fix-apple-getting-started
Fix typo in Apple Getting Started
2023-04-26 16:37:24 +12:00
Christy Jacob d5fb9ab9a6 Merge branch 'master' of https://github.com/appwrite/appwrite into add-console-headers 2023-04-26 03:37:39 +00:00
Christy JacobandGitHub 0e5e3f6f6f Merge pull request #5362 from appwrite/update-cli
feat: update cli version
2023-04-25 23:49:29 +05:30
Torsten DittmannandGitHub 4ceae33a5a Merge pull request #5163 from yatharth1706/fix-5147-fix-error-description-in-case-of-duplicate-user
fix error description for duplicate user
2023-04-25 15:45:59 +02:00
Torsten DittmannandGitHub 713535bf79 Merge pull request #5285 from rinkuhasija/fix-5272-correct-documentation-model-attributeDatetime-Object-example
fix-models-attributeDatetime-object-example
2023-04-25 15:45:39 +02:00
Torsten DittmannandGitHub aaf5ab9024 Merge pull request #5382 from appwrite/fix-5381-var-missing-after-upgrade
Fix missing var after upgrade
2023-04-25 15:41:43 +02:00
Christy JacobandGitHub 1c4dc6a424 Merge pull request #3696 from appwrite/fix-event-multi-execution
Fix: event multi-execution
2023-04-25 17:31:45 +04:00
StevenandGitHub 2d0cf85edd Fix typo in Apple Getting Started 2023-04-24 12:03:41 -07:00
Torsten Dittmann 43a6945d30 fix: migration 2023-04-24 13:21:31 +02:00
Torsten Dittmann 4ebe485f05 remove: leftover from http.php 2023-04-24 13:11:39 +02:00
Torsten Dittmann 5ee3c592a4 chore: release 1.3.2 2023-04-24 13:10:28 +02:00
Torsten Dittmann ff82a24a4b feat: migration 2023-04-24 13:00:23 +02:00
Bhaskar Singh 3865f48d32 Moved check for _APP_USAGE_STATS
to create init hook for App
2023-04-21 23:09:01 +05:30
Torsten Dittmann 5925d61a9c chore: update composer 2023-04-21 13:04:37 +02:00
Steven Nguyen 3f72b738fa Fix related creates 2023-04-20 18:44:53 -07:00
Torsten Dittmann 0230671717 chore: upgrade utopia-php/database 2023-04-20 21:10:48 +02:00
Steven Nguyen e8dee9296c Fix update document not merging existing data 2023-04-20 10:10:51 -07:00
Steven Nguyen 4113ae7ca5 Allow updating document with read-only relationship
A user should be able to update a document without touching the
relationship.

Relates: https://github.com/appwrite/appwrite/issues/5404
2023-04-19 17:21:41 -07:00
Steven Nguyen 37afb82d1c Delegate permissions check to database layer 2023-04-19 17:21:41 -07:00
Steven Nguyen 611dd9b86c Return 404 if a user doesn't have access to a collection
It is better to return 404 so that an end user doesn't know if the
collection actually exists but they don't have access or they really
don't have access.
2023-04-19 17:21:41 -07:00
Steven Nguyen 50bb69290f Ensure collections are created with permissions and documentSecurity 2023-04-19 17:21:41 -07:00
Steven Nguyen 471c832a4f Bump utopia-php/database version 2023-04-19 17:21:41 -07:00
Damodar Lohani b13800386d fix mock for upload changes 2023-04-19 06:15:24 +00:00
Damodar Lohani 3486885dc8 fix large deployment test 2023-04-19 05:38:54 +00:00
Damodar Lohani 26aea21768 fix chunk header size in test 2023-04-19 04:44:59 +00:00
Damodar Lohani 518b45827f content-range end should be 1 less than file size 2023-04-19 02:17:26 +00:00
Vincent (Wen Yu) Ge d965df4a05 Remove reference to env vars in references 2023-04-17 21:12:15 +00:00
Steven Nguyen d41df04b6a Ensure vars are not lost during upgrade
Using a reference on an array element while iterating over it caused
some unexpected behavior. Instead of using a reference, this change
uses a key to allow us to edit the array element.

For reference on the problem, see https://stackoverflow.com/questions/70691375/foreach-with-reference-causing-arrays-last-element-to-repeat.
2023-04-14 16:18:31 -07:00
Jake BarnbyandGitHub d1740d2121 Merge pull request #5363 from appwrite/fix-nested-id-required
Fix auto-setting custom ID on nested documents
2023-04-14 22:37:24 +12:00
Jake Barnby 0dea80c9da Cache whether relation is a list 2023-04-14 22:03:16 +12:00
Jake Barnby fb130f3aa2 Merge remote-tracking branch 'origin/1.3.x' into fix-nested-id-required 2023-04-14 21:59:42 +12:00
Jake BarnbyandGitHub 78aadd2f39 Merge pull request #5361 from appwrite/fix-team-pres-empty-array
Ensure empty team prefs returns as JSON object rather array
2023-04-13 21:09:37 +12:00
Jake Barnby 08be9c4c89 Update changelog 2023-04-13 16:35:42 +12:00
Jake Barnby 975b044de0 Iterate relation by reference on update 2023-04-13 16:08:53 +12:00
Jake Barnby c7317b0468 Fix auto-setting custom ID on nested documents 2023-04-13 15:59:57 +12:00
Christy Jacob 0fcfeb50a6 feat: update cli version 2023-04-13 01:48:44 +04:00
Christy Jacob 5d4e0762bb feat: update cli version 2023-04-13 01:33:25 +04:00
Christy Jacob f30d11ed60 feat: update cli version 2023-04-13 01:23:49 +04:00
Steven Nguyen bb2b48193f Ensure empty team prefs returns as JSON object rather array 2023-04-12 12:06:48 -07:00
Prasanth KotaandGitHub 0a1fcfc889 Update GETTING_STARTED.md 2023-04-13 00:13:20 +05:30
StevenandGitHub 8129bd9156 Update CONTRIBUTING.md to fix specs command
The CLI expects name=value for arguments rather than just positional.
2023-03-31 11:53:27 -07:00
Rinku Hasija f5c7568287 fix-models-attributeDatetime-object-example
Signed-off-by: Rinku Hasija <rishabhasija5454@gmail.com>
2023-03-25 17:32:46 +05:30
Bhaskar Singh 01840b3801 Reverting console change from main repo 2023-03-24 21:46:12 +05:30
Bhaskar SinghandGitHub 700f4f33ed Merge branch 'appwrite:master' into fix-4960-Database-usage-screen-shows-500-error-when_APP_USAGE_STATS-is-disabled 2023-03-24 21:33:42 +05:30
Bhaskar Singh 6324d78a0d Update the console app commit 2023-03-21 21:30:49 +05:30
Bhaskar Singh 5071172b00 Updating the console code 2023-03-21 21:26:22 +05:30
Bhaskar SinghandGitHub 39fb368c1d Merge branch 'appwrite:master' into fix-4960-Database-usage-screen-shows-500-error-when_APP_USAGE_STATS-is-disabled 2023-03-21 20:54:08 +05:30
Bhaskar Singh ac2085ffa8 Updated error when _APP_USAGE_STATS is disabled
for usage
2023-03-18 22:12:36 +05:30
Pranav2612000 c97a4868b1 fix: trigger account subscription event on email verification 2023-03-11 00:23:49 +05:30
Lucas Reis 2021dea936 set correct value for logging drivers
set correct value for logOwl and appSignal logging drivers
2023-02-26 19:31:56 +00:00
yatharth b5f02bd6c8 fix error description for duplicate user 2023-02-25 20:36:09 +05:30
Christy Jacob 1262a07729 chore: update changelog 2022-11-23 12:19:46 +05:30
Christy Jacob 0116be2e3d Merge branch 'master' of github.com:appwrite/appwrite into add-console-headers 2022-11-23 12:09:23 +05:30
Christy Jacob 6a6a90a24c fix: review comments 2022-11-23 02:51:00 +05:30
Christy Jacob 17b7af9199 fix: add headers to console 2022-11-23 02:44:38 +05:30
Matej Bačo 7c2fa12414 Fix getting function ID 2022-08-17 13:42:06 +00:00
Matej Bačo c93b7aa452 Fix event-triggered multi-execution 2022-08-17 13:34:52 +00:00
6005 changed files with 10012 additions and 6525 deletions
+3 -3
View File
@@ -6,7 +6,7 @@ on:
jobs:
tests:
name: Unit & E2E
name: Release
runs-on: ubuntu-latest
steps:
@@ -37,9 +37,9 @@ jobs:
with:
images: appwrite/appwrite
tags: |
type=semver,pattern={{major}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}.{{minor}}.{{patch}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
- name: Build and push
uses: docker/build-push-action@v4
+1
View File
@@ -13,3 +13,4 @@ debug/
app/sdks
dev/yasd_init.php
.phpunit.result.cache
Makefile
+1 -1
View File
@@ -1,4 +1,4 @@
[submodule "app/console"]
path = app/console
url = https://github.com/appwrite/console
branch = 2.3.3
branch = 2.3.4
+47 -2
View File
@@ -1,12 +1,56 @@
# Version 1.3.8
## Bugs
- Fix audit user internal [#5809](https://github.com/appwrite/appwrite/pull/5809)
# Version 1.3.7
## Bugs
- Fix the routing for the default OAuth2 pages [#5640](https://github.com/appwrite/appwrite/pull/5640) [#5648](https://github.com/appwrite/appwrite/pull/5648)
- Add support for trailing slashes in Routes and URLs [#5647](https://github.com/appwrite/appwrite/pull/5647) [#5648](https://github.com/appwrite/appwrite/pull/5648)
# Version 1.3.6
## Bugs
- Fix Console deep linking to result in a 404 [#5632](https://github.com/appwrite/appwrite/pull/5632)
- Fix ACME HTTP Challenge [#5632](https://github.com/appwrite/appwrite/pull/5632)
# Version 1.3.5
## Bugs
- Fix minimum length for string attribute default values [#5606](https://github.com/appwrite/appwrite/pull/5606), [#5602](https://github.com/appwrite/appwrite/pull/5602)
- Update framework to fix route mismatches [#5603](https://github.com/appwrite/appwrite/pull/5603)
# Version 1.3.4
## Bugs
- Update migration to properly migrate bucket permissions [#5497](https://github.com/appwrite/appwrite/pull/5497)
# Version 1.3.3
## Bugs
- Fixed migration resetting some data [#5455](https://github.com/appwrite/appwrite/pull/5455)
# Version 1.3.2
## Bugs
- Fixed auto-setting custom ID on nested documents [#5363](https://github.com/appwrite/appwrite/pull/5363)
- Fixed listDocuments not returning all the documents [#5395](https://github.com/appwrite/appwrite/pull/5395)
- Fixed deleting keys, webhooks, platforms and domains after deleting project [#5395](https://github.com/appwrite/appwrite/pull/5395)
- Fixed empty team prefs returning as JSON object rather array [#5361](https://github.com/appwrite/appwrite/pull/5361)
# Version 1.3.1
## Bugs
- Fixed Migration issue regarding 500 error [4906](https://github.com/appwrite/appwrite/pull/5356)
- Fixed Migration issue regarding 500 error [#5356](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 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)
@@ -57,6 +101,7 @@
## Changes
- Released `appwrite/console` [2.0.2](https://github.com/appwrite/console/releases/tag/2.0.2)
- Make `region` parameter optional with default for project create [#4763](https://github.com/appwrite/appwrite/pull/4763)
- Add security headers to the console endpoint [#4758](https://github.com/appwrite/appwrite/pull/4758)
## Bugs
- Fix default oauth paths [#4725](https://github.com/appwrite/appwrite/pull/4725)
+1 -1
View File
@@ -321,7 +321,7 @@ The Runtimes for all supported cloud functions (multicore builds) can be found a
The following steps are used to generate a new console SDK:
1. Update the console spec file located at `app/config/specs/swagger2-<version-number>.console.json` using Appwrite Tasks. Run the `php app/cli.php specs <version-number> normal` command in a running `appwrite/appwrite` container.
1. Update the console spec file located at `app/config/specs/swagger2-<version-number>.console.json` using Appwrite Tasks. Run the `php app/cli.php specs version=<version-number> mode=normal` command in a running `appwrite/appwrite` container.
2. Generate a new SDK using the command `php app/cli.php sdks`.
3. Change your working dir using `cd app/sdks/console-web`.
4. Build the new SDK `npm run build`.
+5 -6
View File
@@ -1,5 +1,4 @@
> 准备好迎接狂风暴'云'了吗? 🌩 ☂️
> Appwrite Cloud即将到来!你能够通过https://appwrite.io/cloud了解更多的资讯, 注册即可领取试用额度哦
> 好消息!Appwrite 云现已进入公开测试版!立即访问 cloud.appwrite.io 注册,体验无忧的托管服务。今天就加入我们的云端吧!☁️🎉
<br />
<p align="center">
@@ -24,7 +23,7 @@
[English](README.md) | 简体中文
[**宣布带有数据库关系的 Appwrite 1.3!了解最新消息!**](https://dev.to/appwrite/join-celebrations-appwrite-13-ships-relationships-57fc)
[**Appwrite 云公开测试版!立即注册!**](https://cloud.appwrite.io)
Appwrite是一个基于Docker的端到端开发者平台,其容器化的微服务库可应用于网页端,移动端,以及后端。Appwrite 通过视觉化界面简化了从零开始编写 API 的繁琐过程,在保证软件安全的前提下为开发者创造了一个高效的开发环境。
@@ -67,7 +66,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.3.1
appwrite/appwrite:1.3.8
```
### Windows
@@ -79,7 +78,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.3.1
appwrite/appwrite:1.3.8
```
#### PowerShell
@@ -89,7 +88,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.3.1
appwrite/appwrite:1.3.8
```
运行后,可以在浏览器上访问 http://localhost 找到 Appwrite 控制台。在非 Linux 的本机主机上完成安装后,服务器可能需要几分钟才能启动。
+13 -8
View File
@@ -1,12 +1,10 @@
> It's going to get cloudy! 🌩 ☂️
> The Appwrite Cloud is coming soon! You can learn more about our upcoming hosted solution and signup for free credits at: https://appwrite.io/cloud
> Great news! Appwrite Cloud is now in public beta! Sign up at [cloud.appwrite.io](https://cloud.appwrite.io) for a hassle-free, hosted experience. Join us in the Cloud today! ☁️🎉
<br />
<p align="center">
<a href="https://appwrite.io" target="_blank"><img width="260" height="39" src="https://appwrite.io/images/appwrite.svg" alt="Appwrite Logo"></a>
<br />
<br />
<b>A complete backend solution for your [Flutter / Vue / Angular / React / iOS / Android / *ANY OTHER*] app</b>
<b>Appwrite is a backend platform for developing Web, Mobile, and Flutter applications. Built with the open source community and optimized for developer experience in the coding languages you love.</b>
<br />
<br />
</p>
@@ -26,7 +24,7 @@
English | [简体中文](README-CN.md)
[**Announcing Appwrite 1.3 with Database Relationships! Learn what's new!**](https://dev.to/appwrite/join-celebrations-appwrite-13-ships-relationships-57fc)
[**Announcing Appwrite Cloud Public Beta! Sign up today!**](https://cloud.appwrite.io)
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.
@@ -51,6 +49,7 @@ Table of Contents:
- [CMD](#cmd)
- [PowerShell](#powershell)
- [Upgrade from an Older Version](#upgrade-from-an-older-version)
- [One-Click Setups](#one-click-setups)
- [Getting Started](#getting-started)
- [Services](#services)
- [SDKs](#sdks)
@@ -76,7 +75,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.3.1
appwrite/appwrite:1.3.8
```
### Windows
@@ -88,7 +87,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.3.1
appwrite/appwrite:1.3.8
```
#### PowerShell
@@ -98,7 +97,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.3.1
appwrite/appwrite:1.3.8
```
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.
@@ -129,6 +128,12 @@ Choose from one of the providers below:
<br /><sub><b>Gitpod</b></sub></a>
</a>
</td>
<td align="center" width="100" height="100">
<a href="https://www.linode.com/marketplace/apps/appwrite/appwrite/">
<img width="50" height="39" src="public/images/integrations/akamai-logo.svg" alt="Akamai Logo" />
<br /><sub><b>Akamai</b></sub></a>
</a>
</td>
</tr>
</table>
+11
View File
@@ -32,6 +32,17 @@ $collections = [
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('enabled'),
'type' => Database::VAR_BOOLEAN,
'signed' => true,
'size' => 0,
'format' => '',
'filters' => [],
'required' => false,
'default' => true,
'array' => false,
],
[
'$id' => ID::custom('search'),
'type' => Database::VAR_STRING,
+28 -3
View File
@@ -88,6 +88,11 @@ return [
'description' => 'The request cannot be fulfilled with the current protocol. Please check the value of the _APP_OPTIONS_FORCE_HTTPS environment variable.',
'code' => 500,
],
Exception::GENERAL_USAGE_DISABLED => [
'name' => Exception::GENERAL_USAGE_DISABLED,
'description' => 'Usage stats is not configured. Please check the value of the _APP_USAGE_STATS environment variable of your Appwrite server.',
'code' => 501,
],
/** User Errors */
Exception::USER_COUNT_EXCEEDED => [
@@ -102,12 +107,12 @@ return [
],
Exception::USER_ALREADY_EXISTS => [
'name' => Exception::USER_ALREADY_EXISTS,
'description' => 'A user with the same email already exists in your project.',
'description' => 'A user with the same id, email, or phone already exists in your project.',
'code' => 409,
],
Exception::USER_BLOCKED => [
'name' => Exception::USER_BLOCKED,
'description' => 'The current user has been blocked. You can unblock the user from the Appwrite console.',
'description' => 'The current user has been blocked.',
'code' => 401,
],
Exception::USER_INVALID_TOKEN => [
@@ -222,6 +227,11 @@ return [
'description' => 'The invite does not belong to the current user.',
'code' => 401,
],
Exception::TEAM_ALREADY_EXISTS => [
'name' => Exception::TEAM_ALREADY_EXISTS,
'description' => 'Team with requested ID already exists.',
'code' => 409,
],
/** Membership */
Exception::MEMBERSHIP_NOT_FOUND => [
@@ -313,6 +323,11 @@ return [
'description' => 'The requested range is not satisfiable. Please check the value of the Range header.',
'code' => 416,
],
Exception::STORAGE_INVALID_APPWRITE_ID => [
'name' => Exception::STORAGE_INVALID_APPWRITE_ID,
'description' => 'The value for x-appwrite-id header is invalid. Please check the value of the x-appwrite-id header is valid id and not unique().',
'code' => 400,
],
/** Functions */
Exception::FUNCTION_NOT_FOUND => [
@@ -398,9 +413,14 @@ return [
'description' => 'The document structure is invalid. Please ensure the attributes match the collection definition.',
'code' => 400,
],
Exception::DOCUMENT_MISSING_DATA => [
'name' => Exception::DOCUMENT_MISSING_DATA,
'description' => 'The document data is missing. You must provide the document data.',
'code' => 400,
],
Exception::DOCUMENT_MISSING_PAYLOAD => [
'name' => Exception::DOCUMENT_MISSING_PAYLOAD,
'description' => 'The document payload is missing.',
'description' => 'The document data and permissions are missing. You must provide either the document data or permissions to be updated.',
'code' => 400,
],
Exception::DOCUMENT_ALREADY_EXISTS => [
@@ -489,6 +509,11 @@ return [
'description' => 'Project with the requested ID could not be found. Please check the value of the X-Appwrite-Project header to ensure the correct project ID is being used.',
'code' => 404,
],
Exception::PROJECT_ALREADY_EXISTS => [
'name' => Exception::PROJECT_ALREADY_EXISTS,
'description' => 'Project with the requested ID already exists.',
'code' => 409,
],
Exception::PROJECT_UNKNOWN => [
'name' => Exception::PROJECT_UNKNOWN,
'description' => 'The project ID is either missing or not valid. Please check the value of the X-Appwrite-Project header to ensure the correct project ID is being used.',
+1 -1
View File
@@ -17,7 +17,7 @@
"emails.magicSession.signature": "Equipa {{project}}",
"emails.recovery.subject": "Redefinição de senha",
"emails.recovery.hello": "Olá {{name}}",
"emails.recovery.body": "tilize este link para redefinir a palavra-passe do seu projecto {{project}}",
"emails.recovery.body": "Utilize este link para redefinir a palavra-passe do seu projecto {{project}}",
"emails.recovery.footer": "Se não pediu para redefinir a sua palavra-passe, pode ignorar esta mensagem.",
"emails.recovery.thanks": "Obrigado",
"emails.recovery.signature": "Equipa {{project}}",
+23 -23
View File
@@ -28,7 +28,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-web.git',
'gitRepoName' => 'sdk-for-web',
'gitUserName' => 'appwrite',
'gitBranch' => 'master',
'gitBranch' => 'dev',
'demos' => [
[
'icon' => 'react.svg',
@@ -76,7 +76,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-flutter.git',
'gitRepoName' => 'sdk-for-flutter',
'gitUserName' => 'appwrite',
'gitBranch' => 'master',
'gitBranch' => 'dev',
],
[
'key' => 'apple',
@@ -94,7 +94,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-apple.git',
'gitRepoName' => 'sdk-for-apple',
'gitUserName' => 'appwrite',
'gitBranch' => 'master',
'gitBranch' => 'dev',
],
[
'key' => 'objective-c',
@@ -111,7 +111,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-objective-c.git',
'gitRepoName' => 'sdk-for-objective-c',
'gitUserName' => 'appwrite',
'gitBranch' => 'master',
'gitBranch' => 'dev',
],
[
'key' => 'android',
@@ -129,7 +129,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-android.git',
'gitRepoName' => 'sdk-for-android',
'gitUserName' => 'appwrite',
'gitBranch' => 'main',
'gitBranch' => 'dev',
'docDirectories' => [
'Kotlin' => 'kotlin',
'Java' => 'java',
@@ -196,14 +196,14 @@ return [
'prism' => 'javascript',
'source' => \realpath(__DIR__ . '/../sdks/console-web'),
'gitUrl' => 'git@github.com:appwrite/sdk-for-console.git',
'gitBranch' => 'main',
'gitBranch' => 'dev',
'gitRepoName' => 'sdk-for-console',
'gitUserName' => 'appwrite',
],
[
'key' => 'cli',
'name' => 'Command Line',
'version' => '2.0.0',
'version' => '2.0.2',
'url' => 'https://github.com/appwrite/sdk-for-cli',
'package' => 'https://www.npmjs.com/package/appwrite-cli',
'enabled' => true,
@@ -216,7 +216,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-cli.git',
'gitRepoName' => 'sdk-for-cli',
'gitUserName' => 'appwrite',
'gitBranch' => 'master',
'gitBranch' => 'dev',
],
],
],
@@ -244,7 +244,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-node.git',
'gitRepoName' => 'sdk-for-node',
'gitUserName' => 'appwrite',
'gitBranch' => 'master',
'gitBranch' => 'dev',
],
[
'key' => 'deno',
@@ -262,7 +262,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-deno.git',
'gitRepoName' => 'sdk-for-deno',
'gitUserName' => 'appwrite',
'gitBranch' => 'master',
'gitBranch' => 'dev',
],
[
'key' => 'php',
@@ -280,12 +280,12 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-php.git',
'gitRepoName' => 'sdk-for-php',
'gitUserName' => 'appwrite',
'gitBranch' => 'master',
'gitBranch' => 'dev',
],
[
'key' => 'python',
'name' => 'Python',
'version' => '2.0.0',
'version' => '2.0.2',
'url' => 'https://github.com/appwrite/sdk-for-python',
'package' => 'https://pypi.org/project/appwrite/',
'enabled' => true,
@@ -298,7 +298,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-python.git',
'gitRepoName' => 'sdk-for-python',
'gitUserName' => 'appwrite',
'gitBranch' => 'master',
'gitBranch' => 'dev',
],
[
'key' => 'ruby',
@@ -316,7 +316,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-ruby.git',
'gitRepoName' => 'sdk-for-ruby',
'gitUserName' => 'appwrite',
'gitBranch' => 'master',
'gitBranch' => 'dev',
],
[
'key' => 'go',
@@ -334,7 +334,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-go.git',
'gitRepoName' => 'sdk-for-go',
'gitUserName' => 'appwrite',
'gitBranch' => 'master',
'gitBranch' => 'dev',
],
[
'key' => 'java',
@@ -352,17 +352,17 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-java.git',
'gitRepoName' => 'sdk-for-java',
'gitUserName' => 'appwrite',
'gitBranch' => 'master',
'gitBranch' => 'dev',
],
[
'key' => 'dotnet',
'name' => '.NET',
'version' => '2.0.0',
'version' => '0.4.2',
'url' => 'https://github.com/appwrite/sdk-for-dotnet',
'package' => 'https://www.nuget.org/packages/Appwrite',
'enabled' => false,
'enabled' => true,
'beta' => true,
'dev' => true,
'dev' => false,
'hidden' => false,
'family' => APP_PLATFORM_SERVER,
'prism' => 'csharp',
@@ -370,7 +370,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-dotnet.git',
'gitRepoName' => 'sdk-for-dotnet',
'gitUserName' => 'appwrite',
'gitBranch' => 'main',
'gitBranch' => 'dev',
],
[
'key' => 'dart',
@@ -388,7 +388,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-dart.git',
'gitRepoName' => 'sdk-for-dart',
'gitUserName' => 'appwrite',
'gitBranch' => 'master',
'gitBranch' => 'dev',
],
[
'key' => 'kotlin',
@@ -406,7 +406,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-kotlin.git',
'gitRepoName' => 'sdk-for-kotlin',
'gitUserName' => 'appwrite',
'gitBranch' => 'main',
'gitBranch' => 'dev',
'docDirectories' => [
'Kotlin' => 'kotlin',
'Java' => 'java',
@@ -428,7 +428,7 @@ return [
'gitUrl' => 'git@github.com:appwrite/sdk-for-swift.git',
'gitRepoName' => 'sdk-for-swift',
'gitUserName' => 'appwrite',
'gitBranch' => 'main',
'gitBranch' => 'dev',
],
[
'key' => 'graphql',
+12 -2
View File
@@ -201,6 +201,16 @@ return [ // Ordered by ABC.
'beta' => false,
'mock' => false,
],
'oidc' => [
'name' => 'OpenID Connect',
'developers' => 'https://openid.net/connect/faq/',
'icon' => 'icon-oidc',
'enabled' => true,
'sandbox' => false,
'form' => 'oidc.phtml',
'beta' => false,
'mock' => false,
],
'okta' => [
'name' => 'Okta',
'developers' => 'https://developer.okta.com/',
@@ -222,7 +232,7 @@ return [ // Ordered by ABC.
'mock' => false
],
'paypalSandbox' => [
'name' => 'PayPal',
'name' => 'PayPal Sandbox',
'developers' => 'https://developer.paypal.com/docs/api/overview/',
'icon' => 'icon-paypal',
'enabled' => true,
@@ -292,7 +302,7 @@ return [ // Ordered by ABC.
'mock' => false,
],
'tradeshiftBox' => [
'name' => 'Tradeshift',
'name' => 'Tradeshift Sandbox',
'developers' => 'https://developers.tradeshift.com/docs/api',
'icon' => 'icon-tradeshiftbox',
'enabled' => true,
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
@@ -152,7 +152,7 @@ return [
],
[
'name' => '_APP_LOGGING_PROVIDER',
'description' => 'This variable allows you to enable logging errors to 3rd party providers. This value is empty by default, to enable the logger set the value to one of \'sentry\', \'raygun\', \'appsignal\', \'logowl\'',
'description' => 'This variable allows you to enable logging errors to 3rd party providers. This value is empty by default, to enable the logger set the value to one of \'sentry\', \'raygun\', \'appSignal\', \'logOwl\'',
'introduction' => '0.12.0',
'default' => '',
'required' => false,
+20 -12
View File
@@ -549,7 +549,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
$detector = new Detector($request->getUserAgent('UNKNOWN'));
$record = $geodb->get($request->getIP());
$secret = Auth::tokenGenerator();
$expire = DateTime::addSeconds(new \DateTime(), $duration);
$expire = DateTime::formatTz(DateTime::addSeconds(new \DateTime(), $duration));
$session = new Document(array_merge([
'$id' => ID::unique(),
@@ -701,7 +701,7 @@ App::post('/v1/account/sessions/magic-url')
}
$loginSecret = Auth::tokenGenerator();
$expire = DateTime::addSeconds(new \DateTime(), Auth::TOKEN_EXPIRATION_CONFIRM);
$expire = DateTime::formatTz(DateTime::addSeconds(new \DateTime(), Auth::TOKEN_EXPIRATION_CONFIRM));
$token = new Document([
'$id' => ID::unique(),
@@ -827,7 +827,7 @@ App::put('/v1/account/sessions/magic-url')
$detector = new Detector($request->getUserAgent('UNKNOWN'));
$record = $geodb->get($request->getIP());
$secret = Auth::tokenGenerator();
$expire = DateTime::addSeconds(new \DateTime(), $duration);
$expire = DateTime::formatTz(DateTime::addSeconds(new \DateTime(), $duration));
$session = new Document(array_merge(
[
@@ -976,7 +976,7 @@ App::post('/v1/account/sessions/phone')
}
$secret = Auth::codeGenerator();
$expire = DateTime::addSeconds(new \DateTime(), Auth::TOKEN_EXPIRATION_PHONE);
$expire = DateTime::formatTz(DateTime::addSeconds(new \DateTime(), Auth::TOKEN_EXPIRATION_PHONE));
$token = new Document([
'$id' => ID::unique(),
@@ -1064,7 +1064,7 @@ App::put('/v1/account/sessions/phone')
$detector = new Detector($request->getUserAgent('UNKNOWN'));
$record = $geodb->get($request->getIP());
$secret = Auth::tokenGenerator();
$expire = DateTime::addSeconds(new \DateTime(), $duration);
$expire = DateTime::formatTz(DateTime::addSeconds(new \DateTime(), $duration));
$session = new Document(array_merge(
[
@@ -1216,7 +1216,7 @@ App::post('/v1/account/sessions/anonymous')
$detector = new Detector($request->getUserAgent('UNKNOWN'));
$record = $geodb->get($request->getIP());
$secret = Auth::tokenGenerator();
$expire = DateTime::addSeconds(new \DateTime(), $duration);
$expire = DateTime::formatTz(DateTime::addSeconds(new \DateTime(), $duration));
$session = new Document(array_merge(
[
@@ -1389,6 +1389,7 @@ App::get('/v1/account/sessions')
$session->setAttribute('countryName', $countryName);
$session->setAttribute('current', ($current == $session->getId()) ? true : false);
$session->setAttribute('expire', DateTime::formatTz(DateTime::addSeconds(new \DateTime($session->getCreatedAt()), $authDuration)));
$sessions[$key] = $session;
}
@@ -1426,7 +1427,7 @@ App::get('/v1/account/logs')
$audit = new EventAudit($dbForProject);
$logs = $audit->getLogsByUser($user->getId(), $limit, $offset);
$logs = $audit->getLogsByUser($user->getInternalId(), $limit, $offset);
$output = [];
@@ -1495,7 +1496,7 @@ App::get('/v1/account/sessions/:sessionId')
$session
->setAttribute('current', ($session->getAttribute('secret') == Auth::hash(Auth::$secret)))
->setAttribute('countryName', $countryName)
->setAttribute('expire', DateTime::addSeconds(new \DateTime($session->getCreatedAt()), $authDuration))
->setAttribute('expire', DateTime::formatTz(DateTime::addSeconds(new \DateTime($session->getCreatedAt()), $authDuration)))
;
return $response->dynamic($session, Response::MODEL_SESSION);
@@ -1763,11 +1764,12 @@ App::patch('/v1/account/status')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_USER)
->inject('requestTimestamp')
->inject('request')
->inject('response')
->inject('user')
->inject('dbForProject')
->inject('events')
->action(function (?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $events) {
->action(function (?\DateTime $requestTimestamp, Request $request, Response $response, Document $user, Database $dbForProject, Event $events) {
$user->setAttribute('status', false);
@@ -1781,6 +1783,12 @@ App::patch('/v1/account/status')
$response->addHeader('X-Fallback-Cookies', \json_encode([]));
}
$protocol = $request->getProtocol();
$response
->addCookie(Auth::$cookieName . '_legacy', '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null)
->addCookie(Auth::$cookieName, '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite'))
;
$response->dynamic($user, Response::MODEL_ACCOUNT);
});
@@ -1932,7 +1940,7 @@ App::patch('/v1/account/sessions/:sessionId')
$authDuration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG;
$session->setAttribute('expire', DateTime::addSeconds(new \DateTime($session->getCreatedAt()), $authDuration));
$session->setAttribute('expire', DateTime::formatTz(DateTime::addSeconds(new \DateTime($session->getCreatedAt()), $authDuration)));
$events
->setParam('userId', $user->getId())
@@ -2299,7 +2307,7 @@ App::post('/v1/account/verification')
->setBody($body)
->setFrom($from)
->setRecipient($user->getAttribute('email'))
->setName($user->getAttribute('name'))
->setName($user->getAttribute('name') ?? '')
->trigger()
;
@@ -2373,7 +2381,7 @@ App::put('/v1/account/verification')
$dbForProject->deleteCachedDocument('users', $profile->getId());
$events
->setParam('userId', $user->getId())
->setParam('userId', $userId)
->setParam('tokenId', $verificationDocument->getId())
;
+177 -175
View File
@@ -327,22 +327,22 @@ function updateAttribute(
}
if ($type === Database::VAR_RELATIONSHIP) {
$options = \array_merge($attribute->getAttribute('options', []), $options);
$attribute->setAttribute('options', $options);
$primaryDocumentOptions = \array_merge($attribute->getAttribute('options', []), $options);
$attribute->setAttribute('options', $primaryDocumentOptions);
$dbForProject->updateRelationship(
collection: $collectionId,
id: $key,
onDelete: $options['onDelete'],
onDelete: $primaryDocumentOptions['onDelete'],
);
if ($options['twoWay']) {
$relatedCollection = $dbForProject->getDocument('database_' . $db->getInternalId(), $options['relatedCollection']);
$relatedAttribute = $dbForProject->getDocument('attributes', $db->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $options['twoWayKey']);
if ($primaryDocumentOptions['twoWay']) {
$relatedCollection = $dbForProject->getDocument('database_' . $db->getInternalId(), $primaryDocumentOptions['relatedCollection']);
$relatedAttribute = $dbForProject->getDocument('attributes', $db->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $primaryDocumentOptions['twoWayKey']);
$relatedOptions = \array_merge($relatedAttribute->getAttribute('options'), $options);
$relatedAttribute->setAttribute('options', $relatedOptions);
$dbForProject->updateDocument('attributes', $db->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $options['twoWayKey'], $relatedAttribute);
$dbForProject->updateDocument('attributes', $db->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $primaryDocumentOptions['twoWayKey'], $relatedAttribute);
$dbForProject->deleteCachedDocument('database_' . $db->getInternalId(), $relatedCollection->getId());
}
} else {
@@ -384,11 +384,12 @@ App::post('/v1/databases')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_DATABASE) // Model for database needs to be created
->param('databaseId', '', 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('name', '', new Text(128), 'Collection name. Max length: 128 chars.')
->param('name', '', new Text(128), 'Database name. Max length: 128 chars.')
->param('enabled', true, new Boolean(), 'Is database enabled?', true)
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $databaseId, string $name, Response $response, Database $dbForProject, Event $events) {
->action(function (string $databaseId, string $name, bool $enabled, Response $response, Database $dbForProject, Event $events) {
$databaseId = $databaseId == 'unique()' ? ID::unique() : $databaseId;
@@ -396,6 +397,7 @@ App::post('/v1/databases')
$dbForProject->createDocument('databases', new Document([
'$id' => $databaseId,
'name' => $name,
'enabled' => $enabled,
'search' => implode(' ', [$databaseId, $name]),
]));
$database = $dbForProject->getDocument('databases', $databaseId);
@@ -507,7 +509,7 @@ App::get('/v1/databases/:databaseId')
->inject('dbForProject')
->action(function (string $databaseId, Response $response, Database $dbForProject) {
$database = $dbForProject->getDocument('databases', $databaseId);
$database = $dbForProject->getDocument('databases', $databaseId);
if ($database->isEmpty()) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
@@ -564,7 +566,7 @@ App::get('/v1/databases/:databaseId/logs')
$output[$i] = new Document([
'event' => $log['event'],
'userId' => ID::custom($log['userId']),
'userId' => ID::custom($log['data']['userId']),
'userEmail' => $log['data']['userEmail'] ?? null,
'userName' => $log['data']['userName'] ?? null,
'mode' => $log['data']['mode'] ?? null,
@@ -619,12 +621,13 @@ App::put('/v1/databases/:databaseId')
->label('sdk.response.model', Response::MODEL_DATABASE)
->param('databaseId', '', new UID(), 'Database ID.')
->param('name', null, new Text(128), 'Database name. Max length: 128 chars.')
->param('enabled', true, new Boolean(), 'Is database enabled?', true)
->inject('response')
->inject('dbForProject')
->inject('events')
->action(function (string $databaseId, string $name, Response $response, Database $dbForProject, Event $events) {
->action(function (string $databaseId, string $name, bool $enabled, Response $response, Database $dbForProject, Event $events) {
$database = $dbForProject->getDocument('databases', $databaseId);
$database = $dbForProject->getDocument('databases', $databaseId);
if ($database->isEmpty()) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
@@ -633,6 +636,7 @@ App::put('/v1/databases/:databaseId')
try {
$database = $dbForProject->updateDocument('databases', $databaseId, $database
->setAttribute('name', $name)
->setAttribute('enabled', $enabled)
->setAttribute('search', implode(' ', [$databaseId, $name])));
} catch (AuthorizationException $exception) {
throw new Exception(Exception::USER_UNAUTHORIZED);
@@ -714,14 +718,16 @@ App::post('/v1/databases/:databaseId/collections')
->param('name', '', new Text(128), 'Collection name. Max length: 128 chars.')
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](/docs/permissions).', true)
->param('documentSecurity', false, new Boolean(true), 'Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](/docs/permissions).', true)
->param('enabled', true, new Boolean(), 'Is collection enabled?', true)
->inject('response')
->inject('dbForProject')
->inject('mode')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, Response $response, Database $dbForProject, Event $events) {
->action(function (string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, bool $enabled, Response $response, Database $dbForProject, string $mode, Event $events) {
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
if ($database->isEmpty()) {
if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
}
@@ -737,13 +743,13 @@ App::post('/v1/databases/:databaseId/collections')
'databaseId' => $databaseId,
'$permissions' => $permissions ?? [],
'documentSecurity' => $documentSecurity,
'enabled' => true,
'enabled' => $enabled,
'name' => $name,
'search' => implode(' ', [$collectionId, $name]),
]));
$collection = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId);
$dbForProject->createCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId());
$dbForProject->createCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), permissions: $permissions ?? [], documentSecurity: $documentSecurity);
} catch (DuplicateException) {
throw new Exception(Exception::COLLECTION_ALREADY_EXISTS);
} catch (LimitException) {
@@ -779,11 +785,12 @@ App::get('/v1/databases/:databaseId/collections')
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('response')
->inject('dbForProject')
->action(function (string $databaseId, array $queries, string $search, Response $response, Database $dbForProject) {
->inject('mode')
->action(function (string $databaseId, array $queries, string $search, Response $response, Database $dbForProject, string $mode) {
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
if ($database->isEmpty()) {
if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
}
@@ -834,11 +841,12 @@ App::get('/v1/databases/:databaseId/collections/:collectionId')
->param('collectionId', '', new UID(), 'Collection ID.')
->inject('response')
->inject('dbForProject')
->action(function (string $databaseId, string $collectionId, Response $response, Database $dbForProject) {
->inject('mode')
->action(function (string $databaseId, string $collectionId, Response $response, Database $dbForProject, string $mode) {
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
if ($database->isEmpty()) {
if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
}
@@ -874,7 +882,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/logs')
->inject('geodb')
->action(function (string $databaseId, string $collectionId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
if ($database->isEmpty()) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
@@ -909,7 +917,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/logs')
$output[$i] = new Document([
'event' => $log['event'],
'userId' => $log['userId'],
'userId' => $log['data']['userId'],
'userEmail' => $log['data']['userEmail'] ?? null,
'userName' => $log['data']['userName'] ?? null,
'mode' => $log['data']['mode'] ?? null,
@@ -972,12 +980,13 @@ App::put('/v1/databases/:databaseId/collections/:collectionId')
->param('enabled', true, new Boolean(), 'Is collection enabled?', true)
->inject('response')
->inject('dbForProject')
->inject('mode')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, bool $enabled, Response $response, Database $dbForProject, Event $events) {
->action(function (string $databaseId, string $collectionId, string $name, ?array $permissions, bool $documentSecurity, bool $enabled, Response $response, Database $dbForProject, string $mode, Event $events) {
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
if ($database->isEmpty()) {
if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
}
@@ -1001,6 +1010,7 @@ App::put('/v1/databases/:databaseId/collections/:collectionId')
->setAttribute('documentSecurity', $documentSecurity)
->setAttribute('enabled', $enabled)
->setAttribute('search', implode(' ', [$collectionId, $name])));
$dbForProject->updateCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $permissions, $documentSecurity);
} catch (AuthorizationException) {
throw new Exception(Exception::USER_UNAUTHORIZED);
} catch (StructureException $exception) {
@@ -1035,13 +1045,14 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId')
->param('collectionId', '', new UID(), 'Collection ID.')
->inject('response')
->inject('dbForProject')
->inject('mode')
->inject('events')
->inject('deletes')
->action(function (string $databaseId, string $collectionId, Response $response, Database $dbForProject, Event $events, Delete $deletes) {
->action(function (string $databaseId, string $collectionId, Response $response, Database $dbForProject, string $mode, Event $events, Delete $deletes) {
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
if ($database->isEmpty()) {
if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
}
@@ -1059,15 +1070,13 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId')
$deletes
->setType(DELETE_TYPE_DOCUMENT)
->setDocument($collection)
;
->setDocument($collection);
$events
->setContext('database', $database)
->setParam('databaseId', $databaseId)
->setParam('collectionId', $collection->getId())
->setPayload($response->output($collection, Response::MODEL_COLLECTION))
;
->setPayload($response->output($collection, Response::MODEL_COLLECTION));
$response->noContent();
});
@@ -1094,7 +1103,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string
->param('key', '', new Key(), 'Attribute Key.')
->param('size', null, new Range(1, APP_DATABASE_ATTRIBUTE_STRING_MAX_LENGTH, Range::TYPE_INTEGER), 'Attribute size for text attributes, in number of characters.')
->param('required', null, new Boolean(), 'Is attribute required?')
->param('default', null, new Text(0), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true)
->param('default', null, new Text(0, 0), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true)
->param('array', false, new Boolean(), 'Is attribute an array?', true)
->inject('response')
->inject('dbForProject')
@@ -1103,7 +1112,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string
->action(function (string $databaseId, string $collectionId, string $key, ?int $size, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) {
// Ensure attribute default is within required size
$validator = new Text($size);
$validator = new Text($size, 0);
if (!is_null($default) && !$validator->isValid($default)) {
throw new Exception(Exception::ATTRIBUTE_VALUE_INVALID, $validator->getDescription());
}
@@ -1592,7 +1601,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/relati
Database $dbForProject,
EventDatabase $database,
Event $events
) {
) {
$key ??= $relatedCollectionId;
$twoWayKey ??= $collectionId;
@@ -1652,7 +1661,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes')
->inject('dbForProject')
->action(function (string $databaseId, string $collectionId, Response $response, Database $dbForProject) {
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
if ($database->isEmpty()) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
@@ -1703,7 +1712,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes/:key')
->inject('dbForProject')
->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject) {
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
if ($database->isEmpty()) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
@@ -1768,7 +1777,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/strin
->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).')
->param('key', '', new Key(), 'Attribute Key.')
->param('required', null, new Boolean(), 'Is attribute required?')
->param('default', null, new Nullable(new Text(0)), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
->param('default', null, new Nullable(new Text(0, 0)), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
->inject('response')
->inject('dbForProject')
->inject('events')
@@ -2176,7 +2185,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/:key/
$events,
type: Database::VAR_RELATIONSHIP,
required: false,
options : [
options: [
'onDelete' => $onDelete
]
);
@@ -2217,7 +2226,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject, EventDatabase $database, Event $events) {
$db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
$db = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
if ($db->isEmpty()) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
@@ -2270,8 +2279,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key
->setType(DATABASE_TYPE_DELETE_ATTRIBUTE)
->setCollection($collection)
->setDatabase($db)
->setDocument($attribute)
;
->setDocument($attribute);
// Select response model based on type and format
$type = $attribute->getAttribute('type');
@@ -2299,8 +2307,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key
->setParam('attributeId', $attribute->getId())
->setContext('collection', $collection)
->setContext('database', $db)
->setPayload($response->output($attribute, $model))
;
->setPayload($response->output($attribute, $model));
$response->noContent();
});
@@ -2334,7 +2341,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, string $type, array $attributes, array $orders, Response $response, Database $dbForProject, EventDatabase $database, Event $events) {
$db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
$db = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
if ($db->isEmpty()) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
@@ -2357,7 +2364,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes')
}
// Convert Document[] to array of attribute metadata
$oldAttributes = \array_map(fn ($a) => $a->getArrayCopy(), $collection->getAttribute('attributes'));
$oldAttributes = \array_map(fn($a) => $a->getArrayCopy(), $collection->getAttribute('attributes'));
$oldAttributes[] = [
'key' => '$id',
@@ -2443,16 +2450,14 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes')
->setType(DATABASE_TYPE_CREATE_INDEX)
->setDatabase($db)
->setCollection($collection)
->setDocument($index)
;
->setDocument($index);
$events
->setParam('databaseId', $databaseId)
->setParam('collectionId', $collection->getId())
->setParam('indexId', $index->getId())
->setContext('collection', $collection)
->setContext('database', $db)
;
->setContext('database', $db);
$response
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
@@ -2479,7 +2484,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes')
->inject('dbForProject')
->action(function (string $databaseId, string $collectionId, Response $response, Database $dbForProject) {
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
if ($database->isEmpty()) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
@@ -2519,7 +2524,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes/:key')
->inject('dbForProject')
->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject) {
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
if ($database->isEmpty()) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
@@ -2530,21 +2535,15 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/indexes/:key')
throw new Exception(Exception::COLLECTION_NOT_FOUND);
}
$indexes = $collection->getAttribute('indexes');
// Search for index
$indexIndex = array_search($key, array_map(fn($idx) => $idx['key'], $indexes));
if ($indexIndex === false) {
$index = $collection->find('key', $key, 'indexes');
if (empty($index)) {
throw new Exception(Exception::INDEX_NOT_FOUND);
}
$index = $indexes[$indexIndex];
$index->setAttribute('collectionId', $database->getInternalId() . '_' . $collectionId);
$response->dynamic($index, Response::MODEL_INDEX);
});
App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key')
->alias('/v1/database/collections/:collectionId/indexes/:key', ['databaseId' => 'default'])
->desc('Delete Index')
@@ -2570,7 +2569,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key')
->inject('events')
->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject, EventDatabase $database, Event $events) {
$db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
$db = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
if ($db->isEmpty()) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
@@ -2598,8 +2597,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key')
->setType(DATABASE_TYPE_DELETE_INDEX)
->setDatabase($db)
->setCollection($collection)
->setDocument($index)
;
->setDocument($index);
$events
->setParam('databaseId', $databaseId)
@@ -2607,8 +2605,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/indexes/:key')
->setParam('indexId', $index->getId())
->setContext('collection', $collection)
->setContext('database', $db)
->setPayload($response->output($index, Response::MODEL_INDEX))
;
->setPayload($response->output($index, Response::MODEL_INDEX));
$response->noContent();
});
@@ -2620,7 +2617,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
->label('event', 'databases.[databaseId].collections.[collectionId].documents.[documentId].create')
->label('scope', 'documents.write')
->label('audits.event', 'document.create')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}/document/{response.$id}')
->label('usage.metric', 'documents.{scope}.requests.create')
->label('usage.params', ['databaseId:{request.databaseId}', 'collectionId:{request.collectionId}'])
->label('abuse-key', 'ip:{ip},method:{method},url:{url},userId:{userId}')
@@ -2650,7 +2647,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
$data = (\is_string($data)) ? \json_decode($data, true) : $data; // Cast to JSON array
if (empty($data)) {
throw new Exception(Exception::DOCUMENT_MISSING_PAYLOAD);
throw new Exception(Exception::DOCUMENT_MISSING_DATA);
}
if (isset($data['$id'])) {
@@ -2659,7 +2656,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
if ($database->isEmpty()) {
if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
}
@@ -2734,7 +2731,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
$relationships = \array_filter(
$collection->getAttribute('attributes', []),
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
);
foreach ($relationships as $relationship) {
@@ -2743,8 +2740,13 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
if (empty($related)) {
continue;
}
if (!\is_array($related)) {
$related = [$related];
$isList = \is_array($related) && \array_values($related) === $related;
if ($isList) {
$relations = $related;
} else {
$relations = [$related];
}
$relatedCollectionId = $relationship->getAttribute('relatedCollection');
@@ -2752,7 +2754,15 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId)
);
foreach ($related as $relation) {
foreach ($relations as &$relation) {
if (
\is_array($relation)
&& \array_values($relation) !== $relation
&& !isset($relation['$id'])
) {
$relation['$id'] = ID::unique();
$relation = new Document($relation);
}
if ($relation instanceof Document) {
$current = Authorization::skip(
fn() => $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId(), $relation->getId())
@@ -2761,7 +2771,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
if ($current->isEmpty()) {
$type = Database::PERMISSION_CREATE;
if (!isset($relation['$id']) || $relation['$id'] === 'unique()') {
if (isset($relation['$id']) && $relation['$id'] === 'unique()') {
$relation['$id'] = ID::unique();
}
} else {
@@ -2774,6 +2784,12 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
$checkPermissions($relatedCollection, $relation, $type);
}
}
if ($isList) {
$document->setAttribute($relationship->getAttribute('key'), \array_values($relations));
} else {
$document->setAttribute($relationship->getAttribute('key'), \reset($relations));
}
}
};
@@ -2794,7 +2810,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
$relationships = \array_filter(
$collection->getAttribute('attributes', []),
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
);
foreach ($relationships as $relationship) {
@@ -2827,8 +2843,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
->setParam('collectionId', $collection->getId())
->setParam('documentId', $document->getId())
->setContext('collection', $collection)
->setContext('database', $database)
;
->setContext('database', $database);
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
@@ -2858,20 +2873,27 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
->inject('mode')
->action(function (string $databaseId, string $collectionId, array $queries, Response $response, Database $dbForProject, string $mode) {
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
if ($database->isEmpty()) {
if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
}
$collection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId));
if ($collection->isEmpty() || !$collection->getAttribute('enabled')) {
if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) {
throw new Exception(Exception::COLLECTION_NOT_FOUND);
if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) {
if (!$collection->getAttribute('documentSecurity', false)) {
$validator = new Authorization(Database::PERMISSION_READ);
if (!$validator->isValid($collection->getRead())) {
$collection = new Document();
}
}
}
if ($collection->isEmpty() || !$collection->getAttribute('enabled')) {
throw new Exception(Exception::COLLECTION_NOT_FOUND);
}
// Validate queries
$queriesValidator = new Documents($collection->getAttribute('attributes'), $collection->getAttribute('indexes'));
$validQueries = $queriesValidator->isValid($queries);
@@ -2898,40 +2920,22 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
$filterQueries = Query::groupByType($queries)['filters'];
$documents = Authorization::skip(fn () => $dbForProject->find('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $queries));
$documentSecurity = $collection->getAttribute('documentSecurity', false);
$validator = new Authorization(Database::PERMISSION_READ);
$valid = $validator->isValid($collection->getRead());
if (!$valid) {
$total = $documentSecurity
? $dbForProject->count('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $filterQueries, APP_LIMIT_COUNT)
: 0;
} else {
$total = Authorization::skip(fn() => $dbForProject->count('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $filterQueries, APP_LIMIT_COUNT));
}
$documents = $dbForProject->find('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $queries);
$total = $dbForProject->count('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $filterQueries, APP_LIMIT_COUNT);
// Add $collectionId and $databaseId for all documents
$processDocument = function (Document $collection, Document $document) use (&$processDocument, $dbForProject, $database): bool {
$documentSecurity = $collection->getAttribute('documentSecurity', false);
$validator = new Authorization(Database::PERMISSION_READ);
$valid = $validator->isValid($collection->getRead());
if (!$documentSecurity && !$valid) {
return false;
}
$valid = $valid || $validator->isValid($document->getRead());
if ($documentSecurity && !$valid) {
if ($document->isEmpty()) {
return false;
}
$document->removeAttribute('$collection');
$document->setAttribute('$databaseId', $database->getId());
$document->setAttribute('$collectionId', $collection->getId());
$relationships = \array_filter(
$collection->getAttribute('attributes', []),
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
);
foreach ($relationships as $relationship) {
@@ -2947,8 +2951,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
}
$relatedCollectionId = $relationship->getAttribute('relatedCollection');
$relatedCollection = Authorization::skip(fn() =>
$dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId));
$relatedCollection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId));
foreach ($relations as $index => $doc) {
if ($doc instanceof Document) {
@@ -2968,19 +2971,11 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
return true;
};
// The linter is forcing this indentation
foreach ($documents as $index => $document) {
if (!$processDocument($collection, $document)) {
unset($documents[$index]);
if ($valid) {
$total--;
}
}
// The linter is forcing this indentation
foreach ($documents as $document) {
$processDocument($collection, $document);
}
$documents = \array_values($documents);
$response->dynamic(new Document([
'total' => $total,
'documents' => $documents,
@@ -3012,9 +3007,9 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen
->inject('mode')
->action(function (string $databaseId, string $collectionId, string $documentId, array $queries, Response $response, Database $dbForProject, string $mode) {
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
if ($database->isEmpty()) {
if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
}
@@ -3035,7 +3030,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen
$queries = Query::parseQueries($queries);
$document = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId, $queries));
$document = $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId, $queries);
if ($document->isEmpty()) {
throw new Exception(Exception::DOCUMENT_NOT_FOUND);
@@ -3043,17 +3038,8 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen
// Add $collectionId and $databaseId for all documents
$processDocument = function (Document $collection, Document $document) use (&$processDocument, $dbForProject, $database) {
$documentSecurity = $collection->getAttribute('documentSecurity', false);
$validator = new Authorization(Database::PERMISSION_READ);
$valid = $validator->isValid($collection->getRead());
if (!$documentSecurity && !$valid) {
throw new Exception(Exception::DOCUMENT_NOT_FOUND);
}
$valid = $valid || $validator->isValid($document->getRead());
if ($documentSecurity && !$valid) {
throw new Exception(Exception::DOCUMENT_NOT_FOUND);
if ($document->isEmpty()) {
return;
}
$document->setAttribute('$databaseId', $database->getId());
@@ -3061,7 +3047,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen
$relationships = \array_filter(
$collection->getAttribute('attributes', []),
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
);
foreach ($relationships as $relationship) {
@@ -3116,7 +3102,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen
->inject('geodb')
->action(function (string $databaseId, string $collectionId, string $documentId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) {
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
if ($database->isEmpty()) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
@@ -3157,7 +3143,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen
$output[$i] = new Document([
'event' => $log['event'],
'userId' => $log['userId'],
'userId' => $log['data']['userId'],
'userEmail' => $log['data']['userEmail'] ?? null,
'userName' => $log['data']['userName'] ?? null,
'mode' => $log['data']['mode'] ?? null,
@@ -3233,9 +3219,9 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
throw new Exception(Exception::DOCUMENT_MISSING_PAYLOAD);
}
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
if ($database->isEmpty()) {
if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
}
@@ -3287,7 +3273,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
$permissions = $document->getPermissions() ?? [];
}
$data = \array_merge($document->getArrayCopy(), $data);
$data = \array_merge($document->getArrayCopy(), $data); // Merge existing data with new data
$data['$collection'] = $collection->getId(); // Make sure user doesn't switch collectionID
$data['$createdAt'] = $document->getCreatedAt(); // Make sure user doesn't switch createdAt
$data['$id'] = $document->getId(); // Make sure user doesn't switch document unique ID
@@ -3312,7 +3298,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
$relationships = \array_filter(
$collection->getAttribute('attributes', []),
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
);
foreach ($relationships as $relationship) {
@@ -3321,8 +3307,13 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
if (empty($related)) {
continue;
}
if (!\is_array($related)) {
$related = [$related];
$isList = \is_array($related) && \array_values($related) === $related;
if ($isList) {
$relations = $related;
} else {
$relations = [$related];
}
$relatedCollectionId = $relationship->getAttribute('relatedCollection');
@@ -3330,7 +3321,15 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId)
);
foreach ($related as $relation) {
foreach ($relations as &$relation) {
if (
\is_array($relation)
&& \array_values($relation) !== $relation
&& !isset($relation['$id'])
) {
$relation['$id'] = ID::unique();
$relation = new Document($relation);
}
if ($relation instanceof Document) {
$oldDocument = Authorization::skip(fn() => $dbForProject->getDocument(
'database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId(),
@@ -3340,7 +3339,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
if ($oldDocument->isEmpty()) {
$type = Database::PERMISSION_CREATE;
if (!isset($relation['$id']) || $relation['$id'] === 'unique()') {
if (isset($relation['$id']) && $relation['$id'] === 'unique()') {
$relation['$id'] = ID::unique();
}
} else {
@@ -3353,20 +3352,26 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
$checkPermissions($relatedCollection, $relation, $oldDocument, $type);
}
}
if ($isList) {
$document->setAttribute($relationship->getAttribute('key'), \array_values($relations));
} else {
$document->setAttribute($relationship->getAttribute('key'), \reset($relations));
}
}
};
$checkPermissions($collection, $newDocument, $document, Database::PERMISSION_UPDATE);
try {
$document = Authorization::skip(fn() => $dbForProject->withRequestTimestamp(
$document = $dbForProject->withRequestTimestamp(
$requestTimestamp,
fn () => $dbForProject->updateDocument(
fn() => $dbForProject->updateDocument(
'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(),
$document->getId(),
$newDocument
)
));
);
} catch (AuthorizationException) {
throw new Exception(Exception::USER_UNAUTHORIZED);
} catch (DuplicateException) {
@@ -3382,7 +3387,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
$relationships = \array_filter(
$collection->getAttribute('attributes', []),
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
);
foreach ($relationships as $relationship) {
@@ -3415,8 +3420,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
->setParam('collectionId', $collection->getId())
->setParam('documentId', $document->getId())
->setContext('collection', $collection)
->setContext('database', $database)
;
->setContext('database', $database);
$response->dynamic($document, Response::MODEL_DOCUMENT);
});
@@ -3453,9 +3457,9 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
->inject('mode')
->action(function (string $databaseId, string $collectionId, string $documentId, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Event $events, Delete $deletes, string $mode) {
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
$database = Authorization::skip(fn() => $dbForProject->getDocument('databases', $databaseId));
if ($database->isEmpty()) {
if ($database->isEmpty() || (!$database->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
}
@@ -3490,7 +3494,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
$relationships = \array_filter(
$collection->getAttribute('attributes', []),
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
);
foreach ($relationships as $relationship) {
@@ -3521,7 +3525,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
$checkPermissions($collection, $document);
Authorization::skip(fn () => $dbForProject->withRequestTimestamp($requestTimestamp, function () use ($dbForProject, $database, $collection, $documentId) {
Authorization::skip(fn() => $dbForProject->withRequestTimestamp($requestTimestamp, function () use ($dbForProject, $database, $collection, $documentId) {
try {
$dbForProject->deleteDocument(
'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(),
@@ -3544,7 +3548,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
$relationships = \array_filter(
$collection->getAttribute('attributes', []),
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
fn($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
);
foreach ($relationships as $relationship) {
@@ -3574,8 +3578,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
$deletes
->setType(DELETE_TYPE_AUDIT)
->setDocument($document)
;
->setDocument($document);
$events
->setParam('databaseId', $databaseId)
@@ -3583,15 +3586,14 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
->setParam('documentId', $document->getId())
->setContext('collection', $collection)
->setContext('database', $database)
->setPayload($response->output($document, Response::MODEL_DOCUMENT))
;
->setPayload($response->output($document, Response::MODEL_DOCUMENT));
$response->noContent();
});
App::get('/v1/databases/usage')
->desc('Get usage stats for the database')
->groups(['api', 'database'])
->groups(['api', 'database', 'usage'])
->label('scope', 'collections.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'databases')
@@ -3689,16 +3691,16 @@ App::get('/v1/databases/usage')
'databasesCount' => $stats['databases.$all.count.total'] ?? [],
'documentsCount' => $stats['documents.$all.count.total'] ?? [],
'collectionsCount' => $stats['collections.$all.count.total'] ?? [],
'documentsCreate' => $stats['documents.$all.requests.create'] ?? [],
'documentsRead' => $stats['documents.$all.requests.read'] ?? [],
'documentsCreate' => $stats['documents.$all.requests.create'] ?? [],
'documentsRead' => $stats['documents.$all.requests.read'] ?? [],
'documentsUpdate' => $stats['documents.$all.requests.update'] ?? [],
'documentsDelete' => $stats['documents.$all.requests.delete'] ?? [],
'collectionsCreate' => $stats['collections.$all.requests.create'] ?? [],
'collectionsRead' => $stats['collections.$all.requests.read'] ?? [],
'collectionsRead' => $stats['collections.$all.requests.read'] ?? [],
'collectionsUpdate' => $stats['collections.$all.requests.update'] ?? [],
'collectionsDelete' => $stats['collections.$all.requests.delete'] ?? [],
'databasesCreate' => $stats['databases.$all.requests.create'] ?? [],
'databasesRead' => $stats['databases.$all.requests.read'] ?? [],
'databasesRead' => $stats['databases.$all.requests.read'] ?? [],
'databasesUpdate' => $stats['databases.$all.requests.update'] ?? [],
'databasesDelete' => $stats['databases.$all.requests.delete'] ?? [],
]);
@@ -3709,7 +3711,7 @@ App::get('/v1/databases/usage')
App::get('/v1/databases/:databaseId/usage')
->desc('Get usage stats for the database')
->groups(['api', 'database'])
->groups(['api', 'database', 'usage'])
->label('scope', 'collections.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'databases')
@@ -3802,12 +3804,12 @@ App::get('/v1/databases/:databaseId/usage')
'range' => $range,
'collectionsCount' => $stats["collections.{$databaseId}.count.total"] ?? [],
'collectionsCreate' => $stats["collections.{$databaseId}.requests.create"] ?? [],
'collectionsRead' => $stats["collections.{$databaseId}.requests.read"] ?? [],
'collectionsRead' => $stats["collections.{$databaseId}.requests.read"] ?? [],
'collectionsUpdate' => $stats["collections.{$databaseId}.requests.update"] ?? [],
'collectionsDelete' => $stats["collections.{$databaseId}.requests.delete"] ?? [],
'documentsCount' => $stats["documents.{$databaseId}.count.total"] ?? [],
'documentsCreate' => $stats["documents.{$databaseId}.requests.create"] ?? [],
'documentsRead' => $stats["documents.{$databaseId}.requests.read"] ?? [],
'documentsCreate' => $stats["documents.{$databaseId}.requests.create"] ?? [],
'documentsRead' => $stats["documents.{$databaseId}.requests.read"] ?? [],
'documentsUpdate' => $stats["documents.{$databaseId}.requests.update"] ?? [],
'documentsDelete' => $stats["documents.{$databaseId}.requests.delete"] ?? [],
]);
@@ -3819,7 +3821,7 @@ App::get('/v1/databases/:databaseId/usage')
App::get('/v1/databases/:databaseId/collections/:collectionId/usage')
->alias('/v1/database/:collectionId/usage', ['databaseId' => 'default'])
->desc('Get usage stats for a collection')
->groups(['api', 'database'])
->groups(['api', 'database', 'usage'])
->label('scope', 'collections.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'databases')
@@ -3917,8 +3919,8 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/usage')
'documentsCount' => $stats["documents.{$databaseId}/{$collectionId}.count.total"] ?? [],
'documentsCreate' => $stats["documents.{$databaseId}/{$collectionId}.requests.create"] ?? [],
'documentsRead' => $stats["documents.{$databaseId}/{$collectionId}.requests.read"] ?? [],
'documentsUpdate' => $stats["documents.{$databaseId}/{$collectionId}.requests.update"] ?? [],
'documentsDelete' => $stats["documents.{$databaseId}/{$collectionId}.requests.delete" ?? []]
'documentsUpdate' => $stats["documents.{$databaseId}/{$collectionId}.requests.update"] ?? [],
'documentsDelete' => $stats["documents.{$databaseId}/{$collectionId}.requests.delete" ?? []]
]);
}
+6 -4
View File
@@ -211,7 +211,7 @@ App::get('/v1/functions/:functionId')
App::get('/v1/functions/:functionId/usage')
->desc('Get Function Usage')
->groups(['api', 'functions'])
->groups(['api', 'functions', 'usage'])
->label('scope', 'functions.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'functions')
@@ -321,7 +321,7 @@ App::get('/v1/functions/:functionId/usage')
App::get('/v1/functions/usage')
->desc('Get Functions Usage')
->groups(['api', 'functions'])
->groups(['api', 'functions', 'usage'])
->label('scope', 'functions.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'functions')
@@ -650,11 +650,13 @@ App::post('/v1/functions/:functionId/deployments')
$end = $request->getContentRangeEnd();
$fileSize = $request->getContentRangeSize();
$deploymentId = $request->getHeader('x-appwrite-id', $deploymentId);
if (is_null($start) || is_null($end) || is_null($fileSize)) {
// TODO make `end >= $fileSize` in next breaking version
if (is_null($start) || is_null($end) || is_null($fileSize) || $end > $fileSize) {
throw new Exception(Exception::STORAGE_INVALID_CONTENT_RANGE);
}
if ($end === $fileSize) {
// TODO remove the condition that checks `$end === $fileSize` in next breaking version
if ($end === $fileSize - 1 || $end === $fileSize) {
//if it's a last chunks the chunk size might differ, so we set the $chunks and $chunk to notify it's last chunk
$chunks = $chunk = -1;
} else {
+41 -41
View File
@@ -29,6 +29,7 @@ use Utopia\Domains\Domain;
use Utopia\Registry\Registry;
use Appwrite\Extend\Exception;
use Appwrite\Utopia\Database\Validator\Queries\Projects;
use Utopia\Database\Exception\Duplicate;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Boolean;
use Utopia\Validator\Hostname;
@@ -91,38 +92,43 @@ App::post('/v1/projects')
throw new Exception(Exception::PROJECT_RESERVED_PROJECT, "'console' is a reserved project.");
}
$project = $dbForConsole->createDocument('projects', new Document([
'$id' => $projectId,
'$permissions' => [
Permission::read(Role::team(ID::custom($teamId))),
Permission::update(Role::team(ID::custom($teamId), 'owner')),
Permission::update(Role::team(ID::custom($teamId), 'developer')),
Permission::delete(Role::team(ID::custom($teamId), 'owner')),
Permission::delete(Role::team(ID::custom($teamId), 'developer')),
],
'name' => $name,
'teamInternalId' => $team->getInternalId(),
'teamId' => $team->getId(),
'region' => $region,
'description' => $description,
'logo' => $logo,
'url' => $url,
'version' => APP_VERSION_STABLE,
'legalName' => $legalName,
'legalCountry' => $legalCountry,
'legalState' => $legalState,
'legalCity' => $legalCity,
'legalAddress' => $legalAddress,
'legalTaxId' => ID::custom($legalTaxId),
'services' => new stdClass(),
'platforms' => null,
'authProviders' => [],
'webhooks' => null,
'keys' => null,
'domains' => null,
'auths' => $auths,
'search' => implode(' ', [$projectId, $name]),
]));
try {
$project = $dbForConsole->createDocument('projects', new Document([
'$id' => $projectId,
'$permissions' => [
Permission::read(Role::team(ID::custom($teamId))),
Permission::update(Role::team(ID::custom($teamId), 'owner')),
Permission::update(Role::team(ID::custom($teamId), 'developer')),
Permission::delete(Role::team(ID::custom($teamId), 'owner')),
Permission::delete(Role::team(ID::custom($teamId), 'developer')),
],
'name' => $name,
'teamInternalId' => $team->getInternalId(),
'teamId' => $team->getId(),
'region' => $region,
'description' => $description,
'logo' => $logo,
'url' => $url,
'version' => APP_VERSION_STABLE,
'legalName' => $legalName,
'legalCountry' => $legalCountry,
'legalState' => $legalState,
'legalCity' => $legalCity,
'legalAddress' => $legalAddress,
'legalTaxId' => ID::custom($legalTaxId),
'services' => new stdClass(),
'platforms' => null,
'authProviders' => [],
'webhooks' => null,
'keys' => null,
'domains' => null,
'auths' => $auths,
'search' => implode(' ', [$projectId, $name]),
]));
} catch (Duplicate $th) {
throw new Exception(Exception::PROJECT_ALREADY_EXISTS);
}
/** @var array $collections */
$collections = Config::getParam('collections', []);
@@ -245,7 +251,7 @@ App::get('/v1/projects/:projectId')
App::get('/v1/projects/:projectId/usage')
->desc('Get usage stats for a project')
->groups(['api', 'projects'])
->groups(['api', 'projects', 'usage'])
->label('scope', 'projects.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
@@ -678,17 +684,11 @@ App::delete('/v1/projects/:projectId')
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
->label('sdk.response.model', Response::MODEL_NONE)
->param('projectId', '', new UID(), 'Project unique ID.')
->param('password', '', new Password(), 'Your user password for confirmation. Must be at least 8 chars.')
->inject('response')
->inject('user')
->inject('dbForConsole')
->inject('deletes')
->action(function (string $projectId, string $password, Response $response, Document $user, Database $dbForConsole, Delete $deletes) {
if (!Auth::passwordVerify($password, $user->getAttribute('password'), $user->getAttribute('hash'), $user->getAttribute('hashOptions'))) { // Double check user password
throw new Exception(Exception::USER_INVALID_CREDENTIALS);
}
->action(function (string $projectId, Response $response, Document $user, Database $dbForConsole, Delete $deletes) {
$project = $dbForConsole->getDocument('projects', $projectId);
if ($project->isEmpty()) {
@@ -1237,7 +1237,7 @@ App::get('/v1/projects/:projectId/platforms')
}
$platforms = $dbForConsole->find('platforms', [
Query::equal('projectId', [$project->getId()]),
Query::equal('projectInternalId', [$project->getInternalId()]),
Query::limit(5000),
]);
+15 -13
View File
@@ -128,7 +128,7 @@ App::post('/v1/storage/buckets')
$bucket = $dbForProject->getDocument('buckets', $bucketId);
$dbForProject->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes);
$dbForProject->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes, permissions: $permissions ?? [], documentSecurity: $fileSecurity);
} catch (Duplicate) {
throw new Exception(Exception::STORAGE_BUCKET_ALREADY_EXISTS);
}
@@ -274,6 +274,7 @@ App::put('/v1/storage/buckets/:bucketId')
->setAttribute('encryption', $encryption)
->setAttribute('compression', $compression)
->setAttribute('antivirus', $antivirus));
$dbForProject->updateCollection('bucket_' . $bucket->getInternalId(), $permissions, $fileSecurity);
$events
->setParam('bucketId', $bucket->getId())
@@ -358,8 +359,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
->inject('mode')
->inject('deviceFiles')
->inject('deviceLocal')
->inject('deletes')
->action(function (string $bucketId, string $fileId, mixed $file, ?array $permissions, Request $request, Response $response, Database $dbForProject, Document $user, Event $events, string $mode, Device $deviceFiles, Device $deviceLocal, Delete $deletes) {
->action(function (string $bucketId, string $fileId, mixed $file, ?array $permissions, Request $request, Response $response, Database $dbForProject, Document $user, Event $events, string $mode, Device $deviceFiles, Device $deviceLocal) {
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
@@ -444,11 +444,18 @@ App::post('/v1/storage/buckets/:bucketId/files')
$end = $request->getContentRangeEnd();
$fileSize = $request->getContentRangeSize();
$fileId = $request->getHeader('x-appwrite-id', $fileId);
if (is_null($start) || is_null($end) || is_null($fileSize)) {
// TODO make `end >= $fileSize` in next breaking version
if (is_null($start) || is_null($end) || is_null($fileSize) || $end > $fileSize) {
throw new Exception(Exception::STORAGE_INVALID_CONTENT_RANGE);
}
if ($end === $fileSize) {
$idValidator = new UID();
if (!$idValidator->isValid($request->getHeader('x-appwrite-id'))) {
throw new Exception(Exception::STORAGE_INVALID_APPWRITE_ID);
}
// TODO remove the condition that checks `$end === $fileSize` in next breaking version
if ($end === $fileSize - 1 || $end === $fileSize) {
//if it's a last chunks the chunk size might differ, so we set the $chunks and $chunk to -1 notify it's last chunk
$chunks = $chunk = -1;
} else {
@@ -514,6 +521,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
}
$mimeType = $deviceFiles->getFileMimeType($path); // Get mime-type before compression and encryption
$fileHash = $deviceFiles->getFileHash($path); // Get file hash before compression and encryption
$data = '';
// Compression
$algorithm = $bucket->getAttribute('compression', COMPRESSION_TYPE_NONE);
@@ -547,7 +555,6 @@ App::post('/v1/storage/buckets/:bucketId/files')
}
$sizeActual = $deviceFiles->getFileSize($path);
$fileHash = $deviceFiles->getFileHash($path);
$openSSLVersion = null;
$openSSLCipher = null;
@@ -653,11 +660,6 @@ App::post('/v1/storage/buckets/:bucketId/files')
->setContext('bucket', $bucket)
;
$deletes
->setType(DELETE_TYPE_CACHE_BY_RESOURCE)
->setResource('file/' . $file->getId())
;
$metadata = null; // was causing leaks as it was passed by reference
$response
@@ -1447,7 +1449,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
App::get('/v1/storage/usage')
->desc('Get usage stats for storage')
->groups(['api', 'storage'])
->groups(['api', 'storage', 'usage'])
->label('scope', 'files.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'storage')
@@ -1557,7 +1559,7 @@ App::get('/v1/storage/usage')
App::get('/v1/storage/:bucketId/usage')
->desc('Get usage stats for a storage bucket')
->groups(['api', 'storage'])
->groups(['api', 'storage', 'usage'])
->label('scope', 'files.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'storage')
+20 -14
View File
@@ -67,18 +67,23 @@ App::post('/v1/teams')
$isAppUser = Auth::isAppUser(Authorization::getRoles());
$teamId = $teamId == 'unique()' ? ID::unique() : $teamId;
$team = Authorization::skip(fn() => $dbForProject->createDocument('teams', new Document([
'$id' => $teamId,
'$permissions' => [
Permission::read(Role::team($teamId)),
Permission::update(Role::team($teamId, 'owner')),
Permission::delete(Role::team($teamId, 'owner')),
],
'name' => $name,
'total' => ($isPrivilegedUser || $isAppUser) ? 0 : 1,
'prefs' => new \stdClass(),
'search' => implode(' ', [$teamId, $name]),
])));
try {
$team = Authorization::skip(fn() => $dbForProject->createDocument('teams', new Document([
'$id' => $teamId,
'$permissions' => [
Permission::read(Role::team($teamId)),
Permission::update(Role::team($teamId, 'owner')),
Permission::delete(Role::team($teamId, 'owner')),
],
'name' => $name,
'total' => ($isPrivilegedUser || $isAppUser) ? 0 : 1,
'prefs' => new \stdClass(),
'search' => implode(' ', [$teamId, $name]),
])));
} catch (Duplicate $th) {
throw new Exception(Exception::TEAM_ALREADY_EXISTS);
}
if (!$isPrivilegedUser && !$isAppUser) { // Don't add user on server mode
if (!\in_array('owner', $roles)) {
@@ -338,11 +343,12 @@ App::delete('/v1/teams/:teamId')
Query::limit(2000), // TODO fix members limit
]);
// TODO delete all members individually from the user object
// Memberships are deleted here instead of in the worker to make sure user permisions are updated instantly
foreach ($memberships as $membership) {
if (!$dbForProject->deleteDocument('memberships', $membership->getId())) {
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove membership for team from DB');
}
$dbForProject->deleteCachedDocument('users', $membership->getAttribute('userId'));
}
if (!$dbForProject->deleteDocument('teams', $teamId)) {
@@ -1038,7 +1044,7 @@ App::get('/v1/teams/:teamId/logs')
$output[$i] = new Document([
'event' => $log['event'],
'userId' => $log['userId'],
'userId' => $log['data']['userId'],
'userEmail' => $log['data']['userEmail'] ?? null,
'userName' => $log['data']['userName'] ?? null,
'mode' => $log['data']['mode'] ?? null,
+2 -2
View File
@@ -577,7 +577,7 @@ App::get('/v1/users/:userId/logs')
$audit = new Audit($dbForProject);
$logs = $audit->getLogsByUser($user->getId(), $limit, $offset);
$logs = $audit->getLogsByUser($user->getInternalId(), $limit, $offset);
$output = [];
@@ -1129,7 +1129,7 @@ App::delete('/v1/users/:userId')
App::get('/v1/users/usage')
->desc('Get usage stats for the users API')
->groups(['api', 'users'])
->groups(['api', 'users', 'usage'])
->label('scope', 'users.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'users')
+3 -2
View File
@@ -41,6 +41,7 @@ Config::setParam('cookieDomain', 'localhost');
Config::setParam('cookieSamesite', Response::COOKIE_SAMESITE_NONE);
App::init()
->groups(['api'])
->inject('utopia')
->inject('request')
->inject('response')
@@ -437,7 +438,7 @@ App::error()
$log->addExtra('line', $error->getLine());
$log->addExtra('trace', $error->getTraceAsString());
$log->addExtra('detailedTrace', $error->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);
@@ -584,7 +585,7 @@ App::get('/humans.txt')
$response->text($template->render(false));
});
App::get('/.well-known/acme-challenge')
App::get('/.well-known/acme-challenge/*')
->desc('SSL Verification')
->label('scope', 'public')
->label('docs', false)
+6 -6
View File
@@ -286,7 +286,7 @@ App::post('/v1/mock/tests/general/upload')
$id = $request->getHeader('x-appwrite-id', '');
$file['size'] = (\is_array($file['size'])) ? $file['size'][0] : $file['size'];
if (is_null($start) || is_null($end) || is_null($size)) {
if (is_null($start) || is_null($end) || is_null($size) || $end >= $size) {
throw new Exception(Exception::GENERAL_MOCK, 'Invalid content-range header');
}
@@ -302,11 +302,11 @@ App::post('/v1/mock/tests/general/upload')
throw new Exception(Exception::GENERAL_MOCK, 'All chunked request must have id header (except first)');
}
if ($end !== $size && $end - $start + 1 !== $chunkSize) {
if ($end !== $size - 1 && $end - $start + 1 !== $chunkSize) {
throw new Exception(Exception::GENERAL_MOCK, 'Chunk size must be 5MB (except last chunk)');
}
if ($end !== $size && $file['size'] !== $chunkSize) {
if ($end !== $size - 1 && $file['size'] !== $chunkSize) {
throw new Exception(Exception::GENERAL_MOCK, 'Wrong chunk size');
}
@@ -314,11 +314,11 @@ App::post('/v1/mock/tests/general/upload')
throw new Exception(Exception::GENERAL_MOCK, 'Chunk size must be 5MB or less');
}
if ($end !== $size) {
if ($end !== $size - 1) {
$response->json([
'$id' => ID::custom('newfileid'),
'chunksTotal' => $file['size'] / $chunkSize,
'chunksUploaded' => $start / $chunkSize
'chunksTotal' => (int) ceil($size / ($end + 1 - $start)),
'chunksUploaded' => ceil($start / $chunkSize) + 1
]);
}
} else {
+9 -1
View File
@@ -27,7 +27,7 @@ $parseLabel = function (string $label, array $responsePayload, array $requestPar
$parts = explode('.', $match);
if (count($parts) !== 2) {
throw new Exception('Too less or too many parts', 400, Exception::GENERAL_ARGUMENT_INVALID);
throw new Exception(Exception::GENERAL_SERVER_ERROR, "The server encountered an error while parsing the label: $label. Please create an issue on GitHub to allow us to investigate further https://github.com/appwrite/appwrite/issues/new/choose");
}
$namespace = $parts[0] ?? '';
@@ -552,3 +552,11 @@ App::shutdown()
->submit();
}
});
App::init()
->groups(['usage'])
->action(function () {
if (App::getEnv('_APP_USAGE_STATS', 'enabled') !== 'enabled') {
throw new Exception(Exception::GENERAL_USAGE_DISABLED);
}
});
+16 -2
View File
@@ -1,14 +1,28 @@
<?php
use Appwrite\Utopia\Request;
use Appwrite\Utopia\Response;
use Utopia\App;
App::get('/console')
App::init()
->groups(['web'])
->inject('request')
->inject('response')
->action(function (Request $request, Response $response) {
$response
->addHeader('X-Frame-Options', 'SAMEORIGIN') // Avoid console and homepage from showing in iframes
->addHeader('X-XSS-Protection', '1; mode=block; report=/v1/xss?url=' . \urlencode($request->getURI()))
->addHeader('X-UA-Compatible', 'IE=Edge') // Deny IE browsers from going into quirks mode
;
});
App::get('/console/*')
->alias('/')
->alias('auth/*')
->alias('/invite')
->alias('/login')
->alias('/recover')
->alias('/register')
->alias('/register/*')
->groups(['web'])
->label('permission', 'public')
->label('scope', 'home')
+1 -1
View File
@@ -6,7 +6,7 @@ use Utopia\Config\Config;
App::get('/versions')
->desc('Get Version')
->groups(['web', 'home'])
->groups(['home'])
->label('scope', 'public')
->inject('response')
->action(function (Response $response) {
-6
View File
@@ -115,12 +115,6 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
if (!$dbForConsole->getCollection($key)->isEmpty()) {
continue;
}
/**
* Skip to prevent 0.16 migration issues.
*/
if (in_array($key, ['cache', 'variables']) && $dbForConsole->exists(App::getEnv('_APP_DB_SCHEMA', 'appwrite'), 'bucket_1')) {
continue;
}
Console::success('[Setup] - Creating collection: ' . $collection['$id'] . '...');
+3 -3
View File
@@ -100,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 = 503;
const APP_VERSION_STABLE = '1.3.1';
const APP_CACHE_BUSTER = 506;
const APP_VERSION_STABLE = '1.3.8';
const APP_DATABASE_ATTRIBUTE_EMAIL = 'email';
const APP_DATABASE_ATTRIBUTE_ENUM = 'enum';
const APP_DATABASE_ATTRIBUTE_IP = 'ip';
@@ -903,7 +903,7 @@ App::setResource('project', function ($dbForConsole, $request, $console) {
/** @var Utopia\Database\Database $dbForConsole */
/** @var Utopia\Database\Document $console */
$projectId = $request->getParam('project', $request->getHeader('x-appwrite-project', 'console'));
$projectId = $request->getParam('project', $request->getHeader('x-appwrite-project', ''));
if ($projectId === 'console') {
return $console;
+7 -7
View File
@@ -95,9 +95,9 @@ $cli
if (is_null($value)) {
continue;
}
foreach ($vars as &$var) {
foreach ($vars as $i => $var) {
if ($var['name'] === $key) {
$var['default'] = $value;
$vars[$i]['default'] = $value;
}
}
}
@@ -114,9 +114,9 @@ $cli
if (is_null($value)) {
continue;
}
foreach ($vars as &$var) {
foreach ($vars as $i => $var) {
if ($var['name'] === $key) {
$var['default'] = $value;
$vars[$i]['default'] = $value;
}
}
}
@@ -146,7 +146,7 @@ $cli
$input = [];
foreach ($vars as $key => $var) {
foreach ($vars as $var) {
if (!empty($var['filter']) && ($interactive !== 'Y' || !Console::isInteractive())) {
if ($data && $var['default'] !== null) {
$input[$var['name']] = $var['default'];
@@ -224,9 +224,9 @@ $cli
}
}
Console::log("Running \"docker compose -f {$path}/docker-compose.yml up -d --remove-orphans --renew-anon-volumes\"");
Console::log("Running \"docker compose up -d --remove-orphans --renew-anon-volumes\"");
$exit = Console::execute("${env} docker compose -f {$path}/docker-compose.yml up -d --remove-orphans --renew-anon-volumes", '', $stdout, $stderr);
$exit = Console::execute("${env} docker compose --project-directory {$path} up -d --remove-orphans --renew-anon-volumes", '', $stdout, $stderr);
if ($exit !== 0) {
$message = 'Failed to install Appwrite dockers';
+2 -2
View File
@@ -239,8 +239,8 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
cd ' . $target . ' && \
git init --initial-branch=' . $gitBranch . ' && \
git remote add origin ' . $gitUrl . ' && \
git fetch && \
git pull ' . $gitUrl . ' && \
git fetch origin ' . $gitBranch . ' && \
git pull origin ' . $gitBranch . ' && \
rm -rf ' . $target . '/* && \
cp -r ' . $result . '/* ' . $target . '/ && \
git add . && \
+2 -2
View File
@@ -40,8 +40,7 @@ class AuditsV1 extends Worker
$dbForProject = $this->getProjectDB($project->getId());
$audit = new Audit($dbForProject);
$audit->log(
userInternalId: $user->getInternalId(),
userId: $user->getId(),
userId: $user->getInternalId(),
// Pass first, most verbose event pattern
event: $event,
resource: $resource,
@@ -49,6 +48,7 @@ class AuditsV1 extends Worker
ip: $ip,
location: '',
data: [
'userId' => $user->getId(),
'userName' => $userName,
'userEmail' => $userEmail,
'mode' => $mode,
+64 -19
View File
@@ -9,7 +9,6 @@ use Utopia\Database\Document;
use Utopia\Database\Query;
use Appwrite\Resque\Worker;
use Executor\Executor;
use Utopia\Storage\Device\Local;
use Utopia\Abuse\Abuse;
use Utopia\Abuse\Adapters\TimeLimit;
use Utopia\CLI\Console;
@@ -115,10 +114,10 @@ class DeletesV1 extends Worker
break;
case DELETE_TYPE_CACHE_BY_RESOURCE:
$this->deleteCacheByResource($project->getId());
$this->deleteCacheByResource($project, $this->args['resource']);
break;
case DELETE_TYPE_CACHE_BY_TIMESTAMP:
$this->deleteCacheByDate();
$this->deleteCacheByDate($this->args['datetime']);
break;
default:
Console::error('No delete operation for type: ' . $type);
@@ -131,31 +130,56 @@ class DeletesV1 extends Worker
}
/**
* @param string $projectId
* @param Document $project
* @param string $resource
* @throws Exception
*/
protected function deleteCacheByResource(string $projectId): void
protected function deleteCacheByResource(Document $project, string $resource): void
{
$this->deleteCacheFiles([
Query::equal('resource', [$this->args['resource']]),
]);
$projectId = $project->getId();
$dbForProject = $this->getProjectDB($projectId);
$cache = new Cache(
new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId)
);
$query = [
Query::equal('resource', [$resource])
];
$this->deleteByGroup(
'cache',
$query,
$dbForProject,
function (Document $document) use ($cache, $projectId) {
$path = APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId . DIRECTORY_SEPARATOR . $document->getId();
if ($cache->purge($document->getId())) {
Console::success('Deleting cache file: ' . $path);
} else {
Console::error('Failed to delete cache file: ' . $path);
}
}
);
}
protected function deleteCacheByDate(): void
/**
* @param string $datetime
* @throws Exception
*/
protected function deleteCacheByDate(string $datetime): void
{
$this->deleteCacheFiles([
Query::lessThan('accessedAt', $this->args['datetime']),
]);
}
protected function deleteCacheFiles($query): void
{
$this->deleteForProjectIds(function (string $projectId) use ($query) {
$this->deleteForProjectIds(function (string $projectId) use ($datetime) {
$dbForProject = $this->getProjectDB($projectId);
$cache = new Cache(
new Filesystem(APP_STORAGE_CACHE . DIRECTORY_SEPARATOR . 'app-' . $projectId)
);
$query = [
Query::lessThan('accessedAt', $datetime),
];
$this->deleteByGroup(
'cache',
$query,
@@ -291,12 +315,13 @@ class DeletesV1 extends Worker
protected function deleteProject(Document $document): void
{
$projectId = $document->getId();
$projectInternalId = $document->getInternalId();
// Delete project domains and certificates
// Delete project certificates
$dbForConsole = $this->getConsoleDB();
$domains = $dbForConsole->find('domains', [
Query::equal('projectInternalId', [$document->getInternalId()])
Query::equal('projectInternalId', [$projectInternalId])
]);
foreach ($domains as $domain) {
@@ -318,6 +343,26 @@ class DeletesV1 extends Worker
}
}
// Delete Platforms
$this->deleteByGroup('platforms', [
Query::equal('projectInternalId', [$projectInternalId])
], $dbForConsole);
// Delete Domains
$this->deleteByGroup('domains', [
Query::equal('projectInternalId', [$projectInternalId])
], $dbForConsole);
// Delete Keys
$this->deleteByGroup('keys', [
Query::equal('projectInternalId', [$projectInternalId])
], $dbForConsole);
// Delete Webhooks
$this->deleteByGroup('webhooks', [
Query::equal('projectInternalId', [$projectInternalId])
], $dbForConsole);
// Delete metadata tables
try {
$dbForProject->deleteCollection('_metadata');
+15 -11
View File
@@ -82,18 +82,22 @@ class FunctionsV1 extends Worker
Console::success('Iterating function: ' . $function->getAttribute('name'));
$this->execute(
project: $project,
function: $function,
dbForProject: $database,
trigger: 'event',
// Pass first, most verbose event pattern
event: $events[0],
eventData: $payload,
user: $user
);
try {
$this->execute(
project: $project,
function: $function,
dbForProject: $database,
trigger: 'event',
// Pass first, most verbose event pattern
event: $events[0],
eventData: $payload,
user: $user
);
Console::success('Triggered function: ' . $events[0]);
Console::success('Triggered function: ' . $events[0]);
} catch (\Throwable $th) {
Console::error("Failed to execute " . $function->getId() . " with error: " . $th->getMessage());
}
}
}
+1 -1
View File
@@ -29,7 +29,7 @@ class MailsV1 extends Worker
return;
}
$recipient = $this->args['recipient'];
$subject = $this->args['subject'];
$name = $this->args['name'];
+79 -34
View File
@@ -5,6 +5,8 @@ use Appwrite\Resque\Worker;
use Utopia\App;
use Utopia\CLI\Console;
use Utopia\Messaging\Adapter;
use Utopia\Messaging\Adapters\SMS as SMSAdapter;
use Utopia\Messaging\Adapters\SMS\Mock;
use Utopia\Messaging\Adapters\SMS\Msg91;
use Utopia\Messaging\Adapters\SMS\Telesign;
@@ -13,6 +15,17 @@ use Utopia\Messaging\Adapters\SMS\Twilio;
use Utopia\Messaging\Adapters\SMS\Vonage;
use Utopia\Messaging\Messages\SMS;
use Utopia\Messaging\Adapters\Push as PushAdapter;
use Utopia\Messaging\Adapters\Push\APNS;
use Utopia\Messaging\Adapters\Push\FCM;
use Utopia\Messaging\Messages\Push;
use Utopia\Messaging\Adapters\Email as EmailAdapter;
use Utopia\Messaging\Adapters\Email\Mailgun;
use Utopia\Messaging\Adapters\Email\SendGrid;
use Utopia\Messaging\Messages\Email;
require_once __DIR__ . '/../init.php';
Console::title('Messaging V1 Worker');
@@ -20,7 +33,11 @@ Console::success(APP_NAME . ' messaging worker v1 has started' . "\n");
class MessagingV1 extends Worker
{
protected ?Adapter $sms = null;
protected ?SMSAdapter $sms = null;
protected ?PushAdapter $push = null;
protected ?EmailAdapter $email = null;
protected ?string $from = null;
public function getName(): string
@@ -28,48 +45,76 @@ class MessagingV1 extends Worker
return "mails";
}
public function sms($record): ?SMSAdapter
{
return match ($record->getAttribute('provider')) {
'mock' => new Mock($user, $secret), // used for tests
'twilio' => new Twilio($user, $secret),
'text-magic' => new TextMagic($user, $secret),
'telesign' => new Telesign($user, $secret),
'msg91' => new Msg91($user, $secret),
'vonage' => new Vonage($user, $secret),
default => null
};
}
}
function push($record): ?PushAdapter
{
return match ($record->getAttribute('provider')) {
'apns' => new APNS($user, $secret),
'fcm' => new FCM($user, $secret),
default => null
};
}
function email(): ?EmailAdapter
{
return match ($record->getAttribute('provider')) {
'mailgun' => new Mailgun($user, $secret),
'sendgrid' => new SendGrid($user, $secret),
default => null
};
}
public function init(): void
{
$dsn = new DSN(App::getEnv('_APP_SMS_PROVIDER'));
$user = $dsn->getUser();
$secret = $dsn->getPassword();
$this->sms = match ($dsn->getHost()) {
'mock' => new Mock($user, $secret), // used for tests
'twilio' => new Twilio($user, $secret),
'text-magic' => new TextMagic($user, $secret),
'telesign' => new Telesign($user, $secret),
'msg91' => new Msg91($user, $secret),
'vonage' => new Vonage($user, $secret),
default => null
};
$this->from = App::getEnv('_APP_SMS_FROM');
}
public function run(): void
{
if (empty(App::getEnv('_APP_SMS_PROVIDER'))) {
Console::info('Skipped sms processing. No Phone provider has been set.');
return;
}
$providerId = $this->args['providerId'];
$providerRecord =
$this
->getConsoleDB()
->getCollection('providers')
->getDocument($providerId);
if (empty($this->from)) {
Console::info('Skipped sms processing. No phone number has been set.');
return;
}
$provider = match ($providerRecord->getAttribute('type')) {//stubbbbbbed.
'sms' => $this->sms($providerRecord),
'push' => $this->push($providerRecord),
'email' => $this->email($providerRecord),
default => null
};
$message = new SMS(
to: [$this->args['recipient']],
content: $this->args['message'],
from: $this->from,
);
// Query for the provider
// switch on provider name
// call function passing needed credentials returns required provider.
try {
$this->sms->send($message);
} catch (\Exception $error) {
throw new Exception('Error sending message: ' . $error->getMessage(), 500);
}
$messageId = $this->args['messageId'];
$message =
$this
->getConsoleDB()
->getCollection('messages')
->getDocument($messageId);
// Get message
// set up message based on provider
// send a message.
$provider->send($message);
}
public function shutdown(): void
+5 -5
View File
@@ -43,14 +43,14 @@
"ext-sockets": "*",
"appwrite/php-clamav": "1.1.*",
"appwrite/php-runtimes": "0.11.*",
"utopia-php/abuse": "0.24.*",
"utopia-php/abuse": "0.25.*",
"utopia-php/analytics": "0.2.*",
"utopia-php/audit": "0.25.*",
"utopia-php/audit": "0.27.*",
"utopia-php/cache": "0.8.*",
"utopia-php/cli": "0.13.*",
"utopia-php/config": "0.2.*",
"utopia-php/database": "0.35.*",
"utopia-php/domains": "1.1.*",
"utopia-php/database": "0.36.*",
"utopia-php/domains": "0.3.*",
"utopia-php/framework": "0.28.*",
"utopia-php/image": "0.5.*",
"utopia-php/locale": "0.4.*",
@@ -79,7 +79,7 @@
}
],
"require-dev": {
"appwrite/sdk-generator": "0.32.*",
"appwrite/sdk-generator": "0.33.*",
"ext-fileinfo": "*",
"phpunit/phpunit": "9.5.20",
"squizlabs/php_codesniffer": "^3.6",
Generated
+160 -159
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": "87de4ea3130e576470a63b21628e30fb",
"content-hash": "a15f62920dedaf99e321ffd94e89d9f4",
"packages": [
{
"name": "adhocore/jwt",
@@ -300,16 +300,16 @@
},
{
"name": "colinmollenhour/credis",
"version": "v1.14.0",
"version": "v1.15.0",
"source": {
"type": "git",
"url": "https://github.com/colinmollenhour/credis.git",
"reference": "dccc8a46586475075fbb012d8bd523b8a938c2dc"
"reference": "28810439de1d9597b7ba11794ed9479fb6f3de7c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/colinmollenhour/credis/zipball/dccc8a46586475075fbb012d8bd523b8a938c2dc",
"reference": "dccc8a46586475075fbb012d8bd523b8a938c2dc",
"url": "https://api.github.com/repos/colinmollenhour/credis/zipball/28810439de1d9597b7ba11794ed9479fb6f3de7c",
"reference": "28810439de1d9597b7ba11794ed9479fb6f3de7c",
"shasum": ""
},
"require": {
@@ -341,9 +341,9 @@
"homepage": "https://github.com/colinmollenhour/credis",
"support": {
"issues": "https://github.com/colinmollenhour/credis/issues",
"source": "https://github.com/colinmollenhour/credis/tree/v1.14.0"
"source": "https://github.com/colinmollenhour/credis/tree/v1.15.0"
},
"time": "2022-11-09T01:18:39+00:00"
"time": "2023-04-18T15:34:23+00:00"
},
{
"name": "composer/package-versions-deprecated",
@@ -481,22 +481,22 @@
},
{
"name": "guzzlehttp/guzzle",
"version": "7.5.0",
"version": "7.7.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "b50a2a1251152e43f6a37f0fa053e730a67d25ba"
"reference": "fb7566caccf22d74d1ab270de3551f72a58399f5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/b50a2a1251152e43f6a37f0fa053e730a67d25ba",
"reference": "b50a2a1251152e43f6a37f0fa053e730a67d25ba",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/fb7566caccf22d74d1ab270de3551f72a58399f5",
"reference": "fb7566caccf22d74d1ab270de3551f72a58399f5",
"shasum": ""
},
"require": {
"ext-json": "*",
"guzzlehttp/promises": "^1.5",
"guzzlehttp/psr7": "^1.9 || ^2.4",
"guzzlehttp/promises": "^1.5.3 || ^2.0",
"guzzlehttp/psr7": "^1.9.1 || ^2.4.5",
"php": "^7.2.5 || ^8.0",
"psr/http-client": "^1.0",
"symfony/deprecation-contracts": "^2.2 || ^3.0"
@@ -507,7 +507,8 @@
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.1",
"ext-curl": "*",
"php-http/client-integration-tests": "^3.0",
"php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999",
"php-http/message-factory": "^1.1",
"phpunit/phpunit": "^8.5.29 || ^9.5.23",
"psr/log": "^1.1 || ^2.0 || ^3.0"
},
@@ -521,9 +522,6 @@
"bamarni-bin": {
"bin-links": true,
"forward-command": false
},
"branch-alias": {
"dev-master": "7.5-dev"
}
},
"autoload": {
@@ -589,7 +587,7 @@
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/7.5.0"
"source": "https://github.com/guzzle/guzzle/tree/7.7.0"
},
"funding": [
{
@@ -605,38 +603,37 @@
"type": "tidelift"
}
],
"time": "2022-08-28T15:39:27+00:00"
"time": "2023-05-21T14:04:53+00:00"
},
{
"name": "guzzlehttp/promises",
"version": "1.5.2",
"version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "b94b2807d85443f9719887892882d0329d1e2598"
"reference": "3a494dc7dc1d7d12e511890177ae2d0e6c107da6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/b94b2807d85443f9719887892882d0329d1e2598",
"reference": "b94b2807d85443f9719887892882d0329d1e2598",
"url": "https://api.github.com/repos/guzzle/promises/zipball/3a494dc7dc1d7d12e511890177ae2d0e6c107da6",
"reference": "3a494dc7dc1d7d12e511890177ae2d0e6c107da6",
"shasum": ""
},
"require": {
"php": ">=5.5"
"php": "^7.2.5 || ^8.0"
},
"require-dev": {
"symfony/phpunit-bridge": "^4.4 || ^5.1"
"bamarni/composer-bin-plugin": "^1.8.1",
"phpunit/phpunit": "^8.5.29 || ^9.5.23"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.5-dev"
"bamarni-bin": {
"bin-links": true,
"forward-command": false
}
},
"autoload": {
"files": [
"src/functions_include.php"
],
"psr-4": {
"GuzzleHttp\\Promise\\": "src/"
}
@@ -673,7 +670,7 @@
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/1.5.2"
"source": "https://github.com/guzzle/promises/tree/2.0.0"
},
"funding": [
{
@@ -689,26 +686,26 @@
"type": "tidelift"
}
],
"time": "2022-08-28T14:55:35+00:00"
"time": "2023-05-21T13:50:22+00:00"
},
{
"name": "guzzlehttp/psr7",
"version": "2.4.4",
"version": "2.5.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf"
"reference": "b635f279edd83fc275f822a1188157ffea568ff6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf",
"reference": "3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/b635f279edd83fc275f822a1188157ffea568ff6",
"reference": "b635f279edd83fc275f822a1188157ffea568ff6",
"shasum": ""
},
"require": {
"php": "^7.2.5 || ^8.0",
"psr/http-factory": "^1.0",
"psr/http-message": "^1.0",
"psr/http-message": "^1.1 || ^2.0",
"ralouphie/getallheaders": "^3.0"
},
"provide": {
@@ -728,9 +725,6 @@
"bamarni-bin": {
"bin-links": true,
"forward-command": false
},
"branch-alias": {
"dev-master": "2.4-dev"
}
},
"autoload": {
@@ -792,7 +786,7 @@
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/2.4.4"
"source": "https://github.com/guzzle/psr7/tree/2.5.0"
},
"funding": [
{
@@ -808,7 +802,7 @@
"type": "tidelift"
}
],
"time": "2023-03-09T13:19:02+00:00"
"time": "2023-04-17T16:11:26+00:00"
},
{
"name": "influxdb/influxdb-php",
@@ -1372,16 +1366,16 @@
},
{
"name": "psr/http-message",
"version": "1.1",
"version": "2.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba"
"reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
"reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71",
"reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71",
"shasum": ""
},
"require": {
@@ -1390,7 +1384,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
"dev-master": "2.0.x-dev"
}
},
"autoload": {
@@ -1405,7 +1399,7 @@
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for HTTP messages",
@@ -1419,9 +1413,9 @@
"response"
],
"support": {
"source": "https://github.com/php-fig/http-message/tree/1.1"
"source": "https://github.com/php-fig/http-message/tree/2.0"
},
"time": "2023-04-04T09:50:52+00:00"
"time": "2023-04-04T09:54:51+00:00"
},
{
"name": "psr/log",
@@ -1658,16 +1652,16 @@
},
{
"name": "symfony/deprecation-contracts",
"version": "v3.2.1",
"version": "v3.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e"
"reference": "7c3aff79d10325257a001fcf92d991f24fc967cf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e",
"reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf",
"reference": "7c3aff79d10325257a001fcf92d991f24fc967cf",
"shasum": ""
},
"require": {
@@ -1676,7 +1670,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "3.3-dev"
"dev-main": "3.4-dev"
},
"thanks": {
"name": "symfony/contracts",
@@ -1705,7 +1699,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.2.1"
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.3.0"
},
"funding": [
{
@@ -1721,7 +1715,7 @@
"type": "tidelift"
}
],
"time": "2023-03-01T10:25:55+00:00"
"time": "2023-05-23T14:45:45+00:00"
},
{
"name": "symfony/polyfill-php80",
@@ -1808,26 +1802,26 @@
},
{
"name": "utopia-php/abuse",
"version": "0.24.0",
"version": "0.25.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/abuse.git",
"reference": "403641f16a53b81ac40b91111a86e5672da49e8c"
"reference": "49a180cab5316cddec9676d900d5112d03e97ffc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/403641f16a53b81ac40b91111a86e5672da49e8c",
"reference": "403641f16a53b81ac40b91111a86e5672da49e8c",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/49a180cab5316cddec9676d900d5112d03e97ffc",
"reference": "49a180cab5316cddec9676d900d5112d03e97ffc",
"shasum": ""
},
"require": {
"ext-curl": "*",
"ext-pdo": "*",
"php": ">=8.0",
"utopia-php/database": "0.35.*"
"utopia-php/database": "0.36.*"
},
"require-dev": {
"laravel/pint": "1.2.*",
"laravel/pint": "1.5.*",
"phpstan/phpstan": "^1.9",
"phpunit/phpunit": "^9.4"
},
@@ -1851,9 +1845,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/abuse/issues",
"source": "https://github.com/utopia-php/abuse/tree/0.24.0"
"source": "https://github.com/utopia-php/abuse/tree/0.25.0"
},
"time": "2023-04-11T05:31:55+00:00"
"time": "2023-04-27T15:43:47+00:00"
},
{
"name": "utopia-php/analytics",
@@ -1912,24 +1906,24 @@
},
{
"name": "utopia-php/audit",
"version": "0.25.0",
"version": "0.27.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/audit.git",
"reference": "adc209f2e16878e5468f0b9cfd9f7f7ab497db31"
"reference": "bdf89d7fe381bd4c891ad217612580a35e8c7642"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/adc209f2e16878e5468f0b9cfd9f7f7ab497db31",
"reference": "adc209f2e16878e5468f0b9cfd9f7f7ab497db31",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/bdf89d7fe381bd4c891ad217612580a35e8c7642",
"reference": "bdf89d7fe381bd4c891ad217612580a35e8c7642",
"shasum": ""
},
"require": {
"php": ">=8.0",
"utopia-php/database": "0.35.*"
"utopia-php/database": "0.36.*"
},
"require-dev": {
"laravel/pint": "1.2.*",
"laravel/pint": "1.5.*",
"phpstan/phpstan": "^1.8",
"phpunit/phpunit": "^9.3"
},
@@ -1953,9 +1947,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/audit/issues",
"source": "https://github.com/utopia-php/audit/tree/0.25.0"
"source": "https://github.com/utopia-php/audit/tree/0.27.0"
},
"time": "2023-04-11T05:31:15+00:00"
"time": "2023-05-15T07:04:48+00:00"
},
{
"name": "utopia-php/cache",
@@ -2112,16 +2106,16 @@
},
{
"name": "utopia-php/database",
"version": "0.35.0",
"version": "0.36.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/database.git",
"reference": "f162c142fd61753c4b413b15c3c4041f3cd00bb2"
"reference": "f6ab65e59a199da5155c114564077b1ab8c4daef"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/database/zipball/f162c142fd61753c4b413b15c3c4041f3cd00bb2",
"reference": "f162c142fd61753c4b413b15c3c4041f3cd00bb2",
"url": "https://api.github.com/repos/utopia-php/database/zipball/f6ab65e59a199da5155c114564077b1ab8c4daef",
"reference": "f6ab65e59a199da5155c114564077b1ab8c4daef",
"shasum": ""
},
"require": {
@@ -2164,29 +2158,31 @@
],
"support": {
"issues": "https://github.com/utopia-php/database/issues",
"source": "https://github.com/utopia-php/database/tree/0.35.0"
"source": "https://github.com/utopia-php/database/tree/0.36.1"
},
"time": "2023-04-11T04:02:22+00:00"
"time": "2023-04-27T08:39:55+00:00"
},
{
"name": "utopia-php/domains",
"version": "v1.1.0",
"version": "0.3.2",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/domains.git",
"reference": "1665e1d9932afa3be63b5c1e0dcfe01fe77d8e73"
"reference": "aaa8c9a96c69ccb397997b1f4f2299c66f77eefb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/domains/zipball/1665e1d9932afa3be63b5c1e0dcfe01fe77d8e73",
"reference": "1665e1d9932afa3be63b5c1e0dcfe01fe77d8e73",
"url": "https://api.github.com/repos/utopia-php/domains/zipball/aaa8c9a96c69ccb397997b1f4f2299c66f77eefb",
"reference": "aaa8c9a96c69ccb397997b1f4f2299c66f77eefb",
"shasum": ""
},
"require": {
"php": ">=7.1"
"php": ">=8.0",
"utopia-php/framework": "0.*.*"
},
"require-dev": {
"phpunit/phpunit": "^7.0"
"laravel/pint": "1.2.*",
"phpunit/phpunit": "^9.3"
},
"type": "library",
"autoload": {
@@ -2202,6 +2198,10 @@
{
"name": "Eldad Fux",
"email": "eldad@appwrite.io"
},
{
"name": "Wess Cope",
"email": "wess@appwrite.io"
}
],
"description": "Utopia Domains library is simple and lite library for parsing web domains. This library is aiming to be as simple and easy to learn and use.",
@@ -2218,29 +2218,30 @@
],
"support": {
"issues": "https://github.com/utopia-php/domains/issues",
"source": "https://github.com/utopia-php/domains/tree/master"
"source": "https://github.com/utopia-php/domains/tree/0.3.2"
},
"time": "2020-02-23T07:40:02+00:00"
"time": "2023-07-19T16:39:24+00:00"
},
{
"name": "utopia-php/framework",
"version": "0.28.1",
"version": "0.28.4",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/framework.git",
"reference": "7f22c556fc5991e54e5811a68fb39809b21bda55"
"reference": "98c5469efe195aeecc63745dbf8e2f357f8cedac"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/framework/zipball/7f22c556fc5991e54e5811a68fb39809b21bda55",
"reference": "7f22c556fc5991e54e5811a68fb39809b21bda55",
"url": "https://api.github.com/repos/utopia-php/framework/zipball/98c5469efe195aeecc63745dbf8e2f357f8cedac",
"reference": "98c5469efe195aeecc63745dbf8e2f357f8cedac",
"shasum": ""
},
"require": {
"php": ">=8.0.0"
"php": ">=8.0"
},
"require-dev": {
"laravel/pint": "^1.2",
"phpstan/phpstan": "1.9.x-dev",
"phpunit/phpunit": "^9.5.25",
"vimeo/psalm": "4.27.0"
},
@@ -2262,9 +2263,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/framework/issues",
"source": "https://github.com/utopia-php/framework/tree/0.28.1"
"source": "https://github.com/utopia-php/framework/tree/0.28.4"
},
"time": "2023-03-02T08:16:01+00:00"
"time": "2023-06-03T14:09:22+00:00"
},
{
"name": "utopia-php/image",
@@ -2969,16 +2970,16 @@
},
{
"name": "webonyx/graphql-php",
"version": "v14.11.9",
"version": "v14.11.10",
"source": {
"type": "git",
"url": "https://github.com/webonyx/graphql-php.git",
"reference": "ff91c9f3cf241db702e30b2c42bcc0920e70ac70"
"reference": "d9c2fdebc6aa01d831bc2969da00e8588cffef19"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webonyx/graphql-php/zipball/ff91c9f3cf241db702e30b2c42bcc0920e70ac70",
"reference": "ff91c9f3cf241db702e30b2c42bcc0920e70ac70",
"url": "https://api.github.com/repos/webonyx/graphql-php/zipball/d9c2fdebc6aa01d831bc2969da00e8588cffef19",
"reference": "d9c2fdebc6aa01d831bc2969da00e8588cffef19",
"shasum": ""
},
"require": {
@@ -2998,8 +2999,7 @@
"phpunit/phpunit": "^7.2 || ^8.5",
"psr/http-message": "^1.0",
"react/promise": "2.*",
"simpod/php-coveralls-mirror": "^3.0",
"squizlabs/php_codesniffer": "3.5.4"
"simpod/php-coveralls-mirror": "^3.0"
},
"suggest": {
"psr/http-message": "To use standard GraphQL server",
@@ -3023,7 +3023,7 @@
],
"support": {
"issues": "https://github.com/webonyx/graphql-php/issues",
"source": "https://github.com/webonyx/graphql-php/tree/v14.11.9"
"source": "https://github.com/webonyx/graphql-php/tree/v14.11.10"
},
"funding": [
{
@@ -3031,22 +3031,22 @@
"type": "open_collective"
}
],
"time": "2023-01-06T12:12:50+00:00"
"time": "2023-07-05T14:23:37+00:00"
}
],
"packages-dev": [
{
"name": "appwrite/sdk-generator",
"version": "0.32.1",
"version": "0.33.7",
"source": {
"type": "git",
"url": "https://github.com/appwrite/sdk-generator.git",
"reference": "ba1d7afd57e3baef06c04ce6abc26f79310146df"
"reference": "9f5db4a637b23879ceacea9ed2d33b0486771ffc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/ba1d7afd57e3baef06c04ce6abc26f79310146df",
"reference": "ba1d7afd57e3baef06c04ce6abc26f79310146df",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/9f5db4a637b23879ceacea9ed2d33b0486771ffc",
"reference": "9f5db4a637b23879ceacea9ed2d33b0486771ffc",
"shasum": ""
},
"require": {
@@ -3082,31 +3082,35 @@
"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.32.1"
"source": "https://github.com/appwrite/sdk-generator/tree/0.33.7"
},
"time": "2023-04-12T04:43:07+00:00"
"time": "2023-07-12T12:15:43+00:00"
},
{
"name": "doctrine/deprecations",
"version": "v1.0.0",
"version": "v1.1.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/deprecations.git",
"reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de"
"reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
"reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/612a3ee5ab0d5dd97b7cf3874a6efe24325efac3",
"reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3",
"shasum": ""
},
"require": {
"php": "^7.1|^8.0"
"php": "^7.1 || ^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^9",
"phpunit/phpunit": "^7.5|^8.5|^9.5",
"psr/log": "^1|^2|^3"
"phpstan/phpstan": "1.4.10 || 1.10.15",
"phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
"psalm/plugin-phpunit": "0.18.4",
"psr/log": "^1 || ^2 || ^3",
"vimeo/psalm": "4.30.0 || 5.12.0"
},
"suggest": {
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
@@ -3125,9 +3129,9 @@
"homepage": "https://www.doctrine-project.org/",
"support": {
"issues": "https://github.com/doctrine/deprecations/issues",
"source": "https://github.com/doctrine/deprecations/tree/v1.0.0"
"source": "https://github.com/doctrine/deprecations/tree/v1.1.1"
},
"time": "2022-05-02T15:47:09+00:00"
"time": "2023-06-03T09:27:29+00:00"
},
{
"name": "doctrine/instantiator",
@@ -3201,16 +3205,16 @@
},
{
"name": "matthiasmullie/minify",
"version": "1.3.70",
"version": "1.3.71",
"source": {
"type": "git",
"url": "https://github.com/matthiasmullie/minify.git",
"reference": "2807d9f9bece6877577ad44acb5c801bb3ae536b"
"reference": "ae42a47d7fecc1fbb7277b2f2d84c37a33edc3b1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/matthiasmullie/minify/zipball/2807d9f9bece6877577ad44acb5c801bb3ae536b",
"reference": "2807d9f9bece6877577ad44acb5c801bb3ae536b",
"url": "https://api.github.com/repos/matthiasmullie/minify/zipball/ae42a47d7fecc1fbb7277b2f2d84c37a33edc3b1",
"reference": "ae42a47d7fecc1fbb7277b2f2d84c37a33edc3b1",
"shasum": ""
},
"require": {
@@ -3260,7 +3264,7 @@
],
"support": {
"issues": "https://github.com/matthiasmullie/minify/issues",
"source": "https://github.com/matthiasmullie/minify/tree/1.3.70"
"source": "https://github.com/matthiasmullie/minify/tree/1.3.71"
},
"funding": [
{
@@ -3268,7 +3272,7 @@
"type": "github"
}
],
"time": "2022-12-09T12:56:44+00:00"
"time": "2023-04-25T20:33:03+00:00"
},
{
"name": "matthiasmullie/path-converter",
@@ -3384,16 +3388,16 @@
},
{
"name": "nikic/php-parser",
"version": "v4.15.4",
"version": "v4.16.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290"
"reference": "19526a33fb561ef417e822e85f08a00db4059c17"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6bb5176bc4af8bcb7d926f88718db9b96a2d4290",
"reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/19526a33fb561ef417e822e85f08a00db4059c17",
"reference": "19526a33fb561ef417e822e85f08a00db4059c17",
"shasum": ""
},
"require": {
@@ -3434,9 +3438,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.15.4"
"source": "https://github.com/nikic/PHP-Parser/tree/v4.16.0"
},
"time": "2023-03-05T19:49:14+00:00"
"time": "2023-06-25T14:52:30+00:00"
},
{
"name": "phar-io/manifest",
@@ -3661,16 +3665,16 @@
},
{
"name": "phpdocumentor/type-resolver",
"version": "1.7.1",
"version": "1.7.2",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "dfc078e8af9c99210337325ff5aa152872c98714"
"reference": "b2fe4d22a5426f38e014855322200b97b5362c0d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/dfc078e8af9c99210337325ff5aa152872c98714",
"reference": "dfc078e8af9c99210337325ff5aa152872c98714",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b2fe4d22a5426f38e014855322200b97b5362c0d",
"reference": "b2fe4d22a5426f38e014855322200b97b5362c0d",
"shasum": ""
},
"require": {
@@ -3713,9 +3717,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.7.1"
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.2"
},
"time": "2023-03-27T19:02:04+00:00"
"time": "2023-05-30T18:13:47+00:00"
},
{
"name": "phpspec/prophecy",
@@ -3787,22 +3791,24 @@
},
{
"name": "phpstan/phpdoc-parser",
"version": "1.18.1",
"version": "1.22.1",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git",
"reference": "22dcdfd725ddf99583bfe398fc624ad6c5004a0f"
"reference": "65c39594fbd8c67abfc68bb323f86447bab79cc0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/22dcdfd725ddf99583bfe398fc624ad6c5004a0f",
"reference": "22dcdfd725ddf99583bfe398fc624ad6c5004a0f",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/65c39594fbd8c67abfc68bb323f86447bab79cc0",
"reference": "65c39594fbd8c67abfc68bb323f86447bab79cc0",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"require-dev": {
"doctrine/annotations": "^2.0",
"nikic/php-parser": "^4.15",
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "^1.5",
@@ -3826,9 +3832,9 @@
"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"
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.22.1"
},
"time": "2023-04-07T11:51:11+00:00"
"time": "2023-06-29T20:46:06+00:00"
},
{
"name": "phpunit/php-code-coverage",
@@ -4551,16 +4557,16 @@
},
{
"name": "sebastian/diff",
"version": "4.0.4",
"version": "4.0.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/diff.git",
"reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d"
"reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d",
"reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
"reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
"shasum": ""
},
"require": {
@@ -4605,7 +4611,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/diff/issues",
"source": "https://github.com/sebastianbergmann/diff/tree/4.0.4"
"source": "https://github.com/sebastianbergmann/diff/tree/4.0.5"
},
"funding": [
{
@@ -4613,7 +4619,7 @@
"type": "github"
}
],
"time": "2020-10-26T13:10:38+00:00"
"time": "2023-05-07T05:35:17+00:00"
},
{
"name": "sebastian/environment",
@@ -5580,16 +5586,16 @@
},
{
"name": "twig/twig",
"version": "v3.5.1",
"version": "v3.6.1",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "a6e0510cc793912b451fd40ab983a1d28f611c15"
"reference": "7e7d5839d4bec168dfeef0ac66d5c5a2edbabffd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/a6e0510cc793912b451fd40ab983a1d28f611c15",
"reference": "a6e0510cc793912b451fd40ab983a1d28f611c15",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/7e7d5839d4bec168dfeef0ac66d5c5a2edbabffd",
"reference": "7e7d5839d4bec168dfeef0ac66d5c5a2edbabffd",
"shasum": ""
},
"require": {
@@ -5598,15 +5604,10 @@
"symfony/polyfill-mbstring": "^1.3"
},
"require-dev": {
"psr/container": "^1.0",
"psr/container": "^1.0|^2.0",
"symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.5-dev"
}
},
"autoload": {
"psr-4": {
"Twig\\": "src/"
@@ -5640,7 +5641,7 @@
],
"support": {
"issues": "https://github.com/twigphp/Twig/issues",
"source": "https://github.com/twigphp/Twig/tree/v3.5.1"
"source": "https://github.com/twigphp/Twig/tree/v3.6.1"
},
"funding": [
{
@@ -5652,7 +5653,7 @@
"type": "tidelift"
}
],
"time": "2023-02-08T07:49:20+00:00"
"time": "2023-06-08T12:52:13+00:00"
}
],
"aliases": [],
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Account account = new Account(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Avatars avatars = new Avatars(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Avatars avatars = new Avatars(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Avatars avatars = new Avatars(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Avatars avatars = new Avatars(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Avatars avatars = new Avatars(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Avatars avatars = new Avatars(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Avatars avatars = new Avatars(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Databases databases = new Databases(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Databases databases = new Databases(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Databases databases = new Databases(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Databases databases = new Databases(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Databases databases = new Databases(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Functions functions = new Functions(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Functions functions = new Functions(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Functions functions = new Functions(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Locale locale = new Locale(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Locale locale = new Locale(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Locale locale = new Locale(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Locale locale = new Locale(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Locale locale = new Locale(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Locale locale = new Locale(client);
@@ -13,7 +13,7 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
Client client = new Client(getApplicationContext())
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
.setProject("5df5acd0d48c2"); // Your project ID
Locale locale = new Locale(client);

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