mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Merge branch '1.6.x' into feat-1.5.x-mfa-emails
# Conflicts: # composer.lock
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
name: Nightly Security Scan
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *' # 12am UTC daily runtime
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
scan-image:
|
||||
name: Scan Docker Image
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build the Docker image
|
||||
run: docker build . -t appwrite_image:latest
|
||||
- name: Run Trivy vulnerability scanner on image
|
||||
uses: aquasecurity/trivy-action@0.20.0
|
||||
with:
|
||||
image-ref: 'appwrite_image:latest'
|
||||
format: 'sarif'
|
||||
output: 'trivy-image-results.sarif'
|
||||
ignore-unfixed: 'false'
|
||||
severity: 'CRITICAL,HIGH'
|
||||
- name: Upload Docker Image Scan Results
|
||||
uses: github/codeql-action/upload-sarif@v2
|
||||
with:
|
||||
sarif_file: 'trivy-image-results.sarif'
|
||||
|
||||
scan-code:
|
||||
name: Scan Code
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
- name: Run Trivy vulnerability scanner on filesystem
|
||||
uses: aquasecurity/trivy-action@0.20.0
|
||||
with:
|
||||
scan-type: 'fs'
|
||||
format: 'sarif'
|
||||
output: 'trivy-fs-results.sarif'
|
||||
severity: 'CRITICAL,HIGH'
|
||||
- name: Upload Code Scan Results
|
||||
uses: github/codeql-action/upload-sarif@v2
|
||||
with:
|
||||
sarif_file: 'trivy-fs-results.sarif'
|
||||
@@ -1,17 +1,22 @@
|
||||
name: PR Security Scan
|
||||
on:
|
||||
pull_request:
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, synchronize, reopened]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
scan:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Check out code
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
fetch-depth: 0
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: Build the Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
@@ -19,6 +24,7 @@ jobs:
|
||||
push: false
|
||||
load: true
|
||||
tags: pr_image:${{ github.sha }}
|
||||
|
||||
- name: Run Trivy vulnerability scanner on image
|
||||
uses: aquasecurity/trivy-action@0.20.0
|
||||
with:
|
||||
@@ -26,6 +32,7 @@ jobs:
|
||||
format: 'json'
|
||||
output: 'trivy-image-results.json'
|
||||
severity: 'CRITICAL,HIGH'
|
||||
|
||||
- name: Run Trivy vulnerability scanner on source code
|
||||
uses: aquasecurity/trivy-action@0.20.0
|
||||
with:
|
||||
@@ -34,10 +41,11 @@ jobs:
|
||||
format: 'json'
|
||||
output: 'trivy-fs-results.json'
|
||||
severity: 'CRITICAL,HIGH'
|
||||
- name: Process and post Trivy scan results
|
||||
|
||||
- name: Process Trivy scan results
|
||||
id: process-results
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
let commentBody = '## Security Scan Results for PR\n\n';
|
||||
@@ -79,9 +87,19 @@ jobs:
|
||||
commentBody += 'Please contact the core team for assistance.';
|
||||
}
|
||||
|
||||
github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: commentBody
|
||||
});
|
||||
core.setOutput('comment-body', commentBody);
|
||||
- name: Find Comment
|
||||
uses: peter-evans/find-comment@v3
|
||||
id: fc
|
||||
with:
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
comment-author: 'github-actions[bot]'
|
||||
body-includes: Security Scan Results for PR
|
||||
|
||||
- name: Create or update comment
|
||||
uses: peter-evans/create-or-update-comment@v3
|
||||
with:
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
comment-id: ${{ steps.fc.outputs.comment-id }}
|
||||
body: ${{ steps.process-results.outputs.comment-body }}
|
||||
edit-mode: replace
|
||||
|
||||
+142
@@ -1,3 +1,145 @@
|
||||
# Version 1.6.0
|
||||
|
||||
## What's Changed
|
||||
|
||||
### Notable changes
|
||||
|
||||
* Allow execution filter attributes in [#7607](https://github.com/appwrite/appwrite/pull/7607)
|
||||
* Add dynamic API keys for function executions in [#7512](https://github.com/appwrite/appwrite/pull/7512)
|
||||
* Add metrics for successful and failed builds in [#8210](https://github.com/appwrite/appwrite/pull/8210)
|
||||
* Update logging config to use a DSN approach in [#8187](https://github.com/appwrite/appwrite/pull/8187)
|
||||
* Add projects.createJWT endpoint for dynamic keys in [#8213](https://github.com/appwrite/appwrite/pull/8213)
|
||||
* Add users.createJWT() endpoint for local function development in [#8207](https://github.com/appwrite/appwrite/pull/8207)
|
||||
* Added cancel build endpoint in [#7605](https://github.com/appwrite/appwrite/pull/7605)
|
||||
* Add CLI as a function deployment type in [#8215](https://github.com/appwrite/appwrite/pull/8215)
|
||||
* Add vcs.getRepositoryContents() endpoint in [#8330](https://github.com/appwrite/appwrite/pull/8330)
|
||||
* Add appwrite version in function variables in [#8336](https://github.com/appwrite/appwrite/pull/8336)
|
||||
* Add support for scheduled executions in [#8243](https://github.com/appwrite/appwrite/pull/8243)
|
||||
* Add endpoint to delete execution in [#8337](https://github.com/appwrite/appwrite/pull/8337)
|
||||
* OPR v4 support in [#8323](https://github.com/appwrite/appwrite/pull/8323)
|
||||
* Mock OTP and phone numbers in [#7565](https://github.com/appwrite/appwrite/pull/7565)
|
||||
* Support scheduled executions in [#8355](https://github.com/appwrite/appwrite/pull/8355)
|
||||
* Add alert for new sessions in [#8315](https://github.com/appwrite/appwrite/pull/8315)
|
||||
* Update delete authenticator to remove OTP Validation in [#8367](https://github.com/appwrite/appwrite/pull/8367)
|
||||
* Track project last activity in [#8366](https://github.com/appwrite/appwrite/pull/8366)
|
||||
* Containerize the console in [#8406](https://github.com/appwrite/appwrite/pull/8406)
|
||||
* Implement MBSeconds Metric on 1.5.X in [#8385](https://github.com/appwrite/appwrite/pull/8385)
|
||||
* Support JWTs without session ID in [#8420](https://github.com/appwrite/appwrite/pull/8420)
|
||||
* 1.6.x sdks in [#8359](https://github.com/appwrite/appwrite/pull/8359)
|
||||
* Base migration for 1.6.x in [#8417](https://github.com/appwrite/appwrite/pull/8417)
|
||||
* 1.6.x migrations and filters in [#8403](https://github.com/appwrite/appwrite/pull/8403)
|
||||
* Add APPWRITE_REGION in function variables in [#8394](https://github.com/appwrite/appwrite/pull/8394)
|
||||
* Support dynamic keys for domain executions in [#8428](https://github.com/appwrite/appwrite/pull/8428)
|
||||
* Bump DBIP to latest version in [#8467](https://github.com/appwrite/appwrite/pull/8467)
|
||||
* Automatically restart function on crash in [#8473](https://github.com/appwrite/appwrite/pull/8473)
|
||||
* Don't send session alerts for otp and magic-url logins in [#8459](https://github.com/appwrite/appwrite/pull/8459)
|
||||
* Mark 4XX executions as successful in [#8493](https://github.com/appwrite/appwrite/pull/8493)
|
||||
* Add dynamic keys in builds in [#8492](https://github.com/appwrite/appwrite/pull/8492)
|
||||
* Allow deployment queries on type and size in [#8515](https://github.com/appwrite/appwrite/pull/8515)
|
||||
* Add OTP email template in [#8501](https://github.com/appwrite/appwrite/pull/8501)
|
||||
* Update console links in [#8523](https://github.com/appwrite/appwrite/pull/8523)
|
||||
* Add multipart support in [#8477](https://github.com/appwrite/appwrite/pull/8477)
|
||||
* Separate deployment sizes in [#8556](https://github.com/appwrite/appwrite/pull/8556)
|
||||
* Add go runtime in [#8572](https://github.com/appwrite/appwrite/pull/8572)
|
||||
* Add react native platform in [#8562](https://github.com/appwrite/appwrite/pull/8562)
|
||||
* Merge deployments and build storage metrics together in API in [#8443](https://github.com/appwrite/appwrite/pull/8443)
|
||||
* Support string attribute resizing in [#8597](https://github.com/appwrite/appwrite/pull/8597)
|
||||
* Support renaming attributes in [#8544](https://github.com/appwrite/appwrite/pull/8544)
|
||||
* Add VCS vars to deployments & executions in [#8631](https://github.com/appwrite/appwrite/pull/8631)
|
||||
* Function storage metrics in [#8668](https://github.com/appwrite/appwrite/pull/8668)
|
||||
* External messaging usage count in [#8672](https://github.com/appwrite/appwrite/pull/8672)
|
||||
|
||||
### Fixes
|
||||
|
||||
* Fix execution duration in [#8357](https://github.com/appwrite/appwrite/pull/8357)
|
||||
* Fix file size calculations in [#8432](https://github.com/appwrite/appwrite/pull/8432)
|
||||
* Fix disabled function logging in [#8398](https://github.com/appwrite/appwrite/pull/8398)
|
||||
* Fix function redeployments in [#8434](https://github.com/appwrite/appwrite/pull/8434)
|
||||
* Add value to variables template in [#8483](https://github.com/appwrite/appwrite/pull/8483)
|
||||
* Fix build size limits in [#8396](https://github.com/appwrite/appwrite/pull/8396)
|
||||
* Fix deployment method name in [#8490](https://github.com/appwrite/appwrite/pull/8490)
|
||||
* Fix function disconnecting from git in [#8500](https://github.com/appwrite/appwrite/pull/8500)
|
||||
* Increase buckets metadata in [#8452](https://github.com/appwrite/appwrite/pull/8452)
|
||||
* Fix deploy from git with space in [#8517](https://github.com/appwrite/appwrite/pull/8517)
|
||||
* Fix missing build logs in [#8484](https://github.com/appwrite/appwrite/pull/8484)
|
||||
* Delete team memberships synchronously in [#8217](https://github.com/appwrite/appwrite/pull/8217)
|
||||
* Fix Anyof validator in specs in [#8543](https://github.com/appwrite/appwrite/pull/8543)
|
||||
* Fix missing function variables in [#8554](https://github.com/appwrite/appwrite/pull/8554)
|
||||
* Fix deadlock in [#8609](https://github.com/appwrite/appwrite/pull/8609)
|
||||
* Fix domain execution stats in [#8608](https://github.com/appwrite/appwrite/pull/8608)
|
||||
* Update console redirect to include query params in [#8619](https://github.com/appwrite/appwrite/pull/8619)
|
||||
* Update abuse-key for mfa challenge endpoints in [#8649](https://github.com/appwrite/appwrite/pull/8649)
|
||||
* Fix cross-project scheduler stability in [#8641](https://github.com/appwrite/appwrite/pull/8641)
|
||||
* Fix vcs deployment size in [#8640](https://github.com/appwrite/appwrite/pull/8640)
|
||||
* Fix logging behaviour for Functions in [#8627](https://github.com/appwrite/appwrite/pull/8627)
|
||||
* Add retention env vars to deletes worker in [#8662](https://github.com/appwrite/appwrite/pull/8662)
|
||||
* Fix scheduled executions data in [#8639](https://github.com/appwrite/appwrite/pull/8639)
|
||||
|
||||
### Miscellaneous
|
||||
|
||||
* Sync 1.6.x with main in [#8163](https://github.com/appwrite/appwrite/pull/8163)
|
||||
* Remove build ID from rebuild deployment endpoint in [#8214](https://github.com/appwrite/appwrite/pull/8214)
|
||||
* 1.6.x specs in [#8304](https://github.com/appwrite/appwrite/pull/8304)
|
||||
* Sync with main in [#8295](https://github.com/appwrite/appwrite/pull/8295)
|
||||
* Fix 1.6.x failing tests in [#8333](https://github.com/appwrite/appwrite/pull/8333)
|
||||
* Ensure CI/CD works in [#8350](https://github.com/appwrite/appwrite/pull/8350)
|
||||
* Update specs in [#8356](https://github.com/appwrite/appwrite/pull/8356)
|
||||
* Sync main to 1.6.x in [#8430](https://github.com/appwrite/appwrite/pull/8430)
|
||||
* Add scheduledAt in execution response model in [#8425](https://github.com/appwrite/appwrite/pull/8425)
|
||||
* Move functions marketplace to appwrite in [#8427](https://github.com/appwrite/appwrite/pull/8427)
|
||||
* Refactor deployment check in function tests in [#8444](https://github.com/appwrite/appwrite/pull/8444)
|
||||
* Add ci/cd benchmark in [#8414](https://github.com/appwrite/appwrite/pull/8414)
|
||||
* Upgrade SDK version in [#8465](https://github.com/appwrite/appwrite/pull/8465)
|
||||
* Improve session alert in [#8399](https://github.com/appwrite/appwrite/pull/8399)
|
||||
* Address review comments in [#8422](https://github.com/appwrite/appwrite/pull/8422)
|
||||
* Add scopes to function template in [#8496](https://github.com/appwrite/appwrite/pull/8496)
|
||||
* Update benchmark comment in [#8507](https://github.com/appwrite/appwrite/pull/8507)
|
||||
* Add key to runtime model in [#8503](https://github.com/appwrite/appwrite/pull/8503)
|
||||
* Upgrade logger in [#8497](https://github.com/appwrite/appwrite/pull/8497)
|
||||
* Change default email addresses in [#8466](https://github.com/appwrite/appwrite/pull/8466)
|
||||
* Improve scheduled executions in [#8412](https://github.com/appwrite/appwrite/pull/8412)
|
||||
* Sync 1.5.x into main in [#8509](https://github.com/appwrite/appwrite/pull/8509)
|
||||
* Sync 1.6 with main in [#8529](https://github.com/appwrite/appwrite/pull/8529)
|
||||
* Fix templates CORS in [#8528](https://github.com/appwrite/appwrite/pull/8528)
|
||||
* Update size to specification for variable runtimes in [#8537](https://github.com/appwrite/appwrite/pull/8537)
|
||||
* Add boundary to multipart header in [#8539](https://github.com/appwrite/appwrite/pull/8539)
|
||||
* Support manual templates in [#8527](https://github.com/appwrite/appwrite/pull/8527)
|
||||
* Reorder runtimes in [#8540](https://github.com/appwrite/appwrite/pull/8540)
|
||||
* Fix 1.6 bugs in [#8358](https://github.com/appwrite/appwrite/pull/8358)
|
||||
* Add seconds precision to scheduledAt in [#8546](https://github.com/appwrite/appwrite/pull/8546)
|
||||
* Update docker base image in [#8485](https://github.com/appwrite/appwrite/pull/8485)
|
||||
* Update create execution return type in [#8542](https://github.com/appwrite/appwrite/pull/8542)
|
||||
* Default fallback to for templateBranch in [#8547](https://github.com/appwrite/appwrite/pull/8547)
|
||||
* Fix env vars functions test in [#8555](https://github.com/appwrite/appwrite/pull/8555)
|
||||
* Fix session alerts in [#8550](https://github.com/appwrite/appwrite/pull/8550)
|
||||
* Add runtime controls in [#8384](https://github.com/appwrite/appwrite/pull/8384)
|
||||
* Revert request type to json in create execution in [#8563](https://github.com/appwrite/appwrite/pull/8563)
|
||||
* Sync 1.6.x Filters and Migrations with latest in [#8553](https://github.com/appwrite/appwrite/pull/8553)
|
||||
* Update sdks in [#8551](https://github.com/appwrite/appwrite/pull/8551)
|
||||
* Update Docs in [#8567](https://github.com/appwrite/appwrite/pull/8567)
|
||||
* Headers validator benchmark in [#8561](https://github.com/appwrite/appwrite/pull/8561)
|
||||
* Fix go version in [#8571](https://github.com/appwrite/appwrite/pull/8571)
|
||||
* Update dependencies in [#8574](https://github.com/appwrite/appwrite/pull/8574)
|
||||
* Upgrade console in [#8575](https://github.com/appwrite/appwrite/pull/8575)
|
||||
* 1.6.x logging test in [#8580](https://github.com/appwrite/appwrite/pull/8580)
|
||||
* Bump console sdk in [#8581](https://github.com/appwrite/appwrite/pull/8581)
|
||||
* Update sdks in [#8582](https://github.com/appwrite/appwrite/pull/8582)
|
||||
* Add changelogs for dart and flutter in [#8587](https://github.com/appwrite/appwrite/pull/8587)
|
||||
* Add payload validator in [#8594](https://github.com/appwrite/appwrite/pull/8594)
|
||||
* Update geodb in [#8615](https://github.com/appwrite/appwrite/pull/8615)
|
||||
* Update createdeployment methodtype to upload in [#8616](https://github.com/appwrite/appwrite/pull/8616)
|
||||
* Remove tenant in document filter in [#8624](https://github.com/appwrite/appwrite/pull/8624)
|
||||
* Improve mail datetime format in [#8628](https://github.com/appwrite/appwrite/pull/8628)
|
||||
* Fix router function execution logging in [#8625](https://github.com/appwrite/appwrite/pull/8625)
|
||||
* Add Functions templates async test in [#8622](https://github.com/appwrite/appwrite/pull/8622)
|
||||
* Update console in [#8629](https://github.com/appwrite/appwrite/pull/8629)
|
||||
* 1.6.1 in [#8630](https://github.com/appwrite/appwrite/pull/8630)
|
||||
* Update version in [#8646](https://github.com/appwrite/appwrite/pull/8646)
|
||||
* Phone auth metric rename in [#8648](https://github.com/appwrite/appwrite/pull/8648)
|
||||
* Pretty print specs in [#8643](https://github.com/appwrite/appwrite/pull/8643)
|
||||
* Fix messaging metrics in [#8674](https://github.com/appwrite/appwrite/pull/8674)
|
||||
* Bump console to 5.0.6 in [#8585](https://github.com/appwrite/appwrite/pull/8585)
|
||||
|
||||
# Version 1.5.10
|
||||
|
||||
## What's Changed
|
||||
|
||||
@@ -319,10 +319,16 @@ These are the current metrics we collect usage stats for:
|
||||
| users | Total number of users per project|
|
||||
| executions | Total number of executions per project |
|
||||
| databases | Total number of databases per project |
|
||||
| databases.storage | Total amount of storage used by all databases per project (in bytes) |
|
||||
| databases.storage_disk | Total amount of storage used by all database per project on disk (in bytes) |
|
||||
| collections | Total number of collections per project |
|
||||
| {databaseInternalId}.collections | Total number of collections per database|
|
||||
| {databaseInternalId}.storage | Sum of database storage (in bytes) |
|
||||
| {databaseInternalId}.storage_disk | Sum of database storage on disk (in bytes) |
|
||||
| documents | Total number of documents per project |
|
||||
| {databaseInternalId}.{collectionInternalId}.documents | Total number of documents per collection |
|
||||
| {databaseInternalId}.{collectionInternalId}.storage | Sum of database storage used by the collection (in bytes) |
|
||||
| {databsaeInternalId}.{collectionInternalId}.storage_disk | Sum of database storage used by the collection on disk (in bytes) |
|
||||
| buckets | Total number of buckets per project |
|
||||
| files | Total number of files per project |
|
||||
| {bucketInternalId}.files.storage | Sum of files.storage per bucket (in bytes) |
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
FROM composer:2.0 as composer
|
||||
FROM composer:2.0 AS composer
|
||||
|
||||
ARG TESTING=false
|
||||
ENV TESTING=$TESTING
|
||||
@@ -12,7 +12,7 @@ RUN composer install --ignore-platform-reqs --optimize-autoloader \
|
||||
--no-plugins --no-scripts --prefer-dist \
|
||||
`if [ "$TESTING" != "true" ]; then echo "--no-dev"; fi`
|
||||
|
||||
FROM appwrite/base:0.9.2 as final
|
||||
FROM appwrite/base:0.9.3 AS final
|
||||
|
||||
LABEL maintainer="team@appwrite.io"
|
||||
|
||||
|
||||
+3
-3
@@ -67,7 +67,7 @@ docker run -it --rm \
|
||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
|
||||
--entrypoint="install" \
|
||||
appwrite/appwrite:1.5.10
|
||||
appwrite/appwrite:1.6.0
|
||||
```
|
||||
|
||||
### Windows
|
||||
@@ -79,7 +79,7 @@ docker run -it --rm ^
|
||||
--volume //var/run/docker.sock:/var/run/docker.sock ^
|
||||
--volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^
|
||||
--entrypoint="install" ^
|
||||
appwrite/appwrite:1.5.10
|
||||
appwrite/appwrite:1.6.0
|
||||
```
|
||||
|
||||
#### PowerShell
|
||||
@@ -89,7 +89,7 @@ docker run -it --rm `
|
||||
--volume /var/run/docker.sock:/var/run/docker.sock `
|
||||
--volume ${pwd}/appwrite:/usr/src/code/appwrite:rw `
|
||||
--entrypoint="install" `
|
||||
appwrite/appwrite:1.5.10
|
||||
appwrite/appwrite:1.6.0
|
||||
```
|
||||
|
||||
运行后,可以在浏览器上访问 http://localhost 找到 Appwrite 控制台。在非 Linux 的本机主机上完成安装后,服务器可能需要几分钟才能启动。
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
> Our Appwrite Init event has concluded. You can check out all the new and upcoming features [on our Init website](https://appwrite.io/init) 🚀
|
||||
> Appwrite Init has concluded! You can check out all the latest announcements [on our Init website](https://appwrite.io/init) 🚀
|
||||
|
||||
<br />
|
||||
<p align="center">
|
||||
@@ -75,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.5.10
|
||||
appwrite/appwrite:1.6.0
|
||||
```
|
||||
|
||||
### Windows
|
||||
@@ -87,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.5.10
|
||||
appwrite/appwrite:1.6.0
|
||||
```
|
||||
|
||||
#### PowerShell
|
||||
@@ -97,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.5.10
|
||||
appwrite/appwrite:1.6.0
|
||||
```
|
||||
|
||||
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.
|
||||
@@ -134,6 +134,12 @@ Choose from one of the providers below:
|
||||
<br /><sub><b>Akamai Compute</b></sub></a>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" width="100" height="100">
|
||||
<a href="https://aws.amazon.com/marketplace/pp/prodview-2hiaeo2px4md6">
|
||||
<img width="50" height="39" src="public/images/integrations/aws-logo.svg" alt="AWS Logo" />
|
||||
<br /><sub><b>AWS Marketplace</b></sub></a>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
+7
-1
@@ -1,12 +1,12 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/init.php';
|
||||
require_once __DIR__ . '/controllers/general.php';
|
||||
|
||||
use Appwrite\Event\Certificate;
|
||||
use Appwrite\Event\Delete;
|
||||
use Appwrite\Event\Func;
|
||||
use Appwrite\Platform\Appwrite;
|
||||
use Appwrite\Runtimes\Runtimes;
|
||||
use Utopia\Cache\Adapter\Sharding;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\CLI\CLI;
|
||||
@@ -23,6 +23,12 @@ use Utopia\Queue\Connection;
|
||||
use Utopia\Registry\Registry;
|
||||
use Utopia\System\System;
|
||||
|
||||
// overwriting runtimes to be architectur agnostic for CLI
|
||||
Config::setParam('runtimes', (new Runtimes('v4'))->getAll(supported: false));
|
||||
|
||||
// require controllers after overwriting runtimes
|
||||
require_once __DIR__ . '/controllers/general.php';
|
||||
|
||||
Authorization::disable();
|
||||
|
||||
CLI::setResource('register', fn () => $register);
|
||||
|
||||
@@ -699,6 +699,11 @@ return [
|
||||
'description' => 'The relationship value is invalid.',
|
||||
'code' => 400,
|
||||
],
|
||||
Exception::ATTRIBUTE_INVALID_RESIZE => [
|
||||
'name' => Exception::ATTRIBUTE_INVALID_RESIZE,
|
||||
'description' => "Existing data is too large for new size, truncate your existing data then try again.",
|
||||
'code' => 400,
|
||||
],
|
||||
|
||||
/** Indexes */
|
||||
Exception::INDEX_NOT_FOUND => [
|
||||
|
||||
@@ -82,7 +82,7 @@ return [
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => [],
|
||||
'scopes' => ["users.read"]
|
||||
'scopes' => ['users.read']
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-upstash',
|
||||
@@ -125,7 +125,8 @@ return [
|
||||
'required' => true,
|
||||
'type' => 'password'
|
||||
]
|
||||
]
|
||||
],
|
||||
'scopes' => []
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-redis',
|
||||
@@ -167,7 +168,8 @@ return [
|
||||
'required' => true,
|
||||
'type' => 'password'
|
||||
]
|
||||
]
|
||||
],
|
||||
'scopes' => []
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-neo4j',
|
||||
@@ -217,7 +219,8 @@ return [
|
||||
'required' => true,
|
||||
'type' => 'password'
|
||||
]
|
||||
]
|
||||
],
|
||||
'scopes' => []
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-mongodb',
|
||||
@@ -253,7 +256,8 @@ return [
|
||||
'required' => true,
|
||||
'type' => 'password'
|
||||
]
|
||||
]
|
||||
],
|
||||
'scopes' => []
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-neon',
|
||||
@@ -320,7 +324,8 @@ return [
|
||||
'required' => true,
|
||||
'type' => 'text'
|
||||
]
|
||||
]
|
||||
],
|
||||
'scopes' => []
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-open-ai',
|
||||
@@ -380,7 +385,8 @@ return [
|
||||
'required' => false,
|
||||
'type' => 'number'
|
||||
]
|
||||
]
|
||||
],
|
||||
'scopes' => []
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-discord',
|
||||
@@ -442,7 +448,8 @@ return [
|
||||
'required' => true,
|
||||
'type' => 'password'
|
||||
]
|
||||
]
|
||||
],
|
||||
'scopes' => []
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-perspective-api',
|
||||
@@ -476,7 +483,8 @@ return [
|
||||
'required' => true,
|
||||
'type' => 'password'
|
||||
]
|
||||
]
|
||||
],
|
||||
'scopes' => []
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-pangea',
|
||||
@@ -523,7 +531,8 @@ return [
|
||||
'required' => true,
|
||||
'type' => 'password'
|
||||
]
|
||||
]
|
||||
],
|
||||
'scopes' => []
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-document',
|
||||
@@ -543,7 +552,8 @@ return [
|
||||
'providerRepositoryId' => 'templates',
|
||||
'providerOwner' => 'appwrite',
|
||||
'providerVersion' => '0.2.*',
|
||||
'variables' => []
|
||||
'variables' => [],
|
||||
'scopes' => []
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-github',
|
||||
@@ -586,7 +596,8 @@ return [
|
||||
'required' => true,
|
||||
'type' => 'password'
|
||||
]
|
||||
]
|
||||
],
|
||||
'scopes' => []
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-bookmark',
|
||||
@@ -637,7 +648,7 @@ return [
|
||||
'type' => 'url'
|
||||
]
|
||||
],
|
||||
'scopes' => ["databases.read", "databases.write", "collections.write", "attributes.write", "documents.read", "documents.write"]
|
||||
'scopes' => ['databases.read', 'databases.write', 'collections.write', 'attributes.write', 'documents.read', 'documents.write']
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-algolia',
|
||||
@@ -718,7 +729,7 @@ return [
|
||||
'type' => 'password'
|
||||
],
|
||||
],
|
||||
'scopes' => ["databases.read", "collections.read", "documents.read"]
|
||||
'scopes' => ['databases.read', 'collections.read', 'documents.read']
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-meilisearch',
|
||||
@@ -811,7 +822,7 @@ return [
|
||||
'type' => 'text'
|
||||
],
|
||||
],
|
||||
'scopes' => ["databases.read", "collections.read", "documents.read"]
|
||||
'scopes' => ['databases.read', 'collections.read', 'documents.read']
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-vonage',
|
||||
@@ -896,7 +907,8 @@ return [
|
||||
'required' => true,
|
||||
'type' => 'phone'
|
||||
]
|
||||
]
|
||||
],
|
||||
'scopes' => []
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-bell',
|
||||
@@ -951,7 +963,8 @@ return [
|
||||
'required' => true,
|
||||
'type' => 'url'
|
||||
]
|
||||
]
|
||||
],
|
||||
'scopes' => []
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-mail',
|
||||
@@ -1033,7 +1046,8 @@ return [
|
||||
'required' => false,
|
||||
'type' => 'text'
|
||||
]
|
||||
]
|
||||
],
|
||||
'scopes' => []
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-stripe',
|
||||
@@ -1074,7 +1088,7 @@ return [
|
||||
'type' => 'password'
|
||||
]
|
||||
],
|
||||
'scopes' => ["users.read", "sessions.write", "users.write"]
|
||||
'scopes' => ['users.read', 'sessions.write', 'users.write']
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-stripe',
|
||||
@@ -1131,7 +1145,7 @@ return [
|
||||
'type' => 'text'
|
||||
]
|
||||
],
|
||||
'scopes' => ["databases.read", "databases.write", "collections.write", "attributes.write", "documents.read", "documents.write"]
|
||||
'scopes' => ['databases.read', 'databases.write', 'collections.write', 'attributes.write', 'documents.read', 'documents.write']
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-chat',
|
||||
@@ -1164,7 +1178,8 @@ return [
|
||||
'required' => true,
|
||||
'type' => 'password'
|
||||
]
|
||||
]
|
||||
],
|
||||
'scopes' => []
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-translate',
|
||||
@@ -1197,7 +1212,8 @@ return [
|
||||
'required' => true,
|
||||
'type' => 'password'
|
||||
]
|
||||
]
|
||||
],
|
||||
'scopes' => []
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-eye',
|
||||
@@ -1255,7 +1271,7 @@ return [
|
||||
'type' => 'password'
|
||||
]
|
||||
],
|
||||
'scopes' => ["databases.read", "databases.write", "collections.read", "collections.write", "attributes.write", "documents.read", "documents.write", "buckets.read", "buckets.write", "files.read"]
|
||||
'scopes' => ['databases.read', 'databases.write', 'collections.read', 'collections.write', 'attributes.write', 'documents.read', 'documents.write', 'buckets.read', 'buckets.write', 'files.read']
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-eye',
|
||||
@@ -1313,7 +1329,7 @@ return [
|
||||
'type' => 'password'
|
||||
]
|
||||
],
|
||||
"scopes" => ["databases.read", "databases.write", "collections.read", "collections.write", "attributes.write", "documents.read", "documents.write", "buckets.read", "buckets.write", "files.read"]
|
||||
'scopes' => ['databases.read', 'databases.write', 'collections.read', 'collections.write', 'attributes.write', 'documents.read', 'documents.write', 'buckets.read', 'buckets.write', 'files.read']
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-text',
|
||||
@@ -1371,7 +1387,7 @@ return [
|
||||
'type' => 'password'
|
||||
]
|
||||
],
|
||||
"scopes" => ["databases.read", "databases.write", "collections.read", "collections.write", "attributes.write", "documents.read", "documents.write", "buckets.read", "buckets.write", "files.read"]
|
||||
'scopes' => ['databases.read', 'databases.write', 'collections.read', 'collections.write', 'attributes.write', 'documents.read', 'documents.write', 'buckets.read', 'buckets.write', 'files.read']
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-chat',
|
||||
@@ -1429,7 +1445,7 @@ return [
|
||||
'type' => 'password'
|
||||
]
|
||||
],
|
||||
"scopes" => ["buckets.read", "buckets.write", "files.read", "files.write"]
|
||||
'scopes' => ['buckets.read', 'buckets.write', 'files.read', 'files.write']
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-chip',
|
||||
@@ -1463,7 +1479,8 @@ return [
|
||||
'required' => true,
|
||||
'type' => 'password'
|
||||
]
|
||||
]
|
||||
],
|
||||
'scopes' => []
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-chip',
|
||||
@@ -1505,7 +1522,7 @@ return [
|
||||
'type' => 'text'
|
||||
]
|
||||
],
|
||||
"scopes" => ["buckets.write", "files.read", "files.write"]
|
||||
'scopes' => ['buckets.write', 'files.read', 'files.write']
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-chip',
|
||||
@@ -1579,7 +1596,8 @@ return [
|
||||
'required' => true,
|
||||
'type' => 'password'
|
||||
]
|
||||
]
|
||||
],
|
||||
'scopes' => []
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-document-search',
|
||||
@@ -1642,7 +1660,7 @@ return [
|
||||
'type' => 'text'
|
||||
]
|
||||
],
|
||||
"scopes" => ["databases.read", "collections.read", "documents.read"]
|
||||
'scopes' => ['databases.read', 'collections.read', 'documents.read']
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-chip',
|
||||
@@ -1705,7 +1723,7 @@ return [
|
||||
'type' => 'text'
|
||||
]
|
||||
],
|
||||
"scopes" => ["databases.read", "collections.read", "documents.read"]
|
||||
'scopes' => ['databases.read', 'collections.read', 'documents.read']
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-chat',
|
||||
@@ -1760,7 +1778,7 @@ return [
|
||||
'type' => 'text'
|
||||
]
|
||||
],
|
||||
"scopes" => ["buckets.read", "buckets.write", "files.read", "files.write"]
|
||||
'scopes' => ['buckets.read', 'buckets.write', 'files.read', 'files.write']
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-chip',
|
||||
@@ -1801,7 +1819,7 @@ return [
|
||||
'type' => 'text'
|
||||
]
|
||||
],
|
||||
"scopes" => ["buckets.read", "buckets.write", "files.read", "files.write"]
|
||||
'scopes' => ['buckets.read', 'buckets.write', 'files.read', 'files.write']
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-chip',
|
||||
@@ -1841,7 +1859,8 @@ return [
|
||||
'required' => false,
|
||||
'type' => 'number'
|
||||
]
|
||||
]
|
||||
],
|
||||
'scopes' => []
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-music-note',
|
||||
@@ -1883,7 +1902,7 @@ return [
|
||||
'type' => 'password'
|
||||
]
|
||||
],
|
||||
"scopes" => ["buckets.read", "buckets.write", "files.read", "files.write"]
|
||||
'scopes' => ['buckets.read', 'buckets.write', 'files.read', 'files.write']
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-chip',
|
||||
@@ -1917,7 +1936,8 @@ return [
|
||||
'required' => true,
|
||||
'type' => 'password'
|
||||
]
|
||||
]
|
||||
],
|
||||
'scopes' => []
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-currency-dollar',
|
||||
@@ -1972,7 +1992,7 @@ return [
|
||||
'type' => 'text'
|
||||
]
|
||||
],
|
||||
"scopes" => ["users.read", "users.write"]
|
||||
'scopes' => ['users.read', 'users.write']
|
||||
],
|
||||
[
|
||||
'icon' => 'icon-currency-dollar',
|
||||
@@ -2043,6 +2063,6 @@ return [
|
||||
'type' => 'text'
|
||||
]
|
||||
],
|
||||
"scopes" => ["users.read", "users.write"]
|
||||
'scopes' => ['users.read', 'users.write']
|
||||
]
|
||||
];
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"emails.magicSession.signature": "{{project}} team",
|
||||
"emails.sessionAlert.subject": "Security alert: new session on your {{project}} account",
|
||||
"emails.sessionAlert.hello":"Hello {{user}}",
|
||||
"emails.sessionAlert.body": "A new session has been created on your {{b}}{{project}}{{/b}} account, on {{b}}{{dateTime}}{{/b}}.\nHere are the details of the new session: ",
|
||||
"emails.sessionAlert.body": "A new session has been created on your {{b}}{{project}}{{/b}} account, {{b}}on {{date}}, {{year}} at {{time}} UTC{{/b}}.\nHere are the details of the new session: ",
|
||||
"emails.sessionAlert.listDevice": "Device: {{b}}{{device}}{{/b}}",
|
||||
"emails.sessionAlert.listIpAddress": "IP Address: {{b}}{{ipAddress}}{{/b}}",
|
||||
"emails.sessionAlert.listCountry": "Country: {{b}}{{country}}{{/b}}",
|
||||
|
||||
+10
-10
@@ -203,7 +203,7 @@ return [
|
||||
[
|
||||
'key' => 'web',
|
||||
'name' => 'Console',
|
||||
'version' => '1.0.1',
|
||||
'version' => '1.1.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-console',
|
||||
'package' => '',
|
||||
'enabled' => true,
|
||||
@@ -249,7 +249,7 @@ return [
|
||||
[
|
||||
'key' => 'nodejs',
|
||||
'name' => 'Node.js',
|
||||
'version' => '14.0.0',
|
||||
'version' => '14.1.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-node',
|
||||
'package' => 'https://www.npmjs.com/package/node-appwrite',
|
||||
'enabled' => true,
|
||||
@@ -267,7 +267,7 @@ return [
|
||||
[
|
||||
'key' => 'deno',
|
||||
'name' => 'Deno',
|
||||
'version' => '12.0.0',
|
||||
'version' => '12.1.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-deno',
|
||||
'package' => 'https://deno.land/x/appwrite',
|
||||
'enabled' => true,
|
||||
@@ -303,7 +303,7 @@ return [
|
||||
[
|
||||
'key' => 'python',
|
||||
'name' => 'Python',
|
||||
'version' => '6.0.0',
|
||||
'version' => '6.1.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-python',
|
||||
'package' => 'https://pypi.org/project/appwrite/',
|
||||
'enabled' => true,
|
||||
@@ -321,7 +321,7 @@ return [
|
||||
[
|
||||
'key' => 'ruby',
|
||||
'name' => 'Ruby',
|
||||
'version' => '12.0.0',
|
||||
'version' => '12.1.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-ruby',
|
||||
'package' => 'https://rubygems.org/gems/appwrite',
|
||||
'enabled' => true,
|
||||
@@ -339,7 +339,7 @@ return [
|
||||
[
|
||||
'key' => 'go',
|
||||
'name' => 'Go',
|
||||
'version' => '0.1.0',
|
||||
'version' => '0.2.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-go',
|
||||
'package' => 'https://github.com/appwrite/sdk-for-go',
|
||||
'enabled' => true,
|
||||
@@ -357,7 +357,7 @@ return [
|
||||
[
|
||||
'key' => 'dotnet',
|
||||
'name' => '.NET',
|
||||
'version' => '0.9.0',
|
||||
'version' => '0.10.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-dotnet',
|
||||
'package' => 'https://www.nuget.org/packages/Appwrite',
|
||||
'enabled' => true,
|
||||
@@ -375,7 +375,7 @@ return [
|
||||
[
|
||||
'key' => 'dart',
|
||||
'name' => 'Dart',
|
||||
'version' => '12.0.0',
|
||||
'version' => '12.1.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-dart',
|
||||
'package' => 'https://pub.dev/packages/dart_appwrite',
|
||||
'enabled' => true,
|
||||
@@ -393,7 +393,7 @@ return [
|
||||
[
|
||||
'key' => 'kotlin',
|
||||
'name' => 'Kotlin',
|
||||
'version' => '6.0.0',
|
||||
'version' => '6.1.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-kotlin',
|
||||
'package' => 'https://search.maven.org/artifact/io.appwrite/sdk-for-kotlin',
|
||||
'enabled' => true,
|
||||
@@ -415,7 +415,7 @@ return [
|
||||
[
|
||||
'key' => 'swift',
|
||||
'name' => 'Swift',
|
||||
'version' => '6.0.0',
|
||||
'version' => '6.1.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-swift',
|
||||
'package' => 'https://github.com/appwrite/sdk-for-swift',
|
||||
'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
@@ -193,7 +193,7 @@ return [
|
||||
'introduction' => '1.5.1',
|
||||
'default' => '',
|
||||
'required' => true,
|
||||
'question' => '',
|
||||
'question' => 'Enter an email that will be used when registering for SSL certificates',
|
||||
'filter' => ''
|
||||
],
|
||||
[
|
||||
|
||||
@@ -124,7 +124,9 @@ function sendSessionAlert(Locale $locale, Document $user, Document $project, Doc
|
||||
|
||||
$emailVariables = [
|
||||
'direction' => $locale->getText('settings.direction'),
|
||||
'dateTime' => DateTime::format(new \DateTime(), 'h:ia MMMM dS'),
|
||||
'date' => (new \DateTime())->format('F j'),
|
||||
'year' => (new \DateTime())->format('YYYY'),
|
||||
'time' => (new \DateTime())->format('H:i:s'),
|
||||
'user' => $user->getAttribute('name'),
|
||||
'project' => $project->getAttribute('name'),
|
||||
'device' => $session->getAttribute('clientName'),
|
||||
@@ -392,7 +394,7 @@ App::post('/v1/account')
|
||||
$existingTarget = $dbForProject->findOne('targets', [
|
||||
Query::equal('identifier', [$email]),
|
||||
]);
|
||||
if($existingTarget) {
|
||||
if ($existingTarget) {
|
||||
$user->setAttribute('targets', $existingTarget, Document::SET_TYPE_APPEND);
|
||||
}
|
||||
}
|
||||
@@ -4121,7 +4123,7 @@ App::post('/v1/account/mfa/challenge')
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_MFA_CHALLENGE)
|
||||
->label('abuse-limit', 10)
|
||||
->label('abuse-key', 'url:{url},token:{param-token}')
|
||||
->label('abuse-key', 'url:{url},userId:{userId}')
|
||||
->param('factor', '', new WhiteList([Type::EMAIL, Type::PHONE, Type::TOTP, Type::RECOVERY_CODE]), 'Factor used for verification. Must be one of following: `' . Type::EMAIL . '`, `' . Type::PHONE . '`, `' . Type::TOTP . '`, `' . Type::RECOVERY_CODE . '`.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
@@ -4308,7 +4310,7 @@ App::put('/v1/account/mfa/challenge')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
|
||||
->label('sdk.response.model', Response::MODEL_SESSION)
|
||||
->label('abuse-limit', 10)
|
||||
->label('abuse-key', 'userId:{param-userId}')
|
||||
->label('abuse-key', 'url:{url},challengeId:{param-challengeId}')
|
||||
->param('challengeId', '', new Text(256), 'ID of the challenge.')
|
||||
->param('otp', '', new Text(256), 'Valid verification token.')
|
||||
->inject('project')
|
||||
|
||||
@@ -5,6 +5,7 @@ use Appwrite\Detector\Detector;
|
||||
use Appwrite\Event\Database as EventDatabase;
|
||||
use Appwrite\Event\Delete;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Usage;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Network\Validator\Email;
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
@@ -20,12 +21,15 @@ use Utopia\Audit\Audit;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception as DatabaseException;
|
||||
use Utopia\Database\Exception\Authorization as AuthorizationException;
|
||||
use Utopia\Database\Exception\Conflict as ConflictException;
|
||||
use Utopia\Database\Exception\Duplicate as DuplicateException;
|
||||
use Utopia\Database\Exception\Limit as LimitException;
|
||||
use Utopia\Database\Exception\Query as QueryException;
|
||||
use Utopia\Database\Exception\Restricted as RestrictedException;
|
||||
use Utopia\Database\Exception\Structure as StructureException;
|
||||
use Utopia\Database\Exception\Truncate as TruncateException;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
@@ -228,13 +232,15 @@ function updateAttribute(
|
||||
Database $dbForProject,
|
||||
Event $queueForEvents,
|
||||
string $type,
|
||||
int $size = null,
|
||||
string $filter = null,
|
||||
string|bool|int|float $default = null,
|
||||
bool $required = null,
|
||||
int|float $min = null,
|
||||
int|float $max = null,
|
||||
array $elements = null,
|
||||
array $options = []
|
||||
array $options = [],
|
||||
string $newKey = null,
|
||||
): Document {
|
||||
$db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
|
||||
@@ -280,6 +286,10 @@ function updateAttribute(
|
||||
->setAttribute('default', $default)
|
||||
->setAttribute('required', $required);
|
||||
|
||||
if (!empty($size)) {
|
||||
$attribute->setAttribute('size', $size);
|
||||
}
|
||||
|
||||
$formatOptions = $attribute->getAttribute('formatOptions');
|
||||
|
||||
switch ($attribute->getAttribute('format')) {
|
||||
@@ -345,6 +355,7 @@ function updateAttribute(
|
||||
$dbForProject->updateRelationship(
|
||||
collection: $collectionId,
|
||||
id: $key,
|
||||
newKey: $newKey,
|
||||
onDelete: $primaryDocumentOptions['onDelete'],
|
||||
);
|
||||
|
||||
@@ -352,22 +363,52 @@ function updateAttribute(
|
||||
$relatedCollection = $dbForProject->getDocument('database_' . $db->getInternalId(), $primaryDocumentOptions['relatedCollection']);
|
||||
|
||||
$relatedAttribute = $dbForProject->getDocument('attributes', $db->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $primaryDocumentOptions['twoWayKey']);
|
||||
|
||||
if (!empty($newKey) && $newKey !== $key) {
|
||||
$options['twoWayKey'] = $newKey;
|
||||
}
|
||||
|
||||
$relatedOptions = \array_merge($relatedAttribute->getAttribute('options'), $options);
|
||||
$relatedAttribute->setAttribute('options', $relatedOptions);
|
||||
$dbForProject->updateDocument('attributes', $db->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $primaryDocumentOptions['twoWayKey'], $relatedAttribute);
|
||||
|
||||
$dbForProject->purgeCachedDocument('database_' . $db->getInternalId(), $relatedCollection->getId());
|
||||
}
|
||||
} else {
|
||||
$dbForProject->updateAttribute(
|
||||
collection: $collectionId,
|
||||
id: $key,
|
||||
required: $required,
|
||||
default: $default,
|
||||
formatOptions: $options ?? null
|
||||
);
|
||||
try {
|
||||
$dbForProject->updateAttribute(
|
||||
collection: $collectionId,
|
||||
id: $key,
|
||||
size: $size,
|
||||
required: $required,
|
||||
default: $default,
|
||||
formatOptions: $options ?? null,
|
||||
newKey: $newKey ?? null
|
||||
);
|
||||
} catch (TruncateException) {
|
||||
throw new Exception(Exception::ATTRIBUTE_INVALID_RESIZE);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($newKey) && $key !== $newKey) {
|
||||
// Delete attribute and recreate since we can't modify IDs
|
||||
$original = clone $attribute;
|
||||
|
||||
$dbForProject->deleteDocument('attributes', $attribute->getId());
|
||||
|
||||
$attribute
|
||||
->setAttribute('$id', ID::custom($db->getInternalId() . '_' . $collection->getInternalId() . '_' . $newKey))
|
||||
->setAttribute('key', $newKey);
|
||||
|
||||
try {
|
||||
$attribute = $dbForProject->createDocument('attributes', $attribute);
|
||||
} catch (DatabaseException|PDOException) {
|
||||
$attribute = $dbForProject->createDocument('attributes', $original);
|
||||
}
|
||||
} else {
|
||||
$attribute = $dbForProject->updateDocument('attributes', $db->getInternalId() . '_' . $collection->getInternalId() . '_' . $key, $attribute);
|
||||
}
|
||||
|
||||
$attribute = $dbForProject->updateDocument('attributes', $db->getInternalId() . '_' . $collection->getInternalId() . '_' . $key, $attribute);
|
||||
$dbForProject->purgeCachedDocument('database_' . $db->getInternalId(), $collection->getId());
|
||||
|
||||
$queueForEvents
|
||||
@@ -412,7 +453,8 @@ App::post('/v1/databases')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
->action(function (string $databaseId, string $name, bool $enabled, Response $response, Database $dbForProject, Event $queueForEvents) {
|
||||
->inject('queueForUsage')
|
||||
->action(function (string $databaseId, string $name, bool $enabled, Response $response, Database $dbForProject, Event $queueForEvents, Usage $queueForUsage) {
|
||||
|
||||
$databaseId = $databaseId == 'unique()' ? ID::unique() : $databaseId;
|
||||
|
||||
@@ -462,6 +504,7 @@ App::post('/v1/databases')
|
||||
}
|
||||
|
||||
$queueForEvents->setParam('databaseId', $database->getId());
|
||||
$queueForUsage->addMetric(str_replace(['{databaseInternalId}'], [$database->getInternalId()], METRIC_DATABASE_ID_STORAGE), 1); // per database
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
@@ -693,7 +736,8 @@ App::delete('/v1/databases/:databaseId')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForDatabase')
|
||||
->inject('queueForEvents')
|
||||
->action(function (string $databaseId, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
|
||||
->inject('queueForUsage')
|
||||
->action(function (string $databaseId, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Usage $queueForUsage) {
|
||||
|
||||
$database = $dbForProject->getDocument('databases', $databaseId);
|
||||
|
||||
@@ -716,6 +760,9 @@ App::delete('/v1/databases/:databaseId')
|
||||
->setParam('databaseId', $database->getId())
|
||||
->setPayload($response->output($database, Response::MODEL_DATABASE));
|
||||
|
||||
$queueForUsage
|
||||
->addMetric(METRIC_DATABASES_STORAGE, 1); // Global, deletion forces full recalculation
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
|
||||
@@ -1152,6 +1199,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string
|
||||
'filters' => $filters,
|
||||
]), $response, $dbForProject, $queueForDatabase, $queueForEvents);
|
||||
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
|
||||
->dynamic($attribute, Response::MODEL_ATTRIBUTE_STRING);
|
||||
@@ -1859,10 +1907,12 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/strin
|
||||
->param('key', '', new Key(), 'Attribute Key.')
|
||||
->param('required', null, new Boolean(), 'Is attribute required?')
|
||||
->param('default', null, new Nullable(new Text(0, 0)), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
|
||||
->param('size', null, new Integer(), 'Maximum size of the string attribute.', true)
|
||||
->param('newKey', null, new Key(), 'New attribute key.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $queueForEvents) {
|
||||
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, ?int $size, ?string $newKey, Response $response, Database $dbForProject, Event $queueForEvents) {
|
||||
|
||||
$attribute = updateAttribute(
|
||||
databaseId: $databaseId,
|
||||
@@ -1871,8 +1921,10 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/strin
|
||||
dbForProject: $dbForProject,
|
||||
queueForEvents: $queueForEvents,
|
||||
type: Database::VAR_STRING,
|
||||
size: $size,
|
||||
default: $default,
|
||||
required: $required
|
||||
required: $required,
|
||||
newKey: $newKey
|
||||
);
|
||||
|
||||
$response
|
||||
@@ -1898,10 +1950,11 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/email
|
||||
->param('key', '', new Key(), 'Attribute Key.')
|
||||
->param('required', null, new Boolean(), 'Is attribute required?')
|
||||
->param('default', null, new Nullable(new Email()), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
|
||||
->param('newKey', null, new Key(), 'New attribute key.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $queueForEvents) {
|
||||
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, ?string $newKey, Response $response, Database $dbForProject, Event $queueForEvents) {
|
||||
$attribute = updateAttribute(
|
||||
databaseId: $databaseId,
|
||||
collectionId: $collectionId,
|
||||
@@ -1911,7 +1964,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/email
|
||||
type: Database::VAR_STRING,
|
||||
filter: APP_DATABASE_ATTRIBUTE_EMAIL,
|
||||
default: $default,
|
||||
required: $required
|
||||
required: $required,
|
||||
newKey: $newKey
|
||||
);
|
||||
|
||||
$response
|
||||
@@ -1938,10 +1992,11 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/enum/
|
||||
->param('elements', null, new ArrayList(new Text(DATABASE::LENGTH_KEY), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' elements are allowed, each ' . DATABASE::LENGTH_KEY . ' characters long.')
|
||||
->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('newKey', null, new Key(), 'New attribute key.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
->action(function (string $databaseId, string $collectionId, string $key, ?array $elements, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $queueForEvents) {
|
||||
->action(function (string $databaseId, string $collectionId, string $key, ?array $elements, ?bool $required, ?string $default, ?string $newKey, Response $response, Database $dbForProject, Event $queueForEvents) {
|
||||
$attribute = updateAttribute(
|
||||
databaseId: $databaseId,
|
||||
collectionId: $collectionId,
|
||||
@@ -1952,7 +2007,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/enum/
|
||||
filter: APP_DATABASE_ATTRIBUTE_ENUM,
|
||||
default: $default,
|
||||
required: $required,
|
||||
elements: $elements
|
||||
elements: $elements,
|
||||
newKey: $newKey
|
||||
);
|
||||
|
||||
$response
|
||||
@@ -1978,10 +2034,11 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/ip/:k
|
||||
->param('key', '', new Key(), 'Attribute Key.')
|
||||
->param('required', null, new Boolean(), 'Is attribute required?')
|
||||
->param('default', null, new Nullable(new IP()), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
|
||||
->param('newKey', null, new Key(), 'New attribute key.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $queueForEvents) {
|
||||
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, ?string $newKey, Response $response, Database $dbForProject, Event $queueForEvents) {
|
||||
$attribute = updateAttribute(
|
||||
databaseId: $databaseId,
|
||||
collectionId: $collectionId,
|
||||
@@ -1991,7 +2048,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/ip/:k
|
||||
type: Database::VAR_STRING,
|
||||
filter: APP_DATABASE_ATTRIBUTE_IP,
|
||||
default: $default,
|
||||
required: $required
|
||||
required: $required,
|
||||
newKey: $newKey
|
||||
);
|
||||
|
||||
$response
|
||||
@@ -2017,10 +2075,11 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/url/:
|
||||
->param('key', '', new Key(), 'Attribute Key.')
|
||||
->param('required', null, new Boolean(), 'Is attribute required?')
|
||||
->param('default', null, new Nullable(new URL()), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
|
||||
->param('newKey', null, new Key(), 'New attribute key.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $queueForEvents) {
|
||||
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, ?string $newKey, Response $response, Database $dbForProject, Event $queueForEvents) {
|
||||
$attribute = updateAttribute(
|
||||
databaseId: $databaseId,
|
||||
collectionId: $collectionId,
|
||||
@@ -2030,7 +2089,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/url/:
|
||||
type: Database::VAR_STRING,
|
||||
filter: APP_DATABASE_ATTRIBUTE_URL,
|
||||
default: $default,
|
||||
required: $required
|
||||
required: $required,
|
||||
newKey: $newKey
|
||||
);
|
||||
|
||||
$response
|
||||
@@ -2058,10 +2118,11 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/integ
|
||||
->param('min', null, new Integer(), 'Minimum value to enforce on new documents')
|
||||
->param('max', null, new Integer(), 'Maximum value to enforce on new documents')
|
||||
->param('default', null, new Nullable(new Integer()), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
|
||||
->param('newKey', null, new Key(), 'New attribute key.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?int $min, ?int $max, ?int $default, Response $response, Database $dbForProject, Event $queueForEvents) {
|
||||
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?int $min, ?int $max, ?int $default, ?string $newKey, Response $response, Database $dbForProject, Event $queueForEvents) {
|
||||
$attribute = updateAttribute(
|
||||
databaseId: $databaseId,
|
||||
collectionId: $collectionId,
|
||||
@@ -2072,7 +2133,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/integ
|
||||
default: $default,
|
||||
required: $required,
|
||||
min: $min,
|
||||
max: $max
|
||||
max: $max,
|
||||
newKey: $newKey
|
||||
);
|
||||
|
||||
$formatOptions = $attribute->getAttribute('formatOptions', []);
|
||||
@@ -2107,10 +2169,11 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/float
|
||||
->param('min', null, new FloatValidator(), 'Minimum value to enforce on new documents')
|
||||
->param('max', null, new FloatValidator(), 'Maximum value to enforce on new documents')
|
||||
->param('default', null, new Nullable(new FloatValidator()), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
|
||||
->param('newKey', null, new Key(), 'New attribute key.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?float $min, ?float $max, ?float $default, Response $response, Database $dbForProject, Event $queueForEvents) {
|
||||
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?float $min, ?float $max, ?float $default, ?string $newKey, Response $response, Database $dbForProject, Event $queueForEvents) {
|
||||
$attribute = updateAttribute(
|
||||
databaseId: $databaseId,
|
||||
collectionId: $collectionId,
|
||||
@@ -2121,7 +2184,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/float
|
||||
default: $default,
|
||||
required: $required,
|
||||
min: $min,
|
||||
max: $max
|
||||
max: $max,
|
||||
newKey: $newKey
|
||||
);
|
||||
|
||||
$formatOptions = $attribute->getAttribute('formatOptions', []);
|
||||
@@ -2154,10 +2218,11 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/boole
|
||||
->param('key', '', new Key(), 'Attribute Key.')
|
||||
->param('required', null, new Boolean(), 'Is attribute required?')
|
||||
->param('default', null, new Nullable(new Boolean()), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
|
||||
->param('newKey', null, new Key(), 'New attribute key.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?bool $default, Response $response, Database $dbForProject, Event $queueForEvents) {
|
||||
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?bool $default, ?string $newKey, Response $response, Database $dbForProject, Event $queueForEvents) {
|
||||
$attribute = updateAttribute(
|
||||
databaseId: $databaseId,
|
||||
collectionId: $collectionId,
|
||||
@@ -2166,7 +2231,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/boole
|
||||
queueForEvents: $queueForEvents,
|
||||
type: Database::VAR_BOOLEAN,
|
||||
default: $default,
|
||||
required: $required
|
||||
required: $required,
|
||||
newKey: $newKey
|
||||
);
|
||||
|
||||
$response
|
||||
@@ -2192,10 +2258,11 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/datet
|
||||
->param('key', '', new Key(), 'Attribute Key.')
|
||||
->param('required', null, new Boolean(), 'Is attribute required?')
|
||||
->param('default', null, new Nullable(new DatetimeValidator()), 'Default value for attribute when not provided. Cannot be set when attribute is required.')
|
||||
->param('newKey', null, new Key(), 'New attribute key.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $queueForEvents) {
|
||||
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, ?string $newKey, Response $response, Database $dbForProject, Event $queueForEvents) {
|
||||
$attribute = updateAttribute(
|
||||
databaseId: $databaseId,
|
||||
collectionId: $collectionId,
|
||||
@@ -2204,7 +2271,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/datet
|
||||
queueForEvents: $queueForEvents,
|
||||
type: Database::VAR_DATETIME,
|
||||
default: $default,
|
||||
required: $required
|
||||
required: $required,
|
||||
newKey: $newKey
|
||||
);
|
||||
|
||||
$response
|
||||
@@ -2229,6 +2297,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/:key/
|
||||
->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('onDelete', null, new WhiteList([Database::RELATION_MUTATE_CASCADE, Database::RELATION_MUTATE_RESTRICT, Database::RELATION_MUTATE_SET_NULL], true), 'Constraints option', true)
|
||||
->param('newKey', null, new Key(), 'New attribute key.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
@@ -2237,6 +2306,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/:key/
|
||||
string $collectionId,
|
||||
string $key,
|
||||
?string $onDelete,
|
||||
?string $newKey,
|
||||
Response $response,
|
||||
Database $dbForProject,
|
||||
Event $queueForEvents
|
||||
@@ -2251,7 +2321,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/:key/
|
||||
required: false,
|
||||
options: [
|
||||
'onDelete' => $onDelete
|
||||
]
|
||||
],
|
||||
newKey: $newKey
|
||||
);
|
||||
|
||||
$options = $attribute->getAttribute('options', []);
|
||||
@@ -2286,7 +2357,8 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key
|
||||
->inject('dbForProject')
|
||||
->inject('queueForDatabase')
|
||||
->inject('queueForEvents')
|
||||
->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
|
||||
->inject('queueForUsage')
|
||||
->action(function (string $databaseId, string $collectionId, string $key, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Usage $queueForUsage) {
|
||||
|
||||
$db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
|
||||
@@ -2371,6 +2443,9 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/attributes/:key
|
||||
->setContext('database', $db)
|
||||
->setPayload($response->output($attribute, $model));
|
||||
|
||||
$queueForUsage
|
||||
->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$db->getInternalId(), $collection->getInternalId()], METRIC_DATABASE_ID_COLLECTION_ID_STORAGE), 1); // per collection
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
|
||||
@@ -2746,8 +2821,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
|
||||
->inject('dbForProject')
|
||||
->inject('user')
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForUsage')
|
||||
->inject('mode')
|
||||
->action(function (string $databaseId, string $documentId, string $collectionId, string|array $data, ?array $permissions, Response $response, Database $dbForProject, Document $user, Event $queueForEvents, string $mode) {
|
||||
->action(function (string $databaseId, string $documentId, string $collectionId, string|array $data, ?array $permissions, Response $response, Database $dbForProject, Document $user, Event $queueForEvents, Usage $queueForUsage, string $mode) {
|
||||
|
||||
$data = (\is_string($data)) ? \json_decode($data, true) : $data; // Cast to JSON array
|
||||
|
||||
@@ -2963,6 +3039,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents')
|
||||
->setContext('database', $database)
|
||||
->setPayload($response->getPayload(), sensitive: $relationships);
|
||||
|
||||
|
||||
$queueForUsage
|
||||
->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$database->getInternalId(), $collection->getInternalId()], METRIC_DATABASE_ID_COLLECTION_ID_STORAGE), 1); // per collection
|
||||
});
|
||||
|
||||
App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
|
||||
@@ -3579,8 +3658,9 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
|
||||
->inject('dbForProject')
|
||||
->inject('queueForDeletes')
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForUsage')
|
||||
->inject('mode')
|
||||
->action(function (string $databaseId, string $collectionId, string $documentId, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Delete $queueForDeletes, Event $queueForEvents, string $mode) {
|
||||
->action(function (string $databaseId, string $collectionId, string $documentId, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Delete $queueForDeletes, Event $queueForEvents, Usage $queueForUsage, string $mode) {
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
|
||||
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
|
||||
@@ -3665,6 +3745,9 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
|
||||
->setContext('database', $database)
|
||||
->setPayload($response->output($document, Response::MODEL_DOCUMENT), sensitive: $relationships);
|
||||
|
||||
$queueForUsage
|
||||
->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$database->getInternalId(), $collection->getInternalId()], METRIC_DATABASE_ID_COLLECTION_ID_STORAGE), 1); // per collection
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
|
||||
@@ -3690,6 +3773,7 @@ App::get('/v1/databases/usage')
|
||||
METRIC_DATABASES,
|
||||
METRIC_COLLECTIONS,
|
||||
METRIC_DOCUMENTS,
|
||||
METRIC_DATABASES_STORAGE
|
||||
];
|
||||
|
||||
Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) {
|
||||
@@ -3740,9 +3824,11 @@ App::get('/v1/databases/usage')
|
||||
'databasesTotal' => $usage[$metrics[0]]['total'],
|
||||
'collectionsTotal' => $usage[$metrics[1]]['total'],
|
||||
'documentsTotal' => $usage[$metrics[2]]['total'],
|
||||
'storageTotal' => $usage[$metrics[3]]['total'],
|
||||
'databases' => $usage[$metrics[0]]['data'],
|
||||
'collections' => $usage[$metrics[1]]['data'],
|
||||
'documents' => $usage[$metrics[2]]['data'],
|
||||
'storage' => $usage[$metrics[3]]['data'],
|
||||
]), Response::MODEL_USAGE_DATABASES);
|
||||
});
|
||||
|
||||
@@ -3774,6 +3860,7 @@ App::get('/v1/databases/:databaseId/usage')
|
||||
$metrics = [
|
||||
str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_COLLECTIONS),
|
||||
str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_DOCUMENTS),
|
||||
str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_STORAGE)
|
||||
];
|
||||
|
||||
Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) {
|
||||
@@ -3824,8 +3911,10 @@ App::get('/v1/databases/:databaseId/usage')
|
||||
'range' => $range,
|
||||
'collectionsTotal' => $usage[$metrics[0]]['total'],
|
||||
'documentsTotal' => $usage[$metrics[1]]['total'],
|
||||
'storageTotal' => $usage[$metrics[2]]['total'],
|
||||
'collections' => $usage[$metrics[0]]['data'],
|
||||
'documents' => $usage[$metrics[1]]['data'],
|
||||
'storage' => $usage[$metrics[2]]['data'],
|
||||
]), Response::MODEL_USAGE_DATABASE);
|
||||
});
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ use Appwrite\Event\Validator\FunctionEvent;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Extend\Exception as AppwriteException;
|
||||
use Appwrite\Functions\Validator\Headers;
|
||||
use Appwrite\Functions\Validator\Payload;
|
||||
use Appwrite\Functions\Validator\RuntimeSpecification;
|
||||
use Appwrite\Messaging\Adapter\Realtime;
|
||||
use Appwrite\Platform\Tasks\ScheduleExecutions;
|
||||
@@ -295,7 +296,7 @@ App::post('/v1/functions')
|
||||
if (!empty($providerRepositoryId)) {
|
||||
// Deploy VCS
|
||||
$redeployVcs($request, $function, $project, $installation, $dbForProject, $queueForBuilds, $template, $github);
|
||||
} elseif(!$template->isEmpty()) {
|
||||
} elseif (!$template->isEmpty()) {
|
||||
// Deploy non-VCS from template
|
||||
$deploymentId = ID::unique();
|
||||
$deployment = $dbForProject->createDocument('deployments', new Document([
|
||||
@@ -1151,6 +1152,7 @@ App::post('/v1/functions/:functionId/deployments')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'functions')
|
||||
->label('sdk.method', 'createDeployment')
|
||||
->label('sdk.methodType', 'upload')
|
||||
->label('sdk.description', '/docs/references/functions/create-deployment.md')
|
||||
->label('sdk.packaging', true)
|
||||
->label('sdk.request.type', 'multipart/form-data')
|
||||
@@ -1579,7 +1581,7 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/build')
|
||||
}
|
||||
|
||||
$path = $deployment->getAttribute('path');
|
||||
if(empty($path) || !$deviceForFunctions->exists($path)) {
|
||||
if (empty($path) || !$deviceForFunctions->exists($path)) {
|
||||
throw new Exception(Exception::DEPLOYMENT_NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -1715,8 +1717,8 @@ App::post('/v1/functions/:functionId/executions')
|
||||
->label('sdk.response.model', Response::MODEL_EXECUTION)
|
||||
->label('sdk.request.type', Response::CONTENT_TYPE_JSON)
|
||||
->param('functionId', '', new UID(), 'Function ID.')
|
||||
->param('body', '', new Text(10485760, 0), 'HTTP body of execution. Default value is empty string.', true)
|
||||
->param('async', false, new Boolean(), 'Execute code in the background. Default value is false.', true)
|
||||
->param('body', '', new Payload(10485760, 0), 'HTTP body of execution. Default value is empty string.', true)
|
||||
->param('async', false, new Boolean(true), 'Execute code in the background. Default value is false.', true)
|
||||
->param('path', '/', new Text(2048), 'HTTP path of execution. Path can include query params. Default value is /', true)
|
||||
->param('method', 'POST', new Whitelist(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], true), 'HTTP method of execution. Default value is GET.', true)
|
||||
->param('headers', [], new AnyOf([new Assoc(), new Text(65535)], AnyOf::TYPE_MIXED), 'HTTP headers of execution. Defaults to empty.', true)
|
||||
@@ -1731,9 +1733,10 @@ App::post('/v1/functions/:functionId/executions')
|
||||
->inject('queueForUsage')
|
||||
->inject('queueForFunctions')
|
||||
->inject('geodb')
|
||||
->action(function (string $functionId, string $body, bool $async, string $path, string $method, mixed $headers, ?string $scheduledAt, Response $response, Request $request, Document $project, Database $dbForProject, Database $dbForConsole, Document $user, Event $queueForEvents, Usage $queueForUsage, Func $queueForFunctions, Reader $geodb) {
|
||||
->action(function (string $functionId, string $body, mixed $async, string $path, string $method, mixed $headers, ?string $scheduledAt, Response $response, Request $request, Document $project, Database $dbForProject, Database $dbForConsole, Document $user, Event $queueForEvents, Usage $queueForUsage, Func $queueForFunctions, Reader $geodb) {
|
||||
$async = \strval($async) === 'true' || \strval($async) === '1';
|
||||
|
||||
if(!$async && !is_null($scheduledAt)) {
|
||||
if (!$async && !is_null($scheduledAt)) {
|
||||
throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Scheduled executions must run asynchronously. Set scheduledAt to a future date, or set async to true.');
|
||||
}
|
||||
|
||||
@@ -1866,7 +1869,7 @@ App::post('/v1/functions/:functionId/executions')
|
||||
|
||||
$status = $async ? 'waiting' : 'processing';
|
||||
|
||||
if(!is_null($scheduledAt)) {
|
||||
if (!is_null($scheduledAt)) {
|
||||
$status = 'scheduled';
|
||||
}
|
||||
|
||||
@@ -1896,7 +1899,7 @@ App::post('/v1/functions/:functionId/executions')
|
||||
->setContext('function', $function);
|
||||
|
||||
if ($async) {
|
||||
if(is_null($scheduledAt)) {
|
||||
if (is_null($scheduledAt)) {
|
||||
$execution = Authorization::skip(fn () => $dbForProject->createDocument('executions', $execution));
|
||||
$queueForFunctions
|
||||
->setType('http')
|
||||
@@ -1918,7 +1921,7 @@ App::post('/v1/functions/:functionId/executions')
|
||||
'path' => $path,
|
||||
'method' => $method,
|
||||
'body' => $body,
|
||||
'jwt' => $jwt,
|
||||
'userId' => $user->getId()
|
||||
];
|
||||
|
||||
$schedule = $dbForConsole->createDocument('schedules', new Document([
|
||||
@@ -1987,6 +1990,19 @@ App::post('/v1/functions/:functionId/executions')
|
||||
'APPWRITE_FUNCTION_MEMORY' => $spec['memory'] ?? APP_FUNCTION_MEMORY_DEFAULT,
|
||||
'APPWRITE_VERSION' => APP_VERSION_STABLE,
|
||||
'APPWRITE_REGION' => $project->getAttribute('region'),
|
||||
'APPWRITE_DEPLOYMENT_TYPE' => $deployment->getAttribute('type', ''),
|
||||
'APPWRITE_VCS_REPOSITORY_ID' => $deployment->getAttribute('providerRepositoryId', ''),
|
||||
'APPWRITE_VCS_REPOSITORY_NAME' => $deployment->getAttribute('providerRepositoryName', ''),
|
||||
'APPWRITE_VCS_REPOSITORY_OWNER' => $deployment->getAttribute('providerRepositoryOwner', ''),
|
||||
'APPWRITE_VCS_REPOSITORY_URL' => $deployment->getAttribute('providerRepositoryUrl', ''),
|
||||
'APPWRITE_VCS_REPOSITORY_BRANCH' => $deployment->getAttribute('providerBranch', ''),
|
||||
'APPWRITE_VCS_REPOSITORY_BRANCH_URL' => $deployment->getAttribute('providerBranchUrl', ''),
|
||||
'APPWRITE_VCS_COMMIT_HASH' => $deployment->getAttribute('providerCommitHash', ''),
|
||||
'APPWRITE_VCS_COMMIT_MESSAGE' => $deployment->getAttribute('providerCommitMessage', ''),
|
||||
'APPWRITE_VCS_COMMIT_URL' => $deployment->getAttribute('providerCommitUrl', ''),
|
||||
'APPWRITE_VCS_COMMIT_AUTHOR_NAME' => $deployment->getAttribute('providerCommitAuthor', ''),
|
||||
'APPWRITE_VCS_COMMIT_AUTHOR_URL' => $deployment->getAttribute('providerCommitAuthorUrl', ''),
|
||||
'APPWRITE_VCS_ROOT_DIRECTORY' => $deployment->getAttribute('providerRootDirectory', ''),
|
||||
]);
|
||||
|
||||
/** Execute function */
|
||||
@@ -2075,7 +2091,7 @@ App::post('/v1/functions/:functionId/executions')
|
||||
|
||||
$acceptTypes = \explode(', ', $request->getHeader('accept'));
|
||||
foreach ($acceptTypes as $acceptType) {
|
||||
if(\str_starts_with($acceptType, 'application/json') || \str_starts_with($acceptType, 'application/*')) {
|
||||
if (\str_starts_with($acceptType, 'application/json') || \str_starts_with($acceptType, 'application/*')) {
|
||||
$response->setContentType(Response::CONTENT_TYPE_JSON);
|
||||
break;
|
||||
} elseif (\str_starts_with($acceptType, 'multipart/form-data') || \str_starts_with($acceptType, 'multipart/*')) {
|
||||
|
||||
@@ -47,6 +47,7 @@ App::get('/v1/project/usage')
|
||||
METRIC_USERS,
|
||||
METRIC_BUCKETS,
|
||||
METRIC_FILES_STORAGE,
|
||||
METRIC_DATABASES_STORAGE,
|
||||
METRIC_DEPLOYMENTS_STORAGE,
|
||||
METRIC_BUILDS_STORAGE
|
||||
],
|
||||
@@ -56,6 +57,7 @@ App::get('/v1/project/usage')
|
||||
METRIC_NETWORK_OUTBOUND,
|
||||
METRIC_USERS,
|
||||
METRIC_EXECUTIONS,
|
||||
METRIC_DATABASES_STORAGE,
|
||||
METRIC_EXECUTIONS_MB_SECONDS,
|
||||
METRIC_BUILDS_MB_SECONDS
|
||||
]
|
||||
@@ -182,6 +184,23 @@ App::get('/v1/project/usage')
|
||||
];
|
||||
}, $dbForProject->find('buckets'));
|
||||
|
||||
$databasesStorageBreakdown = array_map(function ($database) use ($dbForProject) {
|
||||
$id = $database->getId();
|
||||
$name = $database->getAttribute('name');
|
||||
$metric = str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_STORAGE);
|
||||
|
||||
$value = $dbForProject->findOne('stats', [
|
||||
Query::equal('metric', [$metric]),
|
||||
Query::equal('period', ['inf'])
|
||||
]);
|
||||
|
||||
return [
|
||||
'resourceId' => $id,
|
||||
'name' => $name,
|
||||
'value' => $value['value'] ?? 0,
|
||||
];
|
||||
}, $dbForProject->find('databases'));
|
||||
|
||||
$functionsStorageBreakdown = array_map(function ($function) use ($dbForProject) {
|
||||
$id = $function->getId();
|
||||
$name = $function->getAttribute('name');
|
||||
@@ -269,14 +288,18 @@ App::get('/v1/project/usage')
|
||||
'buildsMbSecondsTotal' => $total[METRIC_BUILDS_MB_SECONDS],
|
||||
'documentsTotal' => $total[METRIC_DOCUMENTS],
|
||||
'databasesTotal' => $total[METRIC_DATABASES],
|
||||
'databasesStorageTotal' => $total[METRIC_DATABASES_STORAGE],
|
||||
'usersTotal' => $total[METRIC_USERS],
|
||||
'bucketsTotal' => $total[METRIC_BUCKETS],
|
||||
'filesStorageTotal' => $total[METRIC_FILES_STORAGE],
|
||||
'functionsStorageTotal' => $total[METRIC_DEPLOYMENTS_STORAGE] + $total[METRIC_BUILDS_STORAGE],
|
||||
'buildsStorageTotal' => $total[METRIC_BUILDS_STORAGE],
|
||||
'deploymentsStorageTotal' => $total[METRIC_DEPLOYMENTS_STORAGE],
|
||||
'executionsBreakdown' => $executionsBreakdown,
|
||||
'executionsMbSecondsBreakdown' => $executionsMbSecondsBreakdown,
|
||||
'buildsMbSecondsBreakdown' => $buildsMbSecondsBreakdown,
|
||||
'bucketsBreakdown' => $bucketsBreakdown,
|
||||
'databasesStorageBreakdown' => $databasesStorageBreakdown,
|
||||
'executionsMbSecondsBreakdown' => $executionsMbSecondsBreakdown,
|
||||
'buildsMbSecondsBreakdown' => $buildsMbSecondsBreakdown,
|
||||
'functionsStorageBreakdown' => $functionsStorageBreakdown,
|
||||
|
||||
@@ -140,7 +140,7 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e
|
||||
$existingTarget = $dbForProject->findOne('targets', [
|
||||
Query::equal('identifier', [$email]),
|
||||
]);
|
||||
if($existingTarget) {
|
||||
if ($existingTarget) {
|
||||
$user->setAttribute('targets', $existingTarget, Document::SET_TYPE_APPEND);
|
||||
}
|
||||
}
|
||||
@@ -164,7 +164,7 @@ function createUser(string $hash, mixed $hashOptions, string $userId, ?string $e
|
||||
$existingTarget = $dbForProject->findOne('targets', [
|
||||
Query::equal('identifier', [$phone]),
|
||||
]);
|
||||
if($existingTarget) {
|
||||
if ($existingTarget) {
|
||||
$user->setAttribute('targets', $existingTarget, Document::SET_TYPE_APPEND);
|
||||
}
|
||||
}
|
||||
@@ -2124,7 +2124,7 @@ App::post('/v1/users/:userId/jwts')
|
||||
$sessions = $user->getAttribute('sessions', []);
|
||||
$session = new Document();
|
||||
|
||||
if($sessionId === 'recent') {
|
||||
if ($sessionId === 'recent') {
|
||||
// Get most recent
|
||||
$session = \count($sessions) > 0 ? $sessions[\count($sessions) - 1] : new Document();
|
||||
} else {
|
||||
|
||||
@@ -509,7 +509,7 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories/:pro
|
||||
$vcsContents = [];
|
||||
foreach ($contents as $content) {
|
||||
$isDirectory = false;
|
||||
if($content['type'] === GitHub::CONTENTS_DIRECTORY) {
|
||||
if ($content['type'] === GitHub::CONTENTS_DIRECTORY) {
|
||||
$isDirectory = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -97,6 +97,9 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo
|
||||
$type = $route->getAttribute('resourceType');
|
||||
|
||||
if ($type === 'function') {
|
||||
$utopia->getRoute()?->label('sdk.namespace', 'functions');
|
||||
$utopia->getRoute()?->label('sdk.method', 'createExecution');
|
||||
|
||||
if (System::getEnv('_APP_OPTIONS_FUNCTIONS_FORCE_HTTPS', 'disabled') === 'enabled') { // Force HTTPS
|
||||
if ($request->getProtocol() !== 'https') {
|
||||
if ($request->getMethod() !== Request::METHOD_GET) {
|
||||
@@ -272,6 +275,19 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo
|
||||
'APPWRITE_FUNCTION_MEMORY' => $spec['memory'] ?? APP_FUNCTION_MEMORY_DEFAULT,
|
||||
'APPWRITE_VERSION' => APP_VERSION_STABLE,
|
||||
'APPWRITE_REGION' => $project->getAttribute('region'),
|
||||
'APPWRITE_DEPLOYMENT_TYPE' => $deployment->getAttribute('type', ''),
|
||||
'APPWRITE_VCS_REPOSITORY_ID' => $deployment->getAttribute('providerRepositoryId', ''),
|
||||
'APPWRITE_VCS_REPOSITORY_NAME' => $deployment->getAttribute('providerRepositoryName', ''),
|
||||
'APPWRITE_VCS_REPOSITORY_OWNER' => $deployment->getAttribute('providerRepositoryOwner', ''),
|
||||
'APPWRITE_VCS_REPOSITORY_URL' => $deployment->getAttribute('providerRepositoryUrl', ''),
|
||||
'APPWRITE_VCS_REPOSITORY_BRANCH' => $deployment->getAttribute('providerBranch', ''),
|
||||
'APPWRITE_VCS_REPOSITORY_BRANCH_URL' => $deployment->getAttribute('providerBranchUrl', ''),
|
||||
'APPWRITE_VCS_COMMIT_HASH' => $deployment->getAttribute('providerCommitHash', ''),
|
||||
'APPWRITE_VCS_COMMIT_MESSAGE' => $deployment->getAttribute('providerCommitMessage', ''),
|
||||
'APPWRITE_VCS_COMMIT_URL' => $deployment->getAttribute('providerCommitUrl', ''),
|
||||
'APPWRITE_VCS_COMMIT_AUTHOR_NAME' => $deployment->getAttribute('providerCommitAuthor', ''),
|
||||
'APPWRITE_VCS_COMMIT_AUTHOR_URL' => $deployment->getAttribute('providerCommitAuthorUrl', ''),
|
||||
'APPWRITE_VCS_ROOT_DIRECTORY' => $deployment->getAttribute('providerRootDirectory', ''),
|
||||
]);
|
||||
|
||||
/** Execute function */
|
||||
@@ -330,7 +346,16 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo
|
||||
throw $th;
|
||||
}
|
||||
} finally {
|
||||
$fileSize = 0;
|
||||
$file = $request->getFiles('file');
|
||||
if (!empty($file)) {
|
||||
$fileSize = (\is_array($file['size']) && isset($file['size'][0])) ? $file['size'][0] : $file['size'];
|
||||
}
|
||||
|
||||
$queueForUsage
|
||||
->addMetric(METRIC_NETWORK_REQUESTS, 1)
|
||||
->addMetric(METRIC_NETWORK_INBOUND, $request->getSize() + $fileSize)
|
||||
->addMetric(METRIC_NETWORK_OUTBOUND, $response->getSize())
|
||||
->addMetric(METRIC_EXECUTIONS, 1)
|
||||
->addMetric(str_replace('{functionInternalId}', $function->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS), 1)
|
||||
->addMetric(METRIC_EXECUTIONS_COMPUTE, (int)($execution->getAttribute('duration') * 1000)) // per project
|
||||
@@ -341,10 +366,7 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo
|
||||
->trigger()
|
||||
;
|
||||
|
||||
if ($function->getAttribute('logging')) {
|
||||
/** @var Document $execution */
|
||||
$execution = Authorization::skip(fn () => $dbForProject->createDocument('executions', $execution));
|
||||
}
|
||||
$execution = Authorization::skip(fn () => $dbForProject->createDocument('executions', $execution));
|
||||
}
|
||||
|
||||
$execution->setAttribute('logs', '');
|
||||
|
||||
@@ -95,7 +95,7 @@ $databaseListener = function (string $event, Document $document, Document $proje
|
||||
$databaseInternalId = $parts[1] ?? 0;
|
||||
$queueForUsage
|
||||
->addMetric(METRIC_COLLECTIONS, $value) // per project
|
||||
->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, METRIC_DATABASE_ID_COLLECTIONS), $value) // per database
|
||||
->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, METRIC_DATABASE_ID_COLLECTIONS), $value)
|
||||
;
|
||||
|
||||
if ($event === Database::EVENT_DOCUMENT_DELETE) {
|
||||
@@ -207,14 +207,14 @@ App::init()
|
||||
}
|
||||
|
||||
// Remove after migration
|
||||
if(!\str_contains($apiKey, '_')) {
|
||||
if (!\str_contains($apiKey, '_')) {
|
||||
$keyType = API_KEY_STANDARD;
|
||||
$authKey = $apiKey;
|
||||
} else {
|
||||
[ $keyType, $authKey ] = \explode('_', $apiKey, 2);
|
||||
}
|
||||
|
||||
if($keyType === API_KEY_DYNAMIC) {
|
||||
if ($keyType === API_KEY_DYNAMIC) {
|
||||
// Dynamic key
|
||||
|
||||
$jwtObj = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 3600, 0);
|
||||
@@ -244,7 +244,7 @@ App::init()
|
||||
Authorization::setRole(Auth::USER_ROLE_APPS);
|
||||
Authorization::setDefaultStatus(false); // Cancel security segmentation for API keys.
|
||||
}
|
||||
} elseif($keyType === API_KEY_STANDARD) {
|
||||
} elseif ($keyType === API_KEY_STANDARD) {
|
||||
// No underline means no prefix. Backwards compatibility.
|
||||
// Regular key
|
||||
|
||||
|
||||
@@ -32,8 +32,9 @@ App::get('/')
|
||||
->action(function (Request $request, Response $response) {
|
||||
$url = parse_url($request->getURI());
|
||||
$target = "/console{$url['path']}";
|
||||
if ($url['query'] ?? false) {
|
||||
$target .= "?{$url['query']}";
|
||||
$params = $request->getParams();
|
||||
if (!empty($params)) {
|
||||
$target .= "?" . \http_build_query($params);
|
||||
}
|
||||
if ($url['fragment'] ?? false) {
|
||||
$target .= "#{$url['fragment']}";
|
||||
|
||||
+21
-5
@@ -223,15 +223,31 @@ const API_KEY_DYNAMIC = 'dynamic';
|
||||
// Usage metrics
|
||||
const METRIC_TEAMS = 'teams';
|
||||
const METRIC_USERS = 'users';
|
||||
const METRIC_MESSAGES = 'messages';
|
||||
const METRIC_MESSAGES_COUNTRY_CODE = '{countryCode}.messages';
|
||||
|
||||
const METRIC_AUTH_METHOD_PHONE = 'auth.method.phone';
|
||||
const METRIC_AUTH_METHOD_PHONE_COUNTRY_CODE = METRIC_AUTH_METHOD_PHONE . '.{countryCode}';
|
||||
const METRIC_MESSAGES = 'messages';
|
||||
const METRIC_MESSAGES_SENT = METRIC_MESSAGES . '.sent';
|
||||
const METRIC_MESSAGES_FAILED = METRIC_MESSAGES . '.failed';
|
||||
const METRIC_MESSAGES_TYPE = METRIC_MESSAGES . '.{type}';
|
||||
const METRIC_MESSAGES_TYPE_SENT = METRIC_MESSAGES . '.{type}.sent';
|
||||
const METRIC_MESSAGES_TYPE_FAILED = METRIC_MESSAGES . '.{type}.failed';
|
||||
const METRIC_MESSAGES_TYPE_PROVIDER = METRIC_MESSAGES . '.{type}.{provider}';
|
||||
const METRIC_MESSAGES_TYPE_PROVIDER_SENT = METRIC_MESSAGES . '.{type}.{provider}.sent';
|
||||
const METRIC_MESSAGES_TYPE_PROVIDER_FAILED = METRIC_MESSAGES . '.{type}.{provider}.failed';
|
||||
const METRIC_SESSIONS = 'sessions';
|
||||
const METRIC_DATABASES = 'databases';
|
||||
const METRIC_COLLECTIONS = 'collections';
|
||||
const METRIC_DATABASES_STORAGE = 'databases.storage';
|
||||
const METRIC_DATABASES_STORAGE_DISK = 'databases.storage_disk';
|
||||
const METRIC_DATABASE_ID_COLLECTIONS = '{databaseInternalId}.collections';
|
||||
const METRIC_DATABASE_ID_STORAGE = '{databaseInternalId}.databases.storage';
|
||||
const METRIC_DATABASE_ID_STORAGE_DISK = '{databaseInternalId}.databases.storage_disk';
|
||||
const METRIC_DOCUMENTS = 'documents';
|
||||
const METRIC_DATABASE_ID_DOCUMENTS = '{databaseInternalId}.documents';
|
||||
const METRIC_DATABASE_ID_COLLECTION_ID_DOCUMENTS = '{databaseInternalId}.{collectionInternalId}.documents';
|
||||
const METRIC_DATABASE_ID_COLLECTION_ID_STORAGE = '{databaseInternalId}.{collectionInternalId}.databases.storage';
|
||||
const METRIC_DATABASE_ID_COLLECTION_ID_STORAGE_DISK = '{databaseInternalId}.{collectionInternalId}.databases.storage_disk';
|
||||
const METRIC_BUCKETS = 'buckets';
|
||||
const METRIC_FILES = 'files';
|
||||
const METRIC_FILES_STORAGE = 'files.storage';
|
||||
@@ -791,7 +807,7 @@ $register->set('logger', function () {
|
||||
$adapter = null;
|
||||
}
|
||||
|
||||
if($adapter === null) {
|
||||
if ($adapter === null) {
|
||||
Console::error("Logging provider not supported. Logging is disabled");
|
||||
return;
|
||||
}
|
||||
@@ -1018,7 +1034,7 @@ $register->set('smtp', function () {
|
||||
return $mail;
|
||||
});
|
||||
$register->set('geodb', function () {
|
||||
return new Reader(__DIR__ . '/assets/dbip/dbip-country-lite-2024-08.mmdb');
|
||||
return new Reader(__DIR__ . '/assets/dbip/dbip-country-lite-2024-09.mmdb');
|
||||
});
|
||||
$register->set('passwordsDictionary', function () {
|
||||
$content = \file_get_contents(__DIR__ . '/assets/security/10k-common-passwords');
|
||||
@@ -1272,7 +1288,7 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons
|
||||
}
|
||||
|
||||
$jwtSessionId = $payload['sessionId'] ?? '';
|
||||
if(!empty($jwtSessionId)) {
|
||||
if (!empty($jwtSessionId)) {
|
||||
if (empty($user->find('$id', $jwtSessionId, 'sessions'))) { // Match JWT to active token
|
||||
$user = new Document([]);
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ $image = $this->getParam('image', '');
|
||||
appwrite-console:
|
||||
<<: *x-logging
|
||||
container_name: appwrite-console
|
||||
image: <?php echo $organization; ?>/console:5.0.4
|
||||
image: <?php echo $organization; ?>/console:5.0.12
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
@@ -336,6 +336,9 @@ $image = $this->getParam('image', '');
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_EXECUTOR_SECRET
|
||||
- _APP_EXECUTOR_HOST
|
||||
- _APP_MAINTENANCE_RETENTION_ABUSE
|
||||
- _APP_MAINTENANCE_RETENTION_AUDIT
|
||||
- _APP_MAINTENANCE_RETENTION_EXECUTION
|
||||
|
||||
appwrite-worker-databases:
|
||||
image: <?php echo $organization; ?>/<?php echo $image; ?>:<?php echo $version."\n"; ?>
|
||||
@@ -528,6 +531,8 @@ $image = $this->getParam('image', '');
|
||||
- _APP_SMTP_USERNAME
|
||||
- _APP_SMTP_PASSWORD
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_DOMAIN
|
||||
- _APP_OPTIONS_FORCE_HTTPS
|
||||
|
||||
appwrite-worker-messaging:
|
||||
image: <?php echo $organization; ?>/<?php echo $image; ?>:<?php echo $version."\n"; ?>
|
||||
@@ -676,6 +681,7 @@ $image = $this->getParam('image', '');
|
||||
entrypoint: worker-usage-dump
|
||||
<<: *x-logging
|
||||
container_name: appwrite-worker-usage-dump
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
@@ -789,7 +795,7 @@ $image = $this->getParam('image', '');
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
stop_signal: SIGINT
|
||||
image: openruntimes/executor:0.6.7
|
||||
image: openruntimes/executor:0.6.11
|
||||
networks:
|
||||
- appwrite
|
||||
- runtimes
|
||||
|
||||
+9
-3
@@ -45,13 +45,13 @@
|
||||
"ext-sockets": "*",
|
||||
"appwrite/php-runtimes": "0.15.*",
|
||||
"appwrite/php-clamav": "2.0.*",
|
||||
"utopia-php/abuse": "0.42.0",
|
||||
"utopia-php/abuse": "0.43.0",
|
||||
"utopia-php/analytics": "0.10.*",
|
||||
"utopia-php/audit": "0.42.0",
|
||||
"utopia-php/audit": "0.43.0",
|
||||
"utopia-php/cache": "0.10.*",
|
||||
"utopia-php/cli": "0.15.*",
|
||||
"utopia-php/config": "0.2.*",
|
||||
"utopia-php/database": "0.52.*",
|
||||
"utopia-php/database": "0.53.5-rc1",
|
||||
"utopia-php/domains": "0.5.*",
|
||||
"utopia-php/dsn": "0.2.1",
|
||||
"utopia-php/framework": "0.33.*",
|
||||
@@ -97,5 +97,11 @@
|
||||
"platform": {
|
||||
"php": "8.3"
|
||||
}
|
||||
},
|
||||
"repositories": {
|
||||
"utopia-php/database": {
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/utopia-php/database"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+57
-24
@@ -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": "eba741eab8bb748ed684c32711d472df",
|
||||
"content-hash": "7066d9ca32e7a1a60614effdc4701970",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
@@ -1429,16 +1429,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/abuse",
|
||||
"version": "0.42.0",
|
||||
"version": "0.43.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/abuse.git",
|
||||
"reference": "08cf17e7f4fd213966c8d8702e406f2269244f0f"
|
||||
"reference": "6346a3b4c5177a43160035a7289e30fdfb0790d6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/08cf17e7f4fd213966c8d8702e406f2269244f0f",
|
||||
"reference": "08cf17e7f4fd213966c8d8702e406f2269244f0f",
|
||||
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/6346a3b4c5177a43160035a7289e30fdfb0790d6",
|
||||
"reference": "6346a3b4c5177a43160035a7289e30fdfb0790d6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1446,7 +1446,7 @@
|
||||
"ext-pdo": "*",
|
||||
"ext-redis": "*",
|
||||
"php": ">=8.0",
|
||||
"utopia-php/database": "0.52.*"
|
||||
"utopia-php/database": "0.53.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.5.*",
|
||||
@@ -1474,9 +1474,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/abuse/issues",
|
||||
"source": "https://github.com/utopia-php/abuse/tree/0.42.0"
|
||||
"source": "https://github.com/utopia-php/abuse/tree/0.43.0"
|
||||
},
|
||||
"time": "2024-08-21T08:24:01+00:00"
|
||||
"time": "2024-08-30T05:17:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/analytics",
|
||||
@@ -1526,21 +1526,21 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/audit",
|
||||
"version": "0.42.0",
|
||||
"version": "0.43.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/audit.git",
|
||||
"reference": "9dc168470625bcf11ff8cd9ab5660db09129f618"
|
||||
"reference": "cef22b5dc6a6d28fcd522f41c7bf7ded4a4dfd3e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/audit/zipball/9dc168470625bcf11ff8cd9ab5660db09129f618",
|
||||
"reference": "9dc168470625bcf11ff8cd9ab5660db09129f618",
|
||||
"url": "https://api.github.com/repos/utopia-php/audit/zipball/cef22b5dc6a6d28fcd522f41c7bf7ded4a4dfd3e",
|
||||
"reference": "cef22b5dc6a6d28fcd522f41c7bf7ded4a4dfd3e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0",
|
||||
"utopia-php/database": "0.52.*"
|
||||
"utopia-php/database": "0.53.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.5.*",
|
||||
@@ -1567,9 +1567,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/audit/issues",
|
||||
"source": "https://github.com/utopia-php/audit/tree/0.42.0"
|
||||
"source": "https://github.com/utopia-php/audit/tree/0.43.0"
|
||||
},
|
||||
"time": "2024-08-21T08:24:08+00:00"
|
||||
"time": "2024-08-30T05:17:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/cache",
|
||||
@@ -1723,16 +1723,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/database",
|
||||
"version": "0.52.2",
|
||||
"version": "0.53.5-rc1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/database.git",
|
||||
"reference": "24b29bcac7eb7a8b81698a80bb75fc5909f4975e"
|
||||
"reference": "689ba22063bf46def385da8695ba7a921e81e38d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/24b29bcac7eb7a8b81698a80bb75fc5909f4975e",
|
||||
"reference": "24b29bcac7eb7a8b81698a80bb75fc5909f4975e",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/689ba22063bf46def385da8695ba7a921e81e38d",
|
||||
"reference": "689ba22063bf46def385da8695ba7a921e81e38d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1759,7 +1759,38 @@
|
||||
"Utopia\\Database\\": "src/Database"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Tests\\E2E\\": "tests/e2e",
|
||||
"Tests\\Unit\\": "tests/unit"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"docker compose build"
|
||||
],
|
||||
"start": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"docker compose up -d"
|
||||
],
|
||||
"test": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"docker compose exec tests vendor/bin/phpunit --configuration phpunit.xml"
|
||||
],
|
||||
"lint": [
|
||||
"./vendor/bin/pint --test"
|
||||
],
|
||||
"format": [
|
||||
"./vendor/bin/pint"
|
||||
],
|
||||
"check": [
|
||||
"./vendor/bin/phpstan analyse --level 7 src tests --memory-limit 512M"
|
||||
],
|
||||
"coverage": [
|
||||
"./vendor/bin/coverage-check ./tmp/clover.xml 90"
|
||||
]
|
||||
},
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
@@ -1772,10 +1803,10 @@
|
||||
"utopia"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/database/issues",
|
||||
"source": "https://github.com/utopia-php/database/tree/0.52.2"
|
||||
"source": "https://github.com/utopia-php/database/tree/0.53.5-rc1",
|
||||
"issues": "https://github.com/utopia-php/database/issues"
|
||||
},
|
||||
"time": "2024-09-02T06:28:50+00:00"
|
||||
"time": "2024-09-24T08:43:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/domains",
|
||||
@@ -6995,7 +7026,9 @@
|
||||
],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"stability-flags": {
|
||||
"utopia-php/database": 5
|
||||
},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
|
||||
+2
-2
@@ -196,7 +196,7 @@ services:
|
||||
appwrite-console:
|
||||
<<: *x-logging
|
||||
container_name: appwrite-console
|
||||
image: appwrite/console:5.0.4
|
||||
image: appwrite/console:5.0.12
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
@@ -874,7 +874,7 @@ services:
|
||||
hostname: exc1
|
||||
<<: *x-logging
|
||||
stop_signal: SIGINT
|
||||
image: openruntimes/executor:0.6.7
|
||||
image: openruntimes/executor:0.6.11
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
|
||||
@@ -11,7 +11,8 @@ const result = await databases.updateBooleanAttribute(
|
||||
'<COLLECTION_ID>', // collectionId
|
||||
'', // key
|
||||
false, // required
|
||||
false // default
|
||||
false, // default
|
||||
'' // newKey (optional)
|
||||
);
|
||||
|
||||
console.log(result);
|
||||
|
||||
@@ -11,7 +11,8 @@ const result = await databases.updateDatetimeAttribute(
|
||||
'<COLLECTION_ID>', // collectionId
|
||||
'', // key
|
||||
false, // required
|
||||
'' // default
|
||||
'', // default
|
||||
'' // newKey (optional)
|
||||
);
|
||||
|
||||
console.log(result);
|
||||
|
||||
@@ -11,7 +11,8 @@ const result = await databases.updateEmailAttribute(
|
||||
'<COLLECTION_ID>', // collectionId
|
||||
'', // key
|
||||
false, // required
|
||||
'email@example.com' // default
|
||||
'email@example.com', // default
|
||||
'' // newKey (optional)
|
||||
);
|
||||
|
||||
console.log(result);
|
||||
|
||||
@@ -12,7 +12,8 @@ const result = await databases.updateEnumAttribute(
|
||||
'', // key
|
||||
[], // elements
|
||||
false, // required
|
||||
'<DEFAULT>' // default
|
||||
'<DEFAULT>', // default
|
||||
'' // newKey (optional)
|
||||
);
|
||||
|
||||
console.log(result);
|
||||
|
||||
@@ -13,7 +13,8 @@ const result = await databases.updateFloatAttribute(
|
||||
false, // required
|
||||
null, // min
|
||||
null, // max
|
||||
null // default
|
||||
null, // default
|
||||
'' // newKey (optional)
|
||||
);
|
||||
|
||||
console.log(result);
|
||||
|
||||
@@ -13,7 +13,8 @@ const result = await databases.updateIntegerAttribute(
|
||||
false, // required
|
||||
null, // min
|
||||
null, // max
|
||||
null // default
|
||||
null, // default
|
||||
'' // newKey (optional)
|
||||
);
|
||||
|
||||
console.log(result);
|
||||
|
||||
@@ -11,7 +11,8 @@ const result = await databases.updateIpAttribute(
|
||||
'<COLLECTION_ID>', // collectionId
|
||||
'', // key
|
||||
false, // required
|
||||
'' // default
|
||||
'', // default
|
||||
'' // newKey (optional)
|
||||
);
|
||||
|
||||
console.log(result);
|
||||
|
||||
@@ -10,7 +10,8 @@ const result = await databases.updateRelationshipAttribute(
|
||||
'<DATABASE_ID>', // databaseId
|
||||
'<COLLECTION_ID>', // collectionId
|
||||
'', // key
|
||||
RelationMutate.Cascade // onDelete (optional)
|
||||
RelationMutate.Cascade, // onDelete (optional)
|
||||
'' // newKey (optional)
|
||||
);
|
||||
|
||||
console.log(result);
|
||||
|
||||
@@ -11,7 +11,9 @@ const result = await databases.updateStringAttribute(
|
||||
'<COLLECTION_ID>', // collectionId
|
||||
'', // key
|
||||
false, // required
|
||||
'<DEFAULT>' // default
|
||||
'<DEFAULT>', // default
|
||||
null, // size (optional)
|
||||
'' // newKey (optional)
|
||||
);
|
||||
|
||||
console.log(result);
|
||||
|
||||
@@ -11,7 +11,8 @@ const result = await databases.updateUrlAttribute(
|
||||
'<COLLECTION_ID>', // collectionId
|
||||
'', // key
|
||||
false, // required
|
||||
'https://example.com' // default
|
||||
'https://example.com', // default
|
||||
'' // newKey (optional)
|
||||
);
|
||||
|
||||
console.log(result);
|
||||
|
||||
@@ -13,4 +13,5 @@ AttributeBoolean result = await databases.updateBooleanAttribute(
|
||||
key: '',
|
||||
xrequired: false,
|
||||
xdefault: false,
|
||||
newKey: '', // (optional)
|
||||
);
|
||||
|
||||
@@ -13,4 +13,5 @@ AttributeDatetime result = await databases.updateDatetimeAttribute(
|
||||
key: '',
|
||||
xrequired: false,
|
||||
xdefault: '',
|
||||
newKey: '', // (optional)
|
||||
);
|
||||
|
||||
@@ -13,4 +13,5 @@ AttributeEmail result = await databases.updateEmailAttribute(
|
||||
key: '',
|
||||
xrequired: false,
|
||||
xdefault: 'email@example.com',
|
||||
newKey: '', // (optional)
|
||||
);
|
||||
|
||||
@@ -14,4 +14,5 @@ AttributeEnum result = await databases.updateEnumAttribute(
|
||||
elements: [],
|
||||
xrequired: false,
|
||||
xdefault: '<DEFAULT>',
|
||||
newKey: '', // (optional)
|
||||
);
|
||||
|
||||
@@ -15,4 +15,5 @@ AttributeFloat result = await databases.updateFloatAttribute(
|
||||
min: 0,
|
||||
max: 0,
|
||||
xdefault: 0,
|
||||
newKey: '', // (optional)
|
||||
);
|
||||
|
||||
@@ -15,4 +15,5 @@ AttributeInteger result = await databases.updateIntegerAttribute(
|
||||
min: 0,
|
||||
max: 0,
|
||||
xdefault: 0,
|
||||
newKey: '', // (optional)
|
||||
);
|
||||
|
||||
@@ -13,4 +13,5 @@ AttributeIp result = await databases.updateIpAttribute(
|
||||
key: '',
|
||||
xrequired: false,
|
||||
xdefault: '',
|
||||
newKey: '', // (optional)
|
||||
);
|
||||
|
||||
@@ -12,4 +12,5 @@ AttributeRelationship result = await databases.updateRelationshipAttribute(
|
||||
collectionId: '<COLLECTION_ID>',
|
||||
key: '',
|
||||
onDelete: RelationMutate.cascade, // (optional)
|
||||
newKey: '', // (optional)
|
||||
);
|
||||
|
||||
@@ -13,4 +13,6 @@ AttributeString result = await databases.updateStringAttribute(
|
||||
key: '',
|
||||
xrequired: false,
|
||||
xdefault: '<DEFAULT>',
|
||||
size: 0, // (optional)
|
||||
newKey: '', // (optional)
|
||||
);
|
||||
|
||||
@@ -13,4 +13,5 @@ AttributeUrl result = await databases.updateUrlAttribute(
|
||||
key: '',
|
||||
xrequired: false,
|
||||
xdefault: 'https://example.com',
|
||||
newKey: '', // (optional)
|
||||
);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'dart:io';
|
||||
import 'package:dart_appwrite/dart_appwrite.dart';
|
||||
|
||||
Client client = Client()
|
||||
|
||||
@@ -12,5 +12,6 @@ const response = await databases.updateBooleanAttribute(
|
||||
'<COLLECTION_ID>', // collectionId
|
||||
'', // key
|
||||
false, // required
|
||||
false // default
|
||||
false, // default
|
||||
'' // newKey (optional)
|
||||
);
|
||||
|
||||
@@ -12,5 +12,6 @@ const response = await databases.updateDatetimeAttribute(
|
||||
'<COLLECTION_ID>', // collectionId
|
||||
'', // key
|
||||
false, // required
|
||||
'' // default
|
||||
'', // default
|
||||
'' // newKey (optional)
|
||||
);
|
||||
|
||||
@@ -12,5 +12,6 @@ const response = await databases.updateEmailAttribute(
|
||||
'<COLLECTION_ID>', // collectionId
|
||||
'', // key
|
||||
false, // required
|
||||
'email@example.com' // default
|
||||
'email@example.com', // default
|
||||
'' // newKey (optional)
|
||||
);
|
||||
|
||||
@@ -13,5 +13,6 @@ const response = await databases.updateEnumAttribute(
|
||||
'', // key
|
||||
[], // elements
|
||||
false, // required
|
||||
'<DEFAULT>' // default
|
||||
'<DEFAULT>', // default
|
||||
'' // newKey (optional)
|
||||
);
|
||||
|
||||
@@ -14,5 +14,6 @@ const response = await databases.updateFloatAttribute(
|
||||
false, // required
|
||||
null, // min
|
||||
null, // max
|
||||
null // default
|
||||
null, // default
|
||||
'' // newKey (optional)
|
||||
);
|
||||
|
||||
@@ -14,5 +14,6 @@ const response = await databases.updateIntegerAttribute(
|
||||
false, // required
|
||||
null, // min
|
||||
null, // max
|
||||
null // default
|
||||
null, // default
|
||||
'' // newKey (optional)
|
||||
);
|
||||
|
||||
@@ -12,5 +12,6 @@ const response = await databases.updateIpAttribute(
|
||||
'<COLLECTION_ID>', // collectionId
|
||||
'', // key
|
||||
false, // required
|
||||
'' // default
|
||||
'', // default
|
||||
'' // newKey (optional)
|
||||
);
|
||||
|
||||
@@ -11,5 +11,6 @@ const response = await databases.updateRelationshipAttribute(
|
||||
'<DATABASE_ID>', // databaseId
|
||||
'<COLLECTION_ID>', // collectionId
|
||||
'', // key
|
||||
RelationMutate.Cascade // onDelete (optional)
|
||||
RelationMutate.Cascade, // onDelete (optional)
|
||||
'' // newKey (optional)
|
||||
);
|
||||
|
||||
@@ -12,5 +12,7 @@ const response = await databases.updateStringAttribute(
|
||||
'<COLLECTION_ID>', // collectionId
|
||||
'', // key
|
||||
false, // required
|
||||
'<DEFAULT>' // default
|
||||
'<DEFAULT>', // default
|
||||
null, // size (optional)
|
||||
'' // newKey (optional)
|
||||
);
|
||||
|
||||
@@ -12,5 +12,6 @@ const response = await databases.updateUrlAttribute(
|
||||
'<COLLECTION_ID>', // collectionId
|
||||
'', // key
|
||||
false, // required
|
||||
'https://example.com' // default
|
||||
'https://example.com', // default
|
||||
'' // newKey (optional)
|
||||
);
|
||||
|
||||
@@ -14,5 +14,6 @@ AttributeBoolean result = await databases.UpdateBooleanAttribute(
|
||||
collectionId: "<COLLECTION_ID>",
|
||||
key: "",
|
||||
required: false,
|
||||
default: false
|
||||
default: false,
|
||||
newKey: "" // optional
|
||||
);
|
||||
@@ -14,5 +14,6 @@ AttributeDatetime result = await databases.UpdateDatetimeAttribute(
|
||||
collectionId: "<COLLECTION_ID>",
|
||||
key: "",
|
||||
required: false,
|
||||
default: ""
|
||||
default: "",
|
||||
newKey: "" // optional
|
||||
);
|
||||
@@ -14,5 +14,6 @@ AttributeEmail result = await databases.UpdateEmailAttribute(
|
||||
collectionId: "<COLLECTION_ID>",
|
||||
key: "",
|
||||
required: false,
|
||||
default: "email@example.com"
|
||||
default: "email@example.com",
|
||||
newKey: "" // optional
|
||||
);
|
||||
@@ -15,5 +15,6 @@ AttributeEnum result = await databases.UpdateEnumAttribute(
|
||||
key: "",
|
||||
elements: new List<string>(),
|
||||
required: false,
|
||||
default: "<DEFAULT>"
|
||||
default: "<DEFAULT>",
|
||||
newKey: "" // optional
|
||||
);
|
||||
@@ -16,5 +16,6 @@ AttributeFloat result = await databases.UpdateFloatAttribute(
|
||||
required: false,
|
||||
min: 0,
|
||||
max: 0,
|
||||
default: 0
|
||||
default: 0,
|
||||
newKey: "" // optional
|
||||
);
|
||||
@@ -16,5 +16,6 @@ AttributeInteger result = await databases.UpdateIntegerAttribute(
|
||||
required: false,
|
||||
min: 0,
|
||||
max: 0,
|
||||
default: 0
|
||||
default: 0,
|
||||
newKey: "" // optional
|
||||
);
|
||||
@@ -14,5 +14,6 @@ AttributeIp result = await databases.UpdateIpAttribute(
|
||||
collectionId: "<COLLECTION_ID>",
|
||||
key: "",
|
||||
required: false,
|
||||
default: ""
|
||||
default: "",
|
||||
newKey: "" // optional
|
||||
);
|
||||
+2
-1
@@ -14,5 +14,6 @@ AttributeRelationship result = await databases.UpdateRelationshipAttribute(
|
||||
databaseId: "<DATABASE_ID>",
|
||||
collectionId: "<COLLECTION_ID>",
|
||||
key: "",
|
||||
onDelete: RelationMutate.Cascade // optional
|
||||
onDelete: RelationMutate.Cascade, // optional
|
||||
newKey: "" // optional
|
||||
);
|
||||
@@ -14,5 +14,7 @@ AttributeString result = await databases.UpdateStringAttribute(
|
||||
collectionId: "<COLLECTION_ID>",
|
||||
key: "",
|
||||
required: false,
|
||||
default: "<DEFAULT>"
|
||||
default: "<DEFAULT>",
|
||||
size: 0, // optional
|
||||
newKey: "" // optional
|
||||
);
|
||||
@@ -14,5 +14,6 @@ AttributeUrl result = await databases.UpdateUrlAttribute(
|
||||
collectionId: "<COLLECTION_ID>",
|
||||
key: "",
|
||||
required: false,
|
||||
default: "https://example.com"
|
||||
default: "https://example.com",
|
||||
newKey: "" // optional
|
||||
);
|
||||
@@ -20,6 +20,7 @@ func main() {
|
||||
"",
|
||||
false,
|
||||
false,
|
||||
databases.WithUpdateBooleanAttributeNewKey(""),
|
||||
)
|
||||
|
||||
if error != nil {
|
||||
|
||||
@@ -20,6 +20,7 @@ func main() {
|
||||
"",
|
||||
false,
|
||||
"",
|
||||
databases.WithUpdateDatetimeAttributeNewKey(""),
|
||||
)
|
||||
|
||||
if error != nil {
|
||||
|
||||
@@ -20,6 +20,7 @@ func main() {
|
||||
"",
|
||||
false,
|
||||
"email@example.com",
|
||||
databases.WithUpdateEmailAttributeNewKey(""),
|
||||
)
|
||||
|
||||
if error != nil {
|
||||
|
||||
@@ -21,6 +21,7 @@ func main() {
|
||||
[]interface{}{},
|
||||
false,
|
||||
"<DEFAULT>",
|
||||
databases.WithUpdateEnumAttributeNewKey(""),
|
||||
)
|
||||
|
||||
if error != nil {
|
||||
|
||||
@@ -22,6 +22,7 @@ func main() {
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
databases.WithUpdateFloatAttributeNewKey(""),
|
||||
)
|
||||
|
||||
if error != nil {
|
||||
|
||||
@@ -22,6 +22,7 @@ func main() {
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
databases.WithUpdateIntegerAttributeNewKey(""),
|
||||
)
|
||||
|
||||
if error != nil {
|
||||
|
||||
@@ -20,6 +20,7 @@ func main() {
|
||||
"",
|
||||
false,
|
||||
"",
|
||||
databases.WithUpdateIpAttributeNewKey(""),
|
||||
)
|
||||
|
||||
if error != nil {
|
||||
|
||||
@@ -19,6 +19,7 @@ func main() {
|
||||
"<COLLECTION_ID>",
|
||||
"",
|
||||
databases.WithUpdateRelationshipAttributeOnDelete("cascade"),
|
||||
databases.WithUpdateRelationshipAttributeNewKey(""),
|
||||
)
|
||||
|
||||
if error != nil {
|
||||
|
||||
@@ -20,6 +20,8 @@ func main() {
|
||||
"",
|
||||
false,
|
||||
"<DEFAULT>",
|
||||
databases.WithUpdateStringAttributeSize(0),
|
||||
databases.WithUpdateStringAttributeNewKey(""),
|
||||
)
|
||||
|
||||
if error != nil {
|
||||
|
||||
@@ -20,6 +20,7 @@ func main() {
|
||||
"",
|
||||
false,
|
||||
"https://example.com",
|
||||
databases.WithUpdateUrlAttributeNewKey(""),
|
||||
)
|
||||
|
||||
if error != nil {
|
||||
|
||||
@@ -4,7 +4,8 @@ mutation {
|
||||
collectionId: "<COLLECTION_ID>",
|
||||
key: "",
|
||||
required: false,
|
||||
default: false
|
||||
default: false,
|
||||
newKey: ""
|
||||
) {
|
||||
key
|
||||
type
|
||||
|
||||
@@ -4,7 +4,8 @@ mutation {
|
||||
collectionId: "<COLLECTION_ID>",
|
||||
key: "",
|
||||
required: false,
|
||||
default: ""
|
||||
default: "",
|
||||
newKey: ""
|
||||
) {
|
||||
key
|
||||
type
|
||||
|
||||
@@ -4,7 +4,8 @@ mutation {
|
||||
collectionId: "<COLLECTION_ID>",
|
||||
key: "",
|
||||
required: false,
|
||||
default: "email@example.com"
|
||||
default: "email@example.com",
|
||||
newKey: ""
|
||||
) {
|
||||
key
|
||||
type
|
||||
|
||||
@@ -5,7 +5,8 @@ mutation {
|
||||
key: "",
|
||||
elements: [],
|
||||
required: false,
|
||||
default: "<DEFAULT>"
|
||||
default: "<DEFAULT>",
|
||||
newKey: ""
|
||||
) {
|
||||
key
|
||||
type
|
||||
|
||||
@@ -6,7 +6,8 @@ mutation {
|
||||
required: false,
|
||||
min: 0,
|
||||
max: 0,
|
||||
default: 0
|
||||
default: 0,
|
||||
newKey: ""
|
||||
) {
|
||||
key
|
||||
type
|
||||
|
||||
@@ -6,7 +6,8 @@ mutation {
|
||||
required: false,
|
||||
min: 0,
|
||||
max: 0,
|
||||
default: 0
|
||||
default: 0,
|
||||
newKey: ""
|
||||
) {
|
||||
key
|
||||
type
|
||||
|
||||
@@ -4,7 +4,8 @@ mutation {
|
||||
collectionId: "<COLLECTION_ID>",
|
||||
key: "",
|
||||
required: false,
|
||||
default: ""
|
||||
default: "",
|
||||
newKey: ""
|
||||
) {
|
||||
key
|
||||
type
|
||||
|
||||
+2
-1
@@ -3,7 +3,8 @@ mutation {
|
||||
databaseId: "<DATABASE_ID>",
|
||||
collectionId: "<COLLECTION_ID>",
|
||||
key: "",
|
||||
onDelete: "cascade"
|
||||
onDelete: "cascade",
|
||||
newKey: ""
|
||||
) {
|
||||
key
|
||||
type
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user