2022-11-14 18:22:04 +00:00
< ? php
2023-03-11 16:06:02 +00:00
use Appwrite\Extend\Exception ;
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 ;
2022-11-14 18:22:04 +00:00
use Appwrite\Utopia\Response ;
use Utopia\Database\Database ;
use Utopia\Database\Document ;
2023-03-11 16:06:02 +00:00
use Utopia\Database\Exception\Duplicate as DuplicateException ;
2023-08-21 07:34:34 +00:00
use Utopia\Database\Helpers\ID ;
use Utopia\Database\Helpers\Permission ;
use Utopia\Database\Helpers\Role ;
2022-11-14 18:22:04 +00:00
use Utopia\Database\Query ;
2025-10-29 18:21:41 +00:00
use Utopia\Database\Validator\Authorization ;
2024-03-06 17:34:21 +00:00
use Utopia\Database\Validator\Datetime as DateTimeValidator ;
2023-03-11 16:06:02 +00:00
use Utopia\Database\Validator\UID ;
2026-02-10 05:04:24 +00:00
use Utopia\Http\Http ;
2024-10-21 14:33:57 +00:00
use Utopia\Validator\Boolean ;
2025-11-10 04:45:49 +00:00
use Utopia\Validator\Nullable ;
2024-10-08 07:54:40 +00:00
use Utopia\Validator\Text ;
use Utopia\Validator\WhiteList ;
2022-11-14 18:22:04 +00:00
2026-02-04 05:30:22 +00:00
Http :: get ( '/v1/project/usage' )
2024-02-26 02:44:20 +00:00
-> desc ( 'Get project usage stats' )
2023-10-25 07:39:59 +00:00
-> groups ([ 'api' , 'usage' ])
2022-11-14 18:22:04 +00:00
-> label ( 'scope' , 'projects.read' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'project' ,
2025-04-12 06:41:57 +00:00
group : null ,
2025-01-17 04:31:39 +00:00
name : 'getUsage' ,
2025-01-17 07:44:25 +00:00
description : '/docs/references/project/get-usage.md' ,
2025-01-17 04:31:39 +00:00
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_USAGE_PROJECT ,
)
]
))
2023-12-10 09:26:33 +00:00
-> param ( 'startDate' , '' , new DateTimeValidator (), 'Starting date for the usage' )
-> param ( 'endDate' , '' , new DateTimeValidator (), 'End date for the usage' )
-> param ( 'period' , '1d' , new WhiteList ([ '1h' , '1d' ]), 'Period used' , true )
2022-11-14 18:22:04 +00:00
-> inject ( 'response' )
2025-03-01 17:45:20 +00:00
-> inject ( 'project' )
2022-11-14 18:22:04 +00:00
-> inject ( 'dbForProject' )
2026-01-14 15:08:00 +00:00
-> inject ( 'authorization' )
2025-03-01 17:45:20 +00:00
-> inject ( 'getLogsDB' )
2025-01-09 18:33:07 +00:00
-> inject ( 'smsRates' )
2026-01-14 15:08:00 +00:00
-> action ( function ( string $startDate , string $endDate , string $period , Response $response , Document $project , Database $dbForProject , Authorization $authorization , callable $getLogsDB , array $smsRates ) {
2023-11-08 16:12:36 +00:00
$stats = $total = $usage = [];
2023-12-10 09:26:33 +00:00
$format = 'Y-m-d 00:00:00' ;
$firstDay = ( new DateTime ( $startDate )) -> format ( $format );
$lastDay = ( new DateTime ( $endDate )) -> format ( $format );
2023-11-08 16:12:36 +00:00
2025-03-01 17:45:20 +00:00
$dbForLogs = call_user_func ( $getLogsDB , $project );
2023-10-25 07:39:59 +00:00
$metrics = [
2024-03-06 17:34:21 +00:00
'total' => [
2023-11-08 16:12:36 +00:00
METRIC_EXECUTIONS ,
2024-07-12 10:02:32 +00:00
METRIC_EXECUTIONS_MB_SECONDS ,
METRIC_BUILDS_MB_SECONDS ,
2023-11-08 16:12:36 +00:00
METRIC_DOCUMENTS ,
METRIC_DATABASES ,
METRIC_USERS ,
METRIC_BUCKETS ,
2024-07-18 04:58:02 +00:00
METRIC_FILES_STORAGE ,
2024-07-18 07:21:56 +00:00
METRIC_DATABASES_STORAGE ,
2024-07-29 03:03:41 +00:00
METRIC_DEPLOYMENTS_STORAGE ,
2025-01-23 13:24:02 +00:00
METRIC_BUILDS_STORAGE ,
METRIC_DATABASES_OPERATIONS_READS ,
METRIC_DATABASES_OPERATIONS_WRITES ,
2025-02-28 08:28:21 +00:00
METRIC_FILES_IMAGES_TRANSFORMED ,
2024-03-06 17:34:21 +00:00
],
'period' => [
2023-11-08 16:12:36 +00:00
METRIC_NETWORK_REQUESTS ,
METRIC_NETWORK_INBOUND ,
METRIC_NETWORK_OUTBOUND ,
2023-12-11 15:19:08 +00:00
METRIC_USERS ,
2024-07-18 04:58:02 +00:00
METRIC_EXECUTIONS ,
2024-09-19 06:37:27 +00:00
METRIC_DATABASES_STORAGE ,
2024-07-12 10:02:32 +00:00
METRIC_EXECUTIONS_MB_SECONDS ,
2025-01-23 13:24:02 +00:00
METRIC_BUILDS_MB_SECONDS ,
METRIC_DATABASES_OPERATIONS_READS ,
METRIC_DATABASES_OPERATIONS_WRITES ,
2025-03-01 17:18:44 +00:00
METRIC_FILES_IMAGES_TRANSFORMED ,
2024-03-06 17:34:21 +00:00
]
2023-10-25 07:39:59 +00:00
];
2023-03-11 16:06:02 +00:00
2023-12-10 09:26:33 +00:00
$factor = match ( $period ) {
'1h' => 3600 ,
'1d' => 86400 ,
};
$limit = match ( $period ) {
2023-12-11 15:19:08 +00:00
'1h' => ( new DateTime ( $startDate )) -> diff ( new DateTime ( $endDate )) -> days * 24 ,
'1d' => ( new DateTime ( $startDate )) -> diff ( new DateTime ( $endDate )) -> days
2023-12-10 09:26:33 +00:00
};
$format = match ( $period ) {
'1h' => 'Y-m-d\TH:00:00.000P' ,
'1d' => 'Y-m-d\T00:00:00.000P' ,
};
2026-01-14 15:08:00 +00:00
$authorization -> skip ( function () use ( $dbForProject , $dbForLogs , $firstDay , $lastDay , $period , $metrics , $limit , & $total , & $stats ) {
2023-11-08 16:12:36 +00:00
foreach ( $metrics [ 'total' ] as $metric ) {
2025-03-01 17:45:20 +00:00
$db = ( $metric === METRIC_FILES_IMAGES_TRANSFORMED ) ? $dbForLogs : $dbForProject ;
$result = $db -> findOne ( 'stats' , [
2023-11-08 16:12:36 +00:00
Query :: equal ( 'metric' , [ $metric ]),
Query :: equal ( 'period' , [ 'inf' ])
]);
$total [ $metric ] = $result [ 'value' ] ? ? 0 ;
}
foreach ( $metrics [ 'period' ] as $metric ) {
2025-03-01 17:45:20 +00:00
$db = ( $metric === METRIC_FILES_IMAGES_TRANSFORMED ) ? $dbForLogs : $dbForProject ;
$results = $db -> find ( 'stats' , [
2023-10-25 07:39:59 +00:00
Query :: equal ( 'metric' , [ $metric ]),
2023-10-25 12:06:54 +00:00
Query :: equal ( 'period' , [ $period ]),
2023-12-10 09:26:33 +00:00
Query :: greaterThanEqual ( 'time' , $firstDay ),
Query :: lessThan ( 'time' , $lastDay ),
2024-05-13 21:17:39 +00:00
Query :: limit ( $limit ),
2023-10-25 07:39:59 +00:00
Query :: orderDesc ( 'time' ),
]);
2023-08-20 12:29:43 +00:00
2023-10-25 07:39:59 +00:00
$stats [ $metric ] = [];
foreach ( $results as $result ) {
$stats [ $metric ][ $result -> getAttribute ( 'time' )] = [
'value' => $result -> getAttribute ( 'value' ),
];
}
}
});
2023-08-20 12:29:43 +00:00
2023-12-10 19:58:38 +00:00
$now = time ();
2023-12-10 09:26:33 +00:00
foreach ( $metrics [ 'period' ] as $metric ) {
$usage [ $metric ] = [];
2023-12-10 19:58:38 +00:00
$leap = $now - ( $limit * $factor );
while ( $leap < $now ) {
2023-12-10 09:26:33 +00:00
$leap += $factor ;
$formatDate = date ( $format , $leap );
$usage [ $metric ][] = [
2023-12-10 19:58:38 +00:00
'value' => $stats [ $metric ][ $formatDate ][ 'value' ] ? ? 0 ,
'date' => $formatDate ,
2023-12-10 09:26:33 +00:00
];
}
2023-03-11 16:06:02 +00:00
}
2023-12-10 09:26:33 +00:00
2023-12-11 15:33:15 +00:00
$executionsBreakdown = array_map ( function ( $function ) use ( $dbForProject ) {
2023-12-11 15:19:08 +00:00
$id = $function -> getId ();
$name = $function -> getAttribute ( 'name' );
2025-05-27 01:36:23 +00:00
$metric = str_replace ([ '{resourceType}' , '{resourceInternalId}' ], [ RESOURCE_TYPE_FUNCTIONS , $function -> getSequence ()], METRIC_RESOURCE_TYPE_ID_EXECUTIONS );
2024-02-12 09:10:52 +00:00
$value = $dbForProject -> findOne ( 'stats' , [
2023-12-11 15:19:08 +00:00
Query :: equal ( 'metric' , [ $metric ]),
Query :: equal ( 'period' , [ 'inf' ])
]);
return [
'resourceId' => $id ,
'name' => $name ,
'value' => $value [ 'value' ] ? ? 0 ,
];
}, $dbForProject -> find ( 'functions' ));
2024-07-12 10:02:32 +00:00
$executionsMbSecondsBreakdown = array_map ( function ( $function ) use ( $dbForProject ) {
$id = $function -> getId ();
$name = $function -> getAttribute ( 'name' );
2025-05-27 01:36:23 +00:00
$metric = str_replace ([ '{resourceType}' , '{resourceInternalId}' ], [ RESOURCE_TYPE_FUNCTIONS , $function -> getSequence ()], METRIC_RESOURCE_TYPE_ID_EXECUTIONS_MB_SECONDS );
2024-07-12 10:02:32 +00:00
$value = $dbForProject -> findOne ( 'stats' , [
Query :: equal ( 'metric' , [ $metric ]),
Query :: equal ( 'period' , [ 'inf' ])
]);
return [
'resourceId' => $id ,
'name' => $name ,
'value' => $value [ 'value' ] ? ? 0 ,
];
}, $dbForProject -> find ( 'functions' ));
$buildsMbSecondsBreakdown = array_map ( function ( $function ) use ( $dbForProject ) {
$id = $function -> getId ();
$name = $function -> getAttribute ( 'name' );
2025-05-27 01:36:23 +00:00
$metric = str_replace ([ '{resourceType}' , '{resourceInternalId}' ], [ RESOURCE_TYPE_FUNCTIONS , $function -> getSequence ()], METRIC_RESOURCE_TYPE_ID_BUILDS_MB_SECONDS );
2024-07-12 10:02:32 +00:00
$value = $dbForProject -> findOne ( 'stats' , [
Query :: equal ( 'metric' , [ $metric ]),
Query :: equal ( 'period' , [ 'inf' ])
]);
return [
'resourceId' => $id ,
'name' => $name ,
'value' => $value [ 'value' ] ? ? 0 ,
];
}, $dbForProject -> find ( 'functions' ));
2023-12-11 15:33:15 +00:00
$bucketsBreakdown = array_map ( function ( $bucket ) use ( $dbForProject ) {
2023-12-11 15:19:08 +00:00
$id = $bucket -> getId ();
$name = $bucket -> getAttribute ( 'name' );
2025-05-26 05:42:11 +00:00
$metric = str_replace ( '{bucketInternalId}' , $bucket -> getSequence (), METRIC_BUCKET_ID_FILES_STORAGE );
2024-02-12 09:10:52 +00:00
$value = $dbForProject -> findOne ( 'stats' , [
2023-12-11 15:19:08 +00:00
Query :: equal ( 'metric' , [ $metric ]),
Query :: equal ( 'period' , [ 'inf' ])
]);
return [
'resourceId' => $id ,
'name' => $name ,
'value' => $value [ 'value' ] ? ? 0 ,
];
}, $dbForProject -> find ( 'buckets' ));
2024-07-18 04:58:02 +00:00
$databasesStorageBreakdown = array_map ( function ( $database ) use ( $dbForProject ) {
$id = $database -> getId ();
$name = $database -> getAttribute ( 'name' );
2025-05-26 05:42:11 +00:00
$metric = str_replace ( '{databaseInternalId}' , $database -> getSequence (), METRIC_DATABASE_ID_STORAGE );
2024-07-18 07:21:56 +00:00
2024-07-18 04:58:02 +00:00
$value = $dbForProject -> findOne ( 'stats' , [
Query :: equal ( 'metric' , [ $metric ]),
Query :: equal ( 'period' , [ 'inf' ])
]);
return [
'resourceId' => $id ,
'name' => $name ,
'value' => $value [ 'value' ] ? ? 0 ,
];
}, $dbForProject -> find ( 'databases' ));
2024-07-29 03:03:41 +00:00
$functionsStorageBreakdown = array_map ( function ( $function ) use ( $dbForProject ) {
2024-06-11 05:14:38 +00:00
$id = $function -> getId ();
$name = $function -> getAttribute ( 'name' );
2025-05-27 01:36:23 +00:00
$deploymentMetric = str_replace ([ '{resourceType}' , '{resourceInternalId}' ], [ RESOURCE_TYPE_FUNCTIONS , $function -> getSequence ()], METRIC_RESOURCE_TYPE_ID_DEPLOYMENTS_STORAGE );
2024-07-29 03:03:41 +00:00
$deploymentValue = $dbForProject -> findOne ( 'stats' , [
Query :: equal ( 'metric' , [ $deploymentMetric ]),
2024-06-11 05:14:38 +00:00
Query :: equal ( 'period' , [ 'inf' ])
]);
2025-05-27 01:36:23 +00:00
$buildMetric = str_replace ([ '{resourceType}' , '{resourceInternalId}' ], [ RESOURCE_TYPE_FUNCTIONS , $function -> getSequence ()], METRIC_RESOURCE_TYPE_ID_BUILDS_STORAGE );
2024-07-29 03:03:41 +00:00
$buildValue = $dbForProject -> findOne ( 'stats' , [
Query :: equal ( 'metric' , [ $buildMetric ]),
Query :: equal ( 'period' , [ 'inf' ])
]);
$value = ( $buildValue [ 'value' ] ? ? 0 ) + ( $deploymentValue [ 'value' ] ? ? 0 );
2024-06-11 05:14:38 +00:00
return [
'resourceId' => $id ,
'name' => $name ,
2024-07-29 03:03:41 +00:00
'value' => $value ,
2024-06-11 05:14:38 +00:00
];
}, $dbForProject -> find ( 'functions' ));
2024-07-30 08:53:28 +00:00
$executionsMbSecondsBreakdown = array_map ( function ( $function ) use ( $dbForProject ) {
2024-06-11 05:14:38 +00:00
$id = $function -> getId ();
$name = $function -> getAttribute ( 'name' );
2025-05-27 01:36:23 +00:00
$metric = str_replace ([ '{resourceType}' , '{resourceInternalId}' ], [ RESOURCE_TYPE_FUNCTIONS , $function -> getSequence ()], METRIC_RESOURCE_TYPE_ID_EXECUTIONS_MB_SECONDS );
2024-07-30 08:53:28 +00:00
$value = $dbForProject -> findOne ( 'stats' , [
Query :: equal ( 'metric' , [ $metric ]),
Query :: equal ( 'period' , [ 'inf' ])
]);
2024-07-18 07:21:56 +00:00
2024-07-30 08:53:28 +00:00
return [
'resourceId' => $id ,
'name' => $name ,
'value' => $value [ 'value' ] ? ? 0 ,
];
}, $dbForProject -> find ( 'functions' ));
$buildsMbSecondsBreakdown = array_map ( function ( $function ) use ( $dbForProject ) {
$id = $function -> getId ();
$name = $function -> getAttribute ( 'name' );
2025-05-27 01:36:23 +00:00
$metric = str_replace ([ '{resourceType}' , '{resourceInternalId}' ], [ RESOURCE_TYPE_FUNCTIONS , $function -> getSequence ()], METRIC_RESOURCE_TYPE_ID_BUILDS_MB_SECONDS );
2024-06-11 05:14:38 +00:00
$value = $dbForProject -> findOne ( 'stats' , [
Query :: equal ( 'metric' , [ $metric ]),
Query :: equal ( 'period' , [ 'inf' ])
]);
return [
'resourceId' => $id ,
'name' => $name ,
'value' => $value [ 'value' ] ? ? 0 ,
];
}, $dbForProject -> find ( 'functions' ));
2025-01-09 16:35:40 +00:00
// This total is includes free and paid SMS usage
2026-01-14 15:08:00 +00:00
$authPhoneTotal = $authorization -> skip ( fn () => $dbForProject -> sum ( 'stats' , 'value' , [
2025-01-09 16:35:40 +00:00
Query :: equal ( 'metric' , [ METRIC_AUTH_METHOD_PHONE ]),
Query :: equal ( 'period' , [ '1d' ]),
Query :: greaterThanEqual ( 'time' , $firstDay ),
Query :: lessThan ( 'time' , $lastDay ),
]));
// This estimate is only for paid SMS usage
2026-01-14 15:08:00 +00:00
$authPhoneMetrics = $authorization -> skip ( fn () => $dbForProject -> find ( 'stats' , [
2025-01-10 17:33:08 +00:00
Query :: startsWith ( 'metric' , METRIC_AUTH_METHOD_PHONE . '.' ),
2025-01-09 16:35:40 +00:00
Query :: equal ( 'period' , [ '1d' ]),
Query :: greaterThanEqual ( 'time' , $firstDay ),
Query :: lessThan ( 'time' , $lastDay ),
]));
$authPhoneEstimate = 0.0 ;
$authPhoneCountryBreakdown = [];
foreach ( $authPhoneMetrics as $metric ) {
$parts = explode ( '.' , $metric -> getAttribute ( 'metric' ));
$countryCode = $parts [ 3 ] ? ? null ;
if ( $countryCode === null ) {
continue ;
}
$value = $metric -> getAttribute ( 'value' , 0 );
2025-01-09 19:03:25 +00:00
if ( isset ( $smsRates [ $countryCode ])) {
2025-01-09 18:33:07 +00:00
$authPhoneEstimate += $value * $smsRates [ $countryCode ];
2025-01-09 16:35:40 +00:00
}
$authPhoneCountryBreakdown [] = [
'name' => $countryCode ,
'value' => $value ,
2025-01-09 19:03:25 +00:00
'estimate' => isset ( $smsRates [ $countryCode ])
2025-01-09 18:33:07 +00:00
? $value * $smsRates [ $countryCode ]
2025-01-09 16:35:40 +00:00
: 0.0 ,
];
}
2024-02-19 06:04:29 +00:00
// merge network inbound + outbound
$projectBandwidth = [];
foreach ( $usage [ METRIC_NETWORK_INBOUND ] as $item ) {
$projectBandwidth [ $item [ 'date' ]] ? ? = 0 ;
$projectBandwidth [ $item [ 'date' ]] += $item [ 'value' ];
}
foreach ( $usage [ METRIC_NETWORK_OUTBOUND ] as $item ) {
$projectBandwidth [ $item [ 'date' ]] ? ? = 0 ;
$projectBandwidth [ $item [ 'date' ]] += $item [ 'value' ];
}
$network = [];
foreach ( $projectBandwidth as $date => $value ) {
$network [] = [
'date' => $date ,
'value' => $value
];
}
2023-10-25 07:39:59 +00:00
$response -> dynamic ( new Document ([
2023-11-08 16:12:36 +00:00
'requests' => ( $usage [ METRIC_NETWORK_REQUESTS ]),
2024-02-19 06:04:29 +00:00
'network' => $network ,
2023-12-11 15:19:08 +00:00
'users' => ( $usage [ METRIC_USERS ]),
2023-12-12 17:48:21 +00:00
'executions' => ( $usage [ METRIC_EXECUTIONS ]),
2023-11-08 16:12:36 +00:00
'executionsTotal' => $total [ METRIC_EXECUTIONS ],
2024-07-12 10:02:32 +00:00
'executionsMbSecondsTotal' => $total [ METRIC_EXECUTIONS_MB_SECONDS ],
'buildsMbSecondsTotal' => $total [ METRIC_BUILDS_MB_SECONDS ],
2023-11-08 16:12:36 +00:00
'documentsTotal' => $total [ METRIC_DOCUMENTS ],
2025-05-08 14:17:35 +00:00
'rowsTotal' => $total [ METRIC_DOCUMENTS ],
2023-11-08 16:12:36 +00:00
'databasesTotal' => $total [ METRIC_DATABASES ],
2024-07-18 04:58:02 +00:00
'databasesStorageTotal' => $total [ METRIC_DATABASES_STORAGE ],
2023-11-08 16:12:36 +00:00
'usersTotal' => $total [ METRIC_USERS ],
'bucketsTotal' => $total [ METRIC_BUCKETS ],
'filesStorageTotal' => $total [ METRIC_FILES_STORAGE ],
2024-09-16 11:49:13 +00:00
'functionsStorageTotal' => $total [ METRIC_DEPLOYMENTS_STORAGE ] + $total [ METRIC_BUILDS_STORAGE ],
2024-09-16 09:58:08 +00:00
'buildsStorageTotal' => $total [ METRIC_BUILDS_STORAGE ],
2024-06-11 05:14:38 +00:00
'deploymentsStorageTotal' => $total [ METRIC_DEPLOYMENTS_STORAGE ],
2025-01-23 13:24:02 +00:00
'databasesReadsTotal' => $total [ METRIC_DATABASES_OPERATIONS_READS ],
'databasesWritesTotal' => $total [ METRIC_DATABASES_OPERATIONS_WRITES ],
2023-12-11 15:19:08 +00:00
'executionsBreakdown' => $executionsBreakdown ,
2024-07-18 04:58:02 +00:00
'bucketsBreakdown' => $bucketsBreakdown ,
2025-01-23 13:24:02 +00:00
'databasesReads' => $usage [ METRIC_DATABASES_OPERATIONS_READS ],
'databasesWrites' => $usage [ METRIC_DATABASES_OPERATIONS_WRITES ],
2024-07-18 04:58:02 +00:00
'databasesStorageBreakdown' => $databasesStorageBreakdown ,
2024-07-12 10:02:32 +00:00
'executionsMbSecondsBreakdown' => $executionsMbSecondsBreakdown ,
'buildsMbSecondsBreakdown' => $buildsMbSecondsBreakdown ,
2024-07-29 03:03:41 +00:00
'functionsStorageBreakdown' => $functionsStorageBreakdown ,
2025-01-09 16:35:40 +00:00
'authPhoneTotal' => $authPhoneTotal ,
'authPhoneEstimate' => $authPhoneEstimate ,
'authPhoneCountryBreakdown' => $authPhoneCountryBreakdown ,
2025-03-01 17:18:44 +00:00
'imageTransformations' => $usage [ METRIC_FILES_IMAGES_TRANSFORMED ],
'imageTransformationsTotal' => $total [ METRIC_FILES_IMAGES_TRANSFORMED ],
2023-10-25 07:39:59 +00:00
]), Response :: MODEL_USAGE_PROJECT );
2023-03-11 16:06:02 +00:00
});
2023-10-25 07:39:59 +00:00
2023-08-21 07:34:34 +00:00
// Variables
2026-02-04 05:30:22 +00:00
Http :: post ( '/v1/project/variables' )
2024-10-08 07:54:40 +00:00
-> desc ( 'Create variable' )
2023-08-21 07:34:34 +00:00
-> groups ([ 'api' ])
-> label ( 'scope' , 'projects.write' )
-> label ( 'audits.event' , 'variable.create' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'project' ,
2025-04-12 06:41:57 +00:00
group : null ,
2025-01-17 04:31:39 +00:00
name : 'createVariable' ,
description : '/docs/references/project/create-variable.md' ,
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_CREATED ,
model : Response :: MODEL_VARIABLE ,
)
]
))
2023-08-21 07:34:34 +00:00
-> param ( 'key' , null , new Text ( Database :: LENGTH_KEY ), 'Variable key. Max length: ' . Database :: LENGTH_KEY . ' chars.' , false )
-> param ( 'value' , null , new Text ( 8192 , 0 ), 'Variable value. Max length: 8192 chars.' , false )
2025-02-11 12:50:54 +00:00
-> param ( 'secret' , true , new Boolean (), 'Secret variables can be updated or deleted, but only projects can read them during build and runtime.' , true )
2023-08-21 07:34:34 +00:00
-> inject ( 'project' )
-> inject ( 'response' )
-> inject ( 'dbForProject' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
2025-02-03 09:05:30 +00:00
-> action ( function ( string $key , string $value , bool $secret , Document $project , Response $response , Database $dbForProject , Database $dbForPlatform ) {
2023-08-21 07:34:34 +00:00
$variableId = ID :: unique ();
$variable = new Document ([
'$id' => $variableId ,
'$permissions' => [
Permission :: read ( Role :: any ()),
Permission :: update ( Role :: any ()),
Permission :: delete ( Role :: any ()),
],
'resourceInternalId' => '' ,
'resourceId' => '' ,
'resourceType' => 'project' ,
'key' => $key ,
'value' => $value ,
2024-10-21 14:33:57 +00:00
'secret' => $secret ,
2023-08-21 07:34:34 +00:00
'search' => implode ( ' ' , [ $variableId , $key , 'project' ]),
]);
try {
$variable = $dbForProject -> createDocument ( 'variables' , $variable );
} catch ( DuplicateException $th ) {
throw new Exception ( Exception :: VARIABLE_ALREADY_EXISTS );
}
$functions = $dbForProject -> find ( 'functions' , [
Query :: limit ( APP_LIMIT_SUBQUERY )
]);
foreach ( $functions as $function ) {
$dbForProject -> updateDocument ( 'functions' , $function -> getId (), $function -> setAttribute ( 'live' , false ));
}
$response
-> setStatusCode ( Response :: STATUS_CODE_CREATED )
-> dynamic ( $variable , Response :: MODEL_VARIABLE );
});
2026-02-04 05:30:22 +00:00
Http :: get ( '/v1/project/variables' )
2024-10-08 07:54:40 +00:00
-> desc ( 'List variables' )
2023-08-21 07:34:34 +00:00
-> groups ([ 'api' ])
-> label ( 'scope' , 'projects.read' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'project' ,
2025-04-12 06:41:57 +00:00
group : null ,
2025-01-17 04:31:39 +00:00
name : 'listVariables' ,
description : '/docs/references/project/list-variables.md' ,
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_VARIABLE_LIST ,
)
]
))
2023-08-21 07:34:34 +00:00
-> inject ( 'response' )
-> inject ( 'dbForProject' )
-> action ( function ( Response $response , Database $dbForProject ) {
$variables = $dbForProject -> find ( 'variables' , [
Query :: equal ( 'resourceType' , [ 'project' ]),
Query :: limit ( APP_LIMIT_SUBQUERY )
]);
$response -> dynamic ( new Document ([
'variables' => $variables ,
'total' => \count ( $variables ),
]), Response :: MODEL_VARIABLE_LIST );
});
2026-02-04 05:30:22 +00:00
Http :: get ( '/v1/project/variables/:variableId' )
2024-10-08 07:54:40 +00:00
-> desc ( 'Get variable' )
2023-08-21 07:34:34 +00:00
-> groups ([ 'api' ])
-> label ( 'scope' , 'projects.read' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'project' ,
2025-04-12 06:41:57 +00:00
group : null ,
2025-01-17 04:31:39 +00:00
name : 'getVariable' ,
description : '/docs/references/project/get-variable.md' ,
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_VARIABLE ,
)
]
))
2023-08-21 07:34:34 +00:00
-> param ( 'variableId' , '' , new UID (), 'Variable unique ID.' , false )
-> inject ( 'response' )
-> inject ( 'project' )
-> inject ( 'dbForProject' )
-> action ( function ( string $variableId , Response $response , Document $project , Database $dbForProject ) {
$variable = $dbForProject -> getDocument ( 'variables' , $variableId );
if ( $variable === false || $variable -> isEmpty () || $variable -> getAttribute ( 'resourceType' ) !== 'project' ) {
throw new Exception ( Exception :: VARIABLE_NOT_FOUND );
}
$response -> dynamic ( $variable , Response :: MODEL_VARIABLE );
});
2026-02-04 05:30:22 +00:00
Http :: put ( '/v1/project/variables/:variableId' )
2024-10-08 07:54:40 +00:00
-> desc ( 'Update variable' )
2023-03-11 16:06:02 +00:00
-> groups ([ 'api' ])
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'project' ,
2025-04-12 06:41:57 +00:00
group : null ,
2025-01-17 04:31:39 +00:00
name : 'updateVariable' ,
description : '/docs/references/project/update-variable.md' ,
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_OK ,
model : Response :: MODEL_VARIABLE ,
)
]
))
2023-03-11 16:06:02 +00:00
-> param ( 'variableId' , '' , new UID (), 'Variable unique ID.' , false )
-> param ( 'key' , null , new Text ( 255 ), 'Variable key. Max length: 255 chars.' , false )
2025-11-10 04:45:49 +00:00
-> param ( 'value' , null , new Nullable ( new Text ( 8192 , 0 )), 'Variable value. Max length: 8192 chars.' , true )
-> param ( 'secret' , null , new Nullable ( new Boolean ()), 'Secret variables can be updated or deleted, but only projects can read them during build and runtime.' , true )
2023-03-11 16:06:02 +00:00
-> inject ( 'project' )
-> inject ( 'response' )
-> inject ( 'dbForProject' )
2024-12-12 10:30:26 +00:00
-> inject ( 'dbForPlatform' )
2025-02-10 10:36:31 +00:00
-> action ( function ( string $variableId , string $key , ? string $value , ? bool $secret , Document $project , Response $response , Database $dbForProject , Database $dbForPlatform ) {
2023-07-24 13:12:36 +00:00
$variable = $dbForProject -> getDocument ( 'variables' , $variableId );
if ( $variable === false || $variable -> isEmpty () || $variable -> getAttribute ( 'resourceType' ) !== 'project' ) {
2023-03-11 16:06:02 +00:00
throw new Exception ( Exception :: VARIABLE_NOT_FOUND );
}
2025-02-10 10:36:31 +00:00
if ( $variable -> getAttribute ( 'secret' ) === true && $secret === false ) {
throw new Exception ( Exception :: VARIABLE_CANNOT_UNSET_SECRET );
}
2023-03-11 16:06:02 +00:00
$variable
-> setAttribute ( 'key' , $key )
-> setAttribute ( 'value' , $value ? ? $variable -> getAttribute ( 'value' ))
2025-02-10 10:36:31 +00:00
-> setAttribute ( 'secret' , $secret ? ? $variable -> getAttribute ( 'secret' ))
2023-06-22 10:59:41 +00:00
-> setAttribute ( 'search' , implode ( ' ' , [ $variableId , $key , 'project' ]));
2023-03-11 16:06:02 +00:00
try {
$dbForProject -> updateDocument ( 'variables' , $variable -> getId (), $variable );
} catch ( DuplicateException $th ) {
throw new Exception ( Exception :: VARIABLE_ALREADY_EXISTS );
}
2023-06-22 10:59:41 +00:00
$functions = $dbForProject -> find ( 'functions' , [
Query :: limit ( APP_LIMIT_SUBQUERY )
]);
2023-03-11 16:06:02 +00:00
2023-06-22 10:59:41 +00:00
foreach ( $functions as $function ) {
$dbForProject -> updateDocument ( 'functions' , $function -> getId (), $function -> setAttribute ( 'live' , false ));
}
2023-03-11 16:06:02 +00:00
$response -> dynamic ( $variable , Response :: MODEL_VARIABLE );
});
2026-02-04 05:30:22 +00:00
Http :: delete ( '/v1/project/variables/:variableId' )
2024-10-08 07:54:40 +00:00
-> desc ( 'Delete variable' )
2023-03-11 16:06:02 +00:00
-> groups ([ 'api' ])
-> label ( 'scope' , 'projects.write' )
2025-01-17 04:31:39 +00:00
-> label ( 'sdk' , new Method (
namespace : 'project' ,
2025-04-12 06:41:57 +00:00
group : null ,
2025-01-17 04:31:39 +00:00
name : 'deleteVariable' ,
description : '/docs/references/project/delete-variable.md' ,
auth : [ AuthType :: ADMIN ],
responses : [
new SDKResponse (
code : Response :: STATUS_CODE_NOCONTENT ,
model : Response :: MODEL_NONE ,
)
],
contentType : ContentType :: NONE
))
2023-03-11 16:06:02 +00:00
-> param ( 'variableId' , '' , new UID (), 'Variable unique ID.' , false )
-> inject ( 'project' )
-> inject ( 'response' )
-> inject ( 'dbForProject' )
-> action ( function ( string $variableId , Document $project , Response $response , Database $dbForProject ) {
2023-07-24 13:12:36 +00:00
$variable = $dbForProject -> getDocument ( 'variables' , $variableId );
if ( $variable === false || $variable -> isEmpty () || $variable -> getAttribute ( 'resourceType' ) !== 'project' ) {
2023-03-11 16:06:02 +00:00
throw new Exception ( Exception :: VARIABLE_NOT_FOUND );
}
2023-09-05 11:55:02 +00:00
$dbForProject -> deleteDocument ( 'variables' , $variable -> getId ());
2023-06-22 10:59:41 +00:00
$functions = $dbForProject -> find ( 'functions' , [
Query :: limit ( APP_LIMIT_SUBQUERY )
]);
foreach ( $functions as $function ) {
$dbForProject -> updateDocument ( 'functions' , $function -> getId (), $function -> setAttribute ( 'live' , false ));
}
2023-03-11 16:06:02 +00:00
$response -> noContent ();
});