mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Compare commits
232
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f85e335df | ||
|
|
7e6eae9464 | ||
|
|
941cb14f49 | ||
|
|
fe1d89dc6e | ||
|
|
ba23fe449c | ||
|
|
1fc93efe70 | ||
|
|
b614c67b56 | ||
|
|
2d6122a4bf | ||
|
|
ecbdceb407 | ||
|
|
c7a3c42225 | ||
|
|
4cdc8a97a0 | ||
|
|
cf0ea48fc8 | ||
|
|
3771da5353 | ||
|
|
abd2b7681b | ||
|
|
7f35419636 | ||
|
|
d33b91b25c | ||
|
|
b34a553c3b | ||
|
|
5965599eaf | ||
|
|
a2039c0b76 | ||
|
|
c549ddd149 | ||
|
|
de88ec4065 | ||
|
|
ec63dc22d4 | ||
|
|
7c7b98399c | ||
|
|
9d679e726e | ||
|
|
070ec03c0c | ||
|
|
be89224c36 | ||
|
|
8edd3c87cb | ||
|
|
9ac3cd73a8 | ||
|
|
203170c36d | ||
|
|
6f5bfdb726 | ||
|
|
b499857871 | ||
|
|
1388b0ca21 | ||
|
|
af095bdf4a | ||
|
|
16f49d13c8 | ||
|
|
e72d7979e0 | ||
|
|
7ad6bb048c | ||
|
|
3db22fd2db | ||
|
|
a423067b36 | ||
|
|
33aab0357f | ||
|
|
34e9c69a62 | ||
|
|
b658cddc71 | ||
|
|
2f1e47e35a | ||
|
|
1004435e9e | ||
|
|
a9e749a81f | ||
|
|
553fe15ba9 | ||
|
|
fec758d237 | ||
|
|
21aae468f2 | ||
|
|
f007b83ccc | ||
|
|
28be12d827 | ||
|
|
81128e8446 | ||
|
|
2bb6b0a2a9 | ||
|
|
5d9ef0dcca | ||
|
|
c8f966b0e5 | ||
|
|
3d2f21be7c | ||
|
|
3e876f5bd8 | ||
|
|
a5e56438c7 | ||
|
|
4e79259c4e | ||
|
|
fae79e5c3f | ||
|
|
b169be9dda | ||
|
|
8f4496346d | ||
|
|
f306c03030 | ||
|
|
a8469a9b92 | ||
|
|
b63510acb5 | ||
|
|
3e612ec88d | ||
|
|
1be36ae552 | ||
|
|
445b657207 | ||
|
|
5098973e0d | ||
|
|
d0976ff429 | ||
|
|
157783f782 | ||
|
|
e3a70373e1 | ||
|
|
a6e5563f8e | ||
|
|
470d84a843 | ||
|
|
80037f7e8d | ||
|
|
cc848c90a7 | ||
|
|
e0c293c5b4 | ||
|
|
2d82013261 | ||
|
|
f28588ecb6 | ||
|
|
6579ea5b56 | ||
|
|
9373688be2 | ||
|
|
2cec06be18 | ||
|
|
3a60bb306c | ||
|
|
e2ddb0d6d0 | ||
|
|
0049265c8a | ||
|
|
1f27867565 | ||
|
|
faf0cdec35 | ||
|
|
6073eab496 | ||
|
|
50ddc611a4 | ||
|
|
0ef2cfa753 | ||
|
|
790e503ad9 | ||
|
|
f6dbc0c882 | ||
|
|
a6c226aac9 | ||
|
|
2d41a3353d | ||
|
|
34e4208b3e | ||
|
|
d51486c62a | ||
|
|
f62f00d4d9 | ||
|
|
44e6ef3146 | ||
|
|
dea49d54c9 | ||
|
|
8a9523fa48 | ||
|
|
5dba0183c0 | ||
|
|
0108f86180 | ||
|
|
bc71d83697 | ||
|
|
0754c6263e | ||
|
|
2c037803f0 | ||
|
|
48410d0cf6 | ||
|
|
66b0f3c9df | ||
|
|
d8910eea73 | ||
|
|
38b04566b6 | ||
|
|
c89af1201a | ||
|
|
9f85ca83b4 | ||
|
|
d5d09061e9 | ||
|
|
f7f965a812 | ||
|
|
143be8239f | ||
|
|
d806bdbca7 | ||
|
|
19b1196633 | ||
|
|
da519046dd | ||
|
|
0c5573ab05 | ||
|
|
88f2b1ad50 | ||
|
|
f5ea19b15d | ||
|
|
fa60f03536 | ||
|
|
28392647e0 | ||
|
|
d2645ecfb1 | ||
|
|
4b0eddcc84 | ||
|
|
94e40c0127 | ||
|
|
44b75d50f4 | ||
|
|
df23aacbc0 | ||
|
|
7d4dfe06e2 | ||
|
|
498235a2ef | ||
|
|
52c9671157 | ||
|
|
e50af4c981 | ||
|
|
4fdab6fd52 | ||
|
|
c54450f582 | ||
|
|
6bf9693146 | ||
|
|
61a1efd0fe | ||
|
|
faf837e389 | ||
|
|
3ecd7e6a95 | ||
|
|
36782650c6 | ||
|
|
2f6bc9115f | ||
|
|
2d3dea84e3 | ||
|
|
b12f4008eb | ||
|
|
408bca400b | ||
|
|
6bacec52c5 | ||
|
|
9d70b5cab2 | ||
|
|
d9baf5b628 | ||
|
|
9e837c2eb9 | ||
|
|
f3460db369 | ||
|
|
422fd8b157 | ||
|
|
bf061b460b | ||
|
|
a035760b00 | ||
|
|
85c0454c49 | ||
|
|
b57839402f | ||
|
|
7bfb0401c6 | ||
|
|
c097f4a450 | ||
|
|
a3faa108c5 | ||
|
|
c89b76ba80 | ||
|
|
763158fe81 | ||
|
|
766c3293d2 | ||
|
|
1226c0834c | ||
|
|
f0983cd9ff | ||
|
|
daeb721995 | ||
|
|
0555a27656 | ||
|
|
da3284ce84 | ||
|
|
80636e8a91 | ||
|
|
53f8a3a78b | ||
|
|
206845e106 | ||
|
|
64d015065f | ||
|
|
56af56e341 | ||
|
|
aa77253b14 | ||
|
|
78c5743e75 | ||
|
|
156a944b54 | ||
|
|
b07fd5afe6 | ||
|
|
3086e1cbc1 | ||
|
|
b032a55045 | ||
|
|
d71c56b11f | ||
|
|
b828621feb | ||
|
|
3edc055c9d | ||
|
|
ceda513083 | ||
|
|
2d47b88246 | ||
|
|
b88e74095b | ||
|
|
4d85c5ca4f | ||
|
|
c89e649d05 | ||
|
|
d9bdf01cee | ||
|
|
54e3a4b25d | ||
|
|
98ee242812 | ||
|
|
79267c8123 | ||
|
|
d2ad0e7c74 | ||
|
|
b1e55702c8 | ||
|
|
f16eba2f9f | ||
|
|
7c0bd1da88 | ||
|
|
cc87de8934 | ||
|
|
5f8dc9998c | ||
|
|
cc7778ceea | ||
|
|
f5fc099d87 | ||
|
|
89d06d00c0 | ||
|
|
882cd8c83e | ||
|
|
80cc6a0bb3 | ||
|
|
fc4ad175dd | ||
|
|
a0def8edf8 | ||
|
|
bdb8204910 | ||
|
|
1274614d18 | ||
|
|
4f937ac549 | ||
|
|
6910d669de | ||
|
|
4fb680350a | ||
|
|
ff35dc6114 | ||
|
|
38433b9ac1 | ||
|
|
b98be4756c | ||
|
|
ff8418ffb9 | ||
|
|
e151425b95 | ||
|
|
b9f4815c3a | ||
|
|
c4fb7ecbc1 | ||
|
|
24b7c95514 | ||
|
|
870125ed84 | ||
|
|
e1475619ba | ||
|
|
ba058a89a3 | ||
|
|
236fab4658 | ||
|
|
6cfd6d9ac9 | ||
|
|
da706378ea | ||
|
|
40e36e23dd | ||
|
|
603980759a | ||
|
|
d63a218bd8 | ||
|
|
def3628205 | ||
|
|
779fb7bd20 | ||
|
|
ea1aef1d70 | ||
|
|
b1cc203eba | ||
|
|
b3e1a3415a | ||
|
|
d48248c9a2 | ||
|
|
eafca0c431 | ||
|
|
a92bdfaed0 | ||
|
|
46965135a4 | ||
|
|
33c5ac83b2 | ||
|
|
57c08a41f1 | ||
|
|
36e7452f78 | ||
|
|
469801b862 |
@@ -37,10 +37,14 @@ _APP_REDIS_PASS=
|
||||
_APP_REDIS_USER=
|
||||
_APP_DB_HOST=mariadb
|
||||
_APP_DB_PORT=3306
|
||||
_APP_DB_ADAPTER=mariadb
|
||||
_APP_DB_SCHEMA=appwrite
|
||||
_APP_DB_USER=user
|
||||
_APP_DB_PASS=password
|
||||
_APP_DB_ROOT_PASS=rootsecretpassword
|
||||
_APP_DB_ADAPTER_DOCUMENTSDB=mongodb
|
||||
_APP_DB_HOST_DOCUMENTSDB=mongodb
|
||||
_APP_DB_PORT_DOCUMENTSDB=27017
|
||||
_APP_STORAGE_DEVICE=Local
|
||||
_APP_STORAGE_S3_ACCESS_KEY=
|
||||
_APP_STORAGE_S3_SECRET=
|
||||
|
||||
@@ -151,10 +151,8 @@ jobs:
|
||||
- name: Failure Logs
|
||||
if: failure()
|
||||
run: |
|
||||
echo "=== Appwrite Worker Builds Logs ==="
|
||||
docker compose logs appwrite-worker-builds
|
||||
echo "=== OpenRuntimes Executor Logs ==="
|
||||
docker compose logs openruntimes-executor
|
||||
echo "=== Appwrite Logs ==="
|
||||
docker compose logs
|
||||
|
||||
e2e_service_test:
|
||||
name: E2E Service Test
|
||||
@@ -163,12 +161,17 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
db_adapter: [
|
||||
MARIADB,
|
||||
MONGODB
|
||||
]
|
||||
service: [
|
||||
Account,
|
||||
Avatars,
|
||||
Console,
|
||||
Databases/Legacy,
|
||||
Databases/TablesDB,
|
||||
Databases/DocumentsDB,
|
||||
Functions,
|
||||
FunctionsSchedule,
|
||||
GraphQL,
|
||||
@@ -202,6 +205,18 @@ jobs:
|
||||
run: |
|
||||
docker load --input /tmp/${{ env.IMAGE }}.tar
|
||||
sed -i 's|^_APP_BROWSER_HOST=.*|_APP_BROWSER_HOST=http://invalid-browser/v1|' .env
|
||||
|
||||
# Set DB Adapter in .env before starting services
|
||||
if [ "${{ matrix.db_adapter }}" = "MARIADB" ]; then
|
||||
sed -i 's|^_APP_DB_ADAPTER=.*|_APP_DB_ADAPTER=mariadb|' .env
|
||||
sed -i 's|^_APP_DB_HOST=.*|_APP_DB_HOST=mariadb|' .env
|
||||
sed -i 's|^_APP_DB_PORT=.*|_APP_DB_PORT=3306|' .env
|
||||
elif [ "${{ matrix.db_adapter }}" = "MONGODB" ]; then
|
||||
sed -i 's|^_APP_DB_ADAPTER=.*|_APP_DB_ADAPTER=mongodb|' .env
|
||||
sed -i 's|^_APP_DB_HOST=.*|_APP_DB_HOST=mongodb|' .env
|
||||
sed -i 's|^_APP_DB_PORT=.*|_APP_DB_PORT=27017|' .env
|
||||
fi
|
||||
|
||||
docker compose up -d
|
||||
sleep 30
|
||||
|
||||
|
||||
@@ -37,6 +37,9 @@ COPY ./app /usr/src/code/app
|
||||
COPY ./public /usr/src/code/public
|
||||
COPY ./bin /usr/local/bin
|
||||
COPY ./src /usr/src/code/src
|
||||
COPY ./dev /usr/src/code/dev
|
||||
COPY ./mongo-init.js /usr/src/code/mongo-init.js
|
||||
COPY ./mongo-entrypoint.sh /usr/src/code/mongo-entrypoint.sh
|
||||
|
||||
# Set Volumes
|
||||
RUN mkdir -p /storage/uploads && \
|
||||
|
||||
@@ -1606,13 +1606,6 @@ return [
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
'$id' => ID::custom('_fulltext_name'),
|
||||
'type' => Database::INDEX_FULLTEXT,
|
||||
'attributes' => ['name'],
|
||||
'lengths' => [],
|
||||
'orders' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('_key_search'),
|
||||
'type' => Database::INDEX_FULLTEXT,
|
||||
@@ -1842,13 +1835,6 @@ return [
|
||||
'lengths' => [],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('_key_name'),
|
||||
'type' => Database::INDEX_FULLTEXT,
|
||||
'attributes' => ['name'],
|
||||
'lengths' => [],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('_key_type'),
|
||||
'type' => Database::INDEX_KEY,
|
||||
@@ -2116,14 +2102,8 @@ return [
|
||||
'filters' => ['topicSearch'],
|
||||
],
|
||||
],
|
||||
|
||||
'indexes' => [
|
||||
[
|
||||
'$id' => ID::custom('_key_name'),
|
||||
'type' => Database::INDEX_FULLTEXT,
|
||||
'attributes' => ['name'],
|
||||
'lengths' => [],
|
||||
'orders' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('_key_search'),
|
||||
'type' => Database::INDEX_FULLTEXT,
|
||||
|
||||
@@ -78,6 +78,17 @@ $platformCollections = [
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('documentsDatabase'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 256,
|
||||
'signed' => true,
|
||||
'required' => true,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('logo'),
|
||||
'type' => Database::VAR_STRING,
|
||||
|
||||
@@ -61,6 +61,15 @@ return [
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('database'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'size' => 128,
|
||||
'required' => true,
|
||||
'signed' => true,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
]
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -369,6 +369,15 @@ return [
|
||||
]
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => '_APP_DB_ADAPTER',
|
||||
'description' => 'Which database engine to use. Possible options are "mariadb" or "mongodb"',
|
||||
'introduction' => '1.8.0',
|
||||
'default' => 'mongoDB',
|
||||
'required' => true,
|
||||
'question' => 'Choose your database (mariadb|mongoDB)',
|
||||
'filter' => ''
|
||||
],
|
||||
[
|
||||
'category' => 'Redis',
|
||||
'description' => 'Appwrite uses a Redis server for managing cache, queues and scheduled tasks. The Redis env vars are used to allow Appwrite server to connect to the Redis container.',
|
||||
|
||||
@@ -367,7 +367,7 @@ App::post('/v1/account')
|
||||
contentType: ContentType::JSON
|
||||
))
|
||||
->label('abuse-limit', 10)
|
||||
->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('email', '', new EmailValidator(), 'User email.')
|
||||
->param('password', '', fn ($project, $passwordsDictionary) => new PasswordDictionary($passwordsDictionary, $project->getAttribute('auths', [])['passwordDictionary'] ?? false), 'New user password. Must be between 8 and 256 chars.', false, ['project', 'passwordsDictionary'])
|
||||
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
|
||||
@@ -727,7 +727,7 @@ App::get('/v1/account/sessions/:sessionId')
|
||||
],
|
||||
contentType: ContentType::JSON
|
||||
))
|
||||
->param('sessionId', '', new UID(), 'Session ID. Use the string \'current\' to get the current device session.')
|
||||
->param('sessionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Session ID. Use the string \'current\' to get the current device session.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->inject('locale')
|
||||
@@ -779,7 +779,7 @@ App::delete('/v1/account/sessions/:sessionId')
|
||||
contentType: ContentType::NONE
|
||||
))
|
||||
->label('abuse-limit', 100)
|
||||
->param('sessionId', '', new UID(), 'Session ID. Use the string \'current\' to delete the current device session.')
|
||||
->param('sessionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Session ID. Use the string \'current\' to delete the current device session.', false, ['dbForProject'])
|
||||
->inject('requestTimestamp')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
@@ -867,7 +867,7 @@ App::patch('/v1/account/sessions/:sessionId')
|
||||
contentType: ContentType::JSON
|
||||
))
|
||||
->label('abuse-limit', 10)
|
||||
->param('sessionId', '', new UID(), 'Session ID. Use the string \'current\' to update the current device session.')
|
||||
->param('sessionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Session ID. Use the string \'current\' to update the current device session.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->inject('dbForProject')
|
||||
@@ -1259,7 +1259,7 @@ App::post('/v1/account/sessions/token')
|
||||
->label('abuse-limit', 10)
|
||||
->label('abuse-key', 'ip:{ip},userId:{param-userId}')
|
||||
->label('abuse-reset', [201])
|
||||
->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('secret', '', new Text(256), 'Secret of a token generated by login methods. For example, the `createMagicURLToken` or `createPhoneToken` methods.')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
@@ -1479,6 +1479,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
||||
} elseif ($protocol === 'http' && $port !== '80') {
|
||||
$callbackBase .= ':' . $port;
|
||||
}
|
||||
|
||||
$callback = $callbackBase . '/v1/account/sessions/oauth2/callback/' . $provider . '/' . $project->getId();
|
||||
$defaultState = ['success' => $project->getAttribute('url', ''), 'failure' => ''];
|
||||
$appId = $project->getAttribute('oAuthProviders', [])[$provider . 'Appid'] ?? '';
|
||||
@@ -1518,6 +1519,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
||||
if (!empty($state['failure'])) {
|
||||
$failure = URLParser::parse($state['failure']);
|
||||
}
|
||||
|
||||
$failureRedirect = (function (string $type, ?string $message = null, ?int $code = null) use ($failure, $response) {
|
||||
$exception = new Exception($type, $message, $code);
|
||||
if (!empty($failure)) {
|
||||
@@ -1563,7 +1565,9 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
||||
$accessToken = $oauth2->getAccessToken($code);
|
||||
$refreshToken = $oauth2->getRefreshToken($code);
|
||||
$accessTokenExpiry = $oauth2->getAccessTokenExpiry($code);
|
||||
|
||||
} catch (OAuth2Exception $ex) {
|
||||
|
||||
$failureRedirect(
|
||||
$ex->getType(),
|
||||
'Failed to obtain access token. The ' . $providerName . ' OAuth2 provider returned an error: ' . $ex->getMessage(),
|
||||
@@ -2063,7 +2067,7 @@ App::post('/v1/account/tokens/magic-url')
|
||||
))
|
||||
->label('abuse-limit', 60)
|
||||
->label('abuse-key', ['url:{url},email:{param-email}', 'url:{url},ip:{ip}'])
|
||||
->param('userId', '', new CustomId(), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars. If the email address has never been used, a new account is created using the provided userId. Otherwise, if the email address is already attached to an account, the user ID is ignored.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars. If the email address has never been used, a new account is created using the provided userId. Otherwise, if the email address is already attached to an account, the user ID is ignored.', false, ['dbForProject'])
|
||||
->param('email', '', new EmailValidator(), 'User email.')
|
||||
->param('url', '', fn ($redirectValidator) => $redirectValidator, '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, ['redirectValidator'])
|
||||
->param('phrase', false, new Boolean(), 'Toggle for security phrase. If enabled, email will be send with a randomly generated phrase and the phrase will also be included in the response. Confirming phrases match increases the security of your authentication flow.', true)
|
||||
@@ -2342,7 +2346,7 @@ App::post('/v1/account/tokens/email')
|
||||
))
|
||||
->label('abuse-limit', 10)
|
||||
->label('abuse-key', ['url:{url},email:{param-email}', 'url:{url},ip:{ip}'])
|
||||
->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars. If the email address has never been used, a new account is created using the provided userId. Otherwise, if the email address is already attached to an account, the user ID is ignored.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars. If the email address has never been used, a new account is created using the provided userId. Otherwise, if the email address is already attached to an account, the user ID is ignored.', false, ['dbForProject'])
|
||||
->param('email', '', new EmailValidator(), 'User email.')
|
||||
->param('phrase', false, new Boolean(), 'Toggle for security phrase. If enabled, email will be send with a randomly generated phrase and the phrase will also be included in the response. Confirming phrases match increases the security of your authentication flow.', true)
|
||||
->inject('request')
|
||||
@@ -2648,7 +2652,7 @@ App::put('/v1/account/sessions/magic-url')
|
||||
->label('abuse-limit', 10)
|
||||
->label('abuse-key', 'ip:{ip},userId:{param-userId}')
|
||||
->label('abuse-reset', [201])
|
||||
->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('secret', '', new Text(256), 'Valid verification token.')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
@@ -2696,7 +2700,7 @@ App::put('/v1/account/sessions/phone')
|
||||
))
|
||||
->label('abuse-limit', 10)
|
||||
->label('abuse-key', 'ip:{ip},userId:{param-userId}')
|
||||
->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('secret', '', new Text(256), 'Valid verification token.')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
@@ -2738,7 +2742,7 @@ App::post('/v1/account/tokens/phone')
|
||||
))
|
||||
->label('abuse-limit', 10)
|
||||
->label('abuse-key', ['url:{url},phone:{param-phone}', 'url:{url},ip:{ip}'])
|
||||
->param('userId', '', new CustomId(), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars. If the phone number has never been used, a new account is created using the provided userId. Otherwise, if the phone number is already attached to an account, the user ID is ignored.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars. If the phone number has never been used, a new account is created using the provided userId. Otherwise, if the phone number is already attached to an account, the user ID is ignored.', false, ['dbForProject'])
|
||||
->param('phone', '', new Phone(), 'Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
@@ -3716,7 +3720,7 @@ App::put('/v1/account/recovery')
|
||||
))
|
||||
->label('abuse-limit', 10)
|
||||
->label('abuse-key', 'url:{url},userId:{param-userId}')
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->param('secret', '', new Text(256), 'Valid reset token.')
|
||||
->param('password', '', fn ($project, $passwordsDictionary) => new PasswordDictionary($passwordsDictionary, $project->getAttribute('auths', [])['passwordDictionary'] ?? false), 'New user password. Must be between 8 and 256 chars.', false, ['project', 'passwordsDictionary'])
|
||||
->inject('response')
|
||||
@@ -4065,7 +4069,7 @@ App::put('/v1/account/verifications/email')
|
||||
])
|
||||
->label('abuse-limit', 10)
|
||||
->label('abuse-key', 'url:{url},userId:{param-userId}')
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->param('secret', '', new Text(256), 'Valid verification token.')
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
@@ -4284,7 +4288,7 @@ App::put('/v1/account/verifications/phone')
|
||||
))
|
||||
->label('abuse-limit', 10)
|
||||
->label('abuse-key', 'userId:{param-userId}')
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->param('secret', '', new Text(256), 'Valid verification token.')
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
@@ -4348,9 +4352,9 @@ App::post('/v1/account/targets/push')
|
||||
],
|
||||
contentType: ContentType::JSON
|
||||
))
|
||||
->param('targetId', '', new CustomId(), 'Target ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('targetId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Target ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)')
|
||||
->param('providerId', '', new UID(), 'Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.', true)
|
||||
->param('providerId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.', true, ['dbForProject'])
|
||||
->inject('queueForEvents')
|
||||
->inject('user')
|
||||
->inject('request')
|
||||
@@ -4431,7 +4435,7 @@ App::put('/v1/account/targets/:targetId/push')
|
||||
],
|
||||
contentType: ContentType::JSON
|
||||
))
|
||||
->param('targetId', '', new UID(), 'Target ID.')
|
||||
->param('targetId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Target ID.', false, ['dbForProject'])
|
||||
->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)')
|
||||
->inject('queueForEvents')
|
||||
->inject('user')
|
||||
@@ -4496,7 +4500,7 @@ App::delete('/v1/account/targets/:targetId/push')
|
||||
],
|
||||
contentType: ContentType::NONE
|
||||
))
|
||||
->param('targetId', '', new UID(), 'Target ID.')
|
||||
->param('targetId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Target ID.', false, ['dbForProject'])
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForDeletes')
|
||||
->inject('user')
|
||||
@@ -4623,7 +4627,7 @@ App::delete('/v1/account/identities/:identityId')
|
||||
],
|
||||
contentType: ContentType::NONE
|
||||
))
|
||||
->param('identityId', '', new UID(), 'Identity ID.')
|
||||
->param('identityId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Identity ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
|
||||
@@ -77,7 +77,7 @@ App::post('/v1/messaging/providers/mailgun')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('providerId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('name', '', new Text(128), 'Provider name.')
|
||||
->param('apiKey', '', new Text(0), 'Mailgun API Key.', true)
|
||||
->param('domain', '', new Text(0), 'Mailgun Domain.', true)
|
||||
@@ -171,7 +171,7 @@ App::post('/v1/messaging/providers/sendgrid')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('providerId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('name', '', new Text(128), 'Provider name.')
|
||||
->param('apiKey', '', new Text(0), 'Sendgrid API key.', true)
|
||||
->param('fromName', '', new Text(128, 0), 'Sender Name.', true)
|
||||
@@ -355,7 +355,7 @@ App::post('/v1/messaging/providers/smtp')
|
||||
]
|
||||
)
|
||||
])
|
||||
->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('providerId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('name', '', new Text(128), 'Provider name.')
|
||||
->param('host', '', new Text(0), 'SMTP hosts. Either a single hostname or multiple semicolon-delimited hostnames. You can also specify a different port for each host such as `smtp1.example.com:25;smtp2.example.com`. You can also specify encryption type, for example: `tls://smtp1.example.com:587;ssl://smtp2.example.com:465"`. Hosts will be tried in order.')
|
||||
->param('port', 587, new Range(1, 65535), 'The default SMTP server port.', true)
|
||||
@@ -450,7 +450,7 @@ App::post('/v1/messaging/providers/msg91')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('providerId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('name', '', new Text(128), 'Provider name.')
|
||||
->param('templateId', '', new Text(0), 'Msg91 template ID', true)
|
||||
->param('senderId', '', new Text(0), 'Msg91 sender ID.', true)
|
||||
@@ -533,7 +533,7 @@ App::post('/v1/messaging/providers/telesign')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('providerId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('name', '', new Text(128), 'Provider name.')
|
||||
->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true)
|
||||
->param('customerId', '', new Text(0), 'Telesign customer ID.', true)
|
||||
@@ -617,7 +617,7 @@ App::post('/v1/messaging/providers/textmagic')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('providerId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('name', '', new Text(128), 'Provider name.')
|
||||
->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true)
|
||||
->param('username', '', new Text(0), 'Textmagic username.', true)
|
||||
@@ -701,7 +701,7 @@ App::post('/v1/messaging/providers/twilio')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('providerId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('name', '', new Text(128), 'Provider name.')
|
||||
->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true)
|
||||
->param('accountSid', '', new Text(0), 'Twilio account secret ID.', true)
|
||||
@@ -785,7 +785,7 @@ App::post('/v1/messaging/providers/vonage')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('providerId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('name', '', new Text(128), 'Provider name.')
|
||||
->param('from', '', new Phone(), 'Sender Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true)
|
||||
->param('apiKey', '', new Text(0), 'Vonage API key.', true)
|
||||
@@ -889,7 +889,7 @@ App::post('/v1/messaging/providers/fcm')
|
||||
]
|
||||
)
|
||||
])
|
||||
->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('providerId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('name', '', new Text(128), 'Provider name.')
|
||||
->param('serviceAccountJSON', null, new Nullable(new JSON()), 'FCM service account JSON.', true)
|
||||
->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true)
|
||||
@@ -979,7 +979,7 @@ App::post('/v1/messaging/providers/apns')
|
||||
]
|
||||
)
|
||||
])
|
||||
->param('providerId', '', new CustomId(), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('providerId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Provider ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('name', '', new Text(128), 'Provider name.')
|
||||
->param('authKey', '', new Text(0), 'APNS authentication key.', true)
|
||||
->param('authKeyId', '', new Text(0), 'APNS authentication key ID.', true)
|
||||
@@ -1138,7 +1138,7 @@ App::get('/v1/messaging/providers/:providerId/logs')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('providerId', '', new UID(), 'Provider ID.')
|
||||
->param('providerId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Provider ID.', false, ['dbForProject'])
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
@@ -1234,7 +1234,7 @@ App::get('/v1/messaging/providers/:providerId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('providerId', '', new UID(), 'Provider ID.')
|
||||
->param('providerId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Provider ID.', false, ['dbForProject'])
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (string $providerId, Database $dbForProject, Response $response) {
|
||||
@@ -1268,7 +1268,7 @@ App::patch('/v1/messaging/providers/mailgun/:providerId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('providerId', '', new UID(), 'Provider ID.')
|
||||
->param('providerId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Provider ID.', false, ['dbForProject'])
|
||||
->param('name', '', new Text(128), 'Provider name.', true)
|
||||
->param('apiKey', '', new Text(0), 'Mailgun API Key.', true)
|
||||
->param('domain', '', new Text(0), 'Mailgun Domain.', true)
|
||||
@@ -1381,7 +1381,7 @@ App::patch('/v1/messaging/providers/sendgrid/:providerId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('providerId', '', new UID(), 'Provider ID.')
|
||||
->param('providerId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Provider ID.', false, ['dbForProject'])
|
||||
->param('name', '', new Text(128), 'Provider name.', true)
|
||||
->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true)
|
||||
->param('apiKey', '', new Text(0), 'Sendgrid API key.', true)
|
||||
@@ -1597,7 +1597,7 @@ App::patch('/v1/messaging/providers/smtp/:providerId')
|
||||
]
|
||||
)
|
||||
])
|
||||
->param('providerId', '', new UID(), 'Provider ID.')
|
||||
->param('providerId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Provider ID.', false, ['dbForProject'])
|
||||
->param('name', '', new Text(128), 'Provider name.', true)
|
||||
->param('host', '', new Text(0), 'SMTP hosts. Either a single hostname or multiple semicolon-delimited hostnames. You can also specify a different port for each host such as `smtp1.example.com:25;smtp2.example.com`. You can also specify encryption type, for example: `tls://smtp1.example.com:587;ssl://smtp2.example.com:465"`. Hosts will be tried in order.', true)
|
||||
->param('port', null, new Nullable(new Range(1, 65535)), 'SMTP port.', true)
|
||||
@@ -1726,7 +1726,7 @@ App::patch('/v1/messaging/providers/msg91/:providerId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('providerId', '', new UID(), 'Provider ID.')
|
||||
->param('providerId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Provider ID.', false, ['dbForProject'])
|
||||
->param('name', '', new Text(128), 'Provider name.', true)
|
||||
->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true)
|
||||
->param('templateId', '', new Text(0), 'Msg91 template ID.', true)
|
||||
@@ -1813,7 +1813,7 @@ App::patch('/v1/messaging/providers/telesign/:providerId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('providerId', '', new UID(), 'Provider ID.')
|
||||
->param('providerId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Provider ID.', false, ['dbForProject'])
|
||||
->param('name', '', new Text(128), 'Provider name.', true)
|
||||
->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true)
|
||||
->param('customerId', '', new Text(0), 'Telesign customer ID.', true)
|
||||
@@ -1902,7 +1902,7 @@ App::patch('/v1/messaging/providers/textmagic/:providerId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('providerId', '', new UID(), 'Provider ID.')
|
||||
->param('providerId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Provider ID.', false, ['dbForProject'])
|
||||
->param('name', '', new Text(128), 'Provider name.', true)
|
||||
->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true)
|
||||
->param('username', '', new Text(0), 'Textmagic username.', true)
|
||||
@@ -1991,7 +1991,7 @@ App::patch('/v1/messaging/providers/twilio/:providerId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('providerId', '', new UID(), 'Provider ID.')
|
||||
->param('providerId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Provider ID.', false, ['dbForProject'])
|
||||
->param('name', '', new Text(128), 'Provider name.', true)
|
||||
->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true)
|
||||
->param('accountSid', '', new Text(0), 'Twilio account secret ID.', true)
|
||||
@@ -2080,7 +2080,7 @@ App::patch('/v1/messaging/providers/vonage/:providerId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('providerId', '', new UID(), 'Provider ID.')
|
||||
->param('providerId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Provider ID.', false, ['dbForProject'])
|
||||
->param('name', '', new Text(128), 'Provider name.', true)
|
||||
->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true)
|
||||
->param('apiKey', '', new Text(0), 'Vonage API key.', true)
|
||||
@@ -2189,7 +2189,7 @@ App::patch('/v1/messaging/providers/fcm/:providerId')
|
||||
]
|
||||
)
|
||||
])
|
||||
->param('providerId', '', new UID(), 'Provider ID.')
|
||||
->param('providerId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Provider ID.', false, ['dbForProject'])
|
||||
->param('name', '', new Text(128), 'Provider name.', true)
|
||||
->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true)
|
||||
->param('serviceAccountJSON', null, new Nullable(new JSON()), 'FCM service account JSON.', true)
|
||||
@@ -2285,7 +2285,7 @@ App::patch('/v1/messaging/providers/apns/:providerId')
|
||||
]
|
||||
)
|
||||
])
|
||||
->param('providerId', '', new UID(), 'Provider ID.')
|
||||
->param('providerId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Provider ID.', false, ['dbForProject'])
|
||||
->param('name', '', new Text(128), 'Provider name.', true)
|
||||
->param('enabled', null, new Nullable(new Boolean()), 'Set as enabled.', true)
|
||||
->param('authKey', '', new Text(0), 'APNS authentication key.', true)
|
||||
@@ -2388,7 +2388,7 @@ App::delete('/v1/messaging/providers/:providerId')
|
||||
],
|
||||
contentType: ContentType::NONE
|
||||
))
|
||||
->param('providerId', '', new UID(), 'Provider ID.')
|
||||
->param('providerId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Provider ID.', false, ['dbForProject'])
|
||||
->inject('queueForEvents')
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
@@ -2430,7 +2430,7 @@ App::post('/v1/messaging/topics')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('topicId', '', new CustomId(), 'Topic ID. Choose a custom Topic ID or a new Topic ID.')
|
||||
->param('topicId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Topic ID. Choose a custom Topic ID or a new Topic ID.', false, ['dbForProject'])
|
||||
->param('name', '', new Text(128), 'Topic Name.')
|
||||
->param('subscribe', [Role::users()], new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of role strings with subscribe permission. By default all users are granted with any subscribe permission. [learn more about roles](https://appwrite.io/docs/permissions#permission-roles). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.', true)
|
||||
->inject('queueForEvents')
|
||||
@@ -2546,7 +2546,7 @@ App::get('/v1/messaging/topics/:topicId/logs')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('topicId', '', new UID(), 'Topic ID.')
|
||||
->param('topicId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Topic ID.', false, ['dbForProject'])
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
@@ -2643,7 +2643,7 @@ App::get('/v1/messaging/topics/:topicId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('topicId', '', new UID(), 'Topic ID.')
|
||||
->param('topicId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Topic ID.', false, ['dbForProject'])
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (string $topicId, Database $dbForProject, Response $response) {
|
||||
@@ -2678,7 +2678,7 @@ App::patch('/v1/messaging/topics/:topicId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('topicId', '', new UID(), 'Topic ID.')
|
||||
->param('topicId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Topic ID.', false, ['dbForProject'])
|
||||
->param('name', null, new Nullable(new Text(128)), 'Topic Name.', true)
|
||||
->param('subscribe', null, new Nullable(new Roles(APP_LIMIT_ARRAY_PARAMS_SIZE)), 'An array of role strings with subscribe permission. By default all users are granted with any subscribe permission. [learn more about roles](https://appwrite.io/docs/permissions#permission-roles). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 64 characters long.', true)
|
||||
->inject('queueForEvents')
|
||||
@@ -2730,7 +2730,7 @@ App::delete('/v1/messaging/topics/:topicId')
|
||||
],
|
||||
contentType: ContentType::NONE
|
||||
))
|
||||
->param('topicId', '', new UID(), 'Topic ID.')
|
||||
->param('topicId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Topic ID.', false, ['dbForProject'])
|
||||
->inject('queueForEvents')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForDeletes')
|
||||
@@ -2777,9 +2777,9 @@ App::post('/v1/messaging/topics/:topicId/subscribers')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('subscriberId', '', new CustomId(), 'Subscriber ID. Choose a custom Subscriber ID or a new Subscriber ID.')
|
||||
->param('topicId', '', new UID(), 'Topic ID. The topic ID to subscribe to.')
|
||||
->param('targetId', '', new UID(), 'Target ID. The target ID to link to the specified Topic ID.')
|
||||
->param('subscriberId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Subscriber ID. Choose a custom Subscriber ID or a new Subscriber ID.', false, ['dbForProject'])
|
||||
->param('topicId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Topic ID. The topic ID to subscribe to.', false, ['dbForProject'])
|
||||
->param('targetId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Target ID. The target ID to link to the specified Topic ID.', false, ['dbForProject'])
|
||||
->inject('queueForEvents')
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
@@ -2877,7 +2877,7 @@ App::get('/v1/messaging/topics/:topicId/subscribers')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('topicId', '', new UID(), 'Topic ID. The topic ID subscribed to.')
|
||||
->param('topicId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Topic ID. The topic ID subscribed to.', false, ['dbForProject'])
|
||||
->param('queries', [], new Subscribers(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Providers::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
@@ -2967,7 +2967,7 @@ App::get('/v1/messaging/subscribers/:subscriberId/logs')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('subscriberId', '', new UID(), 'Subscriber ID.')
|
||||
->param('subscriberId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Subscriber ID.', false, ['dbForProject'])
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
@@ -3064,8 +3064,8 @@ App::get('/v1/messaging/topics/:topicId/subscribers/:subscriberId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('topicId', '', new UID(), 'Topic ID. The topic ID subscribed to.')
|
||||
->param('subscriberId', '', new UID(), 'Subscriber ID.')
|
||||
->param('topicId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Topic ID. The topic ID subscribed to.', false, ['dbForProject'])
|
||||
->param('subscriberId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Subscriber ID.', false, ['dbForProject'])
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (string $topicId, string $subscriberId, Database $dbForProject, Response $response) {
|
||||
@@ -3114,8 +3114,8 @@ App::delete('/v1/messaging/topics/:topicId/subscribers/:subscriberId')
|
||||
],
|
||||
contentType: ContentType::NONE
|
||||
))
|
||||
->param('topicId', '', new UID(), 'Topic ID. The topic ID subscribed to.')
|
||||
->param('subscriberId', '', new UID(), 'Subscriber ID.')
|
||||
->param('topicId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Topic ID. The topic ID subscribed to.', false, ['dbForProject'])
|
||||
->param('subscriberId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Subscriber ID.', false, ['dbForProject'])
|
||||
->inject('queueForEvents')
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
@@ -3180,14 +3180,14 @@ App::post('/v1/messaging/messages/email')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('messageId', '', new CustomId(), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('messageId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('subject', '', new Text(998), 'Email Subject.')
|
||||
->param('content', '', new Text(64230), 'Email Content.')
|
||||
->param('topics', [], new ArrayList(new UID()), 'List of Topic IDs.', true)
|
||||
->param('users', [], new ArrayList(new UID()), 'List of User IDs.', true)
|
||||
->param('targets', [], new ArrayList(new UID()), 'List of Targets IDs.', true)
|
||||
->param('cc', [], new ArrayList(new UID()), 'Array of target IDs to be added as CC.', true)
|
||||
->param('bcc', [], new ArrayList(new UID()), 'Array of target IDs to be added as BCC.', true)
|
||||
->param('topics', [], fn (Database $dbForProject) => new ArrayList(new UID($dbForProject->getAdapter()->getMaxUIDLength())), 'List of Topic IDs.', true, ['dbForProject'])
|
||||
->param('users', [], fn (Database $dbForProject) => new ArrayList(new UID($dbForProject->getAdapter()->getMaxUIDLength())), 'List of User IDs.', true, ['dbForProject'])
|
||||
->param('targets', [], fn (Database $dbForProject) => new ArrayList(new UID($dbForProject->getAdapter()->getMaxUIDLength())), 'List of Targets IDs.', true, ['dbForProject'])
|
||||
->param('cc', [], fn (Database $dbForProject) => new ArrayList(new UID($dbForProject->getAdapter()->getMaxUIDLength())), 'Array of target IDs to be added as CC.', true, ['dbForProject'])
|
||||
->param('bcc', [], fn (Database $dbForProject) => new ArrayList(new UID($dbForProject->getAdapter()->getMaxUIDLength())), 'Array of target IDs to be added as BCC.', true, ['dbForProject'])
|
||||
->param('attachments', [], new ArrayList(new CompoundUID()), 'Array of compound ID strings of bucket IDs and file IDs to be attached to the email. They should be formatted as <BUCKET_ID>:<FILE_ID>.', true)
|
||||
->param('draft', false, new Boolean(), 'Is message a draft', true)
|
||||
->param('html', false, new Boolean(), 'Is content of type HTML', true)
|
||||
@@ -3359,11 +3359,11 @@ App::post('/v1/messaging/messages/sms')
|
||||
]
|
||||
)
|
||||
])
|
||||
->param('messageId', '', new CustomId(), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('messageId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('content', '', new Text(64230), 'SMS Content.')
|
||||
->param('topics', [], new ArrayList(new UID()), 'List of Topic IDs.', true)
|
||||
->param('users', [], new ArrayList(new UID()), 'List of User IDs.', true)
|
||||
->param('targets', [], new ArrayList(new UID()), 'List of Targets IDs.', true)
|
||||
->param('topics', [], fn (Database $dbForProject) => new ArrayList(new UID($dbForProject->getAdapter()->getMaxUIDLength())), 'List of Topic IDs.', true, ['dbForProject'])
|
||||
->param('users', [], fn (Database $dbForProject) => new ArrayList(new UID($dbForProject->getAdapter()->getMaxUIDLength())), 'List of User IDs.', true, ['dbForProject'])
|
||||
->param('targets', [], fn (Database $dbForProject) => new ArrayList(new UID($dbForProject->getAdapter()->getMaxUIDLength())), 'List of Targets IDs.', true, ['dbForProject'])
|
||||
->param('draft', false, new Boolean(), 'Is message a draft', true)
|
||||
->param('scheduledAt', null, new Nullable(new DatetimeValidator(requireDateInFuture: true)), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true)
|
||||
->inject('queueForEvents')
|
||||
@@ -3482,12 +3482,12 @@ App::post('/v1/messaging/messages/push')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('messageId', '', new CustomId(), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('messageId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('title', '', new Text(256), 'Title for push notification.', true)
|
||||
->param('body', '', new Text(64230), 'Body for push notification.', true)
|
||||
->param('topics', [], new ArrayList(new UID()), 'List of Topic IDs.', true)
|
||||
->param('users', [], new ArrayList(new UID()), 'List of User IDs.', true)
|
||||
->param('targets', [], new ArrayList(new UID()), 'List of Targets IDs.', true)
|
||||
->param('topics', [], fn (Database $dbForProject) => new ArrayList(new UID($dbForProject->getAdapter()->getMaxUIDLength())), 'List of Topic IDs.', true, ['dbForProject'])
|
||||
->param('users', [], fn (Database $dbForProject) => new ArrayList(new UID($dbForProject->getAdapter()->getMaxUIDLength())), 'List of User IDs.', true, ['dbForProject'])
|
||||
->param('targets', [], fn (Database $dbForProject) => new ArrayList(new UID($dbForProject->getAdapter()->getMaxUIDLength())), 'List of Targets IDs.', true, ['dbForProject'])
|
||||
->param('data', null, new Nullable(new JSON()), 'Additional key-value pair data for push notification.', true)
|
||||
->param('action', '', new Text(256), 'Action for push notification.', true)
|
||||
->param('image', '', new CompoundUID(), 'Image for push notification. Must be a compound bucket ID to file ID of a jpeg, png, or bmp image in Appwrite Storage. It should be formatted as <BUCKET_ID>:<FILE_ID>.', true)
|
||||
@@ -3767,7 +3767,7 @@ App::get('/v1/messaging/messages/:messageId/logs')
|
||||
)
|
||||
],
|
||||
))
|
||||
->param('messageId', '', new UID(), 'Message ID.')
|
||||
->param('messageId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Message ID.', false, ['dbForProject'])
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
@@ -3864,7 +3864,7 @@ App::get('/v1/messaging/messages/:messageId/targets')
|
||||
)
|
||||
],
|
||||
))
|
||||
->param('messageId', '', new UID(), 'Message ID.')
|
||||
->param('messageId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Message ID.', false, ['dbForProject'])
|
||||
->param('queries', [], new Targets(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Targets::ALLOWED_ATTRIBUTES), true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
@@ -3947,7 +3947,7 @@ App::get('/v1/messaging/messages/:messageId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('messageId', '', new UID(), 'Message ID.')
|
||||
->param('messageId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Message ID.', false, ['dbForProject'])
|
||||
->inject('dbForProject')
|
||||
->inject('response')
|
||||
->action(function (string $messageId, Database $dbForProject, Response $response) {
|
||||
@@ -3981,16 +3981,16 @@ App::patch('/v1/messaging/messages/email/:messageId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('messageId', '', new UID(), 'Message ID.')
|
||||
->param('topics', null, new Nullable(new ArrayList(new UID())), 'List of Topic IDs.', true)
|
||||
->param('users', null, new Nullable(new ArrayList(new UID())), 'List of User IDs.', true)
|
||||
->param('targets', null, new Nullable(new ArrayList(new UID())), 'List of Targets IDs.', true)
|
||||
->param('messageId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Message ID.', false, ['dbForProject'])
|
||||
->param('topics', null, fn (Database $dbForProject) => new Nullable(new ArrayList(new UID($dbForProject->getAdapter()->getMaxUIDLength()))), 'List of Topic IDs.', true, ['dbForProject'])
|
||||
->param('users', null, fn (Database $dbForProject) => new Nullable(new ArrayList(new UID($dbForProject->getAdapter()->getMaxUIDLength()))), 'List of User IDs.', true, ['dbForProject'])
|
||||
->param('targets', null, fn (Database $dbForProject) => new Nullable(new ArrayList(new UID($dbForProject->getAdapter()->getMaxUIDLength()))), 'List of Targets IDs.', true, ['dbForProject'])
|
||||
->param('subject', null, new Nullable(new Text(998)), 'Email Subject.', true)
|
||||
->param('content', null, new Nullable(new Text(64230)), 'Email Content.', true)
|
||||
->param('draft', null, new Nullable(new Boolean()), 'Is message a draft', true)
|
||||
->param('html', null, new Nullable(new Boolean()), 'Is content of type HTML', true)
|
||||
->param('cc', null, new Nullable(new ArrayList(new UID())), 'Array of target IDs to be added as CC.', true)
|
||||
->param('bcc', null, new Nullable(new ArrayList(new UID())), 'Array of target IDs to be added as BCC.', true)
|
||||
->param('cc', null, fn (Database $dbForProject) => new Nullable(new ArrayList(new UID($dbForProject->getAdapter()->getMaxUIDLength()))), 'Array of target IDs to be added as CC.', true, ['dbForProject'])
|
||||
->param('bcc', null, fn (Database $dbForProject) => new Nullable(new ArrayList(new UID($dbForProject->getAdapter()->getMaxUIDLength()))), 'Array of target IDs to be added as BCC.', true, ['dbForProject'])
|
||||
->param('scheduledAt', null, new Nullable(new DatetimeValidator(requireDateInFuture: true)), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true)
|
||||
->param('attachments', null, new Nullable(new ArrayList(new CompoundUID())), 'Array of compound ID strings of bucket IDs and file IDs to be attached to the email. They should be formatted as <BUCKET_ID>:<FILE_ID>.', true)
|
||||
->inject('queueForEvents')
|
||||
@@ -4208,10 +4208,10 @@ App::patch('/v1/messaging/messages/sms/:messageId')
|
||||
]
|
||||
)
|
||||
])
|
||||
->param('messageId', '', new UID(), 'Message ID.')
|
||||
->param('topics', null, new Nullable(new ArrayList(new UID())), 'List of Topic IDs.', true)
|
||||
->param('users', null, new Nullable(new ArrayList(new UID())), 'List of User IDs.', true)
|
||||
->param('targets', null, new Nullable(new ArrayList(new UID())), 'List of Targets IDs.', true)
|
||||
->param('messageId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Message ID.', false, ['dbForProject'])
|
||||
->param('topics', null, fn (Database $dbForProject) => new Nullable(new ArrayList(new UID($dbForProject->getAdapter()->getMaxUIDLength()))), 'List of Topic IDs.', true, ['dbForProject'])
|
||||
->param('users', null, fn (Database $dbForProject) => new Nullable(new ArrayList(new UID($dbForProject->getAdapter()->getMaxUIDLength()))), 'List of User IDs.', true, ['dbForProject'])
|
||||
->param('targets', null, fn (Database $dbForProject) => new Nullable(new ArrayList(new UID($dbForProject->getAdapter()->getMaxUIDLength()))), 'List of Targets IDs.', true, ['dbForProject'])
|
||||
->param('content', null, new Nullable(new Text(64230)), 'Email Content.', true)
|
||||
->param('draft', null, new Nullable(new Boolean()), 'Is message a draft', true)
|
||||
->param('scheduledAt', null, new Nullable(new DatetimeValidator(requireDateInFuture: true)), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true)
|
||||
@@ -4370,10 +4370,10 @@ App::patch('/v1/messaging/messages/push/:messageId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('messageId', '', new UID(), 'Message ID.')
|
||||
->param('topics', null, new Nullable(new ArrayList(new UID())), 'List of Topic IDs.', true)
|
||||
->param('users', null, new Nullable(new ArrayList(new UID())), 'List of User IDs.', true)
|
||||
->param('targets', null, new Nullable(new ArrayList(new UID())), 'List of Targets IDs.', true)
|
||||
->param('messageId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Message ID.', false, ['dbForProject'])
|
||||
->param('topics', null, fn (Database $dbForProject) => new Nullable(new ArrayList(new UID($dbForProject->getAdapter()->getMaxUIDLength()))), 'List of Topic IDs.', true, ['dbForProject'])
|
||||
->param('users', null, fn (Database $dbForProject) => new Nullable(new ArrayList(new UID($dbForProject->getAdapter()->getMaxUIDLength()))), 'List of User IDs.', true, ['dbForProject'])
|
||||
->param('targets', null, fn (Database $dbForProject) => new Nullable(new ArrayList(new UID($dbForProject->getAdapter()->getMaxUIDLength()))), 'List of Targets IDs.', true, ['dbForProject'])
|
||||
->param('title', null, new Nullable(new Text(256)), 'Title for push notification.', true)
|
||||
->param('body', null, new Nullable(new Text(64230)), 'Body for push notification.', true)
|
||||
->param('data', null, new Nullable(new JSON()), 'Additional Data for push notification.', true)
|
||||
@@ -4632,7 +4632,7 @@ App::delete('/v1/messaging/messages/:messageId')
|
||||
],
|
||||
contentType: ContentType::NONE
|
||||
))
|
||||
->param('messageId', '', new UID(), 'Message ID.')
|
||||
->param('messageId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Message ID.', false, ['dbForProject'])
|
||||
->inject('dbForProject')
|
||||
->inject('dbForPlatform')
|
||||
->inject('queueForEvents')
|
||||
|
||||
@@ -43,6 +43,14 @@ use Utopia\Validator\WhiteList;
|
||||
|
||||
include_once __DIR__ . '/../shared/api.php';
|
||||
|
||||
function getDatabaseTransferResourceServices(string $databaseType)
|
||||
{
|
||||
return match($databaseType) {
|
||||
DATABASE_TYPE_LEGACY,
|
||||
DATABASE_TYPE_TABLESDB => Transfer::GROUP_DATABASES_TABLES_DB
|
||||
};
|
||||
}
|
||||
|
||||
App::post('/v1/migrations/appwrite')
|
||||
->groups(['api', 'migrations'])
|
||||
->desc('Create Appwrite migration')
|
||||
@@ -64,7 +72,7 @@ App::post('/v1/migrations/appwrite')
|
||||
))
|
||||
->param('resources', [], new ArrayList(new WhiteList(Appwrite::getSupportedResources())), 'List of resources to migrate')
|
||||
->param('endpoint', '', new URL(), 'Source Appwrite endpoint')
|
||||
->param('projectId', '', new UID(), 'Source Project ID')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Source Project ID', false, ['dbForProject'])
|
||||
->param('apiKey', '', new Text(512), 'Source API Key')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
@@ -335,8 +343,8 @@ App::post('/v1/migrations/csv/imports')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).')
|
||||
->param('fileId', '', new UID(), 'File ID.')
|
||||
->param('bucketId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).', false, ['dbForProject'])
|
||||
->param('fileId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'File ID.', false, ['dbForProject'])
|
||||
->param('resourceId', null, new CompoundUID(), 'Composite ID in the format {databaseId:collectionId}, identifying a collection within a database.')
|
||||
->param('internalFile', false, new Boolean(), 'Is the file stored in an internal bucket?', true)
|
||||
->inject('response')
|
||||
@@ -425,8 +433,16 @@ App::post('/v1/migrations/csv/imports')
|
||||
throw new \Exception('Unable to copy file');
|
||||
}
|
||||
|
||||
// getting databasetype
|
||||
$resources = explode(':', $resourceId);
|
||||
$databaseId = $resources[0];
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
$databaseType = $database->getAttribute('type');
|
||||
if (!in_array($databaseType, CSV_ALLOWED_DATABASE_TYPES)) {
|
||||
throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Database type not supported for csv');
|
||||
}
|
||||
$fileSize = $deviceForMigrations->getFileSize($newPath);
|
||||
$resources = Transfer::extractServices([Transfer::GROUP_DATABASES]);
|
||||
$resources = Transfer::extractServices([getDatabaseTransferResourceServices($databaseType)]);
|
||||
|
||||
$migration = $dbForProject->createDocument('migrations', new Document([
|
||||
'$id' => $migrationId,
|
||||
@@ -553,13 +569,23 @@ App::post('/v1/migrations/csv/exports')
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
|
||||
}
|
||||
|
||||
// getting databasetype
|
||||
$resources = explode(':', $resourceId);
|
||||
$databaseId = $resources[0];
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
$databaseType = $database->getAttribute('type');
|
||||
if (!in_array($databaseType, CSV_ALLOWED_DATABASE_TYPES)) {
|
||||
throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Database type not supported for csv');
|
||||
}
|
||||
$resources = Transfer::extractServices([getDatabaseTransferResourceServices($databaseType)]);
|
||||
|
||||
$migration = $dbForProject->createDocument('migrations', new Document([
|
||||
'$id' => ID::unique(),
|
||||
'status' => 'pending',
|
||||
'stage' => 'init',
|
||||
'source' => Appwrite::getName(),
|
||||
'destination' => CSV::getName(),
|
||||
'resources' => Transfer::extractServices([Transfer::GROUP_DATABASES]),
|
||||
'resources' => $resources,
|
||||
'resourceId' => $resourceId,
|
||||
'resourceType' => Resource::TYPE_DATABASE,
|
||||
'statusCounters' => '{}',
|
||||
@@ -680,7 +706,7 @@ App::get('/v1/migrations/:migrationId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('migrationId', '', new UID(), 'Migration unique ID.')
|
||||
->param('migrationId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Migration unique ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $migrationId, Response $response, Database $dbForProject) {
|
||||
@@ -715,12 +741,10 @@ App::get('/v1/migrations/appwrite/report')
|
||||
->param('projectID', '', new Text(512), "Source's Project ID")
|
||||
->param('key', '', new Text(512), "Source's API Key")
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('project')
|
||||
->inject('user')
|
||||
->action(function (array $resources, string $endpoint, string $projectID, string $key, Response $response) {
|
||||
->inject('getDatabasesDB')
|
||||
->action(function (array $resources, string $endpoint, string $projectID, string $key, Response $response, callable $getDatabasesDB) {
|
||||
|
||||
$appwrite = new Appwrite($projectID, $endpoint, $key);
|
||||
$appwrite = new Appwrite($projectID, $endpoint, $key, $getDatabasesDB);
|
||||
|
||||
try {
|
||||
$report = $appwrite->report($resources);
|
||||
@@ -913,7 +937,7 @@ App::patch('/v1/migrations/:migrationId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('migrationId', '', new UID(), 'Migration unique ID.')
|
||||
->param('migrationId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Migration unique ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('project')
|
||||
@@ -967,7 +991,7 @@ App::delete('/v1/migrations/:migrationId')
|
||||
],
|
||||
contentType: ContentType::NONE
|
||||
))
|
||||
->param('migrationId', '', new UID(), 'Migration ID.')
|
||||
->param('migrationId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Migration ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
|
||||
@@ -61,15 +61,20 @@ App::get('/v1/project/usage')
|
||||
METRIC_EXECUTIONS_MB_SECONDS,
|
||||
METRIC_BUILDS_MB_SECONDS,
|
||||
METRIC_DOCUMENTS,
|
||||
METRIC_DOCUMENTS_DOCUMENTSDB,
|
||||
METRIC_DATABASES,
|
||||
METRIC_DATABASES_DOCUMENTSDB,
|
||||
METRIC_USERS,
|
||||
METRIC_BUCKETS,
|
||||
METRIC_FILES_STORAGE,
|
||||
METRIC_DATABASES_STORAGE,
|
||||
METRIC_DATABASES_STORAGE_DOCUMENTSDB,
|
||||
METRIC_DEPLOYMENTS_STORAGE,
|
||||
METRIC_BUILDS_STORAGE,
|
||||
METRIC_DATABASES_OPERATIONS_READS,
|
||||
METRIC_DATABASES_OPERATIONS_READS_DOCUMENTSDB,
|
||||
METRIC_DATABASES_OPERATIONS_WRITES,
|
||||
METRIC_DATABASES_OPERATIONS_WRITES_DOCUMENTSDB,
|
||||
METRIC_FILES_IMAGES_TRANSFORMED,
|
||||
],
|
||||
'period' => [
|
||||
@@ -79,10 +84,13 @@ App::get('/v1/project/usage')
|
||||
METRIC_USERS,
|
||||
METRIC_EXECUTIONS,
|
||||
METRIC_DATABASES_STORAGE,
|
||||
METRIC_DATABASES_STORAGE_DOCUMENTSDB,
|
||||
METRIC_EXECUTIONS_MB_SECONDS,
|
||||
METRIC_BUILDS_MB_SECONDS,
|
||||
METRIC_DATABASES_OPERATIONS_READS,
|
||||
METRIC_DATABASES_OPERATIONS_READS_DOCUMENTSDB,
|
||||
METRIC_DATABASES_OPERATIONS_WRITES,
|
||||
METRIC_DATABASES_OPERATIONS_WRITES_DOCUMENTSDB,
|
||||
METRIC_FILES_IMAGES_TRANSFORMED,
|
||||
]
|
||||
];
|
||||
@@ -356,8 +364,11 @@ App::get('/v1/project/usage')
|
||||
'buildsMbSecondsTotal' => $total[METRIC_BUILDS_MB_SECONDS],
|
||||
'documentsTotal' => $total[METRIC_DOCUMENTS],
|
||||
'rowsTotal' => $total[METRIC_DOCUMENTS],
|
||||
'documentsdbDocumentsTotal' => $total[METRIC_DOCUMENTS_DOCUMENTSDB],
|
||||
'databasesTotal' => $total[METRIC_DATABASES],
|
||||
'documentsdbTotal' => $total[METRIC_DATABASES_DOCUMENTSDB],
|
||||
'databasesStorageTotal' => $total[METRIC_DATABASES_STORAGE],
|
||||
'documentsdbDatabasesStorageTotal' => $total[METRIC_DATABASES_STORAGE_DOCUMENTSDB],
|
||||
'usersTotal' => $total[METRIC_USERS],
|
||||
'bucketsTotal' => $total[METRIC_BUCKETS],
|
||||
'filesStorageTotal' => $total[METRIC_FILES_STORAGE],
|
||||
@@ -366,10 +377,15 @@ App::get('/v1/project/usage')
|
||||
'deploymentsStorageTotal' => $total[METRIC_DEPLOYMENTS_STORAGE],
|
||||
'databasesReadsTotal' => $total[METRIC_DATABASES_OPERATIONS_READS],
|
||||
'databasesWritesTotal' => $total[METRIC_DATABASES_OPERATIONS_WRITES],
|
||||
'documentsdbDatabasesReadsTotal' => $total[METRIC_DATABASES_OPERATIONS_READS_DOCUMENTSDB],
|
||||
'documentsdbDatabasesWritesTotal' => $total[METRIC_DATABASES_OPERATIONS_WRITES_DOCUMENTSDB],
|
||||
'executionsBreakdown' => $executionsBreakdown,
|
||||
'bucketsBreakdown' => $bucketsBreakdown,
|
||||
'databasesReads' => $usage[METRIC_DATABASES_OPERATIONS_READS],
|
||||
'databasesWrites' => $usage[METRIC_DATABASES_OPERATIONS_WRITES],
|
||||
'documentsdbDatabasesReads' => $usage[METRIC_DATABASES_OPERATIONS_READS_DOCUMENTSDB],
|
||||
'documentsdbDatabasesWrites' => $usage[METRIC_DATABASES_OPERATIONS_WRITES_DOCUMENTSDB],
|
||||
'documentsdbDatabasesStorage' => $usage[METRIC_DATABASES_STORAGE_DOCUMENTSDB],
|
||||
'databasesStorageBreakdown' => $databasesStorageBreakdown,
|
||||
'executionsMbSecondsBreakdown' => $executionsMbSecondsBreakdown,
|
||||
'buildsMbSecondsBreakdown' => $buildsMbSecondsBreakdown,
|
||||
@@ -495,7 +511,7 @@ App::get('/v1/project/variables/:variableId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('variableId', '', new UID(), 'Variable unique ID.', false)
|
||||
->param('variableId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Variable unique ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
->inject('dbForProject')
|
||||
@@ -525,7 +541,7 @@ App::put('/v1/project/variables/:variableId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('variableId', '', new UID(), 'Variable unique ID.', false)
|
||||
->param('variableId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Variable unique ID.', false, ['dbForProject'])
|
||||
->param('key', null, new Text(255), 'Variable key. Max length: 255 chars.', false)
|
||||
->param('value', null, new Nullable(new Text(8192, 0)), 'Variable value. Max length: 8192 chars.', true)
|
||||
->param('secret', null, new Nullable(new Boolean()), 'Secret variables can be updated or deleted, but only projects can read them during build and runtime.', true)
|
||||
@@ -584,7 +600,7 @@ App::delete('/v1/project/variables/:variableId')
|
||||
],
|
||||
contentType: ContentType::NONE
|
||||
))
|
||||
->param('variableId', '', new UID(), 'Variable unique ID.', false)
|
||||
->param('variableId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Variable unique ID.', false, ['dbForProject'])
|
||||
->inject('project')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
|
||||
@@ -16,7 +16,6 @@ use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Template\Template;
|
||||
use Appwrite\Utopia\Database\Validator\ProjectId;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Projects;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
@@ -82,7 +81,7 @@ App::post('/v1/projects')
|
||||
))
|
||||
->param('projectId', '', new ProjectId(), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, and hyphen. 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('teamId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Team unique ID.', false, ['dbForProject'])
|
||||
->param('region', System::getEnv('_APP_REGION', 'default'), new Whitelist(array_keys(array_filter(Config::getParam('regions'), fn ($config) => !$config['disabled']))), 'Project Region.', true)
|
||||
->param('description', '', new Text(256), 'Project description. Max length: 256 chars.', true)
|
||||
->param('logo', '', new Text(1024), 'Project logo.', true)
|
||||
@@ -101,6 +100,97 @@ App::post('/v1/projects')
|
||||
->inject('hooks')
|
||||
->action(function (string $projectId, string $name, string $teamId, string $region, string $description, string $logo, string $url, string $legalName, string $legalCountry, string $legalState, string $legalCity, string $legalAddress, string $legalTaxId, Request $request, Response $response, Database $dbForPlatform, Cache $cache, Group $pools, Hooks $hooks) {
|
||||
|
||||
// for returning dsn of multitype dbs with type optionally based on input dsn
|
||||
$getDatabaseDSN = function (string $databasetype, $region, ?string $dsn = null): string {
|
||||
$isSharedTablesV1 = false;
|
||||
$isSharedTablesV2 = false;
|
||||
if (!empty($dsn)) {
|
||||
try {
|
||||
$parsedDsn = new DSN($dsn);
|
||||
$dsnHost = $parsedDsn->getHost();
|
||||
} catch (\InvalidArgumentException) {
|
||||
$dsnHost = $dsn;
|
||||
}
|
||||
|
||||
$sharedTables = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES', ''));
|
||||
$sharedTablesV1 = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES_V1', ''));
|
||||
$sharedTablesV2 = \array_diff($sharedTables, $sharedTablesV1);
|
||||
$isSharedTablesV1 = \in_array($dsnHost, $sharedTablesV1);
|
||||
$isSharedTablesV2 = \in_array($dsnHost, $sharedTablesV2);
|
||||
}
|
||||
|
||||
$databases = [];
|
||||
$databaseKeys = [];
|
||||
/**
|
||||
* @var string|null $databaseOverride
|
||||
*/
|
||||
$databaseOverride = '';
|
||||
$dbScheme = '';
|
||||
$sharedTables = [];
|
||||
$sharedTablesV1 = [];
|
||||
$sharedTablesV2 = [];
|
||||
|
||||
switch ($databasetype) {
|
||||
case 'documentsDatabase':
|
||||
$databases = Config::getParam('pools-documentsdb', []);
|
||||
$databaseKeys = System::getEnv('_APP_DATABASE_DOCUMENTSDB_KEYS', '');
|
||||
$databaseOverride = System::getEnv('_APP_DATABASE_DOCUMENTSDB_OVERRIDE');
|
||||
$dbScheme = System::getEnv('_APP_DB_HOST_DOCUMENTSDB', 'mongodb');
|
||||
$sharedTables = \explode(',', System::getEnv('_APP_DATABASE_DOCUMENTSDB_SHARED_TABLES', ''));
|
||||
$sharedTablesV1 = \explode(',', System::getEnv('_APP_DATABASE_DOCUMENTSDB_SHARED_TABLES_V1', ''));
|
||||
break;
|
||||
default:
|
||||
// legacy/tablesdb
|
||||
$databases = Config::getParam('pools-database', []);
|
||||
$databaseKeys = System::getEnv('_APP_DATABASE_KEYS', '');
|
||||
$databaseOverride = System::getEnv('_APP_DATABASE_OVERRIDE');
|
||||
$dbScheme = System::getEnv('_APP_DB_HOST', 'mysql');
|
||||
$sharedTables = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES', ''));
|
||||
$sharedTablesV1 = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES_V1', ''));
|
||||
break;
|
||||
}
|
||||
|
||||
if ($region !== 'default') {
|
||||
$keys = explode(',', $databaseKeys);
|
||||
$databases = array_filter($keys, function ($value) use ($region) {
|
||||
return str_contains($value, $region);
|
||||
});
|
||||
}
|
||||
$sharedTablesV2 = \array_diff($sharedTables, $sharedTablesV1);
|
||||
|
||||
$index = \array_search($databaseOverride, $databases);
|
||||
if ($index !== false) {
|
||||
$selectedDsn = $databases[$index];
|
||||
} else {
|
||||
if (!empty($dsn)) {
|
||||
if ($isSharedTablesV1) {
|
||||
$databases = array_filter($databases, fn ($value) => \in_array($value, $sharedTablesV1));
|
||||
} elseif ($isSharedTablesV2) {
|
||||
$databases = array_filter($databases, fn ($value) => \in_array($value, $sharedTablesV2));
|
||||
} else {
|
||||
$databases = array_filter($databases, fn ($value) => !\in_array($value, $sharedTables));
|
||||
}
|
||||
}
|
||||
$selectedDsn = !empty($databases) ? $databases[array_rand($databases)] : '';
|
||||
}
|
||||
|
||||
if (\in_array($selectedDsn, $sharedTables)) {
|
||||
$schema = 'appwrite';
|
||||
$database = 'appwrite';
|
||||
$namespace = System::getEnv('_APP_DATABASE_SHARED_NAMESPACE', '');
|
||||
$selectedDsn = $schema . '://' . $selectedDsn . '?database=' . $database;
|
||||
|
||||
if (!empty($namespace)) {
|
||||
$selectedDsn .= '&namespace=' . $namespace;
|
||||
}
|
||||
}
|
||||
try {
|
||||
new DSN($selectedDsn);
|
||||
} catch (\InvalidArgumentException) {
|
||||
$selectedDsn = $dbScheme.'://' . $selectedDsn;
|
||||
}
|
||||
return $selectedDsn;
|
||||
};
|
||||
$team = $dbForPlatform->getDocument('teams', $teamId);
|
||||
|
||||
if ($team->isEmpty()) {
|
||||
@@ -139,37 +229,7 @@ App::post('/v1/projects')
|
||||
throw new Exception(Exception::PROJECT_RESERVED_PROJECT, "'console' is a reserved project.");
|
||||
}
|
||||
|
||||
$databases = Config::getParam('pools-database', []);
|
||||
|
||||
if ($region !== 'default') {
|
||||
$databaseKeys = System::getEnv('_APP_DATABASE_KEYS', '');
|
||||
$keys = explode(',', $databaseKeys);
|
||||
$databases = array_filter($keys, function ($value) use ($region) {
|
||||
return str_contains($value, $region);
|
||||
});
|
||||
}
|
||||
|
||||
$databaseOverride = System::getEnv('_APP_DATABASE_OVERRIDE');
|
||||
$index = \array_search($databaseOverride, $databases);
|
||||
if ($index !== false) {
|
||||
$dsn = $databases[$index];
|
||||
} else {
|
||||
$dsn = $databases[array_rand($databases)];
|
||||
}
|
||||
|
||||
// TODO: Temporary until all projects are using shared tables.
|
||||
$sharedTables = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES', ''));
|
||||
|
||||
if (\in_array($dsn, $sharedTables)) {
|
||||
$schema = 'appwrite';
|
||||
$database = 'appwrite';
|
||||
$namespace = System::getEnv('_APP_DATABASE_SHARED_NAMESPACE', '');
|
||||
$dsn = $schema . '://' . $dsn . '?database=' . $database;
|
||||
|
||||
if (!empty($namespace)) {
|
||||
$dsn .= '&namespace=' . $namespace;
|
||||
}
|
||||
}
|
||||
$dsn = $getDatabaseDSN('databases', $region);
|
||||
|
||||
try {
|
||||
$project = $dbForPlatform->createDocument('projects', new Document([
|
||||
@@ -205,6 +265,7 @@ App::post('/v1/projects')
|
||||
'search' => implode(' ', [$projectId, $name]),
|
||||
'database' => $dsn,
|
||||
'labels' => [],
|
||||
'documentsDatabase' => $getDatabaseDSN('documentsDatabase', $region, $dsn),
|
||||
]));
|
||||
} catch (Duplicate) {
|
||||
throw new Exception(Exception::PROJECT_ALREADY_EXISTS);
|
||||
@@ -322,7 +383,7 @@ App::get('/v1/projects/:projectId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->action(function (string $projectId, Response $response, Database $dbForPlatform) {
|
||||
@@ -355,7 +416,7 @@ App::patch('/v1/projects/:projectId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('name', null, new Text(128), 'Project name. Max length: 128 chars.')
|
||||
->param('description', '', new Text(256), 'Project description. Max length: 256 chars.', true)
|
||||
->param('logo', '', new Text(1024), 'Project logo.', true)
|
||||
@@ -409,8 +470,8 @@ App::patch('/v1/projects/:projectId/team')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('teamId', '', new UID(), 'Team ID of the team to transfer project to.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('teamId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Team ID of the team to transfer project to.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->action(function (string $projectId, string $teamId, Response $response, Database $dbForPlatform) {
|
||||
@@ -484,7 +545,7 @@ App::patch('/v1/projects/:projectId/service')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('service', '', new WhiteList(array_keys(array_filter(Config::getParam('services'), fn ($element) => $element['optional'])), true), 'Service name.')
|
||||
->param('status', null, new Boolean(), 'Service status.')
|
||||
->inject('response')
|
||||
@@ -522,7 +583,7 @@ App::patch('/v1/projects/:projectId/service/all')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('status', null, new Boolean(), 'Service status.')
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
@@ -583,7 +644,7 @@ App::patch('/v1/projects/:projectId/api')
|
||||
]
|
||||
)
|
||||
])
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('api', '', new WhiteList(array_keys(Config::getParam('apis')), true), 'API name.')
|
||||
->param('status', null, new Boolean(), 'API status.')
|
||||
->inject('response')
|
||||
@@ -641,7 +702,7 @@ App::patch('/v1/projects/:projectId/api/all')
|
||||
]
|
||||
)
|
||||
])
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('status', null, new Boolean(), 'API status.')
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
@@ -682,7 +743,7 @@ App::patch('/v1/projects/:projectId/oauth2')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('provider', '', new WhiteList(\array_keys(Config::getParam('oAuthProviders')), true), 'Provider Name')
|
||||
->param('appId', null, new Nullable(new Text(256)), 'Provider app ID. Max length: 256 chars.', true)
|
||||
->param('secret', null, new Nullable(new text(512)), 'Provider secret key. Max length: 512 chars.', true)
|
||||
@@ -733,7 +794,7 @@ App::patch('/v1/projects/:projectId/auth/session-alerts')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('alerts', false, new Boolean(true), 'Set to true to enable session emails.')
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
@@ -771,7 +832,7 @@ App::patch('/v1/projects/:projectId/auth/memberships-privacy')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('userName', true, new Boolean(true), 'Set to true to show userName to members of a team.')
|
||||
->param('userEmail', true, new Boolean(true), 'Set to true to show email to members of a team.')
|
||||
->param('mfa', true, new Boolean(true), 'Set to true to show mfa to members of a team.')
|
||||
@@ -813,7 +874,7 @@ App::patch('/v1/projects/:projectId/auth/limit')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('limit', false, new Range(0, APP_LIMIT_USERS), 'Set the max number of users allowed in this project. Use 0 for unlimited.')
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
@@ -851,7 +912,7 @@ App::patch('/v1/projects/:projectId/auth/duration')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('duration', 31536000, new Range(0, 31536000), 'Project session length in seconds. Max length: 31536000 seconds.')
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
@@ -889,7 +950,7 @@ App::patch('/v1/projects/:projectId/auth/:method')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('method', '', new WhiteList(\array_keys(Config::getParam('auth')), true), 'Auth Method. Possible values: ' . implode(',', \array_keys(Config::getParam('auth'))), false)
|
||||
->param('status', false, new Boolean(true), 'Set the status of this auth method.')
|
||||
->inject('response')
|
||||
@@ -930,7 +991,7 @@ App::patch('/v1/projects/:projectId/auth/password-history')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('limit', 0, new Range(0, APP_LIMIT_USER_PASSWORD_HISTORY), 'Set the max number of passwords to store in user history. User can\'t choose a new password that is already stored in the password history list. Max number of passwords allowed in history is' . APP_LIMIT_USER_PASSWORD_HISTORY . '. Default value is 0')
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
@@ -968,7 +1029,7 @@ App::patch('/v1/projects/:projectId/auth/password-dictionary')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('enabled', false, new Boolean(false), 'Set whether or not to enable checking user\'s password against most commonly used passwords. Default is false.')
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
@@ -1006,7 +1067,7 @@ App::patch('/v1/projects/:projectId/auth/personal-data')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('enabled', false, new Boolean(false), 'Set whether or not to check a password for similarity with personal data. Default is false.')
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
@@ -1044,7 +1105,7 @@ App::patch('/v1/projects/:projectId/auth/max-sessions')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('limit', false, new Range(1, APP_LIMIT_USER_SESSIONS_MAX), 'Set the max number of users allowed in this project. Value allowed is between 1-' . APP_LIMIT_USER_SESSIONS_MAX . '. Default is ' . APP_LIMIT_USER_SESSIONS_DEFAULT)
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
@@ -1082,7 +1143,7 @@ App::patch('/v1/projects/:projectId/auth/mock-numbers')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('numbers', '', new ArrayList(new MockNumber(), 10), 'An array of mock numbers and their corresponding verification codes (OTPs). Each number should be a valid E.164 formatted phone number. Maximum of 10 numbers are allowed.')
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
@@ -1131,7 +1192,7 @@ App::delete('/v1/projects/:projectId')
|
||||
],
|
||||
contentType: ContentType::NONE
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->inject('dbForPlatform')
|
||||
@@ -1174,7 +1235,7 @@ App::post('/v1/projects/:projectId/webhooks')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('name', null, new Text(128), 'Webhook name. Max length: 128 chars.')
|
||||
->param('enabled', true, new Boolean(true), 'Enable or disable a webhook.', true)
|
||||
->param('events', null, new ArrayList(new Event(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.')
|
||||
@@ -1239,7 +1300,7 @@ App::get('/v1/projects/:projectId/webhooks')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
@@ -1279,8 +1340,8 @@ App::get('/v1/projects/:projectId/webhooks/:webhookId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('webhookId', '', new UID(), 'Webhook unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('webhookId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Webhook unique ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->action(function (string $projectId, string $webhookId, Response $response, Database $dbForPlatform) {
|
||||
@@ -1320,8 +1381,8 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('webhookId', '', new UID(), 'Webhook unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('webhookId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Webhook unique ID.', false, ['dbForProject'])
|
||||
->param('name', null, new Text(128), 'Webhook name. Max length: 128 chars.')
|
||||
->param('enabled', true, new Boolean(true), 'Enable or disable a webhook.', true)
|
||||
->param('events', null, new ArrayList(new Event(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.')
|
||||
@@ -1386,8 +1447,8 @@ App::patch('/v1/projects/:projectId/webhooks/:webhookId/signature')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('webhookId', '', new UID(), 'Webhook unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('webhookId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Webhook unique ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->action(function (string $projectId, string $webhookId, Response $response, Database $dbForPlatform) {
|
||||
@@ -1433,8 +1494,8 @@ App::delete('/v1/projects/:projectId/webhooks/:webhookId')
|
||||
],
|
||||
contentType: ContentType::NONE
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('webhookId', '', new UID(), 'Webhook unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('webhookId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Webhook unique ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->action(function (string $projectId, string $webhookId, Response $response, Database $dbForPlatform) {
|
||||
@@ -1480,7 +1541,7 @@ App::post('/v1/projects/:projectId/keys')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('name', null, new Text(128), 'Key name. Max length: 128 chars.')
|
||||
->param('scopes', null, new Nullable(new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE)), 'Key scopes list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed.')
|
||||
->param('expire', null, new Nullable(new DatetimeValidator()), 'Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration.', true)
|
||||
@@ -1541,7 +1602,7 @@ App::get('/v1/projects/:projectId/keys')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
@@ -1582,8 +1643,8 @@ App::get('/v1/projects/:projectId/keys/:keyId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('keyId', '', new UID(), 'Key unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('keyId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Key unique ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->action(function (string $projectId, string $keyId, Response $response, Database $dbForPlatform) {
|
||||
@@ -1624,8 +1685,8 @@ App::put('/v1/projects/:projectId/keys/:keyId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('keyId', '', new UID(), 'Key unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('keyId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Key unique ID.', false, ['dbForProject'])
|
||||
->param('name', null, new Text(128), 'Key name. Max length: 128 chars.')
|
||||
->param('scopes', null, new Nullable(new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE)), 'Key scopes list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.')
|
||||
->param('expire', null, new Nullable(new DatetimeValidator()), 'Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration.', true)
|
||||
@@ -1679,8 +1740,8 @@ App::delete('/v1/projects/:projectId/keys/:keyId')
|
||||
],
|
||||
contentType: ContentType::NONE
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('keyId', '', new UID(), 'Key unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('keyId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Key unique ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->action(function (string $projectId, string $keyId, Response $response, Database $dbForPlatform) {
|
||||
@@ -1727,7 +1788,7 @@ App::post('/v1/projects/:projectId/jwts')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('scopes', [], new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'List of scopes allowed for JWT key. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed.')
|
||||
->param('duration', 900, new Range(0, 3600), 'Time in seconds before JWT expires. Default duration is 900 seconds, and maximum is 3600 seconds.', true)
|
||||
->inject('response')
|
||||
@@ -1771,7 +1832,7 @@ App::post('/v1/projects/:projectId/platforms')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param(
|
||||
'type',
|
||||
null,
|
||||
@@ -1849,7 +1910,7 @@ App::get('/v1/projects/:projectId/platforms')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
@@ -1889,8 +1950,8 @@ App::get('/v1/projects/:projectId/platforms/:platformId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('platformId', '', new UID(), 'Platform unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('platformId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Platform unique ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->action(function (string $projectId, string $platformId, Response $response, Database $dbForPlatform) {
|
||||
@@ -1930,8 +1991,8 @@ App::put('/v1/projects/:projectId/platforms/:platformId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('platformId', '', new UID(), 'Platform unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('platformId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Platform unique ID.', false, ['dbForProject'])
|
||||
->param('name', null, new Text(128), 'Platform name. Max length: 128 chars.')
|
||||
->param('key', '', new Text(256), 'Package name for android or bundle ID for iOS. Max length: 256 chars.', true)
|
||||
->param('store', '', new Text(256), 'App store or Google Play store ID. Max length: 256 chars.', true)
|
||||
@@ -1987,8 +2048,8 @@ App::delete('/v1/projects/:projectId/platforms/:platformId')
|
||||
],
|
||||
contentType: ContentType::NONE
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('platformId', '', new UID(), 'Platform unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('platformId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Platform unique ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->action(function (string $projectId, string $platformId, Response $response, Database $dbForPlatform) {
|
||||
@@ -2054,7 +2115,7 @@ App::patch('/v1/projects/:projectId/smtp')
|
||||
]
|
||||
)
|
||||
])
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('enabled', false, new Boolean(), 'Enable custom SMTP service')
|
||||
->param('senderName', '', new Text(255, 0), 'Name of the email sender', true)
|
||||
->param('senderEmail', '', new Email(), 'Email of the sender', true)
|
||||
@@ -2172,7 +2233,7 @@ App::post('/v1/projects/:projectId/smtp/tests')
|
||||
]
|
||||
)
|
||||
])
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('emails', [], new ArrayList(new Email(), 10), 'Array of emails to send test email to. Maximum of 10 emails are allowed.')
|
||||
->param('senderName', System::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server'), new Text(255, 0), 'Name of the email sender')
|
||||
->param('senderEmail', System::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM), new Email(), 'Email of the sender')
|
||||
@@ -2267,7 +2328,7 @@ App::get('/v1/projects/:projectId/templates/sms/:type/:locale')
|
||||
]
|
||||
)
|
||||
])
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('type', '', new WhiteList(Config::getParam('locale-templates')['sms'] ?? []), 'Template type')
|
||||
->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->inject('response')
|
||||
@@ -2315,7 +2376,7 @@ App::get('/v1/projects/:projectId/templates/email/:type/:locale')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('type', '', new WhiteList(Config::getParam('locale-templates')['email'] ?? []), 'Template type')
|
||||
->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->inject('response')
|
||||
@@ -2434,7 +2495,7 @@ App::patch('/v1/projects/:projectId/templates/sms/:type/:locale')
|
||||
]
|
||||
)
|
||||
])
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('type', '', new WhiteList(Config::getParam('locale-templates')['sms'] ?? []), 'Template type')
|
||||
->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->param('message', '', new Text(0), 'Template message')
|
||||
@@ -2481,7 +2542,7 @@ App::patch('/v1/projects/:projectId/templates/email/:type/:locale')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('type', '', new WhiteList(Config::getParam('locale-templates')['email'] ?? []), 'Template type')
|
||||
->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->param('subject', '', new Text(255), 'Email Subject')
|
||||
@@ -2560,7 +2621,7 @@ App::delete('/v1/projects/:projectId/templates/sms/:type/:locale')
|
||||
contentType: ContentType::JSON
|
||||
)
|
||||
])
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('type', '', new WhiteList(Config::getParam('locale-templates')['sms'] ?? []), 'Template type')
|
||||
->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->inject('response')
|
||||
@@ -2611,7 +2672,7 @@ App::delete('/v1/projects/:projectId/templates/email/:type/:locale')
|
||||
],
|
||||
contentType: ContentType::JSON
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('type', '', new WhiteList(Config::getParam('locale-templates')['email'] ?? []), 'Template type')
|
||||
->param('locale', '', fn ($localeCodes) => new WhiteList($localeCodes), 'Template locale', false, ['localeCodes'])
|
||||
->inject('response')
|
||||
@@ -2663,7 +2724,7 @@ App::patch('/v1/projects/:projectId/auth/session-invalidation')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('projectId', '', new UID(), 'Project unique ID.')
|
||||
->param('projectId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForProject'])
|
||||
->param('enabled', false, new Boolean(), 'Update authentication session invalidation status. Use this endpoint to enable or disable session invalidation on password change')
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
|
||||
@@ -80,9 +80,9 @@ App::post('/v1/teams')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('teamId', '', new CustomId(), 'Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('teamId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('name', null, new Text(128), 'Team name. Max length: 128 chars.')
|
||||
->param('roles', ['owner'], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), '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](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.', true)
|
||||
->param('roles', ['owner'], fn (Database $dbForProject) => new ArrayList(new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), APP_LIMIT_ARRAY_PARAMS_SIZE), '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](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.', true, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->inject('dbForProject')
|
||||
@@ -245,7 +245,7 @@ App::get('/v1/teams/:teamId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('teamId', '', new UID(), 'Team ID.')
|
||||
->param('teamId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Team ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $teamId, Response $response, Database $dbForProject) {
|
||||
@@ -276,7 +276,7 @@ App::get('/v1/teams/:teamId/prefs')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('teamId', '', new UID(), 'Team ID.')
|
||||
->param('teamId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Team ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $teamId, Response $response, Database $dbForProject) {
|
||||
@@ -318,7 +318,7 @@ App::put('/v1/teams/:teamId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('teamId', '', new UID(), 'Team ID.')
|
||||
->param('teamId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Team ID.', false, ['dbForProject'])
|
||||
->param('name', null, new Text(128), 'New team name. Max length: 128 chars.')
|
||||
->inject('requestTimestamp')
|
||||
->inject('response')
|
||||
@@ -364,7 +364,7 @@ App::put('/v1/teams/:teamId/prefs')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('teamId', '', new UID(), 'Team ID.')
|
||||
->param('teamId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Team ID.', false, ['dbForProject'])
|
||||
->param('prefs', '', new Assoc(), 'Prefs key-value JSON object.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
@@ -412,7 +412,7 @@ App::delete('/v1/teams/:teamId')
|
||||
],
|
||||
contentType: ContentType::NONE
|
||||
))
|
||||
->param('teamId', '', new UID(), 'Team ID.')
|
||||
->param('teamId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Team ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('getProjectDB')
|
||||
->inject('dbForProject')
|
||||
@@ -471,11 +471,11 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
]
|
||||
))
|
||||
->label('abuse-limit', 10)
|
||||
->param('teamId', '', new UID(), 'Team ID.')
|
||||
->param('teamId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Team ID.', false, ['dbForProject'])
|
||||
->param('email', '', new EmailValidator(), 'Email of the new team member.', true)
|
||||
->param('userId', '', new UID(), 'ID of the user to be added to a team.', true)
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'ID of the user to be added to a team.', true, ['dbForProject'])
|
||||
->param('phone', '', new Phone(), 'Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true)
|
||||
->param('roles', [], function (Document $project) {
|
||||
->param('roles', [], function (Document $project, Database $dbForProject) {
|
||||
if ($project->getId() === 'console') {
|
||||
$roles = array_keys(Config::getParam('roles', []));
|
||||
$roles = array_filter($roles, function ($role) {
|
||||
@@ -483,8 +483,8 @@ App::post('/v1/teams/:teamId/memberships')
|
||||
});
|
||||
return new ArrayList(new WhiteList($roles), APP_LIMIT_ARRAY_PARAMS_SIZE);
|
||||
}
|
||||
return new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE);
|
||||
}, 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.', false, ['project'])
|
||||
return new ArrayList(new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), APP_LIMIT_ARRAY_PARAMS_SIZE);
|
||||
}, 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.', false, ['project', 'dbForProject'])
|
||||
->param('url', '', fn ($redirectValidator) => $redirectValidator, 'URL to redirect the user back to your app from the invitation email. This parameter is not required when an API key is supplied. 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, ['redirectValidator']) // TODO add our own built-in confirm page
|
||||
->param('name', '', new Text(128), 'Name of the new team member. Max length: 128 chars.', true)
|
||||
->inject('response')
|
||||
@@ -856,7 +856,7 @@ App::get('/v1/teams/:teamId/memberships')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('teamId', '', new UID(), 'Team ID.')
|
||||
->param('teamId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Team ID.', false, ['dbForProject'])
|
||||
->param('queries', [], new Memberships(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Memberships::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
@@ -999,8 +999,8 @@ App::get('/v1/teams/:teamId/memberships/:membershipId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('teamId', '', new UID(), 'Team ID.')
|
||||
->param('membershipId', '', new UID(), 'Membership ID.')
|
||||
->param('teamId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Team ID.', false, ['dbForProject'])
|
||||
->param('membershipId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Membership ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
->inject('dbForProject')
|
||||
@@ -1086,9 +1086,9 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('teamId', '', new UID(), 'Team ID.')
|
||||
->param('membershipId', '', new UID(), 'Membership ID.')
|
||||
->param('roles', [], function (Document $project) {
|
||||
->param('teamId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Team ID.', false, ['dbForProject'])
|
||||
->param('membershipId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Membership ID.', false, ['dbForProject'])
|
||||
->param('roles', [], function (Document $project, Database $dbForProject) {
|
||||
if ($project->getId() === 'console') {
|
||||
$roles = array_keys(Config::getParam('roles', []));
|
||||
$roles = array_filter($roles, function ($role) {
|
||||
@@ -1096,8 +1096,8 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId')
|
||||
});
|
||||
return new ArrayList(new WhiteList($roles), APP_LIMIT_ARRAY_PARAMS_SIZE);
|
||||
}
|
||||
return new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE);
|
||||
}, 'An array of strings. Use this param to set the user\'s roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.', false, ['project'])
|
||||
return new ArrayList(new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), APP_LIMIT_ARRAY_PARAMS_SIZE);
|
||||
}, 'An array of strings. Use this param to set the user\'s roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.', false, ['project', 'dbForProject'])
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
@@ -1196,9 +1196,9 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('teamId', '', new UID(), 'Team ID.')
|
||||
->param('membershipId', '', new UID(), 'Membership ID.')
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('teamId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Team ID.', false, ['dbForProject'])
|
||||
->param('membershipId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Membership ID.', false, ['dbForProject'])
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->param('secret', '', new Text(256), 'Secret key.')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
@@ -1362,8 +1362,8 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId')
|
||||
],
|
||||
contentType: ContentType::NONE
|
||||
))
|
||||
->param('teamId', '', new UID(), 'Team ID.')
|
||||
->param('membershipId', '', new UID(), 'Membership ID.')
|
||||
->param('teamId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Team ID.', false, ['dbForProject'])
|
||||
->param('membershipId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Membership ID.', false, ['dbForProject'])
|
||||
->inject('user')
|
||||
->inject('project')
|
||||
->inject('response')
|
||||
@@ -1457,7 +1457,7 @@ App::get('/v1/teams/:teamId/logs')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('teamId', '', new UID(), 'Team ID.')
|
||||
->param('teamId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Team ID.', false, ['dbForProject'])
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
|
||||
@@ -246,7 +246,7 @@ App::post('/v1/users')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('email', null, new Nullable(new EmailValidator()), 'User email.', true)
|
||||
->param('phone', null, new Nullable(new Phone()), 'Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true)
|
||||
->param('password', '', fn ($project, $passwordsDictionary) => new PasswordDictionary($passwordsDictionary, $project->getAttribute('auths', [])['passwordDictionary'] ?? false), 'Plain text user password. Must be at least 8 chars.', true, ['project', 'passwordsDictionary'])
|
||||
@@ -283,7 +283,7 @@ App::post('/v1/users/bcrypt')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('email', '', new EmailValidator(), 'User email.')
|
||||
->param('password', '', new Password(), 'User password hashed using Bcrypt.')
|
||||
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
|
||||
@@ -321,7 +321,7 @@ App::post('/v1/users/md5')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('email', '', new EmailValidator(), 'User email.')
|
||||
->param('password', '', new Password(), 'User password hashed using MD5.')
|
||||
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
|
||||
@@ -358,7 +358,7 @@ App::post('/v1/users/argon2')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('email', '', new EmailValidator(), 'User email.')
|
||||
->param('password', '', new Password(), 'User password hashed using Argon2.')
|
||||
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
|
||||
@@ -395,7 +395,7 @@ App::post('/v1/users/sha')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('email', '', new EmailValidator(), 'User email.')
|
||||
->param('password', '', new Password(), 'User password hashed using SHA.')
|
||||
->param('passwordVersion', '', new WhiteList(['sha1', 'sha224', 'sha256', 'sha384', 'sha512/224', 'sha512/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512']), "Optional SHA version used to hash password. Allowed values are: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512/224', 'sha512/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512'", true)
|
||||
@@ -436,7 +436,7 @@ App::post('/v1/users/phpass')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or pass the string `ID.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', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'User ID. Choose a custom ID or pass the string `ID.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.', false, ['dbForProject'])
|
||||
->param('email', '', new EmailValidator(), 'User email.')
|
||||
->param('password', '', new Password(), 'User password hashed using PHPass.')
|
||||
->param('name', '', new Text(128), 'User name. Max length: 128 chars.', true)
|
||||
@@ -473,7 +473,7 @@ App::post('/v1/users/scrypt')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('email', '', new EmailValidator(), 'User email.')
|
||||
->param('password', '', new Password(), 'User password hashed using Scrypt.')
|
||||
->param('passwordSalt', '', new Text(128), 'Optional salt used to hash password.')
|
||||
@@ -521,7 +521,7 @@ App::post('/v1/users/scrypt-modified')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('email', '', new EmailValidator(), 'User email.')
|
||||
->param('password', '', new Password(), 'User password hashed using Scrypt Modified.')
|
||||
->param('passwordSalt', '', new Text(128), 'Salt used to hash password.')
|
||||
@@ -566,11 +566,11 @@ App::post('/v1/users/:userId/targets')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('targetId', '', new CustomId(), 'Target ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('targetId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Target ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->param('providerType', '', new WhiteList([MESSAGE_TYPE_EMAIL, MESSAGE_TYPE_SMS, MESSAGE_TYPE_PUSH]), 'The target provider type. Can be one of the following: `email`, `sms` or `push`.')
|
||||
->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)')
|
||||
->param('providerId', '', new UID(), 'Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.', true)
|
||||
->param('providerId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.', true, ['dbForProject'])
|
||||
->param('name', '', new Text(128), 'Target name. Max length: 128 chars. For example: My Awesome App Galaxy S23.', true)
|
||||
->inject('queueForEvents')
|
||||
->inject('response')
|
||||
@@ -737,7 +737,7 @@ App::get('/v1/users/:userId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $userId, Response $response, Database $dbForProject) {
|
||||
@@ -768,7 +768,7 @@ App::get('/v1/users/:userId/prefs')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $userId, Response $response, Database $dbForProject) {
|
||||
@@ -801,8 +801,8 @@ App::get('/v1/users/:userId/targets/:targetId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('targetId', '', new UID(), 'Target ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->param('targetId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Target ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $userId, string $targetId, Response $response, Database $dbForProject) {
|
||||
@@ -839,7 +839,7 @@ App::get('/v1/users/:userId/sessions')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
@@ -883,7 +883,7 @@ App::get('/v1/users/:userId/memberships')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->param('queries', [], new Memberships(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Memberships::ALLOWED_ATTRIBUTES), true)
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
@@ -938,7 +938,7 @@ App::get('/v1/users/:userId/logs')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
@@ -1025,7 +1025,7 @@ App::get('/v1/users/:userId/targets')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->param('queries', [], new Targets(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Targets::ALLOWED_ATTRIBUTES), true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('response')
|
||||
@@ -1160,7 +1160,7 @@ App::patch('/v1/users/:userId/status')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->param('status', null, new Boolean(true), 'User Status. To activate the user pass `true` and to block the user pass `false`.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
@@ -1201,7 +1201,7 @@ App::put('/v1/users/:userId/labels')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->param('labels', [], new ArrayList(new Text(36, allowList: [...Text::NUMBERS, ...Text::ALPHABET_UPPER, ...Text::ALPHABET_LOWER]), APP_LIMIT_ARRAY_LABELS_SIZE), 'Array of user labels. Replaces the previous labels. Maximum of ' . APP_LIMIT_ARRAY_LABELS_SIZE . ' labels are allowed, each up to 36 alphanumeric characters long.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
@@ -1244,7 +1244,7 @@ App::patch('/v1/users/:userId/verification/phone')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->param('phoneVerification', false, new Boolean(), 'User phone verification status.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
@@ -1286,7 +1286,7 @@ App::patch('/v1/users/:userId/name')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->param('name', '', new Text(128, 0), 'User name. Max length: 128 chars.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
@@ -1329,7 +1329,7 @@ App::patch('/v1/users/:userId/password')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->param('password', '', fn ($project, $passwordsDictionary) => new PasswordDictionary($passwordsDictionary, enabled: $project->getAttribute('auths', [])['passwordDictionary'] ?? false, allowEmpty: true), 'New user password. Must be at least 8 chars.', false, ['project', 'passwordsDictionary'])
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
@@ -1428,7 +1428,7 @@ App::patch('/v1/users/:userId/email')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->param('email', '', new EmailValidator(allowEmpty: true), 'User email.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
@@ -1539,7 +1539,7 @@ App::patch('/v1/users/:userId/phone')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->param('number', '', new Phone(allowEmpty: true), 'User phone number.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
@@ -1629,7 +1629,7 @@ App::patch('/v1/users/:userId/verification')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->param('emailVerification', false, new Boolean(), 'User email verification status.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
@@ -1667,7 +1667,7 @@ App::patch('/v1/users/:userId/prefs')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->param('prefs', '', new Assoc(), 'Prefs key-value JSON object.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
@@ -1708,10 +1708,10 @@ App::patch('/v1/users/:userId/targets/:targetId')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('targetId', '', new UID(), 'Target ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->param('targetId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Target ID.', false, ['dbForProject'])
|
||||
->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)', true)
|
||||
->param('providerId', '', new UID(), 'Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.', true)
|
||||
->param('providerId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.', true, ['dbForProject'])
|
||||
->param('name', '', new Text(128), 'Target name. Max length: 128 chars. For example: My Awesome App Galaxy S23.', true)
|
||||
->inject('queueForEvents')
|
||||
->inject('response')
|
||||
@@ -1833,7 +1833,7 @@ App::patch('/v1/users/:userId/mfa')
|
||||
]
|
||||
)
|
||||
])
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->param('mfa', null, new Boolean(), 'Enable or disable MFA.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
@@ -1893,7 +1893,7 @@ App::get('/v1/users/:userId/mfa/factors')
|
||||
]
|
||||
)
|
||||
])
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $userId, Response $response, Database $dbForProject) {
|
||||
@@ -1952,7 +1952,7 @@ App::get('/v1/users/:userId/mfa/recovery-codes')
|
||||
]
|
||||
)
|
||||
])
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $userId, Response $response, Database $dbForProject) {
|
||||
@@ -2017,7 +2017,7 @@ App::patch('/v1/users/:userId/mfa/recovery-codes')
|
||||
]
|
||||
)
|
||||
])
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
@@ -2090,7 +2090,7 @@ App::put('/v1/users/:userId/mfa/recovery-codes')
|
||||
public: false,
|
||||
)
|
||||
])
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
@@ -2163,7 +2163,7 @@ App::delete('/v1/users/:userId/mfa/authenticators/:type')
|
||||
contentType: ContentType::NONE
|
||||
)
|
||||
])
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->param('type', null, new WhiteList([Type::TOTP]), 'Type of authenticator.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
@@ -2210,7 +2210,7 @@ App::post('/v1/users/:userId/sessions')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new CustomId(), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'User ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
@@ -2302,7 +2302,7 @@ App::post('/v1/users/:userId/tokens')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->param('length', 6, new Range(4, 128), 'Token length in characters. The default length is 6 characters', true)
|
||||
->param('expire', TOKEN_EXPIRATION_GENERIC, new Range(60, TOKEN_EXPIRATION_LOGIN_LONG), 'Token expiration period in seconds. The default expiration is 15 minutes.', true)
|
||||
->inject('request')
|
||||
@@ -2368,8 +2368,8 @@ App::delete('/v1/users/:userId/sessions/:sessionId')
|
||||
],
|
||||
contentType: ContentType::NONE
|
||||
))
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('sessionId', '', new UID(), 'Session ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->param('sessionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Session ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
@@ -2419,7 +2419,7 @@ App::delete('/v1/users/:userId/sessions')
|
||||
],
|
||||
contentType: ContentType::NONE
|
||||
))
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
@@ -2469,7 +2469,7 @@ App::delete('/v1/users/:userId')
|
||||
],
|
||||
contentType: ContentType::NONE
|
||||
))
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
@@ -2521,8 +2521,8 @@ App::delete('/v1/users/:userId/targets/:targetId')
|
||||
],
|
||||
contentType: ContentType::NONE
|
||||
))
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('targetId', '', new UID(), 'Target ID.')
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->param('targetId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Target ID.', false, ['dbForProject'])
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForDeletes')
|
||||
->inject('response')
|
||||
@@ -2579,7 +2579,7 @@ App::delete('/v1/users/identities/:identityId')
|
||||
],
|
||||
contentType: ContentType::NONE,
|
||||
))
|
||||
->param('identityId', '', new UID(), 'Identity ID.')
|
||||
->param('identityId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Identity ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
@@ -2618,8 +2618,8 @@ App::post('/v1/users/:userId/jwts')
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('userId', '', new UID(), 'User ID.')
|
||||
->param('sessionId', '', new UID(), 'Session ID. Use the string \'recent\' to use the most recent session. Defaults to the most recent session.', true)
|
||||
->param('userId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'User ID.', false, ['dbForProject'])
|
||||
->param('sessionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Session ID. Use the string \'recent\' to use the most recent session. Defaults to the most recent session.', true, ['dbForProject'])
|
||||
->param('duration', 900, new Range(0, 3600), 'Time in seconds before JWT expires. Default duration is 900 seconds, and maximum is 3600 seconds.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
|
||||
@@ -31,7 +31,6 @@ App::get('/v1/mock/tests/general/oauth2')
|
||||
->param('state', '', new Text(1024), 'OAuth2 state.')
|
||||
->inject('response')
|
||||
->action(function (string $client_id, string $redirectURI, string $scope, string $state, Response $response) {
|
||||
|
||||
$response->redirect($redirectURI . '?' . \http_build_query(['code' => 'abcdef', 'state' => $state]));
|
||||
});
|
||||
|
||||
|
||||
@@ -74,6 +74,18 @@ $parseLabel = function (string $label, array $responsePayload, array $requestPar
|
||||
return $label;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get database type prefixed metric
|
||||
* Prefixes the metric with database type if it's not legacy or tablesdb
|
||||
*
|
||||
* @param string $databaseType Database type (e.g., 'documentsdb', 'tablesdb', 'legacy', '')
|
||||
* @param string $metric Base metric constant (e.g., METRIC_DATABASES, METRIC_COLLECTIONS)
|
||||
* @return string Prefixed metric or original metric if no prefix needed
|
||||
*/
|
||||
$getDatabaseTypePrefixedMetric = function (string $databaseType, string $metric): string {
|
||||
return implode('.', array_filter([$databaseType, $metric]));
|
||||
};
|
||||
|
||||
/**
|
||||
* This isolated event handling for `users.*.create` which is based on a `Database::EVENT_DOCUMENT_CREATE` listener may look odd, but it is **intentional**.
|
||||
*
|
||||
@@ -112,7 +124,7 @@ $eventDatabaseListener = function (Document $project, Document $document, Respon
|
||||
}
|
||||
};
|
||||
|
||||
$usageDatabaseListener = function (string $event, Document $document, StatsUsage $queueForStatsUsage) {
|
||||
$usageDatabaseListener = function (string $event, Document $document, StatsUsage $queueForStatsUsage, string $databaseType) use ($getDatabaseTypePrefixedMetric) {
|
||||
$value = 1;
|
||||
|
||||
switch ($event) {
|
||||
@@ -144,7 +156,8 @@ $usageDatabaseListener = function (string $event, Document $document, StatsUsage
|
||||
$queueForStatsUsage->addMetric(METRIC_SESSIONS, $value); //per project
|
||||
break;
|
||||
case $document->getCollection() === 'databases': // databases
|
||||
$queueForStatsUsage->addMetric(METRIC_DATABASES, $value); // per project
|
||||
$metric = $getDatabaseTypePrefixedMetric($databaseType, METRIC_DATABASES);
|
||||
$queueForStatsUsage->addMetric($metric, $value); // per project
|
||||
|
||||
if ($event === Database::EVENT_DOCUMENT_DELETE) {
|
||||
$queueForStatsUsage->addReduce($document);
|
||||
@@ -153,22 +166,29 @@ $usageDatabaseListener = function (string $event, Document $document, StatsUsage
|
||||
case str_starts_with($document->getCollection(), 'database_') && !str_contains($document->getCollection(), 'collection'): //collections
|
||||
$parts = explode('_', $document->getCollection());
|
||||
$databaseInternalId = $parts[1] ?? 0;
|
||||
$collectionMetric = $getDatabaseTypePrefixedMetric($databaseType, METRIC_COLLECTIONS);
|
||||
$databaseIdCollectionMetric = $getDatabaseTypePrefixedMetric($databaseType, METRIC_DATABASE_ID_COLLECTIONS);
|
||||
$queueForStatsUsage
|
||||
->addMetric(METRIC_COLLECTIONS, $value) // per project
|
||||
->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, METRIC_DATABASE_ID_COLLECTIONS), $value);
|
||||
->addMetric($collectionMetric, $value) // per project
|
||||
->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, $databaseIdCollectionMetric), $value);
|
||||
|
||||
if ($event === Database::EVENT_DOCUMENT_DELETE) {
|
||||
$queueForStatsUsage->addReduce($document);
|
||||
}
|
||||
break;
|
||||
// for databases route documents are getting created via getDatabasesDB and stats are maintained in the resources
|
||||
// but keeping it since other routes might created documents still directly via dbForProject
|
||||
case str_starts_with($document->getCollection(), 'database_') && str_contains($document->getCollection(), '_collection_'): //documents
|
||||
$parts = explode('_', $document->getCollection());
|
||||
$databaseInternalId = $parts[1] ?? 0;
|
||||
$collectionInternalId = $parts[3] ?? 0;
|
||||
$documentsMetric = $getDatabaseTypePrefixedMetric($databaseType, METRIC_DOCUMENTS);
|
||||
$databaseIdDocumentsMetric = $getDatabaseTypePrefixedMetric($databaseType, METRIC_DATABASE_ID_DOCUMENTS);
|
||||
$databaseIdCollectionIdDocumentsMetric = $getDatabaseTypePrefixedMetric($databaseType, METRIC_DATABASE_ID_COLLECTION_ID_DOCUMENTS);
|
||||
$queueForStatsUsage
|
||||
->addMetric(METRIC_DOCUMENTS, $value) // per project
|
||||
->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, METRIC_DATABASE_ID_DOCUMENTS), $value) // per database
|
||||
->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$databaseInternalId, $collectionInternalId], METRIC_DATABASE_ID_COLLECTION_ID_DOCUMENTS), $value); // per collection
|
||||
->addMetric($documentsMetric, $value) // per project
|
||||
->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, $databaseIdDocumentsMetric), $value) // per database
|
||||
->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$databaseInternalId, $collectionInternalId], $databaseIdCollectionIdDocumentsMetric), $value); // per collection
|
||||
break;
|
||||
case $document->getCollection() === 'buckets': //buckets
|
||||
$queueForStatsUsage
|
||||
@@ -512,6 +532,11 @@ App::init()
|
||||
->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Publisher $publisher, Publisher $publisherFunctions, Publisher $publisherWebhooks, Event $queueForEvents, Messaging $queueForMessaging, Audit $queueForAudits, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Mail $queueForMails, Migration $queueForMigrations, Database $dbForProject, callable $timelimit, Document $resourceToken, string $mode, ?Key $apiKey, array $plan, Document $devKey, Telemetry $telemetry, array $platform) use ($usageDatabaseListener, $eventDatabaseListener) {
|
||||
|
||||
$route = $utopia->getRoute();
|
||||
$path = $route->getMatchedPath();
|
||||
$databaseType = match (true) {
|
||||
str_contains($path, '/documentsdb') => DATABASE_TYPE_DOCUMENTSDB,
|
||||
default => '',
|
||||
};
|
||||
|
||||
if (
|
||||
array_key_exists('rest', $project->getAttribute('apis', []))
|
||||
@@ -524,6 +549,7 @@ App::init()
|
||||
/*
|
||||
* Abuse Check
|
||||
*/
|
||||
|
||||
$abuseKeyLabel = $route->getLabel('abuse-key', 'url:{url},ip:{ip}');
|
||||
$timeLimitArray = [];
|
||||
|
||||
@@ -559,6 +585,7 @@ App::init()
|
||||
|
||||
$abuse = new Abuse($timeLimit);
|
||||
$remaining = $timeLimit->remaining();
|
||||
|
||||
$limit = $timeLimit->limit();
|
||||
$time = $timeLimit->time() + $route->getLabel('abuse-time', 3600);
|
||||
|
||||
@@ -636,12 +663,14 @@ App::init()
|
||||
$queueForWebhooks = new Webhook($publisherWebhooks);
|
||||
$queueForRealtime = new Realtime();
|
||||
|
||||
// to get consumed in the stats worker without calling to database
|
||||
$queueForStatsUsage->setContext('database', new Document(['type' => $databaseType]));
|
||||
$dbForProject
|
||||
->on(Database::EVENT_DOCUMENT_CREATE, 'calculate-usage', fn ($event, $document) => $usageDatabaseListener($event, $document, $queueForStatsUsage))
|
||||
->on(Database::EVENT_DOCUMENT_DELETE, 'calculate-usage', fn ($event, $document) => $usageDatabaseListener($event, $document, $queueForStatsUsage))
|
||||
->on(Database::EVENT_DOCUMENTS_CREATE, 'calculate-usage', fn ($event, $document) => $usageDatabaseListener($event, $document, $queueForStatsUsage))
|
||||
->on(Database::EVENT_DOCUMENTS_DELETE, 'calculate-usage', fn ($event, $document) => $usageDatabaseListener($event, $document, $queueForStatsUsage))
|
||||
->on(Database::EVENT_DOCUMENTS_UPSERT, 'calculate-usage', fn ($event, $document) => $usageDatabaseListener($event, $document, $queueForStatsUsage))
|
||||
->on(Database::EVENT_DOCUMENT_CREATE, 'calculate-usage', fn ($event, $document) => $usageDatabaseListener($event, $document, $queueForStatsUsage, $databaseType))
|
||||
->on(Database::EVENT_DOCUMENT_DELETE, 'calculate-usage', fn ($event, $document) => $usageDatabaseListener($event, $document, $queueForStatsUsage, $databaseType))
|
||||
->on(Database::EVENT_DOCUMENTS_CREATE, 'calculate-usage', fn ($event, $document) => $usageDatabaseListener($event, $document, $queueForStatsUsage, $databaseType))
|
||||
->on(Database::EVENT_DOCUMENTS_DELETE, 'calculate-usage', fn ($event, $document) => $usageDatabaseListener($event, $document, $queueForStatsUsage, $databaseType))
|
||||
->on(Database::EVENT_DOCUMENTS_UPSERT, 'calculate-usage', fn ($event, $document) => $usageDatabaseListener($event, $document, $queueForStatsUsage, $databaseType))
|
||||
->on(Database::EVENT_DOCUMENT_CREATE, 'create-trigger-events', fn ($event, $document) => $eventDatabaseListener(
|
||||
$project,
|
||||
$document,
|
||||
|
||||
+45
-16
@@ -176,8 +176,8 @@ include __DIR__ . '/controllers/general.php';
|
||||
|
||||
function createDatabase(App $app, string $resourceKey, string $dbName, array $collections, mixed $pools, callable $extraSetup = null): void
|
||||
{
|
||||
$max = 10;
|
||||
$sleep = 1;
|
||||
$max = 15;
|
||||
$sleep = 2;
|
||||
$attempts = 0;
|
||||
|
||||
while (true) {
|
||||
@@ -187,7 +187,7 @@ function createDatabase(App $app, string $resourceKey, string $dbName, array $co
|
||||
/* @var $database Database */
|
||||
$database = is_callable($resource) ? $resource() : $resource;
|
||||
break; // exit loop on success
|
||||
} catch (\Exception $e) {
|
||||
} catch (\Throwable $e) {
|
||||
Console::warning(" └── Database not ready. Retrying connection ({$attempts})...");
|
||||
if ($attempts >= $max) {
|
||||
throw new \Exception(' └── Failed to connect to database: ' . $e->getMessage());
|
||||
@@ -198,12 +198,26 @@ function createDatabase(App $app, string $resourceKey, string $dbName, array $co
|
||||
|
||||
Console::success("[Setup] - $dbName database init started...");
|
||||
|
||||
// Attempt to create the database
|
||||
try {
|
||||
Console::info(" └── Creating database: $dbName...");
|
||||
$database->create();
|
||||
} catch (\Exception $e) {
|
||||
Console::info(" └── Skip: metadata table already exists");
|
||||
$attempts = 0;
|
||||
while (true) {
|
||||
try {
|
||||
$attempts++;
|
||||
Console::info(" └── Creating database: $dbName...");
|
||||
$database->create();
|
||||
break; // exit loop on success
|
||||
} catch (\Exception $e) {
|
||||
if ($e instanceof DuplicateException) {
|
||||
Console::info(" └── Skip: metadata table already exists");
|
||||
break;
|
||||
}
|
||||
|
||||
Console::warning(" └── Database create failed. Retrying ({$attempts})...");
|
||||
if ($attempts >= $max) {
|
||||
throw new \Exception(' └── Failed to create database: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
\sleep($sleep);
|
||||
}
|
||||
}
|
||||
|
||||
// Process collections
|
||||
@@ -385,11 +399,25 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg
|
||||
->setTenant(null)
|
||||
->setNamespace(System::getEnv('_APP_DATABASE_SHARED_NAMESPACE', ''));
|
||||
|
||||
try {
|
||||
Console::success('[Setup] - Creating project database: ' . $hostname . '...');
|
||||
$dbForProject->create();
|
||||
} catch (DuplicateException) {
|
||||
Console::success('[Setup] - Skip: metadata table already exists');
|
||||
$max = 15;
|
||||
$sleep = 2;
|
||||
$attempts = 0;
|
||||
while (true) {
|
||||
try {
|
||||
$attempts++;
|
||||
Console::success('[Setup] - Creating project database: ' . $hostname . '...');
|
||||
$dbForProject->create();
|
||||
break; // exit loop on success
|
||||
} catch (DuplicateException) {
|
||||
Console::success('[Setup] - Skip: metadata table already exists');
|
||||
break;
|
||||
} catch (\Throwable $e) {
|
||||
Console::warning(" └── Project database create failed. Retrying ({$attempts})...");
|
||||
if ($attempts >= $max) {
|
||||
throw new \Exception(' └── Failed to create project database: ' . $e->getMessage());
|
||||
}
|
||||
sleep($sleep);
|
||||
}
|
||||
}
|
||||
|
||||
if ($dbForProject->getCollection(AuditAdapterSQL::COLLECTION)->isEmpty()) {
|
||||
@@ -432,6 +460,7 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg
|
||||
});
|
||||
|
||||
$http->on(Constant::EVENT_REQUEST, function (SwooleRequest $swooleRequest, SwooleResponse $swooleResponse) use ($register) {
|
||||
|
||||
App::setResource('swooleRequest', fn () => $swooleRequest);
|
||||
App::setResource('swooleResponse', fn () => $swooleResponse);
|
||||
|
||||
@@ -572,14 +601,14 @@ $http->on(Constant::EVENT_TASK, function () use ($register, $domains) {
|
||||
if ($latestDocument !== null) {
|
||||
$queries[] = Query::cursorAfter($latestDocument);
|
||||
}
|
||||
if ($lastSyncUpdate != null) {
|
||||
if ($lastSyncUpdate !== null) {
|
||||
$queries[] = Query::greaterThanEqual('$updatedAt', $lastSyncUpdate);
|
||||
}
|
||||
$results = [];
|
||||
try {
|
||||
$results = Authorization::skip(fn () => $dbForPlatform->find('rules', $queries));
|
||||
} catch (Throwable $th) {
|
||||
Console::error($th->getMessage());
|
||||
Console::error('rules ' . $th->getMessage());
|
||||
}
|
||||
|
||||
$sum = count($results);
|
||||
|
||||
@@ -275,6 +275,22 @@ const METRIC_DATABASES_OPERATIONS_READS = 'databases.operations.reads';
|
||||
const METRIC_DATABASE_ID_OPERATIONS_READS = '{databaseInternalId}.databases.operations.reads';
|
||||
const METRIC_DATABASES_OPERATIONS_WRITES = 'databases.operations.writes';
|
||||
const METRIC_DATABASE_ID_OPERATIONS_WRITES = '{databaseInternalId}.databases.operations.writes';
|
||||
|
||||
// documentsdb
|
||||
const METRIC_DATABASES_DOCUMENTSDB = 'documentsdb.databases';
|
||||
const METRIC_COLLECTIONS_DOCUMENTSDB = 'documentsdb.collections';
|
||||
const METRIC_DATABASES_STORAGE_DOCUMENTSDB = 'documentsdb.databases.storage';
|
||||
const METRIC_DATABASE_ID_COLLECTIONS_DOCUMENTSDB = 'documentsdb.{databaseInternalId}.collections';
|
||||
const METRIC_DATABASE_ID_STORAGE_DOCUMENTSDB = 'documentsdb.{databaseInternalId}.databases.storage';
|
||||
const METRIC_DOCUMENTS_DOCUMENTSDB = 'documentsdb.documents';
|
||||
const METRIC_DATABASE_ID_DOCUMENTS_DOCUMENTSDB = 'documentsdb.{databaseInternalId}.documents';
|
||||
const METRIC_DATABASE_ID_COLLECTION_ID_DOCUMENTS_DOCUMENTSDB = 'documentsdb.{databaseInternalId}.{collectionInternalId}.documents';
|
||||
const METRIC_DATABASE_ID_COLLECTION_ID_STORAGE_DOCUMENTSDB = 'documentsdb.{databaseInternalId}.{collectionInternalId}.databases.storage';
|
||||
const METRIC_DATABASES_OPERATIONS_READS_DOCUMENTSDB = 'documentsdb.databases.operations.reads';
|
||||
const METRIC_DATABASE_ID_OPERATIONS_READS_DOCUMENTSDB = 'documentsdb.{databaseInternalId}.databases.operations.reads';
|
||||
const METRIC_DATABASES_OPERATIONS_WRITES_DOCUMENTSDB = 'documentsdb.databases.operations.writes';
|
||||
const METRIC_DATABASE_ID_OPERATIONS_WRITES_DOCUMENTSDB = 'documentsdb.{databaseInternalId}.databases.operations.writes';
|
||||
|
||||
const METRIC_BUCKETS = 'buckets';
|
||||
const METRIC_FILES = 'files';
|
||||
const METRIC_FILES_STORAGE = 'files.storage';
|
||||
@@ -374,3 +390,11 @@ const SCHEDULE_RESOURCE_TYPE_MESSAGE = 'message';
|
||||
|
||||
/** Preview cookie */
|
||||
const COOKIE_NAME_PREVIEW = 'a_jwt_console';
|
||||
|
||||
// Database types
|
||||
const DATABASE_TYPE_LEGACY = 'legacy';
|
||||
const DATABASE_TYPE_TABLESDB = 'tablesdb';
|
||||
const DATABASE_TYPE_DOCUMENTSDB = 'documentsdb';
|
||||
|
||||
// CSV import/export allowed database types
|
||||
const CSV_ALLOWED_DATABASE_TYPES = [DATABASE_TYPE_LEGACY, DATABASE_TYPE_LEGACY];
|
||||
|
||||
@@ -73,7 +73,7 @@ Database::addFilter(
|
||||
$attributes = $database->find('attributes', [
|
||||
Query::equal('collectionInternalId', [$document->getSequence()]),
|
||||
Query::equal('databaseInternalId', [$document->getAttribute('databaseInternalId')]),
|
||||
Query::limit($database->getLimitForAttributes()),
|
||||
Query::limit(PHP_INT_MAX),
|
||||
]);
|
||||
|
||||
foreach ($attributes as $attribute) {
|
||||
|
||||
@@ -127,6 +127,8 @@ use Appwrite\Utopia\Response\Model\UsageBuckets;
|
||||
use Appwrite\Utopia\Response\Model\UsageCollection;
|
||||
use Appwrite\Utopia\Response\Model\UsageDatabase;
|
||||
use Appwrite\Utopia\Response\Model\UsageDatabases;
|
||||
use Appwrite\Utopia\Response\Model\UsageDocumentsDB;
|
||||
use Appwrite\Utopia\Response\Model\UsageDocumentsDBs;
|
||||
use Appwrite\Utopia\Response\Model\UsageFunction;
|
||||
use Appwrite\Utopia\Response\Model\UsageFunctions;
|
||||
use Appwrite\Utopia\Response\Model\UsageProject;
|
||||
@@ -310,6 +312,9 @@ Response::setModel(new Metric());
|
||||
Response::setModel(new MetricBreakdown());
|
||||
Response::setModel(new UsageDatabases());
|
||||
Response::setModel(new UsageDatabase());
|
||||
Response::setModel(new UsageDocumentsDB());
|
||||
Response::setModel(new UsageDocumentsDBs());
|
||||
|
||||
Response::setModel(new UsageTable());
|
||||
Response::setModel(new UsageCollection());
|
||||
Response::setModel(new UsageUsers());
|
||||
|
||||
+58
-13
@@ -13,6 +13,7 @@ use Utopia\Cache\Adapter\Redis as RedisCache;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Adapter\MariaDB;
|
||||
use Utopia\Database\Adapter\Mongo;
|
||||
use Utopia\Database\Adapter\MySQL;
|
||||
use Utopia\Database\Adapter\SQL;
|
||||
use Utopia\Database\PDO;
|
||||
@@ -23,6 +24,7 @@ use Utopia\Logger\Adapter\LogOwl;
|
||||
use Utopia\Logger\Adapter\Raygun;
|
||||
use Utopia\Logger\Adapter\Sentry;
|
||||
use Utopia\Logger\Logger;
|
||||
use Utopia\Mongo\Client as MongoClient;
|
||||
use Utopia\Pools\Group;
|
||||
use Utopia\Pools\Pool;
|
||||
use Utopia\Queue;
|
||||
@@ -147,9 +149,17 @@ $register->set('pools', function () {
|
||||
$group = new Group();
|
||||
|
||||
$fallbackForDB = 'db_main=' . AppwriteURL::unparse([
|
||||
'scheme' => 'mariadb',
|
||||
'host' => System::getEnv('_APP_DB_HOST', 'mariadb'),
|
||||
'port' => System::getEnv('_APP_DB_PORT', '3306'),
|
||||
'scheme' => System::getEnv('_APP_DB_ADAPTER', 'mongodb'),
|
||||
'host' => System::getEnv('_APP_DB_HOST', 'mongodb'),
|
||||
'port' => System::getEnv('_APP_DB_PORT', '27017'),
|
||||
'user' => System::getEnv('_APP_DB_USER', ''),
|
||||
'pass' => System::getEnv('_APP_DB_PASS', ''),
|
||||
'path' => System::getEnv('_APP_DB_SCHEMA', ''),
|
||||
]);
|
||||
$fallbackForDocumentsDB = 'db_main=' . AppwriteURL::unparse([
|
||||
'scheme' => System::getEnv('_APP_DB_ADAPTER_DOCUMENTSDB', 'mongodb'),
|
||||
'host' => System::getEnv('_APP_DB_HOST_DOCUMENTSDB', 'mongodb'),
|
||||
'port' => System::getEnv('_APP_DB_PORT_DOCUMENTSDB', '27017'),
|
||||
'user' => System::getEnv('_APP_DB_USER', ''),
|
||||
'pass' => System::getEnv('_APP_DB_PASS', ''),
|
||||
'path' => System::getEnv('_APP_DB_SCHEMA', ''),
|
||||
@@ -167,19 +177,25 @@ $register->set('pools', function () {
|
||||
'type' => 'database',
|
||||
'dsns' => $fallbackForDB,
|
||||
'multiple' => false,
|
||||
'schemes' => ['mariadb', 'mysql'],
|
||||
'schemes' => ['mongodb','mariadb', 'mysql'],
|
||||
],
|
||||
'database' => [
|
||||
'type' => 'database',
|
||||
'dsns' => $fallbackForDB,
|
||||
'multiple' => true,
|
||||
'schemes' => ['mariadb', 'mysql'],
|
||||
'schemes' => ['mongodb','mariadb', 'mysql'],
|
||||
],
|
||||
'documentsdb' => [
|
||||
'type' => 'database',
|
||||
'dsns' => System::getEnv('_APP_CONNECTIONS_DATABASE_DOCUMENTSDB', $fallbackForDocumentsDB),
|
||||
'multiple' => true,
|
||||
'schemes' => ['mongodb'],
|
||||
],
|
||||
'logs' => [
|
||||
'type' => 'database',
|
||||
'dsns' => System::getEnv('_APP_CONNECTIONS_DB_LOGS', $fallbackForDB),
|
||||
'multiple' => false,
|
||||
'schemes' => ['mariadb', 'mysql'],
|
||||
'schemes' => ['mongodb','mariadb', 'mysql'],
|
||||
],
|
||||
'publisher' => [
|
||||
'type' => 'publisher',
|
||||
@@ -259,6 +275,7 @@ $register->set('pools', function () {
|
||||
*
|
||||
* Resource assignment to an adapter will happen below.
|
||||
*/
|
||||
|
||||
$resource = match ($dsnScheme) {
|
||||
'mysql',
|
||||
'mariadb' => function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase) {
|
||||
@@ -272,6 +289,16 @@ $register->set('pools', function () {
|
||||
]);
|
||||
});
|
||||
},
|
||||
'mongodb' => function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase, $dsn) {
|
||||
try {
|
||||
$mongo = new MongoClient($dsnDatabase, $dsnHost, (int)$dsnPort, $dsnUser, $dsnPass, false);
|
||||
@$mongo->connect();
|
||||
|
||||
return $mongo;
|
||||
} catch (\Throwable $e) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, "MongoDB connection failed: " . $e->getMessage());
|
||||
}
|
||||
},
|
||||
'redis' => function () use ($dsnHost, $dsnPort, $dsnPass) {
|
||||
$redis = new \Redis();
|
||||
@$redis->pconnect($dsnHost, (int)$dsnPort);
|
||||
@@ -285,17 +312,21 @@ $register->set('pools', function () {
|
||||
default => throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Invalid scheme'),
|
||||
};
|
||||
|
||||
$pool = new Pool($name, $poolSize, function () use ($type, $resource, $dsn) {
|
||||
$pool = new Pool($name, $poolSize, function () use ($type, $resource, $dsn, $key) {
|
||||
// Get Adapter
|
||||
switch ($type) {
|
||||
case 'database':
|
||||
$adapter = match ($dsn->getScheme()) {
|
||||
'mariadb' => new MariaDB($resource()),
|
||||
'mysql' => new MySQL($resource()),
|
||||
'mongodb' => new Mongo($resource()),
|
||||
default => null
|
||||
};
|
||||
|
||||
$adapter->setDatabase($dsn->getPath());
|
||||
if ($key === 'documentsdb') {
|
||||
$adapter->setSupportForAttributes(false);
|
||||
}
|
||||
return $adapter;
|
||||
case 'pubsub':
|
||||
return match ($dsn->getScheme()) {
|
||||
@@ -334,13 +365,27 @@ $register->set('db', function () {
|
||||
$dbUser = System::getEnv('_APP_DB_USER', '');
|
||||
$dbPass = System::getEnv('_APP_DB_PASS', '');
|
||||
$dbScheme = System::getEnv('_APP_DB_SCHEMA', '');
|
||||
$dbAdapter = System::getEnv('_APP_DB_ADAPTER', 'mongodb');
|
||||
$dsn = '';
|
||||
|
||||
return new PDO(
|
||||
"mysql:host={$dbHost};port={$dbPort};dbname={$dbScheme};charset=utf8mb4",
|
||||
$dbUser,
|
||||
$dbPass,
|
||||
SQL::getPDOAttributes()
|
||||
);
|
||||
switch ($dbAdapter) {
|
||||
case 'mongodb':
|
||||
|
||||
try {
|
||||
$mongo = new MongoClient($dbScheme, $dbHost, (int)$dbPort, $dbUser, $dbPass, false);
|
||||
@$mongo->connect();
|
||||
|
||||
return $mongo;
|
||||
} catch (\Throwable $e) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, "MongoDB connection failed: " . $e->getMessage());
|
||||
}
|
||||
|
||||
case 'mysql':
|
||||
case 'mariadb':
|
||||
default:
|
||||
$dsn = "mysql:host={$dbHost};port={$dbPort};dbname={$dbScheme};charset=utf8mb4";
|
||||
return new PDO($dsn, $dbUser, $dbPass, SQL::getPDOAttributes());
|
||||
}
|
||||
});
|
||||
|
||||
$register->set('smtp', function () {
|
||||
|
||||
+165
-3
@@ -568,6 +568,135 @@ App::setResource('dbForPlatform', function (Group $pools, Cache $cache) {
|
||||
return $database;
|
||||
}, ['pools', 'cache']);
|
||||
|
||||
App::setResource('getDatabasesDB', function (Group $pools, Cache $cache, Document $project, Request $request, StatsUsage $queueForStatsUsage) {
|
||||
|
||||
return function (Document $database) use ($pools, $cache, $project, $request, $queueForStatsUsage): Database {
|
||||
$databaseDSN = $database->getAttribute('database', '');
|
||||
$databaseType = $database->getAttribute('type', '');
|
||||
try {
|
||||
$databaseDSN = new DSN($databaseDSN);
|
||||
} catch (\InvalidArgumentException) {
|
||||
// for old databases migrated through patch script
|
||||
// databaseDSN determines the adapter
|
||||
$databaseDSN = new DSN('mysql://'.$databaseDSN);
|
||||
}
|
||||
try {
|
||||
$dsn = new DSN($project->getAttribute('database'));
|
||||
} catch (\InvalidArgumentException) {
|
||||
// TODO: Temporary until all projects are using shared tables
|
||||
$dsn = new DSN('mysql://' . $project->getAttribute('database'));
|
||||
}
|
||||
|
||||
$pool = $pools->get($databaseDSN->getHost());
|
||||
|
||||
$adapter = new DatabasePool($pool);
|
||||
$database = new Database($adapter, $cache);
|
||||
$sharedTables = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES', ''));
|
||||
|
||||
$database
|
||||
->setMetadata('host', \gethostname())
|
||||
->setMetadata('project', $project->getId())
|
||||
->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_API)
|
||||
->setMaxQueryValues(APP_DATABASE_QUERY_MAX_VALUES);
|
||||
|
||||
if (\in_array($dsn->getHost(), $sharedTables)) {
|
||||
$database
|
||||
->setSharedTables(true)
|
||||
->setTenant((int)$project->getSequence())
|
||||
->setNamespace($dsn->getParam('namespace'));
|
||||
} else {
|
||||
$database
|
||||
->setSharedTables(false)
|
||||
->setTenant(null)
|
||||
->setNamespace('_' . $project->getSequence());
|
||||
}
|
||||
$timeout = \intval($request->getHeader('x-appwrite-timeout'));
|
||||
if (!empty($timeout) && App::isDevelopment()) {
|
||||
$database->setTimeout($timeout);
|
||||
}
|
||||
|
||||
// Register database event listeners for usage stats collection
|
||||
$documentsMetric = METRIC_DOCUMENTS;
|
||||
$databaseIdDocumentsMetric = METRIC_DATABASE_ID_DOCUMENTS;
|
||||
$databaseIdCollectionIdDocumentsMetric = METRIC_DATABASE_ID_COLLECTION_ID_DOCUMENTS;
|
||||
if ($databaseType !== DATABASE_TYPE_LEGACY && $databaseType !== DATABASE_TYPE_TABLESDB) {
|
||||
$documentsMetric = $databaseType. '.' .$documentsMetric;
|
||||
$databaseIdDocumentsMetric = $databaseType. '.' .$databaseIdDocumentsMetric;
|
||||
$databaseIdCollectionIdDocumentsMetric = $databaseType . '.' .$databaseIdCollectionIdDocumentsMetric;
|
||||
}
|
||||
$database
|
||||
->on(Database::EVENT_DOCUMENT_CREATE, 'calculate-usage', function ($event, $document) use ($queueForStatsUsage, $documentsMetric, $databaseIdDocumentsMetric, $databaseIdCollectionIdDocumentsMetric) {
|
||||
$value = 1;
|
||||
|
||||
if (str_starts_with($document->getCollection(), 'database_') && str_contains($document->getCollection(), '_collection_')) {
|
||||
$parts = explode('_', $document->getCollection());
|
||||
$databaseInternalId = $parts[1] ?? 0;
|
||||
$collectionInternalId = $parts[3] ?? 0;
|
||||
$queueForStatsUsage
|
||||
->addMetric($documentsMetric, $value) // per project
|
||||
->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, $databaseIdDocumentsMetric), $value) // per database
|
||||
->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$databaseInternalId, $collectionInternalId], $databaseIdCollectionIdDocumentsMetric), $value); // per collection
|
||||
}
|
||||
})
|
||||
->on(Database::EVENT_DOCUMENT_DELETE, 'calculate-usage', function ($event, $document) use ($queueForStatsUsage, $documentsMetric, $databaseIdDocumentsMetric, $databaseIdCollectionIdDocumentsMetric) {
|
||||
$value = -1;
|
||||
|
||||
if (str_starts_with($document->getCollection(), 'database_') && str_contains($document->getCollection(), '_collection_')) {
|
||||
$parts = explode('_', $document->getCollection());
|
||||
$databaseInternalId = $parts[1] ?? 0;
|
||||
$collectionInternalId = $parts[3] ?? 0;
|
||||
$queueForStatsUsage
|
||||
->addMetric($documentsMetric, $value) // per project
|
||||
->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, $databaseIdDocumentsMetric), $value) // per database
|
||||
->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$databaseInternalId, $collectionInternalId], $databaseIdCollectionIdDocumentsMetric), $value); // per collection
|
||||
}
|
||||
})
|
||||
->on(Database::EVENT_DOCUMENTS_CREATE, 'calculate-usage', function ($event, $document) use ($queueForStatsUsage, $documentsMetric, $databaseIdDocumentsMetric, $databaseIdCollectionIdDocumentsMetric) {
|
||||
$value = $document->getAttribute('modified', 0);
|
||||
|
||||
if (str_starts_with($document->getCollection(), 'database_') && str_contains($document->getCollection(), '_collection_')) {
|
||||
$parts = explode('_', $document->getCollection());
|
||||
$databaseInternalId = $parts[1] ?? 0;
|
||||
$collectionInternalId = $parts[3] ?? 0;
|
||||
$queueForStatsUsage
|
||||
->addMetric($documentsMetric, $value) // per project
|
||||
->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, $databaseIdDocumentsMetric), $value) // per database
|
||||
->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$databaseInternalId, $collectionInternalId], $databaseIdCollectionIdDocumentsMetric), $value); // per collection
|
||||
}
|
||||
})
|
||||
->on(Database::EVENT_DOCUMENTS_DELETE, 'calculate-usage', function ($event, $document) use ($queueForStatsUsage, $documentsMetric, $databaseIdDocumentsMetric, $databaseIdCollectionIdDocumentsMetric) {
|
||||
$value = -1 * $document->getAttribute('modified', 0);
|
||||
|
||||
if (str_starts_with($document->getCollection(), 'database_') && str_contains($document->getCollection(), '_collection_')) {
|
||||
$parts = explode('_', $document->getCollection());
|
||||
$databaseInternalId = $parts[1] ?? 0;
|
||||
$collectionInternalId = $parts[3] ?? 0;
|
||||
$queueForStatsUsage
|
||||
->addMetric($documentsMetric, $value) // per project
|
||||
->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, $databaseIdDocumentsMetric), $value) // per database
|
||||
->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$databaseInternalId, $collectionInternalId], $databaseIdCollectionIdDocumentsMetric), $value); // per collection
|
||||
}
|
||||
})
|
||||
->on(Database::EVENT_DOCUMENTS_UPSERT, 'calculate-usage', function ($event, $document) use ($queueForStatsUsage, $documentsMetric, $databaseIdDocumentsMetric, $databaseIdCollectionIdDocumentsMetric) {
|
||||
$value = $document->getAttribute('created', 0);
|
||||
|
||||
if (str_starts_with($document->getCollection(), 'database_') && str_contains($document->getCollection(), '_collection_')) {
|
||||
$parts = explode('_', $document->getCollection());
|
||||
$databaseInternalId = $parts[1] ?? 0;
|
||||
$collectionInternalId = $parts[3] ?? 0;
|
||||
$queueForStatsUsage
|
||||
->addMetric($documentsMetric, $value) // per project
|
||||
->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, $databaseIdDocumentsMetric), $value) // per database
|
||||
->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$databaseInternalId, $collectionInternalId], $databaseIdCollectionIdDocumentsMetric), $value); // per collection
|
||||
}
|
||||
});
|
||||
|
||||
return $database;
|
||||
};
|
||||
|
||||
}, ['pools','cache','project','request','queueForStatsUsage']);
|
||||
|
||||
|
||||
App::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform, $cache) {
|
||||
$databases = [];
|
||||
|
||||
@@ -1026,6 +1155,8 @@ App::setResource('team', function (Document $project, Database $dbForPlatform, A
|
||||
}
|
||||
}
|
||||
|
||||
// if teamInternalId is empty, return an empty document
|
||||
|
||||
if (empty($teamInternalId)) {
|
||||
return new Document([]);
|
||||
}
|
||||
@@ -1139,6 +1270,37 @@ App::setResource('resourceToken', function ($project, $dbForProject, $request) {
|
||||
return new Document([]);
|
||||
}, ['project', 'dbForProject', 'request']);
|
||||
|
||||
App::setResource('transactionState', function (Database $dbForProject) {
|
||||
return new TransactionState($dbForProject);
|
||||
}, ['dbForProject']);
|
||||
App::setResource('httpReferrer', function (Request $request): string {
|
||||
$referrer = $request->getReferer();
|
||||
return $referrer;
|
||||
}, ['request']);
|
||||
|
||||
App::setResource('httpReferrerSafe', function (Request $request, string $httpReferrer, array $platforms, Database $dbForPlatform, Document $project, App $utopia): string {
|
||||
$origin = \parse_url($request->getOrigin($httpReferrer), PHP_URL_HOST);
|
||||
$protocol = \parse_url($request->getOrigin($httpReferrer), PHP_URL_SCHEME);
|
||||
$port = \parse_url($request->getOrigin($httpReferrer), PHP_URL_PORT);
|
||||
$referrer = (!empty($protocol) ? $protocol : $request->getProtocol()) . '://' . $origin . (!empty($port) ? ':' . $port : '');
|
||||
|
||||
// Safe if route is publicly accessible
|
||||
$route = $utopia->getRoute();
|
||||
if ($route->getLabel('origin', false)) {
|
||||
return $referrer;
|
||||
}
|
||||
|
||||
// Safe if added as web platform
|
||||
$originValidator = new Origin($platforms);
|
||||
if ($originValidator->isValid($request->getOrigin($httpReferrer))) {
|
||||
return $referrer;
|
||||
}
|
||||
|
||||
// Unsafe; Localhost is always safe for ease of local development
|
||||
$origin = 'localhost';
|
||||
$protocol = \parse_url($request->getOrigin($httpReferrer), PHP_URL_SCHEME);
|
||||
$port = \parse_url($request->getOrigin($httpReferrer), PHP_URL_PORT);
|
||||
$referrer = (!empty($protocol) ? $protocol : $request->getProtocol()) . '://' . $origin . (!empty($port) ? ':' . $port : '');
|
||||
return $referrer;
|
||||
}, ['request', 'httpReferrer', 'platforms', 'dbForPlatform', 'project', 'utopia']);
|
||||
|
||||
App::setResource('transactionState', function (Database $dbForProject, callable $getDatabasesDB) {
|
||||
return new TransactionState($dbForProject, $getDatabasesDB);
|
||||
}, ['dbForProject', 'getDatabasesDB']);
|
||||
|
||||
@@ -11,6 +11,7 @@ $httpsPort = $this->getParam('httpsPort', '');
|
||||
$version = $this->getParam('version', '');
|
||||
$organization = $this->getParam('organization', '');
|
||||
$image = $this->getParam('image', '');
|
||||
$dbService = $this->getParam('database');
|
||||
$enableAssistant = $this->getParam('enableAssistant', false);
|
||||
?>services:
|
||||
traefik:
|
||||
@@ -70,7 +71,7 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- appwrite-sites:/storage/sites:rw
|
||||
- appwrite-builds:/storage/builds:rw
|
||||
depends_on:
|
||||
- mariadb
|
||||
- <?= $dbService . "\n" ?>
|
||||
- redis
|
||||
# - clamav
|
||||
environment:
|
||||
@@ -103,6 +104,7 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -222,7 +224,7 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- mariadb
|
||||
- <?= $dbService . "\n" ?>
|
||||
- redis
|
||||
environment:
|
||||
- _APP_ENV
|
||||
@@ -234,6 +236,7 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -252,7 +255,7 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
- <?= $dbService . "\n" ?>
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
@@ -261,6 +264,7 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -278,13 +282,14 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
- <?= $dbService . "\n" ?>
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_EMAIL_SECURITY
|
||||
- _APP_SYSTEM_SECURITY_EMAIL_ADDRESS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -306,7 +311,7 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
- <?= $dbService . "\n" ?>
|
||||
volumes:
|
||||
- appwrite-uploads:/storage/uploads:rw
|
||||
- appwrite-cache:/storage/cache:rw
|
||||
@@ -322,6 +327,7 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -369,7 +375,7 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
- <?= $dbService . "\n" ?>
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
@@ -378,6 +384,7 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -395,7 +402,7 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
- <?= $dbService . "\n" ?>
|
||||
volumes:
|
||||
- appwrite-functions:/storage/functions:rw
|
||||
- appwrite-sites:/storage/sites:rw
|
||||
@@ -411,6 +418,7 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -463,7 +471,7 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
- <?= $dbService . "\n" ?>
|
||||
volumes:
|
||||
- appwrite-config:/storage/config:rw
|
||||
- appwrite-certificates:/storage/certificates:rw
|
||||
@@ -483,6 +491,7 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -500,7 +509,7 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
- <?= $dbService . "\n" ?>
|
||||
- openruntimes-executor
|
||||
environment:
|
||||
- _APP_ENV
|
||||
@@ -512,6 +521,7 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -545,6 +555,7 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_SYSTEM_EMAIL_NAME
|
||||
- _APP_SYSTEM_EMAIL_ADDRESS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -583,6 +594,7 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -625,7 +637,7 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
volumes:
|
||||
- appwrite-imports:/storage/imports:rw
|
||||
depends_on:
|
||||
- mariadb
|
||||
- <?= $dbService . "\n" ?>
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
@@ -641,6 +653,7 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -675,6 +688,7 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -699,11 +713,12 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
- <?= $dbService . "\n" ?>
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -728,11 +743,12 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
- <?= $dbService . "\n" ?>
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -756,11 +772,12 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
- <?= $dbService . "\n" ?>
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -783,7 +800,7 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- mariadb
|
||||
- <?= $dbService . "\n" ?>
|
||||
- redis
|
||||
environment:
|
||||
- _APP_ENV
|
||||
@@ -793,6 +810,7 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -808,7 +826,7 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- mariadb
|
||||
- <?= $dbService . "\n" ?>
|
||||
- redis
|
||||
environment:
|
||||
- _APP_ENV
|
||||
@@ -818,6 +836,7 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -833,7 +852,7 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- mariadb
|
||||
- <?= $dbService . "\n" ?>
|
||||
- redis
|
||||
environment:
|
||||
- _APP_ENV
|
||||
@@ -843,6 +862,7 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -921,22 +941,63 @@ $enableAssistant = $this->getParam('enableAssistant', false);
|
||||
- OPR_EXECUTOR_STORAGE_WASABI_REGION=$_APP_STORAGE_WASABI_REGION
|
||||
- OPR_EXECUTOR_STORAGE_WASABI_BUCKET=$_APP_STORAGE_WASABI_BUCKET
|
||||
|
||||
mariadb:
|
||||
image: mariadb:10.11 # fix issues when upgrading using: mysql_upgrade -u root -p
|
||||
container_name: appwrite-mariadb
|
||||
<?php if ($dbService === 'mariadb'): ?>
|
||||
|
||||
mariadb:
|
||||
image: mariadb:10.11
|
||||
container_name: appwrite-mariadb
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- appwrite-mariadb:/var/lib/mysql:rw
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=${_APP_DB_ROOT_PASS}
|
||||
- MYSQL_DATABASE=${_APP_DB_SCHEMA}
|
||||
- MYSQL_USER=${_APP_DB_USER}
|
||||
- MYSQL_PASSWORD=${_APP_DB_PASS}
|
||||
- MARIADB_AUTO_UPGRADE=1
|
||||
command: 'mysqld --innodb-flush-method=fsync'
|
||||
|
||||
<?php elseif ($dbService === 'mongodb'): ?>
|
||||
|
||||
mongodb:
|
||||
image: mongo:8.0.10
|
||||
container_name: appwrite-mongodb
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- appwrite-mariadb:/var/lib/mysql:rw
|
||||
- appwrite-mongodb:/data/db
|
||||
- appwrite-mongodb-keyfile:/data/keyfile
|
||||
- ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro
|
||||
- ./mongo-entrypoint.sh:/mongo-entrypoint.sh:ro
|
||||
ports:
|
||||
- "27017:27017"
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=${_APP_DB_ROOT_PASS}
|
||||
- MYSQL_DATABASE=${_APP_DB_SCHEMA}
|
||||
- MYSQL_USER=${_APP_DB_USER}
|
||||
- MYSQL_PASSWORD=${_APP_DB_PASS}
|
||||
- MARIADB_AUTO_UPGRADE=1
|
||||
command: 'mysqld --innodb-flush-method=fsync'
|
||||
- MONGO_INITDB_ROOT_USERNAME=root
|
||||
- MONGO_INITDB_ROOT_PASSWORD=${_APP_DB_ROOT_PASS}
|
||||
- MONGO_INITDB_DATABASE=${_APP_DB_SCHEMA}
|
||||
- MONGO_INITDB_USERNAME=${_APP_DB_USER}
|
||||
- MONGO_INITDB_PASSWORD=${_APP_DB_PASS}
|
||||
entrypoint: ["/bin/bash", "/mongo-entrypoint.sh"]
|
||||
healthcheck:
|
||||
test: |
|
||||
bash -c "
|
||||
if mongosh -u root -p ${_APP_DB_ROOT_PASS} --authenticationDatabase admin --quiet --eval 'rs.status().ok' 2>/dev/null | grep -q 1; then
|
||||
exit 0
|
||||
else
|
||||
mongosh -u root -p ${_APP_DB_ROOT_PASS} --authenticationDatabase admin --quiet --eval \"
|
||||
rs.initiate({_id: 'rs0', members: [{_id: 0, host: 'mongodb:27017'}]})
|
||||
\" 2>/dev/null || exit 1
|
||||
fi
|
||||
"
|
||||
interval: 10s
|
||||
timeout: 10s
|
||||
retries: 10
|
||||
start_period: 30s
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
redis:
|
||||
image: redis:7.2.4-alpine
|
||||
@@ -971,7 +1032,12 @@ networks:
|
||||
name: runtimes
|
||||
|
||||
volumes:
|
||||
<?php if ($dbService === 'mariadb'): ?>
|
||||
appwrite-mariadb:
|
||||
<?php elseif ($dbService === 'mongodb'): ?>
|
||||
appwrite-mongodb:
|
||||
appwrite-mongodb-keyfile:
|
||||
<?php endif; ?>
|
||||
appwrite-redis:
|
||||
appwrite-cache:
|
||||
appwrite-uploads:
|
||||
|
||||
@@ -197,6 +197,49 @@ Server::setResource('getLogsDB', function (Group $pools, Cache $cache) {
|
||||
};
|
||||
}, ['pools', 'cache']);
|
||||
|
||||
Server::setResource('getDatabasesDB', function (Cache $cache, Registry $register, Document $project) {
|
||||
return function (Document $database, ?Document $projectDocument = null) use ($cache, $register, $project): Database {
|
||||
$projectDocument ??= $project;
|
||||
$databaseType = $database->getAttribute('database', '');
|
||||
|
||||
try {
|
||||
$databaseDSN = new DSN($databaseType);
|
||||
} catch (\InvalidArgumentException) {
|
||||
$databaseDSN = new DSN('mysql://'.$databaseType);
|
||||
}
|
||||
|
||||
try {
|
||||
$dsn = new DSN($projectDocument->getAttribute('database'));
|
||||
} catch (\InvalidArgumentException) {
|
||||
// Temporary fallback until all projects use shared tables
|
||||
$dsn = new DSN('mysql://' . $projectDocument->getAttribute('database'));
|
||||
}
|
||||
|
||||
$pools = $register->get('pools');
|
||||
$pool = $pools->get($databaseDSN->getHost());
|
||||
|
||||
$adapter = new DatabasePool($pool);
|
||||
$database = new Database($adapter, $cache);
|
||||
|
||||
$sharedTables = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES', ''));
|
||||
|
||||
if (\in_array($dsn->getHost(), $sharedTables, true)) {
|
||||
$database
|
||||
->setSharedTables(true)
|
||||
->setTenant((int) $projectDocument->getSequence())
|
||||
->setNamespace($dsn->getParam('namespace'));
|
||||
} else {
|
||||
$database
|
||||
->setSharedTables(false)
|
||||
->setTenant(null)
|
||||
->setNamespace('_' . $projectDocument->getSequence());
|
||||
}
|
||||
|
||||
$database->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER);
|
||||
return $database;
|
||||
};
|
||||
}, ['cache', 'register', 'project']);
|
||||
|
||||
Server::setResource('abuseRetention', function () {
|
||||
return time() - (int) System::getEnv('_APP_MAINTENANCE_RETENTION_ABUSE', 86400); // 1 day
|
||||
});
|
||||
|
||||
+14
-6
@@ -29,6 +29,8 @@
|
||||
"Appwrite\\Tests\\": "tests/extensions"
|
||||
}
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
"require": {
|
||||
"php": ">=8.3.0",
|
||||
"ext-curl": "*",
|
||||
@@ -64,27 +66,27 @@
|
||||
"utopia-php/locale": "0.8.*",
|
||||
"utopia-php/logger": "0.6.*",
|
||||
"utopia-php/messaging": "0.20.*",
|
||||
"utopia-php/migration": "1.3.*",
|
||||
"utopia-php/migration": "1.4.0",
|
||||
"utopia-php/orchestration": "0.9.*",
|
||||
"utopia-php/platform": "0.7.*",
|
||||
"utopia-php/pools": "0.8.*",
|
||||
"utopia-php/preloader": "0.2.*",
|
||||
"utopia-php/queue": "0.15.*",
|
||||
"utopia-php/registry": "0.5.*",
|
||||
"utopia-php/storage": "0.18.*",
|
||||
"utopia-php/storage": "0.18.*",
|
||||
"utopia-php/swoole": "0.8.*",
|
||||
"utopia-php/system": "0.9.*",
|
||||
"utopia-php/telemetry": "0.1.*",
|
||||
"utopia-php/vcs": "0.13.*",
|
||||
"utopia-php/websocket": "0.3.*",
|
||||
"matomo/device-detector": "6.4.*",
|
||||
"dragonmantank/cron-expression": "3.4.*",
|
||||
"dragonmantank/cron-expression": "3.3.*",
|
||||
"phpmailer/phpmailer": "6.9.*",
|
||||
"chillerlan/php-qrcode": "4.4.*",
|
||||
"chillerlan/php-qrcode": "4.3.*",
|
||||
"adhocore/jwt": "1.1.*",
|
||||
"spomky-labs/otphp": "10.0.*",
|
||||
"spomky-labs/otphp": "^10.0",
|
||||
"webonyx/graphql-php": "14.11.*",
|
||||
"league/csv": "9.24.*",
|
||||
"league/csv": "9.14.*",
|
||||
"enshrined/svg-sanitize": "0.22.*"
|
||||
},
|
||||
"require-dev": {
|
||||
@@ -100,6 +102,12 @@
|
||||
"provide": {
|
||||
"ext-phpiredis": "*"
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/utopia-php/migration.git"
|
||||
}
|
||||
],
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "8.3"
|
||||
|
||||
Generated
+79
-67
@@ -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": "ff3172688b600aa3c560131c9d9c5588",
|
||||
"content-hash": "cd2578268f3230a027e1b28675bb7b81",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
@@ -343,34 +343,31 @@
|
||||
},
|
||||
{
|
||||
"name": "chillerlan/php-qrcode",
|
||||
"version": "4.4.2",
|
||||
"version": "4.3.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/chillerlan/php-qrcode.git",
|
||||
"reference": "345ed8e4ffb56e6b3fcd9f42e3970b9026fa6ce4"
|
||||
"reference": "2ca4bf5ae048af1981d1023ee42a0a2a9d51e51d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/chillerlan/php-qrcode/zipball/345ed8e4ffb56e6b3fcd9f42e3970b9026fa6ce4",
|
||||
"reference": "345ed8e4ffb56e6b3fcd9f42e3970b9026fa6ce4",
|
||||
"url": "https://api.github.com/repos/chillerlan/php-qrcode/zipball/2ca4bf5ae048af1981d1023ee42a0a2a9d51e51d",
|
||||
"reference": "2ca4bf5ae048af1981d1023ee42a0a2a9d51e51d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"chillerlan/php-settings-container": "^2.1.6 || ^3.2.1",
|
||||
"chillerlan/php-settings-container": "^2.1.4",
|
||||
"ext-mbstring": "*",
|
||||
"php": "^7.4 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phan/phan": "^5.4.5",
|
||||
"phpmd/phpmd": "^2.15",
|
||||
"phpunit/phpunit": "^9.6",
|
||||
"setasign/fpdf": "^1.8.2",
|
||||
"squizlabs/php_codesniffer": "^3.11"
|
||||
"phan/phan": "^5.3",
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"setasign/fpdf": "^1.8.2"
|
||||
},
|
||||
"suggest": {
|
||||
"chillerlan/php-authenticator": "Yet another Google authenticator! Also creates URIs for mobile apps.",
|
||||
"setasign/fpdf": "Required to use the QR FPDF output.",
|
||||
"simple-icons/simple-icons": "SVG icons that you can use to embed as logos in the QR Code"
|
||||
"setasign/fpdf": "Required to use the QR FPDF output."
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@@ -397,7 +394,7 @@
|
||||
"homepage": "https://github.com/chillerlan/php-qrcode/graphs/contributors"
|
||||
}
|
||||
],
|
||||
"description": "A QR code generator with a user friendly API. PHP 7.4+",
|
||||
"description": "A QR code generator. PHP 7.4+",
|
||||
"homepage": "https://github.com/chillerlan/php-qrcode",
|
||||
"keywords": [
|
||||
"phpqrcode",
|
||||
@@ -408,39 +405,43 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/chillerlan/php-qrcode/issues",
|
||||
"source": "https://github.com/chillerlan/php-qrcode/tree/4.4.2"
|
||||
"source": "https://github.com/chillerlan/php-qrcode/tree/4.3.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://www.paypal.com/donate?hosted_button_id=WLYUNAT9ZTJZ4",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://ko-fi.com/codemasher",
|
||||
"type": "ko_fi"
|
||||
}
|
||||
],
|
||||
"time": "2024-11-15T15:36:24+00:00"
|
||||
"time": "2022-07-25T09:12:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "chillerlan/php-settings-container",
|
||||
"version": "3.2.1",
|
||||
"version": "2.1.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/chillerlan/php-settings-container.git",
|
||||
"reference": "95ed3e9676a1d47cab2e3174d19b43f5dbf52681"
|
||||
"reference": "5553558bd381fce5108c6d0343c12e488cfec6bb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/chillerlan/php-settings-container/zipball/95ed3e9676a1d47cab2e3174d19b43f5dbf52681",
|
||||
"reference": "95ed3e9676a1d47cab2e3174d19b43f5dbf52681",
|
||||
"url": "https://api.github.com/repos/chillerlan/php-settings-container/zipball/5553558bd381fce5108c6d0343c12e488cfec6bb",
|
||||
"reference": "5553558bd381fce5108c6d0343c12e488cfec6bb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"php": "^8.1"
|
||||
"php": "^7.4 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpmd/phpmd": "^2.15",
|
||||
"phpstan/phpstan": "^1.11",
|
||||
"phpstan/phpstan-deprecation-rules": "^1.2",
|
||||
"phpunit/phpunit": "^10.5",
|
||||
"phpunit/phpunit": "^9.6",
|
||||
"squizlabs/php_codesniffer": "^3.10"
|
||||
},
|
||||
"type": "library",
|
||||
@@ -460,9 +461,10 @@
|
||||
"homepage": "https://github.com/codemasher"
|
||||
}
|
||||
],
|
||||
"description": "A container class for immutable settings objects. Not a DI container.",
|
||||
"description": "A container class for immutable settings objects. Not a DI container. PHP 7.4+",
|
||||
"homepage": "https://github.com/chillerlan/php-settings-container",
|
||||
"keywords": [
|
||||
"PHP7",
|
||||
"Settings",
|
||||
"configuration",
|
||||
"container",
|
||||
@@ -482,7 +484,7 @@
|
||||
"type": "ko_fi"
|
||||
}
|
||||
],
|
||||
"time": "2024-07-16T11:13:48+00:00"
|
||||
"time": "2024-07-17T01:04:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/semver",
|
||||
@@ -563,16 +565,16 @@
|
||||
},
|
||||
{
|
||||
"name": "dragonmantank/cron-expression",
|
||||
"version": "v3.4.0",
|
||||
"version": "v3.3.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/dragonmantank/cron-expression.git",
|
||||
"reference": "8c784d071debd117328803d86b2097615b457500"
|
||||
"reference": "adfb1f505deb6384dc8b39804c5065dd3c8c8c0a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/8c784d071debd117328803d86b2097615b457500",
|
||||
"reference": "8c784d071debd117328803d86b2097615b457500",
|
||||
"url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/adfb1f505deb6384dc8b39804c5065dd3c8c8c0a",
|
||||
"reference": "adfb1f505deb6384dc8b39804c5065dd3c8c8c0a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -585,14 +587,10 @@
|
||||
"require-dev": {
|
||||
"phpstan/extension-installer": "^1.0",
|
||||
"phpstan/phpstan": "^1.0",
|
||||
"phpstan/phpstan-webmozart-assert": "^1.0",
|
||||
"phpunit/phpunit": "^7.0|^8.0|^9.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Cron\\": "src/Cron/"
|
||||
@@ -616,7 +614,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/dragonmantank/cron-expression/issues",
|
||||
"source": "https://github.com/dragonmantank/cron-expression/tree/v3.4.0"
|
||||
"source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -624,7 +622,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-10-09T13:47:03+00:00"
|
||||
"time": "2023-08-10T19:36:49+00:00"
|
||||
},
|
||||
{
|
||||
"name": "enshrined/svg-sanitize",
|
||||
@@ -800,42 +798,40 @@
|
||||
},
|
||||
{
|
||||
"name": "league/csv",
|
||||
"version": "9.24.1",
|
||||
"version": "9.14.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/csv.git",
|
||||
"reference": "e0221a3f16aa2a823047d59fab5809d552e29bc8"
|
||||
"reference": "34bf0df7340b60824b9449b5c526fcc3325070d5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/csv/zipball/e0221a3f16aa2a823047d59fab5809d552e29bc8",
|
||||
"reference": "e0221a3f16aa2a823047d59fab5809d552e29bc8",
|
||||
"url": "https://api.github.com/repos/thephpleague/csv/zipball/34bf0df7340b60824b9449b5c526fcc3325070d5",
|
||||
"reference": "34bf0df7340b60824b9449b5c526fcc3325070d5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-filter": "*",
|
||||
"ext-json": "*",
|
||||
"ext-mbstring": "*",
|
||||
"php": "^8.1.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/collections": "^2.1.4",
|
||||
"ext-dom": "*",
|
||||
"ext-xdebug": "*",
|
||||
"friendsofphp/php-cs-fixer": "^3.75.0",
|
||||
"phpbench/phpbench": "^1.4.1",
|
||||
"phpstan/phpstan": "^1.12.27",
|
||||
"phpstan/phpstan-deprecation-rules": "^1.2.1",
|
||||
"phpstan/phpstan-phpunit": "^1.4.2",
|
||||
"phpstan/phpstan-strict-rules": "^1.6.2",
|
||||
"phpunit/phpunit": "^10.5.16 || ^11.5.22",
|
||||
"symfony/var-dumper": "^6.4.8 || ^7.3.0"
|
||||
"friendsofphp/php-cs-fixer": "^v3.22.0",
|
||||
"phpbench/phpbench": "^1.2.15",
|
||||
"phpstan/phpstan": "^1.10.50",
|
||||
"phpstan/phpstan-deprecation-rules": "^1.1.4",
|
||||
"phpstan/phpstan-phpunit": "^1.3.15",
|
||||
"phpstan/phpstan-strict-rules": "^1.5.2",
|
||||
"phpunit/phpunit": "^10.5.3",
|
||||
"symfony/var-dumper": "^6.4.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-dom": "Required to use the XMLConverter and the HTMLConverter classes",
|
||||
"ext-iconv": "Needed to ease transcoding CSV using iconv stream filters",
|
||||
"ext-mbstring": "Needed to ease transcoding CSV using mb stream filters",
|
||||
"ext-mysqli": "Requiered to use the package with the MySQLi extension",
|
||||
"ext-pdo": "Required to use the package with the PDO extension",
|
||||
"ext-pgsql": "Requiered to use the package with the PgSQL extension",
|
||||
"ext-sqlite3": "Required to use the package with the SQLite3 extension"
|
||||
"ext-iconv": "Needed to ease transcoding CSV using iconv stream filters"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
@@ -887,7 +883,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-06-25T14:53:51+00:00"
|
||||
"time": "2023-12-29T07:34:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "matomo/device-detector",
|
||||
@@ -4516,16 +4512,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/migration",
|
||||
"version": "1.3.13",
|
||||
"version": "1.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/migration.git",
|
||||
"reference": "c5e3f5e970e62e8f7db97b5b90baae2af800a715"
|
||||
"reference": "18bd7d39dcee09280f40edb12879c727ecec98d3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/migration/zipball/c5e3f5e970e62e8f7db97b5b90baae2af800a715",
|
||||
"reference": "c5e3f5e970e62e8f7db97b5b90baae2af800a715",
|
||||
"url": "https://api.github.com/repos/utopia-php/migration/zipball/18bd7d39dcee09280f40edb12879c727ecec98d3",
|
||||
"reference": "18bd7d39dcee09280f40edb12879c727ecec98d3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4551,7 +4547,25 @@
|
||||
"Utopia\\Migration\\": "src/Migration"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Utopia\\Tests\\": "tests/Migration"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": [
|
||||
"./vendor/bin/phpunit"
|
||||
],
|
||||
"lint": [
|
||||
"./vendor/bin/pint --test"
|
||||
],
|
||||
"format": [
|
||||
"./vendor/bin/pint"
|
||||
],
|
||||
"check": [
|
||||
"./vendor/bin/phpstan analyse --level 3 src tests --memory-limit 2G"
|
||||
]
|
||||
},
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
@@ -4564,10 +4578,10 @@
|
||||
"utopia"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/migration/issues",
|
||||
"source": "https://github.com/utopia-php/migration/tree/1.3.13"
|
||||
"source": "https://github.com/utopia-php/migration/tree/1.4.0",
|
||||
"issues": "https://github.com/utopia-php/migration/issues"
|
||||
},
|
||||
"time": "2026-01-07T14:48:05+00:00"
|
||||
"time": "2025-11-21T06:08:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/mongo",
|
||||
@@ -8944,11 +8958,9 @@
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {
|
||||
"utopia-php/audit": 5
|
||||
},
|
||||
"prefer-stable": false,
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": {},
|
||||
"prefer-stable": true,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": ">=8.3.0",
|
||||
|
||||
+89
-17
@@ -98,8 +98,9 @@ services:
|
||||
- ./public:/usr/src/code/public
|
||||
- ./src:/usr/src/code/src
|
||||
- ./dev:/usr/src/code/dev
|
||||
|
||||
depends_on:
|
||||
- mariadb
|
||||
- ${_APP_DB_HOST:-mongodb}
|
||||
- redis
|
||||
- coredns
|
||||
# - clamav
|
||||
@@ -140,6 +141,7 @@ services:
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -277,7 +279,7 @@ services:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- mariadb
|
||||
- ${_APP_DB_HOST:-mongodb}
|
||||
- redis
|
||||
environment:
|
||||
- _APP_ENV
|
||||
@@ -289,6 +291,7 @@ services:
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -311,7 +314,7 @@ services:
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
- ${_APP_DB_HOST:-mongodb}
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
@@ -320,6 +323,7 @@ services:
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -340,7 +344,7 @@ services:
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
- ${_APP_DB_HOST:-mongodb}
|
||||
- request-catcher-sms
|
||||
- request-catcher-webhook
|
||||
environment:
|
||||
@@ -348,6 +352,7 @@ services:
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_EMAIL_SECURITY
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -370,7 +375,7 @@ services:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
- ${_APP_DB_HOST:-mongodb}
|
||||
volumes:
|
||||
- appwrite-uploads:/storage/uploads:rw
|
||||
- appwrite-cache:/storage/cache:rw
|
||||
@@ -388,6 +393,7 @@ services:
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -436,7 +442,7 @@ services:
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
- ${_APP_DB_HOST:-mongodb}
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
@@ -445,6 +451,7 @@ services:
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -470,7 +477,7 @@ services:
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
- ${_APP_DB_HOST:-mongodb}
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
@@ -481,6 +488,7 @@ services:
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -595,7 +603,7 @@ services:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
- ${_APP_DB_HOST:-mongodb}
|
||||
volumes:
|
||||
- appwrite-config:/storage/config:rw
|
||||
- appwrite-certificates:/storage/certificates:rw
|
||||
@@ -618,6 +626,7 @@ services:
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -638,7 +647,7 @@ services:
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
- ${_APP_DB_HOST:-mongodb}
|
||||
- openruntimes-executor
|
||||
environment:
|
||||
- _APP_ENV
|
||||
@@ -650,6 +659,7 @@ services:
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -725,6 +735,7 @@ services:
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -773,7 +784,7 @@ services:
|
||||
- ./src:/usr/src/code/src
|
||||
- ./tests:/usr/src/code/tests
|
||||
depends_on:
|
||||
- mariadb
|
||||
- ${_APP_DB_HOST:-mongodb}
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
@@ -789,6 +800,7 @@ services:
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -828,6 +840,7 @@ services:
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -893,11 +906,12 @@ services:
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
- ${_APP_DB_HOST:-mongodb}
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -924,11 +938,12 @@ services:
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
- ${_APP_DB_HOST:-mongodb}
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -955,11 +970,12 @@ services:
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
- ${_APP_DB_HOST:-mongodb}
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -985,7 +1001,7 @@ services:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- mariadb
|
||||
- ${_APP_DB_HOST:-mongodb}
|
||||
- redis
|
||||
environment:
|
||||
- _APP_ENV
|
||||
@@ -995,6 +1011,7 @@ services:
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -1013,7 +1030,7 @@ services:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- mariadb
|
||||
- ${_APP_DB_HOST:-mongodb}
|
||||
- redis
|
||||
environment:
|
||||
- _APP_ENV
|
||||
@@ -1023,6 +1040,7 @@ services:
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -1040,7 +1058,7 @@ services:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
depends_on:
|
||||
- mariadb
|
||||
- ${_APP_DB_HOST:-mongodb}
|
||||
- redis
|
||||
environment:
|
||||
- _APP_ENV
|
||||
@@ -1050,6 +1068,7 @@ services:
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_ADAPTER
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
@@ -1142,6 +1161,57 @@ services:
|
||||
- MARIADB_AUTO_UPGRADE=1
|
||||
command: "mysqld --innodb-flush-method=fsync"
|
||||
|
||||
mongodb:
|
||||
image: mongo:8.0.10
|
||||
container_name: appwrite-mongodb
|
||||
<<: *x-logging
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- appwrite-mongodb:/data/db
|
||||
- appwrite-mongodb-keyfile:/data/keyfile
|
||||
- ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro
|
||||
- ./mongo-entrypoint.sh:/mongo-entrypoint.sh:ro
|
||||
ports:
|
||||
- "27017:27017"
|
||||
environment:
|
||||
- MONGO_INITDB_ROOT_USERNAME=root
|
||||
- MONGO_INITDB_ROOT_PASSWORD=${_APP_DB_ROOT_PASS}
|
||||
- MONGO_INITDB_DATABASE=${_APP_DB_SCHEMA}
|
||||
- MONGO_INITDB_USERNAME=${_APP_DB_USER}
|
||||
- MONGO_INITDB_PASSWORD=${_APP_DB_PASS}
|
||||
entrypoint: ["/bin/bash", "/mongo-entrypoint.sh"]
|
||||
healthcheck:
|
||||
test: |
|
||||
bash -c "
|
||||
if mongosh -u root -p ${_APP_DB_ROOT_PASS} --authenticationDatabase admin --quiet --eval 'rs.status().ok' 2>/dev/null | grep -q 1; then
|
||||
exit 0
|
||||
else
|
||||
mongosh -u root -p ${_APP_DB_ROOT_PASS} --authenticationDatabase admin --quiet --eval \"
|
||||
rs.initiate({_id: 'rs0', members: [{_id: 0, host: 'appwrite-mongodb:27017'}]})
|
||||
\" 2>/dev/null || exit 1
|
||||
fi
|
||||
"
|
||||
interval: 10s
|
||||
timeout: 10s
|
||||
retries: 10
|
||||
start_period: 30s
|
||||
|
||||
appwrite-mongo-express:
|
||||
image: mongo-express
|
||||
container_name: appwrite-mongo-express
|
||||
networks:
|
||||
- appwrite
|
||||
ports:
|
||||
- "8082:8081"
|
||||
environment:
|
||||
ME_CONFIG_MONGODB_URL: "mongodb://root:${_APP_DB_ROOT_PASS}@appwrite-mongodb:27017/?replicaSet=rs0&directConnection=true"
|
||||
ME_CONFIG_BASICAUTH_USERNAME: ${_APP_DB_USER}
|
||||
ME_CONFIG_BASICAUTH_PASSWORD: ${_APP_DB_PASS}
|
||||
depends_on:
|
||||
- mongodb
|
||||
|
||||
|
||||
redis:
|
||||
image: redis:7.2.4-alpine
|
||||
<<: *x-logging
|
||||
@@ -1369,6 +1439,8 @@ configs:
|
||||
|
||||
volumes:
|
||||
appwrite-mariadb:
|
||||
appwrite-mongodb:
|
||||
appwrite-mongodb-keyfile:
|
||||
appwrite-redis:
|
||||
appwrite-cache:
|
||||
appwrite-uploads:
|
||||
@@ -1377,4 +1449,4 @@ volumes:
|
||||
appwrite-functions:
|
||||
appwrite-sites:
|
||||
appwrite-builds:
|
||||
appwrite-config:
|
||||
appwrite-config:
|
||||
@@ -0,0 +1 @@
|
||||
Create a new Collection. Before using this route, you should create a new database resource using either a [server integration](https://appwrite.io/docs/server/databases#documentsDBCreateCollection) API or directly from your database console.
|
||||
@@ -0,0 +1 @@
|
||||
Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#documentsDBCreateCollection) API or directly from your database console.
|
||||
@@ -0,0 +1 @@
|
||||
Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#documentsDBCreateCollection) API or directly from your database console.
|
||||
@@ -0,0 +1,2 @@
|
||||
Creates an index on the attributes listed. Your index should include all the attributes you will query in a single request.
|
||||
Attributes can be `key`, `fulltext`, and `unique`.
|
||||
@@ -0,0 +1 @@
|
||||
Create a new Database.
|
||||
@@ -0,0 +1 @@
|
||||
Decrement a specific column of a row by a given value.
|
||||
@@ -0,0 +1 @@
|
||||
Delete a collection by its unique ID. Only users with write permissions have access to delete this resource.
|
||||
@@ -0,0 +1 @@
|
||||
Delete a document by its unique ID.
|
||||
@@ -0,0 +1 @@
|
||||
Bulk delete documents using queries, if no queries are passed then all documents are deleted.
|
||||
@@ -0,0 +1 @@
|
||||
Delete an index.
|
||||
@@ -0,0 +1 @@
|
||||
Delete a database by its unique ID. Only API keys with with databases.write scope can delete a database.
|
||||
@@ -0,0 +1 @@
|
||||
Get the collection activity logs list by its unique ID.
|
||||
@@ -0,0 +1 @@
|
||||
Get usage metrics and statistics for a collection. Returning the total number of documents. The response includes both current totals and historical data over time. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, range defaults to 30 days.
|
||||
@@ -0,0 +1 @@
|
||||
Get a collection by its unique ID. This endpoint response returns a JSON object with the collection metadata.
|
||||
@@ -0,0 +1 @@
|
||||
Get usage metrics and statistics for a database. You can view the total number of collections, documents, and storage usage. The response includes both current totals and historical data over time. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, range defaults to 30 days.
|
||||
@@ -0,0 +1 @@
|
||||
Get the document activity logs list by its unique ID.
|
||||
@@ -0,0 +1 @@
|
||||
Get a document by its unique ID. This endpoint response returns a JSON object with the document data.
|
||||
@@ -0,0 +1 @@
|
||||
Get index by ID.
|
||||
@@ -0,0 +1 @@
|
||||
Get the database activity logs list by its unique ID.
|
||||
@@ -0,0 +1 @@
|
||||
Get a database by its unique ID. This endpoint response returns a JSON object with the database metadata.
|
||||
@@ -0,0 +1 @@
|
||||
Increment a specific column of a row by a given value.
|
||||
@@ -0,0 +1 @@
|
||||
List attributes in the collection.
|
||||
@@ -0,0 +1 @@
|
||||
Get a list of all collections that belong to the provided databaseId. You can use the search parameter to filter your results.
|
||||
@@ -0,0 +1 @@
|
||||
Get a list of all the user's documents in a given collection. You can use the query params to filter your results.
|
||||
@@ -0,0 +1 @@
|
||||
List indexes in the collection.
|
||||
@@ -0,0 +1 @@
|
||||
List usage metrics and statistics for all databases in the project. You can view the total number of databases, collections, documents, and storage usage. The response includes both current totals and historical data over time. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, range defaults to 30 days.
|
||||
@@ -0,0 +1 @@
|
||||
Get a list of all databases from the current Appwrite project. You can use the search parameter to filter your results.
|
||||
@@ -0,0 +1 @@
|
||||
Update a collection by its unique ID.
|
||||
@@ -0,0 +1 @@
|
||||
Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated.
|
||||
@@ -0,0 +1 @@
|
||||
Update all documents that match your queries, if no queries are submitted then all documents are updated. You can pass only specific fields to be updated.
|
||||
@@ -0,0 +1 @@
|
||||
Update a database by its unique ID.
|
||||
@@ -0,0 +1 @@
|
||||
Create or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#documentsDBCreateCollection) API or directly from your database console.
|
||||
@@ -0,0 +1 @@
|
||||
Create or update Documents. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#documentsDBCreateCollection) API or directly from your database console.
|
||||
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Fix keyfile permissions if mounted from volume
|
||||
KEYFILE_PATH="/data/keyfile/mongo-keyfile"
|
||||
|
||||
if [ ! -f "$KEYFILE_PATH" ]; then
|
||||
echo "Generating random MongoDB keyfile..."
|
||||
mkdir -p /data/keyfile
|
||||
openssl rand -base64 756 > "$KEYFILE_PATH"
|
||||
fi
|
||||
|
||||
chmod 400 "$KEYFILE_PATH"
|
||||
chown mongodb:mongodb "$KEYFILE_PATH" 2>/dev/null || chown 999:999 "$KEYFILE_PATH"
|
||||
|
||||
# Use MongoDB's standard entrypoint with our command
|
||||
exec docker-entrypoint.sh mongod --replSet rs0 --bind_ip_all --auth --keyFile "$KEYFILE_PATH"
|
||||
@@ -0,0 +1,51 @@
|
||||
#!/bin/bash
|
||||
|
||||
# MongoDB Replica Set Initialization Script
|
||||
# Runs after MongoDB starts as part of docker-entrypoint-initdb.d
|
||||
|
||||
# Check if replica set is already initialized
|
||||
RS_STATUS=$(mongosh --username root --password "${MONGO_INITDB_ROOT_PASSWORD}" --authenticationDatabase admin --eval "try { rs.status().ok } catch(e) { 0 }" --quiet 2>/dev/null || echo "0")
|
||||
|
||||
if [ "$RS_STATUS" = "1" ]; then
|
||||
echo "Replica set already initialized"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Initialize replica set
|
||||
echo "Initializing replica set 'rs0'..."
|
||||
# For single-node replica set, we can use localhost since clients connect directly
|
||||
# The MongoDB driver will handle connection to this node
|
||||
mongosh --username root --password "${MONGO_INITDB_ROOT_PASSWORD}" --authenticationDatabase admin --eval "rs.initiate({ _id: 'rs0', members: [{ _id: 0, host: '127.0.0.1:27017' }] })"
|
||||
|
||||
# Wait for replica set to elect a primary and become stable
|
||||
echo "Waiting for PRIMARY to be ready..."
|
||||
MAX_WAIT=15
|
||||
COUNTER=0
|
||||
while [ $COUNTER -lt $MAX_WAIT ]; do
|
||||
# Use try/catch to handle cases where rs.status() fails during initialization
|
||||
PRIMARY_STATE=$(mongosh --username root --password "${MONGO_INITDB_ROOT_PASSWORD}" --authenticationDatabase admin --eval "try { rs.status().members[0].stateStr } catch(e) { 'WAITING' }" --quiet 2>/dev/null || echo "WAITING")
|
||||
|
||||
if [ "$PRIMARY_STATE" = "PRIMARY" ]; then
|
||||
echo "PRIMARY is ready!"
|
||||
break
|
||||
fi
|
||||
|
||||
# Give it more time between checks
|
||||
sleep 2
|
||||
COUNTER=$((COUNTER+1))
|
||||
|
||||
# Only show status every few attempts to reduce log noise
|
||||
if [ $((COUNTER % 3)) -eq 0 ]; then
|
||||
echo "Still waiting for PRIMARY (attempt $COUNTER/$MAX_WAIT, current state: $PRIMARY_STATE)..."
|
||||
fi
|
||||
done
|
||||
|
||||
# Don't fail the init even if PRIMARY isn't ready immediately
|
||||
# MongoDB will continue to elect a primary in the background
|
||||
# Clients will wait for it to be ready via their connection retry logic
|
||||
if [ $COUNTER -eq $MAX_WAIT ]; then
|
||||
echo "NOTE: PRIMARY not confirmed within $((MAX_WAIT * 2)) seconds, but replica set is configured"
|
||||
echo "MongoDB will continue initializing the replica set in the background"
|
||||
fi
|
||||
|
||||
echo "Replica set initialization complete!"
|
||||
@@ -0,0 +1,18 @@
|
||||
// mongo-init.js
|
||||
|
||||
// Switch to the admin database
|
||||
const adminDb = db.getSiblingDB('admin');
|
||||
|
||||
// Get username and password from environment variables
|
||||
const username = process.env.MONGO_INITDB_USERNAME;
|
||||
const password = process.env.MONGO_INITDB_PASSWORD;
|
||||
const database = process.env.MONGO_INITDB_DATABASE;
|
||||
|
||||
// Create the user
|
||||
adminDb.createUser({
|
||||
user: username,
|
||||
pwd: password,
|
||||
roles: [
|
||||
{ role: 'readWrite', db: database }
|
||||
]
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
i4Ge9ZbzXgpP4ZLLX/9/pkfhZYlEpSCfhl3Gqr0iwx1UAf4z3egza5J5tjj+S1zl
|
||||
flopL/FlHaBLQAbY9E6kQyaIFQHJ4Wd6bOkL5hajIizvBBLtKxgpKMPQdvnx6mwe
|
||||
aeK866TFRx4rWWQs69Gz3nZb822YRmdC4m2H+1rx635/ICWMWv26EdmYayafe010
|
||||
zKJW/Ty75MpAk9yxc3PFEooDZtmb9PQKkkA4c+P7hfg1HBnrkcqfOejmlwvr/tWE
|
||||
P8JIQTtcruo8A/5BFq0x0BToLJzY/eOiGcNe1Qf8CO4/8ZKWnvk00FvxXuU1KQ1G
|
||||
uDlhaCakwitUGEjkKSeIH7V1Qk96JlY8kR5qBhavmROEd/o3VceLfdbbZzd+bitH
|
||||
PRIocDb06SuWWvJGnwLRoyQmpeXu8AEd5YD+yimhGMQqzCfRFhxlT9rIJbWc8Z+Y
|
||||
M8uDgd3bHaVfQCQDxbOgo9xB0zqOx77HUBXqeU4xqMeiOkKJxDrt6Cz0osQyybZO
|
||||
NL9lsJ2y+2S6RyUWNMWJTrVGhgKnse/Z0dgrHpShBMI02G/Q8MKTDXyJmeX1PToe
|
||||
CCdDmVMKhQRkrvZqeNTvOiNGb/hUDqU/Px/lCmhZYzIKsOK7nhaH6U5FiIAzxeNi
|
||||
g03gwyrwRfmJWRyTcTSuQKIprBoobl2xJG2CYjdc2UhtY2I3bSlOue1DOKYnOFjA
|
||||
x58DNwUQdegadSsyd2IPlWpUGIY1GJjTV+J9vEf79TQtnzYSFH5lmg3J08Cq64wg
|
||||
UAedRHUEnRHFlVfg4ZdkGTGL/2Q7l2Dk0jJQCFFq+tEFGncLgGlAJaWXkczaFaZy
|
||||
r9h12ulCUq6trZ1RGS1DlDxwQU2J6bSz0ZFwux/3W0YyIQyq4rWcoDjEG98DSE5n
|
||||
P3Qht2DsBjFkh55nfC0EgwXwnWzBTJiJo1GYf5RdEIVCmmWxmAfTfPYaKWOVcgGG
|
||||
6QGX5TCPyI6+SZUT/qOfGxnIE/1R3N1wD+J1rORXwWucLOiR
|
||||
@@ -56,6 +56,7 @@ class Mock extends OAuth2
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'GET',
|
||||
|
||||
@@ -20,16 +20,22 @@ use Utopia\Database\Validator\Authorization;
|
||||
class TransactionState
|
||||
{
|
||||
private Database $dbForProject;
|
||||
/**
|
||||
* @var callable(Document $database): Database
|
||||
*/
|
||||
private mixed $getDatabasesDB;
|
||||
|
||||
public function __construct(Database $dbForProject)
|
||||
public function __construct(Database $dbForProject, callable $getDatabasesDB)
|
||||
{
|
||||
$this->dbForProject = $dbForProject;
|
||||
$this->getDatabasesDB = $getDatabasesDB;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a document with transaction-aware logic
|
||||
*
|
||||
* @param Document $database Target database document
|
||||
* @param string $collectionId Collection ID
|
||||
* @param string $documentId Document ID
|
||||
* @param string|null $transactionId Optional transaction ID
|
||||
@@ -40,13 +46,15 @@ class TransactionState
|
||||
* @throws Timeout
|
||||
*/
|
||||
public function getDocument(
|
||||
Document $database,
|
||||
string $collectionId,
|
||||
string $documentId,
|
||||
?string $transactionId = null,
|
||||
array $queries = []
|
||||
): Document {
|
||||
$dbForDatabases = ($this->getDatabasesDB)($database);
|
||||
if ($transactionId === null) {
|
||||
return $this->dbForProject->getDocument($collectionId, $documentId, $queries);
|
||||
return $dbForDatabases->getDocument($collectionId, $documentId, $queries);
|
||||
}
|
||||
|
||||
$state = $this->getTransactionState($transactionId);
|
||||
@@ -64,7 +72,7 @@ class TransactionState
|
||||
|
||||
if ($docState['action'] === 'update' || $docState['action'] === 'upsert') {
|
||||
// Merge with committed version
|
||||
$committedDoc = $this->dbForProject->getDocument($collectionId, $documentId, $queries);
|
||||
$committedDoc = $dbForDatabases->getDocument($collectionId, $documentId, $queries);
|
||||
if (!$committedDoc->isEmpty()) {
|
||||
foreach ($docState['document']->getAttributes() as $key => $value) {
|
||||
if ($key !== '$id') {
|
||||
@@ -78,13 +86,13 @@ class TransactionState
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->dbForProject->getDocument($collectionId, $documentId, $queries);
|
||||
return $dbForDatabases->getDocument($collectionId, $documentId, $queries);
|
||||
}
|
||||
|
||||
/**
|
||||
* List documents with transaction-aware logic
|
||||
*
|
||||
* @param Document $database Target database document
|
||||
* @param string $collectionId Collection ID
|
||||
* @param string|null $transactionId Optional transaction ID
|
||||
* @param array $queries Optional query filters
|
||||
@@ -94,17 +102,19 @@ class TransactionState
|
||||
* @throws Timeout
|
||||
*/
|
||||
public function listDocuments(
|
||||
Document $database,
|
||||
string $collectionId,
|
||||
?string $transactionId = null,
|
||||
array $queries = []
|
||||
): array {
|
||||
$dbForDatabases = ($this->getDatabasesDB)($database);
|
||||
// If no transaction, use normal database retrieval
|
||||
if ($transactionId === null) {
|
||||
return $this->dbForProject->find($collectionId, $queries);
|
||||
return $dbForDatabases->find($collectionId, $queries);
|
||||
}
|
||||
|
||||
$state = $this->getTransactionState($transactionId);
|
||||
$committedDocs = $this->dbForProject->find($collectionId, $queries);
|
||||
$committedDocs = $dbForDatabases->find($collectionId, $queries);
|
||||
$documentMap = [];
|
||||
|
||||
// Build map of committed documents
|
||||
@@ -145,6 +155,7 @@ class TransactionState
|
||||
/**
|
||||
* Count documents with transaction-aware logic
|
||||
*
|
||||
* @param Document $database Target database document
|
||||
* @param string $collectionId Collection ID
|
||||
* @param string|null $transactionId Optional transaction ID
|
||||
* @param array $queries Optional query filters
|
||||
@@ -154,23 +165,23 @@ class TransactionState
|
||||
* @throws Timeout
|
||||
*/
|
||||
public function countDocuments(
|
||||
Document $database,
|
||||
string $collectionId,
|
||||
?string $transactionId = null,
|
||||
array $queries = []
|
||||
): int {
|
||||
$dbForDatabases = ($this->getDatabasesDB)($database);
|
||||
if ($transactionId === null) {
|
||||
return $this->dbForProject->count($collectionId, $queries, APP_LIMIT_COUNT);
|
||||
return $dbForDatabases->count($collectionId, $queries, APP_LIMIT_COUNT);
|
||||
}
|
||||
|
||||
$state = $this->getTransactionState($transactionId);
|
||||
|
||||
$baseCount = $this->dbForProject->count($collectionId, $queries, APP_LIMIT_COUNT);
|
||||
$baseCount = $dbForDatabases->count($collectionId, $queries, APP_LIMIT_COUNT);
|
||||
|
||||
if (!isset($state[$collectionId])) {
|
||||
return $baseCount;
|
||||
}
|
||||
|
||||
$committedDocs = $this->dbForProject->find($collectionId, $queries);
|
||||
$committedDocs = $dbForDatabases->find($collectionId, $queries);
|
||||
$committedDocIds = [];
|
||||
foreach ($committedDocs as $doc) {
|
||||
$committedDocIds[$doc->getId()] = true;
|
||||
@@ -212,17 +223,19 @@ class TransactionState
|
||||
/**
|
||||
* Check if a document exists with transaction-aware logic
|
||||
*
|
||||
* @param Document $database Target database document
|
||||
* @param string $collectionId Collection ID
|
||||
* @param string $documentId Document ID
|
||||
* @param string|null $transactionId Optional transaction ID
|
||||
* @return bool True if document exists
|
||||
*/
|
||||
public function documentExists(
|
||||
Document $database,
|
||||
string $collectionId,
|
||||
string $documentId,
|
||||
?string $transactionId = null
|
||||
): bool {
|
||||
$doc = $this->getDocument($collectionId, $documentId, $transactionId);
|
||||
$doc = $this->getDocument($database, $collectionId, $documentId, $transactionId);
|
||||
return !$doc->isEmpty();
|
||||
}
|
||||
|
||||
|
||||
@@ -489,10 +489,11 @@ class Event
|
||||
*
|
||||
* @param string $pattern
|
||||
* @param array $params
|
||||
* @param ?Document $database
|
||||
* @return array
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public static function generateEvents(string $pattern, array $params = []): array
|
||||
public static function generateEvents(string $pattern, array $params = [], ?Document $database = null): array
|
||||
{
|
||||
// $params = \array_filter($params, fn($param) => !\is_array($param));
|
||||
$paramKeys = \array_keys($params);
|
||||
@@ -501,6 +502,12 @@ class Event
|
||||
$patterns = [];
|
||||
|
||||
$parsed = self::parseEventPattern($pattern);
|
||||
// to switch the resource types from databases to the required prefix
|
||||
// eg; all databases events get fired with databases. prefix which mainly depicts legacy type
|
||||
// so a projection from databases to the actual prefix(documentsdb, vectordb,etc)
|
||||
if ((str_contains($pattern, 'databases.') && $database && $database->getAttribute('type') !== 'legacy')) {
|
||||
$parsed = self::getDatabaseTypeEvents($database, $parsed);
|
||||
}
|
||||
$type = $parsed['type'];
|
||||
$resource = $parsed['resource'];
|
||||
$subType = $parsed['subType'];
|
||||
@@ -601,8 +608,8 @@ class Event
|
||||
$eventValues = \array_values($events);
|
||||
|
||||
/**
|
||||
* Return a combined list of table, collection events.
|
||||
*/
|
||||
* Return a combined list of table, collection events and if tablesdb present then include all for backward compatibility
|
||||
*/
|
||||
return Event::mirrorCollectionEvents($pattern, $eventValues[0], $eventValues);
|
||||
}
|
||||
|
||||
@@ -642,16 +649,40 @@ class Event
|
||||
'attributes' => 'columns',
|
||||
];
|
||||
|
||||
$databasesEventMap = [
|
||||
'tablesdb' => 'databases',
|
||||
'tables' => 'collections',
|
||||
'rows' => 'documents',
|
||||
'columns' => 'attributes'
|
||||
];
|
||||
|
||||
if (
|
||||
str_contains($pattern, 'databases.') &&
|
||||
str_contains($firstEvent, 'collections')
|
||||
(
|
||||
str_contains($pattern, 'databases.') &&
|
||||
str_contains($firstEvent, 'collections')
|
||||
) ||
|
||||
(
|
||||
str_contains($firstEvent, 'tablesdb.')
|
||||
)
|
||||
) {
|
||||
$pairedEvents = [];
|
||||
|
||||
foreach ($events as $event) {
|
||||
$pairedEvents[] = $event;
|
||||
|
||||
if (str_contains($event, 'collections')) {
|
||||
// tablesdb needs databases event with tables and collections
|
||||
if (str_contains($event, 'tablesdb')) {
|
||||
$databasesSideEvent = str_replace(
|
||||
array_keys($databasesEventMap),
|
||||
array_values($databasesEventMap),
|
||||
$event
|
||||
);
|
||||
$pairedEvents[] = $databasesSideEvent;
|
||||
$tableSideEvent = str_replace(
|
||||
array_keys($tableEventMap),
|
||||
array_values($tableEventMap),
|
||||
$databasesSideEvent
|
||||
);
|
||||
$pairedEvents[] = $tableSideEvent;
|
||||
} elseif (str_contains($event, 'collections')) {
|
||||
$tableSideEvent = str_replace(
|
||||
array_keys($tableEventMap),
|
||||
array_values($tableEventMap),
|
||||
@@ -663,8 +694,37 @@ class Event
|
||||
|
||||
$events = $pairedEvents;
|
||||
}
|
||||
// mirrored events can have duplicates in case of smaller events
|
||||
return array_unique($events);
|
||||
}
|
||||
|
||||
return $events;
|
||||
/**
|
||||
* Maps event terminology based on database type
|
||||
*/
|
||||
private static function getDatabaseTypeEvents(Document $database, array $event): array
|
||||
{
|
||||
$eventMap = [];
|
||||
switch ($database->getAttribute('type')) {
|
||||
case 'tablesdb':
|
||||
$eventMap = [
|
||||
'databases' => 'tablesdb',
|
||||
'documents' => 'rows',
|
||||
'collections' => 'tables',
|
||||
'attributes' => 'columns',
|
||||
];
|
||||
break;
|
||||
case 'documentsdb':
|
||||
$eventMap = [
|
||||
'databases' => 'documentsdb'
|
||||
];
|
||||
break;
|
||||
}
|
||||
foreach ($event as $eventKey => $eventValue) {
|
||||
if (isset($eventMap[$eventValue])) {
|
||||
$event[$eventKey] = $eventMap[$eventValue];
|
||||
}
|
||||
}
|
||||
return $event;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -72,7 +72,7 @@ class Realtime extends Event
|
||||
return false;
|
||||
}
|
||||
|
||||
$allEvents = Event::generateEvents($this->getEvent(), $this->getParams());
|
||||
$allEvents = Event::generateEvents($this->getEvent(), $this->getParams(), $this->getContext('database'));
|
||||
|
||||
$payload = new Document($this->getPayload());
|
||||
|
||||
|
||||
@@ -84,6 +84,7 @@ class StatsUsage extends Event
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
'context' => $this->context,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,7 +178,6 @@ class Realtime extends MessagingAdapter
|
||||
*/
|
||||
public function getSubscribers(array $event): array
|
||||
{
|
||||
|
||||
$receivers = [];
|
||||
/**
|
||||
* Check if project has subscriber.
|
||||
@@ -298,6 +297,8 @@ class Realtime extends MessagingAdapter
|
||||
$roles = [Role::team(ID::custom($parts[1]))->toString()];
|
||||
break;
|
||||
case 'databases':
|
||||
case 'tablesdb':
|
||||
case 'documentsdb':
|
||||
$resource = $parts[4] ?? '';
|
||||
if (in_array($resource, ['columns', 'attributes', 'indexes'])) {
|
||||
$channels[] = 'console';
|
||||
@@ -315,14 +316,25 @@ class Realtime extends MessagingAdapter
|
||||
$tableId = $payload->getAttribute('$tableId', '');
|
||||
$collectionId = $payload->getAttribute('$collectionId', '');
|
||||
$resourceId = $tableId ?: $collectionId;
|
||||
$channels = [];
|
||||
// backward compat(tablesdb will have databases channels + tablesdb prefixed channels)
|
||||
if ($parts[0] === 'databases' || $parts[0] === 'tablesdb') {
|
||||
$prefix = 'databases';
|
||||
|
||||
$channels[] = 'rows';
|
||||
$channels[] = 'databases.' . $database->getId() . '.tables.' . $resourceId . '.rows';
|
||||
$channels[] = 'databases.' . $database->getId() . '.tables.' . $resourceId . '.rows.' . $payload->getId();
|
||||
$channels = self::getDatabaseChannels('legacy', $database->getId(), $resourceId, $payload->getId(), $prefix);
|
||||
|
||||
$channels[] = 'documents';
|
||||
$channels[] = 'databases.' . $database->getId() . '.collections.' . $resourceId . '.documents';
|
||||
$channels[] = 'databases.' . $database->getId() . '.collections.' . $resourceId . '.documents.' . $payload->getId();
|
||||
$channels = array_unique([
|
||||
...$channels,
|
||||
...self::getDatabaseChannels('tablesdb', $database->getId(), $resourceId, $payload->getId(), $prefix)
|
||||
]);
|
||||
}
|
||||
// prefixed channels -> tablesdb, documentsdb,etc
|
||||
if ($parts[0] !== 'databases') {
|
||||
$channels = array_unique([
|
||||
...$channels,
|
||||
...self::getDatabaseChannels($parts[0], $database->getId(), $resourceId, $payload->getId()),
|
||||
]);
|
||||
}
|
||||
|
||||
$roles = $collection->getAttribute('documentSecurity', false)
|
||||
? \array_merge($collection->getRead(), $payload->getRead())
|
||||
@@ -379,4 +391,63 @@ class Realtime extends MessagingAdapter
|
||||
'projectId' => $projectId
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate realtime channels for database events
|
||||
*
|
||||
* @param string $type The database API type
|
||||
* @param string $databaseId The database ID
|
||||
* @param string $resourceId The collection/table ID
|
||||
* @param string $payloadId The document/row ID
|
||||
* @param string $prefixOverride Override the channel prefix when different API types share the same terminology but need different prefixes
|
||||
* (e.g., 'databases' and 'documentsdb' use same terminology but need different prefixes)
|
||||
* @return array Array of channel names
|
||||
*/
|
||||
private static function getDatabaseChannels(
|
||||
string $type = 'databases',
|
||||
string $databaseId = '',
|
||||
string $resourceId = '',
|
||||
string $payloadId = '',
|
||||
string $prefixOverride = '',
|
||||
): array {
|
||||
$basePrefix = $prefixOverride ?: $type;
|
||||
|
||||
if (!$databaseId || !$resourceId || !$payloadId) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$channels = [];
|
||||
|
||||
switch ($type) {
|
||||
case 'legacy':
|
||||
if (empty($prefixOverride)) {
|
||||
$basePrefix = 'databases';
|
||||
}
|
||||
$channels[] = 'documents';
|
||||
$channels[] = "{$basePrefix}.{$databaseId}.collections.{$resourceId}.documents";
|
||||
$channels[] = "{$basePrefix}.{$databaseId}.collections.{$resourceId}.documents.{$payloadId}";
|
||||
break;
|
||||
case 'tablesdb':
|
||||
$channels[] = 'rows';
|
||||
$channels[] = "{$basePrefix}.{$databaseId}.tables.{$resourceId}.rows";
|
||||
$channels[] = "{$basePrefix}.{$databaseId}.tables.{$resourceId}.rows.{$payloadId}";
|
||||
break;
|
||||
|
||||
case 'documentsdb':
|
||||
$channels[] = 'documents';
|
||||
$channels[] = "{$basePrefix}.{$databaseId}.collections.{$resourceId}.documents";
|
||||
$channels[] = "{$basePrefix}.{$databaseId}.collections.{$resourceId}.documents.{$payloadId}";
|
||||
break;
|
||||
|
||||
default:
|
||||
$basePrefix = 'databases';
|
||||
$channels[] = 'documents';
|
||||
$channels[] = "{$basePrefix}.{$databaseId}.collections.{$resourceId}.documents";
|
||||
$channels[] = "{$basePrefix}.{$databaseId}.collections.{$resourceId}.documents.{$payloadId}";
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return $channels;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,3 +22,6 @@ const INDEX = 'index';
|
||||
const DOCUMENTS = 'document';
|
||||
const ATTRIBUTES = 'attribute';
|
||||
const COLLECTIONS = 'collection';
|
||||
|
||||
const TABLESDB = 'tablesdb';
|
||||
const DOCUMENTSDB = 'documentsdb';
|
||||
|
||||
@@ -10,7 +10,7 @@ use Utopia\Database\Operator;
|
||||
|
||||
class Action extends AppwriteAction
|
||||
{
|
||||
private string $context = 'legacy';
|
||||
private string $context = DATABASE_TYPE_LEGACY;
|
||||
|
||||
public function getDatabaseType(): string
|
||||
{
|
||||
@@ -20,7 +20,10 @@ class Action extends AppwriteAction
|
||||
public function setHttpPath(string $path): AppwriteAction
|
||||
{
|
||||
if (\str_contains($path, '/tablesdb')) {
|
||||
$this->context = 'tablesdb';
|
||||
$this->context = DATABASE_TYPE_TABLESDB;
|
||||
}
|
||||
if (\str_contains($path, '/documentsdb')) {
|
||||
$this->context = DATABASE_TYPE_DOCUMENTSDB;
|
||||
}
|
||||
return parent::setHttpPath($path);
|
||||
}
|
||||
|
||||
+3
-3
@@ -59,9 +59,9 @@ class Create extends Action
|
||||
replaceWith: 'tablesDB.createBooleanColumn',
|
||||
),
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).')
|
||||
->param('key', '', new Key(), 'Attribute Key.')
|
||||
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->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.', true)
|
||||
->param('array', false, new Boolean(), 'Is attribute an array?', true)
|
||||
|
||||
+4
-4
@@ -59,12 +59,12 @@ class Update extends Action
|
||||
replaceWith: 'tablesDB.updateBooleanColumn',
|
||||
),
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#createCollection).')
|
||||
->param('key', '', new Key(), 'Attribute Key.')
|
||||
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#createCollection).', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->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 Nullable(new Key()), 'New attribute key.', true)
|
||||
->param('newKey', null, fn (Database $dbForProject) => new Nullable(new Key(false, $dbForProject->getAdapter()->getMaxUIDLength())), 'New attribute key.', true, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
|
||||
+3
-3
@@ -60,9 +60,9 @@ class Create extends Action
|
||||
replaceWith: 'tablesDB.createDatetimeColumn',
|
||||
),
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#createCollection).')
|
||||
->param('key', '', new Key(), 'Attribute Key.')
|
||||
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#createCollection).', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->param('required', null, new Boolean(), 'Is attribute required?')
|
||||
->param('default', null, fn (Database $dbForProject) => new Nullable(new DatetimeValidator($dbForProject->getAdapter()->getMinDateTime(), $dbForProject->getAdapter()->getMaxDateTime())), 'Default value for the attribute in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Cannot be set when attribute is required.', true, ['dbForProject'])
|
||||
->param('array', false, new Boolean(), 'Is attribute an array?', true)
|
||||
|
||||
+4
-4
@@ -60,12 +60,12 @@ class Update extends Action
|
||||
replaceWith: 'tablesDB.updateDatetimeColumn',
|
||||
),
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID.')
|
||||
->param('key', '', new Key(), 'Attribute Key.')
|
||||
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID.', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->param('required', null, new Boolean(), 'Is attribute required?')
|
||||
->param('default', null, fn (Database $dbForProject) => new Nullable(new DatetimeValidator($dbForProject->getAdapter()->getMinDateTime(), $dbForProject->getAdapter()->getMaxDateTime())), 'Default value for attribute when not provided. Cannot be set when attribute is required.', injections: ['dbForProject'])
|
||||
->param('newKey', null, new Nullable(new Key()), 'New attribute key.', true)
|
||||
->param('newKey', null, fn (Database $dbForProject) => new Nullable(new Key(false, $dbForProject->getAdapter()->getMaxUIDLength())), 'New attribute key.', true, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
|
||||
+3
-3
@@ -60,9 +60,9 @@ class Delete extends Action
|
||||
replaceWith: 'tablesDB.deleteColumn',
|
||||
),
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID.')
|
||||
->param('key', '', new Key(), 'Attribute Key.')
|
||||
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID.', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForDatabase')
|
||||
|
||||
+3
-3
@@ -60,9 +60,9 @@ class Create extends Action
|
||||
replaceWith: 'tablesDB.createEmailColumn',
|
||||
),
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID.')
|
||||
->param('key', '', new Key(), 'Attribute Key.')
|
||||
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID.', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->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.', true)
|
||||
->param('array', false, new Boolean(), 'Is attribute an array?', true)
|
||||
|
||||
+4
-4
@@ -60,12 +60,12 @@ class Update extends Action
|
||||
replaceWith: 'tablesDB.updateEmailColumn',
|
||||
),
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID.')
|
||||
->param('key', '', new Key(), 'Attribute Key.')
|
||||
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID.', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->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 Nullable(new Key()), 'New Attribute Key.', true)
|
||||
->param('newKey', null, fn (Database $dbForProject) => new Nullable(new Key(false, $dbForProject->getAdapter()->getMaxUIDLength())), 'New Attribute Key.', true, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
|
||||
+3
-3
@@ -62,9 +62,9 @@ class Create extends Action
|
||||
replaceWith: 'tablesDB.createEnumColumn',
|
||||
),
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID.')
|
||||
->param('key', '', new Key(), 'Attribute Key.')
|
||||
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID.', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->param('elements', [], new ArrayList(new Text(Database::LENGTH_KEY), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of enum values.')
|
||||
->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.', true)
|
||||
|
||||
+4
-4
@@ -61,13 +61,13 @@ class Update extends Action
|
||||
replaceWith: 'tablesDB.updateEnumColumn',
|
||||
),
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID.')
|
||||
->param('key', '', new Key(), 'Attribute Key.')
|
||||
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID.', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->param('elements', null, new ArrayList(new Text(Database::LENGTH_KEY), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Updated list of enum values.')
|
||||
->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 Nullable(new Key()), 'New Attribute Key.', true)
|
||||
->param('newKey', null, fn (Database $dbForProject) => new Nullable(new Key(false, $dbForProject->getAdapter()->getMaxUIDLength())), 'New Attribute Key.', true, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
|
||||
+3
-3
@@ -62,9 +62,9 @@ class Create extends Action
|
||||
replaceWith: 'tablesDB.createFloatColumn',
|
||||
),
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID.')
|
||||
->param('key', '', new Key(), 'Attribute Key.')
|
||||
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID.', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->param('required', null, new Boolean(), 'Is attribute required?')
|
||||
->param('min', null, new Nullable(new FloatValidator()), 'Minimum value.', true)
|
||||
->param('max', null, new Nullable(new FloatValidator()), 'Maximum value.', true)
|
||||
|
||||
+4
-4
@@ -60,14 +60,14 @@ class Update extends Action
|
||||
replaceWith: 'tablesDB.updateFloatColumn',
|
||||
),
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID.')
|
||||
->param('key', '', new Key(), 'Attribute Key.')
|
||||
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID.', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->param('required', null, new Boolean(), 'Is attribute required?')
|
||||
->param('min', null, new Nullable(new FloatValidator()), 'Minimum value.', true)
|
||||
->param('max', null, new Nullable(new FloatValidator()), 'Maximum value.', true)
|
||||
->param('default', null, new Nullable(new FloatValidator()), 'Default value. Cannot be set when required.')
|
||||
->param('newKey', null, new Nullable(new Key()), 'New Attribute Key.', true)
|
||||
->param('newKey', null, fn (Database $dbForProject) => new Nullable(new Key(false, $dbForProject->getAdapter()->getMaxUIDLength())), 'New Attribute Key.', true, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
|
||||
+3
-3
@@ -63,9 +63,9 @@ class Get extends Action
|
||||
replaceWith: 'tablesDB.getColumn',
|
||||
),
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID.')
|
||||
->param('key', '', new Key(), 'Attribute Key.')
|
||||
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID.', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->callback($this->action(...));
|
||||
|
||||
+3
-3
@@ -60,9 +60,9 @@ class Create extends Action
|
||||
replaceWith: 'tablesDB.createIpColumn',
|
||||
),
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID.')
|
||||
->param('key', '', new Key(), 'Attribute Key.')
|
||||
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID.', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->param('required', null, new Boolean(), 'Is attribute required?')
|
||||
->param('default', null, new Nullable(new IP()), 'Default value. Cannot be set when attribute is required.', true)
|
||||
->param('array', false, new Boolean(), 'Is attribute an array?', true)
|
||||
|
||||
+4
-4
@@ -60,12 +60,12 @@ class Update extends Action
|
||||
replaceWith: 'tablesDB.updateIpColumn',
|
||||
),
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID.')
|
||||
->param('key', '', new Key(), 'Attribute Key.')
|
||||
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID.', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->param('required', null, new Boolean(), 'Is attribute required?')
|
||||
->param('default', null, new Nullable(new IP()), 'Default value. Cannot be set when attribute is required.')
|
||||
->param('newKey', null, new Nullable(new Key()), 'New Attribute Key.', true)
|
||||
->param('newKey', null, fn (Database $dbForProject) => new Nullable(new Key(false, $dbForProject->getAdapter()->getMaxUIDLength())), 'New Attribute Key.', true, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
|
||||
+3
-3
@@ -62,9 +62,9 @@ class Create extends Action
|
||||
replaceWith: 'tablesDB.createIntegerColumn',
|
||||
),
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID.')
|
||||
->param('key', '', new Key(), 'Attribute Key.')
|
||||
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID.', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->param('required', null, new Boolean(), 'Is attribute required?')
|
||||
->param('min', null, new Nullable(new Integer()), 'Minimum value', true)
|
||||
->param('max', null, new Nullable(new Integer()), 'Maximum value', true)
|
||||
|
||||
+4
-4
@@ -60,14 +60,14 @@ class Update extends Action
|
||||
replaceWith: 'tablesDB.updateIntegerColumn',
|
||||
),
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID.')
|
||||
->param('key', '', new Key(), 'Attribute Key.')
|
||||
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID.', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->param('required', null, new Boolean(), 'Is attribute required?')
|
||||
->param('min', null, new Nullable(new Integer()), 'Minimum value', true)
|
||||
->param('max', null, new Nullable(new Integer()), 'Maximum value', true)
|
||||
->param('default', null, new Nullable(new Integer()), 'Default value. Cannot be set when attribute is required.')
|
||||
->param('newKey', null, new Nullable(new Key()), 'New Attribute Key.', true)
|
||||
->param('newKey', null, fn (Database $dbForProject) => new Nullable(new Key(false, $dbForProject->getAdapter()->getMaxUIDLength())), 'New Attribute Key.', true, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
|
||||
+3
-3
@@ -60,9 +60,9 @@ class Create extends Action
|
||||
replaceWith: 'tablesDB.createLineColumn',
|
||||
),
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->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('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->param('required', null, new Boolean(), 'Is attribute required?')
|
||||
->param('default', null, new Nullable(new Spatial(Database::VAR_LINESTRING)), 'Default value for attribute when not provided, two-dimensional array of coordinate pairs, [[longitude, latitude], [longitude, latitude], …], listing the vertices of the line in order. Cannot be set when attribute is required.', true)
|
||||
->inject('response')
|
||||
|
||||
+4
-4
@@ -60,12 +60,12 @@ class Update extends Action
|
||||
replaceWith: 'tablesDB.updateLineColumn',
|
||||
),
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#createCollection).')
|
||||
->param('key', '', new Key(), 'Attribute Key.')
|
||||
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#createCollection).', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->param('required', null, new Boolean(), 'Is attribute required?')
|
||||
->param('default', null, new Nullable(new Spatial(Database::VAR_LINESTRING)), 'Default value for attribute when not provided, two-dimensional array of coordinate pairs, [[longitude, latitude], [longitude, latitude], …], listing the vertices of the line in order. Cannot be set when attribute is required.', true)
|
||||
->param('newKey', null, new Nullable(new Key()), 'New attribute key.', true)
|
||||
->param('newKey', null, fn (Database $dbForProject) => new Nullable(new Key(false, $dbForProject->getAdapter()->getMaxUIDLength())), 'New attribute key.', true, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
|
||||
+3
-3
@@ -60,9 +60,9 @@ class Create extends Action
|
||||
replaceWith: 'tablesDB.createPointColumn',
|
||||
),
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->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('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->param('required', null, new Boolean(), 'Is attribute required?')
|
||||
->param('default', null, new Nullable(new Spatial(Database::VAR_POINT)), 'Default value for attribute when not provided, array of two numbers [longitude, latitude], representing a single coordinate. Cannot be set when attribute is required.', true)
|
||||
->inject('response')
|
||||
|
||||
+4
-4
@@ -60,12 +60,12 @@ class Update extends Action
|
||||
replaceWith: 'tablesDB.updatePointColumn',
|
||||
),
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#createCollection).')
|
||||
->param('key', '', new Key(), 'Attribute Key.')
|
||||
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#createCollection).', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->param('required', null, new Boolean(), 'Is attribute required?')
|
||||
->param('default', null, new Nullable(new Spatial(Database::VAR_POINT)), 'Default value for attribute when not provided, array of two numbers [longitude, latitude], representing a single coordinate. Cannot be set when attribute is required.', true)
|
||||
->param('newKey', null, new Nullable(new Key()), 'New attribute key.', true)
|
||||
->param('newKey', null, fn (Database $dbForProject) => new Nullable(new Key(false, $dbForProject->getAdapter()->getMaxUIDLength())), 'New attribute key.', true, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
|
||||
+3
-3
@@ -60,9 +60,9 @@ class Create extends Action
|
||||
replaceWith: 'tablesDB.createPolygonColumn',
|
||||
),
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->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('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->param('required', null, new Boolean(), 'Is attribute required?')
|
||||
->param('default', null, new Nullable(new Spatial(Database::VAR_POLYGON)), 'Default value for attribute when not provided, three-dimensional array where the outer array holds one or more linear rings, [[[longitude, latitude], …], …], the first ring is the exterior boundary, any additional rings are interior holes, and each ring must start and end with the same coordinate pair. Cannot be set when attribute is required.', true)
|
||||
->inject('response')
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user