Project transfer only for owners

This commit is contained in:
Matej Bačo
2022-12-30 12:16:31 +01:00
parent 967db09d10
commit ff58b8d402
5 changed files with 120 additions and 55 deletions
+1 -1
View File
@@ -84,7 +84,7 @@ return [
],
Auth::USER_ROLE_OWNER => [
'label' => 'Owner',
'scopes' => \array_merge($member, $admins, []),
'scopes' => \array_merge($member, $admins, [ 'projects.transfer' ]),
],
Auth::USER_ROLE_APPS => [
'label' => 'Applications',
+13
View File
@@ -108,6 +108,19 @@ return [
'optional' => false,
'icon' => '',
],
'project' => [
'key' => 'project',
'name' => 'Project',
'subtitle' => 'The Project service allows you to manage all the projects in your Appwrite server.',
'description' => '',
'controller' => 'api/project.php',
'sdk' => true,
'docs' => true,
'docsUrl' => '',
'tests' => false,
'optional' => false,
'icon' => '',
],
'storage' => [
'key' => 'storage',
'name' => 'Storage',
+52
View File
@@ -0,0 +1,52 @@
<?php
use Appwrite\Event\Delete;
use Appwrite\Extend\Exception;
use Appwrite\Utopia\Response;
use Utopia\App;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Validator\UID;
App::patch('/v1/project/:projectId/team')
->desc('Update Project Team')
->groups(['api', 'project'])
->label('scope', 'projects.transfer')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'project')
->label('sdk.method', 'updateTeam')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT)
->param('projectId', '', new UID(), 'Project unique ID.')
->param('teamId', '', new UID(), 'New Team ID.')
->inject('response')
->inject('user')
->inject('dbForConsole')
->inject('deletes')
->action(function (string $projectId, string $teamId, Response $response, Document $user, Database $dbForConsole, Delete $deletes) {
$project = $dbForConsole->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
$team = $dbForConsole->getDocument('teams', $teamId);
if ($team->isEmpty()) {
throw new Exception(Exception::TEAM_NOT_FOUND);
}
if ($team->getInternalId() === $project->getAttribute('teamInternalId')) {
throw new Exception(Exception::PROJECT_TEAM_ALREADY_MATCHES);
}
$project
->setAttribute('teamId', $team->getId())
->setAttribute('teamInternalId', $team->getInternalId())
;
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project);
$response->dynamic($project, Response::MODEL_PROJECT);
});
-46
View File
@@ -646,52 +646,6 @@ App::delete('/v1/projects/:projectId')
$response->noContent();
});
App::patch('/v1/projects/:projectId/team')
->desc('Update Project Team')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateTeam')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT)
->param('projectId', '', new UID(), 'Project unique ID.')
->param('teamId', '', new UID(), 'New Team ID.')
->inject('response')
->inject('user')
->inject('dbForConsole')
->inject('deletes')
->action(function (string $projectId, string $teamId, Response $response, Document $user, Database $dbForConsole, Delete $deletes) {
// TODO: Must be owner of project
$project = $dbForConsole->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
$team = $dbForConsole->getDocument('teams', $teamId);
if ($team->isEmpty()) {
throw new Exception(Exception::TEAM_NOT_FOUND);
}
if ($team->getInternalId() === $project->getAttribute('teamInternalId')) {
throw new Exception(Exception::PROJECT_TEAM_ALREADY_MATCHES);
}
$project
->setAttribute('teamId', $team->getId())
->setAttribute('teamInternalId', $team->getInternalId())
;
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project);
$response->dynamic($project, Response::MODEL_PROJECT);
});
// Webhooks
App::post('/v1/projects/:projectId/webhooks')
@@ -2749,6 +2749,26 @@ class ProjectsConsoleClientTest extends Scope
$team2Id = $team2['body']['$id'];
$response = $this->client->call(Client::METHOD_GET, "/teams/{$team1Id}/memberships", array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(1, $response['body']['total']);
$membership1Id = $response['body']['memberships'][0]['$id'];
$response = $this->client->call(Client::METHOD_GET, "/teams/{$team2Id}/memberships", array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), []);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(1, $response['body']['total']);
$membership2Id = $response['body']['memberships'][0]['$id'];
// Create project in team 1
$project = $this->client->call(Client::METHOD_POST, '/projects', array_merge([
'content-type' => 'application/json',
@@ -2787,9 +2807,10 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(0, $response['body']['total']);
// Transfer project
$project = $this->client->call(Client::METHOD_PATCH, "/projects/{$projectId}/team", array_merge([
$project = $this->client->call(Client::METHOD_PATCH, "/project/{$projectId}/team", array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-project' => $projectId,
'x-appwrite-mode' => 'admin'
], $this->getHeaders()), [
'teamId' => $team2Id
]);
@@ -2827,31 +2848,56 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(0, $response['body']['total']);
// Test failures
$project = $this->client->call(Client::METHOD_PATCH, "/projects/nonExistingProjectId/team", array_merge([
$project = $this->client->call(Client::METHOD_PATCH, "/project/nonExistingProjectId/team", array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-project' => $projectId,
'x-appwrite-mode' => 'admin'
], $this->getHeaders()), [
'teamId' => $team1Id
]);
$this->assertEquals(404, $project['headers']['status-code']);
$project = $this->client->call(Client::METHOD_PATCH, "/projects/{$projectId}/team", array_merge([
$project = $this->client->call(Client::METHOD_PATCH, "/project/{$projectId}/team", array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-project' => $projectId,
'x-appwrite-mode' => 'admin'
], $this->getHeaders()), [
'teamId' => 'nonExistingTeamId'
]);
$this->assertEquals(404, $project['headers']['status-code']);
$project = $this->client->call(Client::METHOD_PATCH, "/projects/{$projectId}/team", array_merge([
$project = $this->client->call(Client::METHOD_PATCH, "/project/{$projectId}/team", array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-project' => $projectId,
'x-appwrite-mode' => 'admin'
], $this->getHeaders()), [
'teamId' => $team2Id
]);
$this->assertEquals(400, $project['headers']['status-code']);
$project = $this->client->call(Client::METHOD_PATCH, "/teams/{$team2Id}/memberships/{$membership2Id}", array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'roles' => ['member']
]);
$this->assertEquals(200, $project['headers']['status-code']);
$this->assertCount(1, $project['body']['roles']);
$this->assertContains('member', $project['body']['roles']);
$this->assertNotContains('owner', $project['body']['roles']);
$project = $this->client->call(Client::METHOD_PATCH, "/project/{$projectId}/team", array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $projectId,
'x-appwrite-mode' => 'admin'
], $this->getHeaders()), [
'teamId' => $team1Id
]);
$this->assertEquals(401, $project['headers']['status-code']);
}
}