2019-12-14 19:33:29 +00:00
< ? php
2024-05-29 08:57:25 +00:00
use Ahc\Jwt\JWT ;
2020-03-24 17:56:32 +00:00
use Appwrite\Auth\Auth ;
2024-02-11 14:51:19 +00:00
use Appwrite\Auth\Validator\MockNumber ;
2022-05-08 15:25:01 +00:00
use Appwrite\Event\Delete ;
2023-12-19 15:08:09 +00:00
use Appwrite\Event\Mail ;
2022-04-04 06:30:07 +00:00
use Appwrite\Event\Validator\Event ;
2023-08-23 02:04:36 +00:00
use Appwrite\Extend\Exception ;
2024-02-06 11:07:47 +00:00
use Appwrite\Hooks\Hooks ;
2025-04-14 11:56:42 +00:00
use Appwrite\Network\Platform ;
2023-08-23 02:04:36 +00:00
use Appwrite\Network\Validator\Email ;
2025-01-17 04:31:39 +00:00
use Appwrite\SDK\AuthType ;
use Appwrite\SDK\ContentType ;
use Appwrite\SDK\Method ;
use Appwrite\SDK\Response as SDKResponse ;
2023-08-23 02:04:36 +00:00
use Appwrite\Template\Template ;
2023-06-23 23:07:58 +00:00
use Appwrite\Utopia\Database\Validator\ProjectId ;
2023-08-23 02:04:36 +00:00
use Appwrite\Utopia\Database\Validator\Queries\Projects ;
2024-06-07 00:54:51 +00:00
use Appwrite\Utopia\Request ;
2020-08-14 21:56:50 +00:00
use Appwrite\Utopia\Response ;
2023-08-23 02:04:36 +00:00
use PHPMailer\PHPMailer\PHPMailer ;
2024-10-08 07:54:40 +00:00
use Utopia\App ;
2021-08-16 13:27:15 +00:00
use Utopia\Audit\Audit ;
2023-08-23 02:04:36 +00:00
use Utopia\Cache\Cache ;
2021-06-07 05:17:29 +00:00
use Utopia\Config\Config ;
2025-05-14 06:14:07 +00:00
use Utopia\Database\Adapter\Pool as DatabasePool ;
2021-08-16 13:27:15 +00:00
use Utopia\Database\Database ;
2024-07-16 01:08:21 +00:00
use Utopia\Database\DateTime ;
2021-05-15 22:41:42 +00:00
use Utopia\Database\Document ;
2023-08-04 19:15:32 +00:00
use Utopia\Database\Exception\Duplicate ;
2025-04-16 12:23:39 +00:00
use Utopia\Database\Exception\Order as OrderException ;
2024-02-12 16:02:04 +00:00
use Utopia\Database\Exception\Query as QueryException ;
2022-12-14 15:42:25 +00:00
use Utopia\Database\Helpers\ID ;
2022-12-14 16:04:06 +00:00
use Utopia\Database\Helpers\Permission ;
use Utopia\Database\Helpers\Role ;
2023-08-23 02:04:36 +00:00
use Utopia\Database\Query ;
2023-03-01 12:00:36 +00:00
use Utopia\Database\Validator\Datetime as DatetimeValidator ;
2024-10-17 05:41:24 +00:00
use Utopia\Database\Validator\Query\Cursor ;
2021-05-15 22:41:42 +00:00
use Utopia\Database\Validator\UID ;
2023-12-28 09:46:08 +00:00
use Utopia\Domains\Validator\PublicDomain ;
2024-05-06 05:33:36 +00:00
use Utopia\DSN\DSN ;
2024-03-08 12:57:20 +00:00
use Utopia\Locale\Locale ;
2024-10-08 07:54:40 +00:00
use Utopia\Pools\Group ;
2024-04-01 11:08:46 +00:00
use Utopia\System\System ;
2024-10-08 07:54:40 +00:00
use Utopia\Validator\ArrayList ;
use Utopia\Validator\Boolean ;
use Utopia\Validator\Hostname ;
use Utopia\Validator\Integer ;
use Utopia\Validator\Multiple ;
use Utopia\Validator\Range ;
use Utopia\Validator\Text ;
use Utopia\Validator\URL ;
use Utopia\Validator\WhiteList ;
App :: init ()
2022-07-22 06:00:42 +00:00
-> groups ([ 'projects' ])
2022-08-02 01:10:48 +00:00
-> inject ( 'project' )
2022-07-22 06:00:42 +00:00
-> action ( function ( Document $project ) {
if ( $project -> getId () !== 'console' ) {
2022-08-08 14:03:01 +00:00
throw new Exception ( Exception :: GENERAL_ACCESS_FORBIDDEN );
2022-07-22 06:00:42 +00:00
}
});
2021-07-31 21:36:18 +00:00
2024-10-08 07:54:40 +00:00
App :: post ( '/v1/projects' )
2023-08-01 15:26:48 +00:00
-> desc ( 'Create project' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'projects' ])
2024-07-22 08:03:53 +00:00
-> label ( 'audits.event' , 'projects.create' )
2024-12-02 09:47:17 +00:00
-> label ( 'audits.resource' , 'project/{response.$id}' )
2020-01-31 22:34:07 +00:00
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'projects' ,
2025-01-17 04:31:39 +00:00
name : 'create' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/create.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_CREATED ,
model : Response :: MODEL_PROJECT ,
)
]
))
2023-06-23 23:07:58 +00:00
-> param ( 'projectId' , '' , new ProjectId (), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, and hyphen. Can\'t start with a special char. Max length is 36 chars.' )
2020-09-10 14:40:14 +00:00
-> param ( 'name' , null , new Text ( 128 ), 'Project name. Max length: 128 chars.' )
-> param ( 'teamId' , '' , new UID (), 'Team unique ID.' )
2024-06-07 00:54:51 +00:00
-> param ( 'region' , System :: getEnv ( '_APP_REGION' , 'default' ), new Whitelist ( array_keys ( array_filter ( Config :: getParam ( 'regions' ), fn ( $config ) => ! $config [ 'disabled' ]))), 'Project Region.' , true )
2020-09-10 14:40:14 +00:00
-> param ( 'description' , '' , new Text ( 256 ), 'Project description. Max length: 256 chars.' , true )
-> param ( 'logo' , '' , new Text ( 1024 ), 'Project logo.' , true )
2022-02-16 15:20:54 +00:00
-> param ( 'url' , '' , new URL (), 'Project URL.' , true )
2020-09-10 14:40:14 +00:00
-> param ( 'legalName' , '' , new Text ( 256 ), 'Project legal Name. Max length: 256 chars.' , true )
-> param ( 'legalCountry' , '' , new Text ( 256 ), 'Project legal Country. Max length: 256 chars.' , true )
-> param ( 'legalState' , '' , new Text ( 256 ), 'Project legal State. Max length: 256 chars.' , true )
-> param ( 'legalCity' , '' , new Text ( 256 ), 'Project legal City. Max length: 256 chars.' , true )
-> param ( 'legalAddress' , '' , new Text ( 256 ), 'Project legal Address. Max length: 256 chars.' , true )
-> param ( 'legalTaxId' , '' , new Text ( 256 ), 'Project legal Tax ID. Max length: 256 chars.' , true )
2023-11-27 11:27:41 +00:00
-> inject ( 'request' )
2020-12-26 16:33:36 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
2022-06-23 08:50:00 +00:00
-> inject ( 'cache' )
2022-10-15 14:14:17 +00:00
-> inject ( 'pools' )
2024-02-06 11:07:47 +00:00
-> inject ( 'hooks' )
2024-12-12 10:30:26 +00:00
-> action ( function ( string $projectId , string $name , string $teamId , string $region , string $description , string $logo , string $url , string $legalName , string $legalCountry , string $legalState , string $legalCity , string $legalAddress , string $legalTaxId , Request $request , Response $response , Database $dbForPlatform , Cache $cache , Group $pools , Hooks $hooks ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$team = $dbForPlatform -> getDocument ( 'teams' , $teamId );
2020-01-31 22:34:07 +00:00
2021-05-06 22:31:05 +00:00
if ( $team -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: TEAM_NOT_FOUND );
2020-06-30 15:46:42 +00:00
}
2021-08-16 13:27:15 +00:00
2024-04-01 11:02:47 +00:00
$allowList = \array_filter ( \explode ( ',' , System :: getEnv ( '_APP_PROJECT_REGIONS' , '' )));
2024-02-20 10:15:46 +00:00
if ( ! empty ( $allowList ) && ! \in_array ( $region , $allowList )) {
throw new Exception ( Exception :: PROJECT_REGION_UNSUPPORTED , 'Region "' . $region . '" is not supported' );
}
2021-08-06 07:42:31 +00:00
$auth = Config :: getParam ( 'auth' , []);
2023-11-22 12:11:48 +00:00
$auths = [
'limit' => 0 ,
'maxSessions' => APP_LIMIT_USER_SESSIONS_DEFAULT ,
'passwordHistory' => 0 ,
'passwordDictionary' => false ,
'duration' => Auth :: TOKEN_EXPIRATION_LOGIN_LONG ,
2024-07-03 08:27:54 +00:00
'personalDataCheck' => false ,
2024-07-03 09:30:11 +00:00
'mockNumbers' => [],
2024-06-24 13:12:09 +00:00
'sessionAlerts' => false ,
2024-11-07 17:23:13 +00:00
'membershipsUserName' => false ,
'membershipsUserEmail' => false ,
'membershipsMfa' => false ,
2023-11-22 12:11:48 +00:00
];
2024-06-21 18:21:05 +00:00
2023-11-22 12:11:48 +00:00
foreach ( $auth as $method ) {
2021-08-06 07:42:31 +00:00
$auths [ $method [ 'key' ] ? ? '' ] = true ;
}
2020-01-31 22:34:07 +00:00
2022-08-14 14:22:38 +00:00
$projectId = ( $projectId == 'unique()' ) ? ID :: unique () : $projectId ;
2022-06-16 07:50:52 +00:00
2024-11-12 09:27:24 +00:00
if ( $projectId === 'console' ) {
throw new Exception ( Exception :: PROJECT_RESERVED_PROJECT , " 'console' is a reserved project. " );
}
2022-10-15 14:14:17 +00:00
$databases = Config :: getParam ( 'pools-database' , []);
2025-02-19 21:28:09 +00:00
2025-04-11 14:52:19 +00:00
if ( $region !== 'default' ) {
$databaseKeys = System :: getEnv ( '_APP_DATABASE_KEYS' , '' );
$keys = explode ( ',' , $databaseKeys );
$databases = array_filter ( $keys , function ( $value ) use ( $region ) {
return str_contains ( $value , $region );
});
}
2024-05-07 10:08:00 +00:00
$databaseOverride = System :: getEnv ( '_APP_DATABASE_OVERRIDE' );
2024-03-07 13:52:13 +00:00
$index = \array_search ( $databaseOverride , $databases );
2023-10-22 21:55:57 +00:00
if ( $index !== false ) {
2024-05-06 05:33:36 +00:00
$dsn = $databases [ $index ];
2023-06-14 19:52:28 +00:00
} else {
2024-05-06 05:33:36 +00:00
$dsn = $databases [ array_rand ( $databases )];
2023-06-14 19:52:28 +00:00
}
2022-06-16 07:50:52 +00:00
2024-06-06 08:11:19 +00:00
// TODO: Temporary until all projects are using shared tables.
2024-11-12 09:27:24 +00:00
$sharedTables = \explode ( ',' , System :: getEnv ( '_APP_DATABASE_SHARED_TABLES' , '' ));
if ( \in_array ( $dsn , $sharedTables )) {
2024-05-06 05:33:36 +00:00
$schema = 'appwrite' ;
$database = 'appwrite' ;
2024-05-07 10:08:00 +00:00
$namespace = System :: getEnv ( '_APP_DATABASE_SHARED_NAMESPACE' , '' );
2024-11-12 09:27:24 +00:00
$dsn = $schema . '://' . $dsn . '?database=' . $database ;
2024-05-06 05:33:36 +00:00
if ( ! empty ( $namespace )) {
$dsn .= '&namespace=' . $namespace ;
}
2023-11-30 03:32:15 +00:00
}
2023-11-27 11:27:41 +00:00
2023-04-29 07:11:17 +00:00
try {
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> createDocument ( 'projects' , new Document ([
2023-04-29 07:11:17 +00:00
'$id' => $projectId ,
'$permissions' => [
Permission :: read ( Role :: team ( ID :: custom ( $teamId ))),
Permission :: update ( Role :: team ( ID :: custom ( $teamId ), 'owner' )),
Permission :: update ( Role :: team ( ID :: custom ( $teamId ), 'developer' )),
Permission :: delete ( Role :: team ( ID :: custom ( $teamId ), 'owner' )),
Permission :: delete ( Role :: team ( ID :: custom ( $teamId ), 'developer' )),
],
'name' => $name ,
2025-05-26 05:42:11 +00:00
'teamInternalId' => $team -> getSequence (),
2023-04-29 07:11:17 +00:00
'teamId' => $team -> getId (),
'region' => $region ,
'description' => $description ,
'logo' => $logo ,
'url' => $url ,
'version' => APP_VERSION_STABLE ,
'legalName' => $legalName ,
'legalCountry' => $legalCountry ,
'legalState' => $legalState ,
'legalCity' => $legalCity ,
'legalAddress' => $legalAddress ,
'legalTaxId' => ID :: custom ( $legalTaxId ),
'services' => new stdClass (),
'platforms' => null ,
2023-10-25 17:33:23 +00:00
'oAuthProviders' => [],
2023-04-29 07:11:17 +00:00
'webhooks' => null ,
'keys' => null ,
'auths' => $auths ,
2024-07-16 01:08:21 +00:00
'accessedAt' => DateTime :: now (),
2023-04-29 07:11:17 +00:00
'search' => implode ( ' ' , [ $projectId , $name ]),
2024-05-06 05:33:36 +00:00
'database' => $dsn ,
2023-04-29 07:11:17 +00:00
]));
2023-11-22 12:11:48 +00:00
} catch ( Duplicate ) {
2023-04-29 07:11:17 +00:00
throw new Exception ( Exception :: PROJECT_ALREADY_EXISTS );
}
2024-05-06 05:33:36 +00:00
2024-05-06 06:13:41 +00:00
try {
$dsn = new DSN ( $dsn );
} catch ( \InvalidArgumentException ) {
2024-05-07 02:07:04 +00:00
// TODO: Temporary until all projects are using shared tables
2024-05-06 06:13:41 +00:00
$dsn = new DSN ( 'mysql://' . $dsn );
2023-11-27 11:27:41 +00:00
}
2023-11-22 12:11:48 +00:00
2024-11-12 09:27:24 +00:00
$sharedTables = \explode ( ',' , System :: getEnv ( '_APP_DATABASE_SHARED_TABLES' , '' ));
$sharedTablesV1 = \explode ( ',' , System :: getEnv ( '_APP_DATABASE_SHARED_TABLES_V1' , '' ));
$projectTables = ! \in_array ( $dsn -> getHost (), $sharedTables );
$sharedTablesV1 = \in_array ( $dsn -> getHost (), $sharedTablesV1 );
$sharedTablesV2 = ! $projectTables && ! $sharedTablesV1 ;
$sharedTables = $sharedTablesV1 || $sharedTablesV2 ;
2024-11-26 07:26:14 +00:00
2024-11-21 03:46:36 +00:00
if ( ! $sharedTablesV2 ) {
2025-05-14 06:14:07 +00:00
$adapter = new DatabasePool ( $pools -> get ( $dsn -> getHost ()));
2025-04-11 14:52:19 +00:00
$dbForProject = new Database ( $adapter , $cache );
2024-11-21 03:46:36 +00:00
if ( $sharedTables ) {
$dbForProject
-> setSharedTables ( true )
2025-06-16 17:24:48 +00:00
-> setTenant ( $sharedTablesV1 ? ( int ) $project -> getSequence () : null )
2024-11-21 03:46:36 +00:00
-> setNamespace ( $dsn -> getParam ( 'namespace' ));
} else {
$dbForProject
-> setSharedTables ( false )
-> setTenant ( null )
2025-05-26 05:42:11 +00:00
-> setNamespace ( '_' . $project -> getSequence ());
2024-11-21 03:46:36 +00:00
}
2024-10-08 07:54:40 +00:00
2024-11-21 03:46:36 +00:00
$create = true ;
2024-10-08 07:54:40 +00:00
2024-11-21 03:46:36 +00:00
try {
$dbForProject -> create ();
} catch ( Duplicate ) {
$create = false ;
}
2024-11-12 09:27:24 +00:00
2024-11-21 03:46:36 +00:00
if ( $create || $projectTables ) {
$audit = new Audit ( $dbForProject );
$audit -> setup ();
}
2022-06-20 11:44:04 +00:00
2024-11-21 03:46:36 +00:00
if ( ! $create && $sharedTablesV1 ) {
$attributes = \array_map ( fn ( $attribute ) => new Document ( $attribute ), Audit :: ATTRIBUTES );
$indexes = \array_map ( fn ( array $index ) => new Document ( $index ), Audit :: INDEXES );
$dbForProject -> createDocument ( Database :: METADATA , new Document ([
'$id' => ID :: custom ( 'audit' ),
'$permissions' => [ Permission :: create ( Role :: any ())],
'name' => 'audit' ,
'attributes' => $attributes ,
'indexes' => $indexes ,
'documentSecurity' => true
]));
}
2021-05-03 08:28:31 +00:00
2024-11-21 03:46:36 +00:00
if ( $create || $sharedTablesV1 ) {
/** @var array $collections */
$collections = Config :: getParam ( 'collections' , [])[ 'projects' ] ? ? [];
foreach ( $collections as $key => $collection ) {
if (( $collection [ '$collection' ] ? ? '' ) !== Database :: METADATA ) {
continue ;
}
$attributes = \array_map ( fn ( $attribute ) => new Document ( $attribute ), $collection [ 'attributes' ]);
$indexes = \array_map ( fn ( array $index ) => new Document ( $index ), $collection [ 'indexes' ]);
try {
$dbForProject -> createCollection ( $key , $attributes , $indexes );
} catch ( Duplicate ) {
$dbForProject -> createDocument ( Database :: METADATA , new Document ([
'$id' => ID :: custom ( $key ),
'$permissions' => [ Permission :: create ( Role :: any ())],
'name' => $key ,
'attributes' => $attributes ,
'indexes' => $indexes ,
'documentSecurity' => true
]));
}
2024-11-12 09:27:24 +00:00
}
2021-05-03 08:28:31 +00:00
}
}
2024-10-08 07:54:40 +00:00
2024-05-24 11:04:30 +00:00
// Hook allowing instant project mirroring during migration
// Outside of migration, hook is not registered and has no effect
2024-10-08 07:54:40 +00:00
$hooks -> trigger ( 'afterProjectCreation' , [ $project , $pools , $cache ]);
2024-02-07 11:04:46 +00:00
2022-09-07 11:02:36 +00:00
$response
-> setStatusCode ( Response :: STATUS_CODE_CREATED )
-> dynamic ( $project , Response :: MODEL_PROJECT );
2020-12-26 16:33:36 +00:00
});
2020-01-31 22:34:07 +00:00
2024-10-08 07:54:40 +00:00
App :: get ( '/v1/projects' )
2023-08-01 15:26:48 +00:00
-> desc ( 'List projects' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'projects' ])
2019-12-14 19:33:29 +00:00
-> label ( 'scope' , 'projects.read' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'projects' ,
2025-01-17 04:31:39 +00:00
name : 'list' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/list.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_PROJECT_LIST ,
)
]
))
2023-03-29 19:38:39 +00:00
-> param ( 'queries' , [], new Projects (), '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 ( ', ' , Projects :: ALLOWED_ATTRIBUTES ), true )
2020-09-10 14:40:14 +00:00
-> param ( 'search' , '' , new Text ( 256 ), 'Search term to filter your list results. Max length: 256 chars.' , true )
2020-12-26 16:33:36 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( array $queries , string $search , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-02-12 16:02:04 +00:00
try {
$queries = Query :: parseQueries ( $queries );
} catch ( QueryException $e ) {
throw new Exception ( Exception :: GENERAL_QUERY_INVALID , $e -> getMessage ());
}
2021-08-06 12:36:17 +00:00
2022-08-11 23:53:52 +00:00
if ( ! empty ( $search )) {
2022-08-31 12:30:16 +00:00
$queries [] = Query :: search ( 'search' , $search );
2021-08-06 12:36:17 +00:00
}
2024-02-12 09:55:45 +00:00
/**
2024-02-12 10:03:31 +00:00
* Get cursor document if there was a cursor query , we use array_filter and reset for reference $cursor to $queries
2024-02-12 09:55:45 +00:00
*/
2023-08-22 03:25:55 +00:00
$cursor = \array_filter ( $queries , function ( $query ) {
2023-12-06 14:10:40 +00:00
return \in_array ( $query -> getMethod (), [ Query :: TYPE_CURSOR_AFTER , Query :: TYPE_CURSOR_BEFORE ]);
2023-08-22 03:25:55 +00:00
});
2022-09-02 14:19:36 +00:00
$cursor = reset ( $cursor );
2022-08-31 12:30:16 +00:00
if ( $cursor ) {
/** @var Query $cursor */
2024-10-17 05:41:24 +00:00
$validator = new Cursor ();
if ( ! $validator -> isValid ( $cursor )) {
throw new Exception ( Exception :: GENERAL_QUERY_INVALID , $validator -> getDescription ());
}
2022-08-31 12:30:16 +00:00
$projectId = $cursor -> getValue ();
2024-12-12 10:30:26 +00:00
$cursorDocument = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2021-08-18 13:42:03 +00:00
2022-08-11 23:53:52 +00:00
if ( $cursorDocument -> isEmpty ()) {
2022-08-31 12:30:16 +00:00
throw new Exception ( Exception :: GENERAL_CURSOR_NOT_FOUND , " Project ' { $projectId } ' for the 'cursor' value not found. " );
2022-08-11 23:53:52 +00:00
}
2022-08-31 12:30:16 +00:00
$cursor -> setValue ( $cursorDocument );
2021-08-18 13:42:03 +00:00
}
2022-08-31 12:30:16 +00:00
$filterQueries = Query :: groupByType ( $queries )[ 'filters' ];
2025-04-16 12:23:39 +00:00
try {
2025-04-17 04:46:26 +00:00
$projects = $dbForPlatform -> find ( 'projects' , $queries );
$total = $dbForPlatform -> count ( 'projects' , $filterQueries , APP_LIMIT_COUNT );
2025-04-16 12:23:39 +00:00
} catch ( OrderException $e ) {
2025-04-17 04:46:26 +00:00
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. " );
2025-04-16 12:23:39 +00:00
}
2021-07-25 14:47:18 +00:00
$response -> dynamic ( new Document ([
2025-04-17 04:46:26 +00:00
'projects' => $projects ,
'total' => $total ,
2020-09-12 08:07:28 +00:00
]), Response :: MODEL_PROJECT_LIST );
2020-12-26 16:33:36 +00:00
});
2019-12-14 19:33:29 +00:00
2024-10-08 07:54:40 +00:00
App :: get ( '/v1/projects/:projectId' )
2023-08-01 15:26:48 +00:00
-> desc ( 'Get project' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'projects' ])
2019-12-14 19:33:29 +00:00
-> label ( 'scope' , 'projects.read' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'projects' ,
2025-01-17 04:31:39 +00:00
name : 'get' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/get.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_PROJECT ,
)
]
))
2020-09-10 14:40:14 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
2020-12-26 16:33:36 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2019-12-14 19:33:29 +00:00
2021-05-15 22:41:42 +00:00
if ( $project -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
2020-06-30 15:46:42 +00:00
}
2019-12-14 19:33:29 +00:00
2021-07-25 14:47:18 +00:00
$response -> dynamic ( $project , Response :: MODEL_PROJECT );
2020-12-26 16:33:36 +00:00
});
2019-12-14 19:33:29 +00:00
2024-10-08 07:54:40 +00:00
App :: patch ( '/v1/projects/:projectId' )
2023-08-01 15:26:48 +00:00
-> desc ( 'Update project' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'projects' ])
2019-12-14 19:33:29 +00:00
-> label ( 'scope' , 'projects.write' )
2024-12-02 09:47:17 +00:00
-> label ( 'audits.event' , 'projects.update' )
-> label ( 'audits.resource' , 'project/{request.projectId}' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'projects' ,
2025-01-17 04:31:39 +00:00
name : 'update' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/update.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_PROJECT ,
)
]
))
2020-09-10 14:40:14 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
-> param ( 'name' , null , new Text ( 128 ), 'Project name. Max length: 128 chars.' )
-> param ( 'description' , '' , new Text ( 256 ), 'Project description. Max length: 256 chars.' , true )
-> param ( 'logo' , '' , new Text ( 1024 ), 'Project logo.' , true )
2022-02-16 15:20:54 +00:00
-> param ( 'url' , '' , new URL (), 'Project URL.' , true )
2020-09-10 14:40:14 +00:00
-> param ( 'legalName' , '' , new Text ( 256 ), 'Project legal name. Max length: 256 chars.' , true )
-> param ( 'legalCountry' , '' , new Text ( 256 ), 'Project legal country. Max length: 256 chars.' , true )
-> param ( 'legalState' , '' , new Text ( 256 ), 'Project legal state. Max length: 256 chars.' , true )
-> param ( 'legalCity' , '' , new Text ( 256 ), 'Project legal city. Max length: 256 chars.' , true )
-> param ( 'legalAddress' , '' , new Text ( 256 ), 'Project legal address. Max length: 256 chars.' , true )
-> param ( 'legalTaxId' , '' , new Text ( 256 ), 'Project legal tax ID. Max length: 256 chars.' , true )
2020-12-26 16:33:36 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , string $name , string $description , string $logo , string $url , string $legalName , string $legalCountry , string $legalState , string $legalCity , string $legalAddress , string $legalTaxId , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2019-12-14 19:33:29 +00:00
2021-05-15 22:41:42 +00:00
if ( $project -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
2020-06-30 15:46:42 +00:00
}
2019-12-14 19:33:29 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> updateDocument ( 'projects' , $project -> getId (), $project
2024-10-08 07:54:40 +00:00
-> setAttribute ( 'name' , $name )
-> setAttribute ( 'description' , $description )
-> setAttribute ( 'logo' , $logo )
-> setAttribute ( 'url' , $url )
-> setAttribute ( 'legalName' , $legalName )
-> setAttribute ( 'legalCountry' , $legalCountry )
-> setAttribute ( 'legalState' , $legalState )
-> setAttribute ( 'legalCity' , $legalCity )
-> setAttribute ( 'legalAddress' , $legalAddress )
-> setAttribute ( 'legalTaxId' , $legalTaxId )
-> setAttribute ( 'search' , implode ( ' ' , [ $projectId , $name ])));
2020-06-30 15:46:42 +00:00
2021-07-25 14:47:18 +00:00
$response -> dynamic ( $project , Response :: MODEL_PROJECT );
2020-12-26 16:33:36 +00:00
});
2019-12-14 19:33:29 +00:00
2024-10-08 07:54:40 +00:00
App :: patch ( '/v1/projects/:projectId/team' )
-> desc ( 'Update project team' )
2023-05-02 06:59:17 +00:00
-> groups ([ 'api' , 'projects' ])
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'projects' ,
2025-01-17 04:31:39 +00:00
name : 'updateTeam' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/update-team.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_PROJECT ,
)
]
))
2023-05-02 06:59:17 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
-> param ( 'teamId' , '' , new UID (), 'Team ID of the team to transfer project to.' )
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , string $teamId , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
$team = $dbForPlatform -> getDocument ( 'teams' , $teamId );
2023-05-02 06:59:17 +00:00
if ( $project -> isEmpty ()) {
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
}
if ( $team -> isEmpty ()) {
throw new Exception ( Exception :: TEAM_NOT_FOUND );
}
2023-10-13 00:34:53 +00:00
$permissions = [
Permission :: read ( Role :: team ( ID :: custom ( $teamId ))),
Permission :: update ( Role :: team ( ID :: custom ( $teamId ), 'owner' )),
Permission :: update ( Role :: team ( ID :: custom ( $teamId ), 'developer' )),
Permission :: delete ( Role :: team ( ID :: custom ( $teamId ), 'owner' )),
Permission :: delete ( Role :: team ( ID :: custom ( $teamId ), 'developer' )),
];
$project
2023-08-28 12:19:37 +00:00
-> setAttribute ( 'teamId' , $teamId )
2025-05-26 05:42:11 +00:00
-> setAttribute ( 'teamInternalId' , $team -> getSequence ())
2023-10-13 00:34:53 +00:00
-> setAttribute ( '$permissions' , $permissions );
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> updateDocument ( 'projects' , $project -> getId (), $project );
2023-10-13 00:34:53 +00:00
2024-12-12 10:30:26 +00:00
$installations = $dbForPlatform -> find ( 'installations' , [
2025-05-26 05:42:11 +00:00
Query :: equal ( 'projectInternalId' , [ $project -> getSequence ()]),
2023-10-13 00:34:53 +00:00
]);
foreach ( $installations as $installation ) {
$installation -> getAttribute ( '$permissions' , $permissions );
2024-12-12 10:30:26 +00:00
$dbForPlatform -> updateDocument ( 'installations' , $installation -> getId (), $installation );
2023-10-13 00:34:53 +00:00
}
2024-12-12 10:30:26 +00:00
$repositories = $dbForPlatform -> find ( 'repositories' , [
2025-05-26 05:42:11 +00:00
Query :: equal ( 'projectInternalId' , [ $project -> getSequence ()]),
2023-10-13 00:34:53 +00:00
]);
foreach ( $repositories as $repository ) {
$repository -> getAttribute ( '$permissions' , $permissions );
2024-12-12 10:30:26 +00:00
$dbForPlatform -> updateDocument ( 'repositories' , $repository -> getId (), $repository );
2023-10-13 00:34:53 +00:00
}
2024-12-12 10:30:26 +00:00
$vcsComments = $dbForPlatform -> find ( 'vcsComments' , [
2025-05-26 05:42:11 +00:00
Query :: equal ( 'projectInternalId' , [ $project -> getSequence ()]),
2023-10-13 00:34:53 +00:00
]);
foreach ( $vcsComments as $vcsComment ) {
$vcsComment -> getAttribute ( '$permissions' , $permissions );
2024-12-12 10:30:26 +00:00
$dbForPlatform -> updateDocument ( 'vcsComments' , $vcsComment -> getId (), $vcsComment );
2023-10-13 00:34:53 +00:00
}
2023-05-02 06:59:17 +00:00
$response -> dynamic ( $project , Response :: MODEL_PROJECT );
});
2024-10-08 07:54:40 +00:00
App :: patch ( '/v1/projects/:projectId/service' )
2021-07-29 10:28:17 +00:00
-> desc ( 'Update service status' )
-> groups ([ 'api' , 'projects' ])
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'projects' ,
2025-01-17 04:31:39 +00:00
name : 'updateServiceStatus' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/update-service-status.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_PROJECT ,
)
]
))
2021-07-29 10:28:17 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
2024-06-07 00:54:51 +00:00
-> param ( 'service' , '' , new WhiteList ( array_keys ( array_filter ( Config :: getParam ( 'services' ), fn ( $element ) => $element [ 'optional' ])), true ), 'Service name.' )
2021-07-31 21:36:18 +00:00
-> param ( 'status' , null , new Boolean (), 'Service status.' )
2021-07-29 10:28:17 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , string $service , bool $status , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2021-07-29 10:28:17 +00:00
2021-07-29 10:56:25 +00:00
if ( $project -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
2021-07-29 10:28:17 +00:00
}
2021-07-31 20:54:50 +00:00
$services = $project -> getAttribute ( 'services' , []);
$services [ $service ] = $status ;
2021-07-29 10:28:17 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> updateDocument ( 'projects' , $project -> getId (), $project -> setAttribute ( 'services' , $services ));
2021-07-29 10:28:17 +00:00
$response -> dynamic ( $project , Response :: MODEL_PROJECT );
});
2024-10-08 07:54:40 +00:00
App :: patch ( '/v1/projects/:projectId/service/all' )
2023-04-05 02:33:38 +00:00
-> desc ( 'Update all service status' )
-> groups ([ 'api' , 'projects' ])
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'projects' ,
2025-01-17 04:31:39 +00:00
name : 'updateServiceStatusAll' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/update-service-status-all.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_PROJECT ,
)
]
))
2023-04-05 02:33:38 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
-> param ( 'status' , null , new Boolean (), 'Service status.' )
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , bool $status , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2023-04-05 02:33:38 +00:00
if ( $project -> isEmpty ()) {
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
}
2024-06-07 00:54:51 +00:00
$allServices = array_keys ( array_filter ( Config :: getParam ( 'services' ), fn ( $element ) => $element [ 'optional' ]));
2023-04-05 02:33:38 +00:00
$services = [];
2023-04-05 05:52:59 +00:00
foreach ( $allServices as $service ) {
2023-04-05 02:33:38 +00:00
$services [ $service ] = $status ;
}
2023-04-05 05:52:59 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> updateDocument ( 'projects' , $project -> getId (), $project -> setAttribute ( 'services' , $services ));
2023-04-05 02:33:38 +00:00
$response -> dynamic ( $project , Response :: MODEL_PROJECT );
});
2024-10-08 07:54:40 +00:00
App :: patch ( '/v1/projects/:projectId/api' )
2024-03-04 22:12:54 +00:00
-> desc ( 'Update API status' )
-> groups ([ 'api' , 'projects' ])
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'projects' ,
2025-01-17 04:31:39 +00:00
name : 'updateApiStatus' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/update-api-status.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_PROJECT ,
)
]
))
2024-03-04 22:12:54 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
-> param ( 'api' , '' , new WhiteList ( array_keys ( Config :: getParam ( 'apis' )), true ), 'API name.' )
-> param ( 'status' , null , new Boolean (), 'API status.' )
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , string $api , bool $status , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2024-03-04 22:12:54 +00:00
if ( $project -> isEmpty ()) {
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
}
$apis = $project -> getAttribute ( 'apis' , []);
$apis [ $api ] = $status ;
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> updateDocument ( 'projects' , $project -> getId (), $project -> setAttribute ( 'apis' , $apis ));
2024-03-04 22:12:54 +00:00
$response -> dynamic ( $project , Response :: MODEL_PROJECT );
});
2024-10-08 07:54:40 +00:00
App :: patch ( '/v1/projects/:projectId/api/all' )
2024-03-04 22:28:42 +00:00
-> desc ( 'Update all API status' )
-> groups ([ 'api' , 'projects' ])
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'projects' ,
2025-01-17 04:31:39 +00:00
name : 'updateApiStatusAll' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/update-api-status-all.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_PROJECT ,
)
]
))
2024-03-04 22:28:42 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
-> param ( 'status' , null , new Boolean (), 'API status.' )
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , bool $status , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2024-03-04 22:28:42 +00:00
if ( $project -> isEmpty ()) {
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
}
$allApis = array_keys ( Config :: getParam ( 'apis' ));
$apis = [];
foreach ( $allApis as $api ) {
$apis [ $api ] = $status ;
}
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> updateDocument ( 'projects' , $project -> getId (), $project -> setAttribute ( 'apis' , $apis ));
2024-03-04 22:28:42 +00:00
$response -> dynamic ( $project , Response :: MODEL_PROJECT );
});
2024-10-08 07:54:40 +00:00
App :: patch ( '/v1/projects/:projectId/oauth2' )
2023-08-01 15:26:48 +00:00
-> desc ( 'Update project OAuth2' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'projects' ])
2019-12-14 19:33:29 +00:00
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'auth' ,
2025-01-17 04:31:39 +00:00
name : 'updateOAuth2' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/update-oauth2.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_PROJECT ,
)
]
))
2020-09-10 14:40:14 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
2023-10-25 17:33:23 +00:00
-> param ( 'provider' , '' , new WhiteList ( \array_keys ( Config :: getParam ( 'oAuthProviders' )), true ), 'Provider Name' )
2022-08-19 09:21:51 +00:00
-> param ( 'appId' , null , new Text ( 256 ), 'Provider app ID. Max length: 256 chars.' , true )
-> param ( 'secret' , null , new text ( 512 ), 'Provider secret key. Max length: 512 chars.' , true )
-> param ( 'enabled' , null , new Boolean (), 'Provider status. Set to \'false\' to disable new session creation.' , true )
2020-12-26 16:33:36 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , string $provider , ? string $appId , ? string $secret , ? bool $enabled , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2019-12-14 19:33:29 +00:00
2021-05-15 22:41:42 +00:00
if ( $project -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
2020-06-30 15:46:42 +00:00
}
2019-12-14 19:33:29 +00:00
2023-10-25 17:33:23 +00:00
$providers = $project -> getAttribute ( 'oAuthProviders' , []);
2022-08-19 09:21:51 +00:00
2022-08-19 09:43:03 +00:00
if ( $appId !== null ) {
2022-08-19 09:21:51 +00:00
$providers [ $provider . 'Appid' ] = $appId ;
}
2022-08-19 09:43:03 +00:00
if ( $secret !== null ) {
2022-08-19 09:21:51 +00:00
$providers [ $provider . 'Secret' ] = $secret ;
}
2022-08-19 09:43:03 +00:00
if ( $enabled !== null ) {
2022-08-19 09:21:51 +00:00
$providers [ $provider . 'Enabled' ] = $enabled ;
}
2021-08-06 10:35:50 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> updateDocument ( 'projects' , $project -> getId (), $project -> setAttribute ( 'oAuthProviders' , $providers ));
2020-06-30 15:46:42 +00:00
2021-07-25 14:47:18 +00:00
$response -> dynamic ( $project , Response :: MODEL_PROJECT );
2020-12-26 16:33:36 +00:00
});
2019-12-14 19:33:29 +00:00
2024-10-08 07:54:40 +00:00
App :: patch ( '/v1/projects/:projectId/auth/session-alerts' )
2024-06-21 18:21:05 +00:00
-> desc ( 'Update project sessions emails' )
-> groups ([ 'api' , 'projects' ])
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'auth' ,
2025-01-17 04:31:39 +00:00
name : 'updateSessionAlerts' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/update-session-alerts.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_PROJECT ,
)
]
))
2024-06-21 18:21:05 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
2024-07-03 07:11:15 +00:00
-> param ( 'alerts' , false , new Boolean ( true ), 'Set to true to enable session emails.' )
2024-06-21 18:21:05 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , bool $alerts , Response $response , Database $dbForPlatform ) {
2024-06-21 18:21:05 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2024-06-21 18:21:05 +00:00
if ( $project -> isEmpty ()) {
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
}
$auths = $project -> getAttribute ( 'auths' , []);
2024-07-03 07:11:15 +00:00
$auths [ 'sessionAlerts' ] = $alerts ;
2024-06-21 18:21:05 +00:00
2024-12-12 10:30:26 +00:00
$dbForPlatform -> updateDocument ( 'projects' , $project -> getId (), $project
2024-06-21 18:21:05 +00:00
-> setAttribute ( 'auths' , $auths ));
$response -> dynamic ( $project , Response :: MODEL_PROJECT );
});
2024-11-06 20:15:31 +00:00
App :: patch ( '/v1/projects/:projectId/auth/memberships-privacy' )
2024-11-07 14:33:44 +00:00
-> desc ( 'Update project memberships privacy attributes' )
2024-11-01 11:38:56 +00:00
-> groups ([ 'api' , 'projects' ])
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'auth' ,
2025-01-17 04:31:39 +00:00
name : 'updateMembershipsPrivacy' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/update-memberships-privacy.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_PROJECT ,
)
]
))
2024-11-01 11:38:56 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
2024-11-06 20:15:31 +00:00
-> param ( 'userName' , true , new Boolean ( true ), 'Set to true to show userName to members of a team.' )
-> param ( 'userEmail' , true , new Boolean ( true ), 'Set to true to show email to members of a team.' )
-> param ( 'mfa' , true , new Boolean ( true ), 'Set to true to show mfa to members of a team.' )
2024-11-01 11:38:56 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , bool $userName , bool $userEmail , bool $mfa , Response $response , Database $dbForPlatform ) {
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2024-11-01 11:38:56 +00:00
if ( $project -> isEmpty ()) {
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
}
$auths = $project -> getAttribute ( 'auths' , []);
2024-11-05 16:05:21 +00:00
2024-11-06 20:15:31 +00:00
$auths [ 'membershipsUserName' ] = $userName ;
$auths [ 'membershipsUserEmail' ] = $userEmail ;
$auths [ 'membershipsMfa' ] = $mfa ;
2024-11-01 11:38:56 +00:00
2024-12-12 10:30:26 +00:00
$dbForPlatform -> updateDocument ( 'projects' , $project -> getId (), $project
2024-11-01 11:38:56 +00:00
-> setAttribute ( 'auths' , $auths ));
$response -> dynamic ( $project , Response :: MODEL_PROJECT );
});
2024-10-08 07:54:40 +00:00
App :: patch ( '/v1/projects/:projectId/auth/limit' )
2023-08-01 15:26:48 +00:00
-> desc ( 'Update project users limit' )
2021-02-28 11:40:59 +00:00
-> groups ([ 'api' , 'projects' ])
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'auth' ,
2025-01-17 04:31:39 +00:00
name : 'updateAuthLimit' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/update-auth-limit.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_PROJECT ,
)
]
))
2021-02-28 11:40:59 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
2022-01-15 23:25:00 +00:00
-> param ( 'limit' , false , new Range ( 0 , APP_LIMIT_USERS ), 'Set the max number of users allowed in this project. Use 0 for unlimited.' )
2021-02-28 11:40:59 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , int $limit , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2021-02-28 11:40:59 +00:00
2021-05-15 22:41:42 +00:00
if ( $project -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
2021-02-28 11:40:59 +00:00
}
2021-08-06 08:34:17 +00:00
$auths = $project -> getAttribute ( 'auths' , []);
$auths [ 'limit' ] = $limit ;
2024-12-12 10:30:26 +00:00
$dbForPlatform -> updateDocument ( 'projects' , $project -> getId (), $project
2024-10-08 07:54:40 +00:00
-> setAttribute ( 'auths' , $auths ));
2021-02-28 11:40:59 +00:00
2021-07-25 14:47:18 +00:00
$response -> dynamic ( $project , Response :: MODEL_PROJECT );
2022-11-14 09:15:55 +00:00
});
2022-11-14 09:33:49 +00:00
2024-10-08 07:54:40 +00:00
App :: patch ( '/v1/projects/:projectId/auth/duration' )
2023-08-01 15:26:48 +00:00
-> desc ( 'Update project authentication duration' )
2022-11-14 09:15:55 +00:00
-> groups ([ 'api' , 'projects' ])
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'auth' ,
2025-01-17 04:31:39 +00:00
name : 'updateAuthDuration' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/update-auth-duration.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_PROJECT ,
)
]
))
2022-11-14 09:15:55 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
2022-11-15 10:25:34 +00:00
-> param ( 'duration' , 31536000 , new Range ( 0 , 31536000 ), 'Project session length in seconds. Max length: 31536000 seconds.' )
2022-11-14 09:15:55 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , int $duration , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2022-11-14 09:15:55 +00:00
if ( $project -> isEmpty ()) {
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
}
2022-11-14 09:30:45 +00:00
$auths = $project -> getAttribute ( 'auths' , []);
2022-11-15 10:25:34 +00:00
$auths [ 'duration' ] = $duration ;
2022-11-14 09:30:45 +00:00
2024-12-12 10:30:26 +00:00
$dbForPlatform -> updateDocument ( 'projects' , $project -> getId (), $project
2024-10-08 07:54:40 +00:00
-> setAttribute ( 'auths' , $auths ));
2022-11-14 09:15:55 +00:00
$response -> dynamic ( $project , Response :: MODEL_PROJECT );
2021-02-28 11:40:59 +00:00
});
2024-10-08 07:54:40 +00:00
App :: patch ( '/v1/projects/:projectId/auth/:method' )
2023-08-01 15:26:48 +00:00
-> desc ( 'Update project auth method status. Use this endpoint to enable or disable a given auth method for this project.' )
2021-02-28 11:40:59 +00:00
-> groups ([ 'api' , 'projects' ])
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'auth' ,
2025-01-17 04:31:39 +00:00
name : 'updateAuthStatus' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/update-auth-status.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_PROJECT ,
)
]
))
2021-02-28 11:40:59 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
2021-06-07 05:17:29 +00:00
-> param ( 'method' , '' , new WhiteList ( \array_keys ( Config :: getParam ( 'auth' )), true ), 'Auth Method. Possible values: ' . implode ( ',' , \array_keys ( Config :: getParam ( 'auth' ))), false )
2021-02-28 15:00:27 +00:00
-> param ( 'status' , false , new Boolean ( true ), 'Set the status of this auth method.' )
2021-02-28 11:40:59 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , string $method , bool $status , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2024-10-08 07:54:40 +00:00
$auth = Config :: getParam ( 'auth' )[ $method ] ? ? [];
$authKey = $auth [ 'key' ] ? ? '' ;
2021-02-28 15:00:27 +00:00
$status = ( $status === '1' || $status === 'true' || $status === 1 || $status === true );
2021-02-28 11:40:59 +00:00
2021-05-15 22:41:42 +00:00
if ( $project -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
2021-02-28 11:40:59 +00:00
}
2021-08-06 07:42:31 +00:00
$auths = $project -> getAttribute ( 'auths' , []);
$auths [ $authKey ] = $status ;
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> updateDocument ( 'projects' , $project -> getId (), $project -> setAttribute ( 'auths' , $auths ));
2021-02-28 11:40:59 +00:00
2021-07-25 14:47:18 +00:00
$response -> dynamic ( $project , Response :: MODEL_PROJECT );
2021-02-28 11:40:59 +00:00
});
2024-10-08 07:54:40 +00:00
App :: patch ( '/v1/projects/:projectId/auth/password-history' )
2023-01-30 06:05:32 +00:00
-> desc ( 'Update authentication password history. Use this endpoint to set the number of password history to save and 0 to disable password history.' )
2022-12-16 10:37:49 +00:00
-> groups ([ 'api' , 'projects' ])
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'auth' ,
2025-01-17 04:31:39 +00:00
name : 'updateAuthPasswordHistory' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/update-auth-password-history.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_PROJECT ,
)
]
))
2022-12-16 10:37:49 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
2022-12-19 05:07:41 +00:00
-> param ( 'limit' , 0 , new Range ( 0 , APP_LIMIT_USER_PASSWORD_HISTORY ), 'Set the max number of passwords to store in user history. User can\'t choose a new password that is already stored in the password history list. Max number of passwords allowed in history is' . APP_LIMIT_USER_PASSWORD_HISTORY . '. Default value is 0' )
2022-12-16 10:37:49 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , int $limit , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2022-12-16 10:37:49 +00:00
if ( $project -> isEmpty ()) {
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
}
$auths = $project -> getAttribute ( 'auths' , []);
$auths [ 'passwordHistory' ] = $limit ;
2024-12-12 10:30:26 +00:00
$dbForPlatform -> updateDocument ( 'projects' , $project -> getId (), $project
2024-10-08 07:54:40 +00:00
-> setAttribute ( 'auths' , $auths ));
2022-12-16 10:37:49 +00:00
$response -> dynamic ( $project , Response :: MODEL_PROJECT );
});
2024-10-08 07:54:40 +00:00
App :: patch ( '/v1/projects/:projectId/auth/password-dictionary' )
2023-04-11 23:01:50 +00:00
-> desc ( 'Update authentication password dictionary status. Use this endpoint to enable or disable the dicitonary check for user password' )
2022-12-26 05:31:49 +00:00
-> groups ([ 'api' , 'projects' ])
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'auth' ,
2025-01-17 04:31:39 +00:00
name : 'updateAuthPasswordDictionary' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/update-auth-password-dictionary.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_PROJECT ,
)
]
))
2022-12-26 05:31:49 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
2023-01-30 06:06:52 +00:00
-> param ( 'enabled' , false , new Boolean ( false ), 'Set whether or not to enable checking user\'s password against most commonly used passwords. Default is false.' )
2022-12-26 05:31:49 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , bool $enabled , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2022-12-26 05:31:49 +00:00
if ( $project -> isEmpty ()) {
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
}
$auths = $project -> getAttribute ( 'auths' , []);
2023-01-30 06:06:52 +00:00
$auths [ 'passwordDictionary' ] = $enabled ;
2022-12-26 05:31:49 +00:00
2024-12-12 10:30:26 +00:00
$dbForPlatform -> updateDocument ( 'projects' , $project -> getId (), $project
2024-10-08 07:54:40 +00:00
-> setAttribute ( 'auths' , $auths ));
2022-12-26 05:31:49 +00:00
$response -> dynamic ( $project , Response :: MODEL_PROJECT );
});
2024-10-08 07:54:40 +00:00
App :: patch ( '/v1/projects/:projectId/auth/personal-data' )
2025-04-14 18:40:48 +00:00
-> desc ( 'Update personal data check' )
2023-04-11 23:01:50 +00:00
-> groups ([ 'api' , 'projects' ])
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'auth' ,
2025-01-17 04:31:39 +00:00
name : 'updatePersonalDataCheck' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/update-personal-data-check.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_PROJECT ,
)
]
))
2023-04-11 23:01:50 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
2023-04-13 20:20:03 +00:00
-> param ( 'enabled' , false , new Boolean ( false ), 'Set whether or not to check a password for similarity with personal data. Default is false.' )
2023-04-11 23:01:50 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , bool $enabled , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2023-04-11 23:01:50 +00:00
if ( $project -> isEmpty ()) {
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
}
$auths = $project -> getAttribute ( 'auths' , []);
2023-07-19 22:24:32 +00:00
$auths [ 'personalDataCheck' ] = $enabled ;
2023-04-11 23:01:50 +00:00
2024-12-12 10:30:26 +00:00
$dbForPlatform -> updateDocument ( 'projects' , $project -> getId (), $project
2024-10-08 07:54:40 +00:00
-> setAttribute ( 'auths' , $auths ));
2023-04-11 23:01:50 +00:00
$response -> dynamic ( $project , Response :: MODEL_PROJECT );
});
2024-10-08 07:54:40 +00:00
App :: patch ( '/v1/projects/:projectId/auth/max-sessions' )
2023-08-01 15:26:48 +00:00
-> desc ( 'Update project user sessions limit' )
2022-12-06 10:45:04 +00:00
-> groups ([ 'api' , 'projects' ])
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'auth' ,
2025-01-17 04:31:39 +00:00
name : 'updateAuthSessionsLimit' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/update-auth-sessions-limit.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_PROJECT ,
)
]
))
2022-12-06 10:45:04 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
2022-12-12 05:07:18 +00:00
-> param ( 'limit' , false , new Range ( 1 , APP_LIMIT_USER_SESSIONS_MAX ), 'Set the max number of users allowed in this project. Value allowed is between 1-' . APP_LIMIT_USER_SESSIONS_MAX . '. Default is ' . APP_LIMIT_USER_SESSIONS_DEFAULT )
2022-12-06 10:45:04 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , int $limit , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2022-12-06 10:45:04 +00:00
if ( $project -> isEmpty ()) {
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
}
$auths = $project -> getAttribute ( 'auths' , []);
2022-12-09 11:33:26 +00:00
$auths [ 'maxSessions' ] = $limit ;
2022-12-06 10:45:04 +00:00
2024-12-12 10:30:26 +00:00
$dbForPlatform -> updateDocument ( 'projects' , $project -> getId (), $project
2024-10-08 07:54:40 +00:00
-> setAttribute ( 'auths' , $auths ));
2022-12-06 10:45:04 +00:00
$response -> dynamic ( $project , Response :: MODEL_PROJECT );
});
2024-10-08 07:54:40 +00:00
App :: patch ( '/v1/projects/:projectId/auth/mock-numbers' )
2024-02-11 14:51:19 +00:00
-> desc ( 'Update the mock numbers for the project' )
-> groups ([ 'api' , 'projects' ])
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'auth' ,
2025-01-17 04:31:39 +00:00
name : 'updateMockNumbers' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/update-mock-numbers.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_PROJECT ,
)
]
))
2024-02-11 14:51:19 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
-> param ( 'numbers' , '' , new ArrayList ( new MockNumber (), 10 ), 'An array of mock numbers and their corresponding verification codes (OTPs). Each number should be a valid E.164 formatted phone number. Maximum of 10 numbers are allowed.' )
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , array $numbers , Response $response , Database $dbForPlatform ) {
2024-02-11 14:51:19 +00:00
2024-07-21 19:30:06 +00:00
$uniqueNumbers = [];
foreach ( $numbers as $number ) {
2024-07-21 19:45:39 +00:00
if ( isset ( $uniqueNumbers [ $number [ 'phone' ]])) {
throw new Exception ( Exception :: GENERAL_BAD_REQUEST , 'Duplicate phone numbers are not allowed.' );
2024-07-21 19:30:06 +00:00
}
2024-07-21 19:45:39 +00:00
$uniqueNumbers [ $number [ 'phone' ]] = $number [ 'otp' ];
2024-07-21 19:30:06 +00:00
}
2024-07-22 09:08:02 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2024-02-11 14:51:19 +00:00
if ( $project -> isEmpty ()) {
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
}
$auths = $project -> getAttribute ( 'auths' , []);
$auths [ 'mockNumbers' ] = $numbers ;
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> updateDocument ( 'projects' , $project -> getId (), $project -> setAttribute ( 'auths' , $auths ));
2024-02-11 14:51:19 +00:00
$response -> dynamic ( $project , Response :: MODEL_PROJECT );
});
2024-10-08 07:54:40 +00:00
App :: delete ( '/v1/projects/:projectId' )
2023-08-01 15:26:48 +00:00
-> desc ( 'Delete project' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'projects' ])
2024-07-22 08:03:53 +00:00
-> label ( 'audits.event' , 'projects.delete' )
2024-12-02 09:47:17 +00:00
-> label ( 'audits.resource' , 'project/{request.projectId}' )
2019-12-14 19:33:29 +00:00
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'projects' ,
2025-01-17 04:31:39 +00:00
name : 'delete' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/delete.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_NOCONTENT ,
model : Response :: MODEL_NONE ,
)
],
contentType : ContentType :: NONE
))
2020-09-10 14:40:14 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
2020-12-26 16:33:36 +00:00
-> inject ( 'response' )
-> inject ( 'user' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
2022-12-20 16:11:30 +00:00
-> inject ( 'queueForDeletes' )
2024-12-12 10:30:26 +00:00
-> action ( function ( string $projectId , Response $response , Document $user , Database $dbForPlatform , Delete $queueForDeletes ) {
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2019-12-14 19:33:29 +00:00
2021-05-15 22:41:42 +00:00
if ( $project -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
2020-06-30 15:46:42 +00:00
}
2019-12-14 19:33:29 +00:00
2022-12-20 16:11:30 +00:00
$queueForDeletes
2024-10-01 14:17:36 +00:00
-> setProject ( $project )
2022-04-17 20:34:32 +00:00
-> setType ( DELETE_TYPE_DOCUMENT )
2023-08-28 12:19:37 +00:00
-> setDocument ( $project );
2021-06-07 05:17:29 +00:00
2024-12-12 10:30:26 +00:00
if ( ! $dbForPlatform -> deleteDocument ( 'projects' , $projectId )) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: GENERAL_SERVER_ERROR , 'Failed to remove project from DB' );
2019-12-18 10:24:54 +00:00
}
2020-06-30 15:46:42 +00:00
$response -> noContent ();
2020-12-26 16:33:36 +00:00
});
2019-12-18 10:24:54 +00:00
// Webhooks
2024-10-08 07:54:40 +00:00
App :: post ( '/v1/projects/:projectId/webhooks' )
2023-08-01 15:26:48 +00:00
-> desc ( 'Create webhook' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'projects' ])
2020-01-31 22:34:07 +00:00
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'webhooks' ,
2025-01-17 04:31:39 +00:00
name : 'createWebhook' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/create-webhook.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_CREATED ,
model : Response :: MODEL_WEBHOOK ,
)
]
))
2022-09-19 10:05:42 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
2020-09-10 14:40:14 +00:00
-> param ( 'name' , null , new Text ( 128 ), 'Webhook name. Max length: 128 chars.' )
2024-01-18 09:49:57 +00:00
-> param ( 'enabled' , true , new Boolean ( true ), 'Enable or disable a webhook.' , true )
2022-05-12 18:41:04 +00:00
-> param ( 'events' , null , new ArrayList ( new Event (), APP_LIMIT_ARRAY_PARAMS_SIZE ), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.' )
2024-06-07 00:54:51 +00:00
-> param ( 'url' , '' , fn ( $request ) => new Multiple ([ new URL ([ 'http' , 'https' ]), new PublicDomain ()], Multiple :: TYPE_STRING ), 'Webhook URL.' , false , [ 'request' ])
2020-09-10 14:40:14 +00:00
-> param ( 'security' , false , new Boolean ( true ), 'Certificate verification, false for disabled or true for enabled.' )
-> param ( 'httpUser' , '' , new Text ( 256 ), 'Webhook HTTP user. Max length: 256 chars.' , true )
-> param ( 'httpPass' , '' , new Text ( 256 ), 'Webhook HTTP password. Max length: 256 chars.' , true )
2020-12-26 16:33:36 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , string $name , bool $enabled , array $events , string $url , bool $security , string $httpUser , string $httpPass , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2020-01-31 22:34:07 +00:00
2021-05-15 22:41:42 +00:00
if ( $project -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
2020-06-30 15:46:42 +00:00
}
2020-01-31 22:34:07 +00:00
2024-10-08 07:54:40 +00:00
$security = ( bool ) filter_var ( $security , FILTER_VALIDATE_BOOLEAN );
2020-06-30 15:46:42 +00:00
2021-05-15 22:41:42 +00:00
$webhook = new Document ([
2022-08-14 14:22:38 +00:00
'$id' => ID :: unique (),
2022-08-02 09:21:53 +00:00
'$permissions' => [
2022-08-14 05:21:11 +00:00
Permission :: read ( Role :: any ()),
Permission :: update ( Role :: any ()),
Permission :: delete ( Role :: any ()),
2022-08-02 09:21:53 +00:00
],
2025-05-26 05:42:11 +00:00
'projectInternalId' => $project -> getSequence (),
2021-08-30 14:24:50 +00:00
'projectId' => $project -> getId (),
2020-06-30 15:46:42 +00:00
'name' => $name ,
'events' => $events ,
'url' => $url ,
2020-07-09 09:11:42 +00:00
'security' => $security ,
2020-06-30 15:46:42 +00:00
'httpUser' => $httpUser ,
'httpPass' => $httpPass ,
2022-06-07 15:11:07 +00:00
'signatureKey' => \bin2hex ( \random_bytes ( 64 )),
2024-01-02 10:47:02 +00:00
'enabled' => $enabled ,
2020-06-30 15:46:42 +00:00
]);
2024-12-12 10:30:26 +00:00
$webhook = $dbForPlatform -> createDocument ( 'webhooks' , $webhook );
2021-08-30 14:24:50 +00:00
2024-12-12 10:30:26 +00:00
$dbForPlatform -> purgeCachedDocument ( 'projects' , $project -> getId ());
2020-06-30 15:46:42 +00:00
2022-09-07 11:02:36 +00:00
$response
-> setStatusCode ( Response :: STATUS_CODE_CREATED )
-> dynamic ( $webhook , Response :: MODEL_WEBHOOK );
2020-12-26 16:33:36 +00:00
});
2020-01-31 22:34:07 +00:00
2024-10-08 07:54:40 +00:00
App :: get ( '/v1/projects/:projectId/webhooks' )
2023-08-01 15:26:48 +00:00
-> desc ( 'List webhooks' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'projects' ])
2019-12-18 10:24:54 +00:00
-> label ( 'scope' , 'projects.read' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'webhooks' ,
2025-01-17 04:31:39 +00:00
name : 'listWebhooks' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/list-webhooks.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_WEBHOOK_LIST ,
)
]
))
2020-09-10 14:40:14 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
2020-12-26 16:33:36 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2019-12-18 10:24:54 +00:00
2021-05-15 22:41:42 +00:00
if ( $project -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
2020-06-30 15:46:42 +00:00
}
2019-12-18 10:24:54 +00:00
2024-12-12 10:30:26 +00:00
$webhooks = $dbForPlatform -> find ( 'webhooks' , [
2025-05-26 05:42:11 +00:00
Query :: equal ( 'projectInternalId' , [ $project -> getSequence ()]),
2022-08-11 23:53:52 +00:00
Query :: limit ( 5000 ),
]);
2019-12-18 10:24:54 +00:00
2021-07-25 14:47:18 +00:00
$response -> dynamic ( new Document ([
2021-05-27 10:09:14 +00:00
'webhooks' => $webhooks ,
2022-02-27 09:57:09 +00:00
'total' => count ( $webhooks ),
2020-08-14 21:56:50 +00:00
]), Response :: MODEL_WEBHOOK_LIST );
2020-12-26 16:33:36 +00:00
});
2019-12-18 10:24:54 +00:00
2024-10-08 07:54:40 +00:00
App :: get ( '/v1/projects/:projectId/webhooks/:webhookId' )
2023-08-01 15:26:48 +00:00
-> desc ( 'Get webhook' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'projects' ])
2019-12-18 10:24:54 +00:00
-> label ( 'scope' , 'projects.read' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'webhooks' ,
2025-01-17 04:31:39 +00:00
name : 'getWebhook' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/get-webhook.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_WEBHOOK ,
)
]
))
2022-09-19 10:05:42 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
-> param ( 'webhookId' , '' , new UID (), 'Webhook unique ID.' )
2020-12-26 16:33:36 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , string $webhookId , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2019-12-18 10:24:54 +00:00
2021-05-15 22:41:42 +00:00
if ( $project -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
2020-06-30 15:46:42 +00:00
}
2019-12-18 10:24:54 +00:00
2024-12-12 10:30:26 +00:00
$webhook = $dbForPlatform -> findOne ( 'webhooks' , [
2023-05-03 11:53:40 +00:00
Query :: equal ( '$id' , [ $webhookId ]),
2025-05-26 05:42:11 +00:00
Query :: equal ( 'projectInternalId' , [ $project -> getSequence ()]),
2021-09-01 08:25:54 +00:00
]);
2019-12-18 10:24:54 +00:00
2024-10-31 08:13:23 +00:00
if ( $webhook -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: WEBHOOK_NOT_FOUND );
2020-06-30 15:46:42 +00:00
}
2019-12-18 10:24:54 +00:00
2021-07-25 14:47:18 +00:00
$response -> dynamic ( $webhook , Response :: MODEL_WEBHOOK );
2020-12-26 16:33:36 +00:00
});
2019-12-18 10:24:54 +00:00
2024-10-08 07:54:40 +00:00
App :: put ( '/v1/projects/:projectId/webhooks/:webhookId' )
2023-08-01 15:26:48 +00:00
-> desc ( 'Update webhook' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'projects' ])
2019-12-18 10:24:54 +00:00
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'webhooks' ,
2025-01-17 04:31:39 +00:00
name : 'updateWebhook' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/update-webhook.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_WEBHOOK ,
)
]
))
2022-09-19 10:05:42 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
-> param ( 'webhookId' , '' , new UID (), 'Webhook unique ID.' )
2020-09-10 14:40:14 +00:00
-> param ( 'name' , null , new Text ( 128 ), 'Webhook name. Max length: 128 chars.' )
2024-01-18 09:49:57 +00:00
-> param ( 'enabled' , true , new Boolean ( true ), 'Enable or disable a webhook.' , true )
2022-05-12 18:41:04 +00:00
-> param ( 'events' , null , new ArrayList ( new Event (), APP_LIMIT_ARRAY_PARAMS_SIZE ), 'Events list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.' )
2024-06-07 00:54:51 +00:00
-> param ( 'url' , '' , fn ( $request ) => new Multiple ([ new URL ([ 'http' , 'https' ]), new PublicDomain ()], Multiple :: TYPE_STRING ), 'Webhook URL.' , false , [ 'request' ])
2020-09-10 14:40:14 +00:00
-> param ( 'security' , false , new Boolean ( true ), 'Certificate verification, false for disabled or true for enabled.' )
-> param ( 'httpUser' , '' , new Text ( 256 ), 'Webhook HTTP user. Max length: 256 chars.' , true )
-> param ( 'httpPass' , '' , new Text ( 256 ), 'Webhook HTTP password. Max length: 256 chars.' , true )
2020-12-26 16:33:36 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , string $webhookId , string $name , bool $enabled , array $events , string $url , bool $security , string $httpUser , string $httpPass , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2019-12-18 10:24:54 +00:00
2021-05-15 22:41:42 +00:00
if ( $project -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
2020-06-30 15:46:42 +00:00
}
2019-12-18 10:24:54 +00:00
2020-06-30 15:46:42 +00:00
$security = ( $security === '1' || $security === 'true' || $security === 1 || $security === true );
2024-12-12 10:30:26 +00:00
$webhook = $dbForPlatform -> findOne ( 'webhooks' , [
2023-05-03 11:53:40 +00:00
Query :: equal ( '$id' , [ $webhookId ]),
2025-05-26 05:42:11 +00:00
Query :: equal ( 'projectInternalId' , [ $project -> getSequence ()]),
2021-09-01 08:25:54 +00:00
]);
2020-06-30 15:46:42 +00:00
2024-10-31 08:13:23 +00:00
if ( $webhook -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: WEBHOOK_NOT_FOUND );
2020-06-30 15:46:42 +00:00
}
2019-12-18 10:24:54 +00:00
2021-08-30 14:24:50 +00:00
$webhook
-> setAttribute ( 'name' , $name )
-> setAttribute ( 'events' , $events )
-> setAttribute ( 'url' , $url )
-> setAttribute ( 'security' , $security )
-> setAttribute ( 'httpUser' , $httpUser )
2023-11-14 08:50:26 +00:00
-> setAttribute ( 'httpPass' , $httpPass )
2024-01-02 10:47:02 +00:00
-> setAttribute ( 'enabled' , $enabled );
if ( $enabled ) {
$webhook -> setAttribute ( 'attempts' , 0 );
}
2020-06-30 15:46:42 +00:00
2024-12-12 10:30:26 +00:00
$dbForPlatform -> updateDocument ( 'webhooks' , $webhook -> getId (), $webhook );
$dbForPlatform -> purgeCachedDocument ( 'projects' , $project -> getId ());
2022-06-20 18:35:33 +00:00
$response -> dynamic ( $webhook , Response :: MODEL_WEBHOOK );
});
2024-10-08 07:54:40 +00:00
App :: patch ( '/v1/projects/:projectId/webhooks/:webhookId/signature' )
2023-08-01 15:26:48 +00:00
-> desc ( 'Update webhook signature key' )
2022-06-20 18:35:33 +00:00
-> groups ([ 'api' , 'projects' ])
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'webhooks' ,
2025-01-17 04:31:39 +00:00
name : 'updateWebhookSignature' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/update-webhook-signature.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_WEBHOOK ,
)
]
))
2022-09-19 10:05:42 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
-> param ( 'webhookId' , '' , new UID (), 'Webhook unique ID.' )
2022-06-20 18:35:33 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , string $webhookId , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2022-06-20 18:35:33 +00:00
if ( $project -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
2022-06-08 07:19:50 +00:00
}
2020-06-30 15:46:42 +00:00
2024-12-12 10:30:26 +00:00
$webhook = $dbForPlatform -> findOne ( 'webhooks' , [
2023-05-03 11:53:40 +00:00
Query :: equal ( '$id' , [ $webhookId ]),
2025-05-26 05:42:11 +00:00
Query :: equal ( 'projectInternalId' , [ $project -> getSequence ()]),
2022-06-20 18:35:33 +00:00
]);
2024-10-31 08:13:23 +00:00
if ( $webhook -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: WEBHOOK_NOT_FOUND );
2022-06-20 18:35:33 +00:00
}
$webhook -> setAttribute ( 'signatureKey' , \bin2hex ( \random_bytes ( 64 )));
2024-12-12 10:30:26 +00:00
$dbForPlatform -> updateDocument ( 'webhooks' , $webhook -> getId (), $webhook );
$dbForPlatform -> purgeCachedDocument ( 'projects' , $project -> getId ());
2021-06-07 05:17:29 +00:00
2021-07-25 14:47:18 +00:00
$response -> dynamic ( $webhook , Response :: MODEL_WEBHOOK );
2020-12-26 16:33:36 +00:00
});
2019-12-18 10:24:54 +00:00
2024-10-08 07:54:40 +00:00
App :: delete ( '/v1/projects/:projectId/webhooks/:webhookId' )
2023-08-01 15:26:48 +00:00
-> desc ( 'Delete webhook' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'projects' ])
2019-12-18 10:24:54 +00:00
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'webhooks' ,
2025-01-17 04:31:39 +00:00
name : 'deleteWebhook' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/delete-webhook.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_NOCONTENT ,
model : Response :: MODEL_NONE ,
)
],
contentType : ContentType :: NONE
))
2022-09-19 10:05:42 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
-> param ( 'webhookId' , '' , new UID (), 'Webhook unique ID.' )
2020-12-26 16:33:36 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , string $webhookId , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2019-12-18 10:24:54 +00:00
2021-05-15 22:41:42 +00:00
if ( $project -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
2020-06-30 15:46:42 +00:00
}
2019-12-18 10:24:54 +00:00
2024-12-12 10:30:26 +00:00
$webhook = $dbForPlatform -> findOne ( 'webhooks' , [
2023-05-03 11:53:40 +00:00
Query :: equal ( '$id' , [ $webhookId ]),
2025-05-26 05:42:11 +00:00
Query :: equal ( 'projectInternalId' , [ $project -> getSequence ()]),
2021-09-01 08:25:54 +00:00
]);
2021-08-30 14:24:50 +00:00
2024-10-31 08:13:23 +00:00
if ( $webhook -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: WEBHOOK_NOT_FOUND );
2020-06-30 15:46:42 +00:00
}
2019-12-18 10:24:54 +00:00
2024-12-12 10:30:26 +00:00
$dbForPlatform -> deleteDocument ( 'webhooks' , $webhook -> getId ());
2021-08-30 14:24:50 +00:00
2024-12-12 10:30:26 +00:00
$dbForPlatform -> purgeCachedDocument ( 'projects' , $project -> getId ());
2020-06-30 15:46:42 +00:00
$response -> noContent ();
2020-12-26 16:33:36 +00:00
});
2019-12-18 10:24:54 +00:00
// Keys
2024-10-08 07:54:40 +00:00
App :: post ( '/v1/projects/:projectId/keys' )
2023-08-01 15:26:48 +00:00
-> desc ( 'Create key' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'projects' ])
2024-09-04 01:51:32 +00:00
-> label ( 'scope' , 'keys.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'keys' ,
2025-01-17 04:31:39 +00:00
name : 'createKey' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/create-key.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_CREATED ,
model : Response :: MODEL_KEY ,
)
]
))
2022-09-19 10:05:42 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
2020-09-10 14:40:14 +00:00
-> param ( 'name' , null , new Text ( 128 ), 'Key name. Max length: 128 chars.' )
2022-05-01 07:54:58 +00:00
-> param ( 'scopes' , null , new ArrayList ( new WhiteList ( array_keys ( Config :: getParam ( 'scopes' )), true ), APP_LIMIT_ARRAY_PARAMS_SIZE ), 'Key scopes list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed.' )
2023-11-09 09:23:42 +00:00
-> param ( 'expire' , null , new DatetimeValidator (), 'Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration.' , true )
2020-12-26 16:33:36 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , string $name , array $scopes , ? string $expire , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2019-12-18 10:24:54 +00:00
2021-05-15 22:41:42 +00:00
if ( $project -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
2020-06-30 15:46:42 +00:00
}
2019-12-18 10:24:54 +00:00
2021-05-15 22:41:42 +00:00
$key = new Document ([
2022-08-14 14:22:38 +00:00
'$id' => ID :: unique (),
2022-08-02 09:21:53 +00:00
'$permissions' => [
2022-08-14 05:21:11 +00:00
Permission :: read ( Role :: any ()),
Permission :: update ( Role :: any ()),
Permission :: delete ( Role :: any ()),
2022-08-02 09:21:53 +00:00
],
2025-05-26 05:42:11 +00:00
'projectInternalId' => $project -> getSequence (),
2021-08-30 14:24:50 +00:00
'projectId' => $project -> getId (),
2020-06-30 15:46:42 +00:00
'name' => $name ,
'scopes' => $scopes ,
2022-05-31 15:41:12 +00:00
'expire' => $expire ,
2022-08-05 10:20:48 +00:00
'sdks' => [],
2022-08-19 09:54:26 +00:00
'accessedAt' => null ,
2024-05-16 08:39:15 +00:00
'secret' => API_KEY_STANDARD . '_' . \bin2hex ( \random_bytes ( 128 )),
2020-06-30 15:46:42 +00:00
]);
2024-12-12 10:30:26 +00:00
$key = $dbForPlatform -> createDocument ( 'keys' , $key );
2021-08-30 14:24:50 +00:00
2024-12-12 10:30:26 +00:00
$dbForPlatform -> purgeCachedDocument ( 'projects' , $project -> getId ());
2020-06-30 15:46:42 +00:00
2022-09-07 11:02:36 +00:00
$response
-> setStatusCode ( Response :: STATUS_CODE_CREATED )
-> dynamic ( $key , Response :: MODEL_KEY );
2020-12-26 16:33:36 +00:00
});
2019-12-18 10:24:54 +00:00
2024-10-08 07:54:40 +00:00
App :: get ( '/v1/projects/:projectId/keys' )
2023-08-01 15:26:48 +00:00
-> desc ( 'List keys' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'projects' ])
2024-09-04 01:51:32 +00:00
-> label ( 'scope' , 'keys.read' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'keys' ,
2025-01-17 04:31:39 +00:00
name : 'listKeys' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/list-keys.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_KEY_LIST ,
)
]
))
2022-09-19 10:05:42 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
2020-12-26 16:33:36 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2020-06-30 15:46:42 +00:00
2021-05-15 22:41:42 +00:00
if ( $project -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
2020-01-31 22:34:07 +00:00
}
2020-06-30 15:46:42 +00:00
2024-12-12 10:30:26 +00:00
$keys = $dbForPlatform -> find ( 'keys' , [
2025-05-26 05:42:11 +00:00
Query :: equal ( 'projectInternalId' , [ $project -> getSequence ()]),
2022-08-11 23:53:52 +00:00
Query :: limit ( 5000 ),
]);
2020-08-14 21:56:50 +00:00
2021-07-25 14:47:18 +00:00
$response -> dynamic ( new Document ([
2021-05-27 10:09:14 +00:00
'keys' => $keys ,
2022-02-27 09:57:09 +00:00
'total' => count ( $keys ),
2020-08-14 21:56:50 +00:00
]), Response :: MODEL_KEY_LIST );
2020-12-26 16:33:36 +00:00
});
2020-01-31 22:34:07 +00:00
2024-10-08 07:54:40 +00:00
App :: get ( '/v1/projects/:projectId/keys/:keyId' )
2023-08-01 15:26:48 +00:00
-> desc ( 'Get key' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'projects' ])
2024-09-04 01:51:32 +00:00
-> label ( 'scope' , 'keys.read' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'keys' ,
2025-01-17 04:31:39 +00:00
name : 'getKey' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/get-key.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_KEY ,
)
]
))
2022-09-19 10:05:42 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
-> param ( 'keyId' , '' , new UID (), 'Key unique ID.' )
2020-12-26 16:33:36 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , string $keyId , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2020-01-31 22:34:07 +00:00
2021-05-15 22:41:42 +00:00
if ( $project -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
2020-06-30 15:46:42 +00:00
}
2020-01-31 22:34:07 +00:00
2024-12-12 10:30:26 +00:00
$key = $dbForPlatform -> findOne ( 'keys' , [
2023-05-03 11:53:40 +00:00
Query :: equal ( '$id' , [ $keyId ]),
2025-05-26 05:42:11 +00:00
Query :: equal ( 'projectInternalId' , [ $project -> getSequence ()]),
2021-09-01 08:25:54 +00:00
]);
2020-01-31 22:34:07 +00:00
2024-10-31 08:13:23 +00:00
if ( $key -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: KEY_NOT_FOUND );
2020-01-31 22:34:07 +00:00
}
2020-06-30 15:46:42 +00:00
2021-07-25 14:47:18 +00:00
$response -> dynamic ( $key , Response :: MODEL_KEY );
2020-12-26 16:33:36 +00:00
});
2020-01-31 22:34:07 +00:00
2024-10-08 07:54:40 +00:00
App :: put ( '/v1/projects/:projectId/keys/:keyId' )
2023-08-01 15:26:48 +00:00
-> desc ( 'Update key' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'projects' ])
2024-09-04 01:51:32 +00:00
-> label ( 'scope' , 'keys.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'keys' ,
2025-01-17 04:31:39 +00:00
name : 'updateKey' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/update-key.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_KEY ,
)
]
))
2022-09-19 10:05:42 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
-> param ( 'keyId' , '' , new UID (), 'Key unique ID.' )
2020-09-10 14:40:14 +00:00
-> param ( 'name' , null , new Text ( 128 ), 'Key name. Max length: 128 chars.' )
2022-05-01 07:54:58 +00:00
-> param ( 'scopes' , null , new ArrayList ( new WhiteList ( array_keys ( Config :: getParam ( 'scopes' )), true ), APP_LIMIT_ARRAY_PARAMS_SIZE ), 'Key scopes list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.' )
2023-11-09 09:23:42 +00:00
-> param ( 'expire' , null , new DatetimeValidator (), 'Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration.' , true )
2020-12-26 16:33:36 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , string $keyId , string $name , array $scopes , ? string $expire , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2019-12-18 10:24:54 +00:00
2021-05-15 22:41:42 +00:00
if ( $project -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
2020-06-30 15:46:42 +00:00
}
2019-12-18 10:24:54 +00:00
2024-12-12 10:30:26 +00:00
$key = $dbForPlatform -> findOne ( 'keys' , [
2023-05-03 11:53:40 +00:00
Query :: equal ( '$id' , [ $keyId ]),
2025-05-26 05:42:11 +00:00
Query :: equal ( 'projectInternalId' , [ $project -> getSequence ()]),
2021-09-01 08:25:54 +00:00
]);
2019-12-18 10:24:54 +00:00
2024-10-31 08:13:23 +00:00
if ( $key -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: KEY_NOT_FOUND );
2020-06-30 15:46:42 +00:00
}
2019-12-18 10:24:54 +00:00
2021-09-14 06:57:55 +00:00
$key
-> setAttribute ( 'name' , $name )
-> setAttribute ( 'scopes' , $scopes )
2023-08-28 12:19:37 +00:00
-> setAttribute ( 'expire' , $expire );
2019-12-18 10:24:54 +00:00
2024-12-12 10:30:26 +00:00
$dbForPlatform -> updateDocument ( 'keys' , $key -> getId (), $key );
2019-12-18 10:24:54 +00:00
2024-12-12 10:30:26 +00:00
$dbForPlatform -> purgeCachedDocument ( 'projects' , $project -> getId ());
2021-06-07 05:17:29 +00:00
2021-07-25 14:47:18 +00:00
$response -> dynamic ( $key , Response :: MODEL_KEY );
2020-12-26 16:33:36 +00:00
});
2019-12-18 10:24:54 +00:00
2024-10-08 07:54:40 +00:00
App :: delete ( '/v1/projects/:projectId/keys/:keyId' )
2023-08-01 15:26:48 +00:00
-> desc ( 'Delete key' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'projects' ])
2024-09-04 01:51:32 +00:00
-> label ( 'scope' , 'keys.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'keys' ,
2025-01-17 04:31:39 +00:00
name : 'deleteKey' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/delete-key.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_NOCONTENT ,
model : Response :: MODEL_NONE ,
)
],
contentType : ContentType :: NONE
))
2022-09-19 10:05:42 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
-> param ( 'keyId' , '' , new UID (), 'Key unique ID.' )
2020-12-26 16:33:36 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , string $keyId , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2019-12-18 10:24:54 +00:00
2021-05-15 22:41:42 +00:00
if ( $project -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
2020-06-30 15:46:42 +00:00
}
2019-12-18 10:24:54 +00:00
2024-12-12 10:30:26 +00:00
$key = $dbForPlatform -> findOne ( 'keys' , [
2023-05-03 11:53:40 +00:00
Query :: equal ( '$id' , [ $keyId ]),
2025-05-26 05:42:11 +00:00
Query :: equal ( 'projectInternalId' , [ $project -> getSequence ()]),
2021-09-01 08:25:54 +00:00
]);
2021-08-30 14:24:50 +00:00
2024-10-31 08:13:23 +00:00
if ( $key -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: KEY_NOT_FOUND );
2020-06-30 15:46:42 +00:00
}
2019-12-18 10:24:54 +00:00
2024-12-12 10:30:26 +00:00
$dbForPlatform -> deleteDocument ( 'keys' , $key -> getId ());
2021-08-30 14:24:50 +00:00
2024-12-12 10:30:26 +00:00
$dbForPlatform -> purgeCachedDocument ( 'projects' , $project -> getId ());
2020-06-30 15:46:42 +00:00
$response -> noContent ();
2020-12-26 16:33:36 +00:00
});
2019-12-18 10:24:54 +00:00
2024-05-29 08:57:25 +00:00
// JWT Keys
2024-10-08 07:54:40 +00:00
App :: post ( '/v1/projects/:projectId/jwts' )
2024-05-29 08:57:25 +00:00
-> groups ([ 'api' , 'projects' ])
-> desc ( 'Create JWT' )
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'auth' ,
2025-01-17 04:31:39 +00:00
name : 'createJWT' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/create-jwt.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_CREATED ,
model : Response :: MODEL_JWT ,
)
]
))
2024-05-29 08:57:25 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
-> param ( 'scopes' , [], new ArrayList ( new WhiteList ( array_keys ( Config :: getParam ( 'scopes' )), true ), APP_LIMIT_ARRAY_PARAMS_SIZE ), 'List of scopes allowed for JWT key. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed.' )
-> param ( 'duration' , 900 , new Range ( 0 , 3600 ), 'Time in seconds before JWT expires. Default duration is 900 seconds, and maximum is 3600 seconds.' , true )
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , array $scopes , int $duration , Response $response , Database $dbForPlatform ) {
2024-05-29 08:57:25 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2024-05-29 08:57:25 +00:00
if ( $project -> isEmpty ()) {
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
}
$jwt = new JWT ( System :: getEnv ( '_APP_OPENSSL_KEY_V1' ), 'HS256' , $duration , 0 );
$response
-> setStatusCode ( Response :: STATUS_CODE_CREATED )
-> dynamic ( new Document ([ 'jwt' => API_KEY_DYNAMIC . '_' . $jwt -> encode ([
'projectId' => $project -> getId (),
'scopes' => $scopes
])]), Response :: MODEL_JWT );
});
2019-12-18 10:24:54 +00:00
// Platforms
2024-10-08 07:54:40 +00:00
App :: post ( '/v1/projects/:projectId/platforms' )
2023-08-01 15:26:48 +00:00
-> desc ( 'Create platform' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'projects' ])
2024-07-22 08:03:53 +00:00
-> label ( 'audits.event' , 'platforms.create' )
2024-12-02 09:47:17 +00:00
-> label ( 'audits.resource' , 'project/{request.projectId}' )
2024-09-04 01:51:32 +00:00
-> label ( 'scope' , 'platforms.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'platforms' ,
2025-01-17 04:31:39 +00:00
name : 'createPlatform' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/create-platform.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_CREATED ,
model : Response :: MODEL_PLATFORM ,
)
]
))
2022-09-19 10:05:42 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
2025-04-14 11:56:42 +00:00
-> param ( 'type' , null , new WhiteList ([ Platform :: TYPE_WEB , Platform :: TYPE_FLUTTER_WEB , Platform :: TYPE_FLUTTER_IOS , Platform :: TYPE_FLUTTER_ANDROID , Platform :: TYPE_FLUTTER_LINUX , Platform :: TYPE_FLUTTER_MACOS , Platform :: TYPE_FLUTTER_WINDOWS , Platform :: TYPE_APPLE_IOS , Platform :: TYPE_APPLE_MACOS , Platform :: TYPE_APPLE_WATCHOS , Platform :: TYPE_APPLE_TVOS , Platform :: TYPE_ANDROID , Platform :: TYPE_UNITY , Platform :: TYPE_REACT_NATIVE_IOS , Platform :: TYPE_REACT_NATIVE_ANDROID ], true ), 'Platform type.' )
2020-09-10 14:40:14 +00:00
-> param ( 'name' , null , new Text ( 128 ), 'Platform name. Max length: 128 chars.' )
2021-09-28 10:24:54 +00:00
-> param ( 'key' , '' , new Text ( 256 ), 'Package name for Android or bundle ID for iOS or macOS. Max length: 256 chars.' , true )
2020-09-10 14:40:14 +00:00
-> param ( 'store' , '' , new Text ( 256 ), 'App store or Google Play store ID. Max length: 256 chars.' , true )
2022-05-12 18:53:54 +00:00
-> param ( 'hostname' , '' , new Hostname (), 'Platform client hostname. Max length: 256 chars.' , true )
2020-12-26 16:33:36 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , string $type , string $name , string $key , string $store , string $hostname , Response $response , Database $dbForPlatform ) {
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2019-12-18 10:24:54 +00:00
2021-05-15 22:41:42 +00:00
if ( $project -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
2020-06-30 15:46:42 +00:00
}
2019-12-18 10:24:54 +00:00
2021-05-15 22:41:42 +00:00
$platform = new Document ([
2022-08-14 14:22:38 +00:00
'$id' => ID :: unique (),
2022-08-02 09:21:53 +00:00
'$permissions' => [
2022-08-15 10:11:17 +00:00
Permission :: read ( Role :: any ()),
Permission :: update ( Role :: any ()),
Permission :: delete ( Role :: any ()),
2022-08-02 09:21:53 +00:00
],
2025-05-26 05:42:11 +00:00
'projectInternalId' => $project -> getSequence (),
2021-08-30 14:24:50 +00:00
'projectId' => $project -> getId (),
2020-06-30 15:46:42 +00:00
'type' => $type ,
'name' => $name ,
'key' => $key ,
'store' => $store ,
2022-06-15 12:46:52 +00:00
'hostname' => $hostname
2020-06-30 15:46:42 +00:00
]);
2024-12-12 10:30:26 +00:00
$platform = $dbForPlatform -> createDocument ( 'platforms' , $platform );
2021-08-30 14:24:50 +00:00
2024-12-12 10:30:26 +00:00
$dbForPlatform -> purgeCachedDocument ( 'projects' , $project -> getId ());
2020-06-30 15:46:42 +00:00
2022-09-07 11:02:36 +00:00
$response
-> setStatusCode ( Response :: STATUS_CODE_CREATED )
-> dynamic ( $platform , Response :: MODEL_PLATFORM );
2020-12-26 16:33:36 +00:00
});
2021-06-07 05:17:29 +00:00
2024-10-08 07:54:40 +00:00
App :: get ( '/v1/projects/:projectId/platforms' )
2023-08-01 15:26:48 +00:00
-> desc ( 'List platforms' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'projects' ])
2024-09-04 01:51:32 +00:00
-> label ( 'scope' , 'platforms.read' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'platforms' ,
2025-01-17 04:31:39 +00:00
name : 'listPlatforms' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/list-platforms.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_PLATFORM_LIST ,
)
]
))
2020-09-10 14:40:14 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
2020-12-26 16:33:36 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2020-01-31 22:34:07 +00:00
2021-05-15 22:41:42 +00:00
if ( $project -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
2020-01-31 22:34:07 +00:00
}
2020-06-30 15:46:42 +00:00
2024-12-12 10:30:26 +00:00
$platforms = $dbForPlatform -> find ( 'platforms' , [
2025-05-26 05:42:11 +00:00
Query :: equal ( 'projectInternalId' , [ $project -> getSequence ()]),
2022-08-11 23:53:52 +00:00
Query :: limit ( 5000 ),
]);
2020-06-30 15:46:42 +00:00
2021-07-25 14:47:18 +00:00
$response -> dynamic ( new Document ([
2021-05-27 10:09:14 +00:00
'platforms' => $platforms ,
2022-02-27 09:57:09 +00:00
'total' => count ( $platforms ),
2020-08-14 21:56:50 +00:00
]), Response :: MODEL_PLATFORM_LIST );
2020-12-26 16:33:36 +00:00
});
2020-01-31 22:34:07 +00:00
2024-10-08 07:54:40 +00:00
App :: get ( '/v1/projects/:projectId/platforms/:platformId' )
2023-08-01 15:26:48 +00:00
-> desc ( 'Get platform' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'projects' ])
2024-09-04 01:51:32 +00:00
-> label ( 'scope' , 'platforms.read' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'platforms' ,
2025-01-17 04:31:39 +00:00
name : 'getPlatform' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/get-platform.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_PLATFORM ,
)
]
))
2022-09-19 10:05:42 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
-> param ( 'platformId' , '' , new UID (), 'Platform unique ID.' )
2020-12-26 16:33:36 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , string $platformId , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2020-01-31 22:34:07 +00:00
2021-05-15 22:41:42 +00:00
if ( $project -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
2020-06-30 15:46:42 +00:00
}
2020-01-31 22:34:07 +00:00
2024-12-12 10:30:26 +00:00
$platform = $dbForPlatform -> findOne ( 'platforms' , [
2023-05-03 11:53:40 +00:00
Query :: equal ( '$id' , [ $platformId ]),
2025-05-26 05:42:11 +00:00
Query :: equal ( 'projectInternalId' , [ $project -> getSequence ()]),
2021-09-01 08:25:54 +00:00
]);
2020-01-31 22:34:07 +00:00
2024-10-31 08:13:23 +00:00
if ( $platform -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: PLATFORM_NOT_FOUND );
2020-01-31 22:34:07 +00:00
}
2020-06-30 15:46:42 +00:00
2021-07-25 14:47:18 +00:00
$response -> dynamic ( $platform , Response :: MODEL_PLATFORM );
2020-12-26 16:33:36 +00:00
});
2019-12-18 10:24:54 +00:00
2024-10-08 07:54:40 +00:00
App :: put ( '/v1/projects/:projectId/platforms/:platformId' )
2023-08-01 15:26:48 +00:00
-> desc ( 'Update platform' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'projects' ])
2024-09-04 01:51:32 +00:00
-> label ( 'scope' , 'platforms.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'platforms' ,
2025-01-17 04:31:39 +00:00
name : 'updatePlatform' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/update-platform.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_PLATFORM ,
)
]
))
2022-09-19 10:05:42 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
-> param ( 'platformId' , '' , new UID (), 'Platform unique ID.' )
2020-09-10 14:40:14 +00:00
-> param ( 'name' , null , new Text ( 128 ), 'Platform name. Max length: 128 chars.' )
-> param ( 'key' , '' , new Text ( 256 ), 'Package name for android or bundle ID for iOS. Max length: 256 chars.' , true )
-> param ( 'store' , '' , new Text ( 256 ), 'App store or Google Play store ID. Max length: 256 chars.' , true )
2022-05-12 18:53:54 +00:00
-> param ( 'hostname' , '' , new Hostname (), 'Platform client URL. Max length: 256 chars.' , true )
2020-12-26 16:33:36 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , string $platformId , string $name , string $key , string $store , string $hostname , Response $response , Database $dbForPlatform ) {
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2019-12-18 10:24:54 +00:00
2021-05-15 22:41:42 +00:00
if ( $project -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
2020-06-30 15:46:42 +00:00
}
2019-12-18 10:24:54 +00:00
2024-12-12 10:30:26 +00:00
$platform = $dbForPlatform -> findOne ( 'platforms' , [
2023-05-03 11:53:40 +00:00
Query :: equal ( '$id' , [ $platformId ]),
2025-05-26 05:42:11 +00:00
Query :: equal ( 'projectInternalId' , [ $project -> getSequence ()]),
2021-09-01 08:25:54 +00:00
]);
2019-12-18 10:24:54 +00:00
2024-10-31 08:13:23 +00:00
if ( $platform -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: PLATFORM_NOT_FOUND );
2020-06-30 15:46:42 +00:00
}
2019-12-18 10:24:54 +00:00
2020-06-30 15:46:42 +00:00
$platform
-> setAttribute ( 'name' , $name )
-> setAttribute ( 'key' , $key )
-> setAttribute ( 'store' , $store )
2023-08-28 12:19:37 +00:00
-> setAttribute ( 'hostname' , $hostname );
2019-12-18 10:24:54 +00:00
2024-12-12 10:30:26 +00:00
$dbForPlatform -> updateDocument ( 'platforms' , $platform -> getId (), $platform );
2020-06-30 15:46:42 +00:00
2024-12-12 10:30:26 +00:00
$dbForPlatform -> purgeCachedDocument ( 'projects' , $project -> getId ());
2021-05-15 22:41:42 +00:00
2021-07-25 14:47:18 +00:00
$response -> dynamic ( $platform , Response :: MODEL_PLATFORM );
2020-12-26 16:33:36 +00:00
});
2019-12-18 10:24:54 +00:00
2024-10-08 07:54:40 +00:00
App :: delete ( '/v1/projects/:projectId/platforms/:platformId' )
2023-08-01 15:26:48 +00:00
-> desc ( 'Delete platform' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'projects' ])
2024-07-22 08:03:53 +00:00
-> label ( 'audits.event' , 'platforms.delete' )
2024-12-02 09:47:17 +00:00
-> label ( 'audits.resource' , 'project/{request.projectId}/platform/${request.platformId}' )
2024-09-04 01:51:32 +00:00
-> label ( 'scope' , 'platforms.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'platforms' ,
2025-01-17 04:31:39 +00:00
name : 'deletePlatform' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/delete-platform.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_NOCONTENT ,
model : Response :: MODEL_NONE ,
)
],
contentType : ContentType :: NONE
))
2022-09-19 10:05:42 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
-> param ( 'platformId' , '' , new UID (), 'Platform unique ID.' )
2020-12-26 16:33:36 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , string $platformId , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2019-12-18 10:24:54 +00:00
2021-05-15 22:41:42 +00:00
if ( $project -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
2020-06-30 15:46:42 +00:00
}
2019-12-18 10:24:54 +00:00
2024-12-12 10:30:26 +00:00
$platform = $dbForPlatform -> findOne ( 'platforms' , [
2023-05-03 11:53:40 +00:00
Query :: equal ( '$id' , [ $platformId ]),
2025-05-26 05:42:11 +00:00
Query :: equal ( 'projectInternalId' , [ $project -> getSequence ()]),
2021-09-01 08:25:54 +00:00
]);
2021-08-30 07:33:45 +00:00
2024-10-31 08:13:23 +00:00
if ( $platform -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: PLATFORM_NOT_FOUND );
2020-06-30 15:46:42 +00:00
}
2019-12-18 10:24:54 +00:00
2024-12-12 10:30:26 +00:00
$dbForPlatform -> deleteDocument ( 'platforms' , $platformId );
2021-09-01 08:25:54 +00:00
2024-12-12 10:30:26 +00:00
$dbForPlatform -> purgeCachedDocument ( 'projects' , $project -> getId ());
2020-06-30 15:46:42 +00:00
$response -> noContent ();
2020-12-26 16:33:36 +00:00
});
2020-02-22 08:10:30 +00:00
2023-03-09 01:59:10 +00:00
// CUSTOM SMTP and Templates
2024-10-08 07:54:40 +00:00
App :: patch ( '/v1/projects/:projectId/smtp' )
2023-12-19 15:08:09 +00:00
-> desc ( 'Update SMTP' )
2023-03-09 01:59:10 +00:00
-> groups ([ 'api' , 'projects' ])
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'templates' ,
2025-01-17 04:31:39 +00:00
name : 'updateSmtp' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/update-smtp.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_PROJECT ,
)
]
))
2023-03-09 01:59:10 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
-> param ( 'enabled' , false , new Boolean (), 'Enable custom SMTP service' )
2023-08-28 14:08:50 +00:00
-> param ( 'senderName' , '' , new Text ( 255 , 0 ), 'Name of the email sender' , true )
2023-08-28 12:19:37 +00:00
-> param ( 'senderEmail' , '' , new Email (), 'Email of the sender' , true )
-> param ( 'replyTo' , '' , new Email (), 'Reply to email' , true )
-> param ( 'host' , '' , new HostName (), 'SMTP server host name' , true )
-> param ( 'port' , 587 , new Integer (), 'SMTP server port' , true )
2023-08-30 05:31:02 +00:00
-> param ( 'username' , '' , new Text ( 0 , 0 ), 'SMTP server username' , true )
-> param ( 'password' , '' , new Text ( 0 , 0 ), 'SMTP server password' , true )
2024-02-26 15:10:41 +00:00
-> param ( 'secure' , '' , new WhiteList ([ 'tls' , 'ssl' ], true ), 'Does SMTP server use secure connection' , true )
2023-03-09 01:59:10 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , bool $enabled , string $senderName , string $senderEmail , string $replyTo , string $host , int $port , string $username , string $password , string $secure , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2023-03-09 01:59:10 +00:00
if ( $project -> isEmpty ()) {
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
}
2023-08-28 12:19:37 +00:00
// Ensure required params for when enabling SMTP
if ( $enabled ) {
if ( empty ( $senderName )) {
throw new Exception ( Exception :: GENERAL_ARGUMENT_INVALID , 'Sender name is required when enabling SMTP.' );
2023-08-28 12:21:35 +00:00
} elseif ( empty ( $senderEmail )) {
2023-08-28 12:19:37 +00:00
throw new Exception ( Exception :: GENERAL_ARGUMENT_INVALID , 'Sender email is required when enabling SMTP.' );
2023-08-28 12:21:35 +00:00
} elseif ( empty ( $host )) {
2023-08-28 12:19:37 +00:00
throw new Exception ( Exception :: GENERAL_ARGUMENT_INVALID , 'Host is required when enabling SMTP.' );
2023-08-28 12:21:35 +00:00
} elseif ( empty ( $port )) {
2023-08-28 12:19:37 +00:00
throw new Exception ( Exception :: GENERAL_ARGUMENT_INVALID , 'Port is required when enabling SMTP.' );
}
}
2023-05-23 05:09:17 +00:00
// validate SMTP settings
2023-08-28 12:19:37 +00:00
if ( $enabled ) {
$mail = new PHPMailer ( true );
$mail -> isSMTP ();
$mail -> Username = $username ;
$mail -> Password = $password ;
$mail -> Host = $host ;
$mail -> Port = $port ;
$mail -> SMTPSecure = $secure ;
$mail -> SMTPAutoTLS = false ;
$mail -> Timeout = 5 ;
try {
$valid = $mail -> SmtpConnect ();
if ( ! $valid ) {
throw new Exception ( 'Connection is not valid.' );
}
} catch ( Throwable $error ) {
throw new Exception ( Exception :: PROJECT_SMTP_CONFIG_INVALID , 'Could not connect to SMTP server: ' . $error -> getMessage ());
}
}
2023-05-23 05:09:17 +00:00
2023-08-28 12:19:37 +00:00
// Save SMTP settings
if ( $enabled ) {
$smtp = [
'enabled' => $enabled ,
'senderName' => $senderName ,
'senderEmail' => $senderEmail ,
'replyTo' => $replyTo ,
'host' => $host ,
'port' => $port ,
'username' => $username ,
'password' => $password ,
'secure' => $secure ,
];
} else {
$smtp = [
'enabled' => false
];
}
2023-03-09 01:59:10 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> updateDocument ( 'projects' , $project -> getId (), $project -> setAttribute ( 'smtp' , $smtp ));
2023-03-09 01:59:10 +00:00
$response -> dynamic ( $project , Response :: MODEL_PROJECT );
});
2024-10-08 07:54:40 +00:00
App :: post ( '/v1/projects/:projectId/smtp/tests' )
2023-12-19 15:08:09 +00:00
-> desc ( 'Create SMTP test' )
-> groups ([ 'api' , 'projects' ])
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'templates' ,
2025-01-17 04:31:39 +00:00
name : 'createSmtpTest' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/create-smtp-test.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_NOCONTENT ,
model : Response :: MODEL_NONE ,
)
]
))
2023-12-19 15:08:09 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
2024-01-15 10:18:17 +00:00
-> param ( 'emails' , [], new ArrayList ( new Email (), 10 ), 'Array of emails to send test email to. Maximum of 10 emails are allowed.' )
2024-04-01 11:02:47 +00:00
-> param ( 'senderName' , System :: getEnv ( '_APP_SYSTEM_EMAIL_NAME' , APP_NAME . ' Server' ), new Text ( 255 , 0 ), 'Name of the email sender' )
-> param ( 'senderEmail' , System :: getEnv ( '_APP_SYSTEM_EMAIL_ADDRESS' , APP_EMAIL_TEAM ), new Email (), 'Email of the sender' )
2024-01-15 10:18:17 +00:00
-> param ( 'replyTo' , '' , new Email (), 'Reply to email' , true )
-> param ( 'host' , '' , new HostName (), 'SMTP server host name' )
-> param ( 'port' , 587 , new Integer (), 'SMTP server port' , true )
-> param ( 'username' , '' , new Text ( 0 , 0 ), 'SMTP server username' , true )
-> param ( 'password' , '' , new Text ( 0 , 0 ), 'SMTP server password' , true )
2024-10-02 17:26:45 +00:00
-> param ( 'secure' , '' , new WhiteList ([ 'tls' , 'ssl' ], true ), 'Does SMTP server use secure connection' , true )
2023-12-19 15:08:09 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
2023-12-19 15:08:09 +00:00
-> inject ( 'queueForMails' )
2025-05-12 13:10:58 +00:00
-> inject ( 'plan' )
-> action ( function ( string $projectId , array $emails , string $senderName , string $senderEmail , string $replyTo , string $host , int $port , string $username , string $password , string $secure , Response $response , Database $dbForPlatform , Mail $queueForMails , array $plan ) {
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2023-12-19 15:08:09 +00:00
if ( $project -> isEmpty ()) {
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
}
2023-12-19 21:46:35 +00:00
2024-01-17 11:22:08 +00:00
$replyToEmail = ! empty ( $replyTo ) ? $replyTo : $senderEmail ;
$subject = 'Custom SMTP email sample' ;
$template = Template :: fromFile ( __DIR__ . '/../../config/locale/templates/email-smtp-test.tpl' );
$template
-> setParam ( '{{from}}' , " { $senderName } ( { $senderEmail } ) " )
2025-05-12 13:10:58 +00:00
-> setParam ( '{{replyTo}}' , " { $senderName } ( { $replyToEmail } ) " )
2025-05-12 13:20:59 +00:00
-> setParam ( '{{logoUrl}}' , $plan [ 'logoUrl' ] ? ? APP_EMAIL_LOGO_URL )
2025-05-15 07:44:14 +00:00
-> setParam ( '{{accentColor}}' , $plan [ 'accentColor' ] ? ? APP_EMAIL_ACCENT_COLOR )
2025-05-12 13:20:59 +00:00
-> setParam ( '{{twitterUrl}}' , $plan [ 'twitterUrl' ] ? ? APP_SOCIAL_TWITTER )
-> setParam ( '{{discordUrl}}' , $plan [ 'discordUrl' ] ? ? APP_SOCIAL_DISCORD )
-> setParam ( '{{githubUrl}}' , $plan [ 'githubUrl' ] ? ? APP_SOCIAL_GITHUB_APPWRITE )
-> setParam ( '{{termsUrl}}' , $plan [ 'termsUrl' ] ? ? APP_EMAIL_TERMS_URL )
-> setParam ( '{{privacyUrl}}' , $plan [ 'privacyUrl' ] ? ? APP_EMAIL_PRIVACY_URL );
2024-01-15 10:18:17 +00:00
2024-01-15 11:02:05 +00:00
foreach ( $emails as $email ) {
2024-01-15 10:18:17 +00:00
$queueForMails
-> setSmtpHost ( $host )
-> setSmtpPort ( $port )
-> setSmtpUsername ( $username )
-> setSmtpPassword ( $password )
-> setSmtpSecure ( $secure )
-> setSmtpReplyTo ( $replyTo )
-> setSmtpSenderEmail ( $senderEmail )
-> setSmtpSenderName ( $senderName )
-> setRecipient ( $email )
-> setName ( '' )
2025-07-25 09:00:03 +00:00
-> setBodyTemplate ( __DIR__ . '/../../config/locale/templates/email-base-styled.tpl' )
2024-01-17 11:22:08 +00:00
-> setBody ( $template -> render ())
2024-01-15 10:18:17 +00:00
-> setVariables ([])
-> setSubject ( $subject )
-> trigger ();
2023-12-19 15:08:09 +00:00
}
return $response -> noContent ();
});
2024-10-08 07:54:40 +00:00
App :: get ( '/v1/projects/:projectId/templates/sms/:type/:locale' )
2023-05-11 06:56:16 +00:00
-> desc ( 'Get custom SMS template' )
2023-03-09 13:44:31 +00:00
-> groups ([ 'api' , 'projects' ])
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'templates' ,
2025-01-17 04:31:39 +00:00
name : 'getSmsTemplate' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/get-sms-template.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_SMS_TEMPLATE ,
)
]
))
2023-03-09 13:44:31 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
-> param ( 'type' , '' , new WhiteList ( Config :: getParam ( 'locale-templates' )[ 'sms' ] ? ? []), 'Template type' )
2024-06-07 00:54:51 +00:00
-> param ( 'locale' , '' , fn ( $localeCodes ) => new WhiteList ( $localeCodes ), 'Template locale' , false , [ 'localeCodes' ])
2023-03-09 13:44:31 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , string $type , string $locale , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2023-08-25 15:13:25 +00:00
throw new Exception ( Exception :: GENERAL_NOT_IMPLEMENTED );
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2023-03-09 13:44:31 +00:00
if ( $project -> isEmpty ()) {
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
}
$templates = $project -> getAttribute ( 'templates' , []);
2024-10-08 07:54:40 +00:00
$template = $templates [ 'sms.' . $type . '-' . $locale ] ? ? null ;
2023-03-09 13:44:31 +00:00
2023-05-11 06:56:16 +00:00
if ( is_null ( $template )) {
$template = [
2023-08-28 12:19:37 +00:00
'message' => Template :: fromFile ( __DIR__ . '/../../config/locale/templates/sms-base.tpl' ) -> render (),
2023-05-11 06:56:16 +00:00
];
}
2023-03-09 13:44:31 +00:00
2023-05-11 06:56:16 +00:00
$template [ 'type' ] = $type ;
$template [ 'locale' ] = $locale ;
$response -> dynamic ( new Document ( $template ), Response :: MODEL_SMS_TEMPLATE );
2023-03-09 13:44:31 +00:00
});
2023-09-27 15:11:58 +00:00
2024-10-08 07:54:40 +00:00
App :: get ( '/v1/projects/:projectId/templates/email/:type/:locale' )
2023-05-11 06:56:16 +00:00
-> desc ( 'Get custom email template' )
2023-03-09 13:44:31 +00:00
-> groups ([ 'api' , 'projects' ])
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'templates' ,
2025-01-17 04:31:39 +00:00
name : 'getEmailTemplate' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/get-email-template.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_EMAIL_TEMPLATE ,
)
]
))
2023-03-09 13:44:31 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
2023-04-17 08:04:52 +00:00
-> param ( 'type' , '' , new WhiteList ( Config :: getParam ( 'locale-templates' )[ 'email' ] ? ? []), 'Template type' )
2024-06-07 00:54:51 +00:00
-> param ( 'locale' , '' , fn ( $localeCodes ) => new WhiteList ( $localeCodes ), 'Template locale' , false , [ 'localeCodes' ])
2023-03-09 13:44:31 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , string $type , string $locale , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2023-03-09 13:44:31 +00:00
if ( $project -> isEmpty ()) {
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
}
$templates = $project -> getAttribute ( 'templates' , []);
2024-10-08 07:54:40 +00:00
$template = $templates [ 'email.' . $type . '-' . $locale ] ? ? null ;
2023-03-09 13:44:31 +00:00
2023-05-11 06:56:16 +00:00
$localeObj = new Locale ( $locale );
if ( is_null ( $template )) {
2025-07-25 09:00:03 +00:00
/**
* different templates , different placeholders .
*/
$templateConfigs = [
'magicSession' => [
'file' => 'email-magic-url.tpl' ,
'placeholders' => [ 'optionButton' , 'buttonText' , 'optionUrl' , 'clientInfo' , 'securityPhrase' ]
],
'mfaChallenge' => [
'file' => 'email-mfa-challenge.tpl' ,
'placeholders' => [ 'description' , 'clientInfo' ]
],
'otpSession' => [
'file' => 'email-otp.tpl' ,
'placeholders' => [ 'description' , 'clientInfo' , 'securityPhrase' ]
],
'sessionAlert' => [
'file' => 'email-session-alert.tpl' ,
'placeholders' => [ 'body' , 'listDevice' , 'listIpAddress' , 'listCountry' , 'footer' ]
],
];
// fallback to the base template.
$config = $templateConfigs [ $type ] ? ? [
'file' => 'email-inner-base.tpl' ,
'placeholders' => [ 'buttonText' , 'body' , 'footer' ]
];
$templateString = file_get_contents ( __DIR__ . '/../../config/locale/templates/' . $config [ 'file' ]);
// We use `fromString` due to the replace above
$message = Template :: fromString ( $templateString );
// Set type-specific parameters
foreach ( $config [ 'placeholders' ] as $param ) {
$escapeHtml = ! in_array ( $param , [ 'clientInfo' , 'body' , 'footer' , 'description' ]);
$message -> setParam ( " { { { $param } }} " , $localeObj -> getText ( " emails. { $type } . { $param } " ), escapeHtml : $escapeHtml );
}
2023-08-28 08:03:55 +00:00
$message
2025-07-25 09:00:03 +00:00
// common placeholders on all the templates
2023-05-11 06:56:16 +00:00
-> setParam ( '{{hello}}' , $localeObj -> getText ( " emails. { $type } .hello " ))
-> setParam ( '{{thanks}}' , $localeObj -> getText ( " emails. { $type } .thanks " ))
2025-07-25 09:00:03 +00:00
-> setParam ( '{{signature}}' , $localeObj -> getText ( " emails. { $type } .signature " ));
// `useContent: false` will strip new lines!
$message = $message -> render ( useContent : true );
2023-05-17 08:25:24 +00:00
2023-05-11 06:56:16 +00:00
$template = [
'message' => $message ,
'subject' => $localeObj -> getText ( 'emails.' . $type . '.subject' ),
2023-08-29 09:40:30 +00:00
'senderEmail' => '' ,
'senderName' => ''
2023-05-11 06:56:16 +00:00
];
}
2023-03-09 13:44:31 +00:00
2023-05-11 06:56:16 +00:00
$template [ 'type' ] = $type ;
$template [ 'locale' ] = $locale ;
$response -> dynamic ( new Document ( $template ), Response :: MODEL_EMAIL_TEMPLATE );
2023-03-10 06:27:42 +00:00
});
2024-10-08 07:54:40 +00:00
App :: patch ( '/v1/projects/:projectId/templates/sms/:type/:locale' )
2023-05-11 06:56:16 +00:00
-> desc ( 'Update custom SMS template' )
2023-03-10 06:27:42 +00:00
-> groups ([ 'api' , 'projects' ])
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'templates' ,
2025-01-17 04:31:39 +00:00
name : 'updateSmsTemplate' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/update-sms-template.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_SMS_TEMPLATE ,
)
]
))
2023-03-10 06:27:42 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
-> param ( 'type' , '' , new WhiteList ( Config :: getParam ( 'locale-templates' )[ 'sms' ] ? ? []), 'Template type' )
2024-06-07 00:54:51 +00:00
-> param ( 'locale' , '' , fn ( $localeCodes ) => new WhiteList ( $localeCodes ), 'Template locale' , false , [ 'localeCodes' ])
2023-05-11 06:56:16 +00:00
-> param ( 'message' , '' , new Text ( 0 ), 'Template message' )
2023-03-10 06:27:42 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , string $type , string $locale , string $message , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2023-08-25 15:13:25 +00:00
throw new Exception ( Exception :: GENERAL_NOT_IMPLEMENTED );
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2023-03-10 06:27:42 +00:00
if ( $project -> isEmpty ()) {
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
}
$templates = $project -> getAttribute ( 'templates' , []);
2023-05-11 06:56:16 +00:00
$templates [ 'sms.' . $type . '-' . $locale ] = [
'message' => $message
];
2023-03-10 06:27:42 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> updateDocument ( 'projects' , $project -> getId (), $project -> setAttribute ( 'templates' , $templates ));
2023-03-10 06:27:42 +00:00
2023-05-11 06:56:16 +00:00
$response -> dynamic ( new Document ([
'message' => $message ,
'type' => $type ,
'locale' => $locale ,
]), Response :: MODEL_SMS_TEMPLATE );
2023-03-10 06:27:42 +00:00
});
2024-10-08 07:54:40 +00:00
App :: patch ( '/v1/projects/:projectId/templates/email/:type/:locale' )
2023-05-11 06:56:16 +00:00
-> desc ( 'Update custom email templates' )
2023-03-10 06:27:42 +00:00
-> groups ([ 'api' , 'projects' ])
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'templates' ,
2025-01-17 04:31:39 +00:00
name : 'updateEmailTemplate' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/update-email-template.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_EMAIL_TEMPLATE ,
)
]
))
2023-03-10 06:27:42 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
2023-04-17 08:04:52 +00:00
-> param ( 'type' , '' , new WhiteList ( Config :: getParam ( 'locale-templates' )[ 'email' ] ? ? []), 'Template type' )
2024-06-07 00:54:51 +00:00
-> param ( 'locale' , '' , fn ( $localeCodes ) => new WhiteList ( $localeCodes ), 'Template locale' , false , [ 'localeCodes' ])
2023-05-11 06:56:16 +00:00
-> param ( 'subject' , '' , new Text ( 255 ), 'Email Subject' )
-> param ( 'message' , '' , new Text ( 0 ), 'Template message' )
2023-08-28 14:08:50 +00:00
-> param ( 'senderName' , '' , new Text ( 255 , 0 ), 'Name of the email sender' , true )
2023-08-28 12:19:37 +00:00
-> param ( 'senderEmail' , '' , new Email (), 'Email of the sender' , true )
2023-05-11 06:56:16 +00:00
-> param ( 'replyTo' , '' , new Email (), 'Reply to email' , true )
2023-03-10 06:27:42 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , string $type , string $locale , string $subject , string $message , string $senderName , string $senderEmail , string $replyTo , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2023-03-10 06:27:42 +00:00
if ( $project -> isEmpty ()) {
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
}
$templates = $project -> getAttribute ( 'templates' , []);
2023-05-11 06:56:16 +00:00
$templates [ 'email.' . $type . '-' . $locale ] = [
'senderName' => $senderName ,
'senderEmail' => $senderEmail ,
'subject' => $subject ,
'replyTo' => $replyTo ,
'message' => $message
];
2023-03-10 06:27:42 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> updateDocument ( 'projects' , $project -> getId (), $project -> setAttribute ( 'templates' , $templates ));
2023-03-10 06:27:42 +00:00
2023-05-11 06:56:16 +00:00
$response -> dynamic ( new Document ([
'type' => $type ,
'locale' => $locale ,
'senderName' => $senderName ,
'senderEmail' => $senderEmail ,
'subject' => $subject ,
'replyTo' => $replyTo ,
'message' => $message
]), Response :: MODEL_EMAIL_TEMPLATE );
2023-03-09 13:44:31 +00:00
});
2023-04-19 08:44:22 +00:00
2024-10-08 07:54:40 +00:00
App :: delete ( '/v1/projects/:projectId/templates/sms/:type/:locale' )
2023-04-19 08:44:22 +00:00
-> desc ( 'Reset custom SMS template' )
-> groups ([ 'api' , 'projects' ])
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'templates' ,
2025-01-17 04:31:39 +00:00
name : 'deleteSmsTemplate' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/delete-sms-template.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_SMS_TEMPLATE ,
)
],
contentType : ContentType :: JSON
))
2023-04-19 08:44:22 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
-> param ( 'type' , '' , new WhiteList ( Config :: getParam ( 'locale-templates' )[ 'sms' ] ? ? []), 'Template type' )
2024-06-07 00:54:51 +00:00
-> param ( 'locale' , '' , fn ( $localeCodes ) => new WhiteList ( $localeCodes ), 'Template locale' , false , [ 'localeCodes' ])
2023-04-19 08:44:22 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , string $type , string $locale , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2023-08-25 15:13:25 +00:00
throw new Exception ( Exception :: GENERAL_NOT_IMPLEMENTED );
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2023-04-19 08:44:22 +00:00
if ( $project -> isEmpty ()) {
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
}
$templates = $project -> getAttribute ( 'templates' , []);
2024-10-08 07:54:40 +00:00
$template = $templates [ 'sms.' . $type . '-' . $locale ] ? ? null ;
2023-04-19 08:44:22 +00:00
if ( is_null ( $template )) {
2023-05-11 06:52:27 +00:00
throw new Exception ( Exception :: PROJECT_TEMPLATE_DEFAULT_DELETION );
2023-04-19 08:44:22 +00:00
}
unset ( $template [ 'sms.' . $type . '-' . $locale ]);
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> updateDocument ( 'projects' , $project -> getId (), $project -> setAttribute ( 'templates' , $templates ));
2023-04-19 08:44:22 +00:00
$response -> dynamic ( new Document ([
'type' => $type ,
'locale' => $locale ,
'message' => $template [ 'message' ]
]), Response :: MODEL_SMS_TEMPLATE );
});
2024-10-08 07:54:40 +00:00
App :: delete ( '/v1/projects/:projectId/templates/email/:type/:locale' )
2025-04-14 18:40:48 +00:00
-> desc ( 'Delete custom email template' )
2023-04-19 08:44:22 +00:00
-> groups ([ 'api' , 'projects' ])
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'projects' ,
2025-03-31 05:48:17 +00:00
group : 'templates' ,
2025-01-17 04:31:39 +00:00
name : 'deleteEmailTemplate' ,
2025-01-20 03:16:00 +00:00
description : '/docs/references/projects/delete-email-template.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_EMAIL_TEMPLATE ,
)
],
contentType : ContentType :: JSON
))
2023-04-19 08:44:22 +00:00
-> param ( 'projectId' , '' , new UID (), 'Project unique ID.' )
-> param ( 'type' , '' , new WhiteList ( Config :: getParam ( 'locale-templates' )[ 'email' ] ? ? []), 'Template type' )
2024-06-07 00:54:51 +00:00
-> param ( 'locale' , '' , fn ( $localeCodes ) => new WhiteList ( $localeCodes ), 'Template locale' , false , [ 'localeCodes' ])
2023-04-19 08:44:22 +00:00
-> inject ( 'response' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
-> action ( function ( string $projectId , string $type , string $locale , Response $response , Database $dbForPlatform ) {
2024-10-08 07:54:40 +00:00
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> getDocument ( 'projects' , $projectId );
2023-04-19 08:44:22 +00:00
if ( $project -> isEmpty ()) {
throw new Exception ( Exception :: PROJECT_NOT_FOUND );
}
$templates = $project -> getAttribute ( 'templates' , []);
2024-10-08 07:54:40 +00:00
$template = $templates [ 'email.' . $type . '-' . $locale ] ? ? null ;
2023-04-19 08:44:22 +00:00
if ( is_null ( $template )) {
2023-05-11 06:52:27 +00:00
throw new Exception ( Exception :: PROJECT_TEMPLATE_DEFAULT_DELETION );
2023-04-19 08:44:22 +00:00
}
unset ( $templates [ 'email.' . $type . '-' . $locale ]);
2024-12-12 10:30:26 +00:00
$project = $dbForPlatform -> updateDocument ( 'projects' , $project -> getId (), $project -> setAttribute ( 'templates' , $templates ));
2023-04-19 08:44:22 +00:00
$response -> dynamic ( new Document ([
'type' => $type ,
'locale' => $locale ,
'senderName' => $template [ 'senderName' ],
'senderEmail' => $template [ 'senderEmail' ],
'subject' => $template [ 'subject' ],
'replyTo' => $template [ 'replyTo' ],
'message' => $template [ 'message' ]
]), Response :: MODEL_EMAIL_TEMPLATE );
});