mirror of
https://github.com/appwrite/appwrite
synced 2026-05-23 00:49:02 +00:00
Merge pull request #3223 from appwrite/feat-account-update-status
feat: account update status
This commit is contained in:
commit
2060a5f0e9
44 changed files with 262 additions and 252 deletions
|
|
@ -12,7 +12,10 @@
|
|||
- `X-Appwrite-Webhook-Event` Webhook header has been renamed to `X-Appwrite-Webhook-Events` and contains all possible events
|
||||
- Renamed `providers` to `authProviders` in Projects **Breaking Change**
|
||||
- Renamed `stdout` to `response` in Projects **Breaking Change**
|
||||
- Added new endppoint to list all memberships on the Users API
|
||||
- Removed deleted endpoint from the Accounts API
|
||||
- Added new endpoint to update user's status from the Accounts API
|
||||
- Deleted users will now free their ID and not reserve it anymore
|
||||
- Added new endpoint to list all memberships on the Users API
|
||||
- Increased Execution response to 1MB
|
||||
- Added Wildcard support to Platforms
|
||||
- Added Activity page to Teams console
|
||||
|
|
|
|||
|
|
@ -1090,18 +1090,7 @@ $collections = [
|
|||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => 'deleted',
|
||||
'type' => Database::VAR_BOOLEAN,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
]
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
|
|
@ -1117,14 +1106,7 @@ $collections = [
|
|||
'attributes' => ['search'],
|
||||
'lengths' => [],
|
||||
'orders' => [],
|
||||
],
|
||||
[
|
||||
'$id' => '_key_deleted_email',
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['deleted', 'email'],
|
||||
'lengths' => [0, 320],
|
||||
'orders' => [Database::ORDER_ASC, Database::ORDER_ASC],
|
||||
],
|
||||
]
|
||||
],
|
||||
],
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -81,9 +81,7 @@ App::post('/v1/account')
|
|||
$limit = $project->getAttribute('auths', [])['limit'] ?? 0;
|
||||
|
||||
if ($limit !== 0) {
|
||||
$total = $dbForProject->count('users', [
|
||||
new Query('deleted', Query::TYPE_EQUAL, [false]),
|
||||
], APP_LIMIT_USERS);
|
||||
$total = $dbForProject->count('users', max: APP_LIMIT_USERS);
|
||||
|
||||
if ($total >= $limit) {
|
||||
throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::USER_COUNT_EXCEEDED);
|
||||
|
|
@ -108,8 +106,7 @@ App::post('/v1/account')
|
|||
'sessions' => null,
|
||||
'tokens' => null,
|
||||
'memberships' => null,
|
||||
'search' => implode(' ', [$userId, $email, $name]),
|
||||
'deleted' => false
|
||||
'search' => implode(' ', [$userId, $email, $name])
|
||||
])));
|
||||
} catch (Duplicate $th) {
|
||||
throw new Exception('Account already exists', 409, Exception::USER_ALREADY_EXISTS);
|
||||
|
|
@ -170,7 +167,6 @@ App::post('/v1/account/sessions')
|
|||
$protocol = $request->getProtocol();
|
||||
|
||||
$profile = $dbForProject->findOne('users', [
|
||||
new Query('deleted', Query::TYPE_EQUAL, [false]),
|
||||
new Query('email', Query::TYPE_EQUAL, [$email])]
|
||||
);
|
||||
|
||||
|
|
@ -482,7 +478,6 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
$isVerified = $oauth2->isEmailVerified($accessToken);
|
||||
|
||||
$user = $dbForProject->findOne('users', [
|
||||
new Query('deleted', Query::TYPE_EQUAL, [false]),
|
||||
new Query('email', Query::TYPE_EQUAL, [$email])]
|
||||
);
|
||||
|
||||
|
|
@ -490,7 +485,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
$limit = $project->getAttribute('auths', [])['limit'] ?? 0;
|
||||
|
||||
if ($limit !== 0) {
|
||||
$total = $dbForProject->count('users', [new Query('deleted', Query::TYPE_EQUAL, [false])], APP_LIMIT_USERS);
|
||||
$total = $dbForProject->count('users', max: APP_LIMIT_USERS);
|
||||
|
||||
if ($total >= $limit) {
|
||||
throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::USER_COUNT_EXCEEDED);
|
||||
|
|
@ -515,8 +510,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
'sessions' => null,
|
||||
'tokens' => null,
|
||||
'memberships' => null,
|
||||
'search' => implode(' ', [$userId, $email, $name]),
|
||||
'deleted' => false
|
||||
'search' => implode(' ', [$userId, $email, $name])
|
||||
])));
|
||||
} catch (Duplicate $th) {
|
||||
throw new Exception('Account already exists', 409, Exception::USER_ALREADY_EXISTS);
|
||||
|
|
@ -664,9 +658,7 @@ App::post('/v1/account/sessions/magic-url')
|
|||
$limit = $project->getAttribute('auths', [])['limit'] ?? 0;
|
||||
|
||||
if ($limit !== 0) {
|
||||
$total = $dbForProject->count('users', [
|
||||
new Query('deleted', Query::TYPE_EQUAL, [false]),
|
||||
], APP_LIMIT_USERS);
|
||||
$total = $dbForProject->count('users', max: APP_LIMIT_USERS);
|
||||
|
||||
if ($total >= $limit) {
|
||||
throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::USER_COUNT_EXCEEDED);
|
||||
|
|
@ -690,8 +682,7 @@ App::post('/v1/account/sessions/magic-url')
|
|||
'sessions' => null,
|
||||
'tokens' => null,
|
||||
'memberships' => null,
|
||||
'search' => implode(' ', [$userId, $email]),
|
||||
'deleted' => false
|
||||
'search' => implode(' ', [$userId, $email])
|
||||
])));
|
||||
}
|
||||
|
||||
|
|
@ -791,7 +782,7 @@ App::put('/v1/account/sessions/magic-url')
|
|||
|
||||
$user = Authorization::skip(fn() => $dbForProject->getDocument('users', $userId));
|
||||
|
||||
if ($user->isEmpty() || $user->getAttribute('deleted')) {
|
||||
if ($user->isEmpty()) {
|
||||
throw new Exception('User not found', 404, Exception::USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
@ -926,9 +917,7 @@ App::post('/v1/account/sessions/anonymous')
|
|||
$limit = $project->getAttribute('auths', [])['limit'] ?? 0;
|
||||
|
||||
if ($limit !== 0) {
|
||||
$total = $dbForProject->count('users', [
|
||||
new Query('deleted', Query::TYPE_EQUAL, [false]),
|
||||
], APP_LIMIT_USERS);
|
||||
$total = $dbForProject->count('users', max: APP_LIMIT_USERS);
|
||||
|
||||
if ($total >= $limit) {
|
||||
throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::USER_COUNT_EXCEEDED);
|
||||
|
|
@ -952,8 +941,7 @@ App::post('/v1/account/sessions/anonymous')
|
|||
'sessions' => null,
|
||||
'tokens' => null,
|
||||
'memberships' => null,
|
||||
'search' => $userId,
|
||||
'deleted' => false
|
||||
'search' => $userId
|
||||
])));
|
||||
|
||||
// Create session token
|
||||
|
|
@ -1470,17 +1458,18 @@ App::patch('/v1/account/prefs')
|
|||
$response->dynamic($user, Response::MODEL_USER);
|
||||
});
|
||||
|
||||
App::delete('/v1/account')
|
||||
->desc('Delete Account')
|
||||
App::patch('/v1/account/status')
|
||||
->desc('Update Account Status')
|
||||
->groups(['api', 'account'])
|
||||
->label('event', 'users.[userId].delete')
|
||||
->label('event', 'users.[userId].update.status')
|
||||
->label('scope', 'account')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_JWT])
|
||||
->label('sdk.namespace', 'account')
|
||||
->label('sdk.method', 'delete')
|
||||
->label('sdk.description', '/docs/references/account/delete.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_NOCONTENT)
|
||||
->label('sdk.response.model', Response::MODEL_NONE)
|
||||
->label('sdk.method', 'updateStatus')
|
||||
->label('sdk.description', '/docs/references/account/update-status.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_USER)
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
|
|
@ -1497,28 +1486,15 @@ App::delete('/v1/account')
|
|||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$protocol = $request->getProtocol();
|
||||
$user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('status', false));
|
||||
|
||||
// TODO Seems to be related to users.php/App::delete('/v1/users/:userId'). Can we share code between these two? Do todos below apply to users.php?
|
||||
|
||||
// TODO delete all tokens or only current session?
|
||||
// TODO delete all user data according to GDPR. Make sure everything is backed up and backups are deleted later
|
||||
/**
|
||||
* Data to delete
|
||||
* * Tokens
|
||||
* * Memberships
|
||||
*/
|
||||
|
||||
$audits
|
||||
->setResource('user/' . $user->getId())
|
||||
->setPayload($response->output($user, Response::MODEL_USER))
|
||||
;
|
||||
->setPayload($response->output($user, Response::MODEL_USER));
|
||||
|
||||
$events
|
||||
->setParam('userId', $user->getId())
|
||||
->setPayload($response->output($user, Response::MODEL_USER))
|
||||
;
|
||||
->setPayload($response->output($user, Response::MODEL_USER));
|
||||
|
||||
if (!Config::getParam('domainVerification')) {
|
||||
$response->addHeader('X-Fallback-Cookies', \json_encode([]));
|
||||
|
|
@ -1526,11 +1502,7 @@ App::delete('/v1/account')
|
|||
|
||||
$usage->setParam('users.delete', 1);
|
||||
|
||||
$response
|
||||
->addCookie(Auth::$cookieName . '_legacy', '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null)
|
||||
->addCookie(Auth::$cookieName, '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite'))
|
||||
->noContent()
|
||||
;
|
||||
$response->dynamic($user, Response::MODEL_USER);
|
||||
});
|
||||
|
||||
App::delete('/v1/account/sessions/:sessionId')
|
||||
|
|
@ -1840,7 +1812,6 @@ App::post('/v1/account/recovery')
|
|||
$email = \strtolower($email);
|
||||
|
||||
$profile = $dbForProject->findOne('users', [
|
||||
new Query('deleted', Query::TYPE_EQUAL, [false]),
|
||||
new Query('email', Query::TYPE_EQUAL, [$email])
|
||||
]);
|
||||
|
||||
|
|
@ -1943,7 +1914,7 @@ App::put('/v1/account/recovery')
|
|||
|
||||
$profile = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($profile->isEmpty() || $profile->getAttribute('deleted')) {
|
||||
if ($profile->isEmpty()) {
|
||||
throw new Exception('User not found', 404, Exception::USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -348,8 +348,7 @@ App::post('/v1/teams/:teamId/memberships')
|
|||
'sessions' => null,
|
||||
'tokens' => null,
|
||||
'memberships' => null,
|
||||
'search' => implode(' ', [$userId, $email, $name]),
|
||||
'deleted' => false
|
||||
'search' => implode(' ', [$userId, $email, $name])
|
||||
])));
|
||||
} catch (Duplicate $th) {
|
||||
throw new Exception('Account already exists', 409, Exception::USER_ALREADY_EXISTS);
|
||||
|
|
|
|||
|
|
@ -68,8 +68,7 @@ App::post('/v1/users')
|
|||
'sessions' => null,
|
||||
'tokens' => null,
|
||||
'memberships' => null,
|
||||
'search' => implode(' ', [$userId, $email, $name]),
|
||||
'deleted' => false
|
||||
'search' => implode(' ', [$userId, $email, $name])
|
||||
]));
|
||||
} catch (Duplicate $th) {
|
||||
throw new Exception('Account already exists', 409, Exception::USER_ALREADY_EXISTS);
|
||||
|
|
@ -120,9 +119,7 @@ App::get('/v1/users')
|
|||
}
|
||||
}
|
||||
|
||||
$queries = [
|
||||
new Query('deleted', Query::TYPE_EQUAL, [false])
|
||||
];
|
||||
$queries = [];
|
||||
|
||||
if (!empty($search)) {
|
||||
$queries[] = new Query('search', Query::TYPE_SEARCH, [$search]);
|
||||
|
|
@ -160,7 +157,7 @@ App::get('/v1/users/:userId')
|
|||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty() || $user->getAttribute('deleted')) {
|
||||
if ($user->isEmpty()) {
|
||||
throw new Exception('User not found', 404, Exception::USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
@ -192,7 +189,7 @@ App::get('/v1/users/:userId/prefs')
|
|||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty() || $user->getAttribute('deleted')) {
|
||||
if ($user->isEmpty()) {
|
||||
throw new Exception('User not found', 404, Exception::USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
@ -228,7 +225,7 @@ App::get('/v1/users/:userId/sessions')
|
|||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty() || $user->getAttribute('deleted')) {
|
||||
if ($user->isEmpty()) {
|
||||
throw new Exception('User not found', 404, Exception::USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
@ -274,7 +271,7 @@ App::get('/v1/users/:userId/memberships')
|
|||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty() || $user->getAttribute('deleted')) {
|
||||
if ($user->isEmpty()) {
|
||||
throw new Exception('User not found', 404, Exception::USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
@ -324,7 +321,7 @@ App::get('/v1/users/:userId/logs')
|
|||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty() || $user->getAttribute('deleted')) {
|
||||
if ($user->isEmpty()) {
|
||||
throw new Exception('User not found', 404, Exception::USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
@ -409,7 +406,7 @@ App::patch('/v1/users/:userId/status')
|
|||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty() || $user->getAttribute('deleted')) {
|
||||
if ($user->isEmpty()) {
|
||||
throw new Exception('User not found', 404, Exception::USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
@ -452,7 +449,7 @@ App::patch('/v1/users/:userId/verification')
|
|||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty() || $user->getAttribute('deleted')) {
|
||||
if ($user->isEmpty()) {
|
||||
throw new Exception('User not found', 404, Exception::USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
@ -495,7 +492,7 @@ App::patch('/v1/users/:userId/name')
|
|||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty() || $user->getAttribute('deleted')) {
|
||||
if ($user->isEmpty()) {
|
||||
throw new Exception('User not found', 404, Exception::USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
@ -543,7 +540,7 @@ App::patch('/v1/users/:userId/password')
|
|||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty() || $user->getAttribute('deleted')) {
|
||||
if ($user->isEmpty()) {
|
||||
throw new Exception('User not found', 404, Exception::USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
@ -590,7 +587,7 @@ App::patch('/v1/users/:userId/email')
|
|||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty() || $user->getAttribute('deleted')) {
|
||||
if ($user->isEmpty()) {
|
||||
throw new Exception('User not found', 404, Exception::USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
@ -650,7 +647,7 @@ App::patch('/v1/users/:userId/prefs')
|
|||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty() || $user->getAttribute('deleted')) {
|
||||
if ($user->isEmpty()) {
|
||||
throw new Exception('User not found', 404, Exception::USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
@ -692,7 +689,7 @@ App::delete('/v1/users/:userId/sessions/:sessionId')
|
|||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty() || $user->getAttribute('deleted')) {
|
||||
if ($user->isEmpty()) {
|
||||
throw new Exception('User not found', 404, Exception::USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
@ -743,7 +740,7 @@ App::delete('/v1/users/:userId/sessions')
|
|||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty() || $user->getAttribute('deleted')) {
|
||||
if ($user->isEmpty()) {
|
||||
throw new Exception('User not found', 404, Exception::USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
@ -795,28 +792,14 @@ App::delete('/v1/users/:userId')
|
|||
|
||||
$user = $dbForProject->getDocument('users', $userId);
|
||||
|
||||
if ($user->isEmpty() || $user->getAttribute('deleted')) {
|
||||
if ($user->isEmpty()) {
|
||||
throw new Exception('User not found', 404, Exception::USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
/**
|
||||
* DO NOT DELETE THE USER RECORD ITSELF.
|
||||
* WE RETAIN THE USER RECORD TO RESERVE THE USER ID AND ENSURE THAT THE USER ID IS NOT REUSED.
|
||||
*/
|
||||
|
||||
// clone user object to send to workers
|
||||
$clone = clone $user;
|
||||
|
||||
$user
|
||||
->setAttribute("name", null)
|
||||
->setAttribute("email", null)
|
||||
->setAttribute("password", null)
|
||||
->setAttribute("deleted", true)
|
||||
->setAttribute("tokens", null)
|
||||
->setAttribute("search", null)
|
||||
;
|
||||
|
||||
$dbForProject->updateDocument('users', $userId, $user);
|
||||
$dbForProject->deleteDocument('users', $userId);
|
||||
|
||||
$deletes
|
||||
->setType(DELETE_TYPE_DOCUMENT)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@ class DeletesV1 extends Worker
|
|||
*/
|
||||
protected $consoleDB = null;
|
||||
|
||||
public function getName(): string {
|
||||
public function getName(): string
|
||||
{
|
||||
return "deletes";
|
||||
}
|
||||
|
||||
|
|
@ -202,11 +203,6 @@ class DeletesV1 extends Worker
|
|||
*/
|
||||
protected function deleteUser(Document $document, string $projectId): void
|
||||
{
|
||||
/**
|
||||
* DO NOT DELETE THE USER RECORD ITSELF.
|
||||
* WE RETAIN THE USER RECORD TO RESERVE THE USER ID AND ENSURE THAT THE USER ID IS NOT REUSED.
|
||||
*/
|
||||
|
||||
$userId = $document->getId();
|
||||
|
||||
// Delete all sessions of this user from the sessions table and update the sessions field of the user record
|
||||
|
|
@ -225,9 +221,14 @@ class DeletesV1 extends Worker
|
|||
$teamId = $document->getAttribute('teamId');
|
||||
$team = $this->getProjectDB($projectId)->getDocument('teams', $teamId);
|
||||
if (!$team->isEmpty()) {
|
||||
$team = $this->getProjectDB($projectId)->updateDocument('teams', $teamId, new Document(\array_merge($team->getArrayCopy(), [
|
||||
'total' => \max($team->getAttribute('total', 0) - 1, 0), // Ensure that total >= 0
|
||||
])));
|
||||
$team = $this
|
||||
->getProjectDB($projectId)
|
||||
->updateDocument(
|
||||
'teams',
|
||||
$teamId,
|
||||
// Ensure that total >= 0
|
||||
$team->setAttribute('total', \max($team->getAttribute('total', 0) - 1, 0))
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -348,7 +349,7 @@ class DeletesV1 extends Worker
|
|||
*/
|
||||
Console::info("Deleting builds for function " . $functionId);
|
||||
$storageBuilds = new Local(APP_STORAGE_BUILDS . '/app-' . $projectId);
|
||||
foreach ($deploymentIds as $deploymentId) {
|
||||
foreach ($deploymentIds as $deploymentId) {
|
||||
$this->deleteByGroup('builds', [
|
||||
new Query('deploymentId', Query::TYPE_EQUAL, [$deploymentId])
|
||||
], $dbForProject, function (Document $document) use ($storageBuilds, $deploymentId) {
|
||||
|
|
@ -362,7 +363,7 @@ class DeletesV1 extends Worker
|
|||
|
||||
/**
|
||||
* Delete Executions
|
||||
*/
|
||||
*/
|
||||
Console::info("Deleting executions for function " . $functionId);
|
||||
$this->deleteByGroup('executions', [
|
||||
new Query('functionId', Query::TYPE_EQUAL, [$functionId])
|
||||
|
|
@ -380,7 +381,6 @@ class DeletesV1 extends Worker
|
|||
Console::error($th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -474,7 +474,7 @@ class DeletesV1 extends Worker
|
|||
$chunk++;
|
||||
|
||||
/** @var string[] $projectIds */
|
||||
$projectIds = array_map(fn(Document $project) => $project->getId(), $projects);
|
||||
$projectIds = array_map(fn (Document $project) => $project->getId(), $projects);
|
||||
|
||||
$sum = count($projects);
|
||||
|
||||
|
|
@ -533,21 +533,21 @@ class DeletesV1 extends Worker
|
|||
$consoleDB = $this->getConsoleDB();
|
||||
|
||||
// If domain has certificate generated
|
||||
if(isset($document['certificateId'])) {
|
||||
if (isset($document['certificateId'])) {
|
||||
$domainUsingCertificate = $consoleDB->findOne('domains', [
|
||||
new Query('certificateId', Query::TYPE_EQUAL, [$document['certificateId']])
|
||||
]);
|
||||
|
||||
if(!$domainUsingCertificate) {
|
||||
if (!$domainUsingCertificate) {
|
||||
$mainDomain = App::getEnv('_APP_DOMAIN_TARGET', '');
|
||||
if($mainDomain === $document->getAttribute('domain')) {
|
||||
if ($mainDomain === $document->getAttribute('domain')) {
|
||||
$domainUsingCertificate = $mainDomain;
|
||||
}
|
||||
}
|
||||
|
||||
// If certificate is still used by some domain, mark we can't delete.
|
||||
// Current domain should not be found, because we only have copy. Original domain is already deleted from database.
|
||||
if($domainUsingCertificate) {
|
||||
if ($domainUsingCertificate) {
|
||||
Console::warning("Skipping certificate deletion, because a domain is still using it.");
|
||||
return;
|
||||
}
|
||||
|
|
@ -559,7 +559,7 @@ class DeletesV1 extends Worker
|
|||
|
||||
if ($domain && $checkTraversal && is_dir($directory)) {
|
||||
// Delete certificate document, so Appwrite is aware of change
|
||||
if(isset($document['certificateId'])) {
|
||||
if (isset($document['certificateId'])) {
|
||||
$consoleDB->deleteDocument('certificates', $document['certificateId']);
|
||||
}
|
||||
|
||||
|
|
@ -577,8 +577,8 @@ class DeletesV1 extends Worker
|
|||
$dbForProject = $this->getProjectDB($projectId);
|
||||
$dbForProject->deleteCollection('bucket_' . $document->getInternalId());
|
||||
|
||||
$device = new Local(APP_STORAGE_UPLOADS.'/app-'.$projectId);
|
||||
|
||||
$device = new Local(APP_STORAGE_UPLOADS . '/app-' . $projectId);
|
||||
|
||||
switch (App::getEnv('_APP_STORAGE_DEVICE', Storage::DEVICE_LOCAL)) {
|
||||
case Storage::DEVICE_S3:
|
||||
$s3AccessKey = App::getEnv('_APP_STORAGE_S3_ACCESS_KEY', '');
|
||||
|
|
@ -597,7 +597,7 @@ class DeletesV1 extends Worker
|
|||
$device = new DOSpaces(APP_STORAGE_UPLOADS . '/app-' . $projectId, $doSpacesAccessKey, $doSpacesSecretKey, $doSpacesBucket, $doSpacesRegion, $doSpacesAcl);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
$device->deletePath($document->getId());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ public class MainActivity extends AppCompatActivity {
|
|||
|
||||
Account account = new Account(client);
|
||||
|
||||
account.delete(new Continuation<Object>() {
|
||||
account.updateStatus(new Continuation<Object>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public CoroutineContext getContext() {
|
||||
|
|
@ -17,7 +17,7 @@ class MainActivity : AppCompatActivity() {
|
|||
val account = Account(client)
|
||||
|
||||
GlobalScope.launch {
|
||||
val response = account.delete()
|
||||
val response = account.updateStatus()
|
||||
val json = response.body?.string()
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ func main() async throws {
|
|||
.setEndpoint("https://[HOSTNAME_OR_IP]/v1") // Your API Endpoint
|
||||
.setProject("5df5acd0d48c2") // Your project ID
|
||||
let account = Account(client)
|
||||
let result = try await account.delete()
|
||||
let user = try await account.updateStatus()
|
||||
|
||||
print(String(describing: result)
|
||||
print(String(describing: user)
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@ void main() { // Init SDK
|
|||
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
|
||||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
Future result = account.delete();
|
||||
Future result = account.updateStatus();
|
||||
|
||||
result
|
||||
.then((response) {
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
const sdk = new Appwrite();
|
||||
|
||||
sdk
|
||||
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
|
||||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.account.updateStatus();
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
}, function (error) {
|
||||
console.log(error); // Failure
|
||||
});
|
||||
|
|
@ -1 +0,0 @@
|
|||
appwrite account delete
|
||||
|
|
@ -0,0 +1 @@
|
|||
appwrite account updateStatus
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
const sdk = new Appwrite();
|
||||
|
||||
sdk
|
||||
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
|
||||
.setProject('5df5acd0d48c2') // Your project ID
|
||||
;
|
||||
|
||||
let promise = sdk.account.updateStatus();
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
}, function (error) {
|
||||
console.log(error); // Failure
|
||||
});
|
||||
|
|
@ -10,7 +10,7 @@ void main() { // Init SDK
|
|||
.setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token
|
||||
;
|
||||
|
||||
Future result = account.delete();
|
||||
Future result = account.updateStatus();
|
||||
|
||||
result
|
||||
.then((response) {
|
||||
|
|
@ -12,7 +12,7 @@ client
|
|||
;
|
||||
|
||||
|
||||
let promise = account.delete();
|
||||
let promise = account.updateStatus();
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response);
|
||||
|
|
@ -8,7 +8,7 @@ public void main() {
|
|||
.setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ..."); // Your secret JSON Web Token
|
||||
|
||||
Account account = new Account(client);
|
||||
account.delete(new Continuation<Response>() {
|
||||
account.updateStatus(new Continuation<Response>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public CoroutineContext getContext() {
|
||||
|
|
@ -8,6 +8,6 @@ suspend fun main() {
|
|||
.setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token
|
||||
|
||||
val account = Account(client)
|
||||
val response = account.delete()
|
||||
val response = account.updateStatus()
|
||||
val json = response.body?.string()
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ client
|
|||
.setJWT('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...') // Your secret JSON Web Token
|
||||
;
|
||||
|
||||
let promise = account.delete();
|
||||
let promise = account.updateStatus();
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response);
|
||||
|
|
@ -13,4 +13,4 @@ $client
|
|||
|
||||
$account = new Account($client);
|
||||
|
||||
$result = $account->delete();
|
||||
$result = $account->updateStatus();
|
||||
|
|
@ -11,4 +11,4 @@ client = Client()
|
|||
|
||||
account = Account(client)
|
||||
|
||||
result = account.delete()
|
||||
result = account.update_status()
|
||||
|
|
@ -9,6 +9,6 @@ client
|
|||
|
||||
account = Appwrite::Account.new(client)
|
||||
|
||||
response = account.delete()
|
||||
response = account.update_status()
|
||||
|
||||
puts response.inspect
|
||||
|
|
@ -6,7 +6,7 @@ func main() async throws {
|
|||
.setProject("5df5acd0d48c2") // Your project ID
|
||||
.setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...") // Your secret JSON Web Token
|
||||
let account = Account(client)
|
||||
let result = try await account.delete()
|
||||
let user = try await account.updateStatus()
|
||||
|
||||
print(String(describing: result)
|
||||
print(String(describing: user)
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
Delete a currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. This is done to avoid deleted accounts being overtaken by new users with the same email address. Any user-related resources like documents or storage files should be deleted separately.
|
||||
1
docs/references/account/update-status.md
Normal file
1
docs/references/account/update-status.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
Block the currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. To completely delete a user, use the Users API instead.
|
||||
|
|
@ -1 +1 @@
|
|||
Delete a user by its unique ID.
|
||||
Delete a user by its unique ID, thereby releasing it's ID. Since ID is released and can be reused, all user-related resources like documents or storage files should be deleted before user deletion. If you want to keep ID reserved, use the [updateStatus](/docs/server/users#usersUpdateStatus) endpoint instead.
|
||||
|
|
@ -1 +1 @@
|
|||
Update the user status by its unique ID.
|
||||
Update the user status by its unique ID. Use this endpoint as an alternative to deleting a user if you want to keep user's ID reserved.
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
stopOnFailure="true"
|
||||
>
|
||||
<extensions>
|
||||
<extension class="Appwrite\Tests\TestHook" />
|
||||
|
|
|
|||
|
|
@ -256,6 +256,15 @@ class V13 extends Migration
|
|||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'users':
|
||||
/**
|
||||
* Remove deleted users.
|
||||
*/
|
||||
if ($document->getAttribute('deleted', false) === true) {
|
||||
$this->projectDB->deleteDocument('users', $document->getId());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return $document;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class AccountCustomClientTest extends Scope
|
|||
/**
|
||||
* @depends testCreateAccountSession
|
||||
*/
|
||||
public function testCreateOAuth2AccountSession():array
|
||||
public function testCreateOAuth2AccountSession(): array
|
||||
{
|
||||
$provider = 'mock';
|
||||
$appId = '1';
|
||||
|
|
@ -26,7 +26,7 @@ class AccountCustomClientTest extends Scope
|
|||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$this->getProject()['$id'].'/oauth2', array_merge([
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $this->getProject()['$id'] . '/oauth2', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => 'console',
|
||||
|
|
@ -39,7 +39,7 @@ class AccountCustomClientTest extends Scope
|
|||
|
||||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account/sessions/oauth2/'.$provider, array_merge([
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account/sessions/oauth2/' . $provider, array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
|
|
@ -54,9 +54,9 @@ class AccountCustomClientTest extends Scope
|
|||
return [];
|
||||
}
|
||||
|
||||
public function testBlockedAccount():array
|
||||
public function testBlockedAccount(): array
|
||||
{
|
||||
$email = uniqid().'user@localhost.test';
|
||||
$email = uniqid() . 'user@localhost.test';
|
||||
$password = 'password';
|
||||
$name = 'User Name (blocked)';
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ class AccountCustomClientTest extends Scope
|
|||
$id = $response['body']['$id'];
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 201);
|
||||
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
|
|
@ -90,13 +90,13 @@ class AccountCustomClientTest extends Scope
|
|||
$this->assertEquals($response['headers']['status-code'], 201);
|
||||
|
||||
$sessionId = $response['body']['$id'];
|
||||
$session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']];
|
||||
$session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']];
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]));
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
|
|
@ -115,7 +115,7 @@ class AccountCustomClientTest extends Scope
|
|||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]));
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 401);
|
||||
|
|
@ -134,9 +134,89 @@ class AccountCustomClientTest extends Scope
|
|||
return [];
|
||||
}
|
||||
|
||||
public function testCreateJWT():array
|
||||
|
||||
public function testSelfBlockedAccount(): array
|
||||
{
|
||||
$email = uniqid().'user@localhost.test';
|
||||
$email = uniqid() . 'user55@localhost.test';
|
||||
$password = 'password';
|
||||
$name = 'User Name (self blocked)';
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'userId' => 'unique()',
|
||||
'email' => $email,
|
||||
'password' => $password,
|
||||
'name' => $name,
|
||||
]);
|
||||
|
||||
$id = $response['body']['$id'];
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 201);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'email' => $email,
|
||||
'password' => $password,
|
||||
]);
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 201);
|
||||
|
||||
$session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']];
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]));
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/account/status', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
], [
|
||||
'status' => false,
|
||||
]);
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]));
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 401);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'email' => $email,
|
||||
'password' => $password,
|
||||
]);
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 401);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public function testCreateJWT(): array
|
||||
{
|
||||
$email = uniqid() . 'user@localhost.test';
|
||||
$password = 'password';
|
||||
$name = 'User Name (JWT)';
|
||||
|
||||
|
|
@ -157,7 +237,7 @@ class AccountCustomClientTest extends Scope
|
|||
$id = $response['body']['$id'];
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 201);
|
||||
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
|
|
@ -170,13 +250,13 @@ class AccountCustomClientTest extends Scope
|
|||
$this->assertEquals($response['headers']['status-code'], 201);
|
||||
|
||||
$sessionId = $response['body']['$id'];
|
||||
$session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']];
|
||||
$session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']];
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]));
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
|
|
@ -185,7 +265,7 @@ class AccountCustomClientTest extends Scope
|
|||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]));
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 201);
|
||||
|
|
@ -212,11 +292,11 @@ class AccountCustomClientTest extends Scope
|
|||
|
||||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_DELETE, '/account/sessions/'.$sessionId, array_merge([
|
||||
$response = $this->client->call(Client::METHOD_DELETE, '/account/sessions/' . $sessionId, array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]));
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 204);
|
||||
|
|
@ -249,7 +329,7 @@ class AccountCustomClientTest extends Scope
|
|||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
|
||||
$session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']];
|
||||
$session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']];
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
|
|
@ -258,7 +338,7 @@ class AccountCustomClientTest extends Scope
|
|||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]);
|
||||
|
||||
$this->assertEquals(401, $response['headers']['status-code']);
|
||||
|
|
@ -278,7 +358,7 @@ class AccountCustomClientTest extends Scope
|
|||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]), [
|
||||
'oldPassword' => '',
|
||||
]);
|
||||
|
|
@ -293,7 +373,7 @@ class AccountCustomClientTest extends Scope
|
|||
*/
|
||||
public function testUpdateAnonymousAccountEmail($session)
|
||||
{
|
||||
$email = uniqid().'new@localhost.test';
|
||||
$email = uniqid() . 'new@localhost.test';
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
|
|
@ -302,7 +382,7 @@ class AccountCustomClientTest extends Scope
|
|||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]), [
|
||||
'email' => $email,
|
||||
'password' => '',
|
||||
|
|
@ -316,7 +396,7 @@ class AccountCustomClientTest extends Scope
|
|||
public function testConvertAnonymousAccount()
|
||||
{
|
||||
$session = $this->testCreateAnonymousAccount();
|
||||
$email = uniqid().'new@localhost.test';
|
||||
$email = uniqid() . 'new@localhost.test';
|
||||
$password = 'new-password';
|
||||
|
||||
/**
|
||||
|
|
@ -336,7 +416,7 @@ class AccountCustomClientTest extends Scope
|
|||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]), [
|
||||
'email' => $email,
|
||||
'password' => $password,
|
||||
|
|
@ -347,13 +427,13 @@ class AccountCustomClientTest extends Scope
|
|||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$email = uniqid().'new@localhost.test';
|
||||
$email = uniqid() . 'new@localhost.test';
|
||||
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/account/email', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]), [
|
||||
'email' => $email,
|
||||
'password' => $password,
|
||||
|
|
@ -394,14 +474,14 @@ class AccountCustomClientTest extends Scope
|
|||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]));
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
|
||||
$userId = $response['body']['$id'] ?? '';
|
||||
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/projects/'.$this->getProject()['$id'].'/oauth2', array_merge([
|
||||
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $this->getProject()['$id'] . '/oauth2', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => 'console',
|
||||
|
|
@ -414,26 +494,26 @@ class AccountCustomClientTest extends Scope
|
|||
|
||||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account/sessions/oauth2/'.$provider, array_merge([
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account/sessions/oauth2/' . $provider, array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]), [
|
||||
'success' => 'http://localhost/v1/mock/tests/general/oauth2/success',
|
||||
'failure' => 'http://localhost/v1/mock/tests/general/oauth2/failure',
|
||||
]);
|
||||
|
||||
$session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_'.$this->getProject()['$id']];
|
||||
$session = $this->client->parseCookie((string)$response['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']];
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals('success', $response['body']['result']);
|
||||
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]));
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
|
|
@ -449,7 +529,7 @@ class AccountCustomClientTest extends Scope
|
|||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]));
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
|
|
@ -458,14 +538,14 @@ class AccountCustomClientTest extends Scope
|
|||
$this->assertGreaterThan(\time() + 14400 - 5, $response['body']['providerAccessTokenExpiry']); // 5 seconds allowed networking delay
|
||||
|
||||
$initialExpiry = $response['body']['providerAccessTokenExpiry'];
|
||||
|
||||
|
||||
sleep(3);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/account/sessions/current', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]));
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
|
|
@ -476,14 +556,15 @@ class AccountCustomClientTest extends Scope
|
|||
return [];
|
||||
}
|
||||
|
||||
public function testGetSessionByID() {
|
||||
public function testGetSessionByID()
|
||||
{
|
||||
$session = $this->testCreateAnonymousAccount();
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account/sessions/current', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]));
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
|
|
@ -491,11 +572,11 @@ class AccountCustomClientTest extends Scope
|
|||
|
||||
$sessionID = $response['body']['$id'];
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account/sessions/'.$sessionID, array_merge([
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account/sessions/' . $sessionID, array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]));
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
|
|
@ -505,7 +586,7 @@ class AccountCustomClientTest extends Scope
|
|||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_'.$this->getProject()['$id'].'=' . $session,
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]));
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 404);
|
||||
|
|
|
|||
|
|
@ -12,49 +12,4 @@ class UsersCustomServerTest extends Scope
|
|||
use UsersBase;
|
||||
use ProjectCustom;
|
||||
use SideServer;
|
||||
|
||||
public function testDeprecatedUsers():array
|
||||
{
|
||||
/**
|
||||
* Test for FAILURE (don't allow recreating account with same custom ID)
|
||||
*/
|
||||
|
||||
// Create user with custom ID 'meldiron'
|
||||
$response = $this->client->call(Client::METHOD_POST, '/users', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'userId' => 'meldiron',
|
||||
'email' => 'matej@appwrite.io',
|
||||
'password' => 'my-superstr0ng-password',
|
||||
'name' => 'Matej Bačo'
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
|
||||
// Delete user with custom ID 'meldiron'
|
||||
$response = $this->client->call(Client::METHOD_DELETE, '/users/meldiron', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(204, $response['headers']['status-code']);
|
||||
|
||||
// Try to create user with custom ID 'meldiron' again, but now it should fail
|
||||
$response1 = $this->client->call(Client::METHOD_POST, '/users', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'userId' => 'meldiron',
|
||||
'email' => 'matej2@appwrite.io',
|
||||
'password' => 'someones-superstr0ng-password',
|
||||
'name' => 'Matej Bačo Second'
|
||||
]);
|
||||
|
||||
$this->assertEquals(409, $response1['headers']['status-code']);
|
||||
$this->assertEquals('Account already exists', $response1['body']['message']);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -101,15 +101,14 @@ class WebhooksCustomClientTest extends Scope
|
|||
$id = $account['body']['$id'];
|
||||
$session = $this->client->parseCookie((string)$accountSession['headers']['set-cookie'])['a_session_' . $this->getProject()['$id']];
|
||||
|
||||
$account = $this->client->call(Client::METHOD_DELETE, '/account', array_merge([
|
||||
$account = $this->client->call(Client::METHOD_PATCH, '/account/status', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]));
|
||||
|
||||
$this->assertEquals($account['headers']['status-code'], 204);
|
||||
$this->assertEmpty($account['body']);
|
||||
$this->assertEquals($account['headers']['status-code'], 200);
|
||||
|
||||
$webhook = $this->getLastRequest();
|
||||
|
||||
|
|
@ -117,9 +116,9 @@ class WebhooksCustomClientTest extends Scope
|
|||
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
|
||||
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
|
||||
$this->assertStringContainsString('users.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('users.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('users.*.update.status', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("users.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("users.{$id}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("users.{$id}.update.status", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], 'not-yet-implemented');
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
|
||||
|
|
|
|||
Loading…
Reference in a new issue