Merge branch 'appwrite:master' into feat-926-oauth2-microsoft-tenant-config
This commit is contained in:
commit
05ff84d1f6
|
@ -1,10 +1,9 @@
|
|||
name: "Tests"
|
||||
|
||||
on: [pull_request]
|
||||
jobs:
|
||||
tests:
|
||||
name: Unit & E2E
|
||||
runs-on: self-hosted
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
|
@ -19,16 +18,29 @@ jobs:
|
|||
- run: git checkout HEAD^2
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
- name: Build Appwrite
|
||||
# Upstream bug causes buildkit pulls to fail so prefetch base images
|
||||
# https://github.com/moby/moby/issues/41864
|
||||
- name: Prepare Docker
|
||||
run: |
|
||||
export COMPOSE_INTERACTIVE_NO_CLI
|
||||
export DOCKER_BUILDKIT=1
|
||||
export COMPOSE_DOCKER_CLI_BUILD=1
|
||||
echo "_APP_FUNCTIONS_RUNTIMES=php-8.0" >> .env
|
||||
docker pull composer:2.0
|
||||
docker pull php:8.0-cli-alpine
|
||||
docker compose build --progress=plain
|
||||
docker compose pull
|
||||
|
||||
- name: Prepare Cache
|
||||
uses: satackey/action-docker-layer-caching@v0.0.11
|
||||
# Ignore the failure of a step and avoid terminating the job.
|
||||
continue-on-error: true
|
||||
|
||||
- name: Build Appwrite
|
||||
run: docker compose build --progress=plain
|
||||
|
||||
- name: Start Appwrite
|
||||
run: |
|
||||
docker compose up -d
|
||||
sleep 30
|
||||
|
||||
- name: Doctor
|
||||
run: docker compose exec -T appwrite doctor
|
||||
|
||||
|
@ -37,9 +49,3 @@ jobs:
|
|||
|
||||
- name: Run Tests
|
||||
run: docker compose exec -T appwrite test --debug
|
||||
|
||||
- name: Teardown
|
||||
if: always()
|
||||
run: |
|
||||
docker compose down -v
|
||||
docker ps -aq | xargs docker rm --force
|
|
@ -1,29 +0,0 @@
|
|||
#!/bin/bash bash
|
||||
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
echo "Missing tag number"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$2" ]
|
||||
then
|
||||
echo "Missing version number"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test $(find "./app/db/DBIP/dbip-country-lite-2021-12.mmdb" -mmin +259200)
|
||||
then
|
||||
printf "${RED}GEO country DB has not been updated for more than 6 months. Go to https://db-ip.com/db/download/ip-to-country-lite to download a newer version${NC}\n"
|
||||
fi
|
||||
|
||||
echo 'Starting build...'
|
||||
|
||||
docker build --build-arg VERSION="$2" --tag appwrite/appwrite:"$1" .
|
||||
|
||||
echo 'Pushing build to registry...'
|
||||
|
||||
docker push appwrite/appwrite:"$1"
|
|
@ -1 +0,0 @@
|
|||
echo 'Nothing to deploy right now.'
|
87
.travis.yml
87
.travis.yml
|
@ -1,87 +0,0 @@
|
|||
dist: focal
|
||||
|
||||
arch:
|
||||
- amd64
|
||||
|
||||
os: linux
|
||||
|
||||
vm:
|
||||
size: large
|
||||
|
||||
language: shell
|
||||
|
||||
notifications:
|
||||
email:
|
||||
- team@appwrite.io
|
||||
|
||||
before_install:
|
||||
# Install latest Docker
|
||||
- curl -fsSL https://get.docker.com | sh
|
||||
# Enable Buildkit in Docker config
|
||||
- echo '{"experimental":"enabled"}' | sudo tee /etc/docker/daemon.json
|
||||
- mkdir -p $HOME/.docker
|
||||
- echo '{"experimental":"enabled"}' | sudo tee $HOME/.docker/config.json
|
||||
- sudo service docker start
|
||||
# Login to increase Docker Hub ratelimit
|
||||
- >
|
||||
if [ ! -z "${DOCKERHUB_PULL_USERNAME:-}" ]; then
|
||||
echo "${DOCKERHUB_PULL_PASSWORD}" | docker login --username "${DOCKERHUB_PULL_USERNAME}" --password-stdin
|
||||
fi
|
||||
- docker --version
|
||||
# Install latest Compose
|
||||
- sudo rm /usr/local/bin/docker-compose
|
||||
- curl -L https://github.com/docker/compose/releases/download/1.29.2/docker-compose-`uname -s`-`uname -m` > docker-compose
|
||||
- chmod +x docker-compose
|
||||
- sudo mv docker-compose /usr/local/bin
|
||||
- docker-compose --version
|
||||
# Enable Buildkit
|
||||
- docker buildx create --name travis_builder --use
|
||||
- export COMPOSE_INTERACTIVE_NO_CLI
|
||||
- export DOCKER_BUILDKIT=1
|
||||
- export COMPOSE_DOCKER_CLI_BUILD=1
|
||||
- export BUILDKIT_PROGRESS=plain
|
||||
# Only pass a single runtime for CI stability
|
||||
- echo "_APP_FUNCTIONS_RUNTIMES=php-8.0" >> .env
|
||||
# Ensure Travis scripts are executable
|
||||
- chmod -R u+x ./.travis-ci
|
||||
|
||||
install:
|
||||
- docker-compose pull
|
||||
# Upstream bug causes buildkit pulls to fail so prefetch base images
|
||||
# https://github.com/moby/moby/issues/41864
|
||||
- docker pull composer:2.0
|
||||
- docker pull php:8.0-cli-alpine
|
||||
- docker-compose build
|
||||
- docker-compose up -d
|
||||
- sleep 60
|
||||
|
||||
script:
|
||||
- docker ps -a
|
||||
# Tests should fail if any container is in exited status
|
||||
# - ALL_UP=`docker ps -aq --filter "status=exited"`
|
||||
# - >
|
||||
# if [[ "$ALL_UP" != "" ]]; then
|
||||
# exit 1
|
||||
# fi
|
||||
- docker-compose logs appwrite
|
||||
- docker-compose logs appwrite-realtime
|
||||
- docker-compose logs mariadb
|
||||
- docker-compose logs appwrite-worker-functions
|
||||
- docker-compose exec appwrite doctor
|
||||
- docker-compose exec appwrite vars
|
||||
- docker-compose exec appwrite test --debug
|
||||
|
||||
after_script:
|
||||
# travis re-uses their build nodes so clean them up
|
||||
- docker buildx rm travis_builder
|
||||
|
||||
after_failure:
|
||||
- docker-compose logs appwrite
|
||||
|
||||
deploy:
|
||||
- provider: script
|
||||
edge: true
|
||||
script: ./.travis-ci/deploy.sh
|
||||
on:
|
||||
repo: appwrite/appwrite
|
||||
branch: deploy
|
|
@ -12,7 +12,7 @@ RUN composer install --ignore-platform-reqs --optimize-autoloader \
|
|||
--no-plugins --no-scripts --prefer-dist \
|
||||
`if [ "$TESTING" != "true" ]; then echo "--no-dev"; fi`
|
||||
|
||||
FROM node:16-alpine as node
|
||||
FROM node:16.13.2-alpine3.15 as node
|
||||
|
||||
WORKDIR /usr/local/src/
|
||||
|
||||
|
@ -24,7 +24,7 @@ COPY public /usr/local/src/public
|
|||
RUN npm ci
|
||||
RUN npm run build
|
||||
|
||||
FROM php:8.0-cli-alpine as compile
|
||||
FROM php:8.0.14-cli-alpine3.15 as compile
|
||||
|
||||
ARG DEBUG=false
|
||||
ENV DEBUG=$DEBUG
|
||||
|
@ -123,7 +123,7 @@ RUN \
|
|||
./configure && \
|
||||
make && make install
|
||||
|
||||
FROM php:8.0-cli-alpine as final
|
||||
FROM php:8.0.14-cli-alpine3.15 as final
|
||||
|
||||
LABEL maintainer="team@appwrite.io"
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ App::post('/v1/account')
|
|||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_USER)
|
||||
->label('abuse-limit', 10)
|
||||
->param('userId', '', new CustomId(), 'Unique Id. Choose your own unique ID or pass the string `unique()` to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('userId', '', new CustomId(), 'Unique Id. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('email', '', new Email(), 'User email.')
|
||||
->param('password', '', new Password(), 'User password. Must be at least 8 chars.')
|
||||
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
|
||||
|
@ -615,7 +615,7 @@ App::post('/v1/account/sessions/magic-url')
|
|||
->label('sdk.response.model', Response::MODEL_TOKEN)
|
||||
->label('abuse-limit', 10)
|
||||
->label('abuse-key', 'url:{url},email:{param-email}')
|
||||
->param('userId', '', new CustomId(), 'Unique Id. Choose your own unique ID or pass the string `unique()` to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('userId', '', new CustomId(), 'Unique Id. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('email', '', new Email(), 'User email.')
|
||||
->param('url', '', function ($clients) { return new Host($clients); }, 'URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients'])
|
||||
->inject('request')
|
||||
|
|
|
@ -148,7 +148,7 @@ App::post('/v1/database/collections')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_COLLECTION)
|
||||
->param('collectionId', '', new CustomId(), 'Unique Id. Choose your own unique ID or pass the string `unique()` to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('collectionId', '', new CustomId(), 'Unique Id. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('name', '', new Text(128), 'Collection name. Max length: 128 chars.')
|
||||
->param('permission', null, new WhiteList(['document', 'collection']), 'Permissions type model to use for reading documents in this collection. You can use collection-level permission set once on the collection using the `read` and `write` params, or you can set document-level permission where each document read and write params will decide who has access to read and write to each document individually. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.')
|
||||
->param('read', null, new Permissions(), 'An array of strings with read permissions. By default no user is granted with any read permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.')
|
||||
|
@ -230,7 +230,7 @@ App::get('/v1/database/collections')
|
|||
$queries = [];
|
||||
|
||||
if (!empty($search)) {
|
||||
$queries[] = new Query('name', Query::TYPE_SEARCH, [$search]);
|
||||
$queries[] = new Query('search', Query::TYPE_SEARCH, [$search]);
|
||||
}
|
||||
|
||||
$usage->setParam('database.collections.read', 1);
|
||||
|
@ -1563,7 +1563,7 @@ App::post('/v1/database/collections/:collectionId/documents')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_DOCUMENT)
|
||||
->param('documentId', '', new CustomId(), 'Document ID. Choose your own unique ID or pass the string `unique()` to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('documentId', '', new CustomId(), 'Document ID. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('collectionId', null, new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection). Make sure to define attributes before creating documents.')
|
||||
->param('data', [], new JSON(), 'Document data as JSON object.')
|
||||
->param('read', null, new Permissions(), 'An array of strings with read permissions. By default only the current user is granted with read permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.', true)
|
||||
|
@ -1832,7 +1832,7 @@ App::get('/v1/database/collections/:collectionId/documents/:documentId')
|
|||
$usage
|
||||
->setParam('database.documents.read', 1)
|
||||
->setParam('collectionId', $collectionId)
|
||||
;
|
||||
;
|
||||
|
||||
$response->dynamic($document, Response::MODEL_DOCUMENT);
|
||||
});
|
||||
|
|
|
@ -39,7 +39,7 @@ App::post('/v1/functions')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_FUNCTION)
|
||||
->param('functionId', '', new CustomId(), 'Function ID. Choose your own unique ID or pass the string `unique()` to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('functionId', '', new CustomId(), 'Function ID. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('name', '', new Text(128), 'Function name. Max length: 128 chars.')
|
||||
->param('execute', [], new ArrayList(new Text(64)), 'An array of strings with execution permissions. By default no user is granted with any execute permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.')
|
||||
->param('runtime', '', new WhiteList(array_keys(Config::getParam('runtimes')), true), 'Execution runtime.')
|
||||
|
@ -714,7 +714,7 @@ App::post('/v1/functions/:functionId/executions')
|
|||
throw new Exception('Tag not found. Deploy tag before trying to execute a function', 404);
|
||||
}
|
||||
|
||||
$validator = new Authorization($function, 'execute');
|
||||
$validator = new Authorization('execute');
|
||||
|
||||
if (!$validator->isValid($function->getAttribute('execute'))) { // Check if user has write access to execute function
|
||||
throw new Exception($validator->getDescription(), 401);
|
||||
|
|
|
@ -43,7 +43,7 @@ App::post('/v1/projects')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_PROJECT)
|
||||
->param('projectId', '', new CustomId(), 'Unique Id. Choose your own unique ID or pass the string `unique()` to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('projectId', '', new CustomId(), 'Unique Id. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('name', null, new Text(128), 'Project name. Max length: 128 chars.')
|
||||
->param('teamId', '', new UID(), 'Team unique ID.')
|
||||
->param('description', '', new Text(256), 'Project description. Max length: 256 chars.', true)
|
||||
|
|
|
@ -41,7 +41,7 @@ App::post('/v1/storage/files')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_FILE)
|
||||
->param('fileId', '', new CustomId(), 'File ID. Choose your own unique ID or pass the string `unique()` to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('fileId', '', new CustomId(), 'File ID. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('file', [], new File(), 'Binary file.', false)
|
||||
->param('read', null, new ArrayList(new Text(64)), 'An array of strings with read permissions. By default only the current user is granted with read permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.', true)
|
||||
->param('write', null, new ArrayList(new Text(64)), 'An array of strings with write permissions. By default only the current user is granted with write permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.', true)
|
||||
|
|
|
@ -34,7 +34,7 @@ App::post('/v1/teams')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_TEAM)
|
||||
->param('teamId', '', new CustomId(), 'Team ID. Choose your own unique ID or pass the string `unique()` to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('teamId', '', new CustomId(), 'Team ID. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('name', null, new Text(128), 'Team name. Max length: 128 chars.')
|
||||
->param('roles', ['owner'], new ArrayList(new Key()), 'Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](/docs/permissions). Max length for each role is 32 chars.', true)
|
||||
->inject('response')
|
||||
|
|
|
@ -34,7 +34,7 @@ App::post('/v1/users')
|
|||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_USER)
|
||||
->param('userId', '', new CustomId(), 'User ID. Choose your own unique ID or pass the string `unique()` to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('userId', '', new CustomId(), 'User ID. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('email', '', new Email(), 'User email.')
|
||||
->param('password', '', new Password(), 'User password. Must be at least 8 chars.')
|
||||
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
|
||||
|
|
|
@ -167,6 +167,7 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons
|
|||
break;
|
||||
case version_compare ($responseFormat , '0.8.0', '<=') :
|
||||
Response::setFilter(new V08());
|
||||
break;
|
||||
case version_compare ($responseFormat , '0.11.0', '<=') :
|
||||
Response::setFilter(new V11());
|
||||
break;
|
||||
|
|
|
@ -620,6 +620,7 @@ $logs = $this->getParam('logs', null);
|
|||
data-failure="alert"
|
||||
data-failure-param-alert-text="Failed to create attribute"
|
||||
data-failure-param-alert-classname="error"
|
||||
@reset="array = required = false"
|
||||
x-data="{ array: false, required: false }">
|
||||
|
||||
<input type="hidden" name="projectId" data-ls-bind="{{router.params.project}}" />
|
||||
|
@ -675,6 +676,7 @@ $logs = $this->getParam('logs', null);
|
|||
data-failure="alert"
|
||||
data-failure-param-alert-text="Failed to create attribute"
|
||||
data-failure-param-alert-classname="error"
|
||||
@reset="array = required = false"
|
||||
x-data="{ array: false, required: false }">
|
||||
|
||||
<input type="hidden" name="projectId" data-ls-bind="{{router.params.project}}" />
|
||||
|
@ -706,10 +708,10 @@ $logs = $this->getParam('logs', null);
|
|||
<label for="integer-default">Default Value</label>
|
||||
|
||||
<template x-if="!(array || required)">
|
||||
<input name="xdefault" type="number" class="margin-bottom-large" autocomplete="off">
|
||||
<input name="xdefault" type="number" class="margin-bottom-large" autocomplete="off" data-cast-to="integer">
|
||||
</template>
|
||||
<template x-if="(array || required)">
|
||||
<input name="xdefault" type="number" class="margin-bottom-large" autocomplete="off" disabled value="">
|
||||
<input name="xdefault" type="number" class="margin-bottom-large" autocomplete="off" data-cast-to="integer" disabled>
|
||||
</template>
|
||||
|
||||
<footer>
|
||||
|
@ -739,6 +741,7 @@ $logs = $this->getParam('logs', null);
|
|||
data-failure="alert"
|
||||
data-failure-param-alert-text="Failed to create attribute"
|
||||
data-failure-param-alert-classname="error"
|
||||
@reset="array = required = false"
|
||||
x-data="{ array: false, required: false }">
|
||||
|
||||
<input type="hidden" name="projectId" data-ls-bind="{{router.params.project}}" />
|
||||
|
@ -770,10 +773,10 @@ $logs = $this->getParam('logs', null);
|
|||
<label for="float-default">Default Value</label>
|
||||
|
||||
<template x-if="!(array || required)">
|
||||
<input name="xdefault" type="number" step="0.01" class="margin-bottom-large" autocomplete="off">
|
||||
<input name="xdefault" type="number" step="0.01" class="margin-bottom-large" autocomplete="off" data-cast-to="float">
|
||||
</template>
|
||||
<template x-if="(array || required)">
|
||||
<input name="xdefault" type="number" step="0.01" class="margin-bottom-large" autocomplete="off" disabled value="">
|
||||
<input name="xdefault" type="number" step="0.01" class="margin-bottom-large" autocomplete="off" data-cast-to="float" disabled>
|
||||
</template>
|
||||
|
||||
<footer>
|
||||
|
@ -803,6 +806,7 @@ $logs = $this->getParam('logs', null);
|
|||
data-failure="alert"
|
||||
data-failure-param-alert-text="Failed to create attribute"
|
||||
data-failure-param-alert-classname="error"
|
||||
@reset="array = required = false"
|
||||
x-data="{ array: false, required: false }">
|
||||
|
||||
<input type="hidden" name="projectId" data-ls-bind="{{router.params.project}}" />
|
||||
|
@ -855,6 +859,7 @@ $logs = $this->getParam('logs', null);
|
|||
data-failure="alert"
|
||||
data-failure-param-alert-text="Failed to create attribute"
|
||||
data-failure-param-alert-classname="error"
|
||||
@reset="array = required = false"
|
||||
x-data="{ array: false, required: false }">
|
||||
|
||||
<input type="hidden" name="projectId" data-ls-bind="{{router.params.project}}" />
|
||||
|
@ -911,6 +916,7 @@ $logs = $this->getParam('logs', null);
|
|||
data-failure="alert"
|
||||
data-failure-param-alert-text="Failed to create attribute"
|
||||
data-failure-param-alert-classname="error"
|
||||
@reset="array = required = false"
|
||||
x-data="{ array: false, required: false }">
|
||||
|
||||
<input type="hidden" name="projectId" data-ls-bind="{{router.params.project}}" />
|
||||
|
@ -963,6 +969,7 @@ $logs = $this->getParam('logs', null);
|
|||
data-failure="alert"
|
||||
data-failure-param-alert-text="Failed to create attribute"
|
||||
data-failure-param-alert-classname="error"
|
||||
@reset="array = required = false"
|
||||
x-data="{ array: false, required: false }">
|
||||
|
||||
<input type="hidden" name="projectId" data-ls-bind="{{router.params.project}}" />
|
||||
|
@ -1015,6 +1022,7 @@ $logs = $this->getParam('logs', null);
|
|||
data-failure="alert"
|
||||
data-failure-param-alert-text="Failed to create attribute"
|
||||
data-failure-param-alert-classname="error"
|
||||
@reset="array = required = false"
|
||||
x-data="{ array: false, required: false }">
|
||||
|
||||
<input type="hidden" name="projectId" data-ls-bind="{{router.params.project}}" />
|
||||
|
|
|
@ -115,7 +115,7 @@ $logs = $this->getParam('logs', null);
|
|||
:name="attr.key"
|
||||
:required="attr.required"
|
||||
x-model="doc[attr.key]"
|
||||
data-cast-to="integer" />
|
||||
data-cast-to="float" />
|
||||
</template>
|
||||
<template x-if="attr.type === 'boolean'">
|
||||
<input
|
||||
|
@ -205,7 +205,7 @@ $logs = $this->getParam('logs', null);
|
|||
:name="attr.key"
|
||||
:required="attr.required"
|
||||
x-model="doc[attr.key][index]"
|
||||
data-cast-to="integer" />
|
||||
data-cast-to="float" />
|
||||
</template>
|
||||
<template x-if="attr.type === 'boolean'">
|
||||
<input
|
||||
|
|
|
@ -176,7 +176,7 @@ $smtpEnabled = $this->getParam('smtpEnabled', false);
|
|||
<input type="email" class="full-width" id="user-email" name="email" required autocomplete="off" />
|
||||
|
||||
<label for="user-password">Password</label>
|
||||
<input type="password" class="full-width" id="user-password" name="password" required pattern=".{6,}" title="Six or more characters" autocomplete="off" />
|
||||
<input type="password" class="full-width" id="user-password" name="password" required minlength="8" title="Eight or more characters" autocomplete="off" />
|
||||
|
||||
<hr />
|
||||
|
||||
|
|
|
@ -28,10 +28,10 @@
|
|||
<input type="hidden" name="secret" data-ls-bind="{{router.params.secret}}">
|
||||
|
||||
<label>Password</label>
|
||||
<input name="password" type="password" autocomplete="off" placeholder="" required data-forms-password-meter pattern=".{6,}" title="Six or more characters">
|
||||
<input name="password" type="password" autocomplete="off" placeholder="" required data-forms-password-meter minlength="8" title="Eight or more characters">
|
||||
|
||||
<label>Confirm Password</label>
|
||||
<input name="passwordAgain" type="password" autocomplete="off" placeholder="" required data-forms-password-meter pattern=".{6,}" title="Six or more characters">
|
||||
<input name="passwordAgain" type="password" autocomplete="off" placeholder="" required data-forms-password-meter minlength="8" title="Eight or more characters">
|
||||
|
||||
<button type="submit" class="btn btn-primary"><i class="fa fa-sign-in"></i> Apply</button>
|
||||
</form>
|
||||
|
|
|
@ -37,7 +37,7 @@ $root = ($this->getParam('root') !== 'disabled');
|
|||
|
||||
<input name="email" type="email" class="full-width" autocomplete="email" placeholder="Email" required>
|
||||
|
||||
<input name="password" type="password" class="full-width" autocomplete="off" placeholder="Password" required pattern=".{6,}" title="Six or more characters">
|
||||
<input name="password" type="password" class="full-width" autocomplete="off" placeholder="Password" required minlength="8" title="Eight or more characters">
|
||||
|
||||
<button>Sign In</button>
|
||||
</form>
|
||||
|
|
|
@ -46,7 +46,7 @@ $root = ($this->getParam('root') !== 'disabled');
|
|||
<input name="email" type="email" autocomplete="email" placeholder="" required data-ls-bind="{{router.params.email}}">
|
||||
|
||||
<label>Password</label>
|
||||
<input name="password" type="password" autocomplete="off" placeholder="" required data-forms-password-meter pattern=".{8,}" title="Eight or more characters">
|
||||
<input name="password" type="password" autocomplete="off" placeholder="" required data-forms-password-meter minlength="8" title="Eight or more characters">
|
||||
|
||||
<div class="agree margin-top-large margin-bottom-large">
|
||||
<div class="pull-start margin-end-small margin-bottom">
|
||||
|
|
|
@ -1 +1 @@
|
|||
Use this endpoint to log out the currently logged in user from all their account sessions across all of their different devices. When using the option id argument, only the session unique ID provider will be deleted.
|
||||
Use this endpoint to log out the currently logged in user from all their account sessions across all of their different devices. When using the Session ID argument, only the unique session ID provided is deleted.
|
||||
|
|
|
@ -1,32 +1,32 @@
|
|||
# Introducing new Environment Variable
|
||||
|
||||
This document is part of the Appwrite contributors' guide. Before you continue reading this document make sure you have read the [Code of Conduct](https://github.com/appwrite/appwrite/blob/master/CODE_OF_CONDUCT.md) and the [Contributing Guide](https://github.com/appwrite/appwrite/blob/master/CONTRIBUTING.md).
|
||||
This document is part of the Appwrite contributors' guide. Before you continue reading this document, make sure you have read the [Code of Conduct](https://github.com/appwrite/appwrite/blob/master/CODE_OF_CONDUCT.md) and the [Contributing Guide](https://github.com/appwrite/appwrite/blob/master/CONTRIBUTING.md).
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Agenda
|
||||
Adding new features may require various configurations options to be set by the users. And for such options we use environment variables in Appwrite.
|
||||
Adding new features may require various configurations options to be set by the users. And for such options, we use environment variables in Appwrite.
|
||||
|
||||
This tutorial will cover, how to properly add a new environment variable in Appwrite.
|
||||
This tutorial will cover how to properly add a new environment variable in Appwrite.
|
||||
|
||||
### Naming environment variable
|
||||
The environment variables in Appwrite are prefixed with `_APP_`. If it belongs to a specific category, the category name is appended as `_APP_REDIS` for the redis category. The available categories are General, Redis, MariaDB, InfluxDB, StatsD, SMTP, Storage and Functions. Finally a properly describing name is given to the variable. For example `_APP_REDIS_HOST` is an environment variable for redis connection host. You can find more information on available categories and existing environment variables in the [environment variables doc](https://appwrite.io/docs/environment-variables).
|
||||
The environment variables in Appwrite are prefixed with `_APP_`. If it belongs to a specific category, the category name is appended as `_APP_REDIS` for the Redis category. The available categories are General, Redis, MariaDB, InfluxDB, StatsD, SMTP, Storage and Functions. Finally, a properly describing name is given to the variable. For example, `_APP_REDIS_HOST` is an environment variable for Redis connection host. You can find more information on available categories and existing environment variables in the [environment variables doc](https://appwrite.io/docs/environment-variables).
|
||||
|
||||
### Describe new environment variable
|
||||
First of all, we add the new environment variable to `app/config/variables.php` in the designated category. If none of the categories fit, add it to the General category. Copy the existing variables description to create a new one, so that you will not miss any required fields.
|
||||
First of all, we add the new environment variable to `app/config/variables.php` in the designated category. If none of the categories fit, add it to the General category. Copy the existing variable description to create a new one so that you will not miss any required fields.
|
||||
|
||||
This information is also used to generate the website documentation at https://appwrite.io/docs/environment-variables, so please use good descriptions that clearly define the purpose and other required info about the environment variable that you are adding.
|
||||
|
||||
### Add to .env and Dockerfile
|
||||
If newly introduced environment variable has a default value, add it to the `.env` and `Dockerfile` along with other environment variables. `.env` file uses settings for Appwrite development environment.
|
||||
If the newly introduced environment variable has a default value, add it to the `.env` and `Dockerfile` along with other environment variables. `.env` file uses settings for Appwrite development environment.
|
||||
|
||||
### Add to docker compose file and template
|
||||
Add the new environment variables to the `docker-compose.yml` and `app/views/install/compose.phtml` for each docker services that require access to those environment variables.
|
||||
### Add to Docker Compose file and template
|
||||
Add the new environment variables to the `docker-compose.yml` and `app/views/install/compose.phtml` for each docker service that requires access to those environment variables.
|
||||
|
||||
The `docker-compose.yml` file is used by the Appwrite maintainers during development where as `app/views/install/compose.phtml` file is used by the Appwrite setup script.
|
||||
The `docker-compose.yml` file is used by the Appwrite maintainers during development, whereas the `app/views/install/compose.phtml` file is used by the Appwrite setup script.
|
||||
|
||||
With these steps, your environment variable is properly added and can be accessed inside Appwrite code and any other containers where it is passed. You can access and use those variables to implement the features you are trying to achieve.
|
||||
|
||||
If everything went well, commit and initiate a PR and wait for the Appwrite team's approval.
|
||||
|
||||
Whooho! you have successfully added new environment variable to Appwrite. 🎉
|
||||
Whooho! You have successfully added a new environment variable to Appwrite. 🎉
|
||||
|
|
28
package-lock.json
generated
28
package-lock.json
generated
|
@ -9,8 +9,8 @@
|
|||
"version": "0.1.0",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"chart.js": "^3.6.2",
|
||||
"markdown-it": "^12.3.0",
|
||||
"chart.js": "^3.7.0",
|
||||
"markdown-it": "^12.3.2",
|
||||
"pell": "^1.0.6",
|
||||
"prismjs": "^1.25.0",
|
||||
"turndown": "^7.1.1"
|
||||
|
@ -549,9 +549,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/chart.js": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.6.2.tgz",
|
||||
"integrity": "sha512-Xz7f/fgtVltfQYWq0zL1Xbv7N2inpG+B54p3D5FSvpCdy3sM+oZhbqa42eNuYXltaVvajgX5UpKCU2GeeJIgxg=="
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.7.0.tgz",
|
||||
"integrity": "sha512-31gVuqqKp3lDIFmzpKIrBeum4OpZsQjSIAqlOpgjosHDJZlULtvwLEZKtEhIAZc7JMPaHlYMys40Qy9Mf+1AAg=="
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "2.1.8",
|
||||
|
@ -2862,9 +2862,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/markdown-it": {
|
||||
"version": "12.3.0",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.0.tgz",
|
||||
"integrity": "sha512-T345UZZ6ejQWTjG6PSEHplzNy5m4kF6zvUpHVDv8Snl/pEU0OxIK0jGg8YLVNwJvT8E0YJC7/2UvssJDk/wQCQ==",
|
||||
"version": "12.3.2",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
|
||||
"integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1",
|
||||
"entities": "~2.1.0",
|
||||
|
@ -5484,9 +5484,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"chart.js": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.6.2.tgz",
|
||||
"integrity": "sha512-Xz7f/fgtVltfQYWq0zL1Xbv7N2inpG+B54p3D5FSvpCdy3sM+oZhbqa42eNuYXltaVvajgX5UpKCU2GeeJIgxg=="
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.7.0.tgz",
|
||||
"integrity": "sha512-31gVuqqKp3lDIFmzpKIrBeum4OpZsQjSIAqlOpgjosHDJZlULtvwLEZKtEhIAZc7JMPaHlYMys40Qy9Mf+1AAg=="
|
||||
},
|
||||
"chokidar": {
|
||||
"version": "2.1.8",
|
||||
|
@ -7413,9 +7413,9 @@
|
|||
}
|
||||
},
|
||||
"markdown-it": {
|
||||
"version": "12.3.0",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.0.tgz",
|
||||
"integrity": "sha512-T345UZZ6ejQWTjG6PSEHplzNy5m4kF6zvUpHVDv8Snl/pEU0OxIK0jGg8YLVNwJvT8E0YJC7/2UvssJDk/wQCQ==",
|
||||
"version": "12.3.2",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
|
||||
"integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
|
||||
"requires": {
|
||||
"argparse": "^2.0.1",
|
||||
"entities": "~2.1.0",
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
"gulp-less": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"chart.js": "^3.6.2",
|
||||
"markdown-it": "^12.3.0",
|
||||
"chart.js": "^3.7.0",
|
||||
"markdown-it": "^12.3.2",
|
||||
"pell": "^1.0.6",
|
||||
"prismjs": "^1.25.0",
|
||||
"turndown": "^7.1.1"
|
||||
|
|
|
@ -26,6 +26,7 @@ use Appwrite\Utopia\Response\Model\Continent;
|
|||
use Appwrite\Utopia\Response\Model\Country;
|
||||
use Appwrite\Utopia\Response\Model\Currency;
|
||||
use Appwrite\Utopia\Response\Model\Document as ModelDocument;
|
||||
use Appwrite\Utopia\Response\Model\DocumentList;
|
||||
use Appwrite\Utopia\Response\Model\Domain;
|
||||
use Appwrite\Utopia\Response\Model\Error;
|
||||
use Appwrite\Utopia\Response\Model\ErrorDev;
|
||||
|
@ -205,9 +206,9 @@ class Response extends SwooleResponse
|
|||
->setModel(new Error())
|
||||
->setModel(new ErrorDev())
|
||||
// Lists
|
||||
->setModel(new BaseList('Documents List', self::MODEL_DOCUMENT_LIST, 'documents', self::MODEL_DOCUMENT))
|
||||
->setModel(new BaseList('Collections List', self::MODEL_COLLECTION_LIST, 'collections', self::MODEL_COLLECTION))
|
||||
->setModel(new BaseList('Indexes List', self::MODEL_INDEX_LIST, 'indexes', self::MODEL_INDEX))
|
||||
->setModel(new BaseList('Documents List', self::MODEL_DOCUMENT_LIST, 'documents', self::MODEL_DOCUMENT))
|
||||
->setModel(new BaseList('Users List', self::MODEL_USER_LIST, 'users', self::MODEL_USER))
|
||||
->setModel(new BaseList('Sessions List', self::MODEL_SESSION_LIST, 'sessions', self::MODEL_SESSION))
|
||||
->setModel(new BaseList('Logs List', self::MODEL_LOG_LIST, 'logs', self::MODEL_LOG))
|
||||
|
@ -370,13 +371,13 @@ class Response extends SwooleResponse
|
|||
$model = $this->getModel($model);
|
||||
$output = [];
|
||||
|
||||
$document = $model->filter($document);
|
||||
|
||||
if ($model->isAny()) {
|
||||
$this->payload = $document->getArrayCopy();
|
||||
return $this->payload;
|
||||
}
|
||||
|
||||
$document = $model->filter($document);
|
||||
|
||||
foreach ($model->getRules() as $key => $rule) {
|
||||
if (!$document->isSet($key) && $rule['require']) { // do not set attribute in response if not required
|
||||
if (!is_null($rule['default'])) {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Document as DatabaseDocument;
|
||||
|
||||
class Document extends Any
|
||||
{
|
||||
|
@ -57,4 +58,11 @@ class Document extends Any
|
|||
])
|
||||
;
|
||||
}
|
||||
|
||||
public function filter(DatabaseDocument $document): DatabaseDocument
|
||||
{
|
||||
$document->removeAttribute('$internalId');
|
||||
|
||||
return $document;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ abstract class Scope extends TestCase
|
|||
|
||||
protected function getLastEmail():array
|
||||
{
|
||||
sleep(5);
|
||||
sleep(3);
|
||||
|
||||
$emails = json_decode(file_get_contents('http://maildev:1080/email'), true);
|
||||
|
||||
|
@ -46,7 +46,7 @@ abstract class Scope extends TestCase
|
|||
|
||||
protected function getLastRequest():array
|
||||
{
|
||||
sleep(5);
|
||||
sleep(2);
|
||||
|
||||
$resquest = json_decode(file_get_contents('http://request-catcher:5000/__last_request__'), true);
|
||||
$resquest['data'] = json_decode($resquest['data'], true);
|
||||
|
@ -167,4 +167,4 @@ abstract class Scope extends TestCase
|
|||
|
||||
return self::$user[$this->getProject()['$id']];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -825,6 +825,9 @@ trait DatabaseBase
|
|||
$this->assertEquals(1944, $documents['body']['documents'][0]['releaseYear']);
|
||||
$this->assertEquals(2017, $documents['body']['documents'][1]['releaseYear']);
|
||||
$this->assertEquals(2019, $documents['body']['documents'][2]['releaseYear']);
|
||||
$this->assertFalse(array_key_exists('$internalId', $documents['body']['documents'][0]));
|
||||
$this->assertFalse(array_key_exists('$internalId', $documents['body']['documents'][1]));
|
||||
$this->assertFalse(array_key_exists('$internalId', $documents['body']['documents'][2]));
|
||||
$this->assertCount(3, $documents['body']['documents']);
|
||||
|
||||
foreach ($documents['body']['documents'] as $document) {
|
||||
|
@ -866,6 +869,7 @@ trait DatabaseBase
|
|||
$this->assertEquals($response['body']['releaseYear'], $document['releaseYear']);
|
||||
$this->assertEquals($response['body']['$read'], $document['$read']);
|
||||
$this->assertEquals($response['body']['$write'], $document['$write']);
|
||||
$this->assertFalse(array_key_exists('$internalId', $response['body']));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -125,6 +125,39 @@ class DatabaseCustomServerTest extends Scope
|
|||
$this->assertCount(0, $collections['body']['collections']);
|
||||
$this->assertEmpty($collections['body']['collections']);
|
||||
|
||||
/**
|
||||
* Test for Search
|
||||
*/
|
||||
$collections = $this->client->call(Client::METHOD_GET, '/database/collections', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'search' => 'first'
|
||||
]);
|
||||
|
||||
$this->assertEquals(1, $collections['body']['sum']);
|
||||
$this->assertEquals('first', $collections['body']['collections'][0]['$id']);
|
||||
|
||||
$collections = $this->client->call(Client::METHOD_GET, '/database/collections', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'search' => 'Test'
|
||||
]);
|
||||
|
||||
$this->assertEquals(2, $collections['body']['sum']);
|
||||
$this->assertEquals('Test 1', $collections['body']['collections'][0]['name']);
|
||||
$this->assertEquals('Test 2', $collections['body']['collections'][1]['name']);
|
||||
|
||||
$collections = $this->client->call(Client::METHOD_GET, '/database/collections', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'search' => 'Nonexistent'
|
||||
]);
|
||||
|
||||
$this->assertEquals(0, $collections['body']['sum']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
|
|
|
@ -218,6 +218,32 @@ class FunctionsCustomClientTest extends Scope
|
|||
];
|
||||
}
|
||||
|
||||
public function testCreateExecutionUnauthorized():array
|
||||
{
|
||||
$function = $this->client->call(Client::METHOD_POST, '/functions', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'functionId' => 'unique()',
|
||||
'name' => 'Test',
|
||||
'execute' => [],
|
||||
'runtime' => 'php-8.0',
|
||||
'timeout' => 10,
|
||||
]);
|
||||
|
||||
$execution = $this->client->call(Client::METHOD_POST, '/functions/'.$function['body']['$id'].'/executions', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], [
|
||||
'async' => 1,
|
||||
]);
|
||||
|
||||
$this->assertEquals(401, $execution['headers']['status-code']);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateCustomExecution
|
||||
*/
|
||||
|
|
|
@ -66,6 +66,7 @@ trait RealtimeBase
|
|||
$this->assertEquals('error', $payload['type']);
|
||||
$this->assertEquals(1008, $payload['data']['code']);
|
||||
$this->assertEquals('Missing or unknown project ID', $payload['data']['message']);
|
||||
\usleep(250000); // 250ms
|
||||
$this->expectException(ConnectionException::class); // Check if server disconnnected client
|
||||
$client->close();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue