mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Merge branch '1.8.x' into 'bump-migrations'.
This commit is contained in:
@@ -85,8 +85,9 @@ _APP_COMPUTE_MAINTENANCE_INTERVAL=600
|
||||
_APP_COMPUTE_RUNTIMES_NETWORK=runtimes
|
||||
_APP_EXECUTOR_SECRET=your-secret-key
|
||||
_APP_EXECUTOR_HOST=http://exc1/v1
|
||||
_APP_FUNCTIONS_RUNTIMES=php-8.0,node-18.0,python-3.9,ruby-3.1
|
||||
_APP_SITES_RUNTIMES=static-1,node-22,flutter-3.32
|
||||
_APP_BROWSER_HOST=http://appwrite-browser:3000/v1
|
||||
_APP_FUNCTIONS_RUNTIMES=node-22
|
||||
_APP_SITES_RUNTIMES=static-1,node-22
|
||||
_APP_MAINTENANCE_INTERVAL=86400
|
||||
_APP_MAINTENANCE_START_TIME=12:00
|
||||
_APP_MAINTENANCE_RETENTION_CACHE=2592000
|
||||
|
||||
@@ -179,6 +179,7 @@ jobs:
|
||||
- name: Load and Start Appwrite
|
||||
run: |
|
||||
docker load --input /tmp/${{ env.IMAGE }}.tar
|
||||
sed -i 's|^_APP_BROWSER_HOST=.*|_APP_BROWSER_HOST=http://invalid-browser/v1|' .env
|
||||
docker compose up -d
|
||||
sleep 30
|
||||
|
||||
@@ -199,7 +200,7 @@ jobs:
|
||||
docker compose exec -T \
|
||||
-e _APP_DATABASE_SHARED_TABLES \
|
||||
-e _APP_DATABASE_SHARED_TABLES_V1 \
|
||||
appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug --exclude-group devKeys
|
||||
appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug --exclude-group devKeys,screenshots
|
||||
|
||||
e2e_shared_mode_test:
|
||||
name: E2E Shared Mode Service Test
|
||||
@@ -279,7 +280,7 @@ jobs:
|
||||
docker compose exec -T \
|
||||
-e _APP_DATABASE_SHARED_TABLES \
|
||||
-e _APP_DATABASE_SHARED_TABLES_V1 \
|
||||
appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug --exclude-group devKeys
|
||||
appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug --exclude-group devKeys,screenshots
|
||||
|
||||
e2e_dev_keys:
|
||||
name: E2E Service Test (Dev Keys)
|
||||
@@ -360,3 +361,85 @@ jobs:
|
||||
-e _APP_DATABASE_SHARED_TABLES \
|
||||
-e _APP_DATABASE_SHARED_TABLES_V1 \
|
||||
appwrite test /usr/src/code/tests/e2e/Services/Projects --debug --group=devKeys
|
||||
|
||||
e2e_screenshots_keys:
|
||||
name: E2E Service Test (Site Screenshots)
|
||||
runs-on: ubuntu-latest
|
||||
needs: setup
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Load Cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
key: ${{ env.CACHE_KEY }}
|
||||
path: /tmp/${{ env.IMAGE }}.tar
|
||||
fail-on-cache-miss: true
|
||||
|
||||
- name: Load and Start Appwrite
|
||||
run: |
|
||||
docker load --input /tmp/${{ env.IMAGE }}.tar
|
||||
sed -i 's/_APP_OPTIONS_ABUSE=disabled/_APP_OPTIONS_ABUSE=enabled/' .env
|
||||
docker compose up -d
|
||||
sleep 30
|
||||
|
||||
- name: Run Site tests with browser connected in dedicated table mode
|
||||
run: |
|
||||
echo "Keeping original value of _APP_BROWSER_HOST"
|
||||
echo "Using project tables"
|
||||
export _APP_DATABASE_SHARED_TABLES=
|
||||
export _APP_DATABASE_SHARED_TABLES_V1=
|
||||
|
||||
docker compose exec -T \
|
||||
-e _APP_DATABASE_SHARED_TABLES \
|
||||
-e _APP_DATABASE_SHARED_TABLES_V1 \
|
||||
appwrite test /usr/src/code/tests/e2e/Services/Sites --debug --group=screenshots
|
||||
|
||||
e2e_screenshots_shared_mode:
|
||||
name: E2E Shared Mode Service Test (Site Screenshots)
|
||||
runs-on: ubuntu-latest
|
||||
needs: [ setup, check_database_changes ]
|
||||
if: needs.check_database_changes.outputs.database_changed == 'true'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
tables-mode: [
|
||||
'Shared V1',
|
||||
'Shared V2',
|
||||
]
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Load Cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
key: ${{ env.CACHE_KEY }}
|
||||
path: /tmp/${{ env.IMAGE }}.tar
|
||||
fail-on-cache-miss: true
|
||||
|
||||
- name: Load and Start Appwrite
|
||||
run: |
|
||||
docker load --input /tmp/${{ env.IMAGE }}.tar
|
||||
sed -i 's/_APP_OPTIONS_ABUSE=disabled/_APP_OPTIONS_ABUSE=enabled/' .env
|
||||
docker compose up -d
|
||||
sleep 30
|
||||
|
||||
- name: Run Site tests with browser connected in ${{ matrix.tables-mode }} table mode
|
||||
run: |
|
||||
echo "Keeping original value of _APP_BROWSER_HOST"
|
||||
if [ "${{ matrix.tables-mode }}" == "Shared V1" ]; then
|
||||
echo "Using shared tables V1"
|
||||
export _APP_DATABASE_SHARED_TABLES=database_db_main
|
||||
export _APP_DATABASE_SHARED_TABLES_V1=database_db_main
|
||||
elif [ "${{ matrix.tables-mode }}" == "Shared V2" ]; then
|
||||
echo "Using shared tables V2"
|
||||
export _APP_DATABASE_SHARED_TABLES=database_db_main
|
||||
export _APP_DATABASE_SHARED_TABLES_V1=
|
||||
fi
|
||||
|
||||
docker compose exec -T \
|
||||
-e _APP_DATABASE_SHARED_TABLES \
|
||||
-e _APP_DATABASE_SHARED_TABLES_V1 \
|
||||
appwrite test /usr/src/code/tests/e2e/Services/Sites --debug --group=screenshots
|
||||
|
||||
@@ -134,7 +134,7 @@ return [
|
||||
[
|
||||
'key' => 'react-native',
|
||||
'name' => 'React Native',
|
||||
'version' => '0.10.0',
|
||||
'version' => '0.10.1',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-react-native',
|
||||
'package' => 'https://npmjs.com/package/react-native-appwrite',
|
||||
'enabled' => true,
|
||||
@@ -217,7 +217,7 @@ return [
|
||||
[
|
||||
'key' => 'cli',
|
||||
'name' => 'Command Line',
|
||||
'version' => '8.1.0',
|
||||
'version' => '8.2.1',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-cli',
|
||||
'package' => 'https://www.npmjs.com/package/appwrite-cli',
|
||||
'enabled' => true,
|
||||
@@ -250,7 +250,7 @@ return [
|
||||
[
|
||||
'key' => 'nodejs',
|
||||
'name' => 'Node.js',
|
||||
'version' => '17.0.0',
|
||||
'version' => '17.1.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-node',
|
||||
'package' => 'https://www.npmjs.com/package/node-appwrite',
|
||||
'enabled' => true,
|
||||
@@ -358,7 +358,7 @@ return [
|
||||
[
|
||||
'key' => 'dotnet',
|
||||
'name' => '.NET',
|
||||
'version' => '0.13.0',
|
||||
'version' => '0.14.0',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-dotnet',
|
||||
'package' => 'https://www.nuget.org/packages/Appwrite',
|
||||
'enabled' => true,
|
||||
|
||||
@@ -1189,9 +1189,16 @@ App::get('/v1/account/sessions/oauth2/:provider')
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
->action(function (string $provider, string $success, string $failure, array $scopes, Request $request, Response $response, Document $project) use ($oauthDefaultSuccess, $oauthDefaultFailure) {
|
||||
$protocol = $request->getProtocol();
|
||||
$protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') === 'disabled' ? 'http' : 'https';
|
||||
$port = $request->getPort();
|
||||
$callbackBase = $protocol . '://' . $request->getHostname();
|
||||
if ($protocol === 'https' && $port !== '443') {
|
||||
$callbackBase .= ':' . $port;
|
||||
} elseif ($protocol === 'http' && $port !== '80') {
|
||||
$callbackBase .= ':' . $port;
|
||||
}
|
||||
|
||||
$callback = $protocol . '://' . $request->getHostname() . '/v1/account/sessions/oauth2/callback/' . $provider . '/' . $project->getId();
|
||||
$callback = $callbackBase . '/v1/account/sessions/oauth2/callback/' . $provider . '/' . $project->getId();
|
||||
$providerEnabled = $project->getAttribute('oAuthProviders', [])[$provider . 'Enabled'] ?? false;
|
||||
|
||||
if (!$providerEnabled) {
|
||||
@@ -1216,12 +1223,20 @@ App::get('/v1/account/sessions/oauth2/:provider')
|
||||
throw new Exception(Exception::PROJECT_PROVIDER_UNSUPPORTED);
|
||||
}
|
||||
|
||||
$host = System::getEnv('_APP_CONSOLE_DOMAIN', System::getEnv('_APP_DOMAIN', ''));
|
||||
$redirectBase = $protocol . '://' . $host;
|
||||
if ($protocol === 'https' && $port !== '443') {
|
||||
$redirectBase .= ':' . $port;
|
||||
} elseif ($protocol === 'http' && $port !== '80') {
|
||||
$redirectBase .= ':' . $port;
|
||||
}
|
||||
|
||||
if (empty($success)) {
|
||||
$success = $protocol . '://' . $request->getHostname() . $oauthDefaultSuccess;
|
||||
$success = $redirectBase . $oauthDefaultSuccess;
|
||||
}
|
||||
|
||||
if (empty($failure)) {
|
||||
$failure = $protocol . '://' . $request->getHostname() . $oauthDefaultFailure;
|
||||
$failure = $redirectBase . $oauthDefaultFailure;
|
||||
}
|
||||
|
||||
$oauth2 = new $className($appId, $appSecret, $callback, [
|
||||
@@ -1251,9 +1266,14 @@ App::get('/v1/account/sessions/oauth2/callback/:provider/:projectId')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->action(function (string $projectId, string $provider, string $code, string $state, string $error, string $error_description, Request $request, Response $response) {
|
||||
|
||||
$domain = $request->getHostname();
|
||||
$protocol = $request->getProtocol();
|
||||
$protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') === 'disabled' ? 'http' : 'https';
|
||||
$port = $request->getPort();
|
||||
$callbackBase = $protocol . '://' . $request->getHostname();
|
||||
if ($protocol === 'https' && $port !== '443') {
|
||||
$callbackBase .= ':' . $port;
|
||||
} elseif ($protocol === 'http' && $port !== '80') {
|
||||
$callbackBase .= ':' . $port;
|
||||
}
|
||||
|
||||
$params = $request->getParams();
|
||||
$params['project'] = $projectId;
|
||||
@@ -1262,7 +1282,7 @@ App::get('/v1/account/sessions/oauth2/callback/:provider/:projectId')
|
||||
$response
|
||||
->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
|
||||
->addHeader('Pragma', 'no-cache')
|
||||
->redirect($protocol . '://' . $domain . '/v1/account/sessions/oauth2/' . $provider . '/redirect?'
|
||||
->redirect($callbackBase . '/v1/account/sessions/oauth2/' . $provider . '/redirect?'
|
||||
. \http_build_query($params));
|
||||
});
|
||||
|
||||
@@ -1282,8 +1302,14 @@ App::post('/v1/account/sessions/oauth2/callback/:provider/:projectId')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->action(function (string $projectId, string $provider, string $code, string $state, string $error, string $error_description, Request $request, Response $response) {
|
||||
$domain = $request->getHostname();
|
||||
$protocol = $request->getProtocol();
|
||||
$protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') === 'disabled' ? 'http' : 'https';
|
||||
$port = $request->getPort();
|
||||
$callbackBase = $protocol . '://' . $request->getHostname();
|
||||
if ($protocol === 'https' && $port !== '443') {
|
||||
$callbackBase .= ':' . $port;
|
||||
} elseif ($protocol === 'http' && $port !== '80') {
|
||||
$callbackBase .= ':' . $port;
|
||||
}
|
||||
|
||||
$params = $request->getParams();
|
||||
$params['project'] = $projectId;
|
||||
@@ -1292,7 +1318,7 @@ App::post('/v1/account/sessions/oauth2/callback/:provider/:projectId')
|
||||
$response
|
||||
->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
|
||||
->addHeader('Pragma', 'no-cache')
|
||||
->redirect($protocol . '://' . $domain . '/v1/account/sessions/oauth2/' . $provider . '/redirect?'
|
||||
->redirect($callbackBase . '/v1/account/sessions/oauth2/' . $provider . '/redirect?'
|
||||
. \http_build_query($params));
|
||||
});
|
||||
|
||||
@@ -1316,15 +1342,24 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
->inject('platforms')
|
||||
->inject('devKey')
|
||||
->inject('user')
|
||||
->inject('dbForProject')
|
||||
->inject('geodb')
|
||||
->inject('queueForEvents')
|
||||
->action(function (string $provider, string $code, string $state, string $error, string $error_description, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Reader $geodb, Event $queueForEvents) use ($oauthDefaultSuccess) {
|
||||
$protocol = $request->getProtocol();
|
||||
$callback = $protocol . '://' . $request->getHostname() . '/v1/account/sessions/oauth2/callback/' . $provider . '/' . $project->getId();
|
||||
->action(function (string $provider, string $code, string $state, string $error, string $error_description, Request $request, Response $response, Document $project, array $platforms, Document $devKey, Document $user, Database $dbForProject, Reader $geodb, Event $queueForEvents) use ($oauthDefaultSuccess) {
|
||||
$protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') === 'disabled' ? 'http' : 'https';
|
||||
$port = $request->getPort();
|
||||
$callbackBase = $protocol . '://' . $request->getHostname();
|
||||
if ($protocol === 'https' && $port !== '443') {
|
||||
$callbackBase .= ':' . $port;
|
||||
} elseif ($protocol === 'http' && $port !== '80') {
|
||||
$callbackBase .= ':' . $port;
|
||||
}
|
||||
$callback = $callbackBase . '/v1/account/sessions/oauth2/callback/' . $provider . '/' . $project->getId();
|
||||
$defaultState = ['success' => $project->getAttribute('url', ''), 'failure' => ''];
|
||||
$validateURL = new URL();
|
||||
$redirect = new Redirect($platforms);
|
||||
$appId = $project->getAttribute('oAuthProviders', [])[$provider . 'Appid'] ?? '';
|
||||
$appSecret = $project->getAttribute('oAuthProviders', [])[$provider . 'Secret'] ?? '{}';
|
||||
$providerEnabled = $project->getAttribute('oAuthProviders', [])[$provider . 'Enabled'] ?? false;
|
||||
@@ -1351,11 +1386,11 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
||||
$state = $defaultState;
|
||||
}
|
||||
|
||||
if (!$validateURL->isValid($state['success'])) {
|
||||
if ($devKey->isEmpty() && !$redirect->isValid($state['success'])) {
|
||||
throw new Exception(Exception::PROJECT_INVALID_SUCCESS_URL);
|
||||
}
|
||||
|
||||
if (!empty($state['failure']) && !$validateURL->isValid($state['failure'])) {
|
||||
if ($devKey->isEmpty() && !empty($state['failure']) && !$redirect->isValid($state['failure'])) {
|
||||
throw new Exception(Exception::PROJECT_INVALID_FAILURE_URL);
|
||||
}
|
||||
$failure = [];
|
||||
@@ -1422,13 +1457,13 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
||||
|
||||
$name = '';
|
||||
$nameOAuth = $oauth2->getUserName($accessToken);
|
||||
$userParam = \json_decode($request->getParam('user'), true);
|
||||
$userParam = $request->getParam('user');
|
||||
if (!empty($nameOAuth)) {
|
||||
$name = $nameOAuth;
|
||||
} elseif (is_array($userParam)) {
|
||||
$nameParam = $userParam['name'];
|
||||
if (is_array($nameParam) && isset($nameParam['firstName']) && isset($nameParam['lastName'])) {
|
||||
$name = $nameParam['firstName'] . ' ' . $nameParam['lastName'];
|
||||
} elseif ($userParam !== null) {
|
||||
$userDecoded = \json_decode($userParam, true);
|
||||
if (isset($userDecoded['name']['firstName']) && isset($userDecoded['name']['lastName'])) {
|
||||
$name = $userDecoded['name']['firstName'] . ' ' . $userDecoded['name']['lastName'];
|
||||
}
|
||||
}
|
||||
$email = $oauth2->getUserEmail($accessToken);
|
||||
@@ -1746,8 +1781,6 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
||||
$state['success']['query'] = URLParser::unparseQuery($query);
|
||||
$state['success'] = URLParser::unparse($state['success']);
|
||||
|
||||
$expire = DateTime::formatTz(DateTime::addSeconds(new \DateTime(), $duration));
|
||||
|
||||
$response
|
||||
->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
|
||||
->addHeader('Pragma', 'no-cache')
|
||||
@@ -1785,9 +1818,16 @@ App::get('/v1/account/tokens/oauth2/:provider')
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
->action(function (string $provider, string $success, string $failure, array $scopes, Request $request, Response $response, Document $project) use ($oauthDefaultSuccess, $oauthDefaultFailure) {
|
||||
$protocol = $request->getProtocol();
|
||||
$protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') === 'disabled' ? 'http' : 'https';
|
||||
$port = $request->getPort();
|
||||
$callbackBase = $protocol . '://' . $request->getHostname();
|
||||
if ($protocol === 'https' && $port !== '443') {
|
||||
$callbackBase .= ':' . $port;
|
||||
} elseif ($protocol === 'http' && $port !== '80') {
|
||||
$callbackBase .= ':' . $port;
|
||||
}
|
||||
|
||||
$callback = $protocol . '://' . $request->getHostname() . '/v1/account/sessions/oauth2/callback/' . $provider . '/' . $project->getId();
|
||||
$callback = $callbackBase . '/v1/account/sessions/oauth2/callback/' . $provider . '/' . $project->getId();
|
||||
$providerEnabled = $project->getAttribute('oAuthProviders', [])[$provider . 'Enabled'] ?? false;
|
||||
|
||||
if (!$providerEnabled) {
|
||||
@@ -1812,12 +1852,20 @@ App::get('/v1/account/tokens/oauth2/:provider')
|
||||
throw new Exception(Exception::PROJECT_PROVIDER_UNSUPPORTED);
|
||||
}
|
||||
|
||||
$host = System::getEnv('_APP_CONSOLE_DOMAIN', System::getEnv('_APP_DOMAIN', ''));
|
||||
$redirectBase = $protocol . '://' . $host;
|
||||
if ($protocol === 'https' && $port !== '443') {
|
||||
$redirectBase .= ':' . $port;
|
||||
} elseif ($protocol === 'http' && $port !== '80') {
|
||||
$redirectBase .= ':' . $port;
|
||||
}
|
||||
|
||||
if (empty($success)) {
|
||||
$success = $protocol . '://' . $request->getHostname() . $oauthDefaultSuccess;
|
||||
$success = $redirectBase . $oauthDefaultSuccess;
|
||||
}
|
||||
|
||||
if (empty($failure)) {
|
||||
$failure = $protocol . '://' . $request->getHostname() . $oauthDefaultFailure;
|
||||
$failure = $redirectBase . $oauthDefaultFailure;
|
||||
}
|
||||
|
||||
$oauth2 = new $className($appId, $appSecret, $callback, [
|
||||
@@ -1960,7 +2008,16 @@ App::post('/v1/account/tokens/magic-url')
|
||||
$dbForProject->purgeCachedDocument('users', $user->getId());
|
||||
|
||||
if (empty($url)) {
|
||||
$url = $request->getProtocol() . '://' . $request->getHostname() . '/console/auth/magic-url';
|
||||
$protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') === 'disabled' ? 'http' : 'https';
|
||||
$host = System::getEnv('_APP_CONSOLE_DOMAIN', System::getEnv('_APP_DOMAIN', ''));
|
||||
$port = $request->getPort();
|
||||
$callbackBase = $protocol . '://' . $host;
|
||||
if ($protocol === 'https' && $port !== '443') {
|
||||
$callbackBase .= ':' . $port;
|
||||
} elseif ($protocol === 'http' && $port !== '80') {
|
||||
$callbackBase .= ':' . $port;
|
||||
}
|
||||
$url = $callbackBase . '/console/auth/magic-url';
|
||||
}
|
||||
|
||||
$url = Template::parseURL($url);
|
||||
|
||||
@@ -967,6 +967,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Imagick extension is missing');
|
||||
}
|
||||
|
||||
/* @type Document $bucket */
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
|
||||
@@ -987,6 +988,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
||||
if ($fileSecurity && !$valid && !$isToken) {
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId);
|
||||
} else {
|
||||
/* @type Document $file */
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId));
|
||||
}
|
||||
|
||||
@@ -1157,7 +1159,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
||||
->inject('resourceToken')
|
||||
->inject('deviceForFiles')
|
||||
->action(function (string $bucketId, string $fileId, ?string $token, Request $request, Response $response, Database $dbForProject, string $mode, Document $resourceToken, Device $deviceForFiles) {
|
||||
|
||||
/* @type Document $bucket */
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
|
||||
@@ -1175,9 +1177,10 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
if ($fileSecurity && !$valid) {
|
||||
if ($fileSecurity && !$valid && !$isToken) {
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId);
|
||||
} else {
|
||||
/* @type Document $file */
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId));
|
||||
}
|
||||
|
||||
@@ -1317,6 +1320,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
||||
->inject('resourceToken')
|
||||
->inject('deviceForFiles')
|
||||
->action(function (string $bucketId, string $fileId, ?string $token, Response $response, Request $request, Database $dbForProject, string $mode, Document $resourceToken, Device $deviceForFiles) {
|
||||
/* @type Document $bucket */
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
|
||||
@@ -1334,9 +1338,10 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
if ($fileSecurity && !$valid) {
|
||||
if ($fileSecurity && !$valid && !$isToken) {
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId);
|
||||
} else {
|
||||
/* @type Document $file */
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getSequence(), $fileId));
|
||||
}
|
||||
|
||||
|
||||
@@ -129,32 +129,6 @@ App::get('/v1/mock/tests/general/oauth2/failure')
|
||||
]);
|
||||
});
|
||||
|
||||
App::patch('/v1/mock/functions-v2')
|
||||
->desc('Update Function Version to V2 (outdated code syntax)')
|
||||
->groups(['mock', 'api', 'functions'])
|
||||
->label('scope', 'functions.write')
|
||||
->label('docs', false)
|
||||
->param('functionId', '', new UID(), 'Function ID.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $functionId, Response $response, Database $dbForProject) {
|
||||
$isDevelopment = System::getEnv('_APP_ENV', 'development') === 'development';
|
||||
|
||||
if (!$isDevelopment) {
|
||||
throw new Exception(Exception::GENERAL_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
if ($function->isEmpty()) {
|
||||
throw new Exception(Exception::FUNCTION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$dbForProject->updateDocument('functions', $function->getId(), $function->setAttribute('version', 'v2'));
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
|
||||
App::post('/v1/mock/api-key-unprefixed')
|
||||
->desc('Create API Key (without standard prefix)')
|
||||
->groups(['mock', 'api', 'projects'])
|
||||
|
||||
@@ -576,7 +576,6 @@ App::init()
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
$isToken = !$resourceToken->isEmpty() && $resourceToken->getAttribute('bucketInternalId') === $bucket->getSequence();
|
||||
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
|
||||
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
|
||||
|
||||
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAppUser && !$isPrivilegedUser)) {
|
||||
|
||||
+3
-2
@@ -214,7 +214,7 @@ services:
|
||||
appwrite-console:
|
||||
<<: *x-logging
|
||||
container_name: appwrite-console
|
||||
image: appwrite/console:6.1.2
|
||||
image: appwrite/console:6.1.12
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
@@ -456,6 +456,7 @@ services:
|
||||
- redis
|
||||
- mariadb
|
||||
environment:
|
||||
- _APP_BROWSER_HOST
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
@@ -977,7 +978,7 @@ services:
|
||||
- OPR_EXECUTOR_ENV=$_APP_ENV
|
||||
- OPR_EXECUTOR_RUNTIMES=$_APP_FUNCTIONS_RUNTIMES,$_APP_SITES_RUNTIMES
|
||||
- OPR_EXECUTOR_SECRET=$_APP_EXECUTOR_SECRET
|
||||
- OPR_EXECUTOR_RUNTIME_VERSIONS=v2,v5
|
||||
- OPR_EXECUTOR_RUNTIME_VERSIONS=v5
|
||||
- OPR_EXECUTOR_LOGGING_CONFIG=$_APP_LOGGING_CONFIG
|
||||
- OPR_EXECUTOR_STORAGE_DEVICE=$_APP_STORAGE_DEVICE
|
||||
- OPR_EXECUTOR_STORAGE_S3_ACCESS_KEY=$_APP_STORAGE_S3_ACCESS_KEY
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
using Appwrite;
|
||||
using Appwrite.Models;
|
||||
using Appwrite.Services;
|
||||
|
||||
Client client = new Client()
|
||||
.SetEndPoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
|
||||
.SetProject("<YOUR_PROJECT_ID>") // Your project ID
|
||||
.SetSession(""); // The user session to authenticate with
|
||||
|
||||
Databases databases = new Databases(client);
|
||||
|
||||
Document result = await databases.UpsertDocument(
|
||||
databaseId: "<DATABASE_ID>",
|
||||
collectionId: "<COLLECTION_ID>",
|
||||
documentId: "<DOCUMENT_ID>",
|
||||
data: [object],
|
||||
permissions: ["read("any")"] // optional
|
||||
);
|
||||
@@ -12,5 +12,5 @@ Databases databases = new Databases(client);
|
||||
DocumentList result = await databases.UpsertDocuments(
|
||||
databaseId: "<DATABASE_ID>",
|
||||
collectionId: "<COLLECTION_ID>",
|
||||
documents: new List<object>() // optional
|
||||
documents: new List<object>()
|
||||
);
|
||||
@@ -0,0 +1,16 @@
|
||||
const sdk = require('node-appwrite');
|
||||
|
||||
const client = new sdk.Client()
|
||||
.setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint
|
||||
.setProject('<YOUR_PROJECT_ID>') // Your project ID
|
||||
.setSession(''); // The user session to authenticate with
|
||||
|
||||
const databases = new sdk.Databases(client);
|
||||
|
||||
const result = await databases.upsertDocument(
|
||||
'<DATABASE_ID>', // databaseId
|
||||
'<COLLECTION_ID>', // collectionId
|
||||
'<DOCUMENT_ID>', // documentId
|
||||
{}, // data
|
||||
["read("any")"] // permissions (optional)
|
||||
);
|
||||
@@ -10,5 +10,5 @@ const databases = new sdk.Databases(client);
|
||||
const result = await databases.upsertDocuments(
|
||||
'<DATABASE_ID>', // databaseId
|
||||
'<COLLECTION_ID>', // collectionId
|
||||
[] // documents (optional)
|
||||
[] // documents
|
||||
);
|
||||
|
||||
@@ -1,5 +1,36 @@
|
||||
# Change Log
|
||||
|
||||
## 8.2.1
|
||||
|
||||
* Added `--with-variables` option to the Sites command for adding/updating environment variables
|
||||
* Fixed Functions environment variables not being pushed with `--with-variables`
|
||||
* Removed `awaitPools` when wiping old variables
|
||||
|
||||
> **Note:** Storing environment variables in the `vars` attribute of `appwrite.json` is now deprecated due to security risks. Variables are now synced directly from the `.env` file in the root directory of the function’s or site’s folder.
|
||||
|
||||
## 8.2.0
|
||||
|
||||
* Add `encrypt` attribute support
|
||||
* Add improved warnings on attribute recreation and deletion
|
||||
* Fix `null` parsing error when using create attribute command
|
||||
* Type generation fixes and improvements:
|
||||
* Add `--strict` / `-s` flag to `appwrite types` command to generate types in strict mode. This automatically converts the casing of attributes to match the language's naming conventions
|
||||
* Add automatic package import to `dart` language which uses package detection to import the correct package
|
||||
* Add `Document` class extension to generated types in `dart` and `js` language to support internal attributes like `$id` and `$collectionId` etc.
|
||||
* Add proper enum support to `js` language
|
||||
* Fix indentation in `java`, `kotlin` and `swift` to use 2 spaces instead of 4 for consistency across all languages
|
||||
* Fix doc comments to use correct syntax in various languages (for eg. `///` instead of `/*`)
|
||||
* Update enums in `dart` to use lowerCamelCase in `strict` mode as per [constant_identifier_names](https://dart.dev/tools/diagnostics/constant_identifier_names?utm_source=dartdev&utm_medium=redir&utm_id=diagcode&utm_content=constant_identifier_names)
|
||||
|
||||
## 8.1.1
|
||||
|
||||
* Fix circular dependency issue due to usage of `success` method in `utils.js` file from `parser.js` file
|
||||
* Type generation fixes:
|
||||
* Add ability to generate types directly to a specific file by passing a file path to `appwrite types output_path`, instead of just a directory
|
||||
* Fix non-required attributes to not be null if default value is provided
|
||||
* Fix `Models` import error
|
||||
* Improve formatting and add auto-generated comments
|
||||
|
||||
## 8.1.0
|
||||
|
||||
* Add multi-region support to `init` command
|
||||
|
||||
@@ -1 +1,63 @@
|
||||
# Change Log
|
||||
# Change Log
|
||||
|
||||
## 0.14.0
|
||||
|
||||
* Refactor from Newtonsoft.Json to System.Text.Json for serialization/deserialization
|
||||
* Update package dependencies in `Package.csproj.twig`
|
||||
* Migrate all serialization/deserialization logic in `Client.cs.twig`, `Query.cs.twig`, and `Extensions.cs.twig`
|
||||
* Update model attributes from `[JsonProperty]` to `[JsonPropertyName]` in `Model.cs.twig`
|
||||
* Create new `ObjectToInferredTypesConverter.cs.twig` for proper object type handling
|
||||
* Replace `JsonConverter` with `JsonConverter<object>` in `ValueClassConverter.cs.twig`
|
||||
* Update error handling to use `JsonDocument` instead of `JObject`
|
||||
|
||||
## 0.13.0
|
||||
|
||||
* Add `<REGION>` to doc examples due to the new multi region endpoints
|
||||
* Add doc examples and methods for bulk api transactions: `createDocuments`, `deleteDocuments` etc.
|
||||
* Add doc examples, class and methods for new `Sites` service
|
||||
* Add doc examples, class and methods for new `Tokens` service
|
||||
* Add enums for `BuildRuntime `, `Adapter`, `Framework`, `DeploymentDownloadType` and `VCSDeploymentType`
|
||||
* Update enum for `runtimes` with Pythonml312, Dart219, Flutter327 and Flutter329
|
||||
* Add `token` param to `getFilePreview` and `getFileView` for File tokens usage
|
||||
* Add `queries` and `search` params to `listMemberships` method
|
||||
* Remove `search` param from `listExecutions` method
|
||||
|
||||
## 0.12.0
|
||||
|
||||
* fix: remove content-type from GET requests by @loks0n in https://github.com/appwrite/sdk-for-dotnet/pull/59
|
||||
* update: min and max are not optional in methods like `UpdateIntegerAttribute` etc.
|
||||
* chore: regenerate sdk by @ChiragAgg5k in https://github.com/appwrite/sdk-for-dotnet/pull/60
|
||||
* chore: fix build error by @ChiragAgg5k in https://github.com/appwrite/sdk-for-dotnet/pull/61
|
||||
|
||||
## 0.11.0
|
||||
|
||||
* Add new push message parameters by @abnegate in https://github.com/appwrite/sdk-for-dotnet/pull/56
|
||||
|
||||
## 0.10.0
|
||||
|
||||
* fix: chunk upload by @byawitz in https://github.com/appwrite/sdk-for-dotnet/pull/52
|
||||
|
||||
## 0.9.0
|
||||
|
||||
* Support for Appwrite 1.6
|
||||
* Added `key` attribute to `Runtime` response model.
|
||||
* Added `buildSize` attribute to `Deployments` response model.
|
||||
* Added `scheduledAt` attribute to `Executions` response model.
|
||||
* Added `scopes` attribute to `Functions` response model.
|
||||
* Added `specifications` attribute to `Functions` response model.
|
||||
* Added new response model for `Specifications`.
|
||||
* Added new response model for `Builds`.
|
||||
* Added `createJWT()` : Enables creating a JWT using the `userId`.
|
||||
* Added `listSpecifications()`: Enables listing available runtime specifications.
|
||||
* Added `deleteExecution()` : Enables deleting executions.
|
||||
* Added `updateDeploymentBuild()`: Enables cancelling a deployment.
|
||||
* Added `scheduledAt` parameter to `createExecution()`: Enables creating a delayed execution
|
||||
|
||||
#### Breaking changes
|
||||
You can find the new syntax for breaking changes in the [Appwrite API references](https://appwrite.io/docs/references). Select version `1.6.x`.
|
||||
* Removed `otp` parameter from `deleteMFAAuthenticator`.
|
||||
* Added `scopes` parameter for create/update function.
|
||||
* Renamed `templateBranch` to `templateVersion` in `createFunction()`.
|
||||
* Renamed `downloadDeployment()` to `getDeploymentDownload()`
|
||||
|
||||
> **Please note: This version is compatible with Appwrite 1.6 and later only. If you do not update your Appwrite SDK, old SDKs will not break your app. Appwrite APIs are backwards compatible.**
|
||||
|
||||
@@ -1,13 +1,68 @@
|
||||
# Change Log
|
||||
|
||||
## 17.1.0
|
||||
|
||||
* Add `upsertDocument` method
|
||||
* Add `dart-3.8` and `flutter-3.32` runtimes
|
||||
* Add `gif` image format
|
||||
* Update bulk operation methods to reflect warning message
|
||||
* Fix file parameter handling in chunked upload method
|
||||
|
||||
## 17.0.0
|
||||
|
||||
* Add `<REGION>` to doc examples due to the new multi region endpoints
|
||||
* Add `REGION` to doc examples due to the new multi region endpoints
|
||||
* Add doc examples and methods for bulk api transactions: `createDocuments`, `deleteDocuments` etc.
|
||||
* Add doc examples, class and methods for new `Sites` service
|
||||
* Add doc examples, class and methods for new `Tokens` service
|
||||
* Add enums for `BuildRuntime `, `Adapter`, `Framework`, `DeploymentDownloadType` and `VCSDeploymentType`
|
||||
* Add enums for `BuildRuntime`, `Adapter`, `Framework`, `DeploymentDownloadType` and `VCSDeploymentType`
|
||||
* Updates enum for `runtimes` with Pythonml312, Dart219, Flutter327 and Flutter329
|
||||
* Add `token` param to `getFilePreview` and `getFileView` for File tokens usage
|
||||
* Add `queries` and `search` params to `listMemberships` method
|
||||
* Removes `search` param from `listExecutions` method
|
||||
* Removes `search` param from `listExecutions` method
|
||||
|
||||
## 16.0.0
|
||||
|
||||
* Fix: remove content-type from GET requests
|
||||
* Update (breaking): min and max params are now optional in `updateFloatAttribute` and `updateIntegerAttribute` methods (changes their positioning in method definition)
|
||||
|
||||
## 15.0.1
|
||||
|
||||
* Remove titles from all function descriptions
|
||||
* Fix typing for collection "attribute" key
|
||||
* Remove unnecessary awaits and asyncs
|
||||
* Ensure `AppwriteException` response is always string
|
||||
|
||||
## 15.0.0
|
||||
|
||||
* Fix: pong response & chunked upload
|
||||
|
||||
## 14.2.0
|
||||
|
||||
* Add new push message parameters
|
||||
|
||||
## 14.1.0
|
||||
|
||||
* Support updating attribute name and size
|
||||
|
||||
## 14.0.0
|
||||
|
||||
* Support for Appwrite 1.6
|
||||
* Add `key` attribute to `Runtime` response model.
|
||||
* Add `buildSize` attribute to `Deployments` response model
|
||||
* Add `scheduledAt` attribute to `Executions` response model
|
||||
* Add `scopes` attribute to `Functions` response model
|
||||
* Add `specifications` attribute to `Functions` response model
|
||||
* Add new response model for `Specifications`
|
||||
* Add new response model for `Builds`
|
||||
* Add `createJWT()` : Enables creating a JWT using the `userId`
|
||||
* Add `listSpecifications()`: Enables listing available runtime specifications
|
||||
* Add `deleteExecution()` : Enables deleting executions
|
||||
* Add `updateDeploymentBuild()`: Enables cancelling a deployment
|
||||
* Add `scheduledAt` parameter to `createExecution()`: Enables creating a delayed execution
|
||||
* Breaking changes
|
||||
* Remove `otp` parameter from `deleteMFAAuthenticator`.
|
||||
* Add `scopes` parameter for create/update function.
|
||||
* Rename `templateBranch` to `templateVersion` in `createFunction()`.
|
||||
* Rename `downloadDeployment()` to `getDeploymentDownload()`
|
||||
|
||||
> You can find the new syntax for breaking changes in the [Appwrite API references](https://appwrite.io/docs/references). Select version `1.6.x`.
|
||||
@@ -1,5 +1,10 @@
|
||||
# Change log
|
||||
|
||||
## 0.10.1
|
||||
|
||||
* Fix URL based methods like `getFileViewURL`, `getFilePreviewURL` etc. by adding the missing `projectId` to searchParams
|
||||
* Add `gif` to ImageFormat enum
|
||||
|
||||
## 0.10.0
|
||||
|
||||
* Add generate file URL methods like`getFilePreviewURL`, `getFileViewURL` etc.
|
||||
|
||||
@@ -267,50 +267,53 @@ class Mapper
|
||||
}
|
||||
|
||||
switch ((!empty($validator)) ? $validator::class : '') {
|
||||
case 'Appwrite\Network\Validator\CNAME':
|
||||
case 'Appwrite\Task\Validator\Cron':
|
||||
case 'Appwrite\Utopia\Database\Validator\CustomId':
|
||||
case 'Utopia\Validator\Domain':
|
||||
case 'Appwrite\Network\Validator\Email':
|
||||
case 'Appwrite\Auth\Validator\Password':
|
||||
case 'Appwrite\Event\Validator\Event':
|
||||
case 'Appwrite\Event\Validator\FunctionEvent':
|
||||
case 'Appwrite\Network\Validator\CNAME':
|
||||
case 'Appwrite\Network\Validator\Email':
|
||||
case 'Appwrite\Network\Validator\Redirect':
|
||||
case 'Appwrite\Network\Validator\DNS':
|
||||
case 'Appwrite\Network\Validator\Origin':
|
||||
case 'Appwrite\Task\Validator\Cron':
|
||||
case 'Appwrite\Utopia\Database\Validator\CustomId':
|
||||
case 'Utopia\Database\Validator\Key':
|
||||
case 'Utopia\Database\Validator\UID':
|
||||
case 'Utopia\Validator\Domain':
|
||||
case 'Utopia\Validator\HexColor':
|
||||
case 'Utopia\Validator\Host':
|
||||
case 'Utopia\Validator\IP':
|
||||
case 'Utopia\Database\Validator\Key':
|
||||
case 'Utopia\Validator\Origin':
|
||||
case 'Appwrite\Auth\Validator\Password':
|
||||
case 'Utopia\Validator\Text':
|
||||
case 'Utopia\Database\Validator\UID':
|
||||
case 'Utopia\Validator\URL':
|
||||
case 'Utopia\Validator\WhiteList':
|
||||
default:
|
||||
$type = Type::string();
|
||||
break;
|
||||
case 'Utopia\Database\Validator\Authorization':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Attributes':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Base':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Buckets':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Tables':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Collections':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Columns':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Attributes':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Indexes':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Databases':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Deployments':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Installations':
|
||||
case 'Utopia\Database\Validator\Queries\Documents':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Executions':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Files':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Functions':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Rules':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Indexes':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Installations':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Memberships':
|
||||
case 'Utopia\Database\Validator\Permissions':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Projects':
|
||||
case 'Utopia\Database\Validator\Queries':
|
||||
case 'Utopia\Database\Validator\Roles':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Rules':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Teams':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Users':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Variables':
|
||||
case 'Utopia\Database\Validator\Authorization':
|
||||
case 'Utopia\Database\Validator\Permissions':
|
||||
case 'Utopia\Database\Validator\Queries':
|
||||
case 'Utopia\Database\Validator\Queries\Documents':
|
||||
case 'Utopia\Database\Validator\Roles':
|
||||
$type = Type::listOf(Type::string());
|
||||
break;
|
||||
case 'Utopia\Validator\Boolean':
|
||||
|
||||
@@ -24,6 +24,10 @@ class Platform
|
||||
|
||||
public const SCHEME_HTTP = 'http';
|
||||
public const SCHEME_HTTPS = 'https';
|
||||
public const SCHEME_CHROME_EXTENSION = 'chrome-extension';
|
||||
public const SCHEME_FIREFOX_EXTENSION = 'moz-extension';
|
||||
public const SCHEME_SAFARI_EXTENSION = 'safari-web-extension';
|
||||
public const SCHEME_EDGE_EXTENSION = 'ms-browser-extension';
|
||||
public const SCHEME_IOS = 'appwrite-ios';
|
||||
public const SCHEME_MACOS = 'appwrite-macos';
|
||||
public const SCHEME_WATCHOS = 'appwrite-watchos';
|
||||
@@ -45,6 +49,10 @@ class Platform
|
||||
self::SCHEME_ANDROID => 'Android',
|
||||
self::SCHEME_WINDOWS => 'Windows',
|
||||
self::SCHEME_LINUX => 'Linux',
|
||||
self::SCHEME_CHROME_EXTENSION => 'Web (Chrome Extension)',
|
||||
self::SCHEME_FIREFOX_EXTENSION => 'Web (Firefox Extension)',
|
||||
self::SCHEME_SAFARI_EXTENSION => 'Web (Safari Extension)',
|
||||
self::SCHEME_EDGE_EXTENSION => 'Web (Edge Extension)',
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -42,7 +42,15 @@ class Origin extends Validator
|
||||
$this->scheme = $this->parseScheme($origin);
|
||||
$this->host = strtolower(parse_url($origin, PHP_URL_HOST) ?? '');
|
||||
|
||||
if (in_array($this->scheme, [Platform::SCHEME_HTTP, Platform::SCHEME_HTTPS], true)) {
|
||||
$webPlatforms = [
|
||||
Platform::SCHEME_HTTP,
|
||||
Platform::SCHEME_HTTPS,
|
||||
Platform::SCHEME_CHROME_EXTENSION,
|
||||
Platform::SCHEME_FIREFOX_EXTENSION,
|
||||
Platform::SCHEME_SAFARI_EXTENSION,
|
||||
Platform::SCHEME_EDGE_EXTENSION,
|
||||
];
|
||||
if (in_array($this->scheme, $webPlatforms, true)) {
|
||||
$validator = new Hostname($this->hostnames);
|
||||
return $validator->isValid($this->host);
|
||||
}
|
||||
|
||||
@@ -63,8 +63,8 @@ class XList extends Base
|
||||
$spec['enabled'] = in_array($spec['slug'], $plan['runtimeSpecifications']);
|
||||
}
|
||||
|
||||
$maxCpus = System::getEnv('_APP_FUNCTIONS_CPUS', 0);
|
||||
$maxMemory = System::getEnv('_APP_FUNCTIONS_MEMORY', 0);
|
||||
$maxCpus = System::getEnv('_APP_COMPUTE_CPUS', 0);
|
||||
$maxMemory = System::getEnv('_APP_COMPUTE_MEMORY', 0);
|
||||
|
||||
// Only add specs that are within the limits set by environment variables
|
||||
// Treat 0 as no limit
|
||||
|
||||
@@ -264,7 +264,7 @@ class Builds extends Action
|
||||
->setParam('deploymentId', $deployment->getId());
|
||||
|
||||
if ($deployment->getAttribute('status') === 'canceled') {
|
||||
Console::info('Build has been canceled');
|
||||
$this->cancelDeployment($deployment->getId(), $dbForProject, $queueForRealtime);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -275,8 +275,7 @@ class Builds extends Action
|
||||
$deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment);
|
||||
|
||||
if ($deployment->getSequence() === $resource->getAttribute('latestDeploymentInternalId', '')) {
|
||||
$resource = $resource->setAttribute('latestDeploymentStatus', $deployment->getAttribute('status', ''));
|
||||
$dbForProject->updateDocument($resource->getCollection(), $resource->getId(), $resource);
|
||||
$resource = $dbForProject->updateDocument($resource->getCollection(), $resource->getId(), new Document(['latestDeploymentStatus' => $deployment->getAttribute('status', '')]));
|
||||
}
|
||||
|
||||
$queueForRealtime
|
||||
@@ -392,7 +391,7 @@ class Builds extends Action
|
||||
Console::execute('mkdir -p ' . \escapeshellarg('/tmp/builds/' . $deploymentId), '', $stdout, $stderr);
|
||||
|
||||
if ($dbForProject->getDocument('deployments', $deploymentId)->getAttribute('status') === 'canceled') {
|
||||
Console::info('Build has been canceled');
|
||||
$this->cancelDeployment($deployment->getId(), $dbForProject, $queueForRealtime);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -525,8 +524,7 @@ class Builds extends Action
|
||||
$deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment);
|
||||
|
||||
if ($deployment->getSequence() === $resource->getAttribute('latestDeploymentInternalId', '')) {
|
||||
$resource = $resource->setAttribute('latestDeploymentStatus', $deployment->getAttribute('status', ''));
|
||||
$dbForProject->updateDocument($resource->getCollection(), $resource->getId(), $resource);
|
||||
$resource = $dbForProject->updateDocument($resource->getCollection(), $resource->getId(), new Document(['latestDeploymentStatus' => $deployment->getAttribute('status', '')]));
|
||||
}
|
||||
|
||||
$queueForRealtime
|
||||
@@ -658,7 +656,7 @@ class Builds extends Action
|
||||
$err = null;
|
||||
|
||||
if ($dbForProject->getDocument('deployments', $deploymentId)->getAttribute('status') === 'canceled') {
|
||||
Console::info('Build has been canceled');
|
||||
$this->cancelDeployment($deployment->getId(), $dbForProject, $queueForRealtime);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -809,7 +807,7 @@ class Builds extends Action
|
||||
]);
|
||||
|
||||
if ($dbForProject->getDocument('deployments', $deploymentId)->getAttribute('status') === 'canceled') {
|
||||
Console::info('Build has been canceled');
|
||||
$this->cancelDeployment($deployment->getId(), $dbForProject, $queueForRealtime);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -858,9 +856,7 @@ class Builds extends Action
|
||||
|
||||
$adapter = $resource->getAttribute('adapter', '');
|
||||
if (empty($adapter)) {
|
||||
$resource->setAttribute('adapter', $detection->getName());
|
||||
$resource->setAttribute('fallbackFile', $detection->getFallbackFile() ?? '');
|
||||
$resource = $dbForProject->updateDocument('sites', $resource->getId(), $resource);
|
||||
$resource = $dbForProject->updateDocument('sites', $resource->getId(), new Document(['adapter' => $detection->getName(), 'fallbackFile' => $detection->getFallbackFile() ?? '']));
|
||||
|
||||
$deployment->setAttribute('adapter', $detection->getName());
|
||||
$deployment->setAttribute('fallbackFile', $detection->getFallbackFile() ?? '');
|
||||
@@ -959,8 +955,9 @@ class Builds extends Action
|
||||
$config['sleep'] = $framework['screenshotSleep'];
|
||||
}
|
||||
|
||||
$browserEndpoint = Config::getParam('_APP_BROWSER_HOST', 'http://appwrite-browser:3000/v1');
|
||||
$fetchResponse = $client->fetch(
|
||||
url: 'http://appwrite-browser:3000/v1/screenshots',
|
||||
url: $browserEndpoint . '/screenshots',
|
||||
method: 'POST',
|
||||
body: $config
|
||||
);
|
||||
@@ -1062,8 +1059,7 @@ class Builds extends Action
|
||||
$deployment = $dbForProject->updateDocument('deployments', $deploymentId, $deployment);
|
||||
|
||||
if ($deployment->getSequence() === $resource->getAttribute('latestDeploymentInternalId', '')) {
|
||||
$resource = $resource->setAttribute('latestDeploymentStatus', $deployment->getAttribute('status', ''));
|
||||
$dbForProject->updateDocument($resource->getCollection(), $resource->getId(), $resource);
|
||||
$resource = $dbForProject->updateDocument($resource->getCollection(), $resource->getId(), new Document(['latestDeploymentStatus' => $deployment->getAttribute('status', '')]));
|
||||
}
|
||||
|
||||
$queueForRealtime
|
||||
@@ -1077,14 +1073,38 @@ class Builds extends Action
|
||||
Console::success("Build id: $deploymentId created");
|
||||
|
||||
/** Set auto deploy */
|
||||
$activateBuild = false;
|
||||
if ($deployment->getAttribute('activate') === true) {
|
||||
$resource->setAttribute('live', true);
|
||||
// Check if current active deployment started later than this deployment
|
||||
$resource = $dbForProject->getDocument($resource->getCollection(), $resource->getId());
|
||||
$currentActiveDeploymentId = $resource->getAttribute('deploymentId', '');
|
||||
if (!empty($currentActiveDeploymentId)) {
|
||||
$currentActiveDeployment = $dbForProject->getDocument('deployments', $currentActiveDeploymentId);
|
||||
if (!$currentActiveDeployment->isEmpty()) {
|
||||
$currentActiveStartTime = $currentActiveDeployment->getCreatedAt();
|
||||
$deploymentStartTime = $deployment->getCreatedAt();
|
||||
|
||||
// Skip auto-activation if current active deployment started later than deployment that is being activated
|
||||
if ($currentActiveStartTime < $deploymentStartTime) {
|
||||
$activateBuild = true;
|
||||
} else {
|
||||
Console::info('Skipping auto-activation as current deployment is more recent');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$activateBuild = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($activateBuild) {
|
||||
switch ($resource->getCollection()) {
|
||||
case 'functions':
|
||||
$resource->setAttribute('deploymentId', $deployment->getId());
|
||||
$resource->setAttribute('deploymentInternalId', $deployment->getSequence());
|
||||
$resource->setAttribute('deploymentCreatedAt', $deployment->getCreatedAt());
|
||||
$resource = $dbForProject->updateDocument('functions', $resource->getId(), $resource);
|
||||
$resource = $dbForProject->updateDocument('functions', $resource->getId(), new Document([
|
||||
'live' => true,
|
||||
'deploymentId' => $deployment->getId(),
|
||||
'deploymentInternalId' => $deployment->getSequence(),
|
||||
'deploymentCreatedAt' => $deployment->getCreatedAt(),
|
||||
]));
|
||||
|
||||
$queries = [
|
||||
Query::equal('projectInternalId', [$project->getSequence()]),
|
||||
@@ -1098,19 +1118,21 @@ class Builds extends Action
|
||||
$rulesUpdated = false;
|
||||
$dbForPlatform->forEach('rules', function (Document $rule) use ($dbForPlatform, $deployment, &$rulesUpdated) {
|
||||
$rulesUpdated = true;
|
||||
$rule = $rule
|
||||
->setAttribute('deploymentId', $deployment->getId())
|
||||
->setAttribute('deploymentInternalId', $deployment->getSequence());
|
||||
$dbForPlatform->updateDocument('rules', $rule->getId(), $rule);
|
||||
$rule = $dbForPlatform->updateDocument('rules', $rule->getId(), new Document([
|
||||
'deploymentId' => $deployment->getId(),
|
||||
'deploymentInternalId' => $deployment->getSequence(),
|
||||
]));
|
||||
}, $queries);
|
||||
break;
|
||||
case 'sites':
|
||||
$resource->setAttribute('deploymentId', $deployment->getId());
|
||||
$resource->setAttribute('deploymentInternalId', $deployment->getSequence());
|
||||
$resource->setAttribute('deploymentScreenshotDark', $deployment->getAttribute('screenshotDark', ''));
|
||||
$resource->setAttribute('deploymentScreenshotLight', $deployment->getAttribute('screenshotLight', ''));
|
||||
$resource->setAttribute('deploymentCreatedAt', $deployment->getCreatedAt());
|
||||
$resource = $dbForProject->updateDocument('sites', $resource->getId(), $resource);
|
||||
$resource = $dbForProject->updateDocument('sites', $resource->getId(), new Document([
|
||||
'live' => true,
|
||||
'deploymentId' => $deployment->getId(),
|
||||
'deploymentInternalId' => $deployment->getSequence(),
|
||||
'deploymentScreenshotDark' => $deployment->getAttribute('screenshotDark', ''),
|
||||
'deploymentScreenshotLight' => $deployment->getAttribute('screenshotLight', ''),
|
||||
'deploymentCreatedAt' => $deployment->getCreatedAt(),
|
||||
]));
|
||||
$queries = [
|
||||
Query::equal('projectInternalId', [$project->getSequence()]),
|
||||
Query::equal('type', ['deployment']),
|
||||
@@ -1121,10 +1143,10 @@ class Builds extends Action
|
||||
];
|
||||
|
||||
$dbForPlatform->forEach('rules', function (Document $rule) use ($dbForPlatform, $deployment) {
|
||||
$rule = $rule
|
||||
->setAttribute('deploymentId', $deployment->getId())
|
||||
->setAttribute('deploymentInternalId', $deployment->getSequence());
|
||||
$dbForPlatform->updateDocument('rules', $rule->getId(), $rule);
|
||||
$rule = $dbForPlatform->updateDocument('rules', $rule->getId(), new Document([
|
||||
'deploymentId' => $deployment->getId(),
|
||||
'deploymentInternalId' => $deployment->getSequence(),
|
||||
]));
|
||||
}, $queries);
|
||||
|
||||
break;
|
||||
@@ -1166,11 +1188,10 @@ class Builds extends Action
|
||||
'region' => $project->getAttribute('region')
|
||||
]));
|
||||
} catch (Duplicate $err) {
|
||||
$rule = $dbForPlatform->getDocument('rules', $ruleId);
|
||||
$rule = $rule
|
||||
->setAttribute('deploymentId', $deployment->getId())
|
||||
->setAttribute('deploymentInternalId', $deployment->getSequence());
|
||||
$dbForPlatform->updateDocument('rules', $rule->getId(), $rule);
|
||||
$rule = $dbForPlatform->updateDocument('rules', $ruleId, new Document([
|
||||
'deploymentId' => $deployment->getId(),
|
||||
'deploymentInternalId' => $deployment->getSequence(),
|
||||
]));
|
||||
}
|
||||
|
||||
$queries = [
|
||||
@@ -1183,10 +1204,10 @@ class Builds extends Action
|
||||
];
|
||||
|
||||
$dbForPlatform->foreach('rules', function (Document $rule) use ($dbForPlatform, $deployment) {
|
||||
$rule = $rule
|
||||
->setAttribute('deploymentId', $deployment->getId())
|
||||
->setAttribute('deploymentInternalId', $deployment->getSequence());
|
||||
$dbForPlatform->updateDocument('rules', $rule->getId(), $rule);
|
||||
$rule = $dbForPlatform->updateDocument('rules', $rule->getId(), new Document([
|
||||
'deploymentId' => $deployment->getId(),
|
||||
'deploymentInternalId' => $deployment->getSequence(),
|
||||
]));
|
||||
}, $queries);
|
||||
}
|
||||
}
|
||||
@@ -1201,7 +1222,7 @@ class Builds extends Action
|
||||
->trigger();
|
||||
|
||||
if ($dbForProject->getDocument('deployments', $deploymentId)->getAttribute('status') === 'canceled') {
|
||||
Console::info('Build has been canceled');
|
||||
$this->cancelDeployment($deployment->getId(), $dbForProject, $queueForRealtime);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1224,7 +1245,7 @@ class Builds extends Action
|
||||
Console::error($th->getTraceAsString());
|
||||
|
||||
if ($dbForProject->getDocument('deployments', $deploymentId)->getAttribute('status') === 'canceled') {
|
||||
Console::info('Build has been canceled');
|
||||
$this->cancelDeployment($deployment->getId(), $dbForProject, $queueForRealtime);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1256,8 +1277,7 @@ class Builds extends Action
|
||||
$deployment = $dbForProject->updateDocument('deployments', $deploymentId, $deployment);
|
||||
|
||||
if ($deployment->getSequence() === $resource->getAttribute('latestDeploymentInternalId', '')) {
|
||||
$resource = $resource->setAttribute('latestDeploymentStatus', $deployment->getAttribute('status', ''));
|
||||
$dbForProject->updateDocument($resource->getCollection(), $resource->getId(), $resource);
|
||||
$resource = $dbForProject->updateDocument($resource->getCollection(), $resource->getId(), new Document(['latestDeploymentStatus' => $deployment->getAttribute('status', '')]));
|
||||
}
|
||||
|
||||
$queueForRealtime
|
||||
@@ -1283,6 +1303,8 @@ class Builds extends Action
|
||||
|
||||
protected function sendUsage(Document $resource, Document $deployment, Document $project, StatsUsage $queue): void
|
||||
{
|
||||
$spec = Config::getParam('specifications')[$resource->getAttribute('specification', APP_COMPUTE_SPECIFICATION_DEFAULT)];
|
||||
|
||||
switch ($deployment->getAttribute('status')) {
|
||||
case 'ready':
|
||||
$queue
|
||||
@@ -1511,4 +1533,22 @@ class Builds extends Action
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function cancelDeployment(string $deploymentId, Database $dbForProject, Realtime $queueForRealtime)
|
||||
{
|
||||
Console::info('Build has been canceled');
|
||||
|
||||
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
|
||||
|
||||
$logs = $deployment->getAttribute('buildLogs', '');
|
||||
$date = \date('H:i:s');
|
||||
$logs .= "[90m[$date] [90m[[0mappwrite[90m][33m Build has been canceled. [0m\n";
|
||||
|
||||
$deployment->setAttribute('buildLogs', $logs);
|
||||
$deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment);
|
||||
|
||||
$queueForRealtime
|
||||
->setPayload($deployment->getArrayCopy())
|
||||
->trigger();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,8 +63,8 @@ class XList extends Base
|
||||
$spec['enabled'] = in_array($spec['slug'], $plan['runtimeSpecifications']);
|
||||
}
|
||||
|
||||
$maxCpus = System::getEnv('_APP_FUNCTIONS_CPUS', 0);
|
||||
$maxMemory = System::getEnv('_APP_FUNCTIONS_MEMORY', 0);
|
||||
$maxCpus = System::getEnv('_APP_COMPUTE_CPUS', 0);
|
||||
$maxMemory = System::getEnv('_APP_COMPUTE_MEMORY', 0);
|
||||
|
||||
// Only add specs that are within the limits set by environment variables
|
||||
// Treat 0 as no limit
|
||||
|
||||
@@ -37,6 +37,7 @@ class Action extends UtopiaAction
|
||||
if ($file->isEmpty()) {
|
||||
throw new Exception(Exception::STORAGE_FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
return [
|
||||
'bucket' => $bucket,
|
||||
'file' => $file,
|
||||
|
||||
@@ -1117,6 +1117,9 @@ class Deletes extends Action
|
||||
): void {
|
||||
$start = \microtime(true);
|
||||
|
||||
$deleteBatchSize = Database::DELETE_BATCH_SIZE;
|
||||
$deleteBatchSize = 500; // TODO: Set right value in DB library after investigation
|
||||
|
||||
/**
|
||||
* deleteDocuments uses a cursor, we need to add a unique order by field or use default
|
||||
*/
|
||||
@@ -1124,7 +1127,7 @@ class Deletes extends Action
|
||||
$count = $database->deleteDocuments(
|
||||
$collection,
|
||||
$queries,
|
||||
Database::DELETE_BATCH_SIZE,
|
||||
$deleteBatchSize,
|
||||
$callback
|
||||
);
|
||||
} catch (Throwable $th) {
|
||||
|
||||
@@ -360,6 +360,7 @@ class OpenAPI3 extends Format
|
||||
break;
|
||||
case 'Utopia\Validator\Host':
|
||||
case 'Utopia\Validator\URL':
|
||||
case 'Appwrite\Network\Validator\Redirect':
|
||||
$node['schema']['type'] = $validator->getType();
|
||||
$node['schema']['format'] = 'url';
|
||||
$node['schema']['x-example'] = 'https://example.com';
|
||||
|
||||
@@ -385,6 +385,7 @@ class Swagger2 extends Format
|
||||
break;
|
||||
case 'Utopia\Validator\Host':
|
||||
case 'Utopia\Validator\URL':
|
||||
case 'Appwrite\Network\Validator\Redirect':
|
||||
$node['type'] = $validator->getType();
|
||||
$node['format'] = 'url';
|
||||
$node['x-example'] = 'https://example.com';
|
||||
|
||||
@@ -26,7 +26,20 @@ class URL
|
||||
'fragment' => '',
|
||||
];
|
||||
|
||||
return \array_merge($default, \parse_url($url));
|
||||
$parsed = \parse_url($url);
|
||||
if (is_array($parsed)) {
|
||||
return \array_merge($default, $parsed);
|
||||
}
|
||||
|
||||
// see if $url is just a scheme
|
||||
if (preg_match('/^([a-z][a-z0-9+.-]*):/i', $url, $matches)) {
|
||||
$scheme = $matches[1];
|
||||
return \array_merge($default, [
|
||||
'scheme' => $scheme
|
||||
]);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('Invalid URL: ' . $url);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,9 +68,9 @@ class URL
|
||||
|
||||
$parts['user'] = isset($url['user']) ? $url['user'] : '';
|
||||
|
||||
$parts['pass'] = isset($url['pass']) ? ':' . $url['pass'] : '';
|
||||
$parts['pass'] = !empty($url['pass']) ? ':' . $url['pass'] : '';
|
||||
|
||||
$parts['pass'] = ($parts['user'] || $parts['pass']) ? $parts['pass'] . '@' : '';
|
||||
$parts['pass'] = ($parts['user'] || !empty($parts['pass'])) ? $parts['pass'] . '@' : '';
|
||||
|
||||
$parts['path'] = isset($url['path']) ? $url['path'] : '';
|
||||
|
||||
|
||||
@@ -2,13 +2,28 @@
|
||||
|
||||
namespace Appwrite\Utopia\Response\Filters;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Filter;
|
||||
|
||||
class V20 extends Filter
|
||||
{
|
||||
// Convert 1.8 format to 1.7 format
|
||||
// removing $sequence from all versions less than 1.8
|
||||
public function parse(array $content, string $model): array
|
||||
{
|
||||
$parsedResponse = $content;
|
||||
|
||||
$parsedResponse = match($model) {
|
||||
Response::MODEL_DOCUMENT => $this->parseDocument($content),
|
||||
Response::MODEL_DOCUMENT_LIST => $this->handleList($content, 'documents', fn ($item) => $this->parseDocument($item)),
|
||||
default => $parsedResponse,
|
||||
};
|
||||
|
||||
return $parsedResponse;
|
||||
}
|
||||
|
||||
protected function parseDocument(array $content): array
|
||||
{
|
||||
unset($content['$sequence']);
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -925,7 +925,8 @@ class UsageTest extends Scope
|
||||
[
|
||||
'functionId' => 'unique()',
|
||||
'name' => 'Test',
|
||||
'runtime' => 'php-8.0',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'vars' => [
|
||||
'funcKey1' => 'funcValue1',
|
||||
'funcKey2' => 'funcValue2',
|
||||
@@ -947,8 +948,7 @@ class UsageTest extends Scope
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
|
||||
$deploymentId = $this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true,
|
||||
]);
|
||||
$this->assertNotEmpty($deploymentId);
|
||||
|
||||
@@ -1995,6 +1995,36 @@ trait DatabasesBase
|
||||
],
|
||||
]);
|
||||
$this->assertEquals(2, $documents['body']['total']);
|
||||
|
||||
// test without passing permissions
|
||||
$document = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $documentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'title' => 'Thor: Ragnarok',
|
||||
'releaseYear' => 2000
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $document['headers']['status-code']);
|
||||
$this->assertEquals('Thor: Ragnarok', $document['body']['title']);
|
||||
|
||||
$document = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $documentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$this->assertEquals(200, $document['headers']['status-code']);
|
||||
|
||||
$deleteResponse = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $documentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$this->assertEquals(204, $deleteResponse['headers']['status-code']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,8 +21,8 @@ class FunctionsConsoleClientTest extends Scope
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'execute' => [Role::user($this->getUser()['$id'])->toString()],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'events' => [
|
||||
'users.*.create',
|
||||
'users.*.delete',
|
||||
@@ -39,8 +39,8 @@ class FunctionsConsoleClientTest extends Scope
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test Failure',
|
||||
'execute' => ['some-random-string'],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $function2['headers']['status-code']);
|
||||
@@ -453,7 +453,7 @@ class FunctionsConsoleClientTest extends Scope
|
||||
{
|
||||
$function = $this->createFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'runtime' => 'node-18.0',
|
||||
'runtime' => 'node-22',
|
||||
'name' => 'Variable E2E Test',
|
||||
'entrypoint' => 'index.js',
|
||||
'logging' => false,
|
||||
@@ -481,7 +481,7 @@ class FunctionsConsoleClientTest extends Scope
|
||||
|
||||
$deploymentId = $this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.js',
|
||||
'code' => $this->packageFunction('node'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -502,7 +502,7 @@ class FunctionsConsoleClientTest extends Scope
|
||||
{
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'runtime' => 'node-18.0',
|
||||
'runtime' => 'node-22',
|
||||
'name' => 'Download Test',
|
||||
'entrypoint' => 'index.js',
|
||||
'logging' => false,
|
||||
@@ -511,7 +511,7 @@ class FunctionsConsoleClientTest extends Scope
|
||||
|
||||
$deploymentId = $this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.js',
|
||||
'code' => $this->packageFunction('node'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
|
||||
@@ -43,8 +43,8 @@ class FunctionsCustomClientTest extends Scope
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'execute' => [Role::user($this->getUser()['$id'])->toString()],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'events' => [
|
||||
'users.*.create',
|
||||
'users.*.delete',
|
||||
@@ -52,8 +52,7 @@ class FunctionsCustomClientTest extends Scope
|
||||
'timeout' => 10,
|
||||
]);
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -84,13 +83,12 @@ class FunctionsCustomClientTest extends Scope
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'execute' => [Role::any()->toString()],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 10,
|
||||
]);
|
||||
$deploymentId = $this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php-fn'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -107,8 +105,8 @@ class FunctionsCustomClientTest extends Scope
|
||||
$this->assertEquals('Test', $output['APPWRITE_FUNCTION_NAME']);
|
||||
$this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']);
|
||||
$this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']);
|
||||
$this->assertEquals('PHP', $output['APPWRITE_FUNCTION_RUNTIME_NAME']);
|
||||
$this->assertEquals('8.0', $output['APPWRITE_FUNCTION_RUNTIME_VERSION']);
|
||||
$this->assertEquals('Node.js', $output['APPWRITE_FUNCTION_RUNTIME_NAME']);
|
||||
$this->assertEquals('22', $output['APPWRITE_FUNCTION_RUNTIME_VERSION']);
|
||||
$this->assertEquals(APP_VERSION_STABLE, $output['APPWRITE_VERSION']);
|
||||
$this->assertEquals(System::getEnv('_APP_REGION', 'default'), $output['APPWRITE_REGION']);
|
||||
$this->assertEquals('', $output['APPWRITE_FUNCTION_EVENT']);
|
||||
@@ -142,10 +140,10 @@ class FunctionsCustomClientTest extends Scope
|
||||
*/
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'name' => 'Test guest execution',
|
||||
'execute' => [Role::any()->toString()],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'vars' => [
|
||||
'funcKey1' => 'funcValue1',
|
||||
'funcKey2' => 'funcValue2',
|
||||
@@ -154,8 +152,7 @@ class FunctionsCustomClientTest extends Scope
|
||||
'timeout' => 10,
|
||||
]);
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php-fn'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -175,8 +172,8 @@ class FunctionsCustomClientTest extends Scope
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'execute' => [],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 10,
|
||||
]);
|
||||
|
||||
@@ -193,15 +190,14 @@ class FunctionsCustomClientTest extends Scope
|
||||
*/
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'name' => 'Test synchronous execution',
|
||||
'execute' => [Role::any()->toString()],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 10,
|
||||
]);
|
||||
$deploymentId = $this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php-fn'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -214,11 +210,11 @@ class FunctionsCustomClientTest extends Scope
|
||||
$this->assertEquals('completed', $execution['body']['status']);
|
||||
$this->assertEquals(200, $execution['body']['responseStatusCode']);
|
||||
$this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']);
|
||||
$this->assertEquals('Test', $output['APPWRITE_FUNCTION_NAME']);
|
||||
$this->assertEquals('Test synchronous execution', $output['APPWRITE_FUNCTION_NAME']);
|
||||
$this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']);
|
||||
$this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']);
|
||||
$this->assertEquals('PHP', $output['APPWRITE_FUNCTION_RUNTIME_NAME']);
|
||||
$this->assertEquals('8.0', $output['APPWRITE_FUNCTION_RUNTIME_VERSION']);
|
||||
$this->assertEquals('Node.js', $output['APPWRITE_FUNCTION_RUNTIME_NAME']);
|
||||
$this->assertEquals('22', $output['APPWRITE_FUNCTION_RUNTIME_VERSION']);
|
||||
$this->assertEquals(APP_VERSION_STABLE, $output['APPWRITE_VERSION']);
|
||||
$this->assertEquals(System::getEnv('_APP_REGION', 'default'), $output['APPWRITE_REGION']);
|
||||
$this->assertEquals('', $output['APPWRITE_FUNCTION_EVENT']);
|
||||
@@ -239,12 +235,12 @@ class FunctionsCustomClientTest extends Scope
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'execute' => [Role::any()->toString()],
|
||||
'runtime' => 'node-18.0',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js'
|
||||
]);
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.js',
|
||||
'code' => $this->packageFunction('node'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -340,7 +336,7 @@ class FunctionsCustomClientTest extends Scope
|
||||
'limit' => 5,
|
||||
'offset' => 2,
|
||||
'useCases' => ['databases'],
|
||||
'runtimes' => ['node-16.0']
|
||||
'runtimes' => ['node-22']
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $templates['headers']['status-code']);
|
||||
@@ -352,7 +348,7 @@ class FunctionsCustomClientTest extends Scope
|
||||
$this->assertContains($template['useCases'][0], ['databases']);
|
||||
}
|
||||
|
||||
$this->assertContains('node-16.0', array_column($templates['body']['templates'][0]['runtimes'], 'name'));
|
||||
$this->assertContains('node-22', array_column($templates['body']['templates'][0]['runtimes'], 'name'));
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
|
||||
@@ -35,7 +35,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$function = $this->createFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Specs function',
|
||||
'runtime' => 'php-8.0',
|
||||
'runtime' => 'node-22',
|
||||
'specification' => $specifications['body']['specifications'][0]['slug']
|
||||
]);
|
||||
$this->assertEquals(201, $function['headers']['status-code']);
|
||||
@@ -50,7 +50,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$function = $this->createFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Specs function',
|
||||
'runtime' => 'php-8.0',
|
||||
'runtime' => 'node-22',
|
||||
'specification' => 'cheap-please'
|
||||
]);
|
||||
$this->assertEquals(400, $function['headers']['status-code']);
|
||||
@@ -64,8 +64,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
$function = $this->createFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'events' => [
|
||||
'buckets.*.create',
|
||||
'buckets.*.delete',
|
||||
@@ -79,7 +79,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertEquals(201, $function['headers']['status-code']);
|
||||
$this->assertNotEmpty($function['body']['$id']);
|
||||
$this->assertEquals('Test', $function['body']['name']);
|
||||
$this->assertEquals('php-8.0', $function['body']['runtime']);
|
||||
$this->assertEquals('node-22', $function['body']['runtime']);
|
||||
$this->assertEquals(true, $dateValidator->isValid($function['body']['$createdAt']));
|
||||
$this->assertEquals(true, $dateValidator->isValid($function['body']['$updatedAt']));
|
||||
$this->assertEquals('', $function['body']['deploymentId']);
|
||||
@@ -180,7 +180,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
|
||||
// Test search runtime
|
||||
$functions = $this->listFunctions([
|
||||
'search' => 'php-8.0'
|
||||
'search' => 'node-22'
|
||||
]);
|
||||
|
||||
$this->assertEquals($functions['headers']['status-code'], 200);
|
||||
@@ -193,8 +193,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test 2',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'events' => [
|
||||
'buckets.*.create',
|
||||
'buckets.*.delete',
|
||||
@@ -286,8 +286,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
],
|
||||
'schedule' => '0 0 1 1 *',
|
||||
'timeout' => 15,
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
]);
|
||||
|
||||
$dateValidator = new DatetimeValidator();
|
||||
@@ -322,8 +322,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'execute' => [Role::user($this->getUser()['$id'])->toString()],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'events' => [
|
||||
'users.*.create',
|
||||
'users.*.delete',
|
||||
@@ -338,8 +338,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
'x-sdk-language' => 'cli',
|
||||
], [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -363,7 +362,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertEquals(200, $starterTemplate['headers']['status-code']);
|
||||
|
||||
$phpRuntime = array_values(array_filter($starterTemplate['body']['runtimes'], function ($runtime) {
|
||||
return $runtime['name'] === 'php-8.0';
|
||||
return $runtime['name'] === 'node-22';
|
||||
}))[0];
|
||||
|
||||
// If this fails, the template has variables, and this test needs to be updated
|
||||
@@ -373,7 +372,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
[
|
||||
'functionId' => ID::unique(),
|
||||
'name' => $starterTemplate['body']['name'],
|
||||
'runtime' => 'php-8.0',
|
||||
'runtime' => 'node-22',
|
||||
'execute' => $starterTemplate['body']['permissions'],
|
||||
'entrypoint' => $phpRuntime['entrypoint'],
|
||||
'events' => $starterTemplate['body']['events'],
|
||||
@@ -514,7 +513,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$functionId = $data['functionId'];
|
||||
|
||||
$deployment = $this->createDeployment($functionId, [
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -522,7 +521,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertNotEmpty($deployment['body']['$id']);
|
||||
$this->assertEquals('waiting', $deployment['body']['status']);
|
||||
$this->assertEquals(true, (new DatetimeValidator())->isValid($deployment['body']['$createdAt']));
|
||||
$this->assertEquals('index.php', $deployment['body']['entrypoint']);
|
||||
$this->assertEquals('index.js', $deployment['body']['entrypoint']);
|
||||
|
||||
$deploymentIdActive = $deployment['body']['$id'] ?? '';
|
||||
|
||||
@@ -533,7 +532,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
}, 50000, 500);
|
||||
|
||||
$deployment = $this->createDeployment($functionId, [
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => 'false'
|
||||
]);
|
||||
|
||||
@@ -573,7 +572,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$functionId = $data['functionId'];
|
||||
|
||||
$deployment = $this->createDeployment($functionId, [
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => 'false'
|
||||
]);
|
||||
|
||||
@@ -582,7 +581,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
$this->assertNotEmpty($deployment['body']['$id']);
|
||||
$this->assertEquals(true, (new DatetimeValidator())->isValid($deployment['body']['$createdAt']));
|
||||
$this->assertEquals('index.php', $deployment['body']['entrypoint']);
|
||||
$this->assertEquals('index.js', $deployment['body']['entrypoint']);
|
||||
|
||||
$this->assertEventually(function () use ($functionId, $deploymentId) {
|
||||
$deployment = $this->getDeployment($functionId, $deploymentId);
|
||||
@@ -595,12 +594,12 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertEquals(200, $deployment['headers']['status-code']);
|
||||
$this->assertEquals('canceled', $deployment['body']['status']);
|
||||
|
||||
/**
|
||||
* Build worker still runs the build.
|
||||
* 30s sleep gives worker enough time to finish build.
|
||||
* After build finished, it should still be canceled, not ready.
|
||||
*/
|
||||
\sleep(30);
|
||||
// Ensures worker got eventually aware of cancellation and reacted properly
|
||||
$this->assertEventually(function () use ($functionId, $deploymentId) {
|
||||
$deployment = $this->getDeployment($functionId, $deploymentId);
|
||||
$this->assertEquals(200, $deployment['headers']['status-code']);
|
||||
$this->assertStringContainsString('Build has been canceled.', $deployment['body']['buildLogs']);
|
||||
});
|
||||
|
||||
$deployment = $this->getDeployment($functionId, $deploymentId);
|
||||
|
||||
@@ -618,7 +617,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
*/
|
||||
$functionId = $data['functionId'];
|
||||
|
||||
$folder = 'php-large';
|
||||
$folder = 'large';
|
||||
$code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
|
||||
Console::execute('cd ' . realpath(__DIR__ . "/../../../resources/functions") . "/$folder && tar --exclude code.tar.gz -czf code.tar.gz .", '', $this->stdout, $this->stderr);
|
||||
|
||||
@@ -633,13 +632,13 @@ class FunctionsCustomServerTest extends Scope
|
||||
];
|
||||
$id = '';
|
||||
while (!feof($handle)) {
|
||||
$curlFile = new \CURLFile('data://' . $mimeType . ';base64,' . base64_encode(@fread($handle, $chunkSize)), $mimeType, 'php-large-fx.tar.gz');
|
||||
$curlFile = new \CURLFile('data://' . $mimeType . ';base64,' . base64_encode(@fread($handle, $chunkSize)), $mimeType, 'large-fx.tar.gz');
|
||||
$headers['content-range'] = 'bytes ' . ($counter * $chunkSize) . '-' . min(((($counter * $chunkSize) + $chunkSize) - 1), $size - 1) . '/' . $size;
|
||||
if (!empty($id)) {
|
||||
$headers['x-appwrite-id'] = $id;
|
||||
}
|
||||
$largeTag = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge($headers, $this->getHeaders()), [
|
||||
'entrypoint' => 'index.php',
|
||||
'entrypoint' => 'index.js',
|
||||
'code' => $curlFile,
|
||||
'activate' => true,
|
||||
'commands' => 'cp blue.mp4 copy.mp4 && ls -al' // +7MB buildSize
|
||||
@@ -652,7 +651,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertEquals(202, $largeTag['headers']['status-code']);
|
||||
$this->assertNotEmpty($largeTag['body']['$id']);
|
||||
$this->assertEquals(true, (new DatetimeValidator())->isValid($largeTag['body']['$createdAt']));
|
||||
$this->assertEquals('index.php', $largeTag['body']['entrypoint']);
|
||||
$this->assertEquals('index.js', $largeTag['body']['entrypoint']);
|
||||
$this->assertGreaterThan(1024 * 1024 * 5, $largeTag['body']['sourceSize']); // ~7MB video file
|
||||
$this->assertLessThan(1024 * 1024 * 10, $largeTag['body']['sourceSize']); // ~7MB video file
|
||||
|
||||
@@ -903,8 +902,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertStringContainsString($data['deploymentId'], $execution['body']['responseBody']);
|
||||
$this->assertStringContainsString('Test1', $execution['body']['responseBody']);
|
||||
$this->assertStringContainsString('http', $execution['body']['responseBody']);
|
||||
$this->assertStringContainsString('PHP', $execution['body']['responseBody']);
|
||||
$this->assertStringContainsString('8.0', $execution['body']['responseBody']);
|
||||
$this->assertStringContainsString('Node.js', $execution['body']['responseBody']);
|
||||
$this->assertStringContainsString('22', $execution['body']['responseBody']);
|
||||
$this->assertStringContainsString('Global Variable Value', $execution['body']['responseBody']);
|
||||
// $this->assertStringContainsString('êä', $execution['body']['responseBody']); // tests unknown utf-8 chars
|
||||
$this->assertNotEmpty($execution['body']['errors']);
|
||||
@@ -1017,8 +1016,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertEquals(200, $execution['body']['responseStatusCode']);
|
||||
$this->assertStringContainsString('Test1', $execution['body']['responseBody']);
|
||||
$this->assertStringContainsString('http', $execution['body']['responseBody']);
|
||||
$this->assertStringContainsString('PHP', $execution['body']['responseBody']);
|
||||
$this->assertStringContainsString('8.0', $execution['body']['responseBody']);
|
||||
$this->assertStringContainsString('Node.js', $execution['body']['responseBody']);
|
||||
$this->assertStringContainsString('22', $execution['body']['responseBody']);
|
||||
// $this->assertStringContainsString('êä', $execution['body']['response']); // tests unknown utf-8 chars
|
||||
$this->assertLessThan(1.500, $execution['body']['duration']);
|
||||
|
||||
@@ -1120,8 +1119,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
'users.*.update.email',
|
||||
],
|
||||
'timeout' => 15,
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'specification' => Specification::S_1VCPU_1GB,
|
||||
]);
|
||||
|
||||
@@ -1148,8 +1147,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
'users.*.update.email',
|
||||
],
|
||||
'timeout' => 15,
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'specification' => Specification::S_1VCPU_512MB,
|
||||
]);
|
||||
|
||||
@@ -1178,8 +1177,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
'users.*.update.email',
|
||||
],
|
||||
'timeout' => 15,
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'specification' => 's-2vcpu-512mb', // Invalid specification
|
||||
]);
|
||||
|
||||
@@ -1236,9 +1235,9 @@ class FunctionsCustomServerTest extends Scope
|
||||
{
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test php-8.0',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'name' => 'Test timeout execution',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'events' => [],
|
||||
'schedule' => '',
|
||||
'timeout' => 5, // Should timeout after 5 seconds
|
||||
@@ -1280,12 +1279,12 @@ class FunctionsCustomServerTest extends Scope
|
||||
*/
|
||||
public function provideCustomExecutions(): array
|
||||
{
|
||||
// Most disabled to keep tests fast
|
||||
return [
|
||||
['folder' => 'php-fn', 'name' => 'php-8.0', 'entrypoint' => 'index.php', 'runtimeName' => 'PHP', 'runtimeVersion' => '8.0'],
|
||||
['folder' => 'node', 'name' => 'node-18.0', 'entrypoint' => 'index.js', 'runtimeName' => 'Node.js', 'runtimeVersion' => '18.0'],
|
||||
['folder' => 'python', 'name' => 'python-3.9', 'entrypoint' => 'main.py', 'runtimeName' => 'Python', 'runtimeVersion' => '3.9'],
|
||||
['folder' => 'ruby', 'name' => 'ruby-3.1', 'entrypoint' => 'main.rb', 'runtimeName' => 'Ruby', 'runtimeVersion' => '3.1'],
|
||||
// Swift and Dart disabled on purpose, as it's very slow.
|
||||
// ['folder' => 'php-fn', 'name' => 'php-8.0', 'entrypoint' => 'index.php', 'runtimeName' => 'PHP', 'runtimeVersion' => '8.0'],
|
||||
['folder' => 'node', 'name' => 'node-22', 'entrypoint' => 'index.js', 'runtimeName' => 'Node.js', 'runtimeVersion' => '22'],
|
||||
// ['folder' => 'python', 'name' => 'python-3.9', 'entrypoint' => 'main.py', 'runtimeName' => 'Python', 'runtimeVersion' => '3.9'],
|
||||
// ['folder' => 'ruby', 'name' => 'ruby-3.1', 'entrypoint' => 'main.rb', 'runtimeName' => 'Ruby', 'runtimeVersion' => '3.1'],
|
||||
// [ 'folder' => 'dart', 'name' => 'dart-2.15', 'entrypoint' => 'main.dart', 'runtimeName' => 'Dart', 'runtimeVersion' => '2.15' ],
|
||||
// [ 'folder' => 'swift', 'name' => 'swift-5.5', 'entrypoint' => 'index.swift', 'runtimeName' => 'Swift', 'runtimeVersion' => '5.5' ],
|
||||
];
|
||||
@@ -1324,27 +1323,14 @@ class FunctionsCustomServerTest extends Scope
|
||||
]);
|
||||
|
||||
$execution = $this->createExecution($functionId, [
|
||||
'body' => 'foobar',
|
||||
'async' => 'false'
|
||||
]);
|
||||
|
||||
$output = json_decode($execution['body']['responseBody'], true);
|
||||
$this->assertEquals(201, $execution['headers']['status-code']);
|
||||
$this->assertEquals('completed', $execution['body']['status']);
|
||||
$this->assertEquals(200, $execution['body']['responseStatusCode']);
|
||||
$this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']);
|
||||
$this->assertEquals('Test ' . $name, $output['APPWRITE_FUNCTION_NAME']);
|
||||
$this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']);
|
||||
$this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']);
|
||||
$this->assertEquals($runtimeName, $output['APPWRITE_FUNCTION_RUNTIME_NAME']);
|
||||
$this->assertEquals($runtimeVersion, $output['APPWRITE_FUNCTION_RUNTIME_VERSION']);
|
||||
$this->assertEquals('', $output['APPWRITE_FUNCTION_EVENT']);
|
||||
$this->assertEquals('foobar', $output['APPWRITE_FUNCTION_DATA']);
|
||||
$this->assertEquals('variable', $output['CUSTOM_VARIABLE']);
|
||||
$this->assertEmpty($output['APPWRITE_FUNCTION_USER_ID']);
|
||||
$this->assertEmpty($output['APPWRITE_FUNCTION_JWT']);
|
||||
$this->assertEquals($this->getProject()['$id'], $output['APPWRITE_FUNCTION_PROJECT_ID']);
|
||||
$this->assertStringContainsString('Amazing Function Log', $execution['body']['logs']);
|
||||
$this->assertEquals('OK', $execution['body']['responseBody']);
|
||||
$this->assertEmpty($execution['body']['logs']);
|
||||
$this->assertEmpty($execution['body']['errors']);
|
||||
|
||||
$executionId = $execution['body']['$id'] ?? '';
|
||||
@@ -1357,7 +1343,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertCount(1, $executions['body']['executions']);
|
||||
$this->assertEquals($executions['body']['executions'][0]['$id'], $executionId);
|
||||
$this->assertEquals($executions['body']['executions'][0]['trigger'], 'http');
|
||||
$this->assertStringContainsString('Amazing Function Log', $executions['body']['executions'][0]['logs']);
|
||||
$this->assertEquals(200, $executions['body']['executions'][0]['responseStatusCode']);
|
||||
$this->assertEmpty($executions['body']['executions'][0]['responseBody']);
|
||||
|
||||
$this->cleanupFunction($functionId);
|
||||
}
|
||||
@@ -1366,15 +1353,14 @@ class FunctionsCustomServerTest extends Scope
|
||||
{
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test PHP Binary executions',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'name' => 'Test Binary executions',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 15,
|
||||
'execute' => ['any']
|
||||
]);
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php-binary-response'),
|
||||
'code' => $this->packageFunction('binary-response'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -1415,15 +1401,14 @@ class FunctionsCustomServerTest extends Scope
|
||||
{
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test PHP Binary executions',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'name' => 'Test Binary executions',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 15,
|
||||
'execute' => ['any']
|
||||
]);
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php-binary-request'),
|
||||
'code' => $this->packageFunction('binary-request'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -1461,49 +1446,6 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->cleanupFunction($functionId);
|
||||
}
|
||||
|
||||
public function testv2Function()
|
||||
{
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test PHP V2',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'events' => [],
|
||||
'timeout' => 15,
|
||||
]);
|
||||
|
||||
$variable = $this->client->call(Client::METHOD_PATCH, '/mock/functions-v2', [
|
||||
'content-type' => 'application/json',
|
||||
'origin' => 'http://localhost',
|
||||
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-mode' => 'admin',
|
||||
], [
|
||||
'functionId' => $functionId
|
||||
]);
|
||||
$this->assertEquals(204, $variable['headers']['status-code']);
|
||||
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php-v2'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
$execution = $this->createExecution($functionId, [
|
||||
'body' => 'foobar',
|
||||
'async' => 'false'
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $execution['headers']['status-code']);
|
||||
$this->assertEquals('completed', $execution['body']['status']);
|
||||
$this->assertEquals(200, $execution['body']['responseStatusCode']);
|
||||
|
||||
$output = json_decode($execution['body']['responseBody'], true);
|
||||
$this->assertEquals(true, $output['v2Woks']);
|
||||
|
||||
$this->cleanupFunction($functionId);
|
||||
}
|
||||
|
||||
public function testGetRuntimes()
|
||||
{
|
||||
$runtimes = $this->client->call(Client::METHOD_GET, '/functions/runtimes', array_merge([
|
||||
@@ -1531,17 +1473,16 @@ class FunctionsCustomServerTest extends Scope
|
||||
{
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test PHP Event executions',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'name' => 'Test Event executions',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'events' => [
|
||||
'users.*.create',
|
||||
],
|
||||
'timeout' => 15,
|
||||
]);
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php-event'),
|
||||
'code' => $this->packageFunction('event-handler'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -1584,17 +1525,16 @@ class FunctionsCustomServerTest extends Scope
|
||||
{
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test PHP Scopes executions',
|
||||
'commands' => 'bash setup.sh && composer install',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'name' => 'Test Scopes executions',
|
||||
'commands' => 'bash setup.sh && npm install',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'scopes' => ['users.read'],
|
||||
'timeout' => 15,
|
||||
]);
|
||||
|
||||
$deploymentId = $this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php-scopes'),
|
||||
'code' => $this->packageFunction('dynamic-api-key'),
|
||||
'activate' => true,
|
||||
]);
|
||||
|
||||
@@ -1643,16 +1583,15 @@ class FunctionsCustomServerTest extends Scope
|
||||
{
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test PHP Cookie executions',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'name' => 'Test Cookie executions',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 15,
|
||||
]);
|
||||
$this->assertNotEmpty($functionId);
|
||||
|
||||
$deploymentId = $this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php-cookie'),
|
||||
'code' => $this->packageFunction('cookies'),
|
||||
'activate' => true
|
||||
]);
|
||||
$this->assertNotEmpty($deploymentId);
|
||||
@@ -1685,9 +1624,9 @@ class FunctionsCustomServerTest extends Scope
|
||||
{
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test PHP Cookie executions',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'name' => 'Test Cookie executions',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 15,
|
||||
'execute' => ['any']
|
||||
]);
|
||||
@@ -1695,8 +1634,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$domain = $this->setupFunctionDomain($functionId);
|
||||
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php-cookie'),
|
||||
'code' => $this->packageFunction('cookies'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -1743,9 +1681,9 @@ class FunctionsCustomServerTest extends Scope
|
||||
{
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test PHP Binary executions',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'name' => 'Test Binary executions',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 15,
|
||||
'execute' => ['any']
|
||||
]);
|
||||
@@ -1753,8 +1691,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$domain = $this->setupFunctionDomain($functionId);
|
||||
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php-binary-response'),
|
||||
'code' => $this->packageFunction('binary-response'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -1778,9 +1715,9 @@ class FunctionsCustomServerTest extends Scope
|
||||
{
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test PHP Binary executions',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'name' => 'Test Binary executions',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 15,
|
||||
'execute' => ['any']
|
||||
]);
|
||||
@@ -1788,8 +1725,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$domain = $this->setupFunctionDomain($functionId);
|
||||
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php-binary-request'),
|
||||
'code' => $this->packageFunction('binary-request'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -1816,8 +1752,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
], $this->getHeaders()), [
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 15,
|
||||
]);
|
||||
|
||||
@@ -1851,8 +1787,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
$function1Id = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 15,
|
||||
'execute' => ['any']
|
||||
]);
|
||||
@@ -1860,8 +1796,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
$function2Id = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test2',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 15,
|
||||
'execute' => ['any']
|
||||
]);
|
||||
@@ -1892,7 +1828,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
{
|
||||
$function = $this->createFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'runtime' => 'node-18.0',
|
||||
'runtime' => 'node-22',
|
||||
'name' => 'Logging Test',
|
||||
'entrypoint' => 'index.js',
|
||||
'logging' => false,
|
||||
@@ -1908,7 +1844,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$domain = $this->setupFunctionDomain($functionId);
|
||||
|
||||
$this->setupDeployment($functionId, [
|
||||
'code' => $this->packageFunction('node'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -1985,7 +1921,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
// Check if the function specifications are correctly set in builds
|
||||
$function = $this->createFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'runtime' => 'node-18.0',
|
||||
'runtime' => 'node-22',
|
||||
'name' => 'Specification Test',
|
||||
'entrypoint' => 'index.js',
|
||||
'logging' => false,
|
||||
@@ -2001,7 +1937,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$functionId = $functionId = $function['body']['$id'] ?? '';
|
||||
|
||||
$deploymentId = $this->setupDeployment($functionId, [
|
||||
'code' => $this->packageFunction('node'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -2027,7 +1963,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
{
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'runtime' => 'node-18.0',
|
||||
'runtime' => 'node-22',
|
||||
'name' => 'Duplicate Deployment Test',
|
||||
'entrypoint' => 'index.js',
|
||||
'commands' => ''
|
||||
@@ -2035,7 +1971,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertNotEmpty($functionId);
|
||||
|
||||
$deploymentId1 = $this->setupDeployment($functionId, [
|
||||
'code' => $this->packageFunction('node'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
$this->assertNotEmpty($deploymentId1);
|
||||
@@ -2045,7 +1981,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertStringContainsString('APPWRITE_FUNCTION_ID', $execution['body']['responseBody']);
|
||||
|
||||
$function = $this->updateFunction($functionId, [
|
||||
'runtime' => 'node-18.0',
|
||||
'runtime' => 'node-22',
|
||||
'name' => 'Duplicate Deployment Test',
|
||||
'entrypoint' => 'index.js',
|
||||
'commands' => 'rm index.js && mv maintenance.js index.js'
|
||||
@@ -2089,13 +2025,12 @@ class FunctionsCustomServerTest extends Scope
|
||||
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'runtime' => 'php-8.0',
|
||||
'runtime' => 'node-22',
|
||||
'name' => 'Re-activate Test',
|
||||
'entrypoint' => 'index.php',
|
||||
'entrypoint' => 'index.js',
|
||||
]);
|
||||
$this->assertNotEmpty($functionId);
|
||||
|
||||
|
||||
$function = $this->getFunction($functionId);
|
||||
$this->assertEquals(200, $function['headers']['status-code']);
|
||||
$this->assertArrayHasKey('latestDeploymentId', $function['body']);
|
||||
@@ -2106,7 +2041,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertEmpty($function['body']['latestDeploymentStatus']);
|
||||
|
||||
$deploymentId1 = $this->setupDeployment($functionId, [
|
||||
'code' => $this->packageFunction('php-cookie'),
|
||||
'code' => $this->packageFunction('cookies'),
|
||||
'activate' => true
|
||||
]);
|
||||
$this->assertNotEmpty($deploymentId1);
|
||||
@@ -2124,7 +2059,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertStringContainsString('cookieValue', $execution['body']['responseBody']);
|
||||
|
||||
$deploymentId2 = $this->setupDeployment($functionId, [
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
$this->assertNotEmpty($deploymentId2);
|
||||
@@ -2192,8 +2127,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test Error Pages',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 15,
|
||||
'commands' => 'cd non-existing-directory',
|
||||
'execute' => ['any']
|
||||
@@ -2203,8 +2138,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$proxyClient->setEndpoint('http://' . $domain);
|
||||
|
||||
$deployment = $this->createDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -2221,8 +2155,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
|
||||
// canceled deployment
|
||||
$deployment = $this->createDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -2250,8 +2183,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test Error Pages',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 15,
|
||||
'commands' => '',
|
||||
'execute' => ['users']
|
||||
@@ -2262,7 +2195,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$proxyClient->setEndpoint('http://' . $domain);
|
||||
|
||||
$deploymentId = $this->setupDeployment($functionId, [
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
$this->assertNotEmpty($deploymentId);
|
||||
@@ -2284,8 +2217,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test Error Pages',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 15,
|
||||
'commands' => '',
|
||||
'execute' => ['any']
|
||||
@@ -2296,7 +2229,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$proxyClient->setEndpoint('http://' . $domain);
|
||||
|
||||
$deploymentId = $this->setupDeployment($functionId, [
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
$this->assertNotEmpty($deploymentId);
|
||||
|
||||
@@ -25,8 +25,8 @@ class FunctionsScheduleTest extends Scope
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'execute' => [Role::user($this->getUser()['$id'])->toString()],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'events' => [
|
||||
'users.*.create',
|
||||
'users.*.delete',
|
||||
@@ -36,8 +36,7 @@ class FunctionsScheduleTest extends Scope
|
||||
]);
|
||||
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -77,14 +76,13 @@ class FunctionsScheduleTest extends Scope
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'execute' => [Role::user($this->getUser()['$id'])->toString()],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 10,
|
||||
'logging' => true,
|
||||
]);
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -179,15 +177,14 @@ class FunctionsScheduleTest extends Scope
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'execute' => [Role::user($this->getUser()['$id'])->toString()],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 10,
|
||||
'logging' => true,
|
||||
]);
|
||||
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
|
||||
@@ -26,8 +26,8 @@ class FunctionsClientTest extends Scope
|
||||
'variables' => [
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test Function',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'execute' => [Role::any()->toString()],
|
||||
]
|
||||
];
|
||||
@@ -96,7 +96,7 @@ class FunctionsClientTest extends Scope
|
||||
'map' => \json_encode([
|
||||
'code' => ["variables.code"]
|
||||
]),
|
||||
'code' => $this->packageFunction('php')
|
||||
'code' => $this->packageFunction('basic')
|
||||
];
|
||||
|
||||
$deployment = $this->client->call(Client::METHOD_POST, '/graphql', [
|
||||
|
||||
@@ -26,8 +26,8 @@ class FunctionsServerTest extends Scope
|
||||
'variables' => [
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test Function',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.js',
|
||||
'runtime' => 'node-22',
|
||||
'execute' => [Role::any()->toString()],
|
||||
]
|
||||
];
|
||||
@@ -95,7 +95,7 @@ class FunctionsServerTest extends Scope
|
||||
'map' => \json_encode([
|
||||
'code' => ["variables.code"]
|
||||
]),
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
];
|
||||
|
||||
$deployment = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
|
||||
|
||||
@@ -805,13 +805,12 @@ trait MigrationsBase
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php'
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js'
|
||||
]);
|
||||
|
||||
$deploymentId = $this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -855,8 +854,8 @@ trait MigrationsBase
|
||||
|
||||
$this->assertEquals($functionId, $response['body']['$id']);
|
||||
$this->assertEquals('Test', $response['body']['name']);
|
||||
$this->assertEquals('php-8.0', $response['body']['runtime']);
|
||||
$this->assertEquals('index.php', $response['body']['entrypoint']);
|
||||
$this->assertEquals('node-22', $response['body']['runtime']);
|
||||
$this->assertEquals('index.js', $response['body']['entrypoint']);
|
||||
|
||||
|
||||
$this->assertEventually(function () use ($functionId) {
|
||||
|
||||
@@ -30,8 +30,6 @@ class ProjectsCustomServerTest extends Scope
|
||||
'domain' => $testId . '-api.appwrite.test',
|
||||
]);
|
||||
|
||||
\var_dump($response);
|
||||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/proxy/rules/api', $headers, [
|
||||
|
||||
@@ -227,7 +227,7 @@ trait ProxyBase
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), [
|
||||
'functionId' => ID::unique(),
|
||||
'runtime' => 'node-18.0',
|
||||
'runtime' => 'node-22',
|
||||
'name' => 'Proxy Function',
|
||||
'entrypoint' => 'index.js',
|
||||
'commands' => '',
|
||||
@@ -244,7 +244,7 @@ trait ProxyBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), [
|
||||
'code' => $this->packageFunction('node'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => 'true'
|
||||
]);
|
||||
|
||||
|
||||
@@ -874,8 +874,8 @@ class RealtimeConsoleClientTest extends Scope
|
||||
], $this->getHeaders()), [
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'events' => [
|
||||
'users.*.create',
|
||||
'users.*.delete',
|
||||
@@ -914,8 +914,7 @@ class RealtimeConsoleClientTest extends Scope
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $projectId,
|
||||
], $this->getHeaders()), [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
|
||||
@@ -1296,10 +1296,10 @@ class RealtimeCustomClientTest extends Scope
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'name' => 'Test timeout execution',
|
||||
'execute' => ['users'],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 10,
|
||||
]);
|
||||
|
||||
@@ -1313,7 +1313,6 @@ class RealtimeCustomClientTest extends Scope
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('timeout'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -14,6 +14,9 @@ class SitesConsoleClientTest extends Scope
|
||||
use SideConsole;
|
||||
use SitesBase;
|
||||
|
||||
/**
|
||||
* @group screenshots
|
||||
*/
|
||||
public function testSiteScreenshot(): void
|
||||
{
|
||||
$siteId = $this->setupSite([
|
||||
|
||||
@@ -937,12 +937,12 @@ class SitesCustomServerTest extends Scope
|
||||
$this->assertEquals(200, $deployment['headers']['status-code']);
|
||||
$this->assertEquals('canceled', $deployment['body']['status']);
|
||||
|
||||
/**
|
||||
* Build worker still runs the build.
|
||||
* 30s sleep gives worker enough time to finish build.
|
||||
* After build finished, it should still be canceled, not ready.
|
||||
*/
|
||||
\sleep(30);
|
||||
// Ensures worker got eventually aware of cancellation and reacted properly
|
||||
$this->assertEventually(function () use ($siteId, $deploymentId) {
|
||||
$deployment = $this->getDeployment($siteId, $deploymentId);
|
||||
$this->assertEquals(200, $deployment['headers']['status-code']);
|
||||
$this->assertStringContainsString('Build has been canceled.', $deployment['body']['buildLogs']);
|
||||
});
|
||||
|
||||
$deployment = $this->getDeployment($siteId, $deploymentId);
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ namespace Tests\E2E\Services\Tokens;
|
||||
use CURLFile;
|
||||
use Tests\E2E\Client;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
|
||||
trait TokensBase
|
||||
{
|
||||
@@ -275,4 +277,88 @@ trait TokensBase
|
||||
$this->assertEquals($image->getImageHeight(), $original->getImageHeight());
|
||||
$this->assertEquals('PNG', $image->getImageFormat());
|
||||
}
|
||||
|
||||
public function testFileAccessWithFileSecurity(): void
|
||||
{
|
||||
$bucket = $this->client->call(
|
||||
Client::METHOD_POST,
|
||||
'/storage/buckets',
|
||||
[
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
],
|
||||
[
|
||||
'name' => 'Test Bucket',
|
||||
'bucketId' => ID::unique(),
|
||||
'fileSecurity' => true,
|
||||
'allowedFileExtensions' => ['jpg', 'png', 'jfif'],
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(201, $bucket['headers']['status-code']);
|
||||
$this->assertNotEmpty($bucket['body']['$id']);
|
||||
|
||||
$bucketId = $bucket['body']['$id'];
|
||||
|
||||
$file = $this->client->call(
|
||||
Client::METHOD_POST,
|
||||
'/storage/buckets/' . $bucketId . '/files',
|
||||
[
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
],
|
||||
[
|
||||
'fileId' => ID::unique(),
|
||||
'permissions' => [ Permission::read(Role::label('devrel')) ],
|
||||
'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'),
|
||||
]
|
||||
);
|
||||
|
||||
$fileId = $file['body']['$id'];
|
||||
|
||||
$token = $this->client->call(
|
||||
Client::METHOD_POST,
|
||||
'/tokens/buckets/' . $bucketId . '/files/' . $fileId,
|
||||
[
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]
|
||||
);
|
||||
|
||||
$jwtToken = $token['body']['secret'];
|
||||
|
||||
$endpoints = ['preview', 'view', 'download'];
|
||||
|
||||
foreach ($endpoints as $endpoint) {
|
||||
$response = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
"/storage/buckets/$bucketId/files/$fileId/$endpoint",
|
||||
[
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
],
|
||||
[
|
||||
'token' => $jwtToken
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals('image/png', $response['headers']['content-type']);
|
||||
|
||||
if ($endpoint === 'download') {
|
||||
$image = new \Imagick();
|
||||
$image->readImageBlob($response['body']);
|
||||
$original = new \Imagick(__DIR__ . '/../../../resources/logo.png');
|
||||
|
||||
$this->assertEquals($original->getImageWidth(), $image->getImageWidth());
|
||||
$this->assertEquals($original->getImageHeight(), $image->getImageHeight());
|
||||
$this->assertEquals('PNG', $image->getImageFormat());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -586,8 +586,8 @@ class WebhooksCustomServerTest extends Scope
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'execute' => [Role::any()->toString()],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 10,
|
||||
]);
|
||||
|
||||
@@ -626,8 +626,8 @@ class WebhooksCustomServerTest extends Scope
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'Test',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'execute' => [Role::any()->toString()],
|
||||
'vars' => [
|
||||
'key1' => 'value1',
|
||||
@@ -683,7 +683,7 @@ class WebhooksCustomServerTest extends Scope
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'entrypoint' => 'index.php',
|
||||
'entrypoint' => 'index.js',
|
||||
'code' => new CURLFile($code, 'application/x-gzip', \basename($code)),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
module.exports = async(context) => {
|
||||
context.log('log-works');
|
||||
context.error('error-log-works');
|
||||
|
||||
if(context.req.headers['x-appwrite-user-jwt']) {
|
||||
context.log('jwt-is-valid');
|
||||
} else {
|
||||
context.log('jwt-is-invalid');
|
||||
}
|
||||
|
||||
if(context.req.path === '/custom-response') {
|
||||
const code = +(context.req.query['code'] || '200');
|
||||
const body = context.req.query['body'] || '';
|
||||
return context.res.send(body, code);
|
||||
}
|
||||
|
||||
context.log('body-is-' + (context.req.body ?? ''));
|
||||
context.log('custom-header-is-' + (context.req.headers['x-custom-header'] ?? ''));
|
||||
context.log('method-is-' + (context.req.method ?? '').toLowerCase());
|
||||
context.log('path-is-' + (context.req.path ?? ''));
|
||||
context.log('user-is-' + (context.req.headers['x-appwrite-user-id'] ?? ''));
|
||||
|
||||
const statusCode = context.req.query['code'] || '200';
|
||||
|
||||
return context.res.json({
|
||||
'APPWRITE_FUNCTION_ID' : process.env.APPWRITE_FUNCTION_ID ?? '',
|
||||
'APPWRITE_FUNCTION_NAME' : process.env.APPWRITE_FUNCTION_NAME ?? '',
|
||||
'APPWRITE_FUNCTION_DEPLOYMENT' : process.env.APPWRITE_FUNCTION_DEPLOYMENT ?? '',
|
||||
'APPWRITE_FUNCTION_TRIGGER' : context.req.headers['x-appwrite-trigger'] ?? '',
|
||||
'APPWRITE_FUNCTION_RUNTIME_NAME' : process.env.APPWRITE_FUNCTION_RUNTIME_NAME,
|
||||
'APPWRITE_FUNCTION_RUNTIME_VERSION' : process.env.APPWRITE_FUNCTION_RUNTIME_VERSION,
|
||||
'APPWRITE_VERSION' : process.env.APPWRITE_VERSION ?? '',
|
||||
'APPWRITE_REGION' : process.env.APPWRITE_REGION ?? '',
|
||||
'UNICODE_TEST' : "êä",
|
||||
'GLOBAL_VARIABLE' : process.env.GLOBAL_VARIABLE ?? '',
|
||||
'APPWRITE_FUNCTION_EVENT' : context.req.headers['x-appwrite-event'] ?? '',
|
||||
'APPWRITE_FUNCTION_EVENT_DATA' : context.req.bodyRaw ?? '',
|
||||
'APPWRITE_FUNCTION_DATA' : context.req.bodyRaw ?? '',
|
||||
'APPWRITE_FUNCTION_USER_ID' : context.req.headers['x-appwrite-user-id'] ?? '',
|
||||
'APPWRITE_FUNCTION_JWT' : context.req.headers['x-appwrite-user-jwt'] ?? '',
|
||||
'APPWRITE_FUNCTION_PROJECT_ID' : process.env.APPWRITE_FUNCTION_PROJECT_ID,
|
||||
'APPWRITE_FUNCTION_MEMORY' : process.env.APPWRITE_FUNCTION_MEMORY,
|
||||
'APPWRITE_FUNCTION_CPUS' : process.env.APPWRITE_FUNCTION_CPUS,
|
||||
'CUSTOM_VARIABLE' : process.env.CUSTOM_VARIABLE
|
||||
}, +statusCode);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
const crypto = require('crypto')
|
||||
|
||||
module.exports = async(context) => {
|
||||
const hash = crypto.createHash('md5').update(context.req.bodyBinary).digest("hex")
|
||||
return context.res.send(hash);
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
module.exports = async(context) => {
|
||||
const bytes = Buffer.from(Uint8Array.from([0, 10, 255]));
|
||||
return context.res.binary(bytes);
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
module.exports = async(context) => {
|
||||
return context.res.send(context.req.headers['cookie'] ?? '');
|
||||
};
|
||||
@@ -1,21 +0,0 @@
|
||||
import 'dart:io' show Platform;
|
||||
|
||||
Future<dynamic> main(final context) async {
|
||||
context.log('Amazing Function Log');
|
||||
|
||||
response.json({
|
||||
'APPWRITE_FUNCTION_ID' : Platform.environment['APPWRITE_FUNCTION_ID'] ?? '',
|
||||
'APPWRITE_FUNCTION_NAME' : Platform.environment['APPWRITE_FUNCTION_NAME'] ?? '',
|
||||
'APPWRITE_FUNCTION_DEPLOYMENT' : Platform.environment['APPWRITE_FUNCTION_DEPLOYMENT'] ?? '',
|
||||
'APPWRITE_FUNCTION_TRIGGER' : context.req.headers['x-appwrite-trigger'] ?? '',
|
||||
'APPWRITE_FUNCTION_RUNTIME_NAME' : Platform.environment['APPWRITE_FUNCTION_RUNTIME_NAME'] ?? '',
|
||||
'APPWRITE_FUNCTION_RUNTIME_VERSION' : Platform.environment['APPWRITE_FUNCTION_RUNTIME_VERSION'] ?? '',
|
||||
'APPWRITE_FUNCTION_EVENT' : context.req.headers['x-appwrite-event'] ?? '',
|
||||
'APPWRITE_FUNCTION_EVENT_DATA' : context.req.bodyRaw ?? '',
|
||||
'APPWRITE_FUNCTION_DATA' : context.req.bodyRaw ?? '',
|
||||
'APPWRITE_FUNCTION_USER_ID' : context.req.headers['x-appwrite-user-id'] ?? '',
|
||||
'APPWRITE_FUNCTION_JWT' : context.req.headers['x-appwrite-user-jwt'] ?? '',
|
||||
'APPWRITE_FUNCTION_PROJECT_ID' : Platform.environment['APPWRITE_FUNCTION_PROJECT_ID'] ?? '',
|
||||
'CUSTOM_VARIABLE' : request.variables['CUSTOM_VARIABLE']
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
const sdk = require('node-appwrite');
|
||||
|
||||
module.exports = async(context) => {
|
||||
const client = new sdk.Client();
|
||||
client.setEndpoint(process.env.APPWRITE_FUNCTION_API_ENDPOINT);
|
||||
client.setProject(process.env.APPWRITE_FUNCTION_PROJECT_ID);
|
||||
client.setKey(context.req.headers['x-appwrite-key']);
|
||||
|
||||
const users = new sdk.Users(client);
|
||||
|
||||
const response = await users.list();
|
||||
context.log(JSON.stringify(response));
|
||||
|
||||
return context.res.json(response);
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "dynamic-api-key",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "dynamic-api-key",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"node-appwrite": "^17.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-appwrite": {
|
||||
"version": "17.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-appwrite/-/node-appwrite-17.0.0.tgz",
|
||||
"integrity": "sha512-5Moi5ENPnoAfU1/6CZP9K2NTuB6Nm3dSyhokno+24RDuP7czjXCdwzfeyjmyHieggbrLkN89AYSOv9W1XkCL9w==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"node-fetch-native-with-agent": "1.7.2"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch-native-with-agent": {
|
||||
"version": "1.7.2",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch-native-with-agent/-/node-fetch-native-with-agent-1.7.2.tgz",
|
||||
"integrity": "sha512-5MaOOCuJEvcckoz7/tjdx1M6OusOY6Xc5f459IaruGStWnKzlI1qpNgaAwmn4LmFYcsSlj+jBMk84wmmRxfk5g==",
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "dynamic-api-key",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"node-appwrite": "^17.0.0"
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
|
||||
ENDPOINT="$APPWRITE_FUNCTION_API_ENDPOINT/users"
|
||||
PROJECT_ID="$APPWRITE_FUNCTION_PROJECT_ID"
|
||||
API_KEY="$APPWRITE_FUNCTION_API_KEY"
|
||||
|
||||
apk add curl
|
||||
|
||||
curl -v -X GET $ENDPOINT -H "x-appwrite-project: $PROJECT_ID" -H "x-appwrite-key: $API_KEY"
|
||||
@@ -0,0 +1,5 @@
|
||||
module.exports = async(context) => {
|
||||
context.log(context.req.body.$id);
|
||||
context.log(context.req.body.name);
|
||||
return context.res.empty();
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
module.exports = async(context) => {
|
||||
return context.res.empty();
|
||||
};
|
||||
@@ -1,21 +1,3 @@
|
||||
module.exports = async(context) => {
|
||||
context.log('Amazing Function Log');
|
||||
|
||||
return context.res.json({
|
||||
'APPWRITE_FUNCTION_ID' : process.env.APPWRITE_FUNCTION_ID ?? '',
|
||||
'APPWRITE_FUNCTION_NAME' : process.env.APPWRITE_FUNCTION_NAME ?? '',
|
||||
'APPWRITE_FUNCTION_DEPLOYMENT' : process.env.APPWRITE_FUNCTION_DEPLOYMENT ?? '',
|
||||
'APPWRITE_FUNCTION_TRIGGER' : context.req.headers['x-appwrite-trigger'] ?? '',
|
||||
'APPWRITE_FUNCTION_RUNTIME_NAME' : process.env.APPWRITE_FUNCTION_RUNTIME_NAME,
|
||||
'APPWRITE_FUNCTION_RUNTIME_VERSION' : process.env.APPWRITE_FUNCTION_RUNTIME_VERSION,
|
||||
'APPWRITE_FUNCTION_EVENT' : context.req.headers['x-appwrite-event'] ?? '',
|
||||
'APPWRITE_FUNCTION_EVENT_DATA' : context.req.bodyRaw ?? '',
|
||||
'APPWRITE_FUNCTION_DATA' : context.req.bodyRaw ?? '',
|
||||
'APPWRITE_FUNCTION_USER_ID' : context.req.headers['x-appwrite-user-id'] ?? '',
|
||||
'APPWRITE_FUNCTION_JWT' : context.req.headers['x-appwrite-user-jwt'] ?? '',
|
||||
'APPWRITE_FUNCTION_PROJECT_ID' : process.env.APPWRITE_FUNCTION_PROJECT_ID,
|
||||
'APPWRITE_FUNCTION_MEMORY' : process.env.APPWRITE_FUNCTION_MEMORY,
|
||||
'APPWRITE_FUNCTION_CPUS' : process.env.APPWRITE_FUNCTION_CPUS,
|
||||
'CUSTOM_VARIABLE' : process.env.CUSTOM_VARIABLE
|
||||
});
|
||||
return context.res.send('OK');
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
|
||||
return function ($context) {
|
||||
$hash = md5($context->req->bodyBinary);
|
||||
return $context->res->send($hash);
|
||||
};
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
|
||||
return function ($context) {
|
||||
$bytes = pack('C*', ...[0, 10, 255]);
|
||||
return $context->res->binary($bytes);
|
||||
};
|
||||
@@ -1,5 +0,0 @@
|
||||
<?php
|
||||
|
||||
return function ($context) {
|
||||
return $context->res->send($context->req->headers['cookie'] ?? '');
|
||||
};
|
||||
@@ -1,8 +0,0 @@
|
||||
<?php
|
||||
|
||||
return function ($context) {
|
||||
$context->log($context->req->body['$id']);
|
||||
$context->log($context->req->body['name']);
|
||||
|
||||
return $context->res->empty();
|
||||
};
|
||||
@@ -1,23 +0,0 @@
|
||||
<?php
|
||||
|
||||
return function ($context) {
|
||||
$context->log('Amazing Function Log');
|
||||
|
||||
return $context->res->json([
|
||||
'APPWRITE_FUNCTION_ID' => \getenv('APPWRITE_FUNCTION_ID') ?: '',
|
||||
'APPWRITE_FUNCTION_NAME' => \getenv('APPWRITE_FUNCTION_NAME') ?: '',
|
||||
'APPWRITE_FUNCTION_DEPLOYMENT' => \getenv('APPWRITE_FUNCTION_DEPLOYMENT') ?: '',
|
||||
'APPWRITE_FUNCTION_TRIGGER' => $context->req->headers['x-appwrite-trigger'] ?? '',
|
||||
'APPWRITE_FUNCTION_RUNTIME_NAME' => \getenv('APPWRITE_FUNCTION_RUNTIME_NAME') ?: '',
|
||||
'APPWRITE_FUNCTION_RUNTIME_VERSION' => \getenv('APPWRITE_FUNCTION_RUNTIME_VERSION') ?: '',
|
||||
'APPWRITE_VERSION' => \getenv('APPWRITE_VERSION') ?: '',
|
||||
'APPWRITE_REGION' => \getenv('APPWRITE_REGION') ?: '',
|
||||
'APPWRITE_FUNCTION_EVENT' => $context->req->headers['x-appwrite-event'] ?? '',
|
||||
'APPWRITE_FUNCTION_EVENT_DATA' => $context->req->bodyRaw ?? '',
|
||||
'APPWRITE_FUNCTION_DATA' => $context->req->bodyRaw ?? '',
|
||||
'APPWRITE_FUNCTION_USER_ID' => $context->req->headers['x-appwrite-user-id'] ?? '',
|
||||
'APPWRITE_FUNCTION_JWT' => $context->req->headers['x-appwrite-user-jwt'] ?? '',
|
||||
'APPWRITE_FUNCTION_PROJECT_ID' => \getenv('APPWRITE_FUNCTION_PROJECT_ID') ?: '',
|
||||
'CUSTOM_VARIABLE' => \getenv('CUSTOM_VARIABLE') ?: '',
|
||||
]);
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"name": "appwrite/cloud-function-demo",
|
||||
"description": "Demo cloud function script",
|
||||
"type": "library",
|
||||
"license": "BSD-3-Clause",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Team Appwrite",
|
||||
"email": "team@appwrite.io"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.4.0",
|
||||
"ext-curl": "*",
|
||||
"ext-json": "*",
|
||||
"appwrite/appwrite": "1.1.*"
|
||||
}
|
||||
}
|
||||
-64
@@ -1,64 +0,0 @@
|
||||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "afdff6a172e6c44aee11f1562175f81a",
|
||||
"packages": [
|
||||
{
|
||||
"name": "appwrite/appwrite",
|
||||
"version": "1.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appwrite/sdk-for-php.git",
|
||||
"reference": "98b327d3fd18a72f4582019916afd735a0e9e0e7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-for-php/zipball/98b327d3fd18a72f4582019916afd735a0e9e0e7",
|
||||
"reference": "98b327d3fd18a72f4582019916afd735a0e9e0e7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-curl": "*",
|
||||
"ext-json": "*",
|
||||
"php": ">=7.1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "3.7.35"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Appwrite\\": "src/Appwrite"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"description": "Appwrite is an open-source backend as a service server that abstract and simplify complex and repetitive development tasks",
|
||||
"support": {
|
||||
"email": "team@localhost.test",
|
||||
"issues": "https://github.com/appwrite/sdk-for-php/issues",
|
||||
"source": "https://github.com/appwrite/sdk-for-php/tree/1.1.2",
|
||||
"url": "https://appwrite.io/support"
|
||||
},
|
||||
"time": "2020-08-15T18:24:32+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": ">=7.4.0",
|
||||
"ext-curl": "*",
|
||||
"ext-json": "*"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.0.0"
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
return function ($context) {
|
||||
return $context->res->json([
|
||||
'APPWRITE_FUNCTION_ID' => \getenv('APPWRITE_FUNCTION_ID') ?: '',
|
||||
'APPWRITE_FUNCTION_NAME' => \getenv('APPWRITE_FUNCTION_NAME') ?: '',
|
||||
'APPWRITE_FUNCTION_DEPLOYMENT' => \getenv('APPWRITE_FUNCTION_DEPLOYMENT') ?: '',
|
||||
'APPWRITE_FUNCTION_TRIGGER' => $context->req->headers['x-appwrite-trigger'] ?? '',
|
||||
'APPWRITE_FUNCTION_RUNTIME_NAME' => \getenv('APPWRITE_FUNCTION_RUNTIME_NAME') ?: '',
|
||||
'APPWRITE_FUNCTION_RUNTIME_VERSION' => \getenv('APPWRITE_FUNCTION_RUNTIME_VERSION') ?: '',
|
||||
'APPWRITE_REGION' => \getenv('APPWRITE_REGION') ?: '',
|
||||
'APPWRITE_FUNCTION_CPUS' => \getenv('APPWRITE_FUNCTION_CPUS') ?: '',
|
||||
'APPWRITE_FUNCTION_MEMORY' => \getenv('APPWRITE_FUNCTION_MEMORY') ?: '',
|
||||
'UNICODE_TEST' => "êä"
|
||||
]);
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"name": "appwrite/php-scopes",
|
||||
"description": "PHP scopes test script",
|
||||
"type": "library",
|
||||
"license": "BSD-3-Clause",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Team Appwrite",
|
||||
"email": "team@appwrite.io"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.4.0",
|
||||
"ext-curl": "*",
|
||||
"ext-json": "*",
|
||||
"appwrite/appwrite": "11.0.*"
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
<?php
|
||||
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
use Appwrite\Client;
|
||||
use Appwrite\Services\Users;
|
||||
|
||||
return function ($context) {
|
||||
$client = new Client();
|
||||
$client
|
||||
->setEndpoint(getenv('APPWRITE_FUNCTION_API_ENDPOINT'))
|
||||
->setProject(getenv('APPWRITE_FUNCTION_PROJECT_ID'))
|
||||
->setKey($context->req->headers['x-appwrite-key']);
|
||||
$users = new Users($client);
|
||||
$response = $users->list();
|
||||
$context->log($response);
|
||||
return $context->res->json($response);
|
||||
};
|
||||
@@ -1,7 +0,0 @@
|
||||
<?php
|
||||
|
||||
return function ($req, $res) {
|
||||
$res->json([
|
||||
'v2Woks' => true
|
||||
]);
|
||||
};
|
||||
@@ -1,39 +0,0 @@
|
||||
<?php
|
||||
|
||||
return function ($context) {
|
||||
if ($context->req->path === '/custom-response') {
|
||||
$code = (int) ($context->req->query['code'] ?? '200');
|
||||
$body = $context->req->query['body'] ?? '';
|
||||
return $context->res->send($body, $code);
|
||||
}
|
||||
|
||||
$context->log('body-is-' . ($context->req->body ?? ''));
|
||||
$context->log('custom-header-is-' . ($context->req->headers['x-custom-header'] ?? ''));
|
||||
$context->log('method-is-' . \strtolower($context->req->method ?? ''));
|
||||
$context->log('path-is-' . ($context->req->path ?? ''));
|
||||
$context->log('user-is-' . $context->req->headers['x-appwrite-user-id'] ?? '');
|
||||
|
||||
if (empty($context->req->headers['x-appwrite-user-jwt'] ?? '')) {
|
||||
$context->log('jwt-is-invalid');
|
||||
} else {
|
||||
$context->log('jwt-is-valid');
|
||||
}
|
||||
|
||||
$context->error('error-log-works');
|
||||
|
||||
$statusCode = $context->req->query['code'] ?? '200';
|
||||
|
||||
return $context->res->json([
|
||||
'APPWRITE_FUNCTION_ID' => \getenv('APPWRITE_FUNCTION_ID') ?: '',
|
||||
'APPWRITE_FUNCTION_NAME' => \getenv('APPWRITE_FUNCTION_NAME') ?: '',
|
||||
'APPWRITE_FUNCTION_DEPLOYMENT' => \getenv('APPWRITE_FUNCTION_DEPLOYMENT') ?: '',
|
||||
'APPWRITE_FUNCTION_TRIGGER' => $context->req->headers['x-appwrite-trigger'] ?? '',
|
||||
'APPWRITE_FUNCTION_RUNTIME_NAME' => \getenv('APPWRITE_FUNCTION_RUNTIME_NAME') ?: '',
|
||||
'APPWRITE_FUNCTION_RUNTIME_VERSION' => \getenv('APPWRITE_FUNCTION_RUNTIME_VERSION') ?: '',
|
||||
'APPWRITE_REGION' => \getenv('APPWRITE_REGION') ?: '',
|
||||
'UNICODE_TEST' => "êä",
|
||||
'GLOBAL_VARIABLE' => \getenv('GLOBAL_VARIABLE') ?: '',
|
||||
'APPWRITE_FUNCTION_CPUS' => \getenv('APPWRITE_FUNCTION_CPUS') ?: '',
|
||||
'APPWRITE_FUNCTION_MEMORY' => \getenv('APPWRITE_FUNCTION_MEMORY') ?: '',
|
||||
], \intval($statusCode));
|
||||
};
|
||||
@@ -1,21 +0,0 @@
|
||||
import json
|
||||
import os
|
||||
|
||||
def main(context):
|
||||
context.log('Amazing Function Log')
|
||||
|
||||
return context.res.json({
|
||||
'APPWRITE_FUNCTION_ID' : os.environ.get('APPWRITE_FUNCTION_ID',''),
|
||||
'APPWRITE_FUNCTION_NAME' : os.environ.get('APPWRITE_FUNCTION_NAME',''),
|
||||
'APPWRITE_FUNCTION_DEPLOYMENT' : os.environ.get('APPWRITE_FUNCTION_DEPLOYMENT',''),
|
||||
'APPWRITE_FUNCTION_TRIGGER' : context.req.headers.get('x-appwrite-trigger', ''),
|
||||
'APPWRITE_FUNCTION_RUNTIME_NAME' : os.environ.get('APPWRITE_FUNCTION_RUNTIME_NAME',''),
|
||||
'APPWRITE_FUNCTION_RUNTIME_VERSION' : os.environ.get('APPWRITE_FUNCTION_RUNTIME_VERSION',''),
|
||||
'APPWRITE_FUNCTION_EVENT' : context.req.headers.get('x-appwrite-event', ''),
|
||||
'APPWRITE_FUNCTION_EVENT_DATA' : context.req.body_raw,
|
||||
'APPWRITE_FUNCTION_DATA' : context.req.body_raw,
|
||||
'APPWRITE_FUNCTION_USER_ID' : context.req.headers.get('x-appwrite-user-id', ''),
|
||||
'APPWRITE_FUNCTION_JWT' : context.req.headers.get('x-appwrite-user-jwt', ''),
|
||||
'APPWRITE_FUNCTION_PROJECT_ID' : os.environ.get('APPWRITE_FUNCTION_PROJECT_ID',''),
|
||||
'CUSTOM_VARIABLE' : os.environ.get('CUSTOM_VARIABLE',''),
|
||||
})
|
||||
@@ -1,19 +0,0 @@
|
||||
def main(context)
|
||||
context.log('Amazing Function Log')
|
||||
|
||||
return context.res.json({
|
||||
'APPWRITE_FUNCTION_ID' => ENV['APPWRITE_FUNCTION_ID'] || '',
|
||||
'APPWRITE_FUNCTION_NAME' => ENV['APPWRITE_FUNCTION_NAME'] || '',
|
||||
'APPWRITE_FUNCTION_DEPLOYMENT' => ENV['APPWRITE_FUNCTION_DEPLOYMENT'] || '',
|
||||
'APPWRITE_FUNCTION_TRIGGER' => context.req.headers['x-appwrite-trigger'] || '',
|
||||
'APPWRITE_FUNCTION_RUNTIME_NAME' => ENV['APPWRITE_FUNCTION_RUNTIME_NAME'] || '',
|
||||
'APPWRITE_FUNCTION_RUNTIME_VERSION' => ENV['APPWRITE_FUNCTION_RUNTIME_VERSION'] || '',
|
||||
'APPWRITE_FUNCTION_EVENT' => context.req.headers['x-appwrite-event'] || '',
|
||||
'APPWRITE_FUNCTION_EVENT_DATA' => context.req.body_raw || '',
|
||||
'APPWRITE_FUNCTION_DATA' => context.req.body_raw || '',
|
||||
'APPWRITE_FUNCTION_USER_ID' => context.req.headers['x-appwrite-user-id'] || '',
|
||||
'APPWRITE_FUNCTION_JWT' => context.req.headers['x-appwrite-user-jwt'] || '',
|
||||
'APPWRITE_FUNCTION_PROJECT_ID' => ENV['APPWRITE_FUNCTION_PROJECT_ID'] || '',
|
||||
'CUSTOM_VARIABLE' => ENV['CUSTOM_VARIABLE'] || ''
|
||||
})
|
||||
end
|
||||
@@ -1,17 +0,0 @@
|
||||
func main(req: RequestValue, res: RequestResponse) throws -> RequestResponse {
|
||||
return res.json(data: [
|
||||
"APPWRITE_FUNCTION_ID": req.variables["APPWRITE_FUNCTION_ID"],
|
||||
"APPWRITE_FUNCTION_NAME": req.variables["APPWRITE_FUNCTION_NAME"],
|
||||
"APPWRITE_FUNCTION_DEPLOYMENT": req.variables["APPWRITE_FUNCTION_DEPLOYMENT"],
|
||||
"APPWRITE_FUNCTION_TRIGGER": req.variables["APPWRITE_FUNCTION_TRIGGER"],
|
||||
"APPWRITE_FUNCTION_RUNTIME_NAME": req.variables["APPWRITE_FUNCTION_RUNTIME_NAME"],
|
||||
"APPWRITE_FUNCTION_RUNTIME_VERSION": req.variables["APPWRITE_FUNCTION_RUNTIME_VERSION"],
|
||||
"APPWRITE_FUNCTION_EVENT": req.variables["APPWRITE_FUNCTION_EVENT"],
|
||||
"APPWRITE_FUNCTION_EVENT_DATA": req.variables["APPWRITE_FUNCTION_EVENT_DATA"],
|
||||
"APPWRITE_FUNCTION_DATA": req.variables["APPWRITE_FUNCTION_DATA"],
|
||||
"APPWRITE_FUNCTION_USER_ID": req.variables["APPWRITE_FUNCTION_USER_ID"],
|
||||
"APPWRITE_FUNCTION_JWT": req.variables["APPWRITE_FUNCTION_JWT"],
|
||||
"APPWRITE_FUNCTION_PROJECT_ID": req.variables["APPWRITE_FUNCTION_PROJECT_ID"],
|
||||
"CUSTOM_VARIABLE": req.variables["CUSTOM_VARIABLE"]
|
||||
])
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
module.exports = async(context) => {
|
||||
await new Promise(resolve => setTimeout(resolve, 1000 * 60));
|
||||
return context.res.send('OK');
|
||||
};
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
|
||||
return function ($context) {
|
||||
sleep(60);
|
||||
return $context->res->send('OK');
|
||||
};
|
||||
@@ -94,5 +94,17 @@ class OriginTest extends TestCase
|
||||
|
||||
$this->assertEquals(false, $validator->isValid('appwrite-windows://com.company.appname'));
|
||||
$this->assertEquals('Invalid Origin. Register your new client (com.company.appname) as a new Windows platform on your project console dashboard', $validator->getDescription());
|
||||
|
||||
$this->assertEquals(false, $validator->isValid('chrome-extension://com.company.appname'));
|
||||
$this->assertEquals('Invalid Origin. Register your new client (com.company.appname) as a new Web (Chrome Extension) platform on your project console dashboard', $validator->getDescription());
|
||||
|
||||
$this->assertEquals(false, $validator->isValid('moz-extension://com.company.appname'));
|
||||
$this->assertEquals('Invalid Origin. Register your new client (com.company.appname) as a new Web (Firefox Extension) platform on your project console dashboard', $validator->getDescription());
|
||||
|
||||
$this->assertEquals(false, $validator->isValid('safari-web-extension://com.company.appname'));
|
||||
$this->assertEquals('Invalid Origin. Register your new client (com.company.appname) as a new Web (Safari Extension) platform on your project console dashboard', $validator->getDescription());
|
||||
|
||||
$this->assertEquals(false, $validator->isValid('ms-browser-extension://com.company.appname'));
|
||||
$this->assertEquals('Invalid Origin. Register your new client (com.company.appname) as a new Web (Edge Extension) platform on your project console dashboard', $validator->getDescription());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,15 @@ class URLTest extends TestCase
|
||||
$this->assertEquals(null, $url['port']);
|
||||
$this->assertEquals('', $url['path']);
|
||||
$this->assertEquals('', $url['query']);
|
||||
|
||||
$url = URL::parse('appwrite-callback-project://');
|
||||
|
||||
$this->assertIsArray($url);
|
||||
$this->assertEquals('appwrite-callback-project', $url['scheme']);
|
||||
$this->assertEquals('', $url['host']);
|
||||
$this->assertEquals(null, $url['port']);
|
||||
$this->assertEquals('', $url['path']);
|
||||
$this->assertEquals('', $url['query']);
|
||||
}
|
||||
|
||||
public function testUnparse(): void
|
||||
@@ -86,6 +95,19 @@ class URLTest extends TestCase
|
||||
|
||||
$this->assertIsString($url);
|
||||
$this->assertEquals('https://eldad:fux@appwrite.io/#bottom', $url);
|
||||
|
||||
$url = URL::unparse([
|
||||
'scheme' => 'https',
|
||||
'user' => '',
|
||||
'pass' => '',
|
||||
'host' => 'appwrite.io',
|
||||
'port' => null,
|
||||
'path' => '',
|
||||
'fragment' => '',
|
||||
]);
|
||||
|
||||
$this->assertIsString($url);
|
||||
$this->assertEquals('https://appwrite.io/#', $url);
|
||||
}
|
||||
|
||||
public function testParseQuery(): void
|
||||
|
||||
Reference in New Issue
Block a user