diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index bf708a06f8..81b14b4e14 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -59,201 +59,6 @@ use Utopia\Validator\Assoc; use Utopia\Validator\Boolean; use Utopia\Validator\Text; -Http::post('/v1/teams') - ->desc('Create team') - ->groups(['api', 'teams']) - ->label('event', 'teams.[teamId].create') - ->label('scope', 'teams.write') - ->label('audits.event', 'team.create') - ->label('audits.resource', 'team/{response.$id}') - ->label('sdk', new Method( - namespace: 'teams', - group: 'teams', - name: 'create', - description: '/docs/references/teams/create-team.md', - auth: [AuthType::ADMIN, AuthType::SESSION, AuthType::KEY, AuthType::JWT], - responses: [ - new SDKResponse( - code: Response::STATUS_CODE_CREATED, - 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) - ->inject('response') - ->inject('user') - ->inject('dbForProject') - ->inject('authorization') - ->inject('queueForEvents') - ->action(function (string $teamId, string $name, array $roles, Response $response, Document $user, Database $dbForProject, Authorization $authorization, Event $queueForEvents) { - - $isPrivilegedUser = User::isPrivileged($authorization->getRoles()); - $isAppUser = User::isApp($authorization->getRoles()); - - $teamId = $teamId == 'unique()' ? ID::unique() : $teamId; - - try { - $team = $authorization->skip(fn () => $dbForProject->createDocument('teams', new Document([ - '$id' => $teamId, - '$permissions' => [ - Permission::read(Role::team($teamId)), - Permission::update(Role::team($teamId, 'owner')), - Permission::delete(Role::team($teamId, 'owner')), - ], - 'labels' => [], - 'name' => $name, - 'total' => ($isPrivilegedUser || $isAppUser) ? 0 : 1, - 'prefs' => new \stdClass(), - 'search' => implode(' ', [$teamId, $name]), - ]))); - } catch (Duplicate $th) { - throw new Exception(Exception::TEAM_ALREADY_EXISTS); - } - - if (!$isPrivilegedUser && !$isAppUser) { // Don't add user on server mode - if (!\in_array('owner', $roles)) { - $roles[] = 'owner'; - } - - $membershipId = ID::unique(); - $membership = new Document([ - '$id' => $membershipId, - '$permissions' => [ - Permission::read(Role::user($user->getId())), - Permission::read(Role::team($team->getId())), - Permission::update(Role::user($user->getId())), - Permission::update(Role::team($team->getId(), 'owner')), - Permission::delete(Role::user($user->getId())), - Permission::delete(Role::team($team->getId(), 'owner')), - ], - 'userId' => $user->getId(), - 'userInternalId' => $user->getSequence(), - 'teamId' => $team->getId(), - 'teamInternalId' => $team->getSequence(), - 'roles' => $roles, - 'invited' => DateTime::now(), - 'joined' => DateTime::now(), - 'confirm' => true, - 'secret' => '', - 'search' => implode(' ', [$membershipId, $user->getId()]) - ]); - - $membership = $dbForProject->createDocument('memberships', $membership); - $dbForProject->purgeCachedDocument('users', $user->getId()); - } - - $queueForEvents->setParam('teamId', $team->getId()); - - if (!empty($user->getId())) { - $queueForEvents->setParam('userId', $user->getId()); - } - - $response - ->setStatusCode(Response::STATUS_CODE_CREATED) - ->dynamic($team, Response::MODEL_TEAM); - }); - -Http::get('/v1/teams') - ->desc('List teams') - ->groups(['api', 'teams']) - ->label('scope', 'teams.read') - ->label('sdk', new Method( - namespace: 'teams', - group: 'teams', - name: 'list', - description: '/docs/references/teams/list-teams.md', - auth: [AuthType::ADMIN, AuthType::SESSION, AuthType::KEY, AuthType::JWT], - responses: [ - new SDKResponse( - code: Response::STATUS_CODE_OK, - model: Response::MODEL_TEAM_LIST, - ) - ] - )) - ->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) - ->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true) - ->inject('response') - ->inject('dbForProject') - ->action(function (array $queries, string $search, bool $includeTotal, Response $response, Database $dbForProject) { - - - try { - $queries = Query::parseQueries($queries); - } catch (QueryException $e) { - throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage()); - } - - if (!empty($search)) { - $queries[] = Query::search('search', $search); - } - - $cursor = Query::getCursorQueries($queries, false); - $cursor = \reset($cursor); - - if ($cursor !== false) { - $validator = new Cursor(); - if (!$validator->isValid($cursor)) { - throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); - } - - $teamId = $cursor->getValue(); - $cursorDocument = $dbForProject->getDocument('teams', $teamId); - - if ($cursorDocument->isEmpty()) { - throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Team '{$teamId}' for the 'cursor' value not found."); - } - - $cursor->setValue($cursorDocument); - } - - $filterQueries = Query::groupByType($queries)['filters']; - try { - $results = $dbForProject->find('teams', $queries); - $total = $includeTotal ? $dbForProject->count('teams', $filterQueries, APP_LIMIT_COUNT) : 0; - } catch (OrderException $e) { - throw new Exception(Exception::DATABASE_QUERY_ORDER_NULL, "The order attribute '{$e->getAttribute()}' had a null value. Cursor pagination requires all documents order attribute values are non-null."); - } - - $response->dynamic(new Document([ - 'teams' => $results, - 'total' => $total, - ]), Response::MODEL_TEAM_LIST); - }); - -Http::get('/v1/teams/:teamId') - ->desc('Get team') - ->groups(['api', 'teams']) - ->label('scope', 'teams.read') - ->label('sdk', new Method( - namespace: 'teams', - group: 'teams', - name: 'get', - description: '/docs/references/teams/get-team.md', - auth: [AuthType::ADMIN, AuthType::SESSION, AuthType::KEY, AuthType::JWT], - responses: [ - new SDKResponse( - code: Response::STATUS_CODE_OK, - model: Response::MODEL_TEAM, - ) - ] - )) - ->param('teamId', '', new UID(), 'Team ID.') - ->inject('response') - ->inject('dbForProject') - ->action(function (string $teamId, Response $response, Database $dbForProject) { - - $team = $dbForProject->getDocument('teams', $teamId); - - if ($team->isEmpty()) { - throw new Exception(Exception::TEAM_NOT_FOUND); - } - - $response->dynamic($team, Response::MODEL_TEAM); - }); - Http::get('/v1/teams/:teamId/prefs') ->desc('Get team preferences') ->groups(['api', 'teams']) @@ -293,51 +98,6 @@ Http::get('/v1/teams/:teamId/prefs') $response->dynamic($prefs, Response::MODEL_PREFERENCES); }); -Http::put('/v1/teams/:teamId') - ->desc('Update name') - ->groups(['api', 'teams']) - ->label('event', 'teams.[teamId].update') - ->label('scope', 'teams.write') - ->label('audits.event', 'team.update') - ->label('audits.resource', 'team/{response.$id}') - ->label('sdk', new Method( - namespace: 'teams', - group: 'teams', - name: 'updateName', - description: '/docs/references/teams/update-team-name.md', - auth: [AuthType::ADMIN, AuthType::SESSION, AuthType::KEY, AuthType::JWT], - responses: [ - new SDKResponse( - code: Response::STATUS_CODE_OK, - model: Response::MODEL_TEAM, - ) - ] - )) - ->param('teamId', '', new UID(), 'Team ID.') - ->param('name', null, new Text(128), 'New team name. Max length: 128 chars.') - ->inject('requestTimestamp') - ->inject('response') - ->inject('dbForProject') - ->inject('queueForEvents') - ->action(function (string $teamId, string $name, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Event $queueForEvents) { - - $team = $dbForProject->getDocument('teams', $teamId); - - if ($team->isEmpty()) { - throw new Exception(Exception::TEAM_NOT_FOUND); - } - - $team - ->setAttribute('name', $name) - ->setAttribute('search', implode(' ', [$teamId, $name])); - - $team = $dbForProject->updateDocument('teams', $team->getId(), $team); - - $queueForEvents->setParam('teamId', $team->getId()); - - $response->dynamic($team, Response::MODEL_TEAM); - }); - Http::put('/v1/teams/:teamId/prefs') ->desc('Update preferences') ->groups(['api', 'teams']) @@ -386,70 +146,6 @@ Http::put('/v1/teams/:teamId/prefs') $response->dynamic($prefs, Response::MODEL_PREFERENCES); }); -Http::delete('/v1/teams/:teamId') - ->desc('Delete team') - ->groups(['api', 'teams']) - ->label('event', 'teams.[teamId].delete') - ->label('scope', 'teams.write') - ->label('audits.event', 'team.delete') - ->label('audits.resource', 'team/{request.teamId}') - ->label('sdk', new Method( - namespace: 'teams', - group: 'teams', - name: 'delete', - description: '/docs/references/teams/delete-team.md', - auth: [AuthType::ADMIN, AuthType::SESSION, AuthType::KEY, AuthType::JWT], - responses: [ - new SDKResponse( - code: Response::STATUS_CODE_NOCONTENT, - model: Response::MODEL_NONE, - ) - ], - contentType: ContentType::NONE - )) - ->param('teamId', '', new UID(), 'Team ID.') - ->inject('response') - ->inject('getProjectDB') - ->inject('dbForProject') - ->inject('queueForDeletes') - ->inject('queueForEvents') - ->inject('project') - ->action(function (string $teamId, Response $response, callable $getProjectDB, Database $dbForProject, Delete $queueForDeletes, Event $queueForEvents, Document $project) { - - $team = $dbForProject->getDocument('teams', $teamId); - - if ($team->isEmpty()) { - throw new Exception(Exception::TEAM_NOT_FOUND); - } - - if (!$dbForProject->deleteDocument('teams', $teamId)) { - throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove team from DB'); - } - - // Sync delete - $deletes = new Deletes(); - $deletes->deleteMemberships($getProjectDB, $team, $project); - - // Async delete - if ($project->getId() === 'console') { - $queueForDeletes - ->setType(DELETE_TYPE_TEAM_PROJECTS) - ->setDocument($team) - ->trigger(); - } - - $queueForDeletes - ->setType(DELETE_TYPE_DOCUMENT) - ->setDocument($team); - - $queueForEvents - ->setParam('teamId', $team->getId()) - ->setPayload($response->output($team, Response::MODEL_TEAM)) - ; - - $response->noContent(); - }); - Http::post('/v1/teams/:teamId/memberships') ->desc('Create team membership') ->groups(['api', 'teams', 'auth']) diff --git a/src/Appwrite/Platform/Appwrite.php b/src/Appwrite/Platform/Appwrite.php index 9982b0bf1e..681e1038c3 100644 --- a/src/Appwrite/Platform/Appwrite.php +++ b/src/Appwrite/Platform/Appwrite.php @@ -13,6 +13,7 @@ use Appwrite\Platform\Modules\Projects; use Appwrite\Platform\Modules\Proxy; use Appwrite\Platform\Modules\Sites; use Appwrite\Platform\Modules\Storage; +use Appwrite\Platform\Modules\Teams; use Appwrite\Platform\Modules\Tokens; use Appwrite\Platform\Modules\VCS; use Utopia\Platform\Platform; @@ -31,6 +32,7 @@ class Appwrite extends Platform $this->addModule(new Sites\Module()); $this->addModule(new Console\Module()); $this->addModule(new Proxy\Module()); + $this->addModule(new Teams\Module()); $this->addModule(new Tokens\Module()); $this->addModule(new Storage\Module()); $this->addModule(new VCS\Module()); diff --git a/src/Appwrite/Platform/Modules/Teams/Http/Teams/Create.php b/src/Appwrite/Platform/Modules/Teams/Http/Teams/Create.php new file mode 100644 index 0000000000..85b46d2347 --- /dev/null +++ b/src/Appwrite/Platform/Modules/Teams/Http/Teams/Create.php @@ -0,0 +1,138 @@ +setHttpMethod(Action::HTTP_REQUEST_METHOD_POST) + ->setHttpPath('/v1/teams') + ->desc('Create team') + ->groups(['api', 'teams']) + ->label('event', 'teams.[teamId].create') + ->label('scope', 'teams.write') + ->label('audits.event', 'team.create') + ->label('audits.resource', 'team/{response.$id}') + ->label('sdk', new Method( + namespace: 'teams', + group: 'teams', + name: 'create', + description: '/docs/references/teams/create-team.md', + auth: [AuthType::ADMIN, AuthType::SESSION, AuthType::KEY, AuthType::JWT], + responses: [ + new SDKResponse( + code: Response::STATUS_CODE_CREATED, + 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) + ->inject('response') + ->inject('user') + ->inject('dbForProject') + ->inject('authorization') + ->inject('queueForEvents') + ->callback($this->action(...)); + } + + public function action(string $teamId, string $name, array $roles, Response $response, Document $user, Database $dbForProject, Authorization $authorization, Event $queueForEvents) + { + $isPrivilegedUser = User::isPrivileged($authorization->getRoles()); + $isAppUser = User::isApp($authorization->getRoles()); + + $teamId = $teamId == 'unique()' ? ID::unique() : $teamId; + + try { + $team = $authorization->skip(fn () => $dbForProject->createDocument('teams', new Document([ + '$id' => $teamId, + '$permissions' => [ + Permission::read(Role::team($teamId)), + Permission::update(Role::team($teamId, 'owner')), + Permission::delete(Role::team($teamId, 'owner')), + ], + 'labels' => [], + 'name' => $name, + 'total' => ($isPrivilegedUser || $isAppUser) ? 0 : 1, + 'prefs' => new \stdClass(), + 'search' => implode(' ', [$teamId, $name]), + ]))); + } catch (Duplicate $th) { + throw new Exception(Exception::TEAM_ALREADY_EXISTS); + } + + if (!$isPrivilegedUser && !$isAppUser) { // Don't add user on server mode + if (!\in_array('owner', $roles)) { + $roles[] = 'owner'; + } + + $membershipId = ID::unique(); + $membership = new Document([ + '$id' => $membershipId, + '$permissions' => [ + Permission::read(Role::user($user->getId())), + Permission::read(Role::team($team->getId())), + Permission::update(Role::user($user->getId())), + Permission::update(Role::team($team->getId(), 'owner')), + Permission::delete(Role::user($user->getId())), + Permission::delete(Role::team($team->getId(), 'owner')), + ], + 'userId' => $user->getId(), + 'userInternalId' => $user->getSequence(), + 'teamId' => $team->getId(), + 'teamInternalId' => $team->getSequence(), + 'roles' => $roles, + 'invited' => DateTime::now(), + 'joined' => DateTime::now(), + 'confirm' => true, + 'secret' => '', + 'search' => implode(' ', [$membershipId, $user->getId()]) + ]); + + $membership = $dbForProject->createDocument('memberships', $membership); + $dbForProject->purgeCachedDocument('users', $user->getId()); + } + + $queueForEvents->setParam('teamId', $team->getId()); + + if (!empty($user->getId())) { + $queueForEvents->setParam('userId', $user->getId()); + } + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($team, Response::MODEL_TEAM); + } +} \ No newline at end of file diff --git a/src/Appwrite/Platform/Modules/Teams/Http/Teams/Delete.php b/src/Appwrite/Platform/Modules/Teams/Http/Teams/Delete.php new file mode 100644 index 0000000000..975f04a10c --- /dev/null +++ b/src/Appwrite/Platform/Modules/Teams/Http/Teams/Delete.php @@ -0,0 +1,99 @@ +setHttpMethod(Action::HTTP_REQUEST_METHOD_DELETE) + ->setHttpPath('/v1/teams/:teamId') + ->desc('Delete team') + ->groups(['api', 'teams']) + ->label('event', 'teams.[teamId].delete') + ->label('scope', 'teams.write') + ->label('audits.event', 'team.delete') + ->label('audits.resource', 'team/{request.teamId}') + ->label('sdk', new Method( + namespace: 'teams', + group: 'teams', + name: 'delete', + description: '/docs/references/teams/delete-team.md', + auth: [AuthType::ADMIN, AuthType::SESSION, AuthType::KEY, AuthType::JWT], + responses: [ + new SDKResponse( + code: Response::STATUS_CODE_NOCONTENT, + model: Response::MODEL_NONE, + ) + ], + contentType: ContentType::NONE + )) + ->param('teamId', '', new UID(), 'Team ID.') + ->inject('response') + ->inject('getProjectDB') + ->inject('dbForProject') + ->inject('queueForDeletes') + ->inject('queueForEvents') + ->inject('project') + ->callback($this->action(...)); + } + + public function action(string $teamId, Response $response, callable $getProjectDB, Database $dbForProject, DeleteEvent $queueForDeletes, Event $queueForEvents, Document $project) + { + $team = $dbForProject->getDocument('teams', $teamId); + + if ($team->isEmpty()) { + throw new Exception(Exception::TEAM_NOT_FOUND); + } + + if (!$dbForProject->deleteDocument('teams', $teamId)) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove team from DB'); + } + + // Sync delete + $deletes = new Deletes(); + $deletes->deleteMemberships($getProjectDB, $team, $project); + + // Async delete + if ($project->getId() === 'console') { + $queueForDeletes + ->setType(DELETE_TYPE_TEAM_PROJECTS) + ->setDocument($team) + ->trigger(); + } + + $queueForDeletes + ->setType(DELETE_TYPE_DOCUMENT) + ->setDocument($team); + + $queueForEvents + ->setParam('teamId', $team->getId()) + ->setPayload($response->output($team, Response::MODEL_TEAM)) + ; + + $response->noContent(); + } +} \ No newline at end of file diff --git a/src/Appwrite/Platform/Modules/Teams/Http/Teams/Get.php b/src/Appwrite/Platform/Modules/Teams/Http/Teams/Get.php new file mode 100644 index 0000000000..fbdb36a6ab --- /dev/null +++ b/src/Appwrite/Platform/Modules/Teams/Http/Teams/Get.php @@ -0,0 +1,61 @@ +setHttpMethod(Action::HTTP_REQUEST_METHOD_GET) + ->setHttpPath('/v1/teams/:teamId') + ->desc('Get team') + ->groups(['api', 'teams']) + ->label('scope', 'teams.read') + ->label('sdk', new Method( + namespace: 'teams', + group: 'teams', + name: 'get', + description: '/docs/references/teams/get-team.md', + auth: [AuthType::ADMIN, AuthType::SESSION, AuthType::KEY, AuthType::JWT], + responses: [ + new SDKResponse( + code: Response::STATUS_CODE_OK, + model: Response::MODEL_TEAM, + ) + ] + )) + ->param('teamId', '', new UID(), 'Team ID.') + ->inject('response') + ->inject('dbForProject') + ->callback($this->action(...)); + } + + public function action(string $teamId, Response $response, Database $dbForProject) + { + $team = $dbForProject->getDocument('teams', $teamId); + + if ($team->isEmpty()) { + throw new Exception(Exception::TEAM_NOT_FOUND); + } + + $response->dynamic($team, Response::MODEL_TEAM); + } +} \ No newline at end of file diff --git a/src/Appwrite/Platform/Modules/Teams/Http/Teams/Name/Update.php b/src/Appwrite/Platform/Modules/Teams/Http/Teams/Name/Update.php new file mode 100644 index 0000000000..c895f36458 --- /dev/null +++ b/src/Appwrite/Platform/Modules/Teams/Http/Teams/Name/Update.php @@ -0,0 +1,76 @@ +setHttpMethod(Action::HTTP_REQUEST_METHOD_PUT) + ->setHttpPath('/v1/teams/:teamId') + ->desc('Update name') + ->groups(['api', 'teams']) + ->label('event', 'teams.[teamId].update') + ->label('scope', 'teams.write') + ->label('audits.event', 'team.update') + ->label('audits.resource', 'team/{response.$id}') + ->label('sdk', new Method( + namespace: 'teams', + group: 'teams', + name: 'updateName', + description: '/docs/references/teams/update-team-name.md', + auth: [AuthType::ADMIN, AuthType::SESSION, AuthType::KEY, AuthType::JWT], + responses: [ + new SDKResponse( + code: Response::STATUS_CODE_OK, + model: Response::MODEL_TEAM, + ) + ] + )) + ->param('teamId', '', new UID(), 'Team ID.') + ->param('name', null, new Text(128), 'New team name. Max length: 128 chars.') + ->inject('response') + ->inject('dbForProject') + ->inject('queueForEvents') + ->callback($this->action(...)); + } + + public function action(string $teamId, string $name, Response $response, Database $dbForProject, Event $queueForEvents) + { + $team = $dbForProject->getDocument('teams', $teamId); + + if ($team->isEmpty()) { + throw new Exception(Exception::TEAM_NOT_FOUND); + } + + $team + ->setAttribute('name', $name) + ->setAttribute('search', implode(' ', [$teamId, $name])); + + $team = $dbForProject->updateDocument('teams', $team->getId(), $team); + + $queueForEvents->setParam('teamId', $team->getId()); + + $response->dynamic($team, Response::MODEL_TEAM); + } +} \ No newline at end of file diff --git a/src/Appwrite/Platform/Modules/Teams/Http/Teams/XList.php b/src/Appwrite/Platform/Modules/Teams/Http/Teams/XList.php new file mode 100644 index 0000000000..8fd5e23941 --- /dev/null +++ b/src/Appwrite/Platform/Modules/Teams/Http/Teams/XList.php @@ -0,0 +1,104 @@ +setHttpMethod(Action::HTTP_REQUEST_METHOD_GET) + ->setHttpPath('/v1/teams') + ->desc('List teams') + ->groups(['api', 'teams']) + ->label('scope', 'teams.read') + ->label('sdk', new Method( + namespace: 'teams', + group: 'teams', + name: 'list', + description: '/docs/references/teams/list-teams.md', + auth: [AuthType::ADMIN, AuthType::SESSION, AuthType::KEY, AuthType::JWT], + responses: [ + new SDKResponse( + code: Response::STATUS_CODE_OK, + model: Response::MODEL_TEAM_LIST, + ) + ] + )) + ->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) + ->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true) + ->inject('response') + ->inject('dbForProject') + ->callback($this->action(...)); + } + + public function action(array $queries, string $search, bool $includeTotal, Response $response, Database $dbForProject) + { + try { + $queries = Query::parseQueries($queries); + } catch (QueryException $e) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage()); + } + + if (!empty($search)) { + $queries[] = Query::search('search', $search); + } + + $cursor = Query::getCursorQueries($queries, false); + $cursor = \reset($cursor); + + if ($cursor !== false) { + $validator = new Cursor(); + if (!$validator->isValid($cursor)) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); + } + + $teamId = $cursor->getValue(); + $cursorDocument = $dbForProject->getDocument('teams', $teamId); + + if ($cursorDocument->isEmpty()) { + throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Team '{$teamId}' for the 'cursor' value not found."); + } + + $cursor->setValue($cursorDocument); + } + + $filterQueries = Query::groupByType($queries)['filters']; + try { + $results = $dbForProject->find('teams', $queries); + $total = $includeTotal ? $dbForProject->count('teams', $filterQueries, APP_LIMIT_COUNT) : 0; + } catch (OrderException $e) { + throw new Exception(Exception::DATABASE_QUERY_ORDER_NULL, "The order attribute '{$e->getAttribute()}' had a null value. Cursor pagination requires all documents order attribute values are non-null."); + } + + $response->dynamic(new Document([ + 'teams' => $results, + 'total' => $total, + ]), Response::MODEL_TEAM_LIST); + } +} \ No newline at end of file diff --git a/src/Appwrite/Platform/Modules/Teams/Module.php b/src/Appwrite/Platform/Modules/Teams/Module.php new file mode 100644 index 0000000000..95a3fee0b3 --- /dev/null +++ b/src/Appwrite/Platform/Modules/Teams/Module.php @@ -0,0 +1,14 @@ +addService('http', new Http()); + } +} diff --git a/src/Appwrite/Platform/Modules/Teams/Services/Http.php b/src/Appwrite/Platform/Modules/Teams/Services/Http.php new file mode 100644 index 0000000000..41804c2c83 --- /dev/null +++ b/src/Appwrite/Platform/Modules/Teams/Services/Http.php @@ -0,0 +1,25 @@ +type = Service::TYPE_HTTP; + + // Teams + $this->addAction(CreateTeam::getName(), new CreateTeam()); + $this->addAction(GetTeam::getName(), new GetTeam()); + $this->addAction(ListTeams::getName(), new ListTeams()); + $this->addAction(DeleteTeam::getName(), new DeleteTeam()); + $this->addAction(UpdateTeamName::getName(), new UpdateTeamName()); + } +} \ No newline at end of file