1
0
Fork 0
mirror of synced 2024-09-21 20:11:15 +12:00

Merge branch '1.5.x' into fix-templates-copy-hidden-files

This commit is contained in:
Luke B. Silver 2024-02-22 18:06:09 +00:00 committed by GitHub
commit 5822f22109
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 445 additions and 343 deletions

View file

@ -287,6 +287,11 @@ return [
'description' => 'A target with the same ID already exists.', 'description' => 'A target with the same ID already exists.',
'code' => 409, 'code' => 409,
], ],
Exception::USER_API_KEY_AND_SESSION_SET => [
'name' => Exception::USER_API_KEY_AND_SESSION_SET,
'description' => 'API key and session used in the same request. Use either `setSession` or `setKey`. Learn about which authentication method to use in the SSR docs: https://appwrite.io/docs/products/auth/server-side-rendering',
'code' => 403,
],
/** Teams */ /** Teams */
Exception::TEAM_NOT_FOUND => [ Exception::TEAM_NOT_FOUND => [

View file

@ -9,8 +9,7 @@ $member = [
'console', 'console',
'graphql', 'graphql',
'sessions.write', 'sessions.write',
'accounts.read', 'account',
'accounts.write',
'teams.read', 'teams.read',
'teams.write', 'teams.write',
'documents.read', 'documents.read',

View file

@ -1,12 +1,6 @@
<?php <?php
return [ // List of publicly visible scopes return [ // List of publicly visible scopes
'accounts.read' => [
'description' => 'Access to read your active user account',
],
'accounts.write' => [
'description' => 'Access to create, update, and delete your active user account',
],
'sessions.write' => [ 'sessions.write' => [
'description' => 'Access to create, update, and delete user sessions', 'description' => 'Access to create, update, and delete user sessions',
], ],

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -342,14 +342,11 @@ App::get('/v1/account/sessions/oauth2/:provider')
->param('provider', '', new WhiteList(\array_keys(Config::getParam('oAuthProviders')), true), 'OAuth2 Provider. Currently, supported providers are: ' . \implode(', ', \array_keys(\array_filter(Config::getParam('oAuthProviders'), fn($node) => (!$node['mock'])))) . '.') ->param('provider', '', new WhiteList(\array_keys(Config::getParam('oAuthProviders')), true), 'OAuth2 Provider. Currently, supported providers are: ' . \implode(', ', \array_keys(\array_filter(Config::getParam('oAuthProviders'), fn($node) => (!$node['mock'])))) . '.')
->param('success', '', fn($clients) => new Host($clients), 'URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients']) ->param('success', '', fn($clients) => new Host($clients), 'URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients'])
->param('failure', '', fn($clients) => new Host($clients), 'URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients']) ->param('failure', '', fn($clients) => new Host($clients), 'URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients'])
->param('token', false, new Boolean(true), 'Include token credentials in the final redirect, useful for server-side integrations, or when cookies are not available.', true)
->param('scopes', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true) ->param('scopes', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true)
->inject('request') ->inject('request')
->inject('response') ->inject('response')
->inject('project') ->inject('project')
->action(function (string $provider, string $success, string $failure, mixed $token, array $scopes, Request $request, Response $response, Document $project) use ($oauthDefaultSuccess, $oauthDefaultFailure) { ->action(function (string $provider, string $success, string $failure, array $scopes, Request $request, Response $response, Document $project) use ($oauthDefaultSuccess, $oauthDefaultFailure) {
$token = in_array($token, ['true', true], true);
$protocol = $request->getProtocol(); $protocol = $request->getProtocol();
$callback = $protocol . '://' . $request->getHostname() . '/v1/account/sessions/oauth2/callback/' . $provider . '/' . $project->getId(); $callback = $protocol . '://' . $request->getHostname() . '/v1/account/sessions/oauth2/callback/' . $provider . '/' . $project->getId();
@ -388,7 +385,77 @@ App::get('/v1/account/sessions/oauth2/:provider')
$oauth2 = new $className($appId, $appSecret, $callback, [ $oauth2 = new $className($appId, $appSecret, $callback, [
'success' => $success, 'success' => $success,
'failure' => $failure, 'failure' => $failure,
'token' => $token, 'token' => false,
], $scopes);
$response
->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
->addHeader('Pragma', 'no-cache')
->redirect($oauth2->getLoginURL());
});
App::get('/v1/account/tokens/oauth2/:provider')
->desc('Create OAuth2 token')
->groups(['api', 'account'])
->label('error', __DIR__ . '/../../views/general/error.phtml')
->label('scope', 'sessions.write')
->label('sdk.auth', [])
->label('sdk.hideServer', true)
->label('sdk.namespace', 'account')
->label('sdk.method', 'createOAuth2Token')
->label('sdk.description', '/docs/references/account/create-token-oauth2.md')
->label('sdk.response.code', Response::STATUS_CODE_MOVED_PERMANENTLY)
->label('sdk.response.type', Response::CONTENT_TYPE_HTML)
->label('sdk.methodType', 'webAuth')
->label('abuse-limit', 50)
->label('abuse-key', 'ip:{ip}')
->param('provider', '', new WhiteList(\array_keys(Config::getParam('oAuthProviders')), true), 'OAuth2 Provider. Currently, supported providers are: ' . \implode(', ', \array_keys(\array_filter(Config::getParam('oAuthProviders'), fn($node) => (!$node['mock'])))) . '.')
->param('success', '', fn($clients) => new Host($clients), 'URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients'])
->param('failure', '', fn($clients) => new Host($clients), 'URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project\'s platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients'])
->param('scopes', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true)
->inject('request')
->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();
$callback = $protocol . '://' . $request->getHostname() . '/v1/account/sessions/oauth2/callback/' . $provider . '/' . $project->getId();
$providerEnabled = $project->getAttribute('oAuthProviders', [])[$provider . 'Enabled'] ?? false;
if (!$providerEnabled) {
throw new Exception(Exception::PROJECT_PROVIDER_DISABLED, 'This provider is disabled. Please enable the provider from your ' . APP_NAME . ' console to continue.');
}
$appId = $project->getAttribute('oAuthProviders', [])[$provider . 'Appid'] ?? '';
$appSecret = $project->getAttribute('oAuthProviders', [])[$provider . 'Secret'] ?? '{}';
if (!empty($appSecret) && isset($appSecret['version'])) {
$key = App::getEnv('_APP_OPENSSL_KEY_V' . $appSecret['version']);
$appSecret = OpenSSL::decrypt($appSecret['data'], $appSecret['method'], $key, 0, \hex2bin($appSecret['iv']), \hex2bin($appSecret['tag']));
}
if (empty($appId) || empty($appSecret)) {
throw new Exception(Exception::PROJECT_PROVIDER_DISABLED, 'This provider is disabled. Please configure the provider app ID and app secret key from your ' . APP_NAME . ' console to continue.');
}
$className = 'Appwrite\\Auth\\OAuth2\\' . \ucfirst($provider);
if (!\class_exists($className)) {
throw new Exception(Exception::PROJECT_PROVIDER_UNSUPPORTED);
}
if (empty($success)) {
$success = $protocol . '://' . $request->getHostname() . $oauthDefaultSuccess;
}
if (empty($failure)) {
$failure = $protocol . '://' . $request->getHostname() . $oauthDefaultFailure;
}
$oauth2 = new $className($appId, $appSecret, $callback, [
'success' => $success,
'failure' => $failure,
'token' => true,
], $scopes); ], $scopes);
$response $response
@ -898,7 +965,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
App::get('/v1/account/identities') App::get('/v1/account/identities')
->desc('List Identities') ->desc('List Identities')
->groups(['api', 'account']) ->groups(['api', 'account'])
->label('scope', 'accounts.read') ->label('scope', 'account')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account') ->label('sdk.namespace', 'account')
->label('sdk.method', 'listIdentities') ->label('sdk.method', 'listIdentities')
@ -954,7 +1021,7 @@ App::get('/v1/account/identities')
App::delete('/v1/account/identities/:identityId') App::delete('/v1/account/identities/:identityId')
->desc('Delete identity') ->desc('Delete identity')
->groups(['api', 'account']) ->groups(['api', 'account'])
->label('scope', 'accounts.write') ->label('scope', 'account')
->label('event', 'users.[userId].identities.[identityId].delete') ->label('event', 'users.[userId].identities.[identityId].delete')
->label('audits.event', 'identity.delete') ->label('audits.event', 'identity.delete')
->label('audits.resource', 'identity/{request.$identityId}') ->label('audits.resource', 'identity/{request.$identityId}')
@ -1940,7 +2007,7 @@ App::post('/v1/account/sessions/anonymous')
App::post('/v1/account/jwt') App::post('/v1/account/jwt')
->desc('Create JWT') ->desc('Create JWT')
->groups(['api', 'account', 'auth']) ->groups(['api', 'account', 'auth'])
->label('scope', 'accounts.write') ->label('scope', 'account')
->label('auth.type', 'jwt') ->label('auth.type', 'jwt')
->label('sdk.auth', []) ->label('sdk.auth', [])
->label('sdk.namespace', 'account') ->label('sdk.namespace', 'account')
@ -1987,7 +2054,7 @@ App::post('/v1/account/jwt')
App::get('/v1/account') App::get('/v1/account')
->desc('Get account') ->desc('Get account')
->groups(['api', 'account']) ->groups(['api', 'account'])
->label('scope', 'accounts.read') ->label('scope', 'account')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account') ->label('sdk.namespace', 'account')
->label('sdk.method', 'get') ->label('sdk.method', 'get')
@ -2010,7 +2077,7 @@ App::get('/v1/account')
App::get('/v1/account/prefs') App::get('/v1/account/prefs')
->desc('Get account preferences') ->desc('Get account preferences')
->groups(['api', 'account']) ->groups(['api', 'account'])
->label('scope', 'accounts.read') ->label('scope', 'account')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account') ->label('sdk.namespace', 'account')
->label('sdk.method', 'getPrefs') ->label('sdk.method', 'getPrefs')
@ -2032,7 +2099,7 @@ App::get('/v1/account/prefs')
App::get('/v1/account/sessions') App::get('/v1/account/sessions')
->desc('List sessions') ->desc('List sessions')
->groups(['api', 'account']) ->groups(['api', 'account'])
->label('scope', 'accounts.read') ->label('scope', 'account')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account') ->label('sdk.namespace', 'account')
->label('sdk.method', 'listSessions') ->label('sdk.method', 'listSessions')
@ -2067,7 +2134,7 @@ App::get('/v1/account/sessions')
App::get('/v1/account/logs') App::get('/v1/account/logs')
->desc('List logs') ->desc('List logs')
->groups(['api', 'account']) ->groups(['api', 'account'])
->label('scope', 'accounts.read') ->label('scope', 'account')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account') ->label('sdk.namespace', 'account')
->label('sdk.method', 'listLogs') ->label('sdk.method', 'listLogs')
@ -2132,7 +2199,7 @@ App::get('/v1/account/logs')
App::get('/v1/account/sessions/:sessionId') App::get('/v1/account/sessions/:sessionId')
->desc('Get session') ->desc('Get session')
->groups(['api', 'account']) ->groups(['api', 'account'])
->label('scope', 'accounts.read') ->label('scope', 'account')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account') ->label('sdk.namespace', 'account')
->label('sdk.method', 'getSession') ->label('sdk.method', 'getSession')
@ -2174,7 +2241,7 @@ App::patch('/v1/account/name')
->desc('Update name') ->desc('Update name')
->groups(['api', 'account']) ->groups(['api', 'account'])
->label('event', 'users.[userId].update.name') ->label('event', 'users.[userId].update.name')
->label('scope', 'accounts.write') ->label('scope', 'account')
->label('audits.event', 'user.update') ->label('audits.event', 'user.update')
->label('audits.resource', 'user/{response.$id}') ->label('audits.resource', 'user/{response.$id}')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
@ -2207,7 +2274,7 @@ App::patch('/v1/account/password')
->desc('Update password') ->desc('Update password')
->groups(['api', 'account']) ->groups(['api', 'account'])
->label('event', 'users.[userId].update.password') ->label('event', 'users.[userId].update.password')
->label('scope', 'accounts.write') ->label('scope', 'account')
->label('audits.event', 'user.update') ->label('audits.event', 'user.update')
->label('audits.resource', 'user/{response.$id}') ->label('audits.resource', 'user/{response.$id}')
->label('audits.userId', '{response.$id}') ->label('audits.userId', '{response.$id}')
@ -2276,7 +2343,7 @@ App::patch('/v1/account/email')
->desc('Update email') ->desc('Update email')
->groups(['api', 'account']) ->groups(['api', 'account'])
->label('event', 'users.[userId].update.email') ->label('event', 'users.[userId].update.email')
->label('scope', 'accounts.write') ->label('scope', 'account')
->label('audits.event', 'user.update') ->label('audits.event', 'user.update')
->label('audits.resource', 'user/{response.$id}') ->label('audits.resource', 'user/{response.$id}')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
@ -2368,7 +2435,7 @@ App::patch('/v1/account/phone')
->desc('Update phone') ->desc('Update phone')
->groups(['api', 'account']) ->groups(['api', 'account'])
->label('event', 'users.[userId].update.phone') ->label('event', 'users.[userId].update.phone')
->label('scope', 'accounts.write') ->label('scope', 'account')
->label('audits.event', 'user.update') ->label('audits.event', 'user.update')
->label('audits.resource', 'user/{response.$id}') ->label('audits.resource', 'user/{response.$id}')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
@ -2449,7 +2516,7 @@ App::patch('/v1/account/prefs')
->desc('Update preferences') ->desc('Update preferences')
->groups(['api', 'account']) ->groups(['api', 'account'])
->label('event', 'users.[userId].update.prefs') ->label('event', 'users.[userId].update.prefs')
->label('scope', 'accounts.write') ->label('scope', 'account')
->label('audits.event', 'user.update') ->label('audits.event', 'user.update')
->label('audits.resource', 'user/{response.$id}') ->label('audits.resource', 'user/{response.$id}')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
@ -2482,7 +2549,7 @@ App::patch('/v1/account/status')
->desc('Update status') ->desc('Update status')
->groups(['api', 'account']) ->groups(['api', 'account'])
->label('event', 'users.[userId].update.status') ->label('event', 'users.[userId].update.status')
->label('scope', 'accounts.write') ->label('scope', 'account')
->label('audits.event', 'user.update') ->label('audits.event', 'user.update')
->label('audits.resource', 'user/{response.$id}') ->label('audits.resource', 'user/{response.$id}')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
@ -2524,7 +2591,7 @@ App::patch('/v1/account/status')
App::delete('/v1/account/sessions/:sessionId') App::delete('/v1/account/sessions/:sessionId')
->desc('Delete session') ->desc('Delete session')
->groups(['api', 'account']) ->groups(['api', 'account'])
->label('scope', 'accounts.write') ->label('scope', 'account')
->label('event', 'users.[userId].sessions.[sessionId].delete') ->label('event', 'users.[userId].sessions.[sessionId].delete')
->label('audits.event', 'session.delete') ->label('audits.event', 'session.delete')
->label('audits.resource', 'user/{user.$id}') ->label('audits.resource', 'user/{user.$id}')
@ -2604,7 +2671,7 @@ App::delete('/v1/account/sessions/:sessionId')
App::patch('/v1/account/sessions/:sessionId') App::patch('/v1/account/sessions/:sessionId')
->desc('Update (or renew) a session') ->desc('Update (or renew) a session')
->groups(['api', 'account']) ->groups(['api', 'account'])
->label('scope', 'accounts.write') ->label('scope', 'account')
->label('event', 'users.[userId].sessions.[sessionId].update') ->label('event', 'users.[userId].sessions.[sessionId].update')
->label('audits.event', 'session.update') ->label('audits.event', 'session.update')
->label('audits.resource', 'user/{response.userId}') ->label('audits.resource', 'user/{response.userId}')
@ -2680,7 +2747,7 @@ App::patch('/v1/account/sessions/:sessionId')
App::delete('/v1/account/sessions') App::delete('/v1/account/sessions')
->desc('Delete sessions') ->desc('Delete sessions')
->groups(['api', 'account']) ->groups(['api', 'account'])
->label('scope', 'accounts.write') ->label('scope', 'account')
->label('event', 'users.[userId].sessions.[sessionId].delete') ->label('event', 'users.[userId].sessions.[sessionId].delete')
->label('audits.event', 'session.delete') ->label('audits.event', 'session.delete')
->label('audits.resource', 'user/{user.$id}') ->label('audits.resource', 'user/{user.$id}')
@ -3007,7 +3074,7 @@ App::put('/v1/account/recovery')
App::post('/v1/account/verification') App::post('/v1/account/verification')
->desc('Create email verification') ->desc('Create email verification')
->groups(['api', 'account']) ->groups(['api', 'account'])
->label('scope', 'accounts.write') ->label('scope', 'account')
->label('event', 'users.[userId].verification.[tokenId].create') ->label('event', 'users.[userId].verification.[tokenId].create')
->label('audits.event', 'verification.create') ->label('audits.event', 'verification.create')
->label('audits.resource', 'user/{response.userId}') ->label('audits.resource', 'user/{response.userId}')
@ -3227,7 +3294,7 @@ App::put('/v1/account/verification')
App::post('/v1/account/verification/phone') App::post('/v1/account/verification/phone')
->desc('Create phone verification') ->desc('Create phone verification')
->groups(['api', 'account', 'auth']) ->groups(['api', 'account', 'auth'])
->label('scope', 'accounts.write') ->label('scope', 'account')
->label('auth.type', 'phone') ->label('auth.type', 'phone')
->label('event', 'users.[userId].verification.[tokenId].create') ->label('event', 'users.[userId].verification.[tokenId].create')
->label('audits.event', 'verification.create') ->label('audits.event', 'verification.create')
@ -3398,7 +3465,7 @@ App::patch('/v1/account/mfa')
->desc('Update MFA') ->desc('Update MFA')
->groups(['api', 'account']) ->groups(['api', 'account'])
->label('event', 'users.[userId].update.mfa') ->label('event', 'users.[userId].update.mfa')
->label('scope', 'accounts.write') ->label('scope', 'account')
->label('audits.event', 'user.update') ->label('audits.event', 'user.update')
->label('audits.resource', 'user/{response.$id}') ->label('audits.resource', 'user/{response.$id}')
->label('audits.userId', '{response.$id}') ->label('audits.userId', '{response.$id}')
@ -3431,7 +3498,7 @@ App::patch('/v1/account/mfa')
App::get('/v1/account/mfa/factors') App::get('/v1/account/mfa/factors')
->desc('List Factors') ->desc('List Factors')
->groups(['api', 'account', 'mfa']) ->groups(['api', 'account', 'mfa'])
->label('scope', 'accounts.read') ->label('scope', 'account')
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT]) ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'account') ->label('sdk.namespace', 'account')
->label('sdk.method', 'listFactors') ->label('sdk.method', 'listFactors')
@ -3458,7 +3525,7 @@ App::post('/v1/account/mfa/:type')
->desc('Add Authenticator') ->desc('Add Authenticator')
->groups(['api', 'account']) ->groups(['api', 'account'])
->label('event', 'users.[userId].update.mfa') ->label('event', 'users.[userId].update.mfa')
->label('scope', 'accounts.write') ->label('scope', 'account')
->label('audits.event', 'user.update') ->label('audits.event', 'user.update')
->label('audits.resource', 'user/{response.$id}') ->label('audits.resource', 'user/{response.$id}')
->label('audits.userId', '{response.$id}') ->label('audits.userId', '{response.$id}')
@ -3517,7 +3584,7 @@ App::put('/v1/account/mfa/:type')
->desc('Verify Authenticator') ->desc('Verify Authenticator')
->groups(['api', 'account']) ->groups(['api', 'account'])
->label('event', 'users.[userId].update.mfa') ->label('event', 'users.[userId].update.mfa')
->label('scope', 'accounts.write') ->label('scope', 'account')
->label('audits.event', 'user.update') ->label('audits.event', 'user.update')
->label('audits.resource', 'user/{response.$id}') ->label('audits.resource', 'user/{response.$id}')
->label('audits.userId', '{response.$id}') ->label('audits.userId', '{response.$id}')
@ -3573,7 +3640,7 @@ App::delete('/v1/account/mfa/:type')
->desc('Delete Authenticator') ->desc('Delete Authenticator')
->groups(['api', 'account']) ->groups(['api', 'account'])
->label('event', 'users.[userId].delete.mfa') ->label('event', 'users.[userId].delete.mfa')
->label('scope', 'accounts.write') ->label('scope', 'account')
->label('audits.event', 'user.update') ->label('audits.event', 'user.update')
->label('audits.resource', 'user/{response.$id}') ->label('audits.resource', 'user/{response.$id}')
->label('audits.userId', '{response.$id}') ->label('audits.userId', '{response.$id}')
@ -3622,7 +3689,7 @@ App::delete('/v1/account/mfa/:type')
App::post('/v1/account/mfa/challenge') App::post('/v1/account/mfa/challenge')
->desc('Create 2FA Challenge') ->desc('Create 2FA Challenge')
->groups(['api', 'account', 'mfa']) ->groups(['api', 'account', 'mfa'])
->label('scope', 'accounts.write') ->label('scope', 'account')
->label('event', 'users.[userId].challenges.[challengeId].create') ->label('event', 'users.[userId].challenges.[challengeId].create')
->label('audits.event', 'challenge.create') ->label('audits.event', 'challenge.create')
->label('audits.resource', 'user/{response.userId}') ->label('audits.resource', 'user/{response.userId}')
@ -3715,7 +3782,7 @@ App::post('/v1/account/mfa/challenge')
App::put('/v1/account/mfa/challenge') App::put('/v1/account/mfa/challenge')
->desc('Create MFA Challenge (confirmation)') ->desc('Create MFA Challenge (confirmation)')
->groups(['api', 'account', 'mfa']) ->groups(['api', 'account', 'mfa'])
->label('scope', 'accounts.write') ->label('scope', 'account')
->label('event', 'users.[userId].sessions.[tokenId].create') ->label('event', 'users.[userId].sessions.[tokenId].create')
->label('audits.event', 'challenges.update') ->label('audits.event', 'challenges.update')
->label('audits.resource', 'user/{response.userId}') ->label('audits.resource', 'user/{response.userId}')
@ -3781,7 +3848,7 @@ App::delete('/v1/account')
->desc('Delete account') ->desc('Delete account')
->groups(['api', 'account']) ->groups(['api', 'account'])
->label('event', 'users.[userId].delete') ->label('event', 'users.[userId].delete')
->label('scope', 'accounts.write') ->label('scope', 'account')
->label('audits.event', 'user.delete') ->label('audits.event', 'user.delete')
->label('audits.resource', 'user/{response.$id}') ->label('audits.resource', 'user/{response.$id}')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])

View file

@ -195,14 +195,14 @@ App::init()
$authKey = $request->getHeader('x-appwrite-key', ''); $authKey = $request->getHeader('x-appwrite-key', '');
if (!empty($authKey)) { // API Key authentication if (!empty($authKey)) { // API Key authentication
// Do not allow API key and session to be set at the same time
if (!$user->isEmpty()) {
throw new Exception(Exception::USER_API_KEY_AND_SESSION_SET);
}
// Check if given key match project API keys // Check if given key match project API keys
$key = $project->find('secret', $authKey, 'keys'); $key = $project->find('secret', $authKey, 'keys');
if ($key) {
/*
* Try app auth when we have project key and no user
* Mock user to app and grant API key scopes in addition to default app scopes
*/
if ($key && $user->isEmpty()) {
$user = new Document([ $user = new Document([
'$id' => '', '$id' => '',
'status' => true, 'status' => true,

View file

@ -0,0 +1,5 @@
Allow the user to login to their account using the OAuth2 provider of their choice. Each OAuth2 provider should be enabled from the Appwrite console first. Use the success and failure arguments to provide a redirect URL's back to your app when login is completed.
If authentication succeeds, `userId` and `secret` of a token will be appended to the success URL as query parameters. These can be used to create a new session using the [Create session](https://appwrite.io/docs/references/cloud/client-web/account#createSession) endpoint.
A user is limited to 10 active sessions at a time by default. [Learn more about session limits](https://appwrite.io/docs/authentication-security#limits).

View file

@ -97,6 +97,7 @@ class Exception extends \Exception
public const USER_DELETION_PROHIBITED = 'user_deletion_prohibited'; public const USER_DELETION_PROHIBITED = 'user_deletion_prohibited';
public const USER_TARGET_NOT_FOUND = 'user_target_not_found'; public const USER_TARGET_NOT_FOUND = 'user_target_not_found';
public const USER_TARGET_ALREADY_EXISTS = 'user_target_already_exists'; public const USER_TARGET_ALREADY_EXISTS = 'user_target_already_exists';
public const USER_API_KEY_AND_SESSION_SET = 'user_key_and_session_set';
/** Teams */ /** Teams */
public const TEAM_NOT_FOUND = 'team_not_found'; public const TEAM_NOT_FOUND = 'team_not_found';

View file

@ -120,12 +120,6 @@ class Specs extends Action
'description' => 'The user session to authenticate with', 'description' => 'The user session to authenticate with',
'in' => 'header', 'in' => 'header',
], ],
'ForwardedFor' => [
'type' => 'apiKey',
'name' => 'X-Forwarded-For',
'description' => 'The IP address of the client that made the request',
'in' => 'header',
],
'ForwardedUserAgent' => [ 'ForwardedUserAgent' => [
'type' => 'apiKey', 'type' => 'apiKey',
'name' => 'X-Forwarded-User-Agent', 'name' => 'X-Forwarded-User-Agent',

View file

@ -32,6 +32,16 @@ class UsageTest extends Scope
protected static string $formatTz = 'Y-m-d\TH:i:s.vP'; protected static string $formatTz = 'Y-m-d\TH:i:s.vP';
protected function getConsoleHeaders(): array
{
return [
'origin' => 'http://localhost',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-mode' => 'admin',
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
];
}
protected function validateDates(array $metrics): void protected function validateDates(array $metrics): void
{ {
foreach ($metrics as $metric) { foreach ($metrics as $metric) {
@ -54,48 +64,56 @@ class UsageTest extends Scope
public function testPrepareUsersStats(): array public function testPrepareUsersStats(): array
{ {
$project = $this->getProject(true); $usersTotal = 0;
$projectId = $project['$id'];
$headers['x-appwrite-project'] = $project['$id'];
$headers['x-appwrite-key'] = $project['apiKey'];
$headers['content-type'] = 'application/json';
$usersTotal = 0;
$requestsTotal = 0; $requestsTotal = 0;
for ($i = 0; $i < self::CREATE; $i++) { for ($i = 0; $i < self::CREATE; $i++) {
$email = uniqid() . 'user@usage.test'; $params = [
$password = 'password'; 'userId' => 'unique()',
$name = uniqid() . 'User'; 'email' => uniqid() . 'user@usage.test',
$res = $this->client->call( 'password' => 'password',
'name' => uniqid() . 'User',
];
$response = $this->client->call(
Client::METHOD_POST, Client::METHOD_POST,
'/users', '/users',
$headers, array_merge([
[ 'content-type' => 'application/json',
'userId' => 'unique()', 'x-appwrite-project' => $this->getProject()['$id']
'email' => $email, ], $this->getHeaders()),
'password' => $password, $params
'name' => $name,
]
); );
$this->assertEquals($email, $res['body']['email']); $this->assertEquals(201, $response['headers']['status-code']);
$this->assertNotEmpty($res['body']['$id']); $this->assertEquals($params['email'], $response['body']['email']);
$usersTotal++; $this->assertNotEmpty($response['body']['$id']);
$requestsTotal++;
$usersTotal += 1;
$requestsTotal += 1;
if ($i < (self::CREATE / 2)) { if ($i < (self::CREATE / 2)) {
$userId = $res['body']['$id']; $userId = $response['body']['$id'];
$res = $this->client->call(Client::METHOD_DELETE, '/users/' . $userId, $headers);
$this->assertEmpty($res['body']); $response = $this->client->call(
$requestsTotal++; Client::METHOD_DELETE,
$usersTotal--; '/users/' . $userId,
array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders())
);
$this->assertEquals(204, $response['headers']['status-code']);
$this->assertEmpty($response['body']);
$requestsTotal += 1;
$usersTotal -= 1;
} }
} }
return [ return [
'projectId' => $projectId, 'usersTotal' => $usersTotal,
'headers' => $headers,
'usersTotal' => $usersTotal,
'requestsTotal' => $requestsTotal 'requestsTotal' => $requestsTotal
]; ];
} }
@ -108,74 +126,62 @@ class UsageTest extends Scope
{ {
sleep(self::WAIT); sleep(self::WAIT);
$projectId = $data['projectId'];
$headers = $data['headers'];
$usersTotal = $data['usersTotal'];
$requestsTotal = $data['requestsTotal']; $requestsTotal = $data['requestsTotal'];
$consoleHeaders = [ $response = $this->client->call(
'origin' => 'http://localhost',
'x-appwrite-project' => 'console',
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
'x-appwrite-project' => $projectId,
'x-appwrite-mode' => 'admin',
];
$res = $this->client->call(
Client::METHOD_GET, Client::METHOD_GET,
'/project/usage', '/project/usage',
$consoleHeaders, $this->getConsoleHeaders(),
[ [
'period' => '1h', 'period' => '1h',
'startDate' => self::getToday(), 'startDate' => self::getToday(),
'endDate' => self::getTomorrow(), 'endDate' => self::getTomorrow(),
] ]
); );
$res = $res['body'];
$this->assertEquals(12, count($res)); $this->assertEquals(200, $response['headers']['status-code']);
$this->validateDates($res['network']); $this->assertEquals(12, count($response['body']));
$this->validateDates($res['requests']); $this->validateDates($response['body']['network']);
$this->validateDates($res['users']); $this->validateDates($response['body']['requests']);
$this->assertArrayHasKey('executionsBreakdown', $res); $this->validateDates($response['body']['users']);
$this->assertArrayHasKey('bucketsBreakdown', $res); $this->assertArrayHasKey('executionsBreakdown', $response['body']);
$this->assertArrayHasKey('bucketsBreakdown', $response['body']);
$res = $this->client->call( $response = $this->client->call(
Client::METHOD_GET, Client::METHOD_GET,
'/users/usage?range=90d', '/users/usage?range=90d',
$consoleHeaders $this->getConsoleHeaders()
); );
$res = $res['body']; $this->assertEquals('90d', $response['body']['range']);
$this->assertEquals('90d', $res['range']); $this->assertEquals(90, count($response['body']['users']));
$this->assertEquals(90, count($res['users'])); $this->assertEquals(90, count($response['body']['sessions']));
$this->assertEquals(90, count($res['sessions'])); $this->assertEquals((self::CREATE / 2), $response['body']['users'][array_key_last($response['body']['users'])]['value']);
$this->assertEquals((self::CREATE / 2), $res['users'][array_key_last($res['users'])]['value']);
return [ return array_merge($data, [
'projectId' => $projectId, 'requestsTotal' => $requestsTotal
'headers' => $headers, ]);
'consoleHeaders' => $consoleHeaders,
'requestsTotal' => $requestsTotal,
];
} }
/** @depends testUsersStats */ /** @depends testUsersStats */
public function testPrepareStorageStats(array $data): array public function testPrepareStorageStats(array $data): array
{ {
$headers = $data['headers'];
$bucketsTotal = 0;
$requestsTotal = $data['requestsTotal']; $requestsTotal = $data['requestsTotal'];
$bucketsTotal = 0;
$storageTotal = 0; $storageTotal = 0;
$filesTotal = 0; $filesTotal = 0;
for ($i = 0; $i < self::CREATE; $i++) { for ($i = 0; $i < self::CREATE; $i++) {
$name = uniqid() . ' bucket'; $name = uniqid() . ' bucket';
$res = $this->client->call(
$response = $this->client->call(
Client::METHOD_POST, Client::METHOD_POST,
'/storage/buckets', '/storage/buckets',
$headers, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()),
[ [
'bucketId' => 'unique()', 'bucketId' => 'unique()',
'name' => $name, 'name' => $name,
@ -188,21 +194,31 @@ class UsageTest extends Scope
], ],
] ]
); );
$this->assertEquals($name, $res['body']['name']);
$this->assertNotEmpty($res['body']['$id']); $this->assertEquals(201, $response['headers']['status-code']);
$bucketId = $res['body']['$id']; $this->assertEquals($name, $response['body']['name']);
$bucketsTotal++; $this->assertNotEmpty($response['body']['$id']);
$requestsTotal++;
$bucketsTotal += 1;
$requestsTotal += 1;
$bucketId = $response['body']['$id'];
if ($i < (self::CREATE / 2)) { if ($i < (self::CREATE / 2)) {
$res = $this->client->call( $response = $this->client->call(
Client::METHOD_DELETE, Client::METHOD_DELETE,
'/storage/buckets/' . $bucketId, '/storage/buckets/' . $bucketId,
$headers array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()),
); );
$this->assertEmpty($res['body']);
$requestsTotal++; $this->assertEquals(204, $response['headers']['status-code']);
$bucketsTotal--; $this->assertEmpty($response['body']);
$requestsTotal += 1;
$bucketsTotal -= 1;
} }
} }
@ -229,33 +245,44 @@ class UsageTest extends Scope
for ($i = 0; $i < self::CREATE; $i++) { for ($i = 0; $i < self::CREATE; $i++) {
$file = $files[$i % count($files)]; $file = $files[$i % count($files)];
$res = $this->client->call( $response = $this->client->call(
Client::METHOD_POST, Client::METHOD_POST,
'/storage/buckets/' . $bucketId . '/files', '/storage/buckets/' . $bucketId . '/files',
array_merge($headers, ['content-type' => 'multipart/form-data']), array_merge([
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()),
[ [
'fileId' => 'unique()', 'fileId' => 'unique()',
'file' => new CURLFile($file['path'], '', $file['name']), 'file' => new CURLFile($file['path'], '', $file['name']),
] ]
); );
$this->assertNotEmpty($res['body']['$id']); $this->assertEquals(201, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
$fileSize = $response['body']['sizeOriginal'];
$fileSize = $res['body']['sizeOriginal'];
$storageTotal += $fileSize; $storageTotal += $fileSize;
$filesTotal++; $filesTotal += 1;
$requestsTotal++; $requestsTotal += 1;
$fileId = $response['body']['$id'];
$fileId = $res['body']['$id'];
if ($i < (self::CREATE / 2)) { if ($i < (self::CREATE / 2)) {
$res = $this->client->call( $response = $this->client->call(
Client::METHOD_DELETE, Client::METHOD_DELETE,
'/storage/buckets/' . $bucketId . '/files/' . $fileId, '/storage/buckets/' . $bucketId . '/files/' . $fileId,
$headers array_merge([
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()),
); );
$this->assertEmpty($res['body']);
$requestsTotal++; $this->assertEquals(204, $response['headers']['status-code']);
$filesTotal--; $this->assertEmpty($response['body']);
$requestsTotal += 1;
$filesTotal -= 1;
$storageTotal -= $fileSize; $storageTotal -= $fileSize;
} }
} }
@ -283,58 +310,44 @@ class UsageTest extends Scope
sleep(self::WAIT); sleep(self::WAIT);
$res = $this->client->call( $response = $this->client->call(
Client::METHOD_GET, Client::METHOD_GET,
'/project/usage', '/project/usage',
array_merge( $this->getConsoleHeaders(),
$data['headers'],
$data['consoleHeaders']
),
[ [
'period' => '1d', 'period' => '1d',
'startDate' => self::getToday(), 'startDate' => self::getToday(),
'endDate' => self::getTomorrow(), 'endDate' => self::getTomorrow(),
] ]
); );
$res = $res['body'];
$this->assertEquals(12, count($res)); $this->assertEquals(12, count($response['body']));
$this->assertEquals(1, count($res['requests'])); $this->assertEquals(1, count($response['body']['requests']));
$this->assertEquals($requestsTotal, $res['requests'][array_key_last($res['requests'])]['value']); $this->assertEquals($requestsTotal, $response['body']['requests'][array_key_last($response['body']['requests'])]['value']);
$this->validateDates($res['requests']); $this->validateDates($response['body']['requests']);
$this->assertEquals($storageTotal, $res['filesStorageTotal']); $this->assertEquals($storageTotal, $response['body']['filesStorageTotal']);
$res = $this->client->call( $response = $this->client->call(
Client::METHOD_GET, Client::METHOD_GET,
'/storage/usage?range=30d', '/storage/usage?range=30d',
array_merge( $this->getConsoleHeaders()
$data['headers'],
$data['consoleHeaders']
)
); );
$res = $res['body']; $this->assertEquals($storageTotal, $response['body']['storage'][array_key_last($response['body']['storage'])]['value']);
$this->assertEquals($storageTotal, $res['storage'][array_key_last($res['storage'])]['value']); $this->validateDates($response['body']['storage']);
$this->validateDates($res['storage']); $this->assertEquals($bucketsTotal, $response['body']['buckets'][array_key_last($response['body']['buckets'])]['value']);
$this->assertEquals($bucketsTotal, $res['buckets'][array_key_last($res['buckets'])]['value']); $this->validateDates($response['body']['buckets']);
$this->validateDates($res['buckets']); $this->assertEquals($filesTotal, $response['body']['files'][array_key_last($response['body']['files'])]['value']);
$this->assertEquals($filesTotal, $res['files'][array_key_last($res['files'])]['value']); $this->validateDates($response['body']['files']);
$this->validateDates($res['files']);
$res = $this->client->call( $response = $this->client->call(
Client::METHOD_GET, Client::METHOD_GET,
'/storage/' . $bucketId . '/usage?range=30d', '/storage/' . $bucketId . '/usage?range=30d',
array_merge( $this->getConsoleHeaders()
$data['headers'],
$data['consoleHeaders']
)
); );
$res = $res['body']; $this->assertEquals($storageTotal, $response['body']['storage'][array_key_last($response['body']['storage'])]['value']);
$this->assertEquals($storageTotal, $res['storage'][array_key_last($res['storage'])]['value']); $this->assertEquals($filesTotal, $response['body']['files'][array_key_last($response['body']['files'])]['value']);
$this->assertEquals($filesTotal, $res['files'][array_key_last($res['files'])]['value']);
$data['requestsTotal'] = $requestsTotal;
return $data; return $data;
} }
@ -342,52 +355,62 @@ class UsageTest extends Scope
/** @depends testStorageStats */ /** @depends testStorageStats */
public function testPrepareDatabaseStats(array $data): array public function testPrepareDatabaseStats(array $data): array
{ {
$headers = $data['headers'];
$requestsTotal = $data['requestsTotal']; $requestsTotal = $data['requestsTotal'];
$databasesTotal = 0; $databasesTotal = 0;
$collectionsTotal = 0; $collectionsTotal = 0;
$documentsTotal = 0; $documentsTotal = 0;
for ($i = 0; $i < self::CREATE; $i++) { for ($i = 0; $i < self::CREATE; $i++) {
$name = uniqid() . ' database'; $name = uniqid() . ' database';
$res = $this->client->call(
$response = $this->client->call(
Client::METHOD_POST, Client::METHOD_POST,
'/databases', '/databases',
$headers, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()),
[ [
'databaseId' => 'unique()', 'databaseId' => 'unique()',
'name' => $name, 'name' => $name,
] ]
); );
$this->assertEquals($name, $response['body']['name']);
$this->assertNotEmpty($response['body']['$id']);
$this->assertEquals($name, $res['body']['name']); $requestsTotal += 1;
$this->assertNotEmpty($res['body']['$id']); $databasesTotal += 1;
$databaseId = $res['body']['$id'];
$requestsTotal++; $databaseId = $response['body']['$id'];
$databasesTotal++;
if ($i < (self::CREATE / 2)) { if ($i < (self::CREATE / 2)) {
$res = $this->client->call( $response = $this->client->call(
Client::METHOD_DELETE, Client::METHOD_DELETE,
'/databases/' . $databaseId, '/databases/' . $databaseId,
$headers array_merge([
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()),
); );
$this->assertEmpty($res['body']);
$databasesTotal--; $this->assertEmpty($response['body']);
$requestsTotal++;
$databasesTotal -= 1;
$requestsTotal += 1;
} }
} }
for ($i = 0; $i < self::CREATE; $i++) { for ($i = 0; $i < self::CREATE; $i++) {
$name = uniqid() . ' collection'; $name = uniqid() . ' collection';
$res = $this->client->call(
$response = $this->client->call(
Client::METHOD_POST, Client::METHOD_POST,
'/databases/' . $databaseId . '/collections', '/databases/' . $databaseId . '/collections',
$headers, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()),
[ [
'collectionId' => 'unique()', 'collectionId' => 'unique()',
'name' => $name, 'name' => $name,
@ -401,29 +424,37 @@ class UsageTest extends Scope
] ]
); );
$this->assertEquals($name, $res['body']['name']); $this->assertEquals($name, $response['body']['name']);
$this->assertNotEmpty($res['body']['$id']); $this->assertNotEmpty($response['body']['$id']);
$collectionId = $res['body']['$id'];
$requestsTotal++; $requestsTotal += 1;
$collectionsTotal++; $collectionsTotal += 1;
$collectionId = $response['body']['$id'];
if ($i < (self::CREATE / 2)) { if ($i < (self::CREATE / 2)) {
$res = $this->client->call( $response = $this->client->call(
Client::METHOD_DELETE, Client::METHOD_DELETE,
'/databases/' . $databaseId . '/collections/' . $collectionId, '/databases/' . $databaseId . '/collections/' . $collectionId,
$headers array_merge([
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()),
); );
$this->assertEmpty($res['body']);
$collectionsTotal--; $this->assertEmpty($response['body']);
$requestsTotal++;
$collectionsTotal -= 1;
$requestsTotal += 1;
} }
} }
$res = $this->client->call( $response = $this->client->call(
Client::METHOD_POST, Client::METHOD_POST,
'/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes' . '/string', '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes' . '/string',
$headers, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()),
[ [
'key' => 'name', 'key' => 'name',
'size' => 255, 'size' => 255,
@ -431,38 +462,49 @@ class UsageTest extends Scope
] ]
); );
$this->assertEquals('name', $res['body']['key']); $this->assertEquals('name', $response['body']['key']);
$requestsTotal++;
$requestsTotal += 1;
sleep(self::WAIT); sleep(self::WAIT);
for ($i = 0; $i < self::CREATE; $i++) { for ($i = 0; $i < self::CREATE; $i++) {
$name = uniqid() . ' collection'; $name = uniqid() . ' collection';
$res = $this->client->call(
$response = $this->client->call(
Client::METHOD_POST, Client::METHOD_POST,
'/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents',
$headers, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()),
[ [
'documentId' => 'unique()', 'documentId' => 'unique()',
'data' => ['name' => $name] 'data' => ['name' => $name]
] ]
); );
$this->assertEquals($name, $res['body']['name']);
$this->assertNotEmpty($res['body']['$id']);
$documentId = $res['body']['$id'];
$requestsTotal++; $this->assertEquals($name, $response['body']['name']);
$documentsTotal++; $this->assertNotEmpty($response['body']['$id']);
$requestsTotal += 1;
$documentsTotal += 1;
$documentId = $response['body']['$id'];
if ($i < (self::CREATE / 2)) { if ($i < (self::CREATE / 2)) {
$res = $this->client->call( $response = $this->client->call(
Client::METHOD_DELETE, Client::METHOD_DELETE,
'/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId,
$headers array_merge([
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()),
); );
$this->assertEmpty($res['body']);
$documentsTotal--; $this->assertEmpty($response['body']);
$requestsTotal++;
$documentsTotal -= 1;
$requestsTotal += 1;
} }
} }
@ -480,8 +522,6 @@ class UsageTest extends Scope
#[Retry(count: 1)] #[Retry(count: 1)]
public function testDatabaseStats(array $data): array public function testDatabaseStats(array $data): array
{ {
$projectId = $data['projectId'];
$databaseId = $data['databaseId']; $databaseId = $data['databaseId'];
$collectionId = $data['collectionId']; $collectionId = $data['collectionId'];
$requestsTotal = $data['requestsTotal']; $requestsTotal = $data['requestsTotal'];
@ -491,60 +531,58 @@ class UsageTest extends Scope
sleep(self::WAIT); sleep(self::WAIT);
$res = $this->client->call( $response = $this->client->call(
Client::METHOD_GET, Client::METHOD_GET,
'/project/usage', '/project/usage',
$data['consoleHeaders'], $this->getConsoleHeaders(),
[ [
'period' => '1d', 'period' => '1d',
'startDate' => self::getToday(), 'startDate' => self::getToday(),
'endDate' => self::getTomorrow(), 'endDate' => self::getTomorrow(),
] ]
); );
$res = $res['body'];
$this->assertEquals(12, count($res)); $this->assertEquals(12, count($response['body']));
$this->assertEquals(1, count($res['requests'])); $this->assertEquals(1, count($response['body']['requests']));
$this->assertEquals(1, count($res['network'])); $this->assertEquals(1, count($response['body']['network']));
$this->assertEquals($requestsTotal, $res['requests'][array_key_last($res['requests'])]['value']); $this->assertEquals($requestsTotal, $response['body']['requests'][array_key_last($response['body']['requests'])]['value']);
$this->validateDates($res['requests']); $this->validateDates($response['body']['requests']);
$this->assertEquals($databasesTotal, $res['databasesTotal']); $this->assertEquals($databasesTotal, $response['body']['databasesTotal']);
$this->assertEquals($documentsTotal, $res['documentsTotal']); $this->assertEquals($documentsTotal, $response['body']['documentsTotal']);
$res = $this->client->call( $response = $this->client->call(
Client::METHOD_GET, Client::METHOD_GET,
'/databases/usage?range=30d', '/databases/usage?range=30d',
$data['consoleHeaders'] $this->getConsoleHeaders()
); );
$res = $res['body'];
$this->assertEquals($databasesTotal, $res['databases'][array_key_last($res['databases'])]['value']); $this->assertEquals($databasesTotal, $response['body']['databases'][array_key_last($response['body']['databases'])]['value']);
$this->validateDates($res['databases']); $this->validateDates($response['body']['databases']);
$this->assertEquals($collectionsTotal, $res['collections'][array_key_last($res['collections'])]['value']); $this->assertEquals($collectionsTotal, $response['body']['collections'][array_key_last($response['body']['collections'])]['value']);
$this->validateDates($res['collections']); $this->validateDates($response['body']['collections']);
$this->assertEquals($documentsTotal, $res['documents'][array_key_last($res['documents'])]['value']); $this->assertEquals($documentsTotal, $response['body']['documents'][array_key_last($response['body']['documents'])]['value']);
$this->validateDates($res['documents']); $this->validateDates($response['body']['documents']);
$res = $this->client->call( $response = $this->client->call(
Client::METHOD_GET, Client::METHOD_GET,
'/databases/' . $databaseId . '/usage?range=30d', '/databases/' . $databaseId . '/usage?range=30d',
$data['consoleHeaders'] $this->getConsoleHeaders()
); );
$res = $res['body'];
$this->assertEquals($collectionsTotal, $res['collections'][array_key_last($res['collections'])]['value']); $this->assertEquals($collectionsTotal, $response['body']['collections'][array_key_last($response['body']['collections'])]['value']);
$this->validateDates($res['collections']); $this->validateDates($response['body']['collections']);
$this->assertEquals($documentsTotal, $res['documents'][array_key_last($res['documents'])]['value']); $this->assertEquals($documentsTotal, $response['body']['documents'][array_key_last($response['body']['documents'])]['value']);
$this->validateDates($res['documents']); $this->validateDates($response['body']['documents']);
$res = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/usage?range=30d', $data['consoleHeaders']); $response = $this->client->call(
$res = $res['body']; Client::METHOD_GET,
'/databases/' . $databaseId . '/collections/' . $collectionId . '/usage?range=30d',
$this->getConsoleHeaders()
);
$this->assertEquals($documentsTotal, $res['documents'][array_key_last($res['documents'])]['value']); $this->assertEquals($documentsTotal, $response['body']['documents'][array_key_last($response['body']['documents'])]['value']);
$this->validateDates($res['documents']); $this->validateDates($response['body']['documents']);
$data['requestsTotal'] = $requestsTotal;
return $data; return $data;
} }
@ -553,16 +591,17 @@ class UsageTest extends Scope
/** @depends testDatabaseStats */ /** @depends testDatabaseStats */
public function testPrepareFunctionsStats(array $data): array public function testPrepareFunctionsStats(array $data): array
{ {
$dateValidator = new DatetimeValidator();
$headers = $data['headers'];
$executionTime = 0; $executionTime = 0;
$executions = 0; $executions = 0;
$failures = 0; $failures = 0;
$response1 = $this->client->call( $response = $this->client->call(
Client::METHOD_POST, Client::METHOD_POST,
'/functions', '/functions',
$headers, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()),
[ [
'functionId' => 'unique()', 'functionId' => 'unique()',
'name' => 'Test', 'name' => 'Test',
@ -581,18 +620,21 @@ class UsageTest extends Scope
] ]
); );
$functionId = $response1['body']['$id'] ?? ''; $functionId = $response['body']['$id'] ?? '';
$this->assertEquals(201, $response1['headers']['status-code']); $this->assertEquals(201, $response['headers']['status-code']);
$this->assertNotEmpty($response1['body']['$id']); $this->assertNotEmpty($response['body']['$id']);
$code = realpath(__DIR__ . '/../../resources/functions') . "/php/code.tar.gz"; $code = realpath(__DIR__ . '/../../resources/functions') . "/php/code.tar.gz";
$this->packageCode('php'); $this->packageCode('php');
$deployment = $this->client->call( $response = $this->client->call(
Client::METHOD_POST, Client::METHOD_POST,
'/functions/' . $functionId . '/deployments', '/functions/' . $functionId . '/deployments',
array_merge($headers, ['content-type' => 'multipart/form-data',]), array_merge([
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()),
[ [
'entrypoint' => 'index.php', 'entrypoint' => 'index.php',
'code' => new CURLFile($code, 'application/x-gzip', \basename($code)), 'code' => new CURLFile($code, 'application/x-gzip', \basename($code)),
@ -600,12 +642,12 @@ class UsageTest extends Scope
] ]
); );
$deploymentId = $deployment['body']['$id'] ?? ''; $deploymentId = $response['body']['$id'] ?? '';
$this->assertEquals(202, $deployment['headers']['status-code']); $this->assertEquals(202, $response['headers']['status-code']);
$this->assertNotEmpty($deployment['body']['$id']); $this->assertNotEmpty($response['body']['$id']);
$this->assertEquals(true, (new DatetimeValidator())->isValid($deployment['body']['$createdAt'])); $this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['$createdAt']));
$this->assertEquals('index.php', $deployment['body']['entrypoint']); $this->assertEquals('index.php', $response['body']['entrypoint']);
// Wait for deployment to build. // Wait for deployment to build.
sleep(self::WAIT + 20); sleep(self::WAIT + 20);
@ -613,7 +655,10 @@ class UsageTest extends Scope
$response = $this->client->call( $response = $this->client->call(
Client::METHOD_PATCH, Client::METHOD_PATCH,
'/functions/' . $functionId . '/deployments/' . $deploymentId, '/functions/' . $functionId . '/deployments/' . $deploymentId,
$headers array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()),
); );
$this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(200, $response['headers']['status-code']);
@ -623,74 +668,86 @@ class UsageTest extends Scope
$this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['$updatedAt'])); $this->assertEquals(true, (new DatetimeValidator())->isValid($response['body']['$updatedAt']));
$this->assertEquals($deploymentId, $response['body']['deployment']); $this->assertEquals($deploymentId, $response['body']['deployment']);
$execution = $this->client->call( $response = $this->client->call(
Client::METHOD_POST, Client::METHOD_POST,
'/functions/' . $functionId . '/executions', '/functions/' . $functionId . '/executions',
$headers, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()),
[ [
'async' => false, 'async' => false,
] ]
); );
$this->assertEquals(201, $execution['headers']['status-code']); $this->assertEquals(201, $response['headers']['status-code']);
$this->assertNotEmpty($execution['body']['$id']); $this->assertNotEmpty($response['body']['$id']);
$this->assertEquals($functionId, $execution['body']['functionId']); $this->assertEquals($functionId, $response['body']['functionId']);
$executionTime += (int) ($execution['body']['duration'] * 1000); $executionTime += (int) ($response['body']['duration'] * 1000);
if ($execution['body']['status'] == 'failed') { if ($response['body']['status'] == 'failed') {
$failures++; $failures += 1;
} elseif ($execution['body']['status'] == 'completed') { } elseif ($response['body']['status'] == 'completed') {
$executions++; $executions += 1;
} }
$execution = $this->client->call( $response = $this->client->call(
Client::METHOD_POST, Client::METHOD_POST,
'/functions/' . $functionId . '/executions', '/functions/' . $functionId . '/executions',
$headers, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()),
[ [
'async' => false, 'async' => false,
] ]
); );
$this->assertEquals(201, $execution['headers']['status-code']); $this->assertEquals(201, $response['headers']['status-code']);
$this->assertNotEmpty($execution['body']['$id']); $this->assertNotEmpty($response['body']['$id']);
$this->assertEquals($functionId, $execution['body']['functionId']); $this->assertEquals($functionId, $response['body']['functionId']);
if ($execution['body']['status'] == 'failed') {
$failures++;
} elseif ($execution['body']['status'] == 'completed') {
$executions++;
}
$executionTime += (int) ($execution['body']['duration'] * 1000);
$execution = $this->client->call( if ($response['body']['status'] == 'failed') {
$failures += 1;
} elseif ($response['body']['status'] == 'completed') {
$executions += 1;
}
$executionTime += (int) ($response['body']['duration'] * 1000);
$response = $this->client->call(
Client::METHOD_POST, Client::METHOD_POST,
'/functions/' . $functionId . '/executions', '/functions/' . $functionId . '/executions',
$headers, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()),
[ [
'async' => true, 'async' => true,
] ]
); );
$this->assertEquals(202, $execution['headers']['status-code']); $this->assertEquals(202, $response['headers']['status-code']);
$this->assertNotEmpty($execution['body']['$id']); $this->assertNotEmpty($response['body']['$id']);
$this->assertEquals($functionId, $execution['body']['functionId']); $this->assertEquals($functionId, $response['body']['functionId']);
sleep(self::WAIT); sleep(self::WAIT);
$execution = $this->client->call( $response = $this->client->call(
Client::METHOD_GET, Client::METHOD_GET,
'/functions/' . $functionId . '/executions/' . $execution['body']['$id'], '/functions/' . $functionId . '/executions/' . $response['body']['$id'],
$headers array_merge([
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()),
); );
if ($execution['body']['status'] == 'failed') { if ($response['body']['status'] == 'failed') {
$failures++; $failures += 1;
} elseif ($execution['body']['status'] == 'completed') { } elseif ($response['body']['status'] == 'completed') {
$executions++; $executions += 1;
} }
$executionTime += (int) ($execution['body']['duration'] * 1000); $executionTime += (int) ($response['body']['duration'] * 1000);
return array_merge($data, [ return array_merge($data, [
'functionId' => $functionId, 'functionId' => $functionId,
@ -713,7 +770,7 @@ class UsageTest extends Scope
$response = $this->client->call( $response = $this->client->call(
Client::METHOD_GET, Client::METHOD_GET,
'/functions/' . $functionId . '/usage?range=30d', '/functions/' . $functionId . '/usage?range=30d',
$data['consoleHeaders'] $this->getConsoleHeaders()
); );
$this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(200, $response['headers']['status-code']);
@ -725,18 +782,15 @@ class UsageTest extends Scope
$this->assertIsArray($response['body']['buildsTime']); $this->assertIsArray($response['body']['buildsTime']);
$this->assertIsArray($response['body']['executions']); $this->assertIsArray($response['body']['executions']);
$this->assertIsArray($response['body']['executionsTime']); $this->assertIsArray($response['body']['executionsTime']);
$this->assertEquals($executions, $response['body']['executions'][array_key_last($response['body']['executions'])]['value']);
$response = $response['body']; $this->validateDates($response['body']['executions']);
$this->assertEquals($executionTime, $response['body']['executionsTime'][array_key_last($response['body']['executionsTime'])]['value']);
$this->assertEquals($executions, $response['executions'][array_key_last($response['executions'])]['value']); $this->validateDates($response['body']['executionsTime']);
$this->validateDates($response['executions']);
$this->assertEquals($executionTime, $response['executionsTime'][array_key_last($response['executionsTime'])]['value']);
$this->validateDates($response['executionsTime']);
$response = $this->client->call( $response = $this->client->call(
Client::METHOD_GET, Client::METHOD_GET,
'/functions/usage?range=30d', '/functions/usage?range=30d',
$data['consoleHeaders'] $this->getConsoleHeaders()
); );
$this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(200, $response['headers']['status-code']);
@ -749,15 +803,12 @@ class UsageTest extends Scope
$this->assertIsArray($response['body']['buildsTime']); $this->assertIsArray($response['body']['buildsTime']);
$this->assertIsArray($response['body']['executions']); $this->assertIsArray($response['body']['executions']);
$this->assertIsArray($response['body']['executionsTime']); $this->assertIsArray($response['body']['executionsTime']);
$this->assertEquals($executions, $response['body']['executions'][array_key_last($response['body']['executions'])]['value']);
$response = $response['body']; $this->validateDates($response['body']['executions']);
$this->assertEquals($executionTime, $response['body']['executionsTime'][array_key_last($response['body']['executionsTime'])]['value']);
$this->assertEquals($executions, $response['executions'][array_key_last($response['executions'])]['value']); $this->validateDates($response['body']['executionsTime']);
$this->validateDates($response['executions']); $this->assertGreaterThan(0, $response['body']['buildsTime'][array_key_last($response['body']['buildsTime'])]['value']);
$this->assertEquals($executionTime, $response['executionsTime'][array_key_last($response['executionsTime'])]['value']); $this->validateDates($response['body']['buildsTime']);
$this->validateDates($response['executionsTime']);
$this->assertGreaterThan(0, $response['buildsTime'][array_key_last($response['buildsTime'])]['value']);
$this->validateDates($response['buildsTime']);
} }
public function tearDown(): void public function tearDown(): void

View file

@ -84,8 +84,6 @@ trait ProjectCustom
'rules.read', 'rules.read',
'rules.write', 'rules.write',
'sessions.write', 'sessions.write',
'accounts.write',
'accounts.read',
'targets.read', 'targets.read',
'targets.write', 'targets.write',
'providers.read', 'providers.read',

View file

@ -27,7 +27,6 @@ class AccountCustomServerTest extends Scope
* Test for SUCCESS * Test for SUCCESS
*/ */
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([ $response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [ ], $this->getHeaders()), [
@ -43,7 +42,6 @@ class AccountCustomServerTest extends Scope
$userId = $response['body']['userId']; $userId = $response['body']['userId'];
$response = $this->client->call(Client::METHOD_GET, '/users/' . $userId, array_merge([ $response = $this->client->call(Client::METHOD_GET, '/users/' . $userId, array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders())); ], $this->getHeaders()));
@ -53,7 +51,6 @@ class AccountCustomServerTest extends Scope
$this->assertNotEmpty($response['body']['accessedAt']); $this->assertNotEmpty($response['body']['accessedAt']);
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([ $response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [ ], $this->getHeaders()), [
@ -67,11 +64,10 @@ class AccountCustomServerTest extends Scope
// already logged in // already logged in
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([ $response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-session' => $session, 'x-appwrite-session' => $session,
], $this->getHeaders()), [ ]), [
'email' => $email, 'email' => $email,
'password' => $password, 'password' => $password,
]); ]);
@ -82,7 +78,6 @@ class AccountCustomServerTest extends Scope
* Test for FAILURE * Test for FAILURE
*/ */
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([ $response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [ ], $this->getHeaders()), [
@ -93,7 +88,6 @@ class AccountCustomServerTest extends Scope
$this->assertEquals(401, $response['headers']['status-code']); $this->assertEquals(401, $response['headers']['status-code']);
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([ $response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [ ], $this->getHeaders()), [
@ -104,7 +98,6 @@ class AccountCustomServerTest extends Scope
$this->assertEquals(401, $response['headers']['status-code']); $this->assertEquals(401, $response['headers']['status-code']);
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([ $response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [ ], $this->getHeaders()), [
@ -133,7 +126,6 @@ class AccountCustomServerTest extends Scope
* Test for SUCCESS * Test for SUCCESS
*/ */
$response = $this->client->call(Client::METHOD_GET, '/account', array_merge([ $response = $this->client->call(Client::METHOD_GET, '/account', array_merge([
'origin' => 'http://localhost',
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-session' => $session, 'x-appwrite-session' => $session,
@ -154,9 +146,9 @@ class AccountCustomServerTest extends Scope
$response = $this->client->call(Client::METHOD_GET, '/account', array_merge([ $response = $this->client->call(Client::METHOD_GET, '/account', array_merge([
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders())); ]));
$this->assertEquals(404, $response['headers']['status-code']); $this->assertEquals(401, $response['headers']['status-code']);
return $data; return $data;
} }
@ -286,8 +278,7 @@ class AccountCustomServerTest extends Scope
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-session' => $session 'x-appwrite-session' => $session
], ]
$this->getHeaders()
)); ));
$this->assertEquals($response['headers']['status-code'], 200); $this->assertEquals($response['headers']['status-code'], 200);

View file

@ -111,8 +111,7 @@ class DatabasesConsoleClientTest extends Scope
$collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([ $collections = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections', array_merge([
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id']
'x-appwrite-key' => $this->getProject()['apiKey']
], $this->getHeaders())); ], $this->getHeaders()));
$this->assertEquals(200, $collections['headers']['status-code']); $this->assertEquals(200, $collections['headers']['status-code']);

View file

@ -114,7 +114,6 @@ class DatabasesCustomClientTest extends Scope
$response = $this->client->call(Client::METHOD_GET, '/account', array_merge([ $response = $this->client->call(Client::METHOD_GET, '/account', array_merge([
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
], $this->getHeaders())); ], $this->getHeaders()));
$this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(200, $response['headers']['status-code']);

View file

@ -2494,7 +2494,6 @@ class ProjectsConsoleClientTest extends Scope
$response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/keys/' . $keyId, array_merge([ $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/keys/' . $keyId, array_merge([
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $keyId
], $this->getHeaders()), []); ], $this->getHeaders()), []);
$this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(200, $response['headers']['status-code']);