2023-05-22 22:58:13 +12:00
< ? php
use Utopia\App ;
use Appwrite\Event\Build ;
use Appwrite\Event\Delete ;
use Utopia\Database\Database ;
use Utopia\Database\Document ;
use Appwrite\Utopia\Request ;
use Appwrite\Utopia\Response ;
use Utopia\Validator\Text ;
use Utopia\VCS\Adapter\Git\GitHub ;
use Appwrite\Extend\Exception ;
2023-05-26 10:29:08 +12:00
use Appwrite\Network\Validator\Host ;
2023-05-22 22:58:13 +12:00
use Appwrite\Utopia\Database\Validator\Queries\Installations ;
2023-05-28 23:39:48 +12:00
use Appwrite\Vcs\Comment ;
2023-05-22 22:58:13 +12:00
use Utopia\Database\Query ;
2023-05-23 01:02:55 +12:00
use Utopia\Database\ID ;
use Utopia\Database\Permission ;
use Utopia\Database\Role ;
2023-05-22 22:58:13 +12:00
use Utopia\Database\Validator\Authorization ;
App :: get ( '/v1/vcs/github/installations' )
-> desc ( 'Install GitHub App' )
-> groups ([ 'api' , 'vcs' ])
-> label ( 'scope' , 'public' )
-> label ( 'origin' , '*' )
-> label ( 'sdk.auth' , [])
-> label ( 'sdk.namespace' , 'vcs' )
-> label ( 'sdk.method' , 'createGitHubInstallation' )
-> label ( 'sdk.description' , '' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_MOVED_PERMANENTLY )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_HTML )
-> label ( 'sdk.methodType' , 'webAuth' )
2023-05-28 23:39:48 +12:00
-> param ( 'redirect' , '' , fn ( $clients ) => new Host ( $clients ), 'URL to redirect back to your Git authorization. Only console hostnames are allowed.' , true , [ 'clients' ])
2023-05-22 22:58:13 +12:00
-> inject ( 'response' )
-> inject ( 'project' )
2023-05-26 10:29:08 +12:00
-> action ( function ( string $redirect , Response $response , Document $project ) {
2023-05-22 22:58:13 +12:00
$projectId = $project -> getId ();
2023-05-26 10:29:08 +12:00
$state = \json_encode ([
'projectId' => $projectId ,
'redirect' => $redirect
]);
2023-05-22 22:58:13 +12:00
$appName = App :: getEnv ( 'VCS_GITHUB_APP_NAME' );
$response
-> addHeader ( 'Cache-Control' , 'no-store, no-cache, must-revalidate, max-age=0' )
-> addHeader ( 'Pragma' , 'no-cache' )
2023-05-26 10:29:08 +12:00
-> redirect ( " https://github.com/apps/ $appName /installations/new? " . \http_build_query ([
'state' => $state
]));
2023-05-22 22:58:13 +12:00
});
App :: get ( '/v1/vcs/github/incominginstallation' )
-> desc ( 'Capture installation id and state after GitHub App Installation' )
-> groups ([ 'api' , 'vcs' ])
-> label ( 'scope' , 'public' )
2023-05-26 10:29:08 +12:00
-> param ( 'installation_id' , '' , new Text ( 256 ), 'GitHub installation ID' )
-> param ( 'setup_action' , '' , new Text ( 256 ), 'GitHub setup actuon type' )
-> param ( 'state' , '' , new Text ( 2048 ), 'GitHub state. Contains info sent when starting authorization flow.' )
2023-05-26 20:44:08 +12:00
-> inject ( 'gitHub' )
2023-05-22 22:58:13 +12:00
-> inject ( 'request' )
-> inject ( 'response' )
-> inject ( 'dbForConsole' )
2023-05-26 20:44:08 +12:00
-> action ( function ( string $installationId , string $setupAction , string $state , GitHub $github , Request $request , Response $response , Database $dbForConsole ) {
2023-05-26 10:29:08 +12:00
$state = \json_decode ( $state , true );
$projectId = $state [ 'projectId' ] ? ? '' ;
$redirect = $state [ 'redirect' ] ? ? '' ;
if ( empty ( $redirect )) {
$redirect = $request -> getProtocol () . '://' . $request -> getHostname () . " /console/project- $projectId /settings/git-installations " ;
}
2023-05-22 22:58:13 +12:00
2023-06-06 19:50:52 +12:00
// TODO: User cant be used, because we dont know project. Fix it. Then remove skip
$project = Authorization :: skip ( fn () => $dbForConsole -> getDocument ( 'projects' , $projectId ));
2023-05-22 22:58:13 +12:00
if ( $project -> isEmpty ()) {
2023-06-06 19:50:52 +12:00
$response
-> addHeader ( 'Cache-Control' , 'no-store, no-cache, must-revalidate, max-age=0' )
-> addHeader ( 'Pragma' , 'no-cache' )
-> redirect ( $redirect );
2023-05-22 22:58:13 +12:00
}
2023-05-26 10:29:08 +12:00
$privateKey = App :: getEnv ( 'VCS_GITHUB_PRIVATE_KEY' );
$githubAppId = App :: getEnv ( 'VCS_GITHUB_APP_ID' );
$github -> initialiseVariables ( $installationId , $privateKey , $githubAppId );
$owner = $github -> getOwnerName ( $installationId );
2023-05-22 22:58:13 +12:00
$projectInternalId = $project -> getInternalId ();
$vcsInstallation = $dbForConsole -> findOne ( 'vcs_installations' , [
Query :: equal ( 'installationId' , [ $installationId ]),
Query :: equal ( 'projectInternalId' , [ $projectInternalId ])
]);
2023-05-23 16:37:25 +12:00
if ( $vcsInstallation === false || $vcsInstallation -> isEmpty ()) {
2023-05-22 22:58:13 +12:00
$vcsInstallation = new Document ([
'$id' => ID :: unique (),
'$permissions' => [
Permission :: read ( Role :: any ()),
Permission :: update ( Role :: any ()),
Permission :: delete ( Role :: any ()),
],
'installationId' => $installationId ,
2023-05-26 10:29:08 +12:00
'projectId' => $projectId ,
2023-05-22 22:58:13 +12:00
'projectInternalId' => $projectInternalId ,
'provider' => 'GitHub' ,
2023-05-26 10:29:08 +12:00
'organization' => $owner ,
2023-05-22 22:58:13 +12:00
'accessToken' => null
]);
$vcsInstallation = $dbForConsole -> createDocument ( 'vcs_installations' , $vcsInstallation );
} else {
2023-05-26 10:29:08 +12:00
$vcsInstallation = $vcsInstallation -> setAttribute ( 'organization' , $owner );
2023-05-22 22:58:13 +12:00
$vcsInstallation = $dbForConsole -> updateDocument ( 'vcs_installations' , $vcsInstallation -> getId (), $vcsInstallation );
}
$response
-> addHeader ( 'Cache-Control' , 'no-store, no-cache, must-revalidate, max-age=0' )
-> addHeader ( 'Pragma' , 'no-cache' )
2023-05-26 10:29:08 +12:00
-> redirect ( $redirect );
2023-05-22 22:58:13 +12:00
});
App :: get ( 'v1/vcs/github/installations/:installationId/repositories' )
-> desc ( 'List repositories' )
-> groups ([ 'api' , 'vcs' ])
-> label ( 'scope' , 'public' )
-> label ( 'sdk.namespace' , 'vcs' )
-> label ( 'sdk.method' , 'listRepositories' )
-> label ( 'sdk.description' , '' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_REPOSITORY_LIST )
-> param ( 'installationId' , '' , new Text ( 256 ), 'Installation Id' )
-> param ( 'search' , '' , new Text ( 256 ), 'Search term to filter your list results. Max length: 256 chars.' , true )
2023-05-26 20:44:08 +12:00
-> inject ( 'gitHub' )
2023-05-22 22:58:13 +12:00
-> inject ( 'response' )
-> inject ( 'project' )
-> inject ( 'dbForConsole' )
2023-05-26 20:44:08 +12:00
-> action ( function ( string $vcsInstallationId , string $search , GitHub $github , Response $response , Document $project , Database $dbForConsole ) {
2023-05-22 22:58:13 +12:00
if ( empty ( $search )) {
$search = " " ;
}
$installation = $dbForConsole -> getDocument ( 'vcs_installations' , $vcsInstallationId , [
Query :: equal ( 'projectInternalId' , [ $project -> getInternalId ()])
]);
if ( $installation -> isEmpty ()) {
throw new Exception ( Exception :: INSTALLATION_NOT_FOUND );
}
$installationId = $installation -> getAttribute ( 'installationId' );
$privateKey = App :: getEnv ( 'VCS_GITHUB_PRIVATE_KEY' );
$githubAppId = App :: getEnv ( 'VCS_GITHUB_APP_ID' );
$github -> initialiseVariables ( $installationId , $privateKey , $githubAppId );
$page = 1 ;
$per_page = 100 ; // max limit of GitHub API
$repos = []; // Array to store all repositories
do {
$repositories = $github -> listRepositoriesForGitHubApp ( $page , $per_page );
$repos = array_merge ( $repos , $repositories );
$page ++ ;
2023-05-26 10:29:08 +12:00
} while ( \count ( $repositories ) === $per_page );
2023-05-22 22:58:13 +12:00
// Filter repositories based on search parameter
if ( ! empty ( $search )) {
$repos = array_filter ( $repos , function ( $repo ) use ( $search ) {
$repoName = strtolower ( $repo [ 'name' ]);
$searchTerm = strtolower ( $search );
return strpos ( $repoName , $searchTerm ) !== false ;
});
}
// Sort repositories by last modified date in descending order
usort ( $repos , function ( $repo1 , $repo2 ) {
return strtotime ( $repo2 [ 'pushed_at' ]) - strtotime ( $repo1 [ 'pushed_at' ]);
});
// Limit the maximum results to 5
$repos = array_slice ( $repos , 0 , 5 );
2023-05-27 23:55:34 +12:00
$repos = \array_map ( function ( $repo ) {
$repo [ 'id' ] = \strval ( $repo [ 'id' ]);
return new Document ( $repo );
}, $repos );
2023-05-22 22:58:13 +12:00
$response -> dynamic ( new Document ([
'repositories' => $repos ,
'total' => \count ( $repos ),
]), Response :: MODEL_REPOSITORY_LIST );
});
2023-05-26 10:29:08 +12:00
App :: get ( 'v1/vcs/github/installations/:installationId/repositories/:repositoryId/branches' )
-> desc ( 'List Repository Branches' )
-> groups ([ 'api' , 'vcs' ])
-> label ( 'scope' , 'public' )
-> label ( 'sdk.namespace' , 'vcs' )
-> label ( 'sdk.method' , 'listRepositoryBranches' )
-> label ( 'sdk.description' , '' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_BRANCH_LIST )
-> param ( 'installationId' , '' , new Text ( 256 ), 'Installation Id' )
-> param ( 'repositoryId' , '' , new Text ( 256 ), 'Repository Id' )
2023-05-26 20:44:08 +12:00
-> inject ( 'gitHub' )
2023-05-26 10:29:08 +12:00
-> inject ( 'response' )
-> inject ( 'project' )
-> inject ( 'dbForConsole' )
2023-05-26 20:44:08 +12:00
-> action ( function ( string $vcsInstallationId , string $repositoryId , GitHub $github , Response $response , Document $project , Database $dbForConsole ) {
2023-05-26 10:29:08 +12:00
$installation = $dbForConsole -> getDocument ( 'vcs_installations' , $vcsInstallationId , [
Query :: equal ( 'projectInternalId' , [ $project -> getInternalId ()])
]);
if ( $installation -> isEmpty ()) {
throw new Exception ( Exception :: INSTALLATION_NOT_FOUND );
}
$installationId = $installation -> getAttribute ( 'installationId' );
$privateKey = App :: getEnv ( 'VCS_GITHUB_PRIVATE_KEY' );
$githubAppId = App :: getEnv ( 'VCS_GITHUB_APP_ID' );
$github -> initialiseVariables ( $installationId , $privateKey , $githubAppId );
$owner = $github -> getOwnerName ( $installationId );
$repoName = $github -> getRepositoryName ( $repositoryId );
$branches = $github -> listBranches ( $owner , $repoName );
$response -> dynamic ( new Document ([
'branches' => \array_map ( function ( $branch ) {
2023-05-28 23:39:48 +12:00
return [ 'name' => $branch ];
2023-05-26 10:29:08 +12:00
}, $branches ),
'total' => \count ( $branches ),
]), Response :: MODEL_BRANCH_LIST );
});
2023-05-29 23:51:03 +12:00
$createGitDeployments = function ( GitHub $github , string $installationId , array $vcsRepos , string $branchName , string $SHA , string $commentId , Database $dbForConsole , callable $getProjectDB , Request $request ) {
2023-05-25 17:30:52 +12:00
foreach ( $vcsRepos as $resource ) {
$resourceType = $resource -> getAttribute ( 'resourceType' );
if ( $resourceType === " function " ) {
$projectId = $resource -> getAttribute ( 'projectId' );
$project = Authorization :: skip ( fn () => $dbForConsole -> getDocument ( 'projects' , $projectId ));
$dbForProject = $getProjectDB ( $project );
$functionId = $resource -> getAttribute ( 'resourceId' );
$deploymentId = ID :: unique ();
$vcsRepoId = $resource -> getId ();
$vcsRepoInternalId = $resource -> getInternalId ();
$vcsInstallationId = $resource -> getAttribute ( 'vcsInstallationId' );
$vcsInstallationInternalId = $resource -> getAttribute ( 'vcsInstallationInternalId' );
$productionBranch = $resource -> getAttribute ( 'branch' , 'main' );
$activate = false ;
if ( $branchName == $productionBranch ) {
$activate = true ;
}
2023-05-29 23:51:03 +12:00
$latestDeployment = Authorization :: skip ( fn () => $dbForProject -> findOne ( 'deployments' , [
Query :: equal ( 'vcsRepositoryId' , [ $vcsRepoId ]),
Query :: equal ( 'branch' , [ $branchName ]),
Query :: equal ( 'resourceType' , [ 'functions' ]),
Query :: orderDesc ( '$createdAt' ),
]));
$latestCommentId = $commentId ? ? '' ;
if ( empty ( $latestCommentId )) {
// Empty comment ID is push event. We try to take ID from last deplyoment
2023-05-28 23:39:48 +12:00
if ( $latestDeployment !== false && ! $latestDeployment -> isEmpty ()) {
2023-05-29 23:51:03 +12:00
$latestCommentId = $latestDeployment -> getAttribute ( 'vcsCommentId' , '' );
}
} else {
// Known comment ID is pull request event. If deployment exists already, we skip
if ( $latestDeployment !== false && ! $latestDeployment -> isEmpty ()) {
$latestDeployment -> setAttribute ( 'vcsCommentId' , $latestCommentId );
Authorization :: skip ( fn () => $dbForProject -> updateDocument ( 'deployments' , $latestDeployment -> getId (), $latestDeployment ));
continue ;
2023-05-28 23:39:48 +12:00
}
}
2023-05-29 23:51:03 +12:00
$function = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'functions' , $functionId ));
2023-05-25 17:30:52 +12:00
$deployment = $dbForProject -> createDocument ( 'deployments' , new Document ([
'$id' => $deploymentId ,
'$permissions' => [
Permission :: read ( Role :: any ()),
Permission :: update ( Role :: any ()),
Permission :: delete ( Role :: any ()),
],
'resourceId' => $functionId ,
'resourceType' => 'functions' ,
'entrypoint' => $function -> getAttribute ( 'entrypoint' ),
'installCommand' => $function -> getAttribute ( 'installCommand' ),
'buildCommand' => $function -> getAttribute ( 'buildCommand' ),
'type' => 'vcs' ,
'vcsInstallationId' => $vcsInstallationId ,
'vcsInstallationInternalId' => $vcsInstallationInternalId ,
2023-05-26 10:29:08 +12:00
'vcsRepositoryId' => $vcsRepoId ,
'vcsRepositoryInternalId' => $vcsRepoInternalId ,
2023-05-29 23:51:03 +12:00
'vcsCommentId' => $latestCommentId ,
2023-05-25 17:30:52 +12:00
'branch' => $branchName ,
'search' => implode ( ' ' , [ $deploymentId , $function -> getAttribute ( 'entrypoint' )]),
'activate' => $activate ,
]));
// TODO: Figure out port
$targetUrl = $request -> getProtocol () . '://' . $request -> getHostname () . " :3000/console/project- $projectId /functions/function- $functionId " ;
2023-05-29 23:51:03 +12:00
if ( ! empty ( $SHA )) {
$functionName = $function -> getAttribute ( 'name' );
$projectName = $project -> getAttribute ( 'name' );
$name = " { $functionName } ( { $projectName } ) " ;
$message = 'Starting...' ;
$repositoryId = $resource -> getAttribute ( 'repositoryId' );
$repositoryName = $github -> getRepositoryName ( $repositoryId );
$owner = $github -> getOwnerName ( $installationId );
$github -> updateCommitStatus ( $repositoryName , $SHA , $owner , 'pending' , $message , $targetUrl , $name );
}
2023-05-25 17:30:52 +12:00
$buildEvent = new Build ();
$buildEvent
-> setType ( BUILD_TYPE_DEPLOYMENT )
-> setResource ( $function )
-> setDeployment ( $deployment )
-> setTargetUrl ( $targetUrl )
-> setSHA ( $SHA )
-> setProject ( $project )
-> trigger ();
//TODO: Add event?
}
}
};
2023-05-22 22:58:13 +12:00
App :: post ( '/v1/vcs/github/incomingwebhook' )
-> desc ( 'Captures GitHub Webhook Events' )
-> groups ([ 'api' , 'vcs' ])
-> label ( 'scope' , 'public' )
2023-05-26 20:44:08 +12:00
-> inject ( 'gitHub' )
2023-05-22 22:58:13 +12:00
-> inject ( 'request' )
-> inject ( 'response' )
-> inject ( 'dbForConsole' )
2023-05-23 16:37:25 +12:00
-> inject ( 'getProjectDB' )
2023-05-22 22:58:13 +12:00
-> action (
2023-05-26 20:44:08 +12:00
function ( GitHub $github , Request $request , Response $response , Database $dbForConsole , callable $getProjectDB ) use ( $createGitDeployments ) {
2023-05-22 22:58:13 +12:00
$event = $request -> getHeader ( 'x-github-event' , '' );
$payload = $request -> getRawPayload ();
$privateKey = App :: getEnv ( 'VCS_GITHUB_PRIVATE_KEY' );
$githubAppId = App :: getEnv ( 'VCS_GITHUB_APP_ID' );
$parsedPayload = $github -> parseWebhookEventPayload ( $event , $payload );
if ( $event == $github :: EVENT_PUSH ) {
$branchName = $parsedPayload [ " branch " ];
$repositoryId = $parsedPayload [ " repositoryId " ];
$installationId = $parsedPayload [ " installationId " ];
$SHA = $parsedPayload [ " SHA " ];
$owner = $parsedPayload [ " owner " ];
2023-05-29 23:51:03 +12:00
$github -> initialiseVariables ( $installationId , $privateKey , $githubAppId );
2023-05-22 22:58:13 +12:00
//find functionId from functions table
2023-05-25 17:30:52 +12:00
$vcsRepos = $dbForConsole -> find ( 'vcs_repos' , [
2023-05-22 22:58:13 +12:00
Query :: equal ( 'repositoryId' , [ $repositoryId ]),
Query :: limit ( 100 ),
]);
2023-05-29 23:51:03 +12:00
$createGitDeployments ( $github , $installationId , $vcsRepos , $branchName , $SHA , '' , $dbForConsole , $getProjectDB , $request );
2023-05-22 22:58:13 +12:00
} elseif ( $event == $github :: EVENT_INSTALLATION ) {
if ( $parsedPayload [ " action " ] == " deleted " ) {
2023-05-26 10:29:08 +12:00
// TODO: Use worker for this job instead (update function as well)
2023-05-22 22:58:13 +12:00
$installationId = $parsedPayload [ " installationId " ];
$vcsInstallations = $dbForConsole -> find ( 'vcs_installations' , [
Query :: equal ( 'installationId' , [ $installationId ]),
Query :: limit ( 1000 )
]);
foreach ( $vcsInstallations as $installation ) {
$vcsRepos = $dbForConsole -> find ( 'vcs_repos' , [
Query :: equal ( 'vcsInstallationId' , [ $installation -> getId ()]),
Query :: limit ( 1000 )
]);
foreach ( $vcsRepos as $repo ) {
$dbForConsole -> deleteDocument ( 'vcs_repos' , $repo -> getId ());
}
$dbForConsole -> deleteDocument ( 'vcs_installations' , $installation -> getId ());
}
}
} elseif ( $event == $github :: EVENT_PULL_REQUEST ) {
if ( $parsedPayload [ " action " ] == " opened " or $parsedPayload [ " action " ] == " reopened " ) {
$branchName = $parsedPayload [ " branch " ];
$repositoryId = $parsedPayload [ " repositoryId " ];
$installationId = $parsedPayload [ " installationId " ];
$pullRequestNumber = $parsedPayload [ " pullRequestNumber " ];
$repositoryName = $parsedPayload [ " repositoryName " ];
$owner = $parsedPayload [ " owner " ];
2023-05-29 23:51:03 +12:00
2023-05-22 22:58:13 +12:00
$github -> initialiseVariables ( $installationId , $privateKey , $githubAppId );
$vcsRepos = $dbForConsole -> find ( 'vcs_repos' , [
Query :: equal ( 'repositoryId' , [ $repositoryId ]),
Query :: orderDesc ( '$createdAt' )
]);
2023-05-28 23:39:48 +12:00
if ( \count ( $vcsRepos ) !== 0 ) {
$comment = new Comment ();
foreach ( $vcsRepos as $vcsRepo ) {
$projectId = $vcsRepo -> getAttribute ( 'projectId' );
$project = Authorization :: skip ( fn () => $dbForConsole -> getDocument ( 'projects' , $projectId ));
$dbForProject = $getProjectDB ( $project );
$vcsRepoId = $vcsRepo -> getId ();
$deployment = Authorization :: skip ( fn () => $dbForProject -> findOne ( 'deployments' , [
Query :: equal ( 'vcsRepositoryId' , [ $vcsRepoId ]),
Query :: equal ( 'branch' , [ $branchName ]),
Query :: equal ( 'resourceType' , [ 'functions' ]),
Query :: orderDesc ( '$createdAt' ),
]));
if ( ! $deployment || $deployment -> isEmpty ()) {
$function = Authorization :: skip ( fn () => $dbForProject -> findOne ( 'functions' , [
Query :: equal ( 'vcsRepositoryId' , [ $vcsRepoId ]),
Query :: orderDesc ( '$createdAt' ),
]));
$build = new Document ([]);
} else {
$function = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'functions' , $deployment -> getAttribute ( 'resourceId' , '' )));
$build = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'builds' , $deployment -> getAttribute ( 'buildId' , '' )));
}
if ( ! $function || $function -> isEmpty ()) {
continue ;
}
$status = ! $build || $build -> isEmpty () ? 'waiting' : $build -> getAttribute ( 'status' , 'waiting' );
$deploymentId = ! $build || $build -> isEmpty () ? '' : $build -> getAttribute ( 'deploymentId' , '' );
$comment -> addBuild ( $project , $function , $status , $deploymentId );
}
$commentId = '' ;
if ( ! $comment -> isEmpty ()) {
$commentId = $github -> createComment ( $owner , $repositoryName , $pullRequestNumber , $comment -> generateComment ());
}
2023-05-25 17:30:52 +12:00
2023-05-29 23:51:03 +12:00
$createGitDeployments ( $github , $installationId , $vcsRepos , $branchName , '' , $commentId , $dbForConsole , $getProjectDB , $request );
2023-05-22 22:58:13 +12:00
}
}
}
$response -> json ( $parsedPayload );
}
);
App :: get ( '/v1/vcs/installations' )
-> groups ([ 'api' , 'vcs' ])
-> desc ( 'List installations' )
-> label ( 'scope' , 'public' )
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'vcs' )
-> label ( 'sdk.method' , 'listInstallations' )
-> label ( 'sdk.description' , '/docs/references/vcs/list-installations.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_INSTALLATION_LIST )
-> param ( 'queries' , [], new Installations (), '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 ( ', ' , Installations :: ALLOWED_ATTRIBUTES ), true )
-> param ( 'search' , '' , new Text ( 256 ), 'Search term to filter your list results. Max length: 256 chars.' , true )
-> inject ( 'response' )
-> inject ( 'project' )
2023-06-06 19:50:52 +12:00
-> inject ( 'dbForProject' )
2023-05-22 22:58:13 +12:00
-> inject ( 'dbForConsole' )
2023-06-06 19:50:52 +12:00
-> action ( function ( array $queries , string $search , Response $response , Document $project , Database $dbForProject , Database $dbForConsole ) {
2023-05-22 22:58:13 +12:00
$queries = Query :: parseQueries ( $queries );
$queries [] = Query :: equal ( 'projectInternalId' , [ $project -> getInternalId ()]);
if ( ! empty ( $search )) {
$queries [] = Query :: search ( 'search' , $search );
}
// Get cursor document if there was a cursor query
$cursor = Query :: getByType ( $queries , Query :: TYPE_CURSORAFTER , Query :: TYPE_CURSORBEFORE );
$cursor = reset ( $cursor );
if ( $cursor ) {
/** @var Query $cursor */
$vcsInstallationId = $cursor -> getValue ();
$cursorDocument = $dbForConsole -> getDocument ( 'vcs_installations' , $vcsInstallationId );
if ( $cursorDocument -> isEmpty ()) {
throw new Exception ( Exception :: GENERAL_CURSOR_NOT_FOUND , " Installation ' { $vcsInstallationId } ' for the 'cursor' value not found. " );
}
$cursor -> setValue ( $cursorDocument );
}
$filterQueries = Query :: groupByType ( $queries )[ 'filters' ];
2023-06-06 19:50:52 +12:00
$results = $dbForConsole -> find ( 'vcs_installations' , $queries );
$total = $dbForConsole -> count ( 'vcs_installations' , $filterQueries , APP_LIMIT_COUNT );
if ( \count ( $results ) > 0 ) {
$installationIds = \array_map ( fn ( $result ) => $result -> getId (), $results );
$functions = Authorization :: skip ( fn () => $dbForProject -> find ( 'functions' , [
Query :: equal ( 'vcsInstallationId' , \array_unique ( $installationIds )),
Query :: limit ( APP_LIMIT_SUBQUERY )
]));
foreach ( $results as $result ) {
$installationFunctions = \array_filter ( $functions , fn ( $function ) => $function -> getAttribute ( 'vcsInstallationId' ) === $result -> getId ());
$result -> setAttribute ( 'functions' , $installationFunctions );
}
}
2023-05-22 22:58:13 +12:00
$response -> dynamic ( new Document ([
2023-06-06 19:50:52 +12:00
'installations' => $results ,
'total' => $total ,
2023-05-22 22:58:13 +12:00
]), Response :: MODEL_INSTALLATION_LIST );
});
App :: delete ( '/v1/vcs/installations/:installationId' )
-> groups ([ 'api' , 'vcs' ])
-> desc ( 'Delete Installation' )
-> label ( 'scope' , 'public' )
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'vcs' )
-> label ( 'sdk.method' , 'deleteInstallation' )
-> label ( 'sdk.description' , '/docs/references/vcs/delete-installation.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_NOCONTENT )
-> label ( 'sdk.response.model' , Response :: MODEL_NONE )
-> param ( 'installationId' , '' , new Text ( 256 ), 'Installation Id' )
-> inject ( 'response' )
-> inject ( 'project' )
-> inject ( 'dbForConsole' )
-> inject ( 'deletes' )
-> action ( function ( string $vcsInstallationId , Response $response , Document $project , Database $dbForConsole , Delete $deletes ) {
$installation = $dbForConsole -> getDocument ( 'vcs_installations' , $vcsInstallationId , [
Query :: equal ( 'projectInternalId' , [ $project -> getInternalId ()])
]);
if ( $installation -> isEmpty ()) {
throw new Exception ( Exception :: INSTALLATION_NOT_FOUND );
}
if ( ! $dbForConsole -> deleteDocument ( 'vcs_installations' , $installation -> getId ())) {
throw new Exception ( Exception :: GENERAL_SERVER_ERROR , 'Failed to remove installation from DB' );
}
$deletes
-> setType ( DELETE_TYPE_DOCUMENT )
-> setDocument ( $installation );
$response -> noContent ();
});