diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 4cb2eb331f..b33fec8cc5 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -59,7 +59,7 @@ App::post('/v1/teams') ->label('sdk.response.model', Response::MODEL_TEAM) ->param('teamId', '', new CustomId(), 'Team ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('name', null, new Text(128), 'Team name. Max length: 128 chars.') - ->param('roles', ['owner'], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.', true) + ->param('roles', ['owner'], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' roles are allowed, each 32 characters long.', true) ->inject('response') ->inject('user') ->inject('dbForProject') @@ -88,8 +88,8 @@ App::post('/v1/teams') throw new Exception(Exception::TEAM_ALREADY_EXISTS); } - if (!$isPrivilegedUser && !$isAppUser) { // Don't add user on server mode - if (!\in_array('owner', $roles)) { + if (! $isPrivilegedUser && ! $isAppUser) { // Don't add user on server mode + if (! \in_array('owner', $roles)) { $roles[] = 'owner'; } @@ -113,7 +113,7 @@ App::post('/v1/teams') 'joined' => DateTime::now(), 'confirm' => true, 'secret' => '', - 'search' => implode(' ', [$membershipId, $user->getId()]) + 'search' => implode(' ', [$membershipId, $user->getId()]), ]); $membership = $dbForProject->createDocument('memberships', $membership); @@ -122,7 +122,7 @@ App::post('/v1/teams') $queueForEvents->setParam('teamId', $team->getId()); - if (!empty($user->getId())) { + if (! empty($user->getId())) { $queueForEvents->setParam('userId', $user->getId()); } @@ -143,7 +143,7 @@ App::get('/v1/teams') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_TEAM_LIST) ->label('sdk.offline.model', '/teams') - ->param('queries', [], new Teams(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Teams::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Teams(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Teams::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') @@ -155,7 +155,7 @@ App::get('/v1/teams') throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage()); } - if (!empty($search)) { + if (! empty($search)) { $queries[] = Query::search('search', $search); } @@ -338,10 +338,12 @@ App::delete('/v1/teams/:teamId') ->label('sdk.response.model', Response::MODEL_NONE) ->param('teamId', '', new UID(), 'Team ID.') ->inject('response') + ->inject('project') ->inject('dbForProject') + ->inject('dbForConsole') ->inject('queueForEvents') ->inject('queueForDeletes') - ->action(function (string $teamId, Response $response, Database $dbForProject, Event $queueForEvents, Delete $queueForDeletes) { + ->action(function (string $teamId, Response $response, Document $project, Database $dbForProject, Database $dbForConsole, Event $queueForEvents, Delete $queueForDeletes) { $team = $dbForProject->getDocument('teams', $teamId); @@ -349,18 +351,39 @@ App::delete('/v1/teams/:teamId') throw new Exception(Exception::TEAM_NOT_FOUND); } - if (!$dbForProject->deleteDocument('teams', $teamId)) { + if (! $dbForProject->deleteDocument('teams', $teamId)) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove team from DB'); } - $queueForDeletes - ->setType(DELETE_TYPE_DOCUMENT) - ->setDocument($team); + $teamInternalId = $team->getInternalId(); + + $this->deleteByGroup( + 'memberships', + [ + Query::equal('teamInternalId', [$teamInternalId]), + ], + $dbForProject, + function (Document $membership) use ($dbForProject) { + $userId = $membership->getAttribute('userId'); + $dbForProject->purgeCachedDocument('users', $userId); + } + ); + + if ($project->getId() === 'console') { + $projects = $dbForConsole->find('projects', [ + Query::equal('teamInternalId', [$teamInternalId]), + ]); + + foreach ($projects as $project) { + $queueForDeletes + ->setType(DELETE_TYPE_DOCUMENT) + ->setDocument($project); + } + } $queueForEvents ->setParam('teamId', $team->getId()) - ->setPayload($response->output($team, Response::MODEL_TEAM)) - ; + ->setPayload($response->output($team, Response::MODEL_TEAM)); $response->noContent(); }); @@ -386,7 +409,7 @@ App::post('/v1/teams/:teamId/memberships') ->param('email', '', new Email(), 'Email of the new team member.', true) ->param('userId', '', new UID(), 'ID of the user to be added to a team.', true) ->param('phone', '', new Phone(), 'Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true) - ->param('roles', [], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.') + ->param('roles', [], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' roles are allowed, each 32 characters long.') ->param('url', '', fn ($clients) => new Host($clients), 'URL to redirect the user back to your app from the invitation email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients']) // TODO add our own built-in confirm page ->param('name', '', new Text(128), 'Name of the new team member. Max length: 128 chars.', true) ->inject('response') @@ -402,7 +425,7 @@ App::post('/v1/teams/:teamId/memberships') $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); if (empty($url)) { - if (!$isAPIKey && !$isPrivilegedUser) { + if (! $isAPIKey && ! $isPrivilegedUser) { throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'URL is required'); } } @@ -413,7 +436,7 @@ App::post('/v1/teams/:teamId/memberships') $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); $isAppUser = Auth::isAppUser(Authorization::getRoles()); - if (!$isPrivilegedUser && !$isAppUser && empty(System::getEnv('_APP_SMTP_HOST'))) { + if (! $isPrivilegedUser && ! $isAppUser && empty(System::getEnv('_APP_SMTP_HOST'))) { throw new Exception(Exception::GENERAL_SMTP_DISABLED); } @@ -424,28 +447,28 @@ App::post('/v1/teams/:teamId/memberships') if ($team->isEmpty()) { throw new Exception(Exception::TEAM_NOT_FOUND); } - if (!empty($userId)) { + if (! empty($userId)) { $invitee = $dbForProject->getDocument('users', $userId); if ($invitee->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND, 'User with given userId doesn\'t exist.', 404); } - if (!empty($email) && $invitee->getAttribute('email', '') !== $email) { + if (! empty($email) && $invitee->getAttribute('email', '') !== $email) { throw new Exception(Exception::USER_ALREADY_EXISTS, 'Given userId and email doesn\'t match', 409); } - if (!empty($phone) && $invitee->getAttribute('phone', '') !== $phone) { + if (! empty($phone) && $invitee->getAttribute('phone', '') !== $phone) { throw new Exception(Exception::USER_ALREADY_EXISTS, 'Given userId and phone doesn\'t match', 409); } $email = $invitee->getAttribute('email', ''); $phone = $invitee->getAttribute('phone', ''); $name = empty($name) ? $invitee->getAttribute('name', '') : $name; - } elseif (!empty($email)) { + } elseif (! empty($email)) { $invitee = $dbForProject->findOne('users', [Query::equal('email', [$email])]); // Get user by email address - if (!empty($invitee) && !empty($phone) && $invitee->getAttribute('phone', '') !== $phone) { + if (! empty($invitee) && ! empty($phone) && $invitee->getAttribute('phone', '') !== $phone) { throw new Exception(Exception::USER_ALREADY_EXISTS, 'Given email and phone doesn\'t match', 409); } - } elseif (!empty($phone)) { + } elseif (! empty($phone)) { $invitee = $dbForProject->findOne('users', [Query::equal('phone', [$phone])]); - if (!empty($invitee) && !empty($email) && $invitee->getAttribute('email', '') !== $email) { + if (! empty($invitee) && ! empty($email) && $invitee->getAttribute('email', '') !== $email) { throw new Exception(Exception::USER_ALREADY_EXISTS, 'Given phone and email doesn\'t match', 409); } } @@ -465,7 +488,7 @@ App::post('/v1/teams/:teamId/memberships') $identityWithMatchingEmail = $dbForProject->findOne('identities', [ Query::equal('providerEmail', [$email]), ]); - if ($identityWithMatchingEmail !== false && !$identityWithMatchingEmail->isEmpty()) { + if ($identityWithMatchingEmail !== false && ! $identityWithMatchingEmail->isEmpty()) { throw new Exception(Exception::USER_EMAIL_ALREADY_EXISTS); } @@ -507,9 +530,9 @@ App::post('/v1/teams/:teamId/memberships') } } - $isOwner = Authorization::isRole('team:' . $team->getId() . '/owner'); + $isOwner = Authorization::isRole('team:'.$team->getId().'/owner'); - if (!$isOwner && !$isPrivilegedUser && !$isAppUser) { // Not owner, not admin, not app (server) + if (! $isOwner && ! $isPrivilegedUser && ! $isAppUser) { // Not owner, not admin, not app (server) throw new Exception(Exception::USER_UNAUTHORIZED, 'User is not allowed to send invitations for this team'); } @@ -534,7 +557,7 @@ App::post('/v1/teams/:teamId/memberships') 'joined' => ($isPrivilegedUser || $isAppUser) ? DateTime::now() : null, 'confirm' => ($isPrivilegedUser || $isAppUser), 'secret' => Auth::hash($secret), - 'search' => implode(' ', [$membershipId, $invitee->getId()]) + 'search' => implode(' ', [$membershipId, $invitee->getId()]), ]); if ($isPrivilegedUser || $isAppUser) { // Allow admin to create membership @@ -557,37 +580,37 @@ App::post('/v1/teams/:teamId/memberships') $url = Template::parseURL($url); $url['query'] = Template::mergeQuery(((isset($url['query'])) ? $url['query'] : ''), ['membershipId' => $membership->getId(), 'userId' => $invitee->getId(), 'secret' => $secret, 'teamId' => $teamId]); $url = Template::unParseURL($url); - if (!empty($email)) { + if (! empty($email)) { $projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]'); - $body = $locale->getText("emails.invitation.body"); - $subject = \sprintf($locale->getText("emails.invitation.subject"), $team->getAttribute('name'), $projectName); - $customTemplate = $project->getAttribute('templates', [])['email.invitation-' . $locale->default] ?? []; + $body = $locale->getText('emails.invitation.body'); + $subject = \sprintf($locale->getText('emails.invitation.subject'), $team->getAttribute('name'), $projectName); + $customTemplate = $project->getAttribute('templates', [])['email.invitation-'.$locale->default] ?? []; - $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/email-inner-base.tpl'); + $message = Template::fromFile(__DIR__.'/../../config/locale/templates/email-inner-base.tpl'); $message ->setParam('{{body}}', $body, escapeHtml: false) - ->setParam('{{hello}}', $locale->getText("emails.invitation.hello")) - ->setParam('{{footer}}', $locale->getText("emails.invitation.footer")) - ->setParam('{{thanks}}', $locale->getText("emails.invitation.thanks")) - ->setParam('{{signature}}', $locale->getText("emails.invitation.signature")); + ->setParam('{{hello}}', $locale->getText('emails.invitation.hello')) + ->setParam('{{footer}}', $locale->getText('emails.invitation.footer')) + ->setParam('{{thanks}}', $locale->getText('emails.invitation.thanks')) + ->setParam('{{signature}}', $locale->getText('emails.invitation.signature')); $body = $message->render(); $smtp = $project->getAttribute('smtp', []); $smtpEnabled = $smtp['enabled'] ?? false; $senderEmail = System::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM); - $senderName = System::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server'); - $replyTo = ""; + $senderName = System::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME.' Server'); + $replyTo = ''; if ($smtpEnabled) { - if (!empty($smtp['senderEmail'])) { + if (! empty($smtp['senderEmail'])) { $senderEmail = $smtp['senderEmail']; } - if (!empty($smtp['senderName'])) { + if (! empty($smtp['senderName'])) { $senderName = $smtp['senderName']; } - if (!empty($smtp['replyTo'])) { + if (! empty($smtp['replyTo'])) { $replyTo = $smtp['replyTo']; } @@ -598,14 +621,14 @@ App::post('/v1/teams/:teamId/memberships') ->setSmtpPassword($smtp['password'] ?? '') ->setSmtpSecure($smtp['secure'] ?? ''); - if (!empty($customTemplate)) { - if (!empty($customTemplate['senderEmail'])) { + if (! empty($customTemplate)) { + if (! empty($customTemplate['senderEmail'])) { $senderEmail = $customTemplate['senderEmail']; } - if (!empty($customTemplate['senderName'])) { + if (! empty($customTemplate['senderName'])) { $senderName = $customTemplate['senderName']; } - if (!empty($customTemplate['replyTo'])) { + if (! empty($customTemplate['replyTo'])) { $replyTo = $customTemplate['replyTo']; } @@ -626,7 +649,7 @@ App::post('/v1/teams/:teamId/memberships') 'user' => $user->getAttribute('name'), 'team' => $team->getAttribute('name'), 'redirect' => $url, - 'project' => $projectName + 'project' => $projectName, ]; $queueForMails @@ -635,17 +658,16 @@ App::post('/v1/teams/:teamId/memberships') ->setRecipient($invitee->getAttribute('email')) ->setName($invitee->getAttribute('name')) ->setVariables($emailVariables) - ->trigger() - ; - } elseif (!empty($phone)) { + ->trigger(); + } elseif (! empty($phone)) { if (empty(System::getEnv('_APP_SMS_PROVIDER'))) { throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured'); } - $message = Template::fromFile(__DIR__ . '/../../config/locale/templates/sms-base.tpl'); + $message = Template::fromFile(__DIR__.'/../../config/locale/templates/sms-base.tpl'); - $customTemplate = $project->getAttribute('templates', [])['sms.invitation-' . $locale->default] ?? []; - if (!empty($customTemplate)) { + $customTemplate = $project->getAttribute('templates', [])['sms.invitation-'.$locale->default] ?? []; + if (! empty($customTemplate)) { $message = $customTemplate['message']; } @@ -669,8 +691,7 @@ App::post('/v1/teams/:teamId/memberships') $queueForEvents ->setParam('teamId', $team->getId()) - ->setParam('membershipId', $membership->getId()) - ; + ->setParam('membershipId', $membership->getId()); $response ->setStatusCode(Response::STATUS_CODE_CREATED) @@ -696,7 +717,7 @@ App::get('/v1/teams/:teamId/memberships') ->label('sdk.response.model', Response::MODEL_MEMBERSHIP_LIST) ->label('sdk.offline.model', '/teams/{teamId}/memberships') ->param('teamId', '', new UID(), 'Team ID.') - ->param('queries', [], new Memberships(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Memberships::ALLOWED_ATTRIBUTES), true) + ->param('queries', [], new Memberships(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' queries are allowed, each '.APP_LIMIT_ARRAY_ELEMENT_SIZE.' characters long. You may filter on the following attributes: '.implode(', ', Memberships::ALLOWED_ATTRIBUTES), true) ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->inject('response') ->inject('dbForProject') @@ -714,7 +735,7 @@ App::get('/v1/teams/:teamId/memberships') throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage()); } - if (!empty($search)) { + if (! empty($search)) { $queries[] = Query::search('search', $search); } @@ -753,7 +774,7 @@ App::get('/v1/teams/:teamId/memberships') max: APP_LIMIT_COUNT ); - $memberships = array_filter($memberships, fn (Document $membership) => !empty($membership->getAttribute('userId'))); + $memberships = array_filter($memberships, fn (Document $membership) => ! empty($membership->getAttribute('userId'))); $memberships = array_map(function ($membership) use ($dbForProject, $team) { $user = $dbForProject->getDocument('users', $membership->getAttribute('userId')); @@ -765,7 +786,7 @@ App::get('/v1/teams/:teamId/memberships') $emailEnabled = $user->getAttribute('email', false) && $user->getAttribute('emailVerification', false); $phoneEnabled = $user->getAttribute('phone', false) && $user->getAttribute('phoneVerification', false); - if (!$totpEnabled && !$emailEnabled && !$phoneEnabled) { + if (! $totpEnabled && ! $emailEnabled && ! $phoneEnabled) { $mfa = false; } } @@ -774,8 +795,7 @@ App::get('/v1/teams/:teamId/memberships') ->setAttribute('mfa', $mfa) ->setAttribute('teamName', $team->getAttribute('name')) ->setAttribute('userName', $user->getAttribute('name')) - ->setAttribute('userEmail', $user->getAttribute('email')) - ; + ->setAttribute('userEmail', $user->getAttribute('email')); return $membership; }, $memberships); @@ -827,7 +847,7 @@ App::get('/v1/teams/:teamId/memberships/:membershipId') $emailEnabled = $user->getAttribute('email', false) && $user->getAttribute('emailVerification', false); $phoneEnabled = $user->getAttribute('phone', false) && $user->getAttribute('phoneVerification', false); - if (!$totpEnabled && !$emailEnabled && !$phoneEnabled) { + if (! $totpEnabled && ! $emailEnabled && ! $phoneEnabled) { $mfa = false; } } @@ -836,8 +856,7 @@ App::get('/v1/teams/:teamId/memberships/:membershipId') ->setAttribute('mfa', $mfa) ->setAttribute('teamName', $team->getAttribute('name')) ->setAttribute('userName', $user->getAttribute('name')) - ->setAttribute('userEmail', $user->getAttribute('email')) - ; + ->setAttribute('userEmail', $user->getAttribute('email')); $response->dynamic($membership, Response::MODEL_MEMBERSHIP); }); @@ -858,7 +877,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') ->label('sdk.response.model', Response::MODEL_MEMBERSHIP) ->param('teamId', '', new UID(), 'Team ID.') ->param('membershipId', '', new UID(), 'Membership ID.') - ->param('roles', [], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings. Use this param to set the user\'s roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.') + ->param('roles', [], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'An array of strings. Use this param to set the user\'s roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of '.APP_LIMIT_ARRAY_PARAMS_SIZE.' roles are allowed, each 32 characters long.') ->inject('request') ->inject('response') ->inject('user') @@ -883,9 +902,9 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') $isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles()); $isAppUser = Auth::isAppUser(Authorization::getRoles()); - $isOwner = Authorization::isRole('team:' . $team->getId() . '/owner'); + $isOwner = Authorization::isRole('team:'.$team->getId().'/owner'); - if (!$isOwner && !$isPrivilegedUser && !$isAppUser) { // Not owner, not admin, not app (server) + if (! $isOwner && ! $isPrivilegedUser && ! $isAppUser) { // Not owner, not admin, not app (server) throw new Exception(Exception::USER_UNAUTHORIZED, 'User is not allowed to modify roles'); } @@ -963,7 +982,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') } if ($userId !== $membership->getAttribute('userId')) { - throw new Exception(Exception::TEAM_INVITE_MISMATCH, 'Invite does not belong to current user (' . $user->getAttribute('email') . ')'); + throw new Exception(Exception::TEAM_INVITE_MISMATCH, 'Invite does not belong to current user ('.$user->getAttribute('email').')'); } if ($user->isEmpty()) { @@ -971,7 +990,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') } if ($membership->getAttribute('userInternalId') !== $user->getInternalId()) { - throw new Exception(Exception::TEAM_INVITE_MISMATCH, 'Invite does not belong to current user (' . $user->getAttribute('email') . ')'); + throw new Exception(Exception::TEAM_INVITE_MISMATCH, 'Invite does not belong to current user ('.$user->getAttribute('email').')'); } if ($membership->getAttribute('confirm') === true) { @@ -980,8 +999,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') $membership // Attach user to team ->setAttribute('joined', DateTime::now()) - ->setAttribute('confirm', true) - ; + ->setAttribute('confirm', true); Authorization::skip(fn () => $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('emailVerification', true))); @@ -1005,7 +1023,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') 'ip' => $request->getIP(), 'factors' => ['email'], 'countryCode' => ($record) ? \strtolower($record['country']['iso_code']) : '--', - 'expire' => DateTime::addSeconds(new \DateTime(), $authDuration) + 'expire' => DateTime::addSeconds(new \DateTime(), $authDuration), ], $detector->getOS(), $detector->getClient(), $detector->getDevice())); $session = $dbForProject->createDocument('sessions', $session @@ -1027,25 +1045,22 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') $queueForEvents ->setParam('teamId', $team->getId()) - ->setParam('membershipId', $membership->getId()) - ; + ->setParam('membershipId', $membership->getId()); - if (!Config::getParam('domainVerification')) { + if (! Config::getParam('domainVerification')) { $response - ->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)])) - ; + ->addHeader('X-Fallback-Cookies', \json_encode([Auth::$cookieName => Auth::encodeSession($user->getId(), $secret)])); } $response - ->addCookie(Auth::$cookieName . '_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, null) - ->addCookie(Auth::$cookieName, Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite')) - ; + ->addCookie(Auth::$cookieName.'_legacy', Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ($protocol == 'https'), true, null) + ->addCookie(Auth::$cookieName, Auth::encodeSession($user->getId(), $secret), (new \DateTime($expire))->getTimestamp(), '/', Config::getParam('cookieDomain'), ($protocol == 'https'), true, Config::getParam('cookieSamesite')); $response->dynamic( $membership - ->setAttribute('teamName', $team->getAttribute('name')) - ->setAttribute('userName', $user->getAttribute('name')) - ->setAttribute('userEmail', $user->getAttribute('email')), + ->setAttribute('teamName', $team->getAttribute('name')) + ->setAttribute('userName', $user->getAttribute('name')) + ->setAttribute('userEmail', $user->getAttribute('email')), Response::MODEL_MEMBERSHIP ); }); @@ -1109,8 +1124,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') $queueForEvents ->setParam('teamId', $team->getId()) ->setParam('membershipId', $membership->getId()) - ->setPayload($response->output($membership, Response::MODEL_MEMBERSHIP)) - ; + ->setPayload($response->output($membership, Response::MODEL_MEMBERSHIP)); $response->noContent(); }); @@ -1151,13 +1165,13 @@ App::get('/v1/teams/:teamId/logs') $offset = $grouped['offset'] ?? 0; $audit = new Audit($dbForProject); - $resource = 'team/' . $team->getId(); + $resource = 'team/'.$team->getId(); $logs = $audit->getLogsByResource($resource, $limit, $offset); $output = []; foreach ($logs as $i => &$log) { - $log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; + $log['userAgent'] = (! empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; $detector = new Detector($log['userAgent']); $detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then) @@ -1185,14 +1199,14 @@ App::get('/v1/teams/:teamId/logs') 'clientEngineVersion' => $client['clientEngineVersion'], 'deviceName' => $device['deviceName'], 'deviceBrand' => $device['deviceBrand'], - 'deviceModel' => $device['deviceModel'] + 'deviceModel' => $device['deviceModel'], ]); $record = $geodb->get($log['ip']); if ($record) { - $output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; - $output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); + $output[$i]['countryCode'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; + $output[$i]['countryName'] = $locale->getText('countries.'.strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); } else { $output[$i]['countryCode'] = '--'; $output[$i]['countryName'] = $locale->getText('locale.country.unknown'); diff --git a/app/init.php b/app/init.php index f69bd323c6..b10355df39 100644 --- a/app/init.php +++ b/app/init.php @@ -167,7 +167,6 @@ const DELETE_TYPE_PROJECTS = 'projects'; const DELETE_TYPE_FUNCTIONS = 'functions'; const DELETE_TYPE_DEPLOYMENTS = 'deployments'; const DELETE_TYPE_USERS = 'users'; -const DELETE_TYPE_TEAMS = 'teams'; const DELETE_TYPE_EXECUTIONS = 'executions'; const DELETE_TYPE_AUDIT = 'audit'; const DELETE_TYPE_ABUSE = 'abuse'; diff --git a/src/Appwrite/Platform/Workers/Deletes.php b/src/Appwrite/Platform/Workers/Deletes.php index 189ef6496b..8e9c4abdd8 100644 --- a/src/Appwrite/Platform/Workers/Deletes.php +++ b/src/Appwrite/Platform/Workers/Deletes.php @@ -93,12 +93,6 @@ class Deletes extends Action case DELETE_TYPE_USERS: $this->deleteUser($getProjectDB, $document, $project); break; - case DELETE_TYPE_TEAMS: - $this->deleteMemberships($getProjectDB, $document, $project); - if ($project->getId() === 'console') { - $this->deleteProjectsByTeam($dbForConsole, $getProjectDB, $deviceForFiles, $deviceForFunctions, $deviceForBuilds, $deviceForCache, $document); - } - break; case DELETE_TYPE_BUCKETS: $this->deleteBucket($getProjectDB, $deviceForFiles, $document, $project); break; @@ -410,53 +404,6 @@ class Deletes extends Action ], $dbForProject); } - /** - * @param callable $getProjectDB - * @param Document $document teams document - * @param Document $project - * @return void - * @throws Exception - */ - private function deleteMemberships(callable $getProjectDB, Document $document, Document $project): void - { - $dbForProject = $getProjectDB($project); - $teamInternalId = $document->getInternalId(); - - // Delete Memberships - $this->deleteByGroup( - 'memberships', - [ - Query::equal('teamInternalId', [$teamInternalId]) - ], - $dbForProject, - function (Document $membership) use ($dbForProject) { - $userId = $membership->getAttribute('userId'); - $dbForProject->purgeCachedDocument('users', $userId); - } - ); - } - - /** - * @param Database $dbForConsole - * @param Document $document - * @return void - * @throws Authorization - * @throws \Utopia\Database\Exception - * @throws Conflict - * @throws Restricted - * @throws Structure - */ - private function deleteProjectsByTeam(Database $dbForConsole, callable $getProjectDB, Device $deviceForFiles, Device $deviceForFunctions, Device $deviceForBuilds, Device $deviceForCache, Document $document): void - { - - $projects = $dbForConsole->find('projects', [ - Query::equal('teamInternalId', [$document->getInternalId()]) - ]); - foreach ($projects as $project) { - $this->deleteProject($dbForConsole, $getProjectDB, $deviceForFiles, $deviceForFunctions, $deviceForBuilds, $deviceForCache, $project); - $dbForConsole->deleteDocument('projects', $project->getId()); - } - } /** * @param Database $dbForConsole