2019-05-09 06:54:39 +00:00
< ? php
use Utopia\App ;
2022-05-25 12:10:10 +00:00
use Appwrite\Event\Delete ;
2022-02-06 16:50:48 +00:00
use Appwrite\Extend\Exception ;
2021-08-15 21:09:40 +00:00
use Utopia\Audit\Audit ;
2022-08-15 12:56:19 +00:00
use Utopia\Database\Permission ;
2022-08-16 11:26:38 +00:00
use Utopia\Database\Role ;
2022-07-25 08:53:41 +00:00
use Utopia\Database\Validator\DatetimeValidator ;
2022-08-14 10:33:36 +00:00
use Utopia\Database\ID ;
2021-06-09 21:11:51 +00:00
use Utopia\Validator\Boolean ;
2021-07-21 14:26:08 +00:00
use Utopia\Validator\FloatValidator ;
2021-07-05 20:27:20 +00:00
use Utopia\Validator\Integer ;
2019-05-09 06:54:39 +00:00
use Utopia\Validator\Range ;
use Utopia\Validator\WhiteList ;
use Utopia\Validator\Text ;
use Utopia\Validator\ArrayList ;
2020-06-18 20:13:03 +00:00
use Utopia\Validator\JSON ;
2021-08-16 23:21:00 +00:00
use Utopia\Database\Database ;
use Utopia\Database\Document ;
2022-07-12 13:32:39 +00:00
use Utopia\Database\DateTime ;
2021-08-16 23:21:00 +00:00
use Utopia\Database\Query ;
2021-08-24 23:35:32 +00:00
use Utopia\Database\Adapter\MariaDB ;
2021-08-12 01:05:19 +00:00
use Utopia\Database\Validator\Authorization ;
2021-06-22 19:34:42 +00:00
use Utopia\Database\Validator\Key ;
2021-07-05 20:27:20 +00:00
use Utopia\Database\Validator\Permissions ;
2021-07-23 14:59:55 +00:00
use Utopia\Database\Validator\Structure ;
2021-07-05 20:27:20 +00:00
use Utopia\Database\Validator\UID ;
2021-06-15 14:24:51 +00:00
use Utopia\Database\Exception\Authorization as AuthorizationException ;
2021-08-15 21:09:40 +00:00
use Utopia\Database\Exception\Duplicate as DuplicateException ;
2021-07-29 23:36:46 +00:00
use Utopia\Database\Exception\Limit as LimitException ;
2021-06-11 20:06:54 +00:00
use Utopia\Database\Exception\Structure as StructureException ;
2022-05-25 12:10:10 +00:00
use Utopia\Locale\Locale ;
2021-11-03 16:38:06 +00:00
use Appwrite\Auth\Auth ;
2021-08-16 23:21:00 +00:00
use Appwrite\Network\Validator\Email ;
use Appwrite\Network\Validator\IP ;
use Appwrite\Network\Validator\URL ;
2022-01-18 11:05:04 +00:00
use Appwrite\Utopia\Database\Validator\CustomId ;
2022-08-30 08:21:34 +00:00
use Appwrite\Utopia\Database\Validator\Query\Limit ;
use Appwrite\Utopia\Database\Validator\Query\Offset ;
2020-10-30 19:53:27 +00:00
use Appwrite\Utopia\Response ;
2021-12-12 17:58:17 +00:00
use Appwrite\Detector\Detector ;
2022-04-13 12:39:31 +00:00
use Appwrite\Event\Database as EventDatabase ;
2021-12-27 12:45:23 +00:00
use Appwrite\Event\Event ;
2022-08-23 13:03:38 +00:00
use Appwrite\Utopia\Database\Validator\Queries ;
2022-08-23 12:30:28 +00:00
use Appwrite\Utopia\Database\Validator\Queries\Collections ;
2022-08-23 09:40:17 +00:00
use Appwrite\Utopia\Database\Validator\Queries\Databases ;
2022-08-23 15:18:59 +00:00
use Appwrite\Utopia\Database\Validator\Queries\Documents ;
2022-06-22 10:51:49 +00:00
use Utopia\Config\Config ;
2022-05-25 12:10:10 +00:00
use MaxMind\Db\Reader ;
2021-07-27 01:00:36 +00:00
2021-08-16 23:21:00 +00:00
/**
* Create attribute of varying type
*
*
* @ return Document Newly created attribute document
2022-06-15 12:57:06 +00:00
* @ throws Exception
2021-08-16 23:21:00 +00:00
*/
2022-08-10 02:18:18 +00:00
function createAttribute ( string $databaseId , string $collectionId , Document $attribute , Response $response , Database $dbForProject , EventDatabase $database , Event $events ) : Document
2021-08-16 23:21:00 +00:00
{
2021-12-16 15:04:30 +00:00
$key = $attribute -> getAttribute ( 'key' );
2021-07-27 01:00:36 +00:00
$type = $attribute -> getAttribute ( 'type' , '' );
$size = $attribute -> getAttribute ( 'size' , 0 );
$required = $attribute -> getAttribute ( 'required' , true );
2022-05-23 14:54:50 +00:00
$signed = $attribute -> getAttribute ( 'signed' , true ); // integers are signed by default
2021-07-27 01:00:36 +00:00
$array = $attribute -> getAttribute ( 'array' , false );
2021-08-21 21:48:07 +00:00
$format = $attribute -> getAttribute ( 'format' , '' );
$formatOptions = $attribute -> getAttribute ( 'formatOptions' , []);
2022-05-23 14:54:50 +00:00
$filters = $attribute -> getAttribute ( 'filters' , []); // filters are hidden from the endpoint
2021-12-16 15:04:30 +00:00
$default = $attribute -> getAttribute ( 'default' );
2021-07-27 01:00:36 +00:00
2022-06-22 10:51:49 +00:00
$db = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
if ( $db -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 10:51:49 +00:00
}
$collection = $dbForProject -> getDocument ( 'database_' . $db -> getInternalId (), $collectionId );
2021-07-27 01:00:36 +00:00
if ( $collection -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-07-27 01:00:36 +00:00
}
2021-08-21 21:48:07 +00:00
if ( ! empty ( $format )) {
if ( ! Structure :: hasFormat ( $format , $type )) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: ATTRIBUTE_FORMAT_UNSUPPORTED , " Format { $format } not available for { $type } attributes. " );
2021-07-27 18:19:37 +00:00
}
2021-07-27 01:00:36 +00:00
}
2021-12-27 12:45:23 +00:00
// Must throw here since dbForProject->createAttribute is performed by db worker
2022-09-30 09:27:19 +00:00
if ( $required && isset ( $default )) {
2022-08-14 06:56:12 +00:00
throw new Exception ( Exception :: ATTRIBUTE_DEFAULT_UNSUPPORTED , 'Cannot set default value for required attribute' );
2021-08-25 20:43:15 +00:00
}
2022-09-30 09:27:19 +00:00
if ( $array && isset ( $default )) {
2022-08-14 08:05:11 +00:00
throw new Exception ( Exception :: ATTRIBUTE_DEFAULT_UNSUPPORTED , 'Cannot set default value for array attributes' );
2021-10-26 20:14:25 +00:00
}
2021-08-21 04:48:28 +00:00
try {
2021-10-05 13:57:57 +00:00
$attribute = new Document ([
2022-08-14 10:33:36 +00:00
'$id' => ID :: custom ( $db -> getInternalId () . '_' . $collection -> getInternalId () . '_' . $key ),
2021-12-16 15:04:30 +00:00
'key' => $key ,
2022-08-15 11:24:31 +00:00
'databaseInternalId' => $db -> getInternalId (),
'databaseId' => $db -> getId (),
'collectionInternalId' => $collection -> getInternalId (),
'collectionId' => $collectionId ,
2021-08-21 04:48:28 +00:00
'type' => $type ,
2021-10-05 00:23:15 +00:00
'status' => 'processing' , // processing, available, failed, deleting, stuck
2021-08-21 04:48:28 +00:00
'size' => $size ,
'required' => $required ,
'signed' => $signed ,
2021-08-27 17:12:16 +00:00
'default' => $default ,
2021-08-21 04:48:28 +00:00
'array' => $array ,
'format' => $format ,
2021-08-21 21:48:07 +00:00
'formatOptions' => $formatOptions ,
2021-11-02 00:47:07 +00:00
'filters' => $filters ,
2021-10-05 13:57:57 +00:00
]);
2021-09-01 01:13:58 +00:00
2021-12-27 12:45:23 +00:00
$dbForProject -> checkAttribute ( $collection , $attribute );
$attribute = $dbForProject -> createDocument ( 'attributes' , $attribute );
2022-05-23 14:54:50 +00:00
} catch ( DuplicateException $exception ) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: ATTRIBUTE_ALREADY_EXISTS );
2022-05-23 14:54:50 +00:00
} catch ( LimitException $exception ) {
2022-08-14 07:02:41 +00:00
throw new Exception ( Exception :: ATTRIBUTE_LIMIT_EXCEEDED , 'Attribute limit exceeded' );
2021-08-21 04:48:28 +00:00
}
2022-06-22 10:51:49 +00:00
$dbForProject -> deleteCachedDocument ( 'database_' . $db -> getInternalId (), $collectionId );
$dbForProject -> deleteCachedCollection ( 'database_' . $db -> getInternalId () . '_collection_' . $collection -> getInternalId ());
2021-07-27 01:00:36 +00:00
$database
2022-04-13 12:39:31 +00:00
-> setType ( DATABASE_TYPE_CREATE_ATTRIBUTE )
2022-06-22 10:51:49 +00:00
-> setDatabase ( $db )
2022-04-13 12:39:31 +00:00
-> setCollection ( $collection )
-> setDocument ( $attribute )
2021-07-27 01:00:36 +00:00
;
2022-04-13 12:39:31 +00:00
$events
2022-06-22 10:51:49 +00:00
-> setContext ( 'collection' , $collection )
-> setContext ( 'database' , $db )
-> setParam ( 'databaseId' , $databaseId )
2022-04-13 12:39:31 +00:00
-> setParam ( 'collectionId' , $collection -> getId ())
-> setParam ( 'attributeId' , $attribute -> getId ())
;
2021-08-15 11:08:32 +00:00
2021-07-27 01:00:36 +00:00
$response -> setStatusCode ( Response :: STATUS_CODE_CREATED );
2021-08-16 23:21:00 +00:00
return $attribute ;
2022-05-30 17:41:25 +00:00
}
2021-07-27 01:00:36 +00:00
2022-06-22 10:51:49 +00:00
App :: post ( '/v1/databases' )
-> desc ( 'Create Database' )
-> groups ([ 'api' , 'database' ])
-> label ( 'event' , 'databases.[databaseId].create' )
-> label ( 'scope' , 'databases.write' )
2022-09-05 08:00:08 +00:00
-> label ( 'audits.event' , 'database.create' )
2022-08-08 14:32:54 +00:00
-> label ( 'audits.resource' , 'database/{response.$id}' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'databases.{scope}.requests.create' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'databases' )
-> label ( 'sdk.method' , 'create' )
2022-06-22 16:28:09 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/create.md' ) // create this file later
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_CREATED )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_DATABASE ) // Model for database needs to be created
-> param ( 'databaseId' , '' , new CustomId (), 'Unique Id. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.' )
-> param ( 'name' , '' , new Text ( 128 ), 'Collection name. Max length: 128 chars.' )
-> inject ( 'response' )
-> inject ( 'dbForProject' )
-> inject ( 'events' )
2022-08-10 02:18:18 +00:00
-> action ( function ( string $databaseId , string $name , Response $response , Database $dbForProject , Event $events ) {
2022-06-22 10:51:49 +00:00
2022-08-14 14:22:38 +00:00
$databaseId = $databaseId == 'unique()' ? ID :: unique () : $databaseId ;
2022-06-22 10:51:49 +00:00
try {
$dbForProject -> createDocument ( 'databases' , new Document ([
2022-08-14 14:22:38 +00:00
'$id' => $databaseId ,
2022-06-22 10:51:49 +00:00
'name' => $name ,
'search' => implode ( ' ' , [ $databaseId , $name ]),
]));
$database = $dbForProject -> getDocument ( 'databases' , $databaseId );
$collections = Config :: getParam ( 'collections' , [])[ 'collections' ] ? ? [];
if ( empty ( $collections )) {
2022-08-14 06:56:12 +00:00
throw new Exception ( Exception :: GENERAL_SERVER_ERROR , 'The "collections" collection is not configured.' );
2022-06-22 10:51:49 +00:00
}
$attributes = [];
$indexes = [];
foreach ( $collections [ 'attributes' ] as $attribute ) {
$attributes [] = new Document ([
2022-08-15 11:24:31 +00:00
'$id' => $attribute [ '$id' ],
2022-06-22 10:51:49 +00:00
'type' => $attribute [ 'type' ],
'size' => $attribute [ 'size' ],
'required' => $attribute [ 'required' ],
'signed' => $attribute [ 'signed' ],
'array' => $attribute [ 'array' ],
'filters' => $attribute [ 'filters' ],
'default' => $attribute [ 'default' ] ? ? null ,
'format' => $attribute [ 'format' ] ? ? ''
]);
}
foreach ( $collections [ 'indexes' ] as $index ) {
$indexes [] = new Document ([
2022-08-15 11:24:31 +00:00
'$id' => $index [ '$id' ],
2022-06-22 10:51:49 +00:00
'type' => $index [ 'type' ],
'attributes' => $index [ 'attributes' ],
'lengths' => $index [ 'lengths' ],
'orders' => $index [ 'orders' ],
]);
}
$dbForProject -> createCollection ( 'database_' . $database -> getInternalId (), $attributes , $indexes );
} catch ( DuplicateException $th ) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DATABASE_ALREADY_EXISTS );
2022-06-22 10:51:49 +00:00
}
$events -> setParam ( 'databaseId' , $database -> getId ());
2022-09-07 11:02:36 +00:00
$response
-> setStatusCode ( Response :: STATUS_CODE_CREATED )
-> dynamic ( $database , Response :: MODEL_DATABASE );
2022-06-22 10:51:49 +00:00
});
App :: get ( '/v1/databases' )
-> desc ( 'List Databases' )
-> groups ([ 'api' , 'database' ])
-> label ( 'scope' , 'databases.read' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'databases.{scope}.requests.read' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'databases' )
-> label ( 'sdk.method' , 'list' )
-> label ( 'sdk.description' , '/docs/references/databases/list.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2022-06-24 07:06:21 +00:00
-> label ( 'sdk.response.model' , Response :: MODEL_DATABASE_LIST )
2022-08-23 09:40:17 +00:00
-> param ( 'queries' , [], new Databases (), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). 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 ( ', ' , Databases :: ALLOWED_ATTRIBUTES ), true )
2022-06-22 10:51:49 +00:00
-> param ( 'search' , '' , new Text ( 256 ), 'Search term to filter your list results. Max length: 256 chars.' , true )
-> inject ( 'response' )
-> inject ( 'dbForProject' )
2022-08-25 09:59:28 +00:00
-> action ( function ( array $queries , string $search , Response $response , Database $dbForProject ) {
2022-06-22 10:51:49 +00:00
2022-08-23 09:40:17 +00:00
$queries = Query :: parseQueries ( $queries );
2022-08-11 23:53:52 +00:00
if ( ! empty ( $search )) {
2022-08-23 09:40:17 +00:00
$queries [] = Query :: search ( 'search' , $search );
2022-08-11 23:53:52 +00:00
}
2022-08-23 09:40:17 +00:00
// Get cursor document if there was a cursor query
2022-08-30 23:31:43 +00:00
$cursor = Query :: getByType ( $queries , Query :: TYPE_CURSORAFTER , Query :: TYPE_CURSORBEFORE );
$cursor = reset ( $cursor );
2022-08-30 11:55:23 +00:00
if ( $cursor ) {
2022-08-23 09:40:17 +00:00
/** @var Query $cursor */
$databaseId = $cursor -> getValue ();
$cursorDocument = $dbForProject -> getDocument ( 'databases' , $databaseId );
2022-06-22 10:51:49 +00:00
if ( $cursorDocument -> isEmpty ()) {
2022-08-23 09:40:17 +00:00
throw new Exception ( Exception :: GENERAL_CURSOR_NOT_FOUND , " Database ' { $databaseId } ' for the 'cursor' value not found. " );
2022-06-22 10:51:49 +00:00
}
2022-08-23 09:40:17 +00:00
$cursor -> setValue ( $cursorDocument );
2022-06-22 10:51:49 +00:00
}
2022-08-23 09:40:17 +00:00
$filterQueries = Query :: groupByType ( $queries )[ 'filters' ];
2022-06-22 10:51:49 +00:00
$response -> dynamic ( new Document ([
2022-08-23 09:40:17 +00:00
'databases' => $dbForProject -> find ( 'databases' , $queries ),
2022-08-11 23:53:52 +00:00
'total' => $dbForProject -> count ( 'databases' , $filterQueries , APP_LIMIT_COUNT ),
2022-06-22 10:51:49 +00:00
]), Response :: MODEL_DATABASE_LIST );
});
App :: get ( '/v1/databases/:databaseId' )
-> desc ( 'Get Database' )
-> groups ([ 'api' , 'database' ])
-> label ( 'scope' , 'databases.read' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'databases.{scope}.requests.read' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'databases' )
-> label ( 'sdk.method' , 'get' )
-> label ( 'sdk.description' , '/docs/references/databases/get.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2022-07-17 07:14:37 +00:00
-> label ( 'sdk.response.model' , Response :: MODEL_DATABASE )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
-> inject ( 'response' )
-> inject ( 'dbForProject' )
2022-08-10 02:18:18 +00:00
-> action ( function ( string $databaseId , Response $response , Database $dbForProject ) {
2022-06-22 10:51:49 +00:00
$database = $dbForProject -> getDocument ( 'databases' , $databaseId );
if ( $database -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 10:51:49 +00:00
}
$response -> dynamic ( $database , Response :: MODEL_DATABASE );
});
App :: get ( '/v1/databases/:databaseId/logs' )
2022-08-19 14:14:39 +00:00
-> desc ( 'List Database Logs' )
2022-06-22 10:51:49 +00:00
-> groups ([ 'api' , 'database' ])
2022-08-19 14:14:39 +00:00
-> label ( 'scope' , 'databases.read' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_ADMIN ])
-> label ( 'sdk.namespace' , 'databases' )
-> label ( 'sdk.method' , 'listLogs' )
2022-08-19 14:14:39 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/get-logs.md' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_LOG_LIST )
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-23 13:03:38 +00:00
-> param ( 'queries' , [], new Queries ( new Limit (), new Offset ()), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Only supported methods are limit and offset' , true )
2022-06-22 10:51:49 +00:00
-> inject ( 'response' )
-> inject ( 'dbForProject' )
-> inject ( 'locale' )
-> inject ( 'geodb' )
2022-08-23 13:03:38 +00:00
-> action ( function ( string $databaseId , array $queries , Response $response , Database $dbForProject , Locale $locale , Reader $geodb ) {
2022-06-22 10:51:49 +00:00
$database = $dbForProject -> getDocument ( 'databases' , $databaseId );
if ( $database -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 10:51:49 +00:00
}
2022-08-23 13:03:38 +00:00
$queries = Query :: parseQueries ( $queries );
$grouped = Query :: groupByType ( $queries );
2022-08-30 11:55:23 +00:00
$limit = $grouped [ 'limit' ] ? ? APP_LIMIT_COUNT ;
2022-08-23 13:03:38 +00:00
$offset = $grouped [ 'offset' ] ? ? 0 ;
2022-06-22 10:51:49 +00:00
$audit = new Audit ( $dbForProject );
$resource = 'database/' . $databaseId ;
$logs = $audit -> getLogsByResource ( $resource , $limit , $offset );
2022-08-23 13:10:27 +00:00
2022-08-23 13:03:38 +00:00
$output = [];
2022-06-22 10:51:49 +00:00
foreach ( $logs as $i => & $log ) {
$log [ 'userAgent' ] = ( ! empty ( $log [ 'userAgent' ])) ? $log [ 'userAgent' ] : 'UNKNOWN' ;
$detector = new Detector ( $log [ 'userAgent' ]);
$detector -> skipBotDetection (); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then)
$os = $detector -> getOS ();
$client = $detector -> getClient ();
$device = $detector -> getDevice ();
$output [ $i ] = new Document ([
'event' => $log [ 'event' ],
2022-08-14 10:33:36 +00:00
'userId' => ID :: custom ( $log [ 'userId' ]),
2022-06-22 10:51:49 +00:00
'userEmail' => $log [ 'data' ][ 'userEmail' ] ? ? null ,
'userName' => $log [ 'data' ][ 'userName' ] ? ? null ,
'mode' => $log [ 'data' ][ 'mode' ] ? ? null ,
'ip' => $log [ 'ip' ],
'time' => $log [ 'time' ],
'osCode' => $os [ 'osCode' ],
'osName' => $os [ 'osName' ],
'osVersion' => $os [ 'osVersion' ],
'clientType' => $client [ 'clientType' ],
'clientCode' => $client [ 'clientCode' ],
'clientName' => $client [ 'clientName' ],
'clientVersion' => $client [ 'clientVersion' ],
'clientEngine' => $client [ 'clientEngine' ],
'clientEngineVersion' => $client [ 'clientEngineVersion' ],
'deviceName' => $device [ 'deviceName' ],
'deviceBrand' => $device [ 'deviceBrand' ],
'deviceModel' => $device [ 'deviceModel' ]
]);
$record = $geodb -> get ( $log [ 'ip' ]);
if ( $record ) {
$output [ $i ][ 'countryCode' ] = $locale -> getText ( 'countries.' . strtolower ( $record [ 'country' ][ 'iso_code' ]), false ) ? \strtolower ( $record [ 'country' ][ 'iso_code' ]) : '--' ;
$output [ $i ][ 'countryName' ] = $locale -> getText ( 'countries.' . strtolower ( $record [ 'country' ][ 'iso_code' ]), $locale -> getText ( 'locale.country.unknown' ));
} else {
$output [ $i ][ 'countryCode' ] = '--' ;
$output [ $i ][ 'countryName' ] = $locale -> getText ( 'locale.country.unknown' );
}
}
$response -> dynamic ( new Document ([
'total' => $audit -> countLogsByResource ( $resource ),
'logs' => $output ,
]), Response :: MODEL_LOG_LIST );
});
App :: put ( '/v1/databases/:databaseId' )
-> desc ( 'Update Database' )
-> groups ([ 'api' , 'database' ])
-> label ( 'scope' , 'databases.write' )
-> label ( 'event' , 'databases.[databaseId].update' )
2022-09-05 08:00:08 +00:00
-> label ( 'audits.event' , 'database.update' )
2022-08-08 14:32:54 +00:00
-> label ( 'audits.resource' , 'database/{response.$id}' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'databases.{scope}.requests.update' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'databases' )
-> label ( 'sdk.method' , 'update' )
-> label ( 'sdk.description' , '/docs/references/databases/update.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2022-07-17 07:14:37 +00:00
-> label ( 'sdk.response.model' , Response :: MODEL_DATABASE )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
-> param ( 'name' , null , new Text ( 128 ), 'Collection name. Max length: 128 chars.' )
2022-06-22 13:30:35 +00:00
-> inject ( 'response' )
2022-06-22 10:51:49 +00:00
-> inject ( 'dbForProject' )
-> inject ( 'events' )
2022-08-10 02:18:18 +00:00
-> action ( function ( string $databaseId , string $name , Response $response , Database $dbForProject , Event $events ) {
2022-06-22 10:51:49 +00:00
$database = $dbForProject -> getDocument ( 'databases' , $databaseId );
if ( $database -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 10:51:49 +00:00
}
try {
$database = $dbForProject -> updateDocument ( 'databases' , $databaseId , $database
-> setAttribute ( 'name' , $name )
-> setAttribute ( 'search' , implode ( ' ' , [ $databaseId , $name ])));
} catch ( AuthorizationException $exception ) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: USER_UNAUTHORIZED );
2022-06-22 10:51:49 +00:00
} catch ( StructureException $exception ) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DOCUMENT_INVALID_STRUCTURE , 'Bad structure. ' . $exception -> getMessage ());
2022-06-22 10:51:49 +00:00
}
$events -> setParam ( 'databaseId' , $database -> getId ());
$response -> dynamic ( $database , Response :: MODEL_DATABASE );
});
App :: delete ( '/v1/databases/:databaseId' )
-> desc ( 'Delete Database' )
-> groups ([ 'api' , 'database' ])
-> label ( 'scope' , 'databases.write' )
-> label ( 'event' , 'databases.[databaseId].delete' )
2022-09-05 08:00:08 +00:00
-> label ( 'audits.event' , 'database.delete' )
2022-08-08 14:32:54 +00:00
-> label ( 'audits.resource' , 'database/{request.databaseId}' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'databases.{scope}.requests.delete' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'databases' )
-> label ( 'sdk.method' , 'delete' )
-> label ( 'sdk.description' , '/docs/references/databases/delete.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_NOCONTENT )
-> label ( 'sdk.response.model' , Response :: MODEL_NONE )
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
-> inject ( 'response' )
-> inject ( 'dbForProject' )
-> inject ( 'events' )
-> inject ( 'deletes' )
2022-08-13 03:14:28 +00:00
-> action ( function ( string $databaseId , Response $response , Database $dbForProject , Event $events , Delete $deletes ) {
2022-06-22 10:51:49 +00:00
$database = $dbForProject -> getDocument ( 'databases' , $databaseId );
if ( $database -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 10:51:49 +00:00
}
if ( ! $dbForProject -> deleteDocument ( 'databases' , $databaseId )) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: GENERAL_SERVER_ERROR , 'Failed to remove collection from DB' );
2022-06-22 10:51:49 +00:00
}
$dbForProject -> deleteCachedCollection ( 'databases' . $database -> getInternalId ());
$deletes
-> setType ( DELETE_TYPE_DOCUMENT )
-> setDocument ( $database )
;
$events
-> setParam ( 'databaseId' , $database -> getId ())
-> setPayload ( $response -> output ( $database , Response :: MODEL_DATABASE ))
;
$response -> noContent ();
});
App :: post ( '/v1/databases/:databaseId/collections' )
2022-06-23 08:50:11 +00:00
-> alias ( '/v1/database/collections' , [ 'databaseId' => 'default' ])
2019-05-09 06:54:39 +00:00
-> desc ( 'Create Collection' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'database' ])
2022-06-22 10:51:49 +00:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].create' )
2019-06-08 13:13:19 +00:00
-> label ( 'scope' , 'collections.write' )
2022-09-05 08:00:08 +00:00
-> label ( 'audits.event' , 'collection.create' )
2022-08-08 15:44:11 +00:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{response.$id}' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.create' )
2022-08-21 02:10:21 +00:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-04-16 07:22:17 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.namespace' , 'databases' )
2019-05-09 06:54:39 +00:00
-> label ( 'sdk.method' , 'createCollection' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/create-collection.md' )
2020-11-11 21:02:24 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_CREATED )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_COLLECTION )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-01-12 22:05:25 +00:00
-> param ( 'collectionId' , '' , new CustomId (), 'Unique Id. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.' )
2021-07-29 08:09:24 +00:00
-> param ( 'name' , '' , new Text ( 128 ), 'Collection name. Max length: 128 chars.' )
2022-09-01 13:14:15 +00:00
-> param ( 'permissions' , null , new Permissions ( APP_LIMIT_ARRAY_PARAMS_SIZE ), 'An array of permissions strings. By default no user is granted with any permissions. [Learn more about permissions](/docs/permissions).' , true )
2022-09-03 00:44:33 +00:00
-> param ( 'documentSecurity' , false , new Boolean ( true ), 'Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](/docs/permissions).' , true )
2020-12-26 15:05:04 +00:00
-> inject ( 'response' )
2021-12-27 12:45:23 +00:00
-> inject ( 'dbForProject' )
2022-04-13 12:39:31 +00:00
-> inject ( 'events' )
2022-08-25 06:21:15 +00:00
-> action ( function ( string $databaseId , string $collectionId , string $name , ? array $permissions , bool $documentSecurity , Response $response , Database $dbForProject , Event $events ) {
2022-06-22 10:51:49 +00:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
if ( $database -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 10:51:49 +00:00
}
2021-06-15 13:38:24 +00:00
2022-08-14 14:22:38 +00:00
$collectionId = $collectionId == 'unique()' ? ID :: unique () : $collectionId ;
2021-07-05 20:27:20 +00:00
2022-08-23 01:42:25 +00:00
// Map aggregate permissions into the multiple permissions they represent.
$permissions = Permission :: aggregate ( $permissions );
2022-08-16 08:33:06 +00:00
2021-08-16 17:28:33 +00:00
try {
2022-06-22 10:51:49 +00:00
$dbForProject -> createDocument ( 'database_' . $database -> getInternalId (), new Document ([
2022-08-14 14:22:38 +00:00
'$id' => $collectionId ,
2022-06-22 10:51:49 +00:00
'databaseInternalId' => $database -> getInternalId (),
'databaseId' => $databaseId ,
2022-08-19 04:49:34 +00:00
'$permissions' => $permissions ? ? [],
2022-08-04 04:20:11 +00:00
'documentSecurity' => $documentSecurity ,
2021-12-13 12:42:04 +00:00
'enabled' => true ,
2021-08-16 17:28:33 +00:00
'name' => $name ,
'search' => implode ( ' ' , [ $collectionId , $name ]),
]));
2022-06-22 10:51:49 +00:00
$collection = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId );
2022-01-24 08:20:02 +00:00
2022-06-22 10:51:49 +00:00
$dbForProject -> createCollection ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId ());
2022-08-24 08:50:05 +00:00
} catch ( DuplicateException ) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: COLLECTION_ALREADY_EXISTS );
2022-08-24 08:50:05 +00:00
} catch ( LimitException ) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: COLLECTION_LIMIT_EXCEEDED );
2021-08-16 17:28:33 +00:00
}
2019-05-09 06:54:39 +00:00
2022-06-22 10:51:49 +00:00
$events
-> setContext ( 'database' , $database )
-> setParam ( 'databaseId' , $databaseId )
-> setParam ( 'collectionId' , $collection -> getId ());
2022-09-07 11:11:10 +00:00
$response
-> setStatusCode ( Response :: STATUS_CODE_CREATED )
-> dynamic ( $collection , Response :: MODEL_COLLECTION );
2020-12-26 15:05:04 +00:00
});
2019-05-09 06:54:39 +00:00
2022-06-22 10:51:49 +00:00
App :: get ( '/v1/databases/:databaseId/collections' )
2022-06-23 08:50:11 +00:00
-> alias ( '/v1/database/collections' , [ 'databaseId' => 'default' ])
2020-01-31 22:34:07 +00:00
-> desc ( 'List Collections' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'database' ])
2020-01-31 22:34:07 +00:00
-> label ( 'scope' , 'collections.read' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.read' )
2022-08-21 02:10:21 +00:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-04-16 07:22:17 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.namespace' , 'databases' )
2020-01-31 22:34:07 +00:00
-> label ( 'sdk.method' , 'listCollections' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/list-collections.md' )
2020-11-11 21:02:24 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_COLLECTION_LIST )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-23 12:30:28 +00:00
-> param ( 'queries' , [], new Collections (), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). 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 ( ', ' , Collections :: ALLOWED_ATTRIBUTES ), true )
2021-07-05 19:19:18 +00:00
-> param ( 'search' , '' , new Text ( 256 ), 'Search term to filter your list results. Max length: 256 chars.' , true )
2020-12-26 15:05:04 +00:00
-> inject ( 'response' )
2021-12-27 12:45:23 +00:00
-> inject ( 'dbForProject' )
2022-08-25 09:59:28 +00:00
-> action ( function ( string $databaseId , array $queries , string $search , Response $response , Database $dbForProject ) {
2022-06-22 10:51:49 +00:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
if ( $database -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 10:51:49 +00:00
}
2020-06-29 21:43:34 +00:00
2022-08-23 12:30:28 +00:00
$queries = Query :: parseQueries ( $queries );
2021-08-16 17:28:33 +00:00
2022-08-11 23:53:52 +00:00
if ( ! empty ( $search )) {
2022-08-23 12:30:28 +00:00
$queries [] = Query :: search ( 'search' , $search );
2021-08-16 17:28:33 +00:00
}
2020-06-29 21:43:34 +00:00
2022-08-23 12:30:28 +00:00
// Get cursor document if there was a cursor query
2022-08-30 23:31:43 +00:00
$cursor = Query :: getByType ( $queries , Query :: TYPE_CURSORAFTER , Query :: TYPE_CURSORBEFORE );
$cursor = reset ( $cursor );
2022-08-30 11:55:23 +00:00
if ( $cursor ) {
2022-08-23 12:30:28 +00:00
/** @var Query $cursor */
$collectionId = $cursor -> getValue ();
$cursorDocument = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId );
2021-08-06 12:35:57 +00:00
2022-08-11 23:53:52 +00:00
if ( $cursorDocument -> isEmpty ()) {
2022-08-23 12:30:28 +00:00
throw new Exception ( Exception :: GENERAL_CURSOR_NOT_FOUND , " Collection ' { $collectionId } ' for the 'cursor' value not found. " );
2022-08-11 23:53:52 +00:00
}
2022-08-23 12:30:28 +00:00
$cursor -> setValue ( $cursorDocument );
2021-08-06 12:35:57 +00:00
}
2022-08-23 12:30:28 +00:00
$filterQueries = Query :: groupByType ( $queries )[ 'filters' ];
2021-07-25 14:47:18 +00:00
$response -> dynamic ( new Document ([
2022-08-23 12:30:28 +00:00
'collections' => $dbForProject -> find ( 'database_' . $database -> getInternalId (), $queries ),
2022-08-11 23:53:52 +00:00
'total' => $dbForProject -> count ( 'database_' . $database -> getInternalId (), $filterQueries , APP_LIMIT_COUNT ),
2020-10-30 19:53:27 +00:00
]), Response :: MODEL_COLLECTION_LIST );
2020-12-26 15:05:04 +00:00
});
2020-01-31 22:34:07 +00:00
2022-06-22 10:51:49 +00:00
App :: get ( '/v1/databases/:databaseId/collections/:collectionId' )
2022-06-23 08:50:11 +00:00
-> alias ( '/v1/database/collections/:collectionId' , [ 'databaseId' => 'default' ])
2020-01-31 22:34:07 +00:00
-> desc ( 'Get Collection' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'database' ])
2020-01-31 22:34:07 +00:00
-> label ( 'scope' , 'collections.read' )
2022-08-15 05:50:36 +00:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.read' )
2022-08-21 02:10:21 +00:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-04-16 07:22:17 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.namespace' , 'databases' )
2020-01-31 22:34:07 +00:00
-> label ( 'sdk.method' , 'getCollection' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/get-collection.md' )
2020-11-11 21:02:24 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_COLLECTION )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2021-12-10 12:27:11 +00:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID.' )
2020-12-26 15:05:04 +00:00
-> inject ( 'response' )
2021-12-27 12:45:23 +00:00
-> inject ( 'dbForProject' )
2022-08-10 02:18:18 +00:00
-> action ( function ( string $databaseId , string $collectionId , Response $response , Database $dbForProject ) {
2020-01-31 22:34:07 +00:00
2022-06-22 10:51:49 +00:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2021-10-27 19:57:20 +00:00
2022-06-22 10:51:49 +00:00
if ( $database -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2021-08-20 10:04:57 +00:00
}
2022-08-08 10:58:28 +00:00
2022-06-22 10:51:49 +00:00
$collection = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId );
2021-08-20 11:38:57 +00:00
if ( $collection -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-08-20 11:38:57 +00:00
}
2021-12-28 15:48:36 +00:00
2022-06-22 10:51:49 +00:00
$response -> dynamic ( $collection , Response :: MODEL_COLLECTION );
2021-08-20 11:38:57 +00:00
});
2021-08-20 08:24:45 +00:00
2022-06-22 10:51:49 +00:00
App :: get ( '/v1/databases/:databaseId/collections/:collectionId/logs' )
2022-06-23 08:50:11 +00:00
-> alias ( '/v1/database/collections/:collectionId/logs' , [ 'databaseId' => 'default' ])
2021-08-14 10:13:24 +00:00
-> desc ( 'List Collection Logs' )
2021-08-10 18:03:32 +00:00
-> groups ([ 'api' , 'database' ])
-> label ( 'scope' , 'collections.read' )
2022-08-21 02:10:21 +00:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.read' )
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-08-10 18:03:32 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_ADMIN ])
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.namespace' , 'databases' )
2021-08-14 10:13:24 +00:00
-> label ( 'sdk.method' , 'listCollectionLogs' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/get-collection-logs.md' )
2021-08-10 18:03:32 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_LOG_LIST )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2021-12-10 12:27:11 +00:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID.' )
2022-08-23 13:03:38 +00:00
-> param ( 'queries' , [], new Queries ( new Limit (), new Offset ()), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Only supported methods are limit and offset' , true )
2021-08-10 18:03:32 +00:00
-> inject ( 'response' )
2021-12-27 12:45:23 +00:00
-> inject ( 'dbForProject' )
2021-08-10 18:03:32 +00:00
-> inject ( 'locale' )
-> inject ( 'geodb' )
2022-08-23 13:03:38 +00:00
-> action ( function ( string $databaseId , string $collectionId , array $queries , Response $response , Database $dbForProject , Locale $locale , Reader $geodb ) {
2021-08-10 18:03:32 +00:00
2022-06-22 10:51:49 +00:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
if ( $database -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 10:51:49 +00:00
}
$collectionDocument = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId );
$collection = $dbForProject -> getCollection ( 'database_' . $database -> getInternalId () . '_collection_' . $collectionDocument -> getInternalId ());
2021-08-10 18:03:32 +00:00
if ( $collection -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-08-10 18:03:32 +00:00
}
2022-08-23 13:03:38 +00:00
$queries = Query :: parseQueries ( $queries );
$grouped = Query :: groupByType ( $queries );
2022-08-30 11:55:23 +00:00
$limit = $grouped [ 'limit' ] ? ? APP_LIMIT_COUNT ;
2022-08-23 13:03:38 +00:00
$offset = $grouped [ 'offset' ] ? ? 0 ;
2021-12-27 12:45:23 +00:00
$audit = new Audit ( $dbForProject );
2022-06-22 10:51:49 +00:00
$resource = 'database/' . $databaseId . '/collection/' . $collectionId ;
2021-11-16 14:54:29 +00:00
$logs = $audit -> getLogsByResource ( $resource , $limit , $offset );
2021-08-10 18:03:32 +00:00
$output = [];
foreach ( $logs as $i => & $log ) {
$log [ 'userAgent' ] = ( ! empty ( $log [ 'userAgent' ])) ? $log [ 'userAgent' ] : 'UNKNOWN' ;
2021-12-12 17:58:17 +00:00
$detector = new Detector ( $log [ 'userAgent' ]);
$detector -> skipBotDetection (); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then)
2021-08-10 18:03:32 +00:00
2021-12-12 17:58:17 +00:00
$os = $detector -> getOS ();
$client = $detector -> getClient ();
$device = $detector -> getDevice ();
2021-08-10 18:03:32 +00:00
$output [ $i ] = new Document ([
'event' => $log [ 'event' ],
2021-08-13 11:19:16 +00:00
'userId' => $log [ 'userId' ],
2021-08-14 10:13:24 +00:00
'userEmail' => $log [ 'data' ][ 'userEmail' ] ? ? null ,
'userName' => $log [ 'data' ][ 'userName' ] ? ? null ,
'mode' => $log [ 'data' ][ 'mode' ] ? ? null ,
2021-08-10 18:03:32 +00:00
'ip' => $log [ 'ip' ],
'time' => $log [ 'time' ],
2021-12-12 17:58:17 +00:00
'osCode' => $os [ 'osCode' ],
'osName' => $os [ 'osName' ],
'osVersion' => $os [ 'osVersion' ],
'clientType' => $client [ 'clientType' ],
'clientCode' => $client [ 'clientCode' ],
'clientName' => $client [ 'clientName' ],
'clientVersion' => $client [ 'clientVersion' ],
'clientEngine' => $client [ 'clientEngine' ],
'clientEngineVersion' => $client [ 'clientEngineVersion' ],
'deviceName' => $device [ 'deviceName' ],
'deviceBrand' => $device [ 'deviceBrand' ],
2021-12-12 17:59:12 +00:00
'deviceModel' => $device [ 'deviceModel' ]
2021-08-10 18:03:32 +00:00
]);
$record = $geodb -> get ( $log [ 'ip' ]);
if ( $record ) {
2022-05-23 14:54:50 +00:00
$output [ $i ][ 'countryCode' ] = $locale -> getText ( 'countries.' . strtolower ( $record [ 'country' ][ 'iso_code' ]), false ) ? \strtolower ( $record [ 'country' ][ 'iso_code' ]) : '--' ;
$output [ $i ][ 'countryName' ] = $locale -> getText ( 'countries.' . strtolower ( $record [ 'country' ][ 'iso_code' ]), $locale -> getText ( 'locale.country.unknown' ));
2021-08-10 18:03:32 +00:00
} else {
$output [ $i ][ 'countryCode' ] = '--' ;
$output [ $i ][ 'countryName' ] = $locale -> getText ( 'locale.country.unknown' );
}
}
2021-11-16 14:54:29 +00:00
$response -> dynamic ( new Document ([
2022-02-27 09:57:09 +00:00
'total' => $audit -> countLogsByResource ( $resource ),
2021-11-16 14:54:29 +00:00
'logs' => $output ,
]), Response :: MODEL_LOG_LIST );
2021-08-10 18:03:32 +00:00
});
2022-06-22 10:51:49 +00:00
App :: put ( '/v1/databases/:databaseId/collections/:collectionId' )
2022-06-23 08:50:11 +00:00
-> alias ( '/v1/database/collections/:collectionId' , [ 'databaseId' => 'default' ])
2019-06-09 11:44:58 +00:00
-> desc ( 'Update Collection' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'database' ])
2019-06-08 13:13:19 +00:00
-> label ( 'scope' , 'collections.write' )
2022-06-22 10:51:49 +00:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].update' )
2022-09-05 08:00:08 +00:00
-> label ( 'audits.event' , 'collection.update' )
2022-08-08 12:19:41 +00:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
2022-08-21 02:10:21 +00:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-04-16 07:22:17 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.namespace' , 'databases' )
2019-06-09 08:51:10 +00:00
-> label ( 'sdk.method' , 'updateCollection' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/update-collection.md' )
2020-11-11 21:02:24 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_COLLECTION )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2021-12-10 12:27:11 +00:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID.' )
2021-07-29 08:09:24 +00:00
-> param ( 'name' , null , new Text ( 128 ), 'Collection name. Max length: 128 chars.' )
2022-08-27 03:19:00 +00:00
-> param ( 'permissions' , null , new Permissions ( APP_LIMIT_ARRAY_PARAMS_SIZE ), 'An array of permission strings. By default the current permission are inherited. [Learn more about permissions](/docs/permissions).' , true )
2022-09-02 03:39:54 +00:00
-> param ( 'documentSecurity' , false , new Boolean ( true ), 'Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](/docs/permissions).' , true )
2021-12-13 12:42:04 +00:00
-> param ( 'enabled' , true , new Boolean (), 'Is collection enabled?' , true )
2020-12-26 15:05:04 +00:00
-> inject ( 'response' )
2021-12-27 12:45:23 +00:00
-> inject ( 'dbForProject' )
2022-04-13 12:39:31 +00:00
-> inject ( 'events' )
2022-08-25 06:21:15 +00:00
-> action ( function ( string $databaseId , string $collectionId , string $name , ? array $permissions , bool $documentSecurity , bool $enabled , Response $response , Database $dbForProject , Event $events ) {
2019-05-09 06:54:39 +00:00
2022-06-22 10:51:49 +00:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
if ( $database -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 10:51:49 +00:00
}
2022-08-08 10:58:28 +00:00
2022-06-22 10:51:49 +00:00
$collection = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId );
2019-10-01 04:57:41 +00:00
2021-06-16 20:36:18 +00:00
if ( $collection -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2020-06-29 21:43:34 +00:00
}
2019-10-01 04:57:41 +00:00
2022-08-04 00:08:16 +00:00
$permissions ? ? = $collection -> getPermissions () ? ? [];
2022-08-16 08:33:06 +00:00
2022-08-23 01:42:25 +00:00
// Map aggregate permissions into the multiple permissions they represent.
$permissions = Permission :: aggregate ( $permissions );
2022-08-16 08:33:06 +00:00
2021-12-13 12:42:04 +00:00
$enabled ? ? = $collection -> getAttribute ( 'enabled' , true );
2019-05-09 06:54:39 +00:00
2020-06-29 21:43:34 +00:00
try {
2022-06-22 10:51:49 +00:00
$collection = $dbForProject -> updateDocument ( 'database_' . $database -> getInternalId (), $collectionId , $collection
2021-08-16 17:28:33 +00:00
-> setAttribute ( 'name' , $name )
2022-08-04 04:20:11 +00:00
-> setAttribute ( '$permissions' , $permissions )
2022-08-02 09:18:49 +00:00
-> setAttribute ( 'documentSecurity' , $documentSecurity )
2021-12-13 12:42:04 +00:00
-> setAttribute ( 'enabled' , $enabled )
2022-05-23 14:54:50 +00:00
-> setAttribute ( 'search' , implode ( ' ' , [ $collectionId , $name ])));
2022-08-08 10:58:28 +00:00
} catch ( AuthorizationException ) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: USER_UNAUTHORIZED );
2022-05-23 14:54:50 +00:00
} catch ( StructureException $exception ) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DOCUMENT_INVALID_STRUCTURE , 'Bad structure. ' . $exception -> getMessage ());
2021-08-16 17:28:33 +00:00
}
2020-01-04 15:45:28 +00:00
2022-06-22 10:51:49 +00:00
$events
-> setContext ( 'database' , $database )
-> setParam ( 'databaseId' , $databaseId )
-> setParam ( 'collectionId' , $collection -> getId ());
2022-04-13 12:39:31 +00:00
2021-07-25 14:47:18 +00:00
$response -> dynamic ( $collection , Response :: MODEL_COLLECTION );
2020-12-26 15:05:04 +00:00
});
2019-05-09 06:54:39 +00:00
2022-06-22 10:51:49 +00:00
App :: delete ( '/v1/databases/:databaseId/collections/:collectionId' )
2022-06-23 08:50:11 +00:00
-> alias ( '/v1/database/collections/:collectionId' , [ 'databaseId' => 'default' ])
2019-05-09 06:54:39 +00:00
-> desc ( 'Delete Collection' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'database' ])
2019-06-08 13:13:19 +00:00
-> label ( 'scope' , 'collections.write' )
2022-06-22 10:51:49 +00:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].delete' )
2022-09-05 08:00:08 +00:00
-> label ( 'audits.event' , 'collection.delete' )
2022-08-08 14:32:54 +00:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.delete' )
2022-08-21 02:10:21 +00:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-04-16 07:22:17 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.namespace' , 'databases' )
2019-05-09 06:54:39 +00:00
-> label ( 'sdk.method' , 'deleteCollection' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/delete-collection.md' )
2020-11-11 21:02:24 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_NOCONTENT )
-> label ( 'sdk.response.model' , Response :: MODEL_NONE )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2021-12-10 12:27:11 +00:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID.' )
2020-12-26 15:05:04 +00:00
-> inject ( 'response' )
2021-12-27 12:45:23 +00:00
-> inject ( 'dbForProject' )
2020-12-26 15:05:04 +00:00
-> inject ( 'events' )
-> inject ( 'deletes' )
2022-08-13 03:14:28 +00:00
-> action ( function ( string $databaseId , string $collectionId , Response $response , Database $dbForProject , Event $events , Delete $deletes ) {
2022-06-22 10:51:49 +00:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
if ( $database -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 10:51:49 +00:00
}
2019-05-09 06:54:39 +00:00
2022-06-22 10:51:49 +00:00
$collection = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId );
2019-05-09 06:54:39 +00:00
2021-06-11 14:25:52 +00:00
if ( $collection -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2020-06-29 21:43:34 +00:00
}
2020-01-04 15:45:28 +00:00
2022-06-22 10:51:49 +00:00
if ( ! $dbForProject -> deleteDocument ( 'database_' . $database -> getInternalId (), $collectionId )) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: GENERAL_SERVER_ERROR , 'Failed to remove collection from DB' );
2021-08-16 17:28:33 +00:00
}
2020-12-04 20:47:02 +00:00
2022-06-22 10:51:49 +00:00
$dbForProject -> deleteCachedCollection ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId ());
2021-11-02 00:48:38 +00:00
2021-09-02 16:45:03 +00:00
$deletes
2022-04-17 20:34:32 +00:00
-> setType ( DELETE_TYPE_DOCUMENT )
-> setDocument ( $collection )
2021-09-02 16:45:03 +00:00
;
2020-12-06 22:14:57 +00:00
$events
2022-06-22 10:51:49 +00:00
-> setContext ( 'database' , $database )
-> setParam ( 'databaseId' , $databaseId )
2022-04-13 12:39:31 +00:00
-> setParam ( 'collectionId' , $collection -> getId ())
-> setPayload ( $response -> output ( $collection , Response :: MODEL_COLLECTION ))
2020-06-29 21:43:34 +00:00
;
2019-05-09 06:54:39 +00:00
2020-06-29 21:43:34 +00:00
$response -> noContent ();
2020-12-26 15:05:04 +00:00
});
2019-05-09 06:54:39 +00:00
2022-06-22 10:51:49 +00:00
App :: post ( '/v1/databases/:databaseId/collections/:collectionId/attributes/string' )
2022-06-23 08:50:11 +00:00
-> alias ( '/v1/database/collections/:collectionId/attributes/string' , [ 'databaseId' => 'default' ])
2021-07-21 13:23:12 +00:00
-> desc ( 'Create String Attribute' )
2021-03-24 15:40:33 +00:00
-> groups ([ 'api' , 'database' ])
2022-06-22 10:51:49 +00:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create' )
2021-08-14 10:16:00 +00:00
-> label ( 'scope' , 'collections.write' )
2022-09-05 08:00:08 +00:00
-> label ( 'audits.event' , 'attribute.create' )
2022-08-08 12:19:41 +00:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
2022-08-21 02:10:21 +00:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-07-31 20:40:34 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.namespace' , 'databases' )
2021-07-21 13:23:12 +00:00
-> label ( 'sdk.method' , 'createStringAttribute' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/create-string-attribute.md' )
2022-07-14 09:52:55 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_ACCEPTED )
2021-03-24 15:40:33 +00:00
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2021-09-30 19:37:21 +00:00
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_STRING )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 08:14:27 +00:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).' )
2021-12-16 15:04:30 +00:00
-> param ( 'key' , '' , new Key (), 'Attribute Key.' )
2021-10-26 20:51:40 +00:00
-> param ( 'size' , null , new Range ( 1 , APP_DATABASE_ATTRIBUTE_STRING_MAX_LENGTH , Range :: TYPE_INTEGER ), 'Attribute size for text attributes, in number of characters.' )
2021-06-09 21:11:51 +00:00
-> param ( 'required' , null , new Boolean (), 'Is attribute required?' )
2021-07-21 13:23:12 +00:00
-> param ( 'default' , null , new Text ( 0 ), 'Default value for attribute when not provided. Cannot be set when attribute is required.' , true )
2021-06-11 18:07:05 +00:00
-> param ( 'array' , false , new Boolean (), 'Is attribute an array?' , true )
2021-03-24 15:40:33 +00:00
-> inject ( 'response' )
2021-12-27 12:45:23 +00:00
-> inject ( 'dbForProject' )
2021-06-18 16:13:37 +00:00
-> inject ( 'database' )
2022-04-13 12:39:31 +00:00
-> inject ( 'events' )
2022-08-10 02:18:18 +00:00
-> action ( function ( string $databaseId , string $collectionId , string $key , ? int $size , ? bool $required , ? string $default , bool $array , Response $response , Database $dbForProject , EventDatabase $database , Event $events ) {
2021-03-24 15:40:33 +00:00
2021-08-16 23:21:00 +00:00
// Ensure attribute default is within required size
$validator = new Text ( $size );
if ( ! is_null ( $default ) && ! $validator -> isValid ( $default )) {
2022-07-26 14:56:59 +00:00
throw new Exception ( Exception :: ATTRIBUTE_VALUE_INVALID , $validator -> getDescription ());
2021-08-16 23:21:00 +00:00
}
2022-06-22 10:51:49 +00:00
$attribute = createAttribute ( $databaseId , $collectionId , new Document ([
2021-12-16 15:04:30 +00:00
'key' => $key ,
2021-07-27 01:00:36 +00:00
'type' => Database :: VAR_STRING ,
'size' => $size ,
'required' => $required ,
'default' => $default ,
'array' => $array ,
2022-08-10 02:18:18 +00:00
]), $response , $dbForProject , $database , $events );
2021-08-16 23:21:00 +00:00
2022-09-07 11:02:36 +00:00
$response
-> setStatusCode ( Response :: STATUS_CODE_ACCEPTED )
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_STRING );
2021-07-27 01:00:36 +00:00
});
2021-06-10 13:15:00 +00:00
2022-06-22 10:51:49 +00:00
App :: post ( '/v1/databases/:databaseId/collections/:collectionId/attributes/email' )
2022-06-23 08:50:11 +00:00
-> alias ( '/v1/database/collections/:collectionId/attributes/email' , [ 'databaseId' => 'default' ])
2021-07-27 01:00:36 +00:00
-> desc ( 'Create Email Attribute' )
-> groups ([ 'api' , 'database' ])
2022-06-22 10:51:49 +00:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create' )
2021-08-14 10:16:00 +00:00
-> label ( 'scope' , 'collections.write' )
2022-09-05 08:00:08 +00:00
-> label ( 'audits.event' , 'attribute.create' )
2022-08-08 12:19:41 +00:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
2022-08-21 02:10:21 +00:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.namespace' , 'databases' )
2021-08-02 20:11:24 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2021-07-27 01:00:36 +00:00
-> label ( 'sdk.method' , 'createEmailAttribute' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/create-email-attribute.md' )
2022-07-14 09:52:55 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_ACCEPTED )
2021-07-27 01:00:36 +00:00
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2021-09-30 19:37:21 +00:00
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_EMAIL )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 08:14:27 +00:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).' )
2021-12-16 15:04:30 +00:00
-> param ( 'key' , '' , new Key (), 'Attribute Key.' )
2021-07-27 01:00:36 +00:00
-> param ( 'required' , null , new Boolean (), 'Is attribute required?' )
2021-08-24 13:46:41 +00:00
-> param ( 'default' , null , new Email (), 'Default value for attribute when not provided. Cannot be set when attribute is required.' , true )
2021-07-27 01:00:36 +00:00
-> param ( 'array' , false , new Boolean (), 'Is attribute an array?' , true )
-> inject ( 'response' )
2021-12-27 12:45:23 +00:00
-> inject ( 'dbForProject' )
2021-07-27 01:00:36 +00:00
-> inject ( 'database' )
2022-04-13 12:39:31 +00:00
-> inject ( 'events' )
2022-08-10 02:18:18 +00:00
-> action ( function ( string $databaseId , string $collectionId , string $key , ? bool $required , ? string $default , bool $array , Response $response , Database $dbForProject , EventDatabase $database , Event $events ) {
2021-07-21 13:23:12 +00:00
2022-06-22 10:51:49 +00:00
$attribute = createAttribute ( $databaseId , $collectionId , new Document ([
2021-12-16 15:04:30 +00:00
'key' => $key ,
2021-07-27 01:00:36 +00:00
'type' => Database :: VAR_STRING ,
'size' => 254 ,
'required' => $required ,
'default' => $default ,
'array' => $array ,
2021-08-23 18:29:05 +00:00
'format' => APP_DATABASE_ATTRIBUTE_EMAIL ,
2022-08-10 02:18:18 +00:00
]), $response , $dbForProject , $database , $events );
2021-08-16 23:21:00 +00:00
2022-09-07 11:02:36 +00:00
$response
-> setStatusCode ( Response :: STATUS_CODE_ACCEPTED )
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_EMAIL );
2021-07-27 01:00:36 +00:00
});
2021-07-21 13:23:12 +00:00
2022-06-22 10:51:49 +00:00
App :: post ( '/v1/databases/:databaseId/collections/:collectionId/attributes/enum' )
2022-06-23 08:50:11 +00:00
-> alias ( '/v1/database/collections/:collectionId/attributes/enum' , [ 'databaseId' => 'default' ])
2021-09-10 20:09:11 +00:00
-> desc ( 'Create Enum Attribute' )
-> groups ([ 'api' , 'database' ])
2022-06-22 10:51:49 +00:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create' )
2021-09-10 20:09:11 +00:00
-> label ( 'scope' , 'collections.write' )
2022-09-05 08:00:08 +00:00
-> label ( 'audits.event' , 'attribute.create' )
2022-08-08 12:19:41 +00:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
2022-08-21 02:10:21 +00:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.namespace' , 'databases' )
2021-09-10 20:09:11 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.method' , 'createEnumAttribute' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/create-attribute-enum.md' )
2022-07-14 09:52:55 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_ACCEPTED )
2021-09-10 20:09:11 +00:00
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2021-10-07 02:25:03 +00:00
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_ENUM )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 08:14:27 +00:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).' )
2021-12-16 15:04:30 +00:00
-> param ( 'key' , '' , new Key (), 'Attribute Key.' )
2022-06-15 12:07:14 +00:00
-> param ( 'elements' , [], new ArrayList ( new Text ( APP_LIMIT_ARRAY_ELEMENT_SIZE ), APP_LIMIT_ARRAY_PARAMS_SIZE ), 'Array of elements in enumerated type. Uses length of longest element to determine size. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' elements are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.' )
2021-09-10 20:09:11 +00:00
-> param ( 'required' , null , new Boolean (), 'Is attribute required?' )
-> param ( 'default' , null , new Text ( 0 ), 'Default value for attribute when not provided. Cannot be set when attribute is required.' , true )
-> param ( 'array' , false , new Boolean (), 'Is attribute an array?' , true )
-> inject ( 'response' )
2021-12-27 12:45:23 +00:00
-> inject ( 'dbForProject' )
2021-09-10 20:09:11 +00:00
-> inject ( 'database' )
2022-04-13 12:39:31 +00:00
-> inject ( 'events' )
2022-08-10 02:18:18 +00:00
-> action ( function ( string $databaseId , string $collectionId , string $key , array $elements , ? bool $required , ? string $default , bool $array , Response $response , Database $dbForProject , EventDatabase $database , Event $events ) {
2021-09-10 20:09:11 +00:00
// use length of longest string as attribute size
$size = 0 ;
foreach ( $elements as $element ) {
$length = \strlen ( $element );
2021-10-07 18:30:52 +00:00
if ( $length === 0 ) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: ATTRIBUTE_VALUE_INVALID , 'Each enum element must not be empty' );
2021-10-07 18:30:52 +00:00
}
2021-09-10 20:09:11 +00:00
$size = ( $length > $size ) ? $length : $size ;
}
2021-12-16 10:15:55 +00:00
if ( ! is_null ( $default ) && ! in_array ( $default , $elements )) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: ATTRIBUTE_VALUE_INVALID , 'Default value not found in elements' );
2021-12-16 10:15:55 +00:00
}
2022-06-22 10:51:49 +00:00
$attribute = createAttribute ( $databaseId , $collectionId , new Document ([
2021-12-16 15:04:30 +00:00
'key' => $key ,
2021-09-10 20:09:11 +00:00
'type' => Database :: VAR_STRING ,
'size' => $size ,
'required' => $required ,
'default' => $default ,
'array' => $array ,
'format' => APP_DATABASE_ATTRIBUTE_ENUM ,
'formatOptions' => [ 'elements' => $elements ],
2022-08-10 02:18:18 +00:00
]), $response , $dbForProject , $database , $events );
2021-09-10 20:09:11 +00:00
2022-09-07 11:02:36 +00:00
$response
-> setStatusCode ( Response :: STATUS_CODE_ACCEPTED )
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_ENUM );
2021-09-10 20:09:11 +00:00
});
2022-06-22 10:51:49 +00:00
App :: post ( '/v1/databases/:databaseId/collections/:collectionId/attributes/ip' )
2022-06-23 08:50:11 +00:00
-> alias ( '/v1/database/collections/:collectionId/attributes/ip' , [ 'databaseId' => 'default' ])
2021-07-27 01:00:36 +00:00
-> desc ( 'Create IP Address Attribute' )
-> groups ([ 'api' , 'database' ])
2022-06-22 10:51:49 +00:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create' )
2021-08-14 10:16:00 +00:00
-> label ( 'scope' , 'collections.write' )
2022-09-05 08:00:08 +00:00
-> label ( 'audits.event' , 'attribute.create' )
2022-08-08 12:19:41 +00:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
2022-08-21 02:10:21 +00:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.namespace' , 'databases' )
2021-08-02 20:11:24 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2021-07-27 01:00:36 +00:00
-> label ( 'sdk.method' , 'createIpAttribute' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/create-ip-attribute.md' )
2022-07-14 09:52:55 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_ACCEPTED )
2021-07-27 01:00:36 +00:00
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2021-09-30 19:37:21 +00:00
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_IP )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 08:14:27 +00:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).' )
2021-12-16 15:04:30 +00:00
-> param ( 'key' , '' , new Key (), 'Attribute Key.' )
2021-07-27 01:00:36 +00:00
-> param ( 'required' , null , new Boolean (), 'Is attribute required?' )
2021-08-24 13:46:41 +00:00
-> param ( 'default' , null , new IP (), 'Default value for attribute when not provided. Cannot be set when attribute is required.' , true )
2021-07-27 01:00:36 +00:00
-> param ( 'array' , false , new Boolean (), 'Is attribute an array?' , true )
-> inject ( 'response' )
2021-12-27 12:45:23 +00:00
-> inject ( 'dbForProject' )
2021-07-27 01:00:36 +00:00
-> inject ( 'database' )
2022-04-13 12:39:31 +00:00
-> inject ( 'events' )
2022-08-10 02:18:18 +00:00
-> action ( function ( string $databaseId , string $collectionId , string $key , ? bool $required , ? string $default , bool $array , Response $response , Database $dbForProject , EventDatabase $database , Event $events ) {
2021-06-10 13:15:00 +00:00
2022-06-22 10:51:49 +00:00
$attribute = createAttribute ( $databaseId , $collectionId , new Document ([
2021-12-16 15:04:30 +00:00
'key' => $key ,
2021-07-27 01:00:36 +00:00
'type' => Database :: VAR_STRING ,
'size' => 39 ,
'required' => $required ,
'default' => $default ,
'array' => $array ,
2021-08-23 18:29:05 +00:00
'format' => APP_DATABASE_ATTRIBUTE_IP ,
2022-08-10 02:18:18 +00:00
]), $response , $dbForProject , $database , $events );
2021-08-16 23:21:00 +00:00
2022-09-07 11:02:36 +00:00
$response
-> setStatusCode ( Response :: STATUS_CODE_ACCEPTED )
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_IP );
2021-07-27 01:00:36 +00:00
});
2021-06-23 14:21:32 +00:00
2022-06-22 10:51:49 +00:00
App :: post ( '/v1/databases/:databaseId/collections/:collectionId/attributes/url' )
2022-06-23 08:50:11 +00:00
-> alias ( '/v1/database/collections/:collectionId/attributes/url' , [ 'databaseId' => 'default' ])
2021-09-23 01:29:56 +00:00
-> desc ( 'Create URL Attribute' )
2021-07-27 01:00:36 +00:00
-> groups ([ 'api' , 'database' ])
2022-06-22 10:51:49 +00:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create' )
2021-08-14 10:16:00 +00:00
-> label ( 'scope' , 'collections.write' )
2022-09-05 08:00:08 +00:00
-> label ( 'audits.event' , 'attribute.create' )
2022-08-08 12:19:41 +00:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
2022-08-21 02:10:21 +00:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.namespace' , 'databases' )
2021-08-02 20:11:24 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2021-07-27 01:00:36 +00:00
-> label ( 'sdk.method' , 'createUrlAttribute' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/create-url-attribute.md' )
2022-07-14 09:52:55 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_ACCEPTED )
2021-07-27 01:00:36 +00:00
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2021-09-30 19:37:21 +00:00
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_URL )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 08:14:27 +00:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).' )
2021-12-16 15:04:30 +00:00
-> param ( 'key' , '' , new Key (), 'Attribute Key.' )
2021-07-27 01:00:36 +00:00
-> param ( 'required' , null , new Boolean (), 'Is attribute required?' )
2021-08-24 13:46:41 +00:00
-> param ( 'default' , null , new URL (), 'Default value for attribute when not provided. Cannot be set when attribute is required.' , true )
2021-07-27 01:00:36 +00:00
-> param ( 'array' , false , new Boolean (), 'Is attribute an array?' , true )
-> inject ( 'response' )
2021-12-27 12:45:23 +00:00
-> inject ( 'dbForProject' )
2021-07-27 01:00:36 +00:00
-> inject ( 'database' )
2022-04-13 12:39:31 +00:00
-> inject ( 'events' )
2022-08-10 02:18:18 +00:00
-> action ( function ( string $databaseId , string $collectionId , string $key , ? bool $required , ? string $default , bool $array , Response $response , Database $dbForProject , EventDatabase $database , Event $events ) {
2021-06-09 21:11:51 +00:00
2022-06-22 10:51:49 +00:00
$attribute = createAttribute ( $databaseId , $collectionId , new Document ([
2021-12-16 15:04:30 +00:00
'key' => $key ,
2021-07-27 01:00:36 +00:00
'type' => Database :: VAR_STRING ,
2021-08-22 12:59:44 +00:00
'size' => 2000 ,
2021-06-09 21:11:51 +00:00
'required' => $required ,
2021-07-02 17:29:03 +00:00
'default' => $default ,
2021-06-09 21:11:51 +00:00
'array' => $array ,
2021-08-23 18:29:05 +00:00
'format' => APP_DATABASE_ATTRIBUTE_URL ,
2022-08-10 02:18:18 +00:00
]), $response , $dbForProject , $database , $events );
2021-08-16 23:21:00 +00:00
2022-09-07 11:02:36 +00:00
$response
-> setStatusCode ( Response :: STATUS_CODE_ACCEPTED )
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_URL );
2021-07-21 13:23:12 +00:00
});
2021-03-24 15:40:33 +00:00
2022-06-22 10:51:49 +00:00
App :: post ( '/v1/databases/:databaseId/collections/:collectionId/attributes/integer' )
2022-06-23 08:50:11 +00:00
-> alias ( '/v1/database/collections/:collectionId/attributes/integer' , [ 'databaseId' => 'default' ])
2021-07-21 13:23:12 +00:00
-> desc ( 'Create Integer Attribute' )
-> groups ([ 'api' , 'database' ])
2022-06-22 10:51:49 +00:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create' )
2021-08-14 10:16:00 +00:00
-> label ( 'scope' , 'collections.write' )
2022-09-05 08:00:08 +00:00
-> label ( 'audits.event' , 'attribute.create' )
2022-08-08 12:19:41 +00:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
2022-08-21 02:10:21 +00:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.namespace' , 'databases' )
2021-08-02 20:11:24 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2021-07-21 13:23:12 +00:00
-> label ( 'sdk.method' , 'createIntegerAttribute' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/create-integer-attribute.md' )
2022-07-14 09:52:55 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_ACCEPTED )
2021-07-21 13:23:12 +00:00
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2021-09-30 19:37:21 +00:00
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_INTEGER )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 08:14:27 +00:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).' )
2021-12-16 15:04:30 +00:00
-> param ( 'key' , '' , new Key (), 'Attribute Key.' )
2021-07-21 13:23:12 +00:00
-> param ( 'required' , null , new Boolean (), 'Is attribute required?' )
2021-07-23 21:38:14 +00:00
-> param ( 'min' , null , new Integer (), 'Minimum value to enforce on new documents' , true )
-> param ( 'max' , null , new Integer (), 'Maximum value to enforce on new documents' , true )
2021-07-21 13:23:12 +00:00
-> param ( 'default' , null , new Integer (), 'Default value for attribute when not provided. Cannot be set when attribute is required.' , true )
-> param ( 'array' , false , new Boolean (), 'Is attribute an array?' , true )
-> inject ( 'response' )
2021-12-27 12:45:23 +00:00
-> inject ( 'dbForProject' )
2021-07-21 13:23:12 +00:00
-> inject ( 'database' )
2022-04-13 12:39:31 +00:00
-> inject ( 'events' )
2022-08-10 02:18:18 +00:00
-> action ( function ( string $databaseId , string $collectionId , string $key , ? bool $required , ? int $min , ? int $max , ? int $default , bool $array , Response $response , Database $dbForProject , EventDatabase $database , Event $events ) {
2021-06-18 16:13:37 +00:00
2021-08-16 23:21:00 +00:00
// Ensure attribute default is within range
2021-08-23 18:29:05 +00:00
$min = ( is_null ( $min )) ? PHP_INT_MIN : \intval ( $min );
$max = ( is_null ( $max )) ? PHP_INT_MAX : \intval ( $max );
2021-10-25 20:10:39 +00:00
if ( $min > $max ) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: ATTRIBUTE_VALUE_INVALID , 'Minimum value must be lesser than maximum value' );
2021-10-25 20:10:39 +00:00
}
2021-08-16 23:21:00 +00:00
$validator = new Range ( $min , $max , Database :: VAR_INTEGER );
if ( ! is_null ( $default ) && ! $validator -> isValid ( $default )) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: ATTRIBUTE_VALUE_INVALID , $validator -> getDescription ());
2021-08-16 23:21:00 +00:00
}
2021-12-29 14:50:21 +00:00
$size = $max > 2147483647 ? 8 : 4 ; // Automatically create BigInt depending on max value
2022-06-22 10:51:49 +00:00
$attribute = createAttribute ( $databaseId , $collectionId , new Document ([
2021-12-16 15:04:30 +00:00
'key' => $key ,
2021-07-27 01:00:36 +00:00
'type' => Database :: VAR_INTEGER ,
2021-12-29 14:50:21 +00:00
'size' => $size ,
2021-07-21 13:23:12 +00:00
'required' => $required ,
'default' => $default ,
'array' => $array ,
2021-08-23 18:29:05 +00:00
'format' => APP_DATABASE_ATTRIBUTE_INT_RANGE ,
2021-08-21 21:48:07 +00:00
'formatOptions' => [
2021-07-27 18:19:37 +00:00
'min' => $min ,
'max' => $max ,
2021-08-21 21:48:07 +00:00
],
2022-08-10 02:18:18 +00:00
]), $response , $dbForProject , $database , $events );
2021-08-16 23:21:00 +00:00
2021-08-24 18:57:34 +00:00
$formatOptions = $attribute -> getAttribute ( 'formatOptions' , []);
if ( ! empty ( $formatOptions )) {
$attribute -> setAttribute ( 'min' , \intval ( $formatOptions [ 'min' ]));
$attribute -> setAttribute ( 'max' , \intval ( $formatOptions [ 'max' ]));
}
2022-09-07 11:02:36 +00:00
$response
-> setStatusCode ( Response :: STATUS_CODE_ACCEPTED )
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_INTEGER );
2021-07-21 13:23:12 +00:00
});
2021-03-24 15:40:33 +00:00
2022-06-22 10:51:49 +00:00
App :: post ( '/v1/databases/:databaseId/collections/:collectionId/attributes/float' )
2022-06-23 08:50:11 +00:00
-> alias ( '/v1/database/collections/:collectionId/attributes/float' , [ 'databaseId' => 'default' ])
2021-07-21 13:23:12 +00:00
-> desc ( 'Create Float Attribute' )
-> groups ([ 'api' , 'database' ])
2022-06-22 10:51:49 +00:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create' )
2021-08-14 10:16:00 +00:00
-> label ( 'scope' , 'collections.write' )
2022-09-05 08:00:08 +00:00
-> label ( 'audits.event' , 'attribute.create' )
2022-08-08 12:19:41 +00:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
2022-08-21 02:10:21 +00:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.namespace' , 'databases' )
2021-08-02 20:11:24 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2021-07-21 13:23:12 +00:00
-> label ( 'sdk.method' , 'createFloatAttribute' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/create-float-attribute.md' )
2022-07-14 09:52:55 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_ACCEPTED )
2021-07-21 13:23:12 +00:00
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2021-09-30 19:37:21 +00:00
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_FLOAT )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 08:14:27 +00:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).' )
2021-12-16 15:04:30 +00:00
-> param ( 'key' , '' , new Key (), 'Attribute Key.' )
2021-07-21 13:23:12 +00:00
-> param ( 'required' , null , new Boolean (), 'Is attribute required?' )
2021-07-23 21:38:14 +00:00
-> param ( 'min' , null , new FloatValidator (), 'Minimum value to enforce on new documents' , true )
-> param ( 'max' , null , new FloatValidator (), 'Maximum value to enforce on new documents' , true )
2021-07-21 14:26:08 +00:00
-> param ( 'default' , null , new FloatValidator (), 'Default value for attribute when not provided. Cannot be set when attribute is required.' , true )
2021-07-21 13:23:12 +00:00
-> param ( 'array' , false , new Boolean (), 'Is attribute an array?' , true )
-> inject ( 'response' )
2021-12-27 12:45:23 +00:00
-> inject ( 'dbForProject' )
2021-07-21 13:23:12 +00:00
-> inject ( 'database' )
2022-04-13 12:39:31 +00:00
-> inject ( 'events' )
2022-08-10 02:18:18 +00:00
-> action ( function ( string $databaseId , string $collectionId , string $key , ? bool $required , ? float $min , ? float $max , ? float $default , bool $array , Response $response , Database $dbForProject , EventDatabase $database , Event $events ) {
2021-07-21 13:23:12 +00:00
2021-08-16 23:21:00 +00:00
// Ensure attribute default is within range
2021-11-02 00:48:14 +00:00
$min = ( is_null ( $min )) ? - PHP_FLOAT_MAX : \floatval ( $min );
2021-08-23 18:29:05 +00:00
$max = ( is_null ( $max )) ? PHP_FLOAT_MAX : \floatval ( $max );
2021-10-25 20:10:39 +00:00
if ( $min > $max ) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: ATTRIBUTE_VALUE_INVALID , 'Minimum value must be lesser than maximum value' );
2021-10-25 20:10:39 +00:00
}
2021-12-14 21:01:58 +00:00
// Ensure default value is a float
if ( ! is_null ( $default )) {
$default = \floatval ( $default );
}
2021-10-25 20:10:39 +00:00
2021-08-16 23:21:00 +00:00
$validator = new Range ( $min , $max , Database :: VAR_FLOAT );
if ( ! is_null ( $default ) && ! $validator -> isValid ( $default )) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: ATTRIBUTE_VALUE_INVALID , $validator -> getDescription ());
2021-08-16 23:21:00 +00:00
}
2022-06-22 10:51:49 +00:00
$attribute = createAttribute ( $databaseId , $collectionId , new Document ([
2021-12-16 15:04:30 +00:00
'key' => $key ,
2021-07-27 01:00:36 +00:00
'type' => Database :: VAR_FLOAT ,
2021-07-21 13:23:12 +00:00
'required' => $required ,
2021-07-27 01:00:36 +00:00
'size' => 0 ,
2021-07-21 13:23:12 +00:00
'default' => $default ,
2021-07-27 01:00:36 +00:00
'array' => $array ,
2021-08-23 18:29:05 +00:00
'format' => APP_DATABASE_ATTRIBUTE_FLOAT_RANGE ,
2021-08-21 21:48:07 +00:00
'formatOptions' => [
2021-07-27 18:19:37 +00:00
'min' => $min ,
'max' => $max ,
2021-08-21 21:48:07 +00:00
],
2022-08-10 02:18:18 +00:00
]), $response , $dbForProject , $database , $events );
2021-08-16 23:21:00 +00:00
2021-08-24 18:57:34 +00:00
$formatOptions = $attribute -> getAttribute ( 'formatOptions' , []);
if ( ! empty ( $formatOptions )) {
$attribute -> setAttribute ( 'min' , \floatval ( $formatOptions [ 'min' ]));
$attribute -> setAttribute ( 'max' , \floatval ( $formatOptions [ 'max' ]));
}
2022-09-07 11:02:36 +00:00
$response
-> setStatusCode ( Response :: STATUS_CODE_ACCEPTED )
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_FLOAT );
2021-07-21 13:23:12 +00:00
});
2022-06-22 10:51:49 +00:00
App :: post ( '/v1/databases/:databaseId/collections/:collectionId/attributes/boolean' )
2022-06-23 08:50:11 +00:00
-> alias ( '/v1/database/collections/:collectionId/attributes/boolean' , [ 'databaseId' => 'default' ])
2021-07-21 13:23:12 +00:00
-> desc ( 'Create Boolean Attribute' )
-> groups ([ 'api' , 'database' ])
2022-06-22 10:51:49 +00:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create' )
2021-08-14 10:16:00 +00:00
-> label ( 'scope' , 'collections.write' )
2022-09-05 08:00:08 +00:00
-> label ( 'audits.event' , 'attribute.create' )
2022-08-08 12:19:41 +00:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
2022-08-21 02:10:21 +00:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.namespace' , 'databases' )
2021-08-02 20:11:24 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2021-07-21 13:23:12 +00:00
-> label ( 'sdk.method' , 'createBooleanAttribute' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/create-boolean-attribute.md' )
2022-07-14 09:52:55 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_ACCEPTED )
2021-07-21 13:23:12 +00:00
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2021-09-30 19:37:21 +00:00
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_BOOLEAN )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 08:14:27 +00:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).' )
2021-12-16 15:04:30 +00:00
-> param ( 'key' , '' , new Key (), 'Attribute Key.' )
2021-07-21 13:23:12 +00:00
-> param ( 'required' , null , new Boolean (), 'Is attribute required?' )
-> param ( 'default' , null , new Boolean (), 'Default value for attribute when not provided. Cannot be set when attribute is required.' , true )
-> param ( 'array' , false , new Boolean (), 'Is attribute an array?' , true )
-> inject ( 'response' )
2021-12-27 12:45:23 +00:00
-> inject ( 'dbForProject' )
2021-07-21 13:23:12 +00:00
-> inject ( 'database' )
2022-04-13 12:39:31 +00:00
-> inject ( 'events' )
2022-08-10 02:18:18 +00:00
-> action ( function ( string $databaseId , string $collectionId , string $key , ? bool $required , ? bool $default , bool $array , Response $response , Database $dbForProject , EventDatabase $database , Event $events ) {
2021-07-21 13:23:12 +00:00
2022-06-22 10:51:49 +00:00
$attribute = createAttribute ( $databaseId , $collectionId , new Document ([
2021-12-16 15:04:30 +00:00
'key' => $key ,
2021-07-27 01:00:36 +00:00
'type' => Database :: VAR_BOOLEAN ,
'size' => 0 ,
2021-06-09 21:11:51 +00:00
'required' => $required ,
2021-07-02 17:29:03 +00:00
'default' => $default ,
2021-06-09 21:11:51 +00:00
'array' => $array ,
2022-08-10 02:18:18 +00:00
]), $response , $dbForProject , $database , $events );
2021-08-16 23:21:00 +00:00
2022-09-07 11:11:10 +00:00
$response
-> setStatusCode ( Response :: STATUS_CODE_ACCEPTED )
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_BOOLEAN );
2021-03-24 15:40:33 +00:00
});
2022-07-25 08:53:41 +00:00
App :: post ( '/v1/databases/:databaseId/collections/:collectionId/attributes/datetime' )
-> alias ( '/v1/database/collections/:collectionId/attributes/datetime' , [ 'databaseId' => 'default' ])
2022-07-28 12:38:54 +00:00
-> desc ( 'Create DateTime Attribute' )
2022-07-25 08:53:41 +00:00
-> groups ([ 'api' , 'database' ])
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create' )
-> label ( 'scope' , 'collections.write' )
2022-09-05 08:00:08 +00:00
-> label ( 'audits.event' , 'attribute.create' )
2022-08-19 05:05:39 +00:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-25 11:49:45 +00:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2022-07-25 08:53:41 +00:00
-> label ( 'sdk.namespace' , 'databases' )
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.method' , 'createDatetimeAttribute' )
-> label ( 'sdk.description' , '/docs/references/databases/create-datetime-attribute.md' )
2022-08-11 23:53:52 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_ACCEPTED )
2022-07-25 08:53:41 +00:00
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_DATETIME )
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 08:14:27 +00:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).' )
2022-07-25 08:53:41 +00:00
-> param ( 'key' , '' , new Key (), 'Attribute Key.' )
-> param ( 'required' , null , new Boolean (), 'Is attribute required?' )
2022-09-04 21:41:26 +00:00
-> param ( 'default' , null , new DatetimeValidator (), 'Default value for the attribute in ISO 8601 format. Cannot be set when attribute is required.' , true )
2022-07-25 08:53:41 +00:00
-> param ( 'array' , false , new Boolean (), 'Is attribute an array?' , true )
-> inject ( 'response' )
-> inject ( 'dbForProject' )
-> inject ( 'database' )
-> inject ( 'events' )
2022-09-06 09:07:39 +00:00
-> action ( function ( string $databaseId , string $collectionId , string $key , ? bool $required , ? string $default , bool $array , Response $response , Database $dbForProject , EventDatabase $database , Event $events ) {
2022-07-25 08:53:41 +00:00
$attribute = createAttribute ( $databaseId , $collectionId , new Document ([
'key' => $key ,
'type' => Database :: VAR_DATETIME ,
'size' => 0 ,
'required' => $required ,
'default' => $default ,
'array' => $array ,
2022-07-28 10:26:22 +00:00
'filters' => [ 'datetime' ]
2022-08-25 10:28:13 +00:00
]), $response , $dbForProject , $database , $events );
2022-07-25 08:53:41 +00:00
2022-09-07 11:11:10 +00:00
$response
-> setStatusCode ( Response :: STATUS_CODE_ACCEPTED )
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_DATETIME );
2022-07-25 08:53:41 +00:00
});
2022-06-22 10:51:49 +00:00
App :: get ( '/v1/databases/:databaseId/collections/:collectionId/attributes' )
2022-06-23 08:50:11 +00:00
-> alias ( '/v1/database/collections/:collectionId/attributes' , [ 'databaseId' => 'default' ])
2021-03-25 19:52:57 +00:00
-> desc ( 'List Attributes' )
-> groups ([ 'api' , 'database' ])
2021-08-14 10:16:00 +00:00
-> label ( 'scope' , 'collections.read' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.read' )
2022-08-21 02:10:21 +00:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-07-31 20:40:34 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.namespace' , 'databases' )
2021-03-25 19:52:57 +00:00
-> label ( 'sdk.method' , 'listAttributes' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/list-attributes.md' )
2021-03-25 19:52:57 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_LIST )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 08:14:27 +00:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).' )
2021-03-25 19:52:57 +00:00
-> inject ( 'response' )
2021-12-27 12:45:23 +00:00
-> inject ( 'dbForProject' )
2022-08-10 02:18:18 +00:00
-> action ( function ( string $databaseId , string $collectionId , Response $response , Database $dbForProject ) {
2022-06-22 10:51:49 +00:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2021-06-08 20:12:14 +00:00
2022-06-22 10:51:49 +00:00
if ( $database -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 10:51:49 +00:00
}
$collection = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId );
2021-03-25 19:52:57 +00:00
2021-06-11 14:25:52 +00:00
if ( $collection -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-06-10 13:15:00 +00:00
}
2021-08-28 00:32:44 +00:00
$attributes = $collection -> getAttribute ( 'attributes' );
2021-06-17 15:53:06 +00:00
2021-07-25 14:47:18 +00:00
$response -> dynamic ( new Document ([
2022-02-27 09:57:09 +00:00
'total' => \count ( $attributes ),
2021-06-08 20:12:14 +00:00
'attributes' => $attributes
]), Response :: MODEL_ATTRIBUTE_LIST );
2021-03-25 19:52:57 +00:00
});
2022-06-22 10:51:49 +00:00
App :: get ( '/v1/databases/:databaseId/collections/:collectionId/attributes/:key' )
2022-06-23 08:50:11 +00:00
-> alias ( '/v1/database/collections/:collectionId/attributes/:key' , [ 'databaseId' => 'default' ])
2021-03-25 19:52:57 +00:00
-> desc ( 'Get Attribute' )
-> groups ([ 'api' , 'database' ])
2021-08-14 10:16:00 +00:00
-> label ( 'scope' , 'collections.read' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.read' )
2022-08-21 02:10:21 +00:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-07-31 20:40:34 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.namespace' , 'databases' )
2021-07-18 08:19:23 +00:00
-> label ( 'sdk.method' , 'getAttribute' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/get-attribute.md' )
2021-03-25 19:52:57 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2021-09-30 19:03:18 +00:00
-> label ( 'sdk.response.model' , [
2022-07-28 10:26:22 +00:00
Response :: MODEL_ATTRIBUTE_DATETIME ,
2021-09-30 19:03:18 +00:00
Response :: MODEL_ATTRIBUTE_BOOLEAN ,
Response :: MODEL_ATTRIBUTE_INTEGER ,
Response :: MODEL_ATTRIBUTE_FLOAT ,
Response :: MODEL_ATTRIBUTE_EMAIL ,
2021-10-07 02:25:03 +00:00
Response :: MODEL_ATTRIBUTE_ENUM ,
2021-09-30 19:03:18 +00:00
Response :: MODEL_ATTRIBUTE_URL ,
Response :: MODEL_ATTRIBUTE_IP ,
2022-07-28 12:38:54 +00:00
Response :: MODEL_ATTRIBUTE_DATETIME ,
Response :: MODEL_ATTRIBUTE_STRING ]) // needs to be last, since its condition would dominate any other string attribute
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 08:14:27 +00:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).' )
2021-12-16 15:04:30 +00:00
-> param ( 'key' , '' , new Key (), 'Attribute Key.' )
2021-03-25 19:52:57 +00:00
-> inject ( 'response' )
2021-12-27 12:45:23 +00:00
-> inject ( 'dbForProject' )
2022-08-10 02:18:18 +00:00
-> action ( function ( string $databaseId , string $collectionId , string $key , Response $response , Database $dbForProject ) {
2022-06-22 10:51:49 +00:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2021-06-08 20:12:14 +00:00
2022-06-22 10:51:49 +00:00
if ( $database -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 10:51:49 +00:00
}
$collection = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId );
2021-03-25 19:52:57 +00:00
2021-12-27 17:07:35 +00:00
if ( $collection -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-06-10 13:15:00 +00:00
}
2022-06-22 10:51:49 +00:00
$attribute = $dbForProject -> getDocument ( 'attributes' , $database -> getInternalId () . '_' . $collection -> getInternalId () . '_' . $key );
2021-08-25 19:37:07 +00:00
2021-12-27 17:07:35 +00:00
if ( $attribute -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: ATTRIBUTE_NOT_FOUND );
2021-06-09 21:11:51 +00:00
}
2021-08-25 19:37:07 +00:00
// Select response model based on type and format
2021-08-16 23:21:00 +00:00
$type = $attribute -> getAttribute ( 'type' );
2021-08-24 18:01:53 +00:00
$format = $attribute -> getAttribute ( 'format' );
2021-08-16 23:21:00 +00:00
2022-05-23 14:54:50 +00:00
$model = match ( $type ) {
2022-07-28 10:26:22 +00:00
Database :: VAR_DATETIME => Response :: MODEL_ATTRIBUTE_DATETIME ,
2021-08-16 23:21:00 +00:00
Database :: VAR_BOOLEAN => Response :: MODEL_ATTRIBUTE_BOOLEAN ,
Database :: VAR_INTEGER => Response :: MODEL_ATTRIBUTE_INTEGER ,
Database :: VAR_FLOAT => Response :: MODEL_ATTRIBUTE_FLOAT ,
2022-05-23 14:54:50 +00:00
Database :: VAR_STRING => match ( $format ) {
2021-08-25 19:37:07 +00:00
APP_DATABASE_ATTRIBUTE_EMAIL => Response :: MODEL_ATTRIBUTE_EMAIL ,
2021-09-10 20:14:12 +00:00
APP_DATABASE_ATTRIBUTE_ENUM => Response :: MODEL_ATTRIBUTE_ENUM ,
2021-08-16 23:21:00 +00:00
APP_DATABASE_ATTRIBUTE_IP => Response :: MODEL_ATTRIBUTE_IP ,
APP_DATABASE_ATTRIBUTE_URL => Response :: MODEL_ATTRIBUTE_URL ,
default => Response :: MODEL_ATTRIBUTE_STRING ,
},
default => Response :: MODEL_ATTRIBUTE ,
};
2021-08-24 18:01:53 +00:00
2021-08-16 23:21:00 +00:00
$response -> dynamic ( $attribute , $model );
2021-03-25 19:52:57 +00:00
});
2022-06-22 10:51:49 +00:00
App :: delete ( '/v1/databases/:databaseId/collections/:collectionId/attributes/:key' )
2022-06-23 08:50:11 +00:00
-> alias ( '/v1/database/collections/:collectionId/attributes/:key' , [ 'databaseId' => 'default' ])
2021-03-24 15:40:33 +00:00
-> desc ( 'Delete Attribute' )
-> groups ([ 'api' , 'database' ])
2021-08-14 10:16:00 +00:00
-> label ( 'scope' , 'collections.write' )
2022-06-22 10:51:49 +00:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].delete' )
2022-09-05 08:00:08 +00:00
-> label ( 'audits.event' , 'attribute.delete' )
2022-08-08 14:32:54 +00:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
2022-08-21 02:10:21 +00:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-07-31 20:40:34 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.namespace' , 'databases' )
2021-03-24 15:40:33 +00:00
-> label ( 'sdk.method' , 'deleteAttribute' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/delete-attribute.md' )
2021-03-24 15:40:33 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_NOCONTENT )
-> label ( 'sdk.response.model' , Response :: MODEL_NONE )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 08:14:27 +00:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).' )
2021-12-16 15:04:30 +00:00
-> param ( 'key' , '' , new Key (), 'Attribute Key.' )
2021-03-24 15:40:33 +00:00
-> inject ( 'response' )
2021-12-27 12:45:23 +00:00
-> inject ( 'dbForProject' )
2021-06-18 18:27:14 +00:00
-> inject ( 'database' )
2021-03-24 15:40:33 +00:00
-> inject ( 'events' )
2022-08-13 03:14:28 +00:00
-> action ( function ( string $databaseId , string $collectionId , string $key , Response $response , Database $dbForProject , EventDatabase $database , Event $events ) {
2021-03-24 15:40:33 +00:00
2022-06-22 10:51:49 +00:00
$db = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
if ( $db -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 10:51:49 +00:00
}
$collection = $dbForProject -> getDocument ( 'database_' . $db -> getInternalId (), $collectionId );
2021-03-24 15:40:33 +00:00
2021-06-11 14:25:52 +00:00
if ( $collection -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-06-10 13:15:00 +00:00
}
2022-06-22 10:51:49 +00:00
$attribute = $dbForProject -> getDocument ( 'attributes' , $db -> getInternalId () . '_' . $collection -> getInternalId () . '_' . $key );
2021-08-08 22:07:59 +00:00
2021-12-27 17:07:35 +00:00
if ( $attribute -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: ATTRIBUTE_NOT_FOUND );
2021-06-09 21:11:51 +00:00
}
2021-10-05 00:23:15 +00:00
// Only update status if removing available attribute
if ( $attribute -> getAttribute ( 'status' === 'available' )) {
2021-12-27 12:45:23 +00:00
$attribute = $dbForProject -> updateDocument ( 'attributes' , $attribute -> getId (), $attribute -> setAttribute ( 'status' , 'deleting' ));
2021-10-05 00:23:15 +00:00
}
2022-06-22 10:51:49 +00:00
$dbForProject -> deleteCachedDocument ( 'database_' . $db -> getInternalId (), $collectionId );
$dbForProject -> deleteCachedCollection ( 'database_' . $db -> getInternalId () . '_collection_' . $collection -> getInternalId ());
2021-08-20 17:02:44 +00:00
2021-06-18 18:27:14 +00:00
$database
2022-04-13 12:39:31 +00:00
-> setType ( DATABASE_TYPE_DELETE_ATTRIBUTE )
-> setCollection ( $collection )
2022-06-22 10:51:49 +00:00
-> setDatabase ( $db )
2022-04-13 12:39:31 +00:00
-> setDocument ( $attribute )
2021-06-18 18:27:14 +00:00
;
2021-06-08 20:12:14 +00:00
2021-10-26 01:12:27 +00:00
// Select response model based on type and format
$type = $attribute -> getAttribute ( 'type' );
$format = $attribute -> getAttribute ( 'format' );
2022-05-23 14:54:50 +00:00
$model = match ( $type ) {
2022-07-28 10:26:22 +00:00
Database :: VAR_DATETIME => Response :: MODEL_ATTRIBUTE_DATETIME ,
2021-10-26 01:12:27 +00:00
Database :: VAR_BOOLEAN => Response :: MODEL_ATTRIBUTE_BOOLEAN ,
Database :: VAR_INTEGER => Response :: MODEL_ATTRIBUTE_INTEGER ,
Database :: VAR_FLOAT => Response :: MODEL_ATTRIBUTE_FLOAT ,
2022-05-23 14:54:50 +00:00
Database :: VAR_STRING => match ( $format ) {
2021-10-26 01:12:27 +00:00
APP_DATABASE_ATTRIBUTE_EMAIL => Response :: MODEL_ATTRIBUTE_EMAIL ,
APP_DATABASE_ATTRIBUTE_ENUM => Response :: MODEL_ATTRIBUTE_ENUM ,
APP_DATABASE_ATTRIBUTE_IP => Response :: MODEL_ATTRIBUTE_IP ,
APP_DATABASE_ATTRIBUTE_URL => Response :: MODEL_ATTRIBUTE_URL ,
default => Response :: MODEL_ATTRIBUTE_STRING ,
},
default => Response :: MODEL_ATTRIBUTE ,
};
2021-06-09 21:11:51 +00:00
$events
2022-06-22 10:51:49 +00:00
-> setParam ( 'databaseId' , $databaseId )
2022-04-13 12:39:31 +00:00
-> setParam ( 'collectionId' , $collection -> getId ())
-> setParam ( 'attributeId' , $attribute -> getId ())
2022-06-22 10:51:49 +00:00
-> setContext ( 'collection' , $collection )
-> setContext ( 'database' , $db )
2022-04-13 12:39:31 +00:00
-> setPayload ( $response -> output ( $attribute , $model ))
2021-06-09 21:11:51 +00:00
;
2021-03-24 15:40:33 +00:00
$response -> noContent ();
});
2022-06-22 10:51:49 +00:00
App :: post ( '/v1/databases/:databaseId/collections/:collectionId/indexes' )
2022-06-23 08:50:11 +00:00
-> alias ( '/v1/database/collections/:collectionId/indexes' , [ 'databaseId' => 'default' ])
2021-03-23 21:19:19 +00:00
-> desc ( 'Create Index' )
-> groups ([ 'api' , 'database' ])
2022-06-22 10:51:49 +00:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].indexes.[indexId].create' )
2021-08-14 10:16:00 +00:00
-> label ( 'scope' , 'collections.write' )
2022-09-05 08:00:08 +00:00
-> label ( 'audits.event' , 'index.create' )
2022-08-08 12:19:41 +00:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
2022-08-21 02:10:21 +00:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-07-31 20:40:34 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.namespace' , 'databases' )
2021-03-23 21:19:19 +00:00
-> label ( 'sdk.method' , 'createIndex' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/create-index.md' )
2022-07-14 09:52:55 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_ACCEPTED )
2021-03-23 21:19:19 +00:00
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_INDEX )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 08:14:27 +00:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).' )
2021-12-16 15:04:30 +00:00
-> param ( 'key' , null , new Key (), 'Index Key.' )
2021-06-17 17:03:24 +00:00
-> param ( 'type' , null , new WhiteList ([ Database :: INDEX_KEY , Database :: INDEX_FULLTEXT , Database :: INDEX_UNIQUE , Database :: INDEX_SPATIAL , Database :: INDEX_ARRAY ]), 'Index type.' )
2022-06-20 14:22:27 +00:00
-> param ( 'attributes' , null , new ArrayList ( new Key ( true ), APP_LIMIT_ARRAY_PARAMS_SIZE ), 'Array of attributes to index. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' attributes are allowed, each 32 characters long.' )
2022-05-01 07:54:58 +00:00
-> param ( 'orders' , [], new ArrayList ( new WhiteList ([ 'ASC' , 'DESC' ], false , Database :: VAR_STRING ), APP_LIMIT_ARRAY_PARAMS_SIZE ), 'Array of index orders. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' orders are allowed.' , true )
2021-03-23 21:19:19 +00:00
-> inject ( 'response' )
2021-12-27 12:45:23 +00:00
-> inject ( 'dbForProject' )
2021-06-18 16:13:37 +00:00
-> inject ( 'database' )
2022-04-13 12:39:31 +00:00
-> inject ( 'events' )
2022-08-10 02:18:18 +00:00
-> action ( function ( string $databaseId , string $collectionId , string $key , string $type , array $attributes , array $orders , Response $response , Database $dbForProject , EventDatabase $database , Event $events ) {
2021-03-23 21:19:19 +00:00
2022-06-22 10:51:49 +00:00
$db = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
if ( $db -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 10:51:49 +00:00
}
$collection = $dbForProject -> getDocument ( 'database_' . $db -> getInternalId (), $collectionId );
2021-06-10 13:15:00 +00:00
2021-06-11 14:25:52 +00:00
if ( $collection -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-06-10 13:15:00 +00:00
}
2021-12-27 12:45:23 +00:00
$count = $dbForProject -> count ( 'indexes' , [
2022-08-11 23:53:52 +00:00
Query :: equal ( 'collectionInternalId' , [ $collection -> getInternalId ()]),
Query :: equal ( 'databaseInternalId' , [ $db -> getInternalId ()])
2022-06-22 10:51:49 +00:00
], 61 );
2021-08-24 23:35:32 +00:00
2022-10-14 11:12:59 +00:00
$limit = 64 - MariaDB :: getCountOfDefaultIndexes ();
2021-08-24 23:35:32 +00:00
if ( $count >= $limit ) {
2022-08-14 08:05:11 +00:00
throw new Exception ( Exception :: INDEX_LIMIT_EXCEEDED , 'Index limit exceeded' );
2021-08-24 23:35:32 +00:00
}
2021-07-03 00:20:09 +00:00
// Convert Document[] to array of attribute metadata
2021-12-27 12:45:23 +00:00
$oldAttributes = \array_map ( fn ( $a ) => $a -> getArrayCopy (), $collection -> getAttribute ( 'attributes' ));
2021-07-02 22:23:58 +00:00
2022-06-20 14:22:27 +00:00
$oldAttributes [] = [
'key' => '$id' ,
2022-09-08 22:18:36 +00:00
'type' => Database :: VAR_STRING ,
2022-06-20 14:22:27 +00:00
'status' => 'available' ,
'required' => true ,
'array' => false ,
'default' => null ,
'size' => 36
];
2022-06-22 09:46:37 +00:00
$oldAttributes [] = [
'key' => '$createdAt' ,
2022-09-08 22:18:36 +00:00
'type' => Database :: VAR_DATETIME ,
2022-06-22 09:46:37 +00:00
'status' => 'available' ,
'signed' => false ,
'required' => false ,
'array' => false ,
'default' => null ,
'size' => 0
];
$oldAttributes [] = [
'key' => '$updatedAt' ,
2022-09-08 22:18:36 +00:00
'type' => Database :: VAR_DATETIME ,
2022-06-22 09:46:37 +00:00
'status' => 'available' ,
'signed' => false ,
'required' => false ,
'array' => false ,
'default' => null ,
'size' => 0
];
2021-07-02 22:23:58 +00:00
2021-06-23 14:21:32 +00:00
// lengths hidden by default
$lengths = [];
2021-12-16 15:04:30 +00:00
foreach ( $attributes as $i => $attribute ) {
2021-07-02 22:23:58 +00:00
// find attribute metadata in collection document
2021-08-22 14:06:59 +00:00
$attributeIndex = \array_search ( $attribute , array_column ( $oldAttributes , 'key' ));
2021-07-02 22:23:58 +00:00
if ( $attributeIndex === false ) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: ATTRIBUTE_UNKNOWN , 'Unknown attribute: ' . $attribute );
2021-07-02 22:23:58 +00:00
}
2021-10-05 00:43:27 +00:00
$attributeStatus = $oldAttributes [ $attributeIndex ][ 'status' ];
2021-07-03 00:20:09 +00:00
$attributeType = $oldAttributes [ $attributeIndex ][ 'type' ];
$attributeSize = $oldAttributes [ $attributeIndex ][ 'size' ];
2021-07-02 22:23:58 +00:00
2021-10-05 00:43:27 +00:00
// ensure attribute is available
if ( $attributeStatus !== 'available' ) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: ATTRIBUTE_NOT_AVAILABLE , 'Attribute not available: ' . $oldAttributes [ $attributeIndex ][ 'key' ]);
2021-10-05 00:43:27 +00:00
}
// set attribute size as index length only for strings
2021-12-16 15:04:30 +00:00
$lengths [ $i ] = ( $attributeType === Database :: VAR_STRING ) ? $attributeSize : null ;
2021-07-02 22:23:58 +00:00
}
2021-08-22 15:00:00 +00:00
try {
2021-12-27 12:45:23 +00:00
$index = $dbForProject -> createDocument ( 'indexes' , new Document ([
2022-08-14 10:33:36 +00:00
'$id' => ID :: custom ( $db -> getInternalId () . '_' . $collection -> getInternalId () . '_' . $key ),
2021-12-16 15:04:30 +00:00
'key' => $key ,
2021-10-05 00:23:15 +00:00
'status' => 'processing' , // processing, available, failed, deleting, stuck
2022-06-22 10:51:49 +00:00
'databaseInternalId' => $db -> getInternalId (),
'databaseId' => $databaseId ,
2022-06-15 12:57:06 +00:00
'collectionInternalId' => $collection -> getInternalId (),
2021-08-22 15:00:00 +00:00
'collectionId' => $collectionId ,
'type' => $type ,
'attributes' => $attributes ,
'lengths' => $lengths ,
'orders' => $orders ,
]));
} catch ( DuplicateException $th ) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: INDEX_ALREADY_EXISTS );
2021-08-22 15:00:00 +00:00
}
2022-06-22 10:51:49 +00:00
$dbForProject -> deleteCachedDocument ( 'database_' . $db -> getInternalId (), $collectionId );
2021-03-23 21:19:19 +00:00
2021-06-18 16:13:37 +00:00
$database
2022-04-13 12:39:31 +00:00
-> setType ( DATABASE_TYPE_CREATE_INDEX )
2022-06-22 10:51:49 +00:00
-> setDatabase ( $db )
2022-04-13 12:39:31 +00:00
-> setCollection ( $collection )
-> setDocument ( $index )
2021-06-18 16:13:37 +00:00
;
2022-04-13 12:39:31 +00:00
$events
2022-06-22 10:51:49 +00:00
-> setParam ( 'databaseId' , $databaseId )
2022-04-13 12:39:31 +00:00
-> setParam ( 'collectionId' , $collection -> getId ())
-> setParam ( 'indexId' , $index -> getId ())
2022-09-07 11:02:36 +00:00
-> setContext ( 'collection' , $collection )
-> setContext ( 'database' , $db )
2022-04-13 12:39:31 +00:00
;
2022-09-07 11:11:10 +00:00
$response
-> setStatusCode ( Response :: STATUS_CODE_ACCEPTED )
-> dynamic ( $index , Response :: MODEL_INDEX );
2021-03-23 21:19:19 +00:00
});
2022-06-22 10:51:49 +00:00
App :: get ( '/v1/databases/:databaseId/collections/:collectionId/indexes' )
2022-06-23 08:50:11 +00:00
-> alias ( '/v1/database/collections/:collectionId/indexes' , [ 'databaseId' => 'default' ])
2021-03-24 15:40:33 +00:00
-> desc ( 'List Indexes' )
-> groups ([ 'api' , 'database' ])
2021-08-14 10:16:00 +00:00
-> label ( 'scope' , 'collections.read' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.read' )
2022-08-21 02:10:21 +00:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-07-31 20:40:34 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.namespace' , 'databases' )
2021-03-24 15:40:33 +00:00
-> label ( 'sdk.method' , 'listIndexes' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/list-indexes.md' )
2021-03-24 15:40:33 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_INDEX_LIST )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 08:14:27 +00:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).' )
2021-03-24 15:40:33 +00:00
-> inject ( 'response' )
2021-12-27 12:45:23 +00:00
-> inject ( 'dbForProject' )
2022-08-10 02:18:18 +00:00
-> action ( function ( string $databaseId , string $collectionId , Response $response , Database $dbForProject ) {
2022-06-22 10:51:49 +00:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2021-06-09 21:11:51 +00:00
2022-06-22 10:51:49 +00:00
if ( $database -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 10:51:49 +00:00
}
$collection = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId );
2021-03-24 15:40:33 +00:00
2021-06-11 14:25:52 +00:00
if ( $collection -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-06-10 13:15:00 +00:00
}
2021-06-09 21:11:51 +00:00
$indexes = $collection -> getAttribute ( 'indexes' );
2021-03-24 15:40:33 +00:00
2021-07-25 14:47:18 +00:00
$response -> dynamic ( new Document ([
2022-02-27 09:57:09 +00:00
'total' => \count ( $indexes ),
2021-12-14 00:42:54 +00:00
'indexes' => $indexes ,
2021-06-09 21:11:51 +00:00
]), Response :: MODEL_INDEX_LIST );
2021-03-24 15:40:33 +00:00
});
2022-06-22 10:51:49 +00:00
App :: get ( '/v1/databases/:databaseId/collections/:collectionId/indexes/:key' )
2022-06-23 08:50:11 +00:00
-> alias ( '/v1/database/collections/:collectionId/indexes/:key' , [ 'databaseId' => 'default' ])
2021-03-25 19:52:57 +00:00
-> desc ( 'Get Index' )
-> groups ([ 'api' , 'database' ])
2021-08-14 10:16:00 +00:00
-> label ( 'scope' , 'collections.read' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.read' )
2022-08-21 02:10:21 +00:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-07-31 20:40:34 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.namespace' , 'databases' )
2021-07-18 08:19:23 +00:00
-> label ( 'sdk.method' , 'getIndex' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/get-index.md' )
2021-03-25 19:52:57 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_INDEX )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 08:14:27 +00:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).' )
2021-12-16 15:04:30 +00:00
-> param ( 'key' , null , new Key (), 'Index Key.' )
2021-03-25 19:52:57 +00:00
-> inject ( 'response' )
2021-12-27 12:45:23 +00:00
-> inject ( 'dbForProject' )
2022-08-10 02:18:18 +00:00
-> action ( function ( string $databaseId , string $collectionId , string $key , Response $response , Database $dbForProject ) {
2022-06-22 10:51:49 +00:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2021-03-25 19:52:57 +00:00
2022-06-22 10:51:49 +00:00
if ( $database -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 10:51:49 +00:00
}
$collection = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId );
2021-06-09 21:11:51 +00:00
2021-06-11 14:25:52 +00:00
if ( $collection -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-06-10 13:15:00 +00:00
}
2021-06-09 21:11:51 +00:00
$indexes = $collection -> getAttribute ( 'indexes' );
2021-03-25 19:52:57 +00:00
2021-08-16 19:24:15 +00:00
// Search for index
2021-12-16 15:04:30 +00:00
$indexIndex = array_search ( $key , array_column ( $indexes , 'key' ));
2021-06-09 21:11:51 +00:00
if ( $indexIndex === false ) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: INDEX_NOT_FOUND );
2021-06-09 21:11:51 +00:00
}
2021-06-17 17:03:24 +00:00
$index = new Document ([ \array_merge ( $indexes [ $indexIndex ], [
2022-06-22 10:51:49 +00:00
'collectionId' => $database -> getInternalId () . '_' . $collectionId ,
2021-06-09 21:11:51 +00:00
])]);
2021-08-15 11:08:32 +00:00
2021-07-25 14:47:18 +00:00
$response -> dynamic ( $index , Response :: MODEL_INDEX );
2021-03-25 19:52:57 +00:00
});
2022-06-22 10:51:49 +00:00
App :: delete ( '/v1/databases/:databaseId/collections/:collectionId/indexes/:key' )
2022-06-23 08:50:11 +00:00
-> alias ( '/v1/database/collections/:collectionId/indexes/:key' , [ 'databaseId' => 'default' ])
2021-03-25 19:52:57 +00:00
-> desc ( 'Delete Index' )
-> groups ([ 'api' , 'database' ])
2021-08-14 10:16:00 +00:00
-> label ( 'scope' , 'collections.write' )
2022-06-22 10:51:49 +00:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].indexes.[indexId].delete' )
2022-09-05 08:00:08 +00:00
-> label ( 'audits.event' , 'index.delete' )
2022-08-08 14:32:54 +00:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
2022-08-21 02:10:21 +00:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-07-31 20:40:34 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.namespace' , 'databases' )
2021-03-25 19:52:57 +00:00
-> label ( 'sdk.method' , 'deleteIndex' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/delete-index.md' )
2021-03-25 19:52:57 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_NOCONTENT )
-> label ( 'sdk.response.model' , Response :: MODEL_NONE )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-09-19 10:05:42 +00:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).' )
2021-12-16 15:04:30 +00:00
-> param ( 'key' , '' , new Key (), 'Index Key.' )
2021-03-25 19:52:57 +00:00
-> inject ( 'response' )
2021-12-27 12:45:23 +00:00
-> inject ( 'dbForProject' )
2021-06-18 18:27:14 +00:00
-> inject ( 'database' )
2021-03-25 19:52:57 +00:00
-> inject ( 'events' )
2022-08-13 03:14:28 +00:00
-> action ( function ( string $databaseId , string $collectionId , string $key , Response $response , Database $dbForProject , EventDatabase $database , Event $events ) {
2021-03-25 19:52:57 +00:00
2022-06-22 10:51:49 +00:00
$db = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
if ( $db -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 10:51:49 +00:00
}
$collection = $dbForProject -> getDocument ( 'database_' . $db -> getInternalId (), $collectionId );
2021-06-09 21:11:51 +00:00
2021-06-11 18:07:05 +00:00
if ( $collection -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-06-10 13:15:00 +00:00
}
2022-06-22 10:51:49 +00:00
$index = $dbForProject -> getDocument ( 'indexes' , $db -> getInternalId () . '_' . $collection -> getInternalId () . '_' . $key );
2021-06-09 21:11:51 +00:00
2021-08-23 04:06:53 +00:00
if ( empty ( $index -> getId ())) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: INDEX_NOT_FOUND );
2021-03-25 19:52:57 +00:00
}
2021-10-05 00:23:15 +00:00
// Only update status if removing available index
if ( $index -> getAttribute ( 'status' ) === 'available' ) {
2021-12-27 12:45:23 +00:00
$index = $dbForProject -> updateDocument ( 'indexes' , $index -> getId (), $index -> setAttribute ( 'status' , 'deleting' ));
2021-10-05 00:23:15 +00:00
}
2022-06-22 10:51:49 +00:00
$dbForProject -> deleteCachedDocument ( 'database_' . $db -> getInternalId (), $collectionId );
2021-08-23 04:06:53 +00:00
2021-06-18 18:27:14 +00:00
$database
2022-04-13 12:39:31 +00:00
-> setType ( DATABASE_TYPE_DELETE_INDEX )
2022-06-22 10:51:49 +00:00
-> setDatabase ( $db )
2022-04-13 12:39:31 +00:00
-> setCollection ( $collection )
-> setDocument ( $index )
2021-06-18 18:27:14 +00:00
;
2021-03-25 19:52:57 +00:00
$events
2022-06-22 10:51:49 +00:00
-> setParam ( 'databaseId' , $databaseId )
2022-04-13 12:39:31 +00:00
-> setParam ( 'collectionId' , $collection -> getId ())
-> setParam ( 'indexId' , $index -> getId ())
2022-08-05 06:01:25 +00:00
-> setContext ( 'collection' , $collection )
-> setContext ( 'database' , $db )
2022-04-13 12:39:31 +00:00
-> setPayload ( $response -> output ( $index , Response :: MODEL_INDEX ))
2021-03-25 19:52:57 +00:00
;
$response -> noContent ();
});
2022-06-22 10:51:49 +00:00
App :: post ( '/v1/databases/:databaseId/collections/:collectionId/documents' )
2022-06-23 08:50:11 +00:00
-> alias ( '/v1/database/collections/:collectionId/documents' , [ 'databaseId' => 'default' ])
2020-01-31 22:34:07 +00:00
-> desc ( 'Create Document' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'database' ])
2022-06-22 10:51:49 +00:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].documents.[documentId].create' )
2020-01-31 22:34:07 +00:00
-> label ( 'scope' , 'documents.write' )
2022-09-05 08:00:08 +00:00
-> label ( 'audits.event' , 'document.create' )
2022-08-08 12:19:41 +00:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'documents.{scope}.requests.create' )
2022-08-21 02:10:21 +00:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' , 'collectionId:{request.collectionId}' ])
2022-08-31 03:58:32 +00:00
-> label ( 'abuse-key' , 'ip:{ip},method:{method},url:{url},userId:{userId}' )
2022-08-30 23:34:17 +00:00
-> label ( 'abuse-limit' , APP_LIMIT_WRITE_RATE_DEFAULT * 2 )
-> label ( 'abuse-time' , APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT )
2021-04-16 07:22:17 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_SESSION , APP_AUTH_TYPE_KEY , APP_AUTH_TYPE_JWT ])
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.namespace' , 'databases' )
2020-01-31 22:34:07 +00:00
-> label ( 'sdk.method' , 'createDocument' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/create-document.md' )
2020-11-11 21:02:24 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_CREATED )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2021-04-08 08:39:23 +00:00
-> label ( 'sdk.response.model' , Response :: MODEL_DOCUMENT )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-01-12 22:05:25 +00:00
-> param ( 'documentId' , '' , new CustomId (), 'Document ID. Choose your own unique ID or pass the string "unique()" to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.' )
2022-09-19 10:05:42 +00:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection). Make sure to define attributes before creating documents.' )
2022-03-15 15:22:48 +00:00
-> param ( 'data' , [], new JSON (), 'Document data as JSON object.' )
2022-09-06 09:17:25 +00:00
-> param ( 'permissions' , null , new Permissions ( APP_LIMIT_ARRAY_PARAMS_SIZE , [ Database :: PERMISSION_READ , Database :: PERMISSION_UPDATE , Database :: PERMISSION_DELETE , Database :: PERMISSION_WRITE ]), 'An array of permissions strings. By default the current user is granted with all permissions. [Learn more about permissions](/docs/permissions).' , true )
2020-12-26 15:05:04 +00:00
-> inject ( 'response' )
2021-12-27 12:45:23 +00:00
-> inject ( 'dbForProject' )
2021-03-21 22:17:20 +00:00
-> inject ( 'user' )
2021-12-16 18:12:06 +00:00
-> inject ( 'events' )
2021-12-13 12:42:04 +00:00
-> inject ( 'mode' )
2022-08-25 06:21:15 +00:00
-> action ( function ( string $databaseId , string $documentId , string $collectionId , string | array $data , ? array $permissions , Response $response , Database $dbForProject , Document $user , Event $events , string $mode ) {
2021-10-05 10:30:33 +00:00
2020-06-29 21:43:34 +00:00
$data = ( \is_string ( $data )) ? \json_decode ( $data , true ) : $data ; // Cast to JSON array
if ( empty ( $data )) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DOCUMENT_MISSING_PAYLOAD );
2020-06-29 21:43:34 +00:00
}
2020-01-31 22:34:07 +00:00
2020-06-29 21:43:34 +00:00
if ( isset ( $data [ '$id' ])) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DOCUMENT_INVALID_STRUCTURE , '$id is not allowed for creating new documents, try update instead' );
2020-06-29 21:43:34 +00:00
}
2021-10-05 10:30:33 +00:00
2022-08-24 08:50:05 +00:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2022-08-08 10:58:28 +00:00
if ( $database -> isEmpty ()) {
2022-08-16 08:30:00 +00:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-08-08 10:58:28 +00:00
}
2022-06-22 10:51:49 +00:00
$collection = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId ));
2020-01-31 22:34:07 +00:00
2021-12-17 12:51:07 +00:00
if ( $collection -> isEmpty () || ! $collection -> getAttribute ( 'enabled' )) {
if ( ! ( $mode === APP_MODE_ADMIN && Auth :: isPrivilegedUser ( Authorization :: getRoles ()))) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-12-17 12:51:07 +00:00
}
2020-06-29 21:43:34 +00:00
}
2020-01-31 22:34:07 +00:00
2022-08-24 08:50:05 +00:00
$validator = new Authorization ( Database :: PERMISSION_CREATE );
2022-08-13 14:10:28 +00:00
if ( ! $validator -> isValid ( $collection -> getCreate ())) {
2022-08-16 08:30:00 +00:00
throw new Exception ( Exception :: USER_UNAUTHORIZED );
2022-08-08 10:58:28 +00:00
}
2022-08-23 01:42:25 +00:00
$allowedPermissions = [
Database :: PERMISSION_READ ,
Database :: PERMISSION_UPDATE ,
Database :: PERMISSION_DELETE ,
];
2022-08-16 05:54:44 +00:00
2022-08-23 01:42:25 +00:00
// Map aggregate permissions to into the set of individual permissions they represent.
$permissions = Permission :: aggregate ( $permissions , $allowedPermissions );
// Add permissions for current the user if none were provided.
2022-08-15 12:56:19 +00:00
if ( \is_null ( $permissions )) {
$permissions = [];
2022-08-15 13:16:20 +00:00
if ( ! empty ( $user -> getId ())) {
2022-08-15 12:56:19 +00:00
foreach ( $allowedPermissions as $permission ) {
2022-08-15 13:16:20 +00:00
$permissions [] = ( new Permission ( $permission , 'user' , $user -> getId ())) -> toString ();
2022-08-15 12:56:19 +00:00
}
}
}
2022-08-14 05:24:50 +00:00
2022-08-15 12:56:19 +00:00
// Users can only manage their own roles, API keys and Admin users can manage any
$roles = Authorization :: getRoles ();
if ( ! Auth :: isAppUser ( $roles ) && ! Auth :: isPrivilegedUser ( $roles )) {
foreach ( Database :: PERMISSIONS as $type ) {
foreach ( $permissions as $permission ) {
2022-08-16 11:26:38 +00:00
$permission = Permission :: parse ( $permission );
if ( $permission -> getPermission () != $type ) {
2022-08-15 12:56:19 +00:00
continue ;
}
2022-08-16 11:26:38 +00:00
$role = ( new Role (
$permission -> getRole (),
$permission -> getIdentifier (),
$permission -> getDimension ()
)) -> toString ();
2022-08-15 12:56:19 +00:00
if ( ! Authorization :: isRole ( $role )) {
2022-08-25 03:51:21 +00:00
throw new Exception ( Exception :: USER_UNAUTHORIZED , 'Permissions must be one of: (' . \implode ( ', ' , $roles ) . ')' );
2022-08-15 12:56:19 +00:00
}
}
}
2022-08-08 10:58:28 +00:00
}
2021-06-15 13:38:24 +00:00
$data [ '$collection' ] = $collection -> getId (); // Adding this param to make API easier for developers
2022-08-14 14:22:38 +00:00
$data [ '$id' ] = $documentId == 'unique()' ? ID :: unique () : $documentId ;
2022-08-02 09:18:49 +00:00
$data [ '$permissions' ] = $permissions ;
2020-01-31 22:34:07 +00:00
2021-06-11 20:06:54 +00:00
try {
2022-08-05 06:01:25 +00:00
$document = $dbForProject -> createDocument ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (), new Document ( $data ));
2022-09-12 21:58:23 +00:00
$document -> setAttribute ( '$collectionId' , $collectionId );
$document -> setAttribute ( '$databaseId' , $databaseId );
2022-05-23 14:54:50 +00:00
} catch ( StructureException $exception ) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DOCUMENT_INVALID_STRUCTURE , $exception -> getMessage ());
2022-05-23 14:54:50 +00:00
} catch ( DuplicateException $exception ) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DOCUMENT_ALREADY_EXISTS );
2021-08-21 21:48:07 +00:00
}
2020-01-31 22:34:07 +00:00
2022-04-13 12:39:31 +00:00
$events
2022-06-22 10:51:49 +00:00
-> setParam ( 'databaseId' , $databaseId )
2022-04-13 12:39:31 +00:00
-> setParam ( 'collectionId' , $collection -> getId ())
-> setParam ( 'documentId' , $document -> getId ())
2022-06-22 10:51:49 +00:00
-> setContext ( 'collection' , $collection )
-> setContext ( 'database' , $database )
2022-04-13 12:39:31 +00:00
;
2021-12-16 18:12:06 +00:00
2022-09-07 11:11:10 +00:00
$response
-> setStatusCode ( Response :: STATUS_CODE_CREATED )
-> dynamic ( $document , Response :: MODEL_DOCUMENT );
2020-12-26 15:05:04 +00:00
});
2020-01-31 22:34:07 +00:00
2022-06-22 10:51:49 +00:00
App :: get ( '/v1/databases/:databaseId/collections/:collectionId/documents' )
2022-06-23 08:50:11 +00:00
-> alias ( '/v1/database/collections/:collectionId/documents' , [ 'databaseId' => 'default' ])
2019-05-09 06:54:39 +00:00
-> desc ( 'List Documents' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'database' ])
2019-06-08 13:13:19 +00:00
-> label ( 'scope' , 'documents.read' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'documents.{scope}.requests.read' )
2022-08-21 02:10:21 +00:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' , 'collectionId:{request.collectionId}' ])
2021-04-16 07:22:17 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_SESSION , APP_AUTH_TYPE_KEY , APP_AUTH_TYPE_JWT ])
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.namespace' , 'databases' )
2019-05-09 06:54:39 +00:00
-> label ( 'sdk.method' , 'listDocuments' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/list-documents.md' )
2020-11-11 21:02:24 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_DOCUMENT_LIST )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 08:14:27 +00:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).' )
2022-08-23 16:33:08 +00:00
-> param ( 'queries' , [], new ArrayList ( new Text ( APP_LIMIT_ARRAY_ELEMENT_SIZE ), APP_LIMIT_ARRAY_PARAMS_SIZE ), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.' , true )
2020-12-26 15:05:04 +00:00
-> inject ( 'response' )
2021-12-27 12:45:23 +00:00
-> inject ( 'dbForProject' )
2021-12-13 12:42:04 +00:00
-> inject ( 'mode' )
2022-08-25 09:59:28 +00:00
-> action ( function ( string $databaseId , string $collectionId , array $queries , Response $response , Database $dbForProject , string $mode ) {
2022-06-22 10:51:49 +00:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2019-05-09 06:54:39 +00:00
2022-06-22 10:51:49 +00:00
if ( $database -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 10:51:49 +00:00
}
2022-08-08 10:58:28 +00:00
2022-06-22 10:51:49 +00:00
$collection = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId ));
2019-05-09 06:54:39 +00:00
2021-12-17 12:51:07 +00:00
if ( $collection -> isEmpty () || ! $collection -> getAttribute ( 'enabled' )) {
if ( ! ( $mode === APP_MODE_ADMIN && Auth :: isPrivilegedUser ( Authorization :: getRoles ()))) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-12-17 12:51:07 +00:00
}
2020-06-29 21:43:34 +00:00
}
2020-06-21 12:12:13 +00:00
2022-08-08 10:58:28 +00:00
$documentSecurity = $collection -> getAttribute ( 'documentSecurity' , false );
2022-08-24 13:24:19 +00:00
$validator = new Authorization ( Database :: PERMISSION_READ );
2022-08-08 10:58:28 +00:00
$valid = $validator -> isValid ( $collection -> getRead ());
2022-08-24 13:24:19 +00:00
if ( ! $documentSecurity && ! $valid ) {
2022-08-16 08:30:00 +00:00
throw new Exception ( Exception :: USER_UNAUTHORIZED );
2021-08-12 01:05:19 +00:00
}
2022-08-23 16:33:08 +00:00
// Validate queries
2022-08-29 10:05:11 +00:00
$queriesValidator = new Documents ( $collection -> getAttribute ( 'attributes' ), $collection -> getAttribute ( 'indexes' ));
$validQueries = $queriesValidator -> isValid ( $queries );
if ( ! $validQueries ) {
2022-08-29 10:27:56 +00:00
throw new Exception ( Exception :: GENERAL_ARGUMENT_INVALID , $queriesValidator -> getDescription ());
2022-08-20 00:47:10 +00:00
}
2021-12-28 17:57:24 +00:00
2022-08-23 15:18:59 +00:00
$queries = Query :: parseQueries ( $queries );
2020-06-29 21:43:34 +00:00
2022-08-23 15:18:59 +00:00
// Get cursor document if there was a cursor query
2022-08-30 23:31:43 +00:00
$cursor = Query :: getByType ( $queries , Query :: TYPE_CURSORAFTER , Query :: TYPE_CURSORBEFORE );
$cursor = reset ( $cursor );
2022-08-30 11:55:23 +00:00
if ( $cursor ) {
2022-08-23 15:18:59 +00:00
/** @var Query $cursor */
$documentId = $cursor -> getValue ();
2021-07-05 20:27:20 +00:00
2022-08-25 01:04:47 +00:00
if ( $documentSecurity && ! $valid ) {
2022-08-23 15:18:59 +00:00
$cursorDocument = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (), $documentId );
2022-08-25 01:04:47 +00:00
} else {
2022-08-23 15:18:59 +00:00
$cursorDocument = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (), $documentId ));
2022-08-25 01:04:47 +00:00
}
2022-08-24 13:24:19 +00:00
2021-10-05 10:30:33 +00:00
if ( $cursorDocument -> isEmpty ()) {
2022-08-23 15:18:59 +00:00
throw new Exception ( Exception :: GENERAL_CURSOR_NOT_FOUND , " Document ' { $documentId } ' for the 'cursor' value not found. " );
2021-08-05 19:01:00 +00:00
}
2022-08-11 23:53:52 +00:00
2022-08-23 15:18:59 +00:00
$cursor -> setValue ( $cursorDocument );
2022-08-11 23:53:52 +00:00
}
2022-08-23 15:18:59 +00:00
$filterQueries = Query :: groupByType ( $queries )[ 'filters' ];
2022-08-11 23:53:52 +00:00
2022-08-29 08:49:00 +00:00
if ( $documentSecurity && ! $valid ) {
2022-08-23 15:18:59 +00:00
$documents = $dbForProject -> find ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (), $queries );
2022-08-11 23:53:52 +00:00
$total = $dbForProject -> count ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (), $filterQueries , APP_LIMIT_COUNT );
2022-08-09 06:03:41 +00:00
} else {
2022-08-23 15:18:59 +00:00
$documents = Authorization :: skip ( fn () => $dbForProject -> find ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (), $queries ));
2022-08-14 11:46:34 +00:00
$total = Authorization :: skip ( fn () => $dbForProject -> count ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (), $filterQueries , APP_LIMIT_COUNT ));
2022-08-09 06:03:41 +00:00
}
2021-08-12 01:26:31 +00:00
2021-12-27 10:45:24 +00:00
/**
* Reset $collection attribute to remove prefix .
*/
2022-09-12 21:58:23 +00:00
$documents = array_map ( function ( Document $document ) use ( $collectionId , $databaseId ) {
$document -> setAttribute ( '$collectionId' , $collectionId );
$document -> setAttribute ( '$databaseId' , $databaseId );
return $document ;
}, $documents );
2021-12-27 10:45:24 +00:00
2021-07-25 14:47:18 +00:00
$response -> dynamic ( new Document ([
2022-02-27 09:57:09 +00:00
'total' => $total ,
2021-08-12 01:26:31 +00:00
'documents' => $documents ,
2021-06-14 19:55:36 +00:00
]), Response :: MODEL_DOCUMENT_LIST );
2020-12-26 15:05:04 +00:00
});
2019-05-09 06:54:39 +00:00
2022-06-22 10:51:49 +00:00
App :: get ( '/v1/databases/:databaseId/collections/:collectionId/documents/:documentId' )
2022-06-23 08:50:11 +00:00
-> alias ( '/v1/database/collections/:collectionId/documents/:documentId' , [ 'databaseId' => 'default' ])
2019-05-09 06:54:39 +00:00
-> desc ( 'Get Document' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'database' ])
2019-06-08 13:13:19 +00:00
-> label ( 'scope' , 'documents.read' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'documents.{scope}.requests.read' )
2022-08-21 02:10:21 +00:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' , 'collectionId:{request.collectionId}' ])
2021-04-16 07:22:17 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_SESSION , APP_AUTH_TYPE_KEY , APP_AUTH_TYPE_JWT ])
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.namespace' , 'databases' )
2019-05-09 06:54:39 +00:00
-> label ( 'sdk.method' , 'getDocument' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/get-document.md' )
2020-11-11 21:02:24 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2021-04-08 08:39:23 +00:00
-> label ( 'sdk.response.model' , Response :: MODEL_DOCUMENT )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-09-19 10:05:42 +00:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).' )
-> param ( 'documentId' , '' , new UID (), 'Document ID.' )
2020-12-26 15:05:04 +00:00
-> inject ( 'response' )
2021-12-27 12:45:23 +00:00
-> inject ( 'dbForProject' )
2021-12-13 12:42:04 +00:00
-> inject ( 'mode' )
2022-08-10 02:18:18 +00:00
-> action ( function ( string $databaseId , string $collectionId , string $documentId , Response $response , Database $dbForProject , string $mode ) {
2022-06-22 10:51:49 +00:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2019-05-09 06:54:39 +00:00
2022-06-22 10:51:49 +00:00
if ( $database -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 10:51:49 +00:00
}
2022-08-08 10:58:28 +00:00
2022-06-22 10:51:49 +00:00
$collection = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId ));
2019-05-09 06:54:39 +00:00
2021-12-17 12:51:07 +00:00
if ( $collection -> isEmpty () || ! $collection -> getAttribute ( 'enabled' )) {
if ( ! ( $mode === APP_MODE_ADMIN && Auth :: isPrivilegedUser ( Authorization :: getRoles ()))) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-12-17 12:51:07 +00:00
}
2021-06-10 18:19:42 +00:00
}
2022-08-08 10:58:28 +00:00
$documentSecurity = $collection -> getAttribute ( 'documentSecurity' , false );
2022-08-24 08:50:05 +00:00
$validator = new Authorization ( Database :: PERMISSION_READ );
2022-08-08 10:58:28 +00:00
$valid = $validator -> isValid ( $collection -> getRead ());
2022-08-24 13:24:19 +00:00
if ( ! $documentSecurity && ! $valid ) {
2022-08-16 08:30:00 +00:00
throw new Exception ( Exception :: USER_UNAUTHORIZED );
2021-08-12 01:05:19 +00:00
}
2022-08-24 13:24:19 +00:00
if ( $documentSecurity && ! $valid ) {
2022-08-24 08:50:05 +00:00
$document = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (), $documentId );
} else {
$document = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (), $documentId ));
}
2022-08-08 10:58:28 +00:00
if ( $document -> isEmpty ()) {
2022-08-16 09:07:30 +00:00
throw new Exception ( Exception :: DOCUMENT_NOT_FOUND );
2022-08-08 10:58:28 +00:00
}
2021-12-27 10:45:24 +00:00
/**
* Reset $collection attribute to remove prefix .
*/
2022-09-12 21:58:23 +00:00
$document -> setAttribute ( '$collectionId' , $collectionId );
$document -> setAttribute ( '$databaseId' , $databaseId );
2021-12-27 10:45:24 +00:00
2021-07-25 14:47:18 +00:00
$response -> dynamic ( $document , Response :: MODEL_DOCUMENT );
2020-12-26 15:05:04 +00:00
});
2019-05-09 06:54:39 +00:00
2022-06-22 10:51:49 +00:00
App :: get ( '/v1/databases/:databaseId/collections/:collectionId/documents/:documentId/logs' )
2022-06-23 08:50:11 +00:00
-> alias ( '/v1/database/collections/:collectionId/documents/:documentId/logs' , [ 'databaseId' => 'default' ])
2021-08-29 07:43:09 +00:00
-> desc ( 'List Document Logs' )
-> groups ([ 'api' , 'database' ])
-> label ( 'scope' , 'documents.read' )
2022-08-21 02:10:21 +00:00
-> label ( 'usage.metric' , 'documents.{scope}.requests.read' )
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' , 'collectionId:{request.collectionId}' ])
2021-08-29 07:43:09 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_ADMIN ])
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.namespace' , 'databases' )
2021-08-29 07:43:09 +00:00
-> label ( 'sdk.method' , 'listDocumentLogs' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/get-document-logs.md' )
2021-08-29 07:43:09 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_LOG_LIST )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2021-12-10 12:27:11 +00:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID.' )
2022-09-19 10:05:42 +00:00
-> param ( 'documentId' , '' , new UID (), 'Document ID.' )
2022-08-23 13:03:38 +00:00
-> param ( 'queries' , [], new Queries ( new Limit (), new Offset ()), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Only supported methods are limit and offset' , true )
2021-08-29 07:43:09 +00:00
-> inject ( 'response' )
2021-12-27 12:45:23 +00:00
-> inject ( 'dbForProject' )
2021-08-29 07:43:09 +00:00
-> inject ( 'locale' )
-> inject ( 'geodb' )
2022-08-23 13:03:38 +00:00
-> action ( function ( string $databaseId , string $collectionId , string $documentId , array $queries , Response $response , Database $dbForProject , Locale $locale , Reader $geodb ) {
2021-08-29 07:43:09 +00:00
2022-06-22 10:51:49 +00:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
if ( $database -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 10:51:49 +00:00
}
2022-08-25 01:04:47 +00:00
2022-06-22 10:51:49 +00:00
$collection = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId );
2021-08-29 07:43:09 +00:00
if ( $collection -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-08-29 07:43:09 +00:00
}
2022-06-22 10:51:49 +00:00
$document = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (), $documentId );
2021-08-29 07:43:09 +00:00
if ( $document -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DOCUMENT_NOT_FOUND );
2021-08-29 07:43:09 +00:00
}
2022-08-23 13:03:38 +00:00
$queries = Query :: parseQueries ( $queries );
$grouped = Query :: groupByType ( $queries );
2022-08-30 11:55:23 +00:00
$limit = $grouped [ 'limit' ] ? ? APP_LIMIT_COUNT ;
2022-08-23 13:03:38 +00:00
$offset = $grouped [ 'offset' ] ? ? 0 ;
2021-12-27 12:45:23 +00:00
$audit = new Audit ( $dbForProject );
2022-06-22 10:51:49 +00:00
$resource = 'database/' . $databaseId . '/collection/' . $collectionId . '/document/' . $document -> getId ();
2021-11-18 10:33:42 +00:00
$logs = $audit -> getLogsByResource ( $resource , $limit , $offset );
2021-08-29 07:43:09 +00:00
$output = [];
foreach ( $logs as $i => & $log ) {
$log [ 'userAgent' ] = ( ! empty ( $log [ 'userAgent' ])) ? $log [ 'userAgent' ] : 'UNKNOWN' ;
2021-12-12 17:59:12 +00:00
$detector = new Detector ( $log [ 'userAgent' ]);
$detector -> skipBotDetection (); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then)
2021-08-29 07:43:09 +00:00
2021-12-12 17:59:12 +00:00
$os = $detector -> getOS ();
$client = $detector -> getClient ();
$device = $detector -> getDevice ();
2021-08-29 07:43:09 +00:00
$output [ $i ] = new Document ([
'event' => $log [ 'event' ],
'userId' => $log [ 'userId' ],
'userEmail' => $log [ 'data' ][ 'userEmail' ] ? ? null ,
'userName' => $log [ 'data' ][ 'userName' ] ? ? null ,
'mode' => $log [ 'data' ][ 'mode' ] ? ? null ,
'ip' => $log [ 'ip' ],
'time' => $log [ 'time' ],
2021-12-12 17:59:12 +00:00
'osCode' => $os [ 'osCode' ],
'osName' => $os [ 'osName' ],
'osVersion' => $os [ 'osVersion' ],
'clientType' => $client [ 'clientType' ],
'clientCode' => $client [ 'clientCode' ],
'clientName' => $client [ 'clientName' ],
'clientVersion' => $client [ 'clientVersion' ],
'clientEngine' => $client [ 'clientEngine' ],
'clientEngineVersion' => $client [ 'clientEngineVersion' ],
'deviceName' => $device [ 'deviceName' ],
'deviceBrand' => $device [ 'deviceBrand' ],
'deviceModel' => $device [ 'deviceModel' ]
2021-08-29 07:43:09 +00:00
]);
$record = $geodb -> get ( $log [ 'ip' ]);
if ( $record ) {
2022-05-23 14:54:50 +00:00
$output [ $i ][ 'countryCode' ] = $locale -> getText ( 'countries.' . strtolower ( $record [ 'country' ][ 'iso_code' ]), false ) ? \strtolower ( $record [ 'country' ][ 'iso_code' ]) : '--' ;
$output [ $i ][ 'countryName' ] = $locale -> getText ( 'countries.' . strtolower ( $record [ 'country' ][ 'iso_code' ]), $locale -> getText ( 'locale.country.unknown' ));
2021-08-29 07:43:09 +00:00
} else {
$output [ $i ][ 'countryCode' ] = '--' ;
$output [ $i ][ 'countryName' ] = $locale -> getText ( 'locale.country.unknown' );
}
}
2021-11-18 10:33:42 +00:00
$response -> dynamic ( new Document ([
2022-02-27 09:57:09 +00:00
'total' => $audit -> countLogsByResource ( $resource ),
2021-11-18 10:33:42 +00:00
'logs' => $output ,
]), Response :: MODEL_LOG_LIST );
2021-08-29 07:43:09 +00:00
});
2022-06-22 10:51:49 +00:00
App :: patch ( '/v1/databases/:databaseId/collections/:collectionId/documents/:documentId' )
2022-06-23 08:50:11 +00:00
-> alias ( '/v1/database/collections/:collectionId/documents/:documentId' , [ 'databaseId' => 'default' ])
2019-05-09 06:54:39 +00:00
-> desc ( 'Update Document' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'database' ])
2022-06-22 10:51:49 +00:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].documents.[documentId].update' )
2019-06-08 13:13:19 +00:00
-> label ( 'scope' , 'documents.write' )
2022-09-05 08:00:08 +00:00
-> label ( 'audits.event' , 'document.update' )
2022-08-08 14:32:54 +00:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}/document/{response.$id}' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'documents.{scope}.requests.update' )
2022-08-21 02:10:21 +00:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' , 'collectionId:{request.collectionId}' ])
2022-08-31 03:58:32 +00:00
-> label ( 'abuse-key' , 'ip:{ip},method:{method},url:{url},userId:{userId}' )
2022-08-30 23:34:17 +00:00
-> label ( 'abuse-limit' , APP_LIMIT_WRITE_RATE_DEFAULT * 2 )
-> label ( 'abuse-time' , APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT )
2021-04-16 07:22:17 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_SESSION , APP_AUTH_TYPE_KEY , APP_AUTH_TYPE_JWT ])
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.namespace' , 'databases' )
2019-05-09 06:54:39 +00:00
-> label ( 'sdk.method' , 'updateDocument' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/update-document.md' )
2020-11-11 21:02:24 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2021-04-08 08:39:23 +00:00
-> label ( 'sdk.response.model' , Response :: MODEL_DOCUMENT )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-09-19 10:05:42 +00:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID.' )
-> param ( 'documentId' , '' , new UID (), 'Document ID.' )
2022-06-09 00:49:27 +00:00
-> param ( 'data' , [], new JSON (), 'Document data as JSON object. Include only attribute and value pairs to be updated.' , true )
2022-09-06 09:17:25 +00:00
-> param ( 'permissions' , null , new Permissions ( APP_LIMIT_ARRAY_PARAMS_SIZE , [ Database :: PERMISSION_READ , Database :: PERMISSION_UPDATE , Database :: PERMISSION_DELETE , Database :: PERMISSION_WRITE ]), 'An array of permissions strings. By default the current permissions are inherited. [Learn more about permissions](/docs/permissions).' , true )
2020-12-26 15:05:04 +00:00
-> inject ( 'response' )
2021-12-27 12:45:23 +00:00
-> inject ( 'dbForProject' )
2021-12-16 18:12:06 +00:00
-> inject ( 'events' )
2021-12-13 12:42:04 +00:00
-> inject ( 'mode' )
2022-08-25 06:21:15 +00:00
-> action ( function ( string $databaseId , string $collectionId , string $documentId , string | array $data , ? array $permissions , Response $response , Database $dbForProject , Event $events , string $mode ) {
2019-05-09 06:54:39 +00:00
2022-08-08 10:58:28 +00:00
$data = ( \is_string ( $data )) ? \json_decode ( $data , true ) : $data ; // Cast to JSON array
2022-08-14 05:21:33 +00:00
if ( empty ( $data ) && \is_null ( $permissions )) {
2022-08-16 09:07:30 +00:00
throw new Exception ( Exception :: DOCUMENT_MISSING_PAYLOAD );
2022-08-08 10:58:28 +00:00
}
2022-06-22 10:51:49 +00:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
if ( $database -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 10:51:49 +00:00
}
2022-08-08 10:58:28 +00:00
2022-06-22 10:51:49 +00:00
$collection = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId ));
2019-09-16 19:03:24 +00:00
2021-12-17 12:51:07 +00:00
if ( $collection -> isEmpty () || ! $collection -> getAttribute ( 'enabled' )) {
if ( ! ( $mode === APP_MODE_ADMIN && Auth :: isPrivilegedUser ( Authorization :: getRoles ()))) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-12-17 12:51:07 +00:00
}
2020-06-29 21:43:34 +00:00
}
2019-05-09 06:54:39 +00:00
2022-08-08 10:58:28 +00:00
$documentSecurity = $collection -> getAttribute ( 'documentSecurity' , false );
2022-08-24 08:50:05 +00:00
$validator = new Authorization ( Database :: PERMISSION_UPDATE );
2022-08-08 10:58:28 +00:00
$valid = $validator -> isValid ( $collection -> getUpdate ());
2022-08-24 13:24:19 +00:00
if ( ! $documentSecurity && ! $valid ) {
2022-08-16 08:30:00 +00:00
throw new Exception ( Exception :: USER_UNAUTHORIZED );
2021-08-12 01:05:19 +00:00
}
2022-08-25 01:04:47 +00:00
// Read permission should not be required for update
2022-08-24 08:50:05 +00:00
$document = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (), $documentId ));
2021-06-15 13:38:24 +00:00
if ( $document -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DOCUMENT_NOT_FOUND );
2020-06-29 21:43:34 +00:00
}
2019-05-09 06:54:39 +00:00
2022-08-25 03:51:21 +00:00
// Map aggregate permissions into the multiple permissions they represent.
$permissions = Permission :: aggregate ( $permissions , [
Database :: PERMISSION_READ ,
Database :: PERMISSION_UPDATE ,
Database :: PERMISSION_DELETE ,
]);
2022-08-15 12:56:19 +00:00
// Users can only manage their own roles, API keys and Admin users can manage any
2022-08-08 10:58:28 +00:00
$roles = Authorization :: getRoles ();
2022-08-15 12:56:19 +00:00
if ( ! Auth :: isAppUser ( $roles ) && ! Auth :: isPrivilegedUser ( $roles ) && ! \is_null ( $permissions )) {
foreach ( Database :: PERMISSIONS as $type ) {
foreach ( $permissions as $permission ) {
2022-08-16 11:26:38 +00:00
$permission = Permission :: parse ( $permission );
if ( $permission -> getPermission () != $type ) {
2022-08-15 12:56:19 +00:00
continue ;
}
2022-08-16 11:26:38 +00:00
$role = ( new Role (
$permission -> getRole (),
$permission -> getIdentifier (),
$permission -> getDimension ()
)) -> toString ();
2022-08-15 12:56:19 +00:00
if ( ! Authorization :: isRole ( $role )) {
2022-08-25 03:51:21 +00:00
throw new Exception ( Exception :: USER_UNAUTHORIZED , 'Permissions must be one of: (' . \implode ( ', ' , $roles ) . ')' );
2022-08-15 12:56:19 +00:00
}
2022-08-08 10:58:28 +00:00
}
}
}
2022-08-02 09:18:49 +00:00
2022-08-25 11:46:56 +00:00
if ( \is_null ( $permissions )) {
$permissions = $document -> getPermissions () ? ? [];
}
2022-08-08 10:58:28 +00:00
$data = \array_merge ( $document -> getArrayCopy (), $data );
$data [ '$collection' ] = $collection -> getId (); // Make sure user doesn't switch collectionID
$data [ '$createdAt' ] = $document -> getCreatedAt (); // Make sure user doesn't switch createdAt
$data [ '$id' ] = $document -> getId (); // Make sure user doesn't switch document unique ID
2022-08-02 09:18:49 +00:00
$data [ '$permissions' ] = $permissions ;
2020-10-30 19:53:27 +00:00
2020-06-29 21:43:34 +00:00
try {
2022-08-24 13:24:19 +00:00
if ( $documentSecurity && ! $valid ) {
2022-08-24 08:50:05 +00:00
$document = $dbForProject -> updateDocument ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (), $document -> getId (), new Document ( $data ));
} else {
$document = Authorization :: skip ( fn () => $dbForProject -> updateDocument ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (), $document -> getId (), new Document ( $data )));
}
2022-08-08 10:58:28 +00:00
2021-12-27 10:45:24 +00:00
/**
* Reset $collection attribute to remove prefix .
*/
2022-09-12 21:58:23 +00:00
$document -> setAttribute ( '$collectionId' , $collectionId );
$document -> setAttribute ( '$databaseId' , $databaseId );
2022-08-25 11:30:26 +00:00
} catch ( AuthorizationException ) {
throw new Exception ( Exception :: USER_UNAUTHORIZED );
2022-08-08 10:58:28 +00:00
} catch ( DuplicateException ) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DOCUMENT_ALREADY_EXISTS );
2022-05-23 14:54:50 +00:00
} catch ( StructureException $exception ) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DOCUMENT_INVALID_STRUCTURE , $exception -> getMessage ());
2021-08-15 21:09:40 +00:00
}
2021-12-16 18:12:06 +00:00
2022-04-13 12:39:31 +00:00
$events
2022-06-22 10:51:49 +00:00
-> setParam ( 'databaseId' , $databaseId )
2022-04-13 12:39:31 +00:00
-> setParam ( 'collectionId' , $collection -> getId ())
-> setParam ( 'documentId' , $document -> getId ())
2022-06-22 10:51:49 +00:00
-> setContext ( 'collection' , $collection )
-> setContext ( 'database' , $database )
2022-04-13 12:39:31 +00:00
;
2021-12-16 18:12:06 +00:00
2021-07-25 14:47:18 +00:00
$response -> dynamic ( $document , Response :: MODEL_DOCUMENT );
2020-12-26 15:05:04 +00:00
});
2019-05-09 06:54:39 +00:00
2022-06-22 10:51:49 +00:00
App :: delete ( '/v1/databases/:databaseId/collections/:collectionId/documents/:documentId' )
2022-06-23 08:50:11 +00:00
-> alias ( '/v1/database/collections/:collectionId/documents/:documentId' , [ 'databaseId' => 'default' ])
2019-05-09 06:54:39 +00:00
-> desc ( 'Delete Document' )
2020-06-25 18:32:12 +00:00
-> groups ([ 'api' , 'database' ])
2019-06-08 13:13:19 +00:00
-> label ( 'scope' , 'documents.write' )
2022-06-22 10:51:49 +00:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].documents.[documentId].delete' )
2022-09-05 08:00:08 +00:00
-> label ( 'audits.event' , 'document.delete' )
2022-08-08 14:32:54 +00:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}/document/{request.documentId}' )
2022-08-10 02:18:18 +00:00
-> label ( 'usage.metric' , 'documents.{scope}.requests.delete' )
2022-08-21 02:10:21 +00:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' , 'collectionId:{request.collectionId}' ])
2022-08-31 03:58:32 +00:00
-> label ( 'abuse-key' , 'ip:{ip},method:{method},url:{url},userId:{userId}' )
2022-08-30 23:34:17 +00:00
-> label ( 'abuse-limit' , APP_LIMIT_WRITE_RATE_DEFAULT )
-> label ( 'abuse-time' , APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT )
2021-04-16 07:22:17 +00:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_SESSION , APP_AUTH_TYPE_KEY , APP_AUTH_TYPE_JWT ])
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.namespace' , 'databases' )
2019-05-09 06:54:39 +00:00
-> label ( 'sdk.method' , 'deleteDocument' )
2022-06-22 10:51:49 +00:00
-> label ( 'sdk.description' , '/docs/references/databases/delete-document.md' )
2020-11-11 21:02:24 +00:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_NOCONTENT )
-> label ( 'sdk.response.model' , Response :: MODEL_NONE )
2022-06-22 10:51:49 +00:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-09-19 10:05:42 +00:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).' )
-> param ( 'documentId' , '' , new UID (), 'Document ID.' )
2020-12-26 15:05:04 +00:00
-> inject ( 'response' )
2021-12-27 12:45:23 +00:00
-> inject ( 'dbForProject' )
2020-12-26 15:05:04 +00:00
-> inject ( 'events' )
2022-01-03 10:29:15 +00:00
-> inject ( 'deletes' )
2021-12-13 12:42:04 +00:00
-> inject ( 'mode' )
2022-08-13 03:14:28 +00:00
-> action ( function ( string $databaseId , string $collectionId , string $documentId , Response $response , Database $dbForProject , Event $events , Delete $deletes , string $mode ) {
2022-06-22 10:51:49 +00:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2019-05-09 06:54:39 +00:00
2022-06-22 10:51:49 +00:00
if ( $database -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 10:51:49 +00:00
}
2022-08-08 10:58:28 +00:00
2022-06-22 10:51:49 +00:00
$collection = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId ));
2019-05-09 06:54:39 +00:00
2021-12-17 12:51:07 +00:00
if ( $collection -> isEmpty () || ! $collection -> getAttribute ( 'enabled' )) {
if ( ! ( $mode === APP_MODE_ADMIN && Auth :: isPrivilegedUser ( Authorization :: getRoles ()))) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-12-17 12:51:07 +00:00
}
2020-06-29 21:43:34 +00:00
}
2022-08-08 10:58:28 +00:00
$documentSecurity = $collection -> getAttribute ( 'documentSecurity' , false );
2022-08-24 08:50:05 +00:00
$validator = new Authorization ( Database :: PERMISSION_DELETE );
2022-08-08 10:58:28 +00:00
$valid = $validator -> isValid ( $collection -> getDelete ());
2022-08-24 13:24:19 +00:00
if ( ! $documentSecurity && ! $valid ) {
2022-08-16 08:30:00 +00:00
throw new Exception ( Exception :: USER_UNAUTHORIZED );
2021-08-12 01:05:19 +00:00
}
2022-08-25 01:04:47 +00:00
// Read permission should not be required for delete
2022-08-24 08:50:05 +00:00
$document = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (), $documentId ));
2021-06-10 18:19:42 +00:00
if ( $document -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: DOCUMENT_NOT_FOUND );
2020-06-29 21:43:34 +00:00
}
2019-05-09 06:54:39 +00:00
2022-08-24 13:24:19 +00:00
if ( $documentSecurity && ! $valid ) {
2022-08-25 11:30:26 +00:00
try {
$dbForProject -> deleteDocument ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (), $documentId );
} catch ( AuthorizationException ) {
throw new Exception ( Exception :: USER_UNAUTHORIZED );
}
2022-08-24 08:50:05 +00:00
} else {
Authorization :: skip ( fn () => $dbForProject -> deleteDocument ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (), $documentId ));
2022-08-08 10:58:28 +00:00
}
2022-06-22 10:51:49 +00:00
$dbForProject -> deleteCachedDocument ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (), $documentId );
2021-06-10 18:19:42 +00:00
2021-12-27 10:45:24 +00:00
/**
* Reset $collection attribute to remove prefix .
*/
2022-09-12 21:58:23 +00:00
$document -> setAttribute ( '$collectionId' , $collectionId );
$document -> setAttribute ( '$databaseId' , $databaseId );
2021-12-27 10:45:24 +00:00
2022-01-03 10:29:15 +00:00
$deletes
2022-04-17 20:34:32 +00:00
-> setType ( DELETE_TYPE_AUDIT )
-> setDocument ( $document )
2022-01-03 10:29:15 +00:00
;
2020-12-06 22:14:57 +00:00
$events
2022-06-22 10:51:49 +00:00
-> setParam ( 'databaseId' , $databaseId )
2022-04-13 12:39:31 +00:00
-> setParam ( 'collectionId' , $collection -> getId ())
-> setParam ( 'documentId' , $document -> getId ())
2022-06-22 10:51:49 +00:00
-> setContext ( 'collection' , $collection )
-> setContext ( 'database' , $database )
2022-04-13 12:39:31 +00:00
-> setPayload ( $response -> output ( $document , Response :: MODEL_DOCUMENT ))
2020-06-29 21:43:34 +00:00
;
2021-04-14 09:02:17 +00:00
2020-06-29 21:43:34 +00:00
$response -> noContent ();
2021-08-24 14:03:32 +00:00
});
2022-06-22 10:51:49 +00:00
App :: get ( '/v1/databases/usage' )
2022-06-23 08:50:11 +00:00
-> desc ( 'Get usage stats for the database' )
-> groups ([ 'api' , 'database' ])
-> label ( 'scope' , 'collections.read' )
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_ADMIN ])
-> label ( 'sdk.namespace' , 'databases' )
-> label ( 'sdk.method' , 'getUsage' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_USAGE_DATABASES )
-> param ( 'range' , '30d' , new WhiteList ([ '24h' , '7d' , '30d' , '90d' ], true ), '`Date range.' , true )
-> inject ( 'response' )
-> inject ( 'dbForProject' )
-> action ( function ( string $range , Response $response , Database $dbForProject ) {
$usage = [];
if ( App :: getEnv ( '_APP_USAGE_STATS' , 'enabled' ) == 'enabled' ) {
$periods = [
'24h' => [
2022-10-09 06:30:26 +00:00
'period' => '1h' ,
'limit' => 24 ,
2022-06-23 08:50:11 +00:00
],
'7d' => [
'period' => '1d' ,
'limit' => 7 ,
],
'30d' => [
'period' => '1d' ,
'limit' => 30 ,
],
'90d' => [
'period' => '1d' ,
'limit' => 90 ,
],
];
$metrics = [
2022-08-09 06:28:38 +00:00
'databases.$all.count.total' ,
'documents.$all.count.total' ,
'collections.$all.count.total' ,
'databases.$all.requests.create' ,
'databases.$all.requests.read' ,
'databases.$all.requests.update' ,
'databases.$all.requests.delete' ,
'collections.$all.requests.create' ,
'collections.$all.requests.read' ,
'collections.$all.requests.update' ,
'collections.$all.requests.delete' ,
'documents.$all.requests.create' ,
'documents.$all.requests.read' ,
'documents.$all.requests.update' ,
'documents.$all.requests.delete'
2022-06-23 08:50:11 +00:00
];
$stats = [];
Authorization :: skip ( function () use ( $dbForProject , $periods , $range , $metrics , & $stats ) {
foreach ( $metrics as $metric ) {
$limit = $periods [ $range ][ 'limit' ];
$period = $periods [ $range ][ 'period' ];
$requestDocs = $dbForProject -> find ( 'stats' , [
2022-08-11 23:53:52 +00:00
Query :: equal ( 'period' , [ $period ]),
Query :: equal ( 'metric' , [ $metric ]),
Query :: limit ( $limit ),
Query :: orderDesc ( 'time' ),
]);
2022-06-23 08:50:11 +00:00
$stats [ $metric ] = [];
foreach ( $requestDocs as $requestDoc ) {
$stats [ $metric ][] = [
'value' => $requestDoc -> getAttribute ( 'value' ),
'date' => $requestDoc -> getAttribute ( 'time' ),
];
}
2022-06-22 10:51:49 +00:00
2022-06-23 08:50:11 +00:00
// backfill metrics with empty values for graphs
$backfill = $limit - \count ( $requestDocs );
while ( $backfill > 0 ) {
$last = $limit - $backfill - 1 ; // array index of last added metric
$diff = match ( $period ) { // convert period to seconds for unix timestamp math
2022-10-09 06:33:14 +00:00
'1h' => 3600 ,
2022-06-23 08:50:11 +00:00
'1d' => 86400 ,
};
$stats [ $metric ][] = [
'value' => 0 ,
2022-09-15 23:48:09 +00:00
'date' => DateTime :: formatTz ( DateTime :: addSeconds ( new \DateTime ( $stats [ $metric ][ $last ][ 'date' ] ? ? null ), - 1 * $diff )),
2022-06-23 08:50:11 +00:00
];
$backfill -- ;
}
2022-07-11 15:12:41 +00:00
// Added 3'rd level to Index [period, metric, time] because of order by.
2022-06-23 08:50:11 +00:00
$stats [ $metric ] = array_reverse ( $stats [ $metric ]);
2022-06-22 10:51:49 +00:00
}
2022-06-23 08:50:11 +00:00
});
$usage = new Document ([
'range' => $range ,
2022-08-20 11:20:31 +00:00
'databasesCount' => $stats [ 'databases.$all.count.total' ] ? ? [],
'documentsCount' => $stats [ 'documents.$all.count.total' ] ? ? [],
'collectionsCount' => $stats [ 'collections.$all.count.total' ] ? ? [],
'documentsCreate' => $stats [ 'documents.$all.requests.create' ] ? ? [],
'documentsRead' => $stats [ 'documents.$all.requests.read' ] ? ? [],
'documentsUpdate' => $stats [ 'documents.$all.requests.update' ] ? ? [],
'documentsDelete' => $stats [ 'documents.$all.requests.delete' ] ? ? [],
'collectionsCreate' => $stats [ 'collections.$all.requests.create' ] ? ? [],
'collectionsRead' => $stats [ 'collections.$all.requests.read' ] ? ? [],
'collectionsUpdate' => $stats [ 'collections.$all.requests.update' ] ? ? [],
'collectionsDelete' => $stats [ 'collections.$all.requests.delete' ] ? ? [],
'databasesCreate' => $stats [ 'databases.$all.requests.create' ] ? ? [],
'databasesRead' => $stats [ 'databases.$all.requests.read' ] ? ? [],
'databasesUpdate' => $stats [ 'databases.$all.requests.update' ] ? ? [],
'databasesDelete' => $stats [ 'databases.$all.requests.delete' ] ? ? [],
2022-06-23 08:50:11 +00:00
]);
}
2022-06-22 10:51:49 +00:00
2022-06-23 08:50:11 +00:00
$response -> dynamic ( $usage , Response :: MODEL_USAGE_DATABASES );
});
2022-06-22 10:51:49 +00:00
App :: get ( '/v1/databases/:databaseId/usage' )
2022-06-23 08:50:11 +00:00
-> desc ( 'Get usage stats for the database' )
-> groups ([ 'api' , 'database' ])
-> label ( 'scope' , 'collections.read' )
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_ADMIN ])
-> label ( 'sdk.namespace' , 'databases' )
-> label ( 'sdk.method' , 'getDatabaseUsage' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_USAGE_DATABASE )
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
-> param ( 'range' , '30d' , new WhiteList ([ '24h' , '7d' , '30d' , '90d' ], true ), '`Date range.' , true )
-> inject ( 'response' )
-> inject ( 'dbForProject' )
-> action ( function ( string $databaseId , string $range , Response $response , Database $dbForProject ) {
$usage = [];
if ( App :: getEnv ( '_APP_USAGE_STATS' , 'enabled' ) == 'enabled' ) {
$periods = [
'24h' => [
2022-10-09 06:30:26 +00:00
'period' => '1h' ,
'limit' => 24 ,
2022-06-23 08:50:11 +00:00
],
'7d' => [
'period' => '1d' ,
'limit' => 7 ,
],
'30d' => [
'period' => '1d' ,
'limit' => 30 ,
],
'90d' => [
'period' => '1d' ,
'limit' => 90 ,
],
];
$metrics = [
2022-08-09 06:28:38 +00:00
'collections.' . $databaseId . '.count.total' ,
'collections.' . $databaseId . '.requests.create' ,
'collections.' . $databaseId . '.requests.read' ,
'collections.' . $databaseId . '.requests.update' ,
'collections.' . $databaseId . '.requests.delete' ,
2022-08-13 05:02:18 +00:00
'documents.' . $databaseId . '.count.total' ,
2022-08-09 06:28:38 +00:00
'documents.' . $databaseId . '.requests.create' ,
'documents.' . $databaseId . '.requests.read' ,
'documents.' . $databaseId . '.requests.update' ,
'documents.' . $databaseId . '.requests.delete'
2022-06-23 08:50:11 +00:00
];
$stats = [];
Authorization :: skip ( function () use ( $dbForProject , $periods , $range , $metrics , & $stats ) {
foreach ( $metrics as $metric ) {
$limit = $periods [ $range ][ 'limit' ];
$period = $periods [ $range ][ 'period' ];
$requestDocs = $dbForProject -> find ( 'stats' , [
2022-08-11 23:53:52 +00:00
Query :: equal ( 'period' , [ $period ]),
Query :: equal ( 'metric' , [ $metric ]),
Query :: limit ( $limit ),
Query :: orderDesc ( 'time' ),
]);
2022-06-23 08:50:11 +00:00
$stats [ $metric ] = [];
foreach ( $requestDocs as $requestDoc ) {
$stats [ $metric ][] = [
'value' => $requestDoc -> getAttribute ( 'value' ),
'date' => $requestDoc -> getAttribute ( 'time' ),
];
}
2022-06-22 10:51:49 +00:00
2022-06-23 08:50:11 +00:00
// backfill metrics with empty values for graphs
$backfill = $limit - \count ( $requestDocs );
while ( $backfill > 0 ) {
$last = $limit - $backfill - 1 ; // array index of last added metric
$diff = match ( $period ) { // convert period to seconds for unix timestamp math
2022-10-09 06:33:14 +00:00
'1h' => 3600 ,
2022-06-23 08:50:11 +00:00
'1d' => 86400 ,
};
$stats [ $metric ][] = [
'value' => 0 ,
2022-09-15 23:48:09 +00:00
'date' => DateTime :: formatTz ( DateTime :: addSeconds ( new \DateTime ( $stats [ $metric ][ $last ][ 'date' ] ? ? null ), - 1 * $diff )),
2022-06-23 08:50:11 +00:00
];
$backfill -- ;
}
// TODO@kodumbeats explore performance if query is ordered by time ASC
$stats [ $metric ] = array_reverse ( $stats [ $metric ]);
2022-06-22 10:51:49 +00:00
}
2022-06-23 08:50:11 +00:00
});
$usage = new Document ([
'range' => $range ,
2022-08-20 11:20:31 +00:00
'collectionsCount' => $stats [ " collections. { $databaseId } .count.total " ] ? ? [],
'collectionsCreate' => $stats [ " collections. { $databaseId } .requests.create " ] ? ? [],
'collectionsRead' => $stats [ " collections. { $databaseId } .requests.read " ] ? ? [],
'collectionsUpdate' => $stats [ " collections. { $databaseId } .requests.update " ] ? ? [],
'collectionsDelete' => $stats [ " collections. { $databaseId } .requests.delete " ] ? ? [],
'documentsCount' => $stats [ " documents. { $databaseId } .count.total " ] ? ? [],
'documentsCreate' => $stats [ " documents. { $databaseId } .requests.create " ] ? ? [],
'documentsRead' => $stats [ " documents. { $databaseId } .requests.read " ] ? ? [],
'documentsUpdate' => $stats [ " documents. { $databaseId } .requests.update " ] ? ? [],
'documentsDelete' => $stats [ " documents. { $databaseId } .requests.delete " ] ? ? [],
2022-06-23 08:50:11 +00:00
]);
}
2022-06-22 10:51:49 +00:00
2022-06-23 08:50:11 +00:00
$response -> dynamic ( $usage , Response :: MODEL_USAGE_DATABASE );
});
2022-06-22 10:51:49 +00:00
App :: get ( '/v1/databases/:databaseId/collections/:collectionId/usage' )
2022-07-05 23:13:48 +00:00
-> alias ( '/v1/database/:collectionId/usage' , [ 'databaseId' => 'default' ])
2022-06-23 08:50:11 +00:00
-> desc ( 'Get usage stats for a collection' )
-> groups ([ 'api' , 'database' ])
-> label ( 'scope' , 'collections.read' )
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_ADMIN ])
-> label ( 'sdk.namespace' , 'databases' )
-> label ( 'sdk.method' , 'getCollectionUsage' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_USAGE_COLLECTION )
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
-> param ( 'range' , '30d' , new WhiteList ([ '24h' , '7d' , '30d' , '90d' ], true ), 'Date range.' , true )
-> param ( 'collectionId' , '' , new UID (), 'Collection ID.' )
-> inject ( 'response' )
-> inject ( 'dbForProject' )
-> action ( function ( string $databaseId , string $range , string $collectionId , Response $response , Database $dbForProject ) {
2022-06-22 10:51:49 +00:00
2022-06-23 08:50:11 +00:00
$database = $dbForProject -> getDocument ( 'databases' , $databaseId );
2022-06-22 10:51:49 +00:00
2022-06-23 08:50:11 +00:00
$collectionDocument = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId );
$collection = $dbForProject -> getCollection ( 'database_' . $database -> getInternalId () . '_collection_' . $collectionDocument -> getInternalId ());
if ( $collection -> isEmpty ()) {
2022-07-26 14:24:32 +00:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2022-06-23 08:50:11 +00:00
}
2022-06-22 10:51:49 +00:00
2022-06-23 08:50:11 +00:00
$usage = [];
if ( App :: getEnv ( '_APP_USAGE_STATS' , 'enabled' ) == 'enabled' ) {
$periods = [
'24h' => [
2022-10-09 06:30:26 +00:00
'period' => '1h' ,
'limit' => 24 ,
2022-06-23 08:50:11 +00:00
],
'7d' => [
'period' => '1d' ,
'limit' => 7 ,
],
'30d' => [
'period' => '1d' ,
'limit' => 30 ,
],
'90d' => [
'period' => '1d' ,
'limit' => 90 ,
],
];
$metrics = [
2022-08-09 06:28:38 +00:00
" documents. { $databaseId } / { $collectionId } .count.total " ,
" documents. { $databaseId } / { $collectionId } .requests.create " ,
" documents. { $databaseId } / { $collectionId } .requests.read " ,
" documents. { $databaseId } / { $collectionId } .requests.update " ,
" documents. { $databaseId } / { $collectionId } .requests.delete " ,
2022-06-23 08:50:11 +00:00
];
$stats = [];
Authorization :: skip ( function () use ( $dbForProject , $periods , $range , $metrics , & $stats ) {
foreach ( $metrics as $metric ) {
$limit = $periods [ $range ][ 'limit' ];
$period = $periods [ $range ][ 'period' ];
$requestDocs = $dbForProject -> find ( 'stats' , [
2022-08-11 23:53:52 +00:00
Query :: equal ( 'period' , [ $period ]),
Query :: equal ( 'metric' , [ $metric ]),
Query :: limit ( $limit ),
Query :: orderDesc ( 'time' ),
]);
2022-06-23 08:50:11 +00:00
$stats [ $metric ] = [];
foreach ( $requestDocs as $requestDoc ) {
$stats [ $metric ][] = [
'value' => $requestDoc -> getAttribute ( 'value' ),
'date' => $requestDoc -> getAttribute ( 'time' ),
];
}
2022-06-22 10:51:49 +00:00
2022-06-23 08:50:11 +00:00
// backfill metrics with empty values for graphs
$backfill = $limit - \count ( $requestDocs );
while ( $backfill > 0 ) {
$last = $limit - $backfill - 1 ; // array index of last added metric
$diff = match ( $period ) { // convert period to seconds for unix timestamp math
2022-10-09 06:33:14 +00:00
'1h' => 3600 ,
2022-06-23 08:50:11 +00:00
'1d' => 86400 ,
};
$stats [ $metric ][] = [
'value' => 0 ,
2022-09-15 23:48:09 +00:00
'date' => DateTime :: formatTz ( DateTime :: addSeconds ( new \DateTime ( $stats [ $metric ][ $last ][ 'date' ] ? ? null ), - 1 * $diff )),
2022-06-23 08:50:11 +00:00
];
$backfill -- ;
}
$stats [ $metric ] = array_reverse ( $stats [ $metric ]);
2022-06-22 10:51:49 +00:00
}
2022-06-23 08:50:11 +00:00
});
$usage = new Document ([
'range' => $range ,
2022-08-20 11:20:31 +00:00
'documentsCount' => $stats [ " documents. { $databaseId } / { $collectionId } .count.total " ] ? ? [],
'documentsCreate' => $stats [ " documents. { $databaseId } / { $collectionId } .requests.create " ] ? ? [],
'documentsRead' => $stats [ " documents. { $databaseId } / { $collectionId } .requests.read " ] ? ? [],
'documentsUpdate' => $stats [ " documents. { $databaseId } / { $collectionId } .requests.update " ] ? ? [],
'documentsDelete' => $stats [ " documents. { $databaseId } / { $collectionId } .requests.delete " ? ? []]
2022-06-23 08:50:11 +00:00
]);
}
2022-06-22 10:51:49 +00:00
2022-06-23 08:50:11 +00:00
$response -> dynamic ( $usage , Response :: MODEL_USAGE_COLLECTION );
});