2019-05-09 18:54:39 +12:00
< ? php
2023-06-15 17:29:03 +12:00
use Appwrite\Auth\Auth ;
use Appwrite\Detector\Detector ;
use Appwrite\Event\Database as EventDatabase ;
2022-05-26 00:10:10 +12:00
use Appwrite\Event\Delete ;
2023-06-15 17:29:03 +12:00
use Appwrite\Event\Event ;
2022-02-07 05:50:48 +13:00
use Appwrite\Extend\Exception ;
2023-06-15 17:29:03 +12:00
use Appwrite\Network\Validator\Email ;
use Appwrite\Utopia\Database\Validator\CustomId ;
use Appwrite\Utopia\Database\Validator\Queries\Collections ;
use Appwrite\Utopia\Database\Validator\Queries\Databases ;
use Appwrite\Utopia\Response ;
use MaxMind\Db\Reader ;
use Utopia\App ;
2021-08-16 09:09:40 +12:00
use Utopia\Audit\Audit ;
2023-06-15 17:29:03 +12:00
use Utopia\Config\Config ;
use Utopia\Database\Adapter\MariaDB ;
2021-08-17 11:21:00 +12:00
use Utopia\Database\Database ;
2022-07-13 01:32:39 +12:00
use Utopia\Database\DateTime ;
2023-06-15 17:29:03 +12:00
use Utopia\Database\Document ;
use Utopia\Database\Exception\Authorization as AuthorizationException ;
use Utopia\Database\Exception\Duplicate as DuplicateException ;
use Utopia\Database\Exception\Limit as LimitException ;
use Utopia\Database\Exception\Restricted as RestrictedException ;
use Utopia\Database\Exception\Structure as StructureException ;
use Utopia\Database\Helpers\ID ;
use Utopia\Database\Helpers\Permission ;
use Utopia\Database\Helpers\Role ;
2021-08-17 11:21:00 +12:00
use Utopia\Database\Query ;
2021-08-12 13:05:19 +12:00
use Utopia\Database\Validator\Authorization ;
2023-06-15 17:29:03 +12:00
use Utopia\Database\Validator\Datetime as DatetimeValidator ;
use Utopia\Database\Validator\Index as IndexValidator ;
2021-06-23 07:34:42 +12:00
use Utopia\Database\Validator\Key ;
2021-07-06 08:27:20 +12:00
use Utopia\Database\Validator\Permissions ;
2023-06-15 17:29:03 +12:00
use Utopia\Database\Validator\Queries ;
use Utopia\Database\Validator\Queries\Document as DocumentQueriesValidator ;
use Utopia\Database\Validator\Queries\Documents ;
use Utopia\Database\Validator\Query\Limit ;
use Utopia\Database\Validator\Query\Offset ;
2021-07-24 02:59:55 +12:00
use Utopia\Database\Validator\Structure ;
2021-07-06 08:27:20 +12:00
use Utopia\Database\Validator\UID ;
2022-05-26 00:10:10 +12:00
use Utopia\Locale\Locale ;
2023-06-15 17:29:03 +12:00
use Utopia\Validator\ArrayList ;
use Utopia\Validator\Boolean ;
use Utopia\Validator\FloatValidator ;
2023-01-14 04:28:04 +13:00
use Utopia\Validator\IP ;
2023-06-15 17:29:03 +12:00
use Utopia\Validator\Integer ;
use Utopia\Validator\JSON ;
2023-03-02 01:00:36 +13:00
use Utopia\Validator\Nullable ;
2023-06-15 17:29:03 +12:00
use Utopia\Validator\Range ;
use Utopia\Validator\Text ;
use Utopia\Validator\URL ;
use Utopia\Validator\WhiteList ;
2021-07-27 13:00:36 +12:00
2021-08-17 11:21:00 +12:00
/**
* Create attribute of varying type
*
*
* @ return Document Newly created attribute document
2022-06-16 00:57:06 +12:00
* @ throws Exception
2021-08-17 11:21:00 +12:00
*/
2022-08-10 14:18:18 +12:00
function createAttribute ( string $databaseId , string $collectionId , Document $attribute , Response $response , Database $dbForProject , EventDatabase $database , Event $events ) : Document
2021-08-17 11:21:00 +12:00
{
2021-12-17 04:04:30 +13:00
$key = $attribute -> getAttribute ( 'key' );
2021-07-27 13:00:36 +12:00
$type = $attribute -> getAttribute ( 'type' , '' );
$size = $attribute -> getAttribute ( 'size' , 0 );
$required = $attribute -> getAttribute ( 'required' , true );
2022-05-24 02:54:50 +12:00
$signed = $attribute -> getAttribute ( 'signed' , true ); // integers are signed by default
2021-07-27 13:00:36 +12:00
$array = $attribute -> getAttribute ( 'array' , false );
2021-08-22 09:48:07 +12:00
$format = $attribute -> getAttribute ( 'format' , '' );
$formatOptions = $attribute -> getAttribute ( 'formatOptions' , []);
2022-05-24 02:54:50 +12:00
$filters = $attribute -> getAttribute ( 'filters' , []); // filters are hidden from the endpoint
2021-12-17 04:04:30 +13:00
$default = $attribute -> getAttribute ( 'default' );
2023-03-16 20:31:48 +13:00
$options = $attribute -> getAttribute ( 'options' , []);
2021-07-27 13:00:36 +12:00
2023-07-18 23:16:33 +12:00
$db = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2022-06-22 22:51:49 +12:00
if ( $db -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 22:51:49 +12:00
}
$collection = $dbForProject -> getDocument ( 'database_' . $db -> getInternalId (), $collectionId );
2021-07-27 13:00:36 +12:00
if ( $collection -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-07-27 13:00:36 +12:00
}
2021-08-22 09:48:07 +12:00
if ( ! empty ( $format )) {
if ( ! Structure :: hasFormat ( $format , $type )) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: ATTRIBUTE_FORMAT_UNSUPPORTED , " Format { $format } not available for { $type } attributes. " );
2021-07-28 06:19:37 +12:00
}
2021-07-27 13:00:36 +12:00
}
2021-12-28 01:45:23 +13:00
// Must throw here since dbForProject->createAttribute is performed by db worker
2022-09-30 22:27:19 +13:00
if ( $required && isset ( $default )) {
2022-08-14 18:56:12 +12:00
throw new Exception ( Exception :: ATTRIBUTE_DEFAULT_UNSUPPORTED , 'Cannot set default value for required attribute' );
2021-08-26 08:43:15 +12:00
}
2022-09-30 22:27:19 +13:00
if ( $array && isset ( $default )) {
2022-08-14 20:05:11 +12:00
throw new Exception ( Exception :: ATTRIBUTE_DEFAULT_UNSUPPORTED , 'Cannot set default value for array attributes' );
2021-10-27 09:14:25 +13:00
}
2023-03-13 21:22:01 +13:00
if ( $type === Database :: VAR_RELATIONSHIP ) {
2023-03-30 20:41:18 +13:00
$options [ 'side' ] = Database :: RELATION_SIDE_PARENT ;
2023-04-05 18:19:25 +12:00
$relatedCollection = $dbForProject -> getDocument ( 'database_' . $db -> getInternalId (), $options [ 'relatedCollection' ] ? ? '' );
2023-03-13 21:22:01 +13:00
if ( $relatedCollection -> isEmpty ()) {
2023-04-05 18:19:40 +12:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND , 'The related collection was not found.' );
2023-03-13 21:22:01 +13:00
}
}
2021-08-21 16:48:28 +12:00
try {
2021-10-06 02:57:57 +13:00
$attribute = new Document ([
2022-08-14 22:33:36 +12:00
'$id' => ID :: custom ( $db -> getInternalId () . '_' . $collection -> getInternalId () . '_' . $key ),
2021-12-17 04:04:30 +13:00
'key' => $key ,
2022-08-15 23:24:31 +12:00
'databaseInternalId' => $db -> getInternalId (),
'databaseId' => $db -> getId (),
'collectionInternalId' => $collection -> getInternalId (),
'collectionId' => $collectionId ,
2021-08-21 16:48:28 +12:00
'type' => $type ,
2021-10-05 13:23:15 +13:00
'status' => 'processing' , // processing, available, failed, deleting, stuck
2021-08-21 16:48:28 +12:00
'size' => $size ,
'required' => $required ,
'signed' => $signed ,
2021-08-28 05:12:16 +12:00
'default' => $default ,
2021-08-21 16:48:28 +12:00
'array' => $array ,
'format' => $format ,
2021-08-22 09:48:07 +12:00
'formatOptions' => $formatOptions ,
2021-11-02 13:47:07 +13:00
'filters' => $filters ,
2023-03-16 20:31:48 +13:00
'options' => $options ,
2021-10-06 02:57:57 +13:00
]);
2021-09-01 13:13:58 +12:00
2021-12-28 01:45:23 +13:00
$dbForProject -> checkAttribute ( $collection , $attribute );
$attribute = $dbForProject -> createDocument ( 'attributes' , $attribute );
2023-03-29 20:28:59 +13:00
} catch ( DuplicateException ) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: ATTRIBUTE_ALREADY_EXISTS );
2023-03-29 20:28:59 +13:00
} catch ( LimitException ) {
2022-08-14 19:02:41 +12:00
throw new Exception ( Exception :: ATTRIBUTE_LIMIT_EXCEEDED , 'Attribute limit exceeded' );
2023-04-05 18:48:57 +12:00
} catch ( \Exception $e ) {
$dbForProject -> deleteCachedDocument ( 'database_' . $db -> getInternalId (), $collectionId );
$dbForProject -> deleteCachedCollection ( 'database_' . $db -> getInternalId () . '_collection_' . $collection -> getInternalId ());
throw $e ;
2021-08-21 16:48:28 +12:00
}
2022-06-22 22:51:49 +12:00
$dbForProject -> deleteCachedDocument ( 'database_' . $db -> getInternalId (), $collectionId );
$dbForProject -> deleteCachedCollection ( 'database_' . $db -> getInternalId () . '_collection_' . $collection -> getInternalId ());
2021-07-27 13:00:36 +12:00
2023-03-29 20:28:59 +13:00
if ( $type === Database :: VAR_RELATIONSHIP && $options [ 'twoWay' ]) {
$twoWayKey = $options [ 'twoWayKey' ];
$options [ 'relatedCollection' ] = $collection -> getId ();
$options [ 'twoWayKey' ] = $key ;
2023-03-30 20:41:18 +13:00
$options [ 'side' ] = Database :: RELATION_SIDE_CHILD ;
2023-03-29 20:28:59 +13:00
try {
$twoWayAttribute = new Document ([
'$id' => ID :: custom ( $db -> getInternalId () . '_' . $relatedCollection -> getInternalId () . '_' . $twoWayKey ),
'key' => $twoWayKey ,
'databaseInternalId' => $db -> getInternalId (),
'databaseId' => $db -> getId (),
'collectionInternalId' => $relatedCollection -> getInternalId (),
'collectionId' => $relatedCollection -> getId (),
'type' => $type ,
2023-03-30 13:01:58 +13:00
'status' => 'processing' , // processing, available, failed, deleting, stuck
2023-03-29 20:28:59 +13:00
'size' => $size ,
'required' => $required ,
'signed' => $signed ,
'default' => $default ,
'array' => $array ,
'format' => $format ,
'formatOptions' => $formatOptions ,
'filters' => $filters ,
'options' => $options ,
]);
$dbForProject -> checkAttribute ( $relatedCollection , $twoWayAttribute );
$dbForProject -> createDocument ( 'attributes' , $twoWayAttribute );
} catch ( DuplicateException ) {
$dbForProject -> deleteDocument ( 'attributes' , $attribute -> getId ());
throw new Exception ( Exception :: ATTRIBUTE_ALREADY_EXISTS );
} catch ( LimitException ) {
$dbForProject -> deleteDocument ( 'attributes' , $attribute -> getId ());
throw new Exception ( Exception :: ATTRIBUTE_LIMIT_EXCEEDED , 'Attribute limit exceeded' );
2023-04-05 18:48:57 +12:00
} catch ( \Exception $e ) {
2023-04-06 02:57:37 +12:00
$dbForProject -> deleteCachedDocument ( 'database_' . $db -> getInternalId (), $relatedCollection -> getId ());
$dbForProject -> deleteCachedCollection ( 'database_' . $db -> getInternalId () . '_collection_' . $relatedCollection -> getInternalId ());
2023-04-05 18:48:57 +12:00
throw $e ;
2023-03-29 19:26:58 +13:00
}
2023-03-29 20:28:59 +13:00
$dbForProject -> deleteCachedDocument ( 'database_' . $db -> getInternalId (), $relatedCollection -> getId ());
$dbForProject -> deleteCachedCollection ( 'database_' . $db -> getInternalId () . '_collection_' . $relatedCollection -> getInternalId ());
2023-03-29 19:26:58 +13:00
}
2021-07-27 13:00:36 +12:00
$database
2022-04-14 00:39:31 +12:00
-> setType ( DATABASE_TYPE_CREATE_ATTRIBUTE )
2022-06-22 22:51:49 +12:00
-> setDatabase ( $db )
2022-04-14 00:39:31 +12:00
-> setCollection ( $collection )
2023-07-18 23:16:33 +12:00
-> setDocument ( $attribute );
2021-07-27 13:00:36 +12:00
2022-04-14 00:39:31 +12:00
$events
2022-06-22 22:51:49 +12:00
-> setContext ( 'collection' , $collection )
-> setContext ( 'database' , $db )
-> setParam ( 'databaseId' , $databaseId )
2022-04-14 00:39:31 +12:00
-> setParam ( 'collectionId' , $collection -> getId ())
2023-07-18 23:16:33 +12:00
-> setParam ( 'attributeId' , $attribute -> getId ());
2021-08-15 23:08:32 +12:00
2021-07-27 13:00:36 +12:00
$response -> setStatusCode ( Response :: STATUS_CODE_CREATED );
2021-08-17 11:21:00 +12:00
return $attribute ;
2022-05-31 05:41:25 +12:00
}
2021-07-27 13:00:36 +12:00
2023-02-27 01:33:18 +13:00
function updateAttribute (
string $databaseId ,
string $collectionId ,
string $key ,
Database $dbForProject ,
2023-02-27 04:44:22 +13:00
Event $events ,
2023-02-27 01:33:18 +13:00
string $type ,
string $filter = null ,
string | bool | int | float $default = null ,
bool $required = null ,
int | float $min = null ,
2023-02-27 04:44:22 +13:00
int | float $max = null ,
2023-03-23 04:49:08 +13:00
array $elements = null ,
array $options = []
2023-02-27 01:33:18 +13:00
) : Document {
2023-07-18 23:16:33 +12:00
$db = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2023-02-27 01:33:18 +13:00
if ( $db -> isEmpty ()) {
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
}
$collection = $dbForProject -> getDocument ( 'database_' . $db -> getInternalId (), $collectionId );
if ( $collection -> isEmpty ()) {
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
}
2023-03-31 18:38:37 +13:00
$attribute = $dbForProject -> getDocument ( 'attributes' , $db -> getInternalId () . '_' . $collection -> getInternalId () . '_' . $key );
2023-02-27 01:33:18 +13:00
if ( $attribute -> isEmpty ()) {
throw new Exception ( Exception :: ATTRIBUTE_NOT_FOUND );
}
if ( $attribute -> getAttribute ( 'status' ) !== 'available' ) {
throw new Exception ( Exception :: ATTRIBUTE_NOT_AVAILABLE );
}
2023-02-27 20:45:11 +13:00
if ( $attribute -> getAttribute (( 'type' ) !== $type )) {
throw new Exception ( Exception :: ATTRIBUTE_TYPE_INVALID );
}
if ( $attribute -> getAttribute ( 'type' ) === Database :: VAR_STRING && $attribute -> getAttribute (( 'filter' ) !== $filter )) {
2023-02-27 01:33:18 +13:00
throw new Exception ( Exception :: ATTRIBUTE_TYPE_INVALID );
}
2023-02-27 04:44:22 +13:00
if ( $required && isset ( $default )) {
throw new Exception ( Exception :: ATTRIBUTE_DEFAULT_UNSUPPORTED , 'Cannot set default value for required attribute' );
2023-02-27 01:33:18 +13:00
}
2023-02-27 04:44:22 +13:00
if ( $attribute -> getAttribute ( 'array' , false ) && isset ( $default )) {
throw new Exception ( Exception :: ATTRIBUTE_DEFAULT_UNSUPPORTED , 'Cannot set default value for array attributes' );
2023-02-27 01:33:18 +13:00
}
2023-02-27 04:44:22 +13:00
$collectionId = 'database_' . $db -> getInternalId () . '_collection_' . $collection -> getInternalId ();
2023-03-10 23:06:10 +13:00
$attribute
-> setAttribute ( 'default' , $default )
-> setAttribute ( 'required' , $required );
2023-02-27 04:44:22 +13:00
$formatOptions = $attribute -> getAttribute ( 'formatOptions' );
switch ( $attribute -> getAttribute ( 'format' )) {
case APP_DATABASE_ATTRIBUTE_INT_RANGE :
case APP_DATABASE_ATTRIBUTE_FLOAT_RANGE :
if ( $min === $formatOptions [ 'min' ] && $max === $formatOptions [ 'max' ]) {
break ;
}
if ( $min > $max ) {
throw new Exception ( Exception :: ATTRIBUTE_VALUE_INVALID , 'Minimum value must be lesser than maximum value' );
}
2023-03-20 22:13:23 +13:00
if ( $attribute -> getAttribute ( 'format' ) === APP_DATABASE_ATTRIBUTE_INT_RANGE ) {
$validator = new Range ( $min , $max , Database :: VAR_INTEGER );
} else {
$validator = new Range ( $min , $max , Database :: VAR_FLOAT );
2023-02-27 04:44:22 +13:00
2023-03-20 22:13:23 +13:00
if ( ! is_null ( $default )) {
$default = \floatval ( $default );
}
}
2023-02-27 04:44:22 +13:00
if ( ! is_null ( $default ) && ! $validator -> isValid ( $default )) {
throw new Exception ( Exception :: ATTRIBUTE_VALUE_INVALID , $validator -> getDescription ());
}
$options = [
'min' => $min ,
'max' => $max
];
$attribute -> setAttribute ( 'formatOptions' , $options );
break ;
case APP_DATABASE_ATTRIBUTE_ENUM :
if ( empty ( $elements )) {
2023-02-27 20:45:11 +13:00
throw new Exception ( Exception :: ATTRIBUTE_VALUE_INVALID , 'Enum elements must not be empty' );
2023-02-27 04:44:22 +13:00
}
foreach ( $elements as $element ) {
2023-03-20 22:13:23 +13:00
if ( \strlen ( $element ) === 0 ) {
2023-02-27 04:44:22 +13:00
throw new Exception ( Exception :: ATTRIBUTE_VALUE_INVALID , 'Each enum element must not be empty' );
}
}
if ( ! is_null ( $default ) && ! in_array ( $default , $elements )) {
throw new Exception ( Exception :: ATTRIBUTE_VALUE_INVALID , 'Default value not found in elements' );
}
2023-03-10 23:06:10 +13:00
2023-02-27 04:44:22 +13:00
$options = [
'elements' => $elements
];
2023-03-20 22:13:23 +13:00
2023-02-27 04:44:22 +13:00
$attribute -> setAttribute ( 'formatOptions' , $options );
break ;
}
2023-03-23 04:49:08 +13:00
if ( $type === Database :: VAR_RELATIONSHIP ) {
2023-07-08 06:20:06 +12:00
$primaryDocumentOptions = \array_merge ( $attribute -> getAttribute ( 'options' , []), $options );
$attribute -> setAttribute ( 'options' , $primaryDocumentOptions );
2023-03-23 04:49:08 +13:00
$dbForProject -> updateRelationship (
collection : $collectionId ,
2023-04-05 20:13:51 +12:00
id : $key ,
2023-07-08 06:20:06 +12:00
onDelete : $primaryDocumentOptions [ 'onDelete' ],
2023-03-23 04:49:08 +13:00
);
2023-03-31 18:38:37 +13:00
2023-07-08 06:20:06 +12:00
if ( $primaryDocumentOptions [ 'twoWay' ]) {
$relatedCollection = $dbForProject -> getDocument ( 'database_' . $db -> getInternalId (), $primaryDocumentOptions [ 'relatedCollection' ]);
$relatedAttribute = $dbForProject -> getDocument ( 'attributes' , $db -> getInternalId () . '_' . $relatedCollection -> getInternalId () . '_' . $primaryDocumentOptions [ 'twoWayKey' ]);
2023-03-31 18:38:37 +13:00
$relatedOptions = \array_merge ( $relatedAttribute -> getAttribute ( 'options' ), $options );
$relatedAttribute -> setAttribute ( 'options' , $relatedOptions );
2023-07-08 06:20:06 +12:00
$dbForProject -> updateDocument ( 'attributes' , $db -> getInternalId () . '_' . $relatedCollection -> getInternalId () . '_' . $primaryDocumentOptions [ 'twoWayKey' ], $relatedAttribute );
2023-03-31 18:38:37 +13:00
$dbForProject -> deleteCachedDocument ( 'database_' . $db -> getInternalId (), $relatedCollection -> getId ());
}
2023-03-23 04:49:08 +13:00
} else {
$dbForProject -> updateAttribute (
collection : $collectionId ,
id : $key ,
required : $required ,
default : $default ,
formatOptions : $options ? ? null
);
}
2023-03-10 23:06:10 +13:00
$dbForProject -> updateDocument ( 'attributes' , $db -> getInternalId () . '_' . $collection -> getInternalId () . '_' . $key , $attribute );
2023-04-03 15:43:14 +12:00
$dbForProject -> deleteCachedDocument ( 'database_' . $db -> getInternalId (), $collection -> getId ());
2023-02-27 01:33:18 +13:00
2023-02-27 04:44:22 +13:00
$events
-> setContext ( 'collection' , $collection )
-> setContext ( 'database' , $db )
-> setParam ( 'databaseId' , $databaseId )
-> setParam ( 'collectionId' , $collection -> getId ())
2023-03-10 23:06:10 +13:00
-> setParam ( 'attributeId' , $attribute -> getId ());
2023-02-27 04:44:22 +13:00
2023-02-27 01:33:18 +13:00
return $attribute ;
}
2022-06-22 22:51:49 +12:00
App :: post ( '/v1/databases' )
-> desc ( 'Create Database' )
-> groups ([ 'api' , 'database' ])
-> label ( 'event' , 'databases.[databaseId].create' )
-> label ( 'scope' , 'databases.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'database.create' )
2022-08-09 02:32:54 +12:00
-> label ( 'audits.resource' , 'database/{response.$id}' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'databases.{scope}.requests.create' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'databases' )
-> label ( 'sdk.method' , 'create' )
2022-06-23 04:28:09 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/create.md' ) // create this file later
2022-06-22 22:51:49 +12: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
2023-01-21 11:22:16 +13:00
-> param ( 'databaseId' , '' , new CustomId (), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. 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.' )
2023-05-19 01:25:22 +12:00
-> param ( 'name' , '' , new Text ( 128 ), 'Database name. Max length: 128 chars.' )
2023-05-19 19:24:07 +12:00
-> param ( 'enabled' , true , new Boolean (), 'Is database enabled?' , true )
2022-06-22 22:51:49 +12:00
-> inject ( 'response' )
-> inject ( 'dbForProject' )
-> inject ( 'events' )
2023-05-19 01:25:22 +12:00
-> action ( function ( string $databaseId , string $name , bool $enabled , Response $response , Database $dbForProject , Event $events ) {
2022-06-22 22:51:49 +12:00
2022-08-15 02:22:38 +12:00
$databaseId = $databaseId == 'unique()' ? ID :: unique () : $databaseId ;
2022-06-22 22:51:49 +12:00
try {
$dbForProject -> createDocument ( 'databases' , new Document ([
2022-08-15 02:22:38 +12:00
'$id' => $databaseId ,
2022-06-22 22:51:49 +12:00
'name' => $name ,
2023-05-19 01:25:22 +12:00
'enabled' => $enabled ,
2022-06-22 22:51:49 +12:00
'search' => implode ( ' ' , [ $databaseId , $name ]),
]));
$database = $dbForProject -> getDocument ( 'databases' , $databaseId );
$collections = Config :: getParam ( 'collections' , [])[ 'collections' ] ? ? [];
if ( empty ( $collections )) {
2022-08-14 18:56:12 +12:00
throw new Exception ( Exception :: GENERAL_SERVER_ERROR , 'The "collections" collection is not configured.' );
2022-06-22 22:51:49 +12:00
}
$attributes = [];
$indexes = [];
foreach ( $collections [ 'attributes' ] as $attribute ) {
$attributes [] = new Document ([
2022-08-15 23:24:31 +12:00
'$id' => $attribute [ '$id' ],
2022-06-22 22:51:49 +12: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 23:24:31 +12:00
'$id' => $index [ '$id' ],
2022-06-22 22:51:49 +12:00
'type' => $index [ 'type' ],
'attributes' => $index [ 'attributes' ],
'lengths' => $index [ 'lengths' ],
'orders' => $index [ 'orders' ],
]);
}
$dbForProject -> createCollection ( 'database_' . $database -> getInternalId (), $attributes , $indexes );
2023-06-15 17:29:03 +12:00
} catch ( DuplicateException ) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DATABASE_ALREADY_EXISTS );
2022-06-22 22:51:49 +12:00
}
$events -> setParam ( 'databaseId' , $database -> getId ());
2022-09-07 23:02:36 +12:00
$response
-> setStatusCode ( Response :: STATUS_CODE_CREATED )
-> dynamic ( $database , Response :: MODEL_DATABASE );
2022-06-22 22:51:49 +12:00
});
App :: get ( '/v1/databases' )
-> desc ( 'List Databases' )
-> groups ([ 'api' , 'database' ])
-> label ( 'scope' , 'databases.read' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'databases.{scope}.requests.read' )
2022-06-22 22:51:49 +12: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 19:06:21 +12:00
-> label ( 'sdk.response.model' , Response :: MODEL_DATABASE_LIST )
2023-03-30 08:38:39 +13: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/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode ( ', ' , Databases :: ALLOWED_ATTRIBUTES ), true )
2022-06-22 22:51:49 +12: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 21:59:28 +12:00
-> action ( function ( array $queries , string $search , Response $response , Database $dbForProject ) {
2022-06-22 22:51:49 +12:00
2022-08-23 21:40:17 +12:00
$queries = Query :: parseQueries ( $queries );
2022-08-12 11:53:52 +12:00
if ( ! empty ( $search )) {
2022-08-23 21:40:17 +12:00
$queries [] = Query :: search ( 'search' , $search );
2022-08-12 11:53:52 +12:00
}
2022-08-23 21:40:17 +12:00
// Get cursor document if there was a cursor query
2023-05-01 21:18:50 +12:00
$cursor = Query :: getByType ( $queries , [ Query :: TYPE_CURSORAFTER , Query :: TYPE_CURSORBEFORE ]);
2022-08-31 11:31:43 +12:00
$cursor = reset ( $cursor );
2022-08-30 23:55:23 +12:00
if ( $cursor ) {
2022-08-23 21:40:17 +12:00
$databaseId = $cursor -> getValue ();
$cursorDocument = $dbForProject -> getDocument ( 'databases' , $databaseId );
2022-06-22 22:51:49 +12:00
if ( $cursorDocument -> isEmpty ()) {
2022-08-23 21:40:17 +12:00
throw new Exception ( Exception :: GENERAL_CURSOR_NOT_FOUND , " Database ' { $databaseId } ' for the 'cursor' value not found. " );
2022-06-22 22:51:49 +12:00
}
2022-08-23 21:40:17 +12:00
$cursor -> setValue ( $cursorDocument );
2022-06-22 22:51:49 +12:00
}
2022-08-23 21:40:17 +12:00
$filterQueries = Query :: groupByType ( $queries )[ 'filters' ];
2022-06-22 22:51:49 +12:00
$response -> dynamic ( new Document ([
2022-08-23 21:40:17 +12:00
'databases' => $dbForProject -> find ( 'databases' , $queries ),
2022-08-12 11:53:52 +12:00
'total' => $dbForProject -> count ( 'databases' , $filterQueries , APP_LIMIT_COUNT ),
2022-06-22 22:51:49 +12:00
]), Response :: MODEL_DATABASE_LIST );
});
App :: get ( '/v1/databases/:databaseId' )
-> desc ( 'Get Database' )
-> groups ([ 'api' , 'database' ])
-> label ( 'scope' , 'databases.read' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'databases.{scope}.requests.read' )
2022-06-22 22:51:49 +12: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 19:14:37 +12:00
-> label ( 'sdk.response.model' , Response :: MODEL_DATABASE )
2022-06-22 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
-> inject ( 'response' )
-> inject ( 'dbForProject' )
2022-08-10 14:18:18 +12:00
-> action ( function ( string $databaseId , Response $response , Database $dbForProject ) {
2022-06-22 22:51:49 +12:00
2023-05-24 22:09:08 +12:00
$database = $dbForProject -> getDocument ( 'databases' , $databaseId );
2022-06-22 22:51:49 +12:00
if ( $database -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 22:51:49 +12:00
}
$response -> dynamic ( $database , Response :: MODEL_DATABASE );
});
App :: get ( '/v1/databases/:databaseId/logs' )
2022-08-20 02:14:39 +12:00
-> desc ( 'List Database Logs' )
2022-06-22 22:51:49 +12:00
-> groups ([ 'api' , 'database' ])
2022-08-20 02:14:39 +12:00
-> label ( 'scope' , 'databases.read' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_ADMIN ])
-> label ( 'sdk.namespace' , 'databases' )
-> label ( 'sdk.method' , 'listLogs' )
2022-08-20 02:14:39 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/get-logs.md' )
2022-06-22 22:51:49 +12: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.' )
2023-05-17 00:56:20 +12: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/queries). Only supported methods are limit and offset' , true )
2022-06-22 22:51:49 +12:00
-> inject ( 'response' )
-> inject ( 'dbForProject' )
-> inject ( 'locale' )
-> inject ( 'geodb' )
2022-08-24 01:03:38 +12:00
-> action ( function ( string $databaseId , array $queries , Response $response , Database $dbForProject , Locale $locale , Reader $geodb ) {
2022-06-22 22:51:49 +12:00
$database = $dbForProject -> getDocument ( 'databases' , $databaseId );
if ( $database -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 22:51:49 +12:00
}
2022-08-24 01:03:38 +12:00
$queries = Query :: parseQueries ( $queries );
$grouped = Query :: groupByType ( $queries );
2022-08-30 23:55:23 +12:00
$limit = $grouped [ 'limit' ] ? ? APP_LIMIT_COUNT ;
2022-08-24 01:03:38 +12:00
$offset = $grouped [ 'offset' ] ? ? 0 ;
2022-06-22 22:51:49 +12:00
$audit = new Audit ( $dbForProject );
$resource = 'database/' . $databaseId ;
$logs = $audit -> getLogsByResource ( $resource , $limit , $offset );
2022-08-24 01:10:27 +12:00
2022-08-24 01:03:38 +12:00
$output = [];
2022-06-22 22:51:49 +12: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 22:33:36 +12:00
'userId' => ID :: custom ( $log [ 'userId' ]),
2022-06-22 22:51:49 +12: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' )
2022-07-08 17:43:20 +12:00
-> groups ([ 'api' , 'database' , 'schema' ])
2022-06-22 22:51:49 +12:00
-> label ( 'scope' , 'databases.write' )
-> label ( 'event' , 'databases.[databaseId].update' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'database.update' )
2022-08-09 02:32:54 +12:00
-> label ( 'audits.resource' , 'database/{response.$id}' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'databases.{scope}.requests.update' )
2022-06-22 22:51:49 +12: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 19:14:37 +12:00
-> label ( 'sdk.response.model' , Response :: MODEL_DATABASE )
2022-06-22 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-07-08 17:43:20 +12:00
-> param ( 'name' , null , new Text ( 128 ), 'Database name. Max length: 128 chars.' )
2023-05-19 19:24:07 +12:00
-> param ( 'enabled' , true , new Boolean (), 'Is database enabled?' , true )
2022-06-23 01:30:35 +12:00
-> inject ( 'response' )
2022-06-22 22:51:49 +12:00
-> inject ( 'dbForProject' )
-> inject ( 'events' )
2023-05-19 01:25:22 +12:00
-> action ( function ( string $databaseId , string $name , bool $enabled , Response $response , Database $dbForProject , Event $events ) {
2022-06-22 22:51:49 +12:00
2023-05-24 22:09:08 +12:00
$database = $dbForProject -> getDocument ( 'databases' , $databaseId );
2022-06-22 22:51:49 +12:00
if ( $database -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 22:51:49 +12:00
}
try {
$database = $dbForProject -> updateDocument ( 'databases' , $databaseId , $database
-> setAttribute ( 'name' , $name )
2023-05-19 01:25:22 +12:00
-> setAttribute ( 'enabled' , $enabled )
2022-06-22 22:51:49 +12:00
-> setAttribute ( 'search' , implode ( ' ' , [ $databaseId , $name ])));
2023-06-15 17:29:03 +12:00
} catch ( AuthorizationException ) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: USER_UNAUTHORIZED );
2022-06-22 22:51:49 +12:00
} catch ( StructureException $exception ) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DOCUMENT_INVALID_STRUCTURE , 'Bad structure. ' . $exception -> getMessage ());
2022-06-22 22:51:49 +12:00
}
$events -> setParam ( 'databaseId' , $database -> getId ());
$response -> dynamic ( $database , Response :: MODEL_DATABASE );
});
App :: delete ( '/v1/databases/:databaseId' )
-> desc ( 'Delete Database' )
2022-07-08 17:43:20 +12:00
-> groups ([ 'api' , 'database' , 'schema' ])
2022-06-22 22:51:49 +12:00
-> label ( 'scope' , 'databases.write' )
-> label ( 'event' , 'databases.[databaseId].delete' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'database.delete' )
2022-08-09 02:32:54 +12:00
-> label ( 'audits.resource' , 'database/{request.databaseId}' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'databases.{scope}.requests.delete' )
2022-06-22 22:51:49 +12: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 15:14:28 +12:00
-> action ( function ( string $databaseId , Response $response , Database $dbForProject , Event $events , Delete $deletes ) {
2022-06-22 22:51:49 +12:00
$database = $dbForProject -> getDocument ( 'databases' , $databaseId );
if ( $database -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 22:51:49 +12:00
}
if ( ! $dbForProject -> deleteDocument ( 'databases' , $databaseId )) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: GENERAL_SERVER_ERROR , 'Failed to remove collection from DB' );
2022-06-22 22:51:49 +12:00
}
2023-04-03 15:51:44 +12:00
$dbForProject -> deleteCachedDocument ( 'databases' , $database -> getId ());
$dbForProject -> deleteCachedCollection ( 'databases_' . $database -> getInternalId ());
2022-06-22 22:51:49 +12:00
$deletes
-> setType ( DELETE_TYPE_DOCUMENT )
2023-07-18 23:16:33 +12:00
-> setDocument ( $database );
2022-06-22 22:51:49 +12:00
$events
-> setParam ( 'databaseId' , $database -> getId ())
2023-07-18 23:16:33 +12:00
-> setPayload ( $response -> output ( $database , Response :: MODEL_DATABASE ));
2022-06-22 22:51:49 +12:00
$response -> noContent ();
});
App :: post ( '/v1/databases/:databaseId/collections' )
2022-06-23 20:50:11 +12:00
-> alias ( '/v1/database/collections' , [ 'databaseId' => 'default' ])
2019-05-09 18:54:39 +12:00
-> desc ( 'Create Collection' )
2020-06-26 06:32:12 +12:00
-> groups ([ 'api' , 'database' ])
2022-06-22 22:51:49 +12:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].create' )
2019-06-09 01:13:19 +12:00
-> label ( 'scope' , 'collections.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'collection.create' )
2022-08-09 03:44:11 +12:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{response.$id}' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.create' )
2022-08-21 14:10:21 +12:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.namespace' , 'databases' )
2019-05-09 18:54:39 +12:00
-> label ( 'sdk.method' , 'createCollection' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/create-collection.md' )
2020-11-12 10:02:24 +13: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 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2023-01-21 11:22:16 +13:00
-> param ( 'collectionId' , '' , new CustomId (), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. 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 20:09:24 +12:00
-> param ( 'name' , '' , new Text ( 128 ), 'Collection name. Max length: 128 chars.' )
2022-12-21 10:43:55 +13: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 12:44:33 +12: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 )
2023-05-19 01:25:22 +12:00
-> param ( 'enabled' , true , new Boolean (), 'Is collection enabled?' , true )
2020-12-27 04:05:04 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2023-05-25 00:28:40 +12:00
-> inject ( 'mode' )
2022-04-14 00:39:31 +12:00
-> inject ( 'events' )
2023-05-25 04:54:57 +12:00
-> action ( function ( string $databaseId , string $collectionId , string $name , ? array $permissions , bool $documentSecurity , bool $enabled , Response $response , Database $dbForProject , string $mode , Event $events ) {
2022-06-22 22:51:49 +12:00
2023-05-24 22:09:08 +12:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2022-06-22 22:51:49 +12:00
2023-05-25 00:28:40 +12:00
if ( $database -> isEmpty () || ( ! $database -> getAttribute ( 'enabled' ) && $mode !== APP_MODE_ADMIN )) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 22:51:49 +12:00
}
2021-06-16 01:38:24 +12:00
2022-08-15 02:22:38 +12:00
$collectionId = $collectionId == 'unique()' ? ID :: unique () : $collectionId ;
2021-07-06 08:27:20 +12:00
2022-08-23 13:42:25 +12:00
// Map aggregate permissions into the multiple permissions they represent.
$permissions = Permission :: aggregate ( $permissions );
2022-08-16 20:33:06 +12:00
2021-08-17 05:28:33 +12:00
try {
2022-06-22 22:51:49 +12:00
$dbForProject -> createDocument ( 'database_' . $database -> getInternalId (), new Document ([
2022-08-15 02:22:38 +12:00
'$id' => $collectionId ,
2022-06-22 22:51:49 +12:00
'databaseInternalId' => $database -> getInternalId (),
'databaseId' => $databaseId ,
2022-08-19 16:49:34 +12:00
'$permissions' => $permissions ? ? [],
2022-08-04 16:20:11 +12:00
'documentSecurity' => $documentSecurity ,
2023-05-19 01:25:22 +12:00
'enabled' => $enabled ,
2021-08-17 05:28:33 +12:00
'name' => $name ,
'search' => implode ( ' ' , [ $collectionId , $name ]),
]));
2022-06-22 22:51:49 +12:00
$collection = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId );
2022-01-24 21:20:02 +13:00
2023-04-18 12:40:36 +12:00
$dbForProject -> createCollection ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (), permissions : $permissions ? ? [], documentSecurity : $documentSecurity );
2022-08-24 20:50:05 +12:00
} catch ( DuplicateException ) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: COLLECTION_ALREADY_EXISTS );
2022-08-24 20:50:05 +12:00
} catch ( LimitException ) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: COLLECTION_LIMIT_EXCEEDED );
2021-08-17 05:28:33 +12:00
}
2019-05-09 18:54:39 +12:00
2022-06-22 22:51:49 +12:00
$events
-> setContext ( 'database' , $database )
-> setParam ( 'databaseId' , $databaseId )
-> setParam ( 'collectionId' , $collection -> getId ());
2022-09-07 23:11:10 +12:00
$response
-> setStatusCode ( Response :: STATUS_CODE_CREATED )
-> dynamic ( $collection , Response :: MODEL_COLLECTION );
2020-12-27 04:05:04 +13:00
});
2019-05-09 18:54:39 +12:00
2022-06-22 22:51:49 +12:00
App :: get ( '/v1/databases/:databaseId/collections' )
2022-06-23 20:50:11 +12:00
-> alias ( '/v1/database/collections' , [ 'databaseId' => 'default' ])
2020-02-01 11:34:07 +13:00
-> desc ( 'List Collections' )
2020-06-26 06:32:12 +12:00
-> groups ([ 'api' , 'database' ])
2020-02-01 11:34:07 +13:00
-> label ( 'scope' , 'collections.read' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.read' )
2022-08-21 14:10:21 +12:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.namespace' , 'databases' )
2020-02-01 11:34:07 +13:00
-> label ( 'sdk.method' , 'listCollections' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/list-collections.md' )
2020-11-12 10:02:24 +13: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 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2023-03-30 08:38:39 +13: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/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode ( ', ' , Collections :: ALLOWED_ATTRIBUTES ), true )
2021-07-06 07:19:18 +12:00
-> param ( 'search' , '' , new Text ( 256 ), 'Search term to filter your list results. Max length: 256 chars.' , true )
2020-12-27 04:05:04 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2023-05-26 23:38:09 +12:00
-> inject ( 'mode' )
-> action ( function ( string $databaseId , array $queries , string $search , Response $response , Database $dbForProject , string $mode ) {
2022-06-22 22:51:49 +12:00
2023-05-24 22:09:08 +12:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2022-06-22 22:51:49 +12:00
2023-05-26 23:38:09 +12:00
if ( $database -> isEmpty () || ( ! $database -> getAttribute ( 'enabled' ) && $mode !== APP_MODE_ADMIN )) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 22:51:49 +12:00
}
2020-06-30 09:43:34 +12:00
2022-08-24 00:30:28 +12:00
$queries = Query :: parseQueries ( $queries );
2021-08-17 05:28:33 +12:00
2022-08-12 11:53:52 +12:00
if ( ! empty ( $search )) {
2022-08-24 00:30:28 +12:00
$queries [] = Query :: search ( 'search' , $search );
2021-08-17 05:28:33 +12:00
}
2020-06-30 09:43:34 +12:00
2022-08-24 00:30:28 +12:00
// Get cursor document if there was a cursor query
2023-05-01 21:18:50 +12:00
$cursor = Query :: getByType ( $queries , [ Query :: TYPE_CURSORAFTER , Query :: TYPE_CURSORBEFORE ]);
2022-08-31 11:31:43 +12:00
$cursor = reset ( $cursor );
2022-08-30 23:55:23 +12:00
if ( $cursor ) {
2022-08-24 00:30:28 +12:00
/** @var Query $cursor */
$collectionId = $cursor -> getValue ();
$cursorDocument = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId );
2021-08-07 00:35:57 +12:00
2022-08-12 11:53:52 +12:00
if ( $cursorDocument -> isEmpty ()) {
2022-08-24 00:30:28 +12:00
throw new Exception ( Exception :: GENERAL_CURSOR_NOT_FOUND , " Collection ' { $collectionId } ' for the 'cursor' value not found. " );
2022-08-12 11:53:52 +12:00
}
2022-08-24 00:30:28 +12:00
$cursor -> setValue ( $cursorDocument );
2021-08-07 00:35:57 +12:00
}
2022-08-24 00:30:28 +12:00
$filterQueries = Query :: groupByType ( $queries )[ 'filters' ];
2021-07-26 02:47:18 +12:00
$response -> dynamic ( new Document ([
2022-08-24 00:30:28 +12:00
'collections' => $dbForProject -> find ( 'database_' . $database -> getInternalId (), $queries ),
2022-08-12 11:53:52 +12:00
'total' => $dbForProject -> count ( 'database_' . $database -> getInternalId (), $filterQueries , APP_LIMIT_COUNT ),
2020-10-31 08:53:27 +13:00
]), Response :: MODEL_COLLECTION_LIST );
2020-12-27 04:05:04 +13:00
});
2020-02-01 11:34:07 +13:00
2022-06-22 22:51:49 +12:00
App :: get ( '/v1/databases/:databaseId/collections/:collectionId' )
2022-06-23 20:50:11 +12:00
-> alias ( '/v1/database/collections/:collectionId' , [ 'databaseId' => 'default' ])
2020-02-01 11:34:07 +13:00
-> desc ( 'Get Collection' )
2020-06-26 06:32:12 +12:00
-> groups ([ 'api' , 'database' ])
2020-02-01 11:34:07 +13:00
-> label ( 'scope' , 'collections.read' )
2022-08-15 17:50:36 +12:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.read' )
2022-08-21 14:10:21 +12:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.namespace' , 'databases' )
2020-02-01 11:34:07 +13:00
-> label ( 'sdk.method' , 'getCollection' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/get-collection.md' )
2020-11-12 10:02:24 +13: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 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2021-12-11 01:27:11 +13:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID.' )
2020-12-27 04:05:04 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2023-05-26 23:38:09 +12:00
-> inject ( 'mode' )
-> action ( function ( string $databaseId , string $collectionId , Response $response , Database $dbForProject , string $mode ) {
2020-02-01 11:34:07 +13:00
2023-05-24 22:09:08 +12:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2021-10-28 08:57:20 +13:00
2023-05-26 23:38:09 +12:00
if ( $database -> isEmpty () || ( ! $database -> getAttribute ( 'enabled' ) && $mode !== APP_MODE_ADMIN )) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2021-08-20 22:04:57 +12:00
}
2022-08-08 22:58:28 +12:00
2022-06-22 22:51:49 +12:00
$collection = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId );
2021-08-20 23:38:57 +12:00
if ( $collection -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-08-20 23:38:57 +12:00
}
2021-12-29 04:48:36 +13:00
2022-06-22 22:51:49 +12:00
$response -> dynamic ( $collection , Response :: MODEL_COLLECTION );
2021-08-20 23:38:57 +12:00
});
2021-08-20 20:24:45 +12:00
2022-06-22 22:51:49 +12:00
App :: get ( '/v1/databases/:databaseId/collections/:collectionId/logs' )
2022-06-23 20:50:11 +12:00
-> alias ( '/v1/database/collections/:collectionId/logs' , [ 'databaseId' => 'default' ])
2021-08-14 22:13:24 +12:00
-> desc ( 'List Collection Logs' )
2021-08-11 06:03:32 +12:00
-> groups ([ 'api' , 'database' ])
-> label ( 'scope' , 'collections.read' )
2022-08-21 14:10:21 +12:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.read' )
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-08-11 06:03:32 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_ADMIN ])
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.namespace' , 'databases' )
2021-08-14 22:13:24 +12:00
-> label ( 'sdk.method' , 'listCollectionLogs' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/get-collection-logs.md' )
2021-08-11 06:03:32 +12: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 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2021-12-11 01:27:11 +13:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID.' )
2023-05-17 00:56:20 +12: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/queries). Only supported methods are limit and offset' , true )
2021-08-11 06:03:32 +12:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2021-08-11 06:03:32 +12:00
-> inject ( 'locale' )
-> inject ( 'geodb' )
2022-08-24 01:03:38 +12:00
-> action ( function ( string $databaseId , string $collectionId , array $queries , Response $response , Database $dbForProject , Locale $locale , Reader $geodb ) {
2021-08-11 06:03:32 +12:00
2023-05-24 22:09:08 +12:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2022-06-22 22:51:49 +12:00
if ( $database -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 22:51:49 +12:00
}
$collectionDocument = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId );
$collection = $dbForProject -> getCollection ( 'database_' . $database -> getInternalId () . '_collection_' . $collectionDocument -> getInternalId ());
2021-08-11 06:03:32 +12:00
if ( $collection -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-08-11 06:03:32 +12:00
}
2022-08-24 01:03:38 +12:00
$queries = Query :: parseQueries ( $queries );
$grouped = Query :: groupByType ( $queries );
2022-08-30 23:55:23 +12:00
$limit = $grouped [ 'limit' ] ? ? APP_LIMIT_COUNT ;
2022-08-24 01:03:38 +12:00
$offset = $grouped [ 'offset' ] ? ? 0 ;
2021-12-28 01:45:23 +13:00
$audit = new Audit ( $dbForProject );
2022-06-22 22:51:49 +12:00
$resource = 'database/' . $databaseId . '/collection/' . $collectionId ;
2021-11-17 03:54:29 +13:00
$logs = $audit -> getLogsByResource ( $resource , $limit , $offset );
2021-08-11 06:03:32 +12:00
$output = [];
foreach ( $logs as $i => & $log ) {
$log [ 'userAgent' ] = ( ! empty ( $log [ 'userAgent' ])) ? $log [ 'userAgent' ] : 'UNKNOWN' ;
2021-12-13 06:58:17 +13: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-11 06:03:32 +12:00
2021-12-13 06:58:17 +13:00
$os = $detector -> getOS ();
$client = $detector -> getClient ();
$device = $detector -> getDevice ();
2021-08-11 06:03:32 +12:00
$output [ $i ] = new Document ([
'event' => $log [ 'event' ],
2021-08-13 23:19:16 +12:00
'userId' => $log [ 'userId' ],
2021-08-14 22:13:24 +12:00
'userEmail' => $log [ 'data' ][ 'userEmail' ] ? ? null ,
'userName' => $log [ 'data' ][ 'userName' ] ? ? null ,
'mode' => $log [ 'data' ][ 'mode' ] ? ? null ,
2021-08-11 06:03:32 +12:00
'ip' => $log [ 'ip' ],
'time' => $log [ 'time' ],
2021-12-13 06:58:17 +13: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-13 06:59:12 +13:00
'deviceModel' => $device [ 'deviceModel' ]
2021-08-11 06:03:32 +12:00
]);
$record = $geodb -> get ( $log [ 'ip' ]);
if ( $record ) {
2022-05-24 02:54:50 +12: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-11 06:03:32 +12:00
} else {
$output [ $i ][ 'countryCode' ] = '--' ;
$output [ $i ][ 'countryName' ] = $locale -> getText ( 'locale.country.unknown' );
}
}
2021-11-17 03:54:29 +13:00
$response -> dynamic ( new Document ([
2022-02-27 22:57:09 +13:00
'total' => $audit -> countLogsByResource ( $resource ),
2021-11-17 03:54:29 +13:00
'logs' => $output ,
]), Response :: MODEL_LOG_LIST );
2021-08-11 06:03:32 +12:00
});
2022-06-22 22:51:49 +12:00
App :: put ( '/v1/databases/:databaseId/collections/:collectionId' )
2022-06-23 20:50:11 +12:00
-> alias ( '/v1/database/collections/:collectionId' , [ 'databaseId' => 'default' ])
2019-06-09 23:44:58 +12:00
-> desc ( 'Update Collection' )
2022-07-08 17:43:20 +12:00
-> groups ([ 'api' , 'database' , 'schema' ])
2019-06-09 01:13:19 +12:00
-> label ( 'scope' , 'collections.write' )
2022-06-22 22:51:49 +12:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].update' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'collection.update' )
2022-08-09 00:19:41 +12:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
2022-08-21 14:10:21 +12:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.namespace' , 'databases' )
2019-06-09 20:51:10 +12:00
-> label ( 'sdk.method' , 'updateCollection' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/update-collection.md' )
2020-11-12 10:02:24 +13: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 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2021-12-11 01:27:11 +13:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID.' )
2021-07-29 20:09:24 +12:00
-> param ( 'name' , null , new Text ( 128 ), 'Collection name. Max length: 128 chars.' )
2022-12-21 10:43:55 +13:00
-> param ( 'permissions' , null , new Permissions ( APP_LIMIT_ARRAY_PARAMS_SIZE ), 'An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](/docs/permissions).' , true )
2022-09-02 15:39:54 +12: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-14 01:42:04 +13:00
-> param ( 'enabled' , true , new Boolean (), 'Is collection enabled?' , true )
2020-12-27 04:05:04 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2023-05-26 23:38:09 +12:00
-> inject ( 'mode' )
2022-04-14 00:39:31 +12:00
-> inject ( 'events' )
2023-05-26 23:38:09 +12:00
-> action ( function ( string $databaseId , string $collectionId , string $name , ? array $permissions , bool $documentSecurity , bool $enabled , Response $response , Database $dbForProject , string $mode , Event $events ) {
2019-05-09 18:54:39 +12:00
2023-05-24 22:09:08 +12:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2022-06-22 22:51:49 +12:00
2023-05-26 23:38:09 +12:00
if ( $database -> isEmpty () || ( ! $database -> getAttribute ( 'enabled' ) && $mode !== APP_MODE_ADMIN )) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 22:51:49 +12:00
}
2022-08-08 22:58:28 +12:00
2022-06-22 22:51:49 +12:00
$collection = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId );
2019-10-01 17:57:41 +13:00
2021-06-17 08:36:18 +12:00
if ( $collection -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2020-06-30 09:43:34 +12:00
}
2019-10-01 17:57:41 +13:00
2022-08-04 12:08:16 +12:00
$permissions ? ? = $collection -> getPermissions () ? ? [];
2022-08-16 20:33:06 +12:00
2022-08-23 13:42:25 +12:00
// Map aggregate permissions into the multiple permissions they represent.
$permissions = Permission :: aggregate ( $permissions );
2022-08-16 20:33:06 +12:00
2021-12-14 01:42:04 +13:00
$enabled ? ? = $collection -> getAttribute ( 'enabled' , true );
2019-05-09 18:54:39 +12:00
2020-06-30 09:43:34 +12:00
try {
2022-06-22 22:51:49 +12:00
$collection = $dbForProject -> updateDocument ( 'database_' . $database -> getInternalId (), $collectionId , $collection
2021-08-17 05:28:33 +12:00
-> setAttribute ( 'name' , $name )
2022-08-04 16:20:11 +12:00
-> setAttribute ( '$permissions' , $permissions )
2022-08-02 21:18:49 +12:00
-> setAttribute ( 'documentSecurity' , $documentSecurity )
2021-12-14 01:42:04 +13:00
-> setAttribute ( 'enabled' , $enabled )
2022-05-24 02:54:50 +12:00
-> setAttribute ( 'search' , implode ( ' ' , [ $collectionId , $name ])));
2023-04-18 12:40:36 +12:00
$dbForProject -> updateCollection ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (), $permissions , $documentSecurity );
2022-08-08 22:58:28 +12:00
} catch ( AuthorizationException ) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: USER_UNAUTHORIZED );
2022-05-24 02:54:50 +12:00
} catch ( StructureException $exception ) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DOCUMENT_INVALID_STRUCTURE , 'Bad structure. ' . $exception -> getMessage ());
2021-08-17 05:28:33 +12:00
}
2020-01-05 04:45:28 +13:00
2022-06-22 22:51:49 +12:00
$events
-> setContext ( 'database' , $database )
-> setParam ( 'databaseId' , $databaseId )
-> setParam ( 'collectionId' , $collection -> getId ());
2022-04-14 00:39:31 +12:00
2021-07-26 02:47:18 +12:00
$response -> dynamic ( $collection , Response :: MODEL_COLLECTION );
2020-12-27 04:05:04 +13:00
});
2019-05-09 18:54:39 +12:00
2022-06-22 22:51:49 +12:00
App :: delete ( '/v1/databases/:databaseId/collections/:collectionId' )
2022-06-23 20:50:11 +12:00
-> alias ( '/v1/database/collections/:collectionId' , [ 'databaseId' => 'default' ])
2019-05-09 18:54:39 +12:00
-> desc ( 'Delete Collection' )
2022-07-08 17:43:20 +12:00
-> groups ([ 'api' , 'database' , 'schema' ])
2019-06-09 01:13:19 +12:00
-> label ( 'scope' , 'collections.write' )
2022-06-22 22:51:49 +12:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].delete' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'collection.delete' )
2022-08-09 02:32:54 +12:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.delete' )
2022-08-21 14:10:21 +12:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.namespace' , 'databases' )
2019-05-09 18:54:39 +12:00
-> label ( 'sdk.method' , 'deleteCollection' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/delete-collection.md' )
2020-11-12 10:02:24 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_NOCONTENT )
-> label ( 'sdk.response.model' , Response :: MODEL_NONE )
2022-06-22 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2021-12-11 01:27:11 +13:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID.' )
2020-12-27 04:05:04 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2023-05-26 23:38:09 +12:00
-> inject ( 'mode' )
2020-12-27 04:05:04 +13:00
-> inject ( 'events' )
-> inject ( 'deletes' )
2023-05-26 23:38:09 +12:00
-> action ( function ( string $databaseId , string $collectionId , Response $response , Database $dbForProject , string $mode , Event $events , Delete $deletes ) {
2022-06-22 22:51:49 +12:00
2023-05-24 22:09:08 +12:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2022-06-22 22:51:49 +12:00
2023-05-26 23:38:09 +12:00
if ( $database -> isEmpty () || ( ! $database -> getAttribute ( 'enabled' ) && $mode !== APP_MODE_ADMIN )) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 22:51:49 +12:00
}
2019-05-09 18:54:39 +12:00
2022-06-22 22:51:49 +12:00
$collection = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId );
2019-05-09 18:54:39 +12:00
2021-06-12 02:25:52 +12:00
if ( $collection -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2020-06-30 09:43:34 +12:00
}
2020-01-05 04:45:28 +13:00
2022-06-22 22:51:49 +12:00
if ( ! $dbForProject -> deleteDocument ( 'database_' . $database -> getInternalId (), $collectionId )) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: GENERAL_SERVER_ERROR , 'Failed to remove collection from DB' );
2021-08-17 05:28:33 +12:00
}
2020-12-05 09:47:02 +13:00
2022-06-22 22:51:49 +12:00
$dbForProject -> deleteCachedCollection ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId ());
2021-11-02 13:48:38 +13:00
2021-09-03 04:45:03 +12:00
$deletes
2022-04-18 08:34:32 +12:00
-> setType ( DELETE_TYPE_DOCUMENT )
2023-05-24 22:09:08 +12:00
-> setDocument ( $collection );
2021-09-03 04:45:03 +12:00
2020-12-07 11:14:57 +13:00
$events
2022-06-22 22:51:49 +12:00
-> setContext ( 'database' , $database )
-> setParam ( 'databaseId' , $databaseId )
2022-04-14 00:39:31 +12:00
-> setParam ( 'collectionId' , $collection -> getId ())
2023-05-24 22:09:08 +12:00
-> setPayload ( $response -> output ( $collection , Response :: MODEL_COLLECTION ));
2019-05-09 18:54:39 +12:00
2020-06-30 09:43:34 +12:00
$response -> noContent ();
2020-12-27 04:05:04 +13:00
});
2019-05-09 18:54:39 +12:00
2022-06-22 22:51:49 +12:00
App :: post ( '/v1/databases/:databaseId/collections/:collectionId/attributes/string' )
2022-06-23 20:50:11 +12:00
-> alias ( '/v1/database/collections/:collectionId/attributes/string' , [ 'databaseId' => 'default' ])
2021-07-22 01:23:12 +12:00
-> desc ( 'Create String Attribute' )
2022-07-08 17:43:20 +12:00
-> groups ([ 'api' , 'database' , 'schema' ])
2022-06-22 22:51:49 +12:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create' )
2021-08-14 22:16:00 +12:00
-> label ( 'scope' , 'collections.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'attribute.create' )
2022-08-09 00:19:41 +12:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
2022-08-21 14:10:21 +12:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-08-01 08:40:34 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.namespace' , 'databases' )
2021-07-22 01:23:12 +12:00
-> label ( 'sdk.method' , 'createStringAttribute' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/create-string-attribute.md' )
2022-07-14 21:52:55 +12:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_ACCEPTED )
2021-03-25 04:40:33 +13:00
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2021-10-01 08:37:21 +13:00
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_STRING )
2022-06-22 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 20:14:27 +12: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-17 04:04:30 +13:00
-> param ( 'key' , '' , new Key (), 'Attribute Key.' )
2021-10-27 09:51:40 +13: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-10 09:11:51 +12:00
-> param ( 'required' , null , new Boolean (), 'Is attribute required?' )
2023-05-30 14:52:59 +12:00
-> param ( 'default' , null , new Text ( 0 , 0 ), 'Default value for attribute when not provided. Cannot be set when attribute is required.' , true )
2021-06-12 06:07:05 +12:00
-> param ( 'array' , false , new Boolean (), 'Is attribute an array?' , true )
2021-03-25 04:40:33 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2021-06-19 04:13:37 +12:00
-> inject ( 'database' )
2022-04-14 00:39:31 +12:00
-> inject ( 'events' )
2022-08-10 14:18:18 +12: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-25 04:40:33 +13:00
2021-08-17 11:21:00 +12:00
// Ensure attribute default is within required size
2023-05-30 14:52:59 +12:00
$validator = new Text ( $size , 0 );
2021-08-17 11:21:00 +12:00
if ( ! is_null ( $default ) && ! $validator -> isValid ( $default )) {
2022-07-27 02:56:59 +12:00
throw new Exception ( Exception :: ATTRIBUTE_VALUE_INVALID , $validator -> getDescription ());
2021-08-17 11:21:00 +12:00
}
2022-06-22 22:51:49 +12:00
$attribute = createAttribute ( $databaseId , $collectionId , new Document ([
2021-12-17 04:04:30 +13:00
'key' => $key ,
2021-07-27 13:00:36 +12:00
'type' => Database :: VAR_STRING ,
'size' => $size ,
'required' => $required ,
'default' => $default ,
'array' => $array ,
2022-08-10 14:18:18 +12:00
]), $response , $dbForProject , $database , $events );
2021-08-17 11:21:00 +12:00
2022-09-07 23:02:36 +12:00
$response
-> setStatusCode ( Response :: STATUS_CODE_ACCEPTED )
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_STRING );
2021-07-27 13:00:36 +12:00
});
2021-06-11 01:15:00 +12:00
2022-06-22 22:51:49 +12:00
App :: post ( '/v1/databases/:databaseId/collections/:collectionId/attributes/email' )
2022-06-23 20:50:11 +12:00
-> alias ( '/v1/database/collections/:collectionId/attributes/email' , [ 'databaseId' => 'default' ])
2021-07-27 13:00:36 +12:00
-> desc ( 'Create Email Attribute' )
2022-07-08 17:43:20 +12:00
-> groups ([ 'api' , 'database' , 'schema' ])
2022-06-22 22:51:49 +12:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create' )
2021-08-14 22:16:00 +12:00
-> label ( 'scope' , 'collections.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'attribute.create' )
2022-08-09 00:19:41 +12:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
2022-08-21 14:10:21 +12:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.namespace' , 'databases' )
2021-08-03 08:11:24 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2021-07-27 13:00:36 +12:00
-> label ( 'sdk.method' , 'createEmailAttribute' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/create-email-attribute.md' )
2022-07-14 21:52:55 +12:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_ACCEPTED )
2021-07-27 13:00:36 +12:00
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2021-10-01 08:37:21 +13:00
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_EMAIL )
2022-06-22 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 20:14:27 +12: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-17 04:04:30 +13:00
-> param ( 'key' , '' , new Key (), 'Attribute Key.' )
2021-07-27 13:00:36 +12:00
-> param ( 'required' , null , new Boolean (), 'Is attribute required?' )
2021-08-25 01:46:41 +12:00
-> param ( 'default' , null , new Email (), 'Default value for attribute when not provided. Cannot be set when attribute is required.' , true )
2021-07-27 13:00:36 +12:00
-> param ( 'array' , false , new Boolean (), 'Is attribute an array?' , true )
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2021-07-27 13:00:36 +12:00
-> inject ( 'database' )
2022-04-14 00:39:31 +12:00
-> inject ( 'events' )
2022-08-10 14:18:18 +12: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-22 01:23:12 +12:00
2022-06-22 22:51:49 +12:00
$attribute = createAttribute ( $databaseId , $collectionId , new Document ([
2021-12-17 04:04:30 +13:00
'key' => $key ,
2021-07-27 13:00:36 +12:00
'type' => Database :: VAR_STRING ,
'size' => 254 ,
'required' => $required ,
'default' => $default ,
'array' => $array ,
2021-08-24 06:29:05 +12:00
'format' => APP_DATABASE_ATTRIBUTE_EMAIL ,
2022-08-10 14:18:18 +12:00
]), $response , $dbForProject , $database , $events );
2021-08-17 11:21:00 +12:00
2022-09-07 23:02:36 +12:00
$response
-> setStatusCode ( Response :: STATUS_CODE_ACCEPTED )
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_EMAIL );
2021-07-27 13:00:36 +12:00
});
2021-07-22 01:23:12 +12:00
2022-06-22 22:51:49 +12:00
App :: post ( '/v1/databases/:databaseId/collections/:collectionId/attributes/enum' )
2022-06-23 20:50:11 +12:00
-> alias ( '/v1/database/collections/:collectionId/attributes/enum' , [ 'databaseId' => 'default' ])
2021-09-11 08:09:11 +12:00
-> desc ( 'Create Enum Attribute' )
2022-07-08 17:43:20 +12:00
-> groups ([ 'api' , 'database' , 'schema' ])
2022-06-22 22:51:49 +12:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create' )
2021-09-11 08:09:11 +12:00
-> label ( 'scope' , 'collections.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'attribute.create' )
2022-08-09 00:19:41 +12:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
2022-08-21 14:10:21 +12:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.namespace' , 'databases' )
2021-09-11 08:09:11 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.method' , 'createEnumAttribute' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/create-attribute-enum.md' )
2022-07-14 21:52:55 +12:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_ACCEPTED )
2021-09-11 08:09:11 +12:00
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2021-10-07 15:25:03 +13:00
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_ENUM )
2022-06-22 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 20:14:27 +12: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-17 04:04:30 +13:00
-> param ( 'key' , '' , new Key (), 'Attribute Key.' )
2023-03-02 01:00:36 +13:00
-> param ( 'elements' , [], new ArrayList ( new Text ( APP_LIMIT_ARRAY_ELEMENT_SIZE , min : 0 ), 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-11 08:09:11 +12: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-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2021-09-11 08:09:11 +12:00
-> inject ( 'database' )
2022-04-14 00:39:31 +12:00
-> inject ( 'events' )
2022-08-10 14:18:18 +12: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-11 08:09:11 +12:00
// use length of longest string as attribute size
$size = 0 ;
foreach ( $elements as $element ) {
$length = \strlen ( $element );
2021-10-08 07:30:52 +13:00
if ( $length === 0 ) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: ATTRIBUTE_VALUE_INVALID , 'Each enum element must not be empty' );
2021-10-08 07:30:52 +13:00
}
2021-09-11 08:09:11 +12:00
$size = ( $length > $size ) ? $length : $size ;
}
2021-12-16 23:15:55 +13:00
if ( ! is_null ( $default ) && ! in_array ( $default , $elements )) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: ATTRIBUTE_VALUE_INVALID , 'Default value not found in elements' );
2021-12-16 23:15:55 +13:00
}
2022-06-22 22:51:49 +12:00
$attribute = createAttribute ( $databaseId , $collectionId , new Document ([
2021-12-17 04:04:30 +13:00
'key' => $key ,
2021-09-11 08:09:11 +12:00
'type' => Database :: VAR_STRING ,
'size' => $size ,
'required' => $required ,
'default' => $default ,
'array' => $array ,
'format' => APP_DATABASE_ATTRIBUTE_ENUM ,
'formatOptions' => [ 'elements' => $elements ],
2022-08-10 14:18:18 +12:00
]), $response , $dbForProject , $database , $events );
2021-09-11 08:09:11 +12:00
2022-09-07 23:02:36 +12:00
$response
-> setStatusCode ( Response :: STATUS_CODE_ACCEPTED )
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_ENUM );
2021-09-11 08:09:11 +12:00
});
2022-06-22 22:51:49 +12:00
App :: post ( '/v1/databases/:databaseId/collections/:collectionId/attributes/ip' )
2022-06-23 20:50:11 +12:00
-> alias ( '/v1/database/collections/:collectionId/attributes/ip' , [ 'databaseId' => 'default' ])
2021-07-27 13:00:36 +12:00
-> desc ( 'Create IP Address Attribute' )
2022-07-08 17:43:20 +12:00
-> groups ([ 'api' , 'database' , 'schema' ])
2022-06-22 22:51:49 +12:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create' )
2021-08-14 22:16:00 +12:00
-> label ( 'scope' , 'collections.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'attribute.create' )
2022-08-09 00:19:41 +12:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
2022-08-21 14:10:21 +12:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.namespace' , 'databases' )
2021-08-03 08:11:24 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2021-07-27 13:00:36 +12:00
-> label ( 'sdk.method' , 'createIpAttribute' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/create-ip-attribute.md' )
2022-07-14 21:52:55 +12:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_ACCEPTED )
2021-07-27 13:00:36 +12:00
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2021-10-01 08:37:21 +13:00
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_IP )
2022-06-22 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 20:14:27 +12: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-17 04:04:30 +13:00
-> param ( 'key' , '' , new Key (), 'Attribute Key.' )
2021-07-27 13:00:36 +12:00
-> param ( 'required' , null , new Boolean (), 'Is attribute required?' )
2021-08-25 01:46:41 +12:00
-> param ( 'default' , null , new IP (), 'Default value for attribute when not provided. Cannot be set when attribute is required.' , true )
2021-07-27 13:00:36 +12:00
-> param ( 'array' , false , new Boolean (), 'Is attribute an array?' , true )
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2021-07-27 13:00:36 +12:00
-> inject ( 'database' )
2022-04-14 00:39:31 +12:00
-> inject ( 'events' )
2022-08-10 14:18:18 +12: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-11 01:15:00 +12:00
2022-06-22 22:51:49 +12:00
$attribute = createAttribute ( $databaseId , $collectionId , new Document ([
2021-12-17 04:04:30 +13:00
'key' => $key ,
2021-07-27 13:00:36 +12:00
'type' => Database :: VAR_STRING ,
'size' => 39 ,
'required' => $required ,
'default' => $default ,
'array' => $array ,
2021-08-24 06:29:05 +12:00
'format' => APP_DATABASE_ATTRIBUTE_IP ,
2022-08-10 14:18:18 +12:00
]), $response , $dbForProject , $database , $events );
2021-08-17 11:21:00 +12:00
2022-09-07 23:02:36 +12:00
$response
-> setStatusCode ( Response :: STATUS_CODE_ACCEPTED )
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_IP );
2021-07-27 13:00:36 +12:00
});
2021-06-24 02:21:32 +12:00
2022-06-22 22:51:49 +12:00
App :: post ( '/v1/databases/:databaseId/collections/:collectionId/attributes/url' )
2022-06-23 20:50:11 +12:00
-> alias ( '/v1/database/collections/:collectionId/attributes/url' , [ 'databaseId' => 'default' ])
2021-09-23 13:29:56 +12:00
-> desc ( 'Create URL Attribute' )
2022-07-08 17:43:20 +12:00
-> groups ([ 'api' , 'database' , 'schema' ])
2022-06-22 22:51:49 +12:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create' )
2021-08-14 22:16:00 +12:00
-> label ( 'scope' , 'collections.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'attribute.create' )
2022-08-09 00:19:41 +12:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
2022-08-21 14:10:21 +12:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.namespace' , 'databases' )
2021-08-03 08:11:24 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2021-07-27 13:00:36 +12:00
-> label ( 'sdk.method' , 'createUrlAttribute' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/create-url-attribute.md' )
2022-07-14 21:52:55 +12:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_ACCEPTED )
2021-07-27 13:00:36 +12:00
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2021-10-01 08:37:21 +13:00
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_URL )
2022-06-22 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 20:14:27 +12: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-17 04:04:30 +13:00
-> param ( 'key' , '' , new Key (), 'Attribute Key.' )
2021-07-27 13:00:36 +12:00
-> param ( 'required' , null , new Boolean (), 'Is attribute required?' )
2021-08-25 01:46:41 +12:00
-> param ( 'default' , null , new URL (), 'Default value for attribute when not provided. Cannot be set when attribute is required.' , true )
2021-07-27 13:00:36 +12:00
-> param ( 'array' , false , new Boolean (), 'Is attribute an array?' , true )
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2021-07-27 13:00:36 +12:00
-> inject ( 'database' )
2022-04-14 00:39:31 +12:00
-> inject ( 'events' )
2022-08-10 14:18:18 +12: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 09:11:51 +12:00
2022-06-22 22:51:49 +12:00
$attribute = createAttribute ( $databaseId , $collectionId , new Document ([
2021-12-17 04:04:30 +13:00
'key' => $key ,
2021-07-27 13:00:36 +12:00
'type' => Database :: VAR_STRING ,
2021-08-23 00:59:44 +12:00
'size' => 2000 ,
2021-06-10 09:11:51 +12:00
'required' => $required ,
2021-07-03 05:29:03 +12:00
'default' => $default ,
2021-06-10 09:11:51 +12:00
'array' => $array ,
2021-08-24 06:29:05 +12:00
'format' => APP_DATABASE_ATTRIBUTE_URL ,
2022-08-10 14:18:18 +12:00
]), $response , $dbForProject , $database , $events );
2021-08-17 11:21:00 +12:00
2022-09-07 23:02:36 +12:00
$response
-> setStatusCode ( Response :: STATUS_CODE_ACCEPTED )
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_URL );
2021-07-22 01:23:12 +12:00
});
2021-03-25 04:40:33 +13:00
2022-06-22 22:51:49 +12:00
App :: post ( '/v1/databases/:databaseId/collections/:collectionId/attributes/integer' )
2022-06-23 20:50:11 +12:00
-> alias ( '/v1/database/collections/:collectionId/attributes/integer' , [ 'databaseId' => 'default' ])
2021-07-22 01:23:12 +12:00
-> desc ( 'Create Integer Attribute' )
2022-07-08 17:43:20 +12:00
-> groups ([ 'api' , 'database' , 'schema' ])
2022-06-22 22:51:49 +12:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create' )
2021-08-14 22:16:00 +12:00
-> label ( 'scope' , 'collections.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'attribute.create' )
2022-08-09 00:19:41 +12:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
2022-08-21 14:10:21 +12:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.namespace' , 'databases' )
2021-08-03 08:11:24 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2021-07-22 01:23:12 +12:00
-> label ( 'sdk.method' , 'createIntegerAttribute' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/create-integer-attribute.md' )
2022-07-14 21:52:55 +12:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_ACCEPTED )
2021-07-22 01:23:12 +12:00
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2021-10-01 08:37:21 +13:00
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_INTEGER )
2022-06-22 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 20:14:27 +12: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-17 04:04:30 +13:00
-> param ( 'key' , '' , new Key (), 'Attribute Key.' )
2021-07-22 01:23:12 +12:00
-> param ( 'required' , null , new Boolean (), 'Is attribute required?' )
2021-07-24 09:38:14 +12: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-22 01:23:12 +12: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-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2021-07-22 01:23:12 +12:00
-> inject ( 'database' )
2022-04-14 00:39:31 +12:00
-> inject ( 'events' )
2022-08-10 14:18:18 +12: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-19 04:13:37 +12:00
2021-08-17 11:21:00 +12:00
// Ensure attribute default is within range
2021-08-24 06:29:05 +12:00
$min = ( is_null ( $min )) ? PHP_INT_MIN : \intval ( $min );
$max = ( is_null ( $max )) ? PHP_INT_MAX : \intval ( $max );
2021-10-26 09:10:39 +13:00
if ( $min > $max ) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: ATTRIBUTE_VALUE_INVALID , 'Minimum value must be lesser than maximum value' );
2021-10-26 09:10:39 +13:00
}
2021-08-17 11:21:00 +12:00
$validator = new Range ( $min , $max , Database :: VAR_INTEGER );
if ( ! is_null ( $default ) && ! $validator -> isValid ( $default )) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: ATTRIBUTE_VALUE_INVALID , $validator -> getDescription ());
2021-08-17 11:21:00 +12:00
}
2021-12-30 03:50:21 +13:00
$size = $max > 2147483647 ? 8 : 4 ; // Automatically create BigInt depending on max value
2022-06-22 22:51:49 +12:00
$attribute = createAttribute ( $databaseId , $collectionId , new Document ([
2021-12-17 04:04:30 +13:00
'key' => $key ,
2021-07-27 13:00:36 +12:00
'type' => Database :: VAR_INTEGER ,
2021-12-30 03:50:21 +13:00
'size' => $size ,
2021-07-22 01:23:12 +12:00
'required' => $required ,
'default' => $default ,
'array' => $array ,
2021-08-24 06:29:05 +12:00
'format' => APP_DATABASE_ATTRIBUTE_INT_RANGE ,
2021-08-22 09:48:07 +12:00
'formatOptions' => [
2021-07-28 06:19:37 +12:00
'min' => $min ,
'max' => $max ,
2021-08-22 09:48:07 +12:00
],
2022-08-10 14:18:18 +12:00
]), $response , $dbForProject , $database , $events );
2021-08-17 11:21:00 +12:00
2021-08-25 06:57:34 +12:00
$formatOptions = $attribute -> getAttribute ( 'formatOptions' , []);
if ( ! empty ( $formatOptions )) {
$attribute -> setAttribute ( 'min' , \intval ( $formatOptions [ 'min' ]));
$attribute -> setAttribute ( 'max' , \intval ( $formatOptions [ 'max' ]));
}
2022-09-07 23:02:36 +12:00
$response
-> setStatusCode ( Response :: STATUS_CODE_ACCEPTED )
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_INTEGER );
2021-07-22 01:23:12 +12:00
});
2021-03-25 04:40:33 +13:00
2022-06-22 22:51:49 +12:00
App :: post ( '/v1/databases/:databaseId/collections/:collectionId/attributes/float' )
2022-06-23 20:50:11 +12:00
-> alias ( '/v1/database/collections/:collectionId/attributes/float' , [ 'databaseId' => 'default' ])
2021-07-22 01:23:12 +12:00
-> desc ( 'Create Float Attribute' )
2022-07-08 17:43:20 +12:00
-> groups ([ 'api' , 'database' , 'schema' ])
2022-06-22 22:51:49 +12:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create' )
2021-08-14 22:16:00 +12:00
-> label ( 'scope' , 'collections.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'attribute.create' )
2022-08-09 00:19:41 +12:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
2022-08-21 14:10:21 +12:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.namespace' , 'databases' )
2021-08-03 08:11:24 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2021-07-22 01:23:12 +12:00
-> label ( 'sdk.method' , 'createFloatAttribute' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/create-float-attribute.md' )
2022-07-14 21:52:55 +12:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_ACCEPTED )
2021-07-22 01:23:12 +12:00
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2021-10-01 08:37:21 +13:00
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_FLOAT )
2022-06-22 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 20:14:27 +12: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-17 04:04:30 +13:00
-> param ( 'key' , '' , new Key (), 'Attribute Key.' )
2021-07-22 01:23:12 +12:00
-> param ( 'required' , null , new Boolean (), 'Is attribute required?' )
2021-07-24 09:38:14 +12: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-22 02:26:08 +12:00
-> param ( 'default' , null , new FloatValidator (), 'Default value for attribute when not provided. Cannot be set when attribute is required.' , true )
2021-07-22 01:23:12 +12:00
-> param ( 'array' , false , new Boolean (), 'Is attribute an array?' , true )
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2021-07-22 01:23:12 +12:00
-> inject ( 'database' )
2022-04-14 00:39:31 +12:00
-> inject ( 'events' )
2022-08-10 14:18:18 +12: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-22 01:23:12 +12:00
2021-08-17 11:21:00 +12:00
// Ensure attribute default is within range
2021-11-02 13:48:14 +13:00
$min = ( is_null ( $min )) ? - PHP_FLOAT_MAX : \floatval ( $min );
2021-08-24 06:29:05 +12:00
$max = ( is_null ( $max )) ? PHP_FLOAT_MAX : \floatval ( $max );
2021-10-26 09:10:39 +13:00
if ( $min > $max ) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: ATTRIBUTE_VALUE_INVALID , 'Minimum value must be lesser than maximum value' );
2021-10-26 09:10:39 +13:00
}
2021-12-15 10:01:58 +13:00
// Ensure default value is a float
if ( ! is_null ( $default )) {
$default = \floatval ( $default );
}
2021-10-26 09:10:39 +13:00
2021-08-17 11:21:00 +12:00
$validator = new Range ( $min , $max , Database :: VAR_FLOAT );
if ( ! is_null ( $default ) && ! $validator -> isValid ( $default )) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: ATTRIBUTE_VALUE_INVALID , $validator -> getDescription ());
2021-08-17 11:21:00 +12:00
}
2022-06-22 22:51:49 +12:00
$attribute = createAttribute ( $databaseId , $collectionId , new Document ([
2021-12-17 04:04:30 +13:00
'key' => $key ,
2021-07-27 13:00:36 +12:00
'type' => Database :: VAR_FLOAT ,
2021-07-22 01:23:12 +12:00
'required' => $required ,
2021-07-27 13:00:36 +12:00
'size' => 0 ,
2021-07-22 01:23:12 +12:00
'default' => $default ,
2021-07-27 13:00:36 +12:00
'array' => $array ,
2021-08-24 06:29:05 +12:00
'format' => APP_DATABASE_ATTRIBUTE_FLOAT_RANGE ,
2021-08-22 09:48:07 +12:00
'formatOptions' => [
2021-07-28 06:19:37 +12:00
'min' => $min ,
'max' => $max ,
2021-08-22 09:48:07 +12:00
],
2022-08-10 14:18:18 +12:00
]), $response , $dbForProject , $database , $events );
2021-08-17 11:21:00 +12:00
2021-08-25 06:57:34 +12:00
$formatOptions = $attribute -> getAttribute ( 'formatOptions' , []);
if ( ! empty ( $formatOptions )) {
$attribute -> setAttribute ( 'min' , \floatval ( $formatOptions [ 'min' ]));
$attribute -> setAttribute ( 'max' , \floatval ( $formatOptions [ 'max' ]));
}
2022-09-07 23:02:36 +12:00
$response
-> setStatusCode ( Response :: STATUS_CODE_ACCEPTED )
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_FLOAT );
2021-07-22 01:23:12 +12:00
});
2022-06-22 22:51:49 +12:00
App :: post ( '/v1/databases/:databaseId/collections/:collectionId/attributes/boolean' )
2022-06-23 20:50:11 +12:00
-> alias ( '/v1/database/collections/:collectionId/attributes/boolean' , [ 'databaseId' => 'default' ])
2021-07-22 01:23:12 +12:00
-> desc ( 'Create Boolean Attribute' )
2022-07-08 17:43:20 +12:00
-> groups ([ 'api' , 'database' , 'schema' ])
2022-06-22 22:51:49 +12:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create' )
2021-08-14 22:16:00 +12:00
-> label ( 'scope' , 'collections.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'attribute.create' )
2022-08-09 00:19:41 +12:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
2022-08-21 14:10:21 +12:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.namespace' , 'databases' )
2021-08-03 08:11:24 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2021-07-22 01:23:12 +12:00
-> label ( 'sdk.method' , 'createBooleanAttribute' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/create-boolean-attribute.md' )
2022-07-14 21:52:55 +12:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_ACCEPTED )
2021-07-22 01:23:12 +12:00
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2021-10-01 08:37:21 +13:00
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_BOOLEAN )
2022-06-22 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 20:14:27 +12: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-17 04:04:30 +13:00
-> param ( 'key' , '' , new Key (), 'Attribute Key.' )
2021-07-22 01:23:12 +12: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-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2021-07-22 01:23:12 +12:00
-> inject ( 'database' )
2022-04-14 00:39:31 +12:00
-> inject ( 'events' )
2022-08-10 14:18:18 +12: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-22 01:23:12 +12:00
2022-06-22 22:51:49 +12:00
$attribute = createAttribute ( $databaseId , $collectionId , new Document ([
2021-12-17 04:04:30 +13:00
'key' => $key ,
2021-07-27 13:00:36 +12:00
'type' => Database :: VAR_BOOLEAN ,
'size' => 0 ,
2021-06-10 09:11:51 +12:00
'required' => $required ,
2021-07-03 05:29:03 +12:00
'default' => $default ,
2021-06-10 09:11:51 +12:00
'array' => $array ,
2022-08-10 14:18:18 +12:00
]), $response , $dbForProject , $database , $events );
2021-08-17 11:21:00 +12:00
2022-09-07 23:11:10 +12:00
$response
-> setStatusCode ( Response :: STATUS_CODE_ACCEPTED )
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_BOOLEAN );
2021-03-25 04:40:33 +13:00
});
2022-07-25 20:53:41 +12:00
App :: post ( '/v1/databases/:databaseId/collections/:collectionId/attributes/datetime' )
-> alias ( '/v1/database/collections/:collectionId/attributes/datetime' , [ 'databaseId' => 'default' ])
2022-07-29 00:38:54 +12:00
-> desc ( 'Create DateTime Attribute' )
2022-07-25 20:53:41 +12:00
-> groups ([ 'api' , 'database' ])
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create' )
-> label ( 'scope' , 'collections.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'attribute.create' )
2022-08-19 17:05:39 +12:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-25 23:49:45 +12:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2022-07-25 20:53:41 +12: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-12 11:53:52 +12:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_ACCEPTED )
2022-07-25 20:53:41 +12: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 20:14:27 +12: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 20:53:41 +12:00
-> param ( 'key' , '' , new Key (), 'Attribute Key.' )
-> param ( 'required' , null , new Boolean (), 'Is attribute required?' )
2022-09-05 09:41:26 +12: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 20:53:41 +12:00
-> param ( 'array' , false , new Boolean (), 'Is attribute an array?' , true )
-> inject ( 'response' )
-> inject ( 'dbForProject' )
-> inject ( 'database' )
-> inject ( 'events' )
2022-09-06 21:07:39 +12: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 20:53:41 +12:00
$attribute = createAttribute ( $databaseId , $collectionId , new Document ([
'key' => $key ,
'type' => Database :: VAR_DATETIME ,
'size' => 0 ,
'required' => $required ,
'default' => $default ,
'array' => $array ,
2022-07-28 22:26:22 +12:00
'filters' => [ 'datetime' ]
2022-08-25 22:28:13 +12:00
]), $response , $dbForProject , $database , $events );
2022-07-25 20:53:41 +12:00
2022-09-07 23:11:10 +12:00
$response
-> setStatusCode ( Response :: STATUS_CODE_ACCEPTED )
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_DATETIME );
2022-07-25 20:53:41 +12:00
});
2023-03-13 04:06:56 +13:00
App :: post ( '/v1/databases/:databaseId/collections/:collectionId/attributes/relationship' )
-> alias ( '/v1/database/collections/:collectionId/attributes/relationship' , [ 'databaseId' => 'default' ])
2023-03-29 13:33:27 +13:00
-> desc ( 'Create Relationship Attribute' )
2023-03-13 03:04:18 +13:00
-> groups ([ 'api' , 'database' ])
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].create' )
-> label ( 'scope' , 'collections.write' )
-> label ( 'audits.event' , 'attribute.create' )
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
-> label ( 'sdk.namespace' , 'databases' )
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2023-03-13 04:06:56 +13:00
-> label ( 'sdk.method' , 'createRelationshipAttribute' )
-> label ( 'sdk.description' , '/docs/references/databases/create-relationship-attribute.md' )
2023-03-13 03:04:18 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_ACCEPTED )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2023-03-14 21:24:53 +13:00
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_RELATIONSHIP )
2023-03-13 03:04:18 +13:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
-> 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).' )
2023-03-29 13:37:03 +13:00
-> param ( 'relatedCollectionId' , '' , new UID (), 'Related Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).' )
2023-03-29 02:24:18 +13:00
-> param ( 'type' , '' , new WhiteList ([ Database :: RELATION_ONE_TO_ONE , Database :: RELATION_MANY_TO_ONE , Database :: RELATION_MANY_TO_MANY , Database :: RELATION_ONE_TO_MANY ], true ), 'Relation type' )
2023-03-13 03:04:18 +13:00
-> param ( 'twoWay' , false , new Boolean (), 'Is Two Way?' , true )
2023-03-24 16:57:56 +13:00
-> param ( 'key' , null , new Key (), 'Attribute Key.' , true )
2023-03-24 18:08:50 +13:00
-> param ( 'twoWayKey' , null , new Key (), 'Two Way Attribute Key.' , true )
2023-03-29 02:24:18 +13:00
-> param ( 'onDelete' , Database :: RELATION_MUTATE_RESTRICT , new WhiteList ([ Database :: RELATION_MUTATE_CASCADE , Database :: RELATION_MUTATE_RESTRICT , Database :: RELATION_MUTATE_SET_NULL ], true ), 'Constraints option' , true )
2023-03-13 03:04:18 +13:00
-> inject ( 'response' )
-> inject ( 'dbForProject' )
-> inject ( 'database' )
-> inject ( 'events' )
-> action ( function (
string $databaseId ,
string $collectionId ,
string $relatedCollectionId ,
string $type ,
bool $twoWay ,
2023-03-24 16:57:56 +13:00
? string $key ,
2023-03-23 16:58:41 +13:00
? string $twoWayKey ,
2023-03-13 03:04:18 +13:00
string $onDelete ,
Response $response ,
Database $dbForProject ,
EventDatabase $database ,
Event $events
2023-05-24 22:09:08 +12:00
) {
2023-03-24 16:57:56 +13:00
$key ? ? = $relatedCollectionId ;
2023-03-23 16:58:41 +13:00
$twoWayKey ? ? = $collectionId ;
2023-03-23 04:49:08 +13:00
$attribute = createAttribute (
$databaseId ,
$collectionId ,
new Document ([
'key' => $key ,
'type' => Database :: VAR_RELATIONSHIP ,
'size' => 0 ,
'required' => false ,
'default' => null ,
'array' => false ,
'filters' => [],
'options' => [
'relatedCollection' => $relatedCollectionId ,
'relationType' => $type ,
'twoWay' => $twoWay ,
'twoWayKey' => $twoWayKey ,
'onDelete' => $onDelete ,
]
]),
$response ,
$dbForProject ,
$database ,
$events
);
$options = $attribute -> getAttribute ( 'options' , []);
foreach ( $options as $key => $option ) {
$attribute -> setAttribute ( $key , $option );
}
$response
2023-03-23 16:58:41 +13:00
-> setStatusCode ( Response :: STATUS_CODE_ACCEPTED )
2023-03-23 04:49:08 +13:00
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_RELATIONSHIP );
2023-03-13 03:04:18 +13:00
});
2022-07-25 20:53:41 +12:00
2022-06-22 22:51:49 +12:00
App :: get ( '/v1/databases/:databaseId/collections/:collectionId/attributes' )
2022-06-23 20:50:11 +12:00
-> alias ( '/v1/database/collections/:collectionId/attributes' , [ 'databaseId' => 'default' ])
2021-03-26 08:52:57 +13:00
-> desc ( 'List Attributes' )
-> groups ([ 'api' , 'database' ])
2021-08-14 22:16:00 +12:00
-> label ( 'scope' , 'collections.read' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.read' )
2022-08-21 14:10:21 +12:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-08-01 08:40:34 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.namespace' , 'databases' )
2021-03-26 08:52:57 +13:00
-> label ( 'sdk.method' , 'listAttributes' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/list-attributes.md' )
2021-03-26 08:52:57 +13: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 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 20:14:27 +12: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-26 08:52:57 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2022-08-10 14:18:18 +12:00
-> action ( function ( string $databaseId , string $collectionId , Response $response , Database $dbForProject ) {
2022-06-22 22:51:49 +12:00
2023-05-24 22:09:08 +12:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2021-06-09 08:12:14 +12:00
2022-06-22 22:51:49 +12:00
if ( $database -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 22:51:49 +12:00
}
2023-03-25 16:28:07 +13:00
2022-06-22 22:51:49 +12:00
$collection = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId );
2021-03-26 08:52:57 +13:00
2021-06-12 02:25:52 +12:00
if ( $collection -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-06-11 01:15:00 +12:00
}
2021-08-28 12:32:44 +12:00
$attributes = $collection -> getAttribute ( 'attributes' );
2021-06-18 03:53:06 +12:00
2021-07-26 02:47:18 +12:00
$response -> dynamic ( new Document ([
2022-02-27 22:57:09 +13:00
'total' => \count ( $attributes ),
2021-06-09 08:12:14 +12:00
'attributes' => $attributes
]), Response :: MODEL_ATTRIBUTE_LIST );
2021-03-26 08:52:57 +13:00
});
2022-06-22 22:51:49 +12:00
App :: get ( '/v1/databases/:databaseId/collections/:collectionId/attributes/:key' )
2022-06-23 20:50:11 +12:00
-> alias ( '/v1/database/collections/:collectionId/attributes/:key' , [ 'databaseId' => 'default' ])
2021-03-26 08:52:57 +13:00
-> desc ( 'Get Attribute' )
-> groups ([ 'api' , 'database' ])
2021-08-14 22:16:00 +12:00
-> label ( 'scope' , 'collections.read' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.read' )
2022-08-21 14:10:21 +12:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-08-01 08:40:34 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.namespace' , 'databases' )
2021-07-18 20:19:23 +12:00
-> label ( 'sdk.method' , 'getAttribute' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/get-attribute.md' )
2021-03-26 08:52:57 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2021-10-01 08:03:18 +13:00
-> label ( 'sdk.response.model' , [
Response :: MODEL_ATTRIBUTE_BOOLEAN ,
Response :: MODEL_ATTRIBUTE_INTEGER ,
Response :: MODEL_ATTRIBUTE_FLOAT ,
Response :: MODEL_ATTRIBUTE_EMAIL ,
2021-10-07 15:25:03 +13:00
Response :: MODEL_ATTRIBUTE_ENUM ,
2021-10-01 08:03:18 +13:00
Response :: MODEL_ATTRIBUTE_URL ,
Response :: MODEL_ATTRIBUTE_IP ,
2023-03-29 13:37:51 +13:00
Response :: MODEL_ATTRIBUTE_DATETIME ,
Response :: MODEL_ATTRIBUTE_RELATIONSHIP ,
2022-07-29 00:38:54 +12:00
Response :: MODEL_ATTRIBUTE_STRING ]) // needs to be last, since its condition would dominate any other string attribute
2022-06-22 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 20:14:27 +12: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-17 04:04:30 +13:00
-> param ( 'key' , '' , new Key (), 'Attribute Key.' )
2021-03-26 08:52:57 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2022-08-10 14:18:18 +12:00
-> action ( function ( string $databaseId , string $collectionId , string $key , Response $response , Database $dbForProject ) {
2022-06-22 22:51:49 +12:00
2023-05-24 22:09:08 +12:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2021-06-09 08:12:14 +12:00
2022-06-22 22:51:49 +12:00
if ( $database -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 22:51:49 +12:00
}
$collection = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId );
2021-03-26 08:52:57 +13:00
2021-12-28 06:07:35 +13:00
if ( $collection -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-06-11 01:15:00 +12:00
}
2022-06-22 22:51:49 +12:00
$attribute = $dbForProject -> getDocument ( 'attributes' , $database -> getInternalId () . '_' . $collection -> getInternalId () . '_' . $key );
2021-08-26 07:37:07 +12:00
2021-12-28 06:07:35 +13:00
if ( $attribute -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: ATTRIBUTE_NOT_FOUND );
2021-06-10 09:11:51 +12:00
}
2021-08-26 07:37:07 +12:00
// Select response model based on type and format
2021-08-17 11:21:00 +12:00
$type = $attribute -> getAttribute ( 'type' );
2021-08-25 06:01:53 +12:00
$format = $attribute -> getAttribute ( 'format' );
2023-03-21 00:20:24 +13:00
$options = $attribute -> getAttribute ( 'options' , []);
foreach ( $options as $key => $option ) {
$attribute -> setAttribute ( $key , $option );
}
2021-08-17 11:21:00 +12:00
2022-05-24 02:54:50 +12:00
$model = match ( $type ) {
2021-08-17 11:21:00 +12:00
Database :: VAR_BOOLEAN => Response :: MODEL_ATTRIBUTE_BOOLEAN ,
Database :: VAR_INTEGER => Response :: MODEL_ATTRIBUTE_INTEGER ,
Database :: VAR_FLOAT => Response :: MODEL_ATTRIBUTE_FLOAT ,
2023-03-29 13:37:51 +13:00
Database :: VAR_DATETIME => Response :: MODEL_ATTRIBUTE_DATETIME ,
Database :: VAR_RELATIONSHIP => Response :: MODEL_ATTRIBUTE_RELATIONSHIP ,
2022-05-24 02:54:50 +12:00
Database :: VAR_STRING => match ( $format ) {
2021-08-26 07:37:07 +12:00
APP_DATABASE_ATTRIBUTE_EMAIL => Response :: MODEL_ATTRIBUTE_EMAIL ,
2021-09-11 08:14:12 +12:00
APP_DATABASE_ATTRIBUTE_ENUM => Response :: MODEL_ATTRIBUTE_ENUM ,
2021-08-17 11:21:00 +12: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-25 06:01:53 +12:00
2021-08-17 11:21:00 +12:00
$response -> dynamic ( $attribute , $model );
2021-03-26 08:52:57 +13:00
});
2023-03-23 23:25:40 +13:00
App :: patch ( '/v1/databases/:databaseId/collections/:collectionId/attributes/string/:key' )
2023-02-27 01:33:18 +13:00
-> desc ( 'Update String Attribute' )
-> groups ([ 'api' , 'database' , 'schema' ])
-> label ( 'scope' , 'collections.write' )
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update' )
-> label ( 'audits.event' , 'attribute.update' )
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'databases' )
-> label ( 'sdk.method' , 'updateStringAttribute' )
-> label ( 'sdk.description' , '/docs/references/databases/update-string-attribute.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_STRING )
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
-> 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 ( 'key' , '' , new Key (), 'Attribute Key.' )
2023-02-27 20:45:11 +13:00
-> param ( 'required' , null , new Boolean (), 'Is attribute required?' )
2023-05-30 14:52:59 +12:00
-> param ( 'default' , null , new Nullable ( new Text ( 0 , 0 )), 'Default value for attribute when not provided. Cannot be set when attribute is required.' )
2023-02-27 01:33:18 +13:00
-> inject ( 'response' )
-> inject ( 'dbForProject' )
2023-02-27 04:44:22 +13:00
-> inject ( 'events' )
-> action ( function ( string $databaseId , string $collectionId , string $key , ? bool $required , ? string $default , Response $response , Database $dbForProject , Event $events ) {
2023-02-27 01:33:18 +13:00
$attribute = updateAttribute (
databaseId : $databaseId ,
collectionId : $collectionId ,
key : $key ,
dbForProject : $dbForProject ,
2023-02-27 04:44:22 +13:00
events : $events ,
2023-02-27 01:33:18 +13:00
type : Database :: VAR_STRING ,
default : $default ,
required : $required
);
$response
2023-03-02 19:45:10 +13:00
-> setStatusCode ( Response :: STATUS_CODE_OK )
2023-02-27 01:33:18 +13:00
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_STRING );
});
2023-03-23 23:25:40 +13:00
App :: patch ( '/v1/databases/:databaseId/collections/:collectionId/attributes/email/:key' )
2023-02-27 01:33:18 +13:00
-> desc ( 'Update Email Attribute' )
-> groups ([ 'api' , 'database' , 'schema' ])
-> label ( 'scope' , 'collections.write' )
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update' )
-> label ( 'audits.event' , 'attribute.update' )
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'databases' )
-> label ( 'sdk.method' , 'updateEmailAttribute' )
-> label ( 'sdk.description' , '/docs/references/databases/update-email-attribute.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_EMAIL )
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
-> 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 ( 'key' , '' , new Key (), 'Attribute Key.' )
2023-02-27 04:44:22 +13:00
-> param ( 'required' , null , new Boolean (), 'Is attribute required?' )
2023-03-02 01:00:36 +13:00
-> param ( 'default' , null , new Nullable ( new Email ()), 'Default value for attribute when not provided. Cannot be set when attribute is required.' )
2023-02-27 01:33:18 +13:00
-> inject ( 'response' )
-> inject ( 'dbForProject' )
2023-02-27 04:44:22 +13:00
-> inject ( 'events' )
-> action ( function ( string $databaseId , string $collectionId , string $key , ? bool $required , ? string $default , Response $response , Database $dbForProject , Event $events ) {
2023-02-27 01:33:18 +13:00
$attribute = updateAttribute (
databaseId : $databaseId ,
collectionId : $collectionId ,
key : $key ,
dbForProject : $dbForProject ,
2023-02-27 04:44:22 +13:00
events : $events ,
2023-02-27 01:33:18 +13:00
type : Database :: VAR_STRING ,
filter : APP_DATABASE_ATTRIBUTE_EMAIL ,
default : $default ,
required : $required
);
$response
2023-03-02 19:45:10 +13:00
-> setStatusCode ( Response :: STATUS_CODE_OK )
2023-02-27 01:33:18 +13:00
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_EMAIL );
});
2023-03-23 23:25:40 +13:00
App :: patch ( '/v1/databases/:databaseId/collections/:collectionId/attributes/enum/:key' )
2023-02-27 01:33:18 +13:00
-> desc ( 'Update Enum Attribute' )
-> groups ([ 'api' , 'database' , 'schema' ])
-> label ( 'scope' , 'collections.write' )
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update' )
-> label ( 'audits.event' , 'attribute.update' )
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'databases' )
-> label ( 'sdk.method' , 'updateEnumAttribute' )
-> label ( 'sdk.description' , '/docs/references/databases/update-enum-attribute.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_ENUM )
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
-> 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 ( 'key' , '' , new Key (), 'Attribute Key.' )
2023-02-27 20:45:11 +13:00
-> param ( 'elements' , null , 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.' )
2023-02-27 04:44:22 +13:00
-> param ( 'required' , null , new Boolean (), 'Is attribute required?' )
2023-03-02 01:00:36 +13:00
-> param ( 'default' , null , new Nullable ( new Text ( 0 )), 'Default value for attribute when not provided. Cannot be set when attribute is required.' )
2023-02-27 01:33:18 +13:00
-> inject ( 'response' )
-> inject ( 'dbForProject' )
2023-02-27 04:44:22 +13:00
-> inject ( 'events' )
2023-02-27 20:45:11 +13:00
-> action ( function ( string $databaseId , string $collectionId , string $key , ? array $elements , ? bool $required , ? string $default , Response $response , Database $dbForProject , Event $events ) {
2023-02-27 01:33:18 +13:00
$attribute = updateAttribute (
databaseId : $databaseId ,
collectionId : $collectionId ,
key : $key ,
dbForProject : $dbForProject ,
2023-02-27 04:44:22 +13:00
events : $events ,
2023-02-27 01:33:18 +13:00
type : Database :: VAR_STRING ,
filter : APP_DATABASE_ATTRIBUTE_ENUM ,
default : $default ,
2023-02-27 20:45:11 +13:00
required : $required ,
elements : $elements
2023-02-27 01:33:18 +13:00
);
$response
2023-03-02 19:45:10 +13:00
-> setStatusCode ( Response :: STATUS_CODE_OK )
2023-02-27 01:33:18 +13:00
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_ENUM );
});
2023-03-23 23:25:40 +13:00
App :: patch ( '/v1/databases/:databaseId/collections/:collectionId/attributes/ip/:key' )
2023-02-27 01:33:18 +13:00
-> desc ( 'Update IP Address Attribute' )
-> groups ([ 'api' , 'database' , 'schema' ])
-> label ( 'scope' , 'collections.write' )
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update' )
-> label ( 'audits.event' , 'attribute.update' )
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'databases' )
-> label ( 'sdk.method' , 'updateIpAttribute' )
-> label ( 'sdk.description' , '/docs/references/databases/update-ip-attribute.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_IP )
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
-> 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 ( 'key' , '' , new Key (), 'Attribute Key.' )
2023-02-27 04:44:22 +13:00
-> param ( 'required' , null , new Boolean (), 'Is attribute required?' )
2023-03-02 01:00:36 +13:00
-> param ( 'default' , null , new Nullable ( new IP ()), 'Default value for attribute when not provided. Cannot be set when attribute is required.' )
2023-02-27 01:33:18 +13:00
-> inject ( 'response' )
-> inject ( 'dbForProject' )
2023-02-27 04:44:22 +13:00
-> inject ( 'events' )
-> action ( function ( string $databaseId , string $collectionId , string $key , ? bool $required , ? string $default , Response $response , Database $dbForProject , Event $events ) {
2023-02-27 01:33:18 +13:00
$attribute = updateAttribute (
databaseId : $databaseId ,
collectionId : $collectionId ,
key : $key ,
dbForProject : $dbForProject ,
2023-02-27 04:44:22 +13:00
events : $events ,
2023-02-27 01:33:18 +13:00
type : Database :: VAR_STRING ,
filter : APP_DATABASE_ATTRIBUTE_IP ,
default : $default ,
required : $required
);
$response
2023-03-02 19:45:10 +13:00
-> setStatusCode ( Response :: STATUS_CODE_OK )
2023-02-27 01:33:18 +13:00
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_IP );
});
2023-03-23 23:25:40 +13:00
App :: patch ( '/v1/databases/:databaseId/collections/:collectionId/attributes/url/:key' )
2023-02-27 01:33:18 +13:00
-> desc ( 'Update URL Attribute' )
-> groups ([ 'api' , 'database' , 'schema' ])
-> label ( 'scope' , 'collections.write' )
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update' )
-> label ( 'audits.event' , 'attribute.update' )
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'databases' )
-> label ( 'sdk.method' , 'updateUrlAttribute' )
-> label ( 'sdk.description' , '/docs/references/databases/update-url-attribute.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_URL )
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
-> 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 ( 'key' , '' , new Key (), 'Attribute Key.' )
2023-02-27 04:44:22 +13:00
-> param ( 'required' , null , new Boolean (), 'Is attribute required?' )
2023-03-02 01:00:36 +13:00
-> param ( 'default' , null , new Nullable ( new URL ()), 'Default value for attribute when not provided. Cannot be set when attribute is required.' )
2023-02-27 01:33:18 +13:00
-> inject ( 'response' )
-> inject ( 'dbForProject' )
2023-03-11 02:06:34 +13:00
-> inject ( 'events' )
2023-02-27 04:44:22 +13:00
-> action ( function ( string $databaseId , string $collectionId , string $key , ? bool $required , ? string $default , Response $response , Database $dbForProject , Event $events ) {
2023-02-27 01:33:18 +13:00
$attribute = updateAttribute (
databaseId : $databaseId ,
collectionId : $collectionId ,
key : $key ,
dbForProject : $dbForProject ,
2023-02-27 04:44:22 +13:00
events : $events ,
2023-02-27 01:33:18 +13:00
type : Database :: VAR_STRING ,
filter : APP_DATABASE_ATTRIBUTE_URL ,
default : $default ,
required : $required
);
$response
2023-03-02 19:45:10 +13:00
-> setStatusCode ( Response :: STATUS_CODE_OK )
2023-02-27 01:33:18 +13:00
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_URL );
});
2023-03-23 23:25:40 +13:00
App :: patch ( '/v1/databases/:databaseId/collections/:collectionId/attributes/integer/:key' )
2023-02-27 01:33:18 +13:00
-> desc ( 'Update Integer Attribute' )
-> groups ([ 'api' , 'database' , 'schema' ])
-> label ( 'scope' , 'collections.write' )
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update' )
-> label ( 'audits.event' , 'attribute.update' )
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'databases' )
-> label ( 'sdk.method' , 'updateIntegerAttribute' )
-> label ( 'sdk.description' , '/docs/references/databases/update-integer-attribute.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_INTEGER )
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
-> 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 ( 'key' , '' , new Key (), 'Attribute Key.' )
2023-02-27 04:44:22 +13:00
-> param ( 'required' , null , new Boolean (), 'Is attribute required?' )
-> param ( 'min' , null , new Integer (), 'Minimum value to enforce on new documents' )
-> param ( 'max' , null , new Integer (), 'Maximum value to enforce on new documents' )
2023-03-02 01:00:36 +13:00
-> param ( 'default' , null , new Nullable ( new Integer ()), 'Default value for attribute when not provided. Cannot be set when attribute is required.' )
2023-02-27 01:33:18 +13:00
-> inject ( 'response' )
-> inject ( 'dbForProject' )
2023-02-27 04:44:22 +13:00
-> inject ( 'events' )
-> action ( function ( string $databaseId , string $collectionId , string $key , ? bool $required , ? int $min , ? int $max , ? int $default , Response $response , Database $dbForProject , Event $events ) {
2023-02-27 01:33:18 +13:00
$attribute = updateAttribute (
databaseId : $databaseId ,
collectionId : $collectionId ,
key : $key ,
dbForProject : $dbForProject ,
2023-02-27 04:44:22 +13:00
events : $events ,
2023-02-27 01:33:18 +13:00
type : Database :: VAR_INTEGER ,
default : $default ,
required : $required ,
min : $min ,
max : $max
);
2023-03-11 02:06:34 +13:00
$formatOptions = $attribute -> getAttribute ( 'formatOptions' , []);
if ( ! empty ( $formatOptions )) {
$attribute -> setAttribute ( 'min' , \intval ( $formatOptions [ 'min' ]));
$attribute -> setAttribute ( 'max' , \intval ( $formatOptions [ 'max' ]));
}
2023-02-27 01:33:18 +13:00
$response
2023-03-02 19:45:10 +13:00
-> setStatusCode ( Response :: STATUS_CODE_OK )
2023-02-27 01:33:18 +13:00
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_INTEGER );
});
2023-03-23 23:25:40 +13:00
App :: patch ( '/v1/databases/:databaseId/collections/:collectionId/attributes/float/:key' )
2023-02-27 01:33:18 +13:00
-> desc ( 'Update Float Attribute' )
-> groups ([ 'api' , 'database' , 'schema' ])
-> label ( 'scope' , 'collections.write' )
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update' )
-> label ( 'audits.event' , 'attribute.update' )
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'databases' )
-> label ( 'sdk.method' , 'updateFloatAttribute' )
-> label ( 'sdk.description' , '/docs/references/databases/update-float-attribute.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_FLOAT )
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
-> 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 ( 'key' , '' , new Key (), 'Attribute Key.' )
2023-02-27 04:44:22 +13:00
-> param ( 'required' , null , new Boolean (), 'Is attribute required?' )
-> param ( 'min' , null , new FloatValidator (), 'Minimum value to enforce on new documents' )
-> param ( 'max' , null , new FloatValidator (), 'Maximum value to enforce on new documents' )
2023-03-02 01:00:36 +13:00
-> param ( 'default' , null , new Nullable ( new FloatValidator ()), 'Default value for attribute when not provided. Cannot be set when attribute is required.' )
2023-02-27 01:33:18 +13:00
-> inject ( 'response' )
-> inject ( 'dbForProject' )
2023-02-27 04:44:22 +13:00
-> inject ( 'events' )
-> action ( function ( string $databaseId , string $collectionId , string $key , ? bool $required , ? float $min , ? float $max , ? float $default , Response $response , Database $dbForProject , Event $events ) {
2023-02-27 01:33:18 +13:00
$attribute = updateAttribute (
databaseId : $databaseId ,
collectionId : $collectionId ,
key : $key ,
dbForProject : $dbForProject ,
2023-02-27 04:44:22 +13:00
events : $events ,
2023-02-27 01:33:18 +13:00
type : Database :: VAR_FLOAT ,
default : $default ,
required : $required ,
min : $min ,
max : $max
);
2023-03-11 02:06:34 +13:00
$formatOptions = $attribute -> getAttribute ( 'formatOptions' , []);
if ( ! empty ( $formatOptions )) {
$attribute -> setAttribute ( 'min' , \floatval ( $formatOptions [ 'min' ]));
$attribute -> setAttribute ( 'max' , \floatval ( $formatOptions [ 'max' ]));
}
2023-02-27 01:33:18 +13:00
$response
2023-03-02 19:45:10 +13:00
-> setStatusCode ( Response :: STATUS_CODE_OK )
2023-02-27 01:33:18 +13:00
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_FLOAT );
});
2023-03-23 23:25:40 +13:00
App :: patch ( '/v1/databases/:databaseId/collections/:collectionId/attributes/boolean/:key' )
2023-02-27 01:33:18 +13:00
-> desc ( 'Update Boolean Attribute' )
-> groups ([ 'api' , 'database' , 'schema' ])
-> label ( 'scope' , 'collections.write' )
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update' )
-> label ( 'audits.event' , 'attribute.update' )
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'databases' )
2023-03-11 02:06:34 +13:00
-> label ( 'sdk.method' , 'updateBooleanAttribute' )
2023-02-27 01:33:18 +13:00
-> label ( 'sdk.description' , '/docs/references/databases/update-boolean-attribute.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_BOOLEAN )
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
-> 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 ( 'key' , '' , new Key (), 'Attribute Key.' )
2023-02-27 04:44:22 +13:00
-> param ( 'required' , null , new Boolean (), 'Is attribute required?' )
2023-03-02 01:00:36 +13:00
-> param ( 'default' , null , new Nullable ( new Boolean ()), 'Default value for attribute when not provided. Cannot be set when attribute is required.' )
2023-02-27 01:33:18 +13:00
-> inject ( 'response' )
-> inject ( 'dbForProject' )
2023-02-27 04:44:22 +13:00
-> inject ( 'events' )
-> action ( function ( string $databaseId , string $collectionId , string $key , ? bool $required , ? bool $default , Response $response , Database $dbForProject , Event $events ) {
2023-02-27 01:33:18 +13:00
$attribute = updateAttribute (
databaseId : $databaseId ,
collectionId : $collectionId ,
key : $key ,
dbForProject : $dbForProject ,
2023-02-27 04:44:22 +13:00
events : $events ,
2023-02-27 01:33:18 +13:00
type : Database :: VAR_BOOLEAN ,
default : $default ,
required : $required
);
$response
2023-03-02 19:45:10 +13:00
-> setStatusCode ( Response :: STATUS_CODE_OK )
2023-02-27 01:33:18 +13:00
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_BOOLEAN );
});
2023-03-23 23:25:40 +13:00
App :: patch ( '/v1/databases/:databaseId/collections/:collectionId/attributes/datetime/:key' )
2023-02-27 01:33:18 +13:00
-> desc ( 'Update DateTime Attribute' )
-> groups ([ 'api' , 'database' , 'schema' ])
-> label ( 'scope' , 'collections.write' )
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update' )
-> label ( 'audits.event' , 'attribute.update' )
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'databases' )
-> label ( 'sdk.method' , 'updateDatetimeAttribute' )
-> label ( 'sdk.description' , '/docs/references/databases/update-datetime-attribute.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_DATETIME )
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
-> 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 ( 'key' , '' , new Key (), 'Attribute Key.' )
2023-02-27 04:44:22 +13:00
-> param ( 'required' , null , new Boolean (), 'Is attribute required?' )
2023-03-02 01:00:36 +13:00
-> param ( 'default' , null , new Nullable ( new DatetimeValidator ()), 'Default value for attribute when not provided. Cannot be set when attribute is required.' )
2023-02-27 01:33:18 +13:00
-> inject ( 'response' )
-> inject ( 'dbForProject' )
2023-02-27 04:44:22 +13:00
-> inject ( 'events' )
-> action ( function ( string $databaseId , string $collectionId , string $key , ? bool $required , ? string $default , Response $response , Database $dbForProject , Event $events ) {
2023-02-27 01:33:18 +13:00
$attribute = updateAttribute (
databaseId : $databaseId ,
collectionId : $collectionId ,
key : $key ,
dbForProject : $dbForProject ,
2023-02-27 04:44:22 +13:00
events : $events ,
2023-02-27 01:33:18 +13:00
type : Database :: VAR_DATETIME ,
default : $default ,
required : $required
);
$response
2023-03-02 19:45:10 +13:00
-> setStatusCode ( Response :: STATUS_CODE_OK )
2023-02-27 01:33:18 +13:00
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_DATETIME );
});
2023-03-23 16:58:41 +13:00
App :: patch ( '/v1/databases/:databaseId/collections/:collectionId/attributes/:key/relationship' )
-> desc ( 'Update Relationship Attribute' )
-> groups ([ 'api' , 'database' , 'schema' ])
-> label ( 'scope' , 'collections.write' )
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].update' )
-> label ( 'audits.event' , 'attribute.update' )
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
-> label ( 'sdk.namespace' , 'databases' )
-> label ( 'sdk.method' , 'updateRelationshipAttribute' )
-> label ( 'sdk.description' , '/docs/references/databases/update-relationship-attribute.md' )
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.model' , Response :: MODEL_ATTRIBUTE_RELATIONSHIP )
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
-> 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 ( 'key' , '' , new Key (), 'Attribute Key.' )
2023-03-29 02:24:18 +13:00
-> param ( 'onDelete' , null , new WhiteList ([ Database :: RELATION_MUTATE_CASCADE , Database :: RELATION_MUTATE_RESTRICT , Database :: RELATION_MUTATE_SET_NULL ], true ), 'Constraints option' , true )
2023-03-23 16:58:41 +13:00
-> inject ( 'response' )
-> inject ( 'dbForProject' )
-> inject ( 'events' )
-> action ( function (
string $databaseId ,
string $collectionId ,
string $key ,
? string $onDelete ,
Response $response ,
Database $dbForProject ,
Event $events
) {
$attribute = updateAttribute (
$databaseId ,
$collectionId ,
$key ,
$dbForProject ,
$events ,
type : Database :: VAR_RELATIONSHIP ,
required : false ,
2023-05-24 22:09:08 +12:00
options : [
2023-03-23 16:58:41 +13:00
'onDelete' => $onDelete
]
);
$options = $attribute -> getAttribute ( 'options' , []);
foreach ( $options as $key => $option ) {
$attribute -> setAttribute ( $key , $option );
}
$response
-> setStatusCode ( Response :: STATUS_CODE_OK )
-> dynamic ( $attribute , Response :: MODEL_ATTRIBUTE_RELATIONSHIP );
});
2022-06-22 22:51:49 +12:00
App :: delete ( '/v1/databases/:databaseId/collections/:collectionId/attributes/:key' )
2022-06-23 20:50:11 +12:00
-> alias ( '/v1/database/collections/:collectionId/attributes/:key' , [ 'databaseId' => 'default' ])
2021-03-25 04:40:33 +13:00
-> desc ( 'Delete Attribute' )
2022-07-08 17:43:20 +12:00
-> groups ([ 'api' , 'database' , 'schema' ])
2021-08-14 22:16:00 +12:00
-> label ( 'scope' , 'collections.write' )
2022-06-22 22:51:49 +12:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].attributes.[attributeId].delete' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'attribute.delete' )
2022-08-09 02:32:54 +12:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
2022-08-21 14:10:21 +12:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-08-01 08:40:34 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.namespace' , 'databases' )
2021-03-25 04:40:33 +13:00
-> label ( 'sdk.method' , 'deleteAttribute' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/delete-attribute.md' )
2021-03-25 04:40:33 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_NOCONTENT )
-> label ( 'sdk.response.model' , Response :: MODEL_NONE )
2022-06-22 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 20:14:27 +12: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-17 04:04:30 +13:00
-> param ( 'key' , '' , new Key (), 'Attribute Key.' )
2021-03-25 04:40:33 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2021-06-19 06:27:14 +12:00
-> inject ( 'database' )
2021-03-25 04:40:33 +13:00
-> inject ( 'events' )
2022-08-13 15:14:28 +12:00
-> action ( function ( string $databaseId , string $collectionId , string $key , Response $response , Database $dbForProject , EventDatabase $database , Event $events ) {
2021-03-25 04:40:33 +13:00
2023-05-24 22:09:08 +12:00
$db = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2022-06-22 22:51:49 +12:00
if ( $db -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 22:51:49 +12:00
}
$collection = $dbForProject -> getDocument ( 'database_' . $db -> getInternalId (), $collectionId );
2021-03-25 04:40:33 +13:00
2021-06-12 02:25:52 +12:00
if ( $collection -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-06-11 01:15:00 +12:00
}
2022-06-22 22:51:49 +12:00
$attribute = $dbForProject -> getDocument ( 'attributes' , $db -> getInternalId () . '_' . $collection -> getInternalId () . '_' . $key );
2021-08-09 10:07:59 +12:00
2021-12-28 06:07:35 +13:00
if ( $attribute -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: ATTRIBUTE_NOT_FOUND );
2021-06-10 09:11:51 +12:00
}
2021-10-05 13:23:15 +13:00
// Only update status if removing available attribute
2023-02-27 01:33:18 +13:00
if ( $attribute -> getAttribute ( 'status' ) === 'available' ) {
2021-12-28 01:45:23 +13:00
$attribute = $dbForProject -> updateDocument ( 'attributes' , $attribute -> getId (), $attribute -> setAttribute ( 'status' , 'deleting' ));
2021-10-05 13:23:15 +13:00
}
2022-06-22 22:51:49 +12:00
$dbForProject -> deleteCachedDocument ( 'database_' . $db -> getInternalId (), $collectionId );
$dbForProject -> deleteCachedCollection ( 'database_' . $db -> getInternalId () . '_collection_' . $collection -> getInternalId ());
2021-08-21 05:02:44 +12:00
2023-03-31 06:36:24 +13:00
if ( $attribute -> getAttribute ( 'type' ) === Database :: VAR_RELATIONSHIP ) {
$options = $attribute -> getAttribute ( 'options' );
if ( $options [ 'twoWay' ]) {
$relatedCollection = $dbForProject -> getDocument ( 'database_' . $db -> getInternalId (), $options [ 'relatedCollection' ]);
if ( $relatedCollection -> isEmpty ()) {
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
}
$relatedAttribute = $dbForProject -> getDocument ( 'attributes' , $db -> getInternalId () . '_' . $relatedCollection -> getInternalId () . '_' . $options [ 'twoWayKey' ]);
if ( $relatedAttribute -> isEmpty ()) {
throw new Exception ( Exception :: ATTRIBUTE_NOT_FOUND );
}
if ( $relatedAttribute -> getAttribute ( 'status' ) === 'available' ) {
2023-04-06 00:54:44 +12:00
$dbForProject -> updateDocument ( 'attributes' , $relatedAttribute -> getId (), $relatedAttribute -> setAttribute ( 'status' , 'deleting' ));
2023-03-31 06:36:24 +13:00
}
$dbForProject -> deleteCachedDocument ( 'database_' . $db -> getInternalId (), $options [ 'relatedCollection' ]);
$dbForProject -> deleteCachedCollection ( 'database_' . $db -> getInternalId () . '_collection_' . $relatedCollection -> getInternalId ());
}
}
2021-06-19 06:27:14 +12:00
$database
2022-04-14 00:39:31 +12:00
-> setType ( DATABASE_TYPE_DELETE_ATTRIBUTE )
-> setCollection ( $collection )
2022-06-22 22:51:49 +12:00
-> setDatabase ( $db )
2023-05-24 22:09:08 +12:00
-> setDocument ( $attribute );
2021-06-09 08:12:14 +12:00
2021-10-26 14:12:27 +13:00
// Select response model based on type and format
$type = $attribute -> getAttribute ( 'type' );
$format = $attribute -> getAttribute ( 'format' );
2022-05-24 02:54:50 +12:00
$model = match ( $type ) {
2021-10-26 14:12:27 +13:00
Database :: VAR_BOOLEAN => Response :: MODEL_ATTRIBUTE_BOOLEAN ,
Database :: VAR_INTEGER => Response :: MODEL_ATTRIBUTE_INTEGER ,
Database :: VAR_FLOAT => Response :: MODEL_ATTRIBUTE_FLOAT ,
2023-03-29 13:37:51 +13:00
Database :: VAR_DATETIME => Response :: MODEL_ATTRIBUTE_DATETIME ,
Database :: VAR_RELATIONSHIP => Response :: MODEL_ATTRIBUTE_RELATIONSHIP ,
2022-05-24 02:54:50 +12:00
Database :: VAR_STRING => match ( $format ) {
2021-10-26 14:12:27 +13: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-10 09:11:51 +12:00
$events
2022-06-22 22:51:49 +12:00
-> setParam ( 'databaseId' , $databaseId )
2022-04-14 00:39:31 +12:00
-> setParam ( 'collectionId' , $collection -> getId ())
-> setParam ( 'attributeId' , $attribute -> getId ())
2022-06-22 22:51:49 +12:00
-> setContext ( 'collection' , $collection )
-> setContext ( 'database' , $db )
2023-05-24 22:09:08 +12:00
-> setPayload ( $response -> output ( $attribute , $model ));
2021-03-25 04:40:33 +13:00
$response -> noContent ();
});
2022-06-22 22:51:49 +12:00
App :: post ( '/v1/databases/:databaseId/collections/:collectionId/indexes' )
2022-06-23 20:50:11 +12:00
-> alias ( '/v1/database/collections/:collectionId/indexes' , [ 'databaseId' => 'default' ])
2021-03-24 10:19:19 +13:00
-> desc ( 'Create Index' )
-> groups ([ 'api' , 'database' ])
2022-06-22 22:51:49 +12:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].indexes.[indexId].create' )
2021-08-14 22:16:00 +12:00
-> label ( 'scope' , 'collections.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'index.create' )
2022-08-09 00:19:41 +12:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
2022-08-21 14:10:21 +12:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-08-01 08:40:34 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.namespace' , 'databases' )
2021-03-24 10:19:19 +13:00
-> label ( 'sdk.method' , 'createIndex' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/create-index.md' )
2022-07-14 21:52:55 +12:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_ACCEPTED )
2021-03-24 10:19:19 +13:00
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
-> label ( 'sdk.response.model' , Response :: MODEL_INDEX )
2022-06-22 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 20:14:27 +12: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-17 04:04:30 +13:00
-> param ( 'key' , null , new Key (), 'Index Key.' )
2021-06-18 05:03:24 +12: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-21 02:22:27 +12: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 19:54:58 +12: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-24 10:19:19 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2021-06-19 04:13:37 +12:00
-> inject ( 'database' )
2022-04-14 00:39:31 +12:00
-> inject ( 'events' )
2022-08-10 14:18:18 +12: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-24 10:19:19 +13:00
2023-05-24 22:09:08 +12:00
$db = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2022-06-22 22:51:49 +12:00
if ( $db -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 22:51:49 +12:00
}
2023-06-15 17:29:03 +12:00
2022-06-22 22:51:49 +12:00
$collection = $dbForProject -> getDocument ( 'database_' . $db -> getInternalId (), $collectionId );
2021-06-11 01:15:00 +12:00
2021-06-12 02:25:52 +12:00
if ( $collection -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-06-11 01:15:00 +12:00
}
2021-12-28 01:45:23 +13:00
$count = $dbForProject -> count ( 'indexes' , [
2022-08-12 11:53:52 +12:00
Query :: equal ( 'collectionInternalId' , [ $collection -> getInternalId ()]),
Query :: equal ( 'databaseInternalId' , [ $db -> getInternalId ()])
2022-06-22 22:51:49 +12:00
], 61 );
2021-08-25 11:35:32 +12:00
2022-10-15 00:24:37 +13:00
$limit = 64 - MariaDB :: getCountOfDefaultIndexes ();
2021-08-25 11:35:32 +12:00
if ( $count >= $limit ) {
2022-08-14 20:05:11 +12:00
throw new Exception ( Exception :: INDEX_LIMIT_EXCEEDED , 'Index limit exceeded' );
2021-08-25 11:35:32 +12:00
}
2021-07-03 12:20:09 +12:00
// Convert Document[] to array of attribute metadata
2023-07-18 23:16:33 +12:00
$oldAttributes = \array_map ( fn ( $a ) => $a -> getArrayCopy (), $collection -> getAttribute ( 'attributes' ));
2021-07-03 10:23:58 +12:00
2022-06-21 02:22:27 +12:00
$oldAttributes [] = [
'key' => '$id' ,
2022-09-09 10:18:36 +12:00
'type' => Database :: VAR_STRING ,
2022-06-21 02:22:27 +12:00
'status' => 'available' ,
'required' => true ,
'array' => false ,
'default' => null ,
'size' => 36
];
2022-06-22 21:46:37 +12:00
$oldAttributes [] = [
'key' => '$createdAt' ,
2022-09-09 10:18:36 +12:00
'type' => Database :: VAR_DATETIME ,
2022-06-22 21:46:37 +12:00
'status' => 'available' ,
'signed' => false ,
'required' => false ,
'array' => false ,
'default' => null ,
'size' => 0
];
$oldAttributes [] = [
'key' => '$updatedAt' ,
2022-09-09 10:18:36 +12:00
'type' => Database :: VAR_DATETIME ,
2022-06-22 21:46:37 +12:00
'status' => 'available' ,
'signed' => false ,
'required' => false ,
'array' => false ,
'default' => null ,
'size' => 0
];
2021-07-03 10:23:58 +12:00
2021-06-24 02:21:32 +12:00
// lengths hidden by default
$lengths = [];
2021-12-17 04:04:30 +13:00
foreach ( $attributes as $i => $attribute ) {
2021-07-03 10:23:58 +12:00
// find attribute metadata in collection document
2021-08-23 02:06:59 +12:00
$attributeIndex = \array_search ( $attribute , array_column ( $oldAttributes , 'key' ));
2021-07-03 10:23:58 +12:00
if ( $attributeIndex === false ) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: ATTRIBUTE_UNKNOWN , 'Unknown attribute: ' . $attribute );
2021-07-03 10:23:58 +12:00
}
2021-10-05 13:43:27 +13:00
$attributeStatus = $oldAttributes [ $attributeIndex ][ 'status' ];
2021-07-03 12:20:09 +12:00
$attributeType = $oldAttributes [ $attributeIndex ][ 'type' ];
$attributeSize = $oldAttributes [ $attributeIndex ][ 'size' ];
2021-07-03 10:23:58 +12:00
2023-03-31 18:06:50 +13:00
if ( $attributeType === Database :: VAR_RELATIONSHIP ) {
throw new Exception ( Exception :: ATTRIBUTE_TYPE_INVALID , 'Cannot create an index for a relationship attribute: ' . $oldAttributes [ $attributeIndex ][ 'key' ]);
}
2021-10-05 13:43:27 +13:00
// ensure attribute is available
if ( $attributeStatus !== 'available' ) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: ATTRIBUTE_NOT_AVAILABLE , 'Attribute not available: ' . $oldAttributes [ $attributeIndex ][ 'key' ]);
2021-10-05 13:43:27 +13:00
}
// set attribute size as index length only for strings
2021-12-17 04:04:30 +13:00
$lengths [ $i ] = ( $attributeType === Database :: VAR_STRING ) ? $attributeSize : null ;
2021-07-03 10:23:58 +12:00
}
2023-06-15 17:29:03 +12:00
$index = new Document ([
'$id' => ID :: custom ( $db -> getInternalId () . '_' . $collection -> getInternalId () . '_' . $key ),
'key' => $key ,
'status' => 'processing' , // processing, available, failed, deleting, stuck
'databaseInternalId' => $db -> getInternalId (),
'databaseId' => $databaseId ,
'collectionInternalId' => $collection -> getInternalId (),
'collectionId' => $collectionId ,
'type' => $type ,
'attributes' => $attributes ,
'lengths' => $lengths ,
'orders' => $orders ,
]);
$validator = new IndexValidator ( $dbForProject -> getAdapter () -> getMaxIndexLength ());
if ( ! $validator -> isValid ( $collection -> setAttribute ( 'indexes' , $index , Document :: SET_TYPE_APPEND ))) {
throw new Exception ( Exception :: INDEX_INVALID , $validator -> getDescription ());
}
2021-08-23 03:00:00 +12:00
try {
2023-06-15 17:29:03 +12:00
$index = $dbForProject -> createDocument ( 'indexes' , $index );
} catch ( DuplicateException ) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: INDEX_ALREADY_EXISTS );
2021-08-23 03:00:00 +12:00
}
2022-06-22 22:51:49 +12:00
$dbForProject -> deleteCachedDocument ( 'database_' . $db -> getInternalId (), $collectionId );
2021-03-24 10:19:19 +13:00
2021-06-19 04:13:37 +12:00
$database
2022-04-14 00:39:31 +12:00
-> setType ( DATABASE_TYPE_CREATE_INDEX )
2022-06-22 22:51:49 +12:00
-> setDatabase ( $db )
2022-04-14 00:39:31 +12:00
-> setCollection ( $collection )
2023-05-24 22:09:08 +12:00
-> setDocument ( $index );
2021-06-19 04:13:37 +12:00
2022-04-14 00:39:31 +12:00
$events
2022-06-22 22:51:49 +12:00
-> setParam ( 'databaseId' , $databaseId )
2022-04-14 00:39:31 +12:00
-> setParam ( 'collectionId' , $collection -> getId ())
-> setParam ( 'indexId' , $index -> getId ())
2022-09-07 23:02:36 +12:00
-> setContext ( 'collection' , $collection )
2023-05-24 22:09:08 +12:00
-> setContext ( 'database' , $db );
2022-04-14 00:39:31 +12:00
2022-09-07 23:11:10 +12:00
$response
-> setStatusCode ( Response :: STATUS_CODE_ACCEPTED )
-> dynamic ( $index , Response :: MODEL_INDEX );
2021-03-24 10:19:19 +13:00
});
2022-06-22 22:51:49 +12:00
App :: get ( '/v1/databases/:databaseId/collections/:collectionId/indexes' )
2022-06-23 20:50:11 +12:00
-> alias ( '/v1/database/collections/:collectionId/indexes' , [ 'databaseId' => 'default' ])
2021-03-25 04:40:33 +13:00
-> desc ( 'List Indexes' )
-> groups ([ 'api' , 'database' ])
2021-08-14 22:16:00 +12:00
-> label ( 'scope' , 'collections.read' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.read' )
2022-08-21 14:10:21 +12:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-08-01 08:40:34 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.namespace' , 'databases' )
2021-03-25 04:40:33 +13:00
-> label ( 'sdk.method' , 'listIndexes' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/list-indexes.md' )
2021-03-25 04:40:33 +13: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 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 20:14:27 +12: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 04:40:33 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2022-08-10 14:18:18 +12:00
-> action ( function ( string $databaseId , string $collectionId , Response $response , Database $dbForProject ) {
2022-06-22 22:51:49 +12:00
2023-05-24 22:09:08 +12:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2021-06-10 09:11:51 +12:00
2022-06-22 22:51:49 +12:00
if ( $database -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 22:51:49 +12:00
}
$collection = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId );
2021-03-25 04:40:33 +13:00
2021-06-12 02:25:52 +12:00
if ( $collection -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-06-11 01:15:00 +12:00
}
2021-06-10 09:11:51 +12:00
$indexes = $collection -> getAttribute ( 'indexes' );
2021-03-25 04:40:33 +13:00
2021-07-26 02:47:18 +12:00
$response -> dynamic ( new Document ([
2022-02-27 22:57:09 +13:00
'total' => \count ( $indexes ),
2021-12-14 13:42:54 +13:00
'indexes' => $indexes ,
2021-06-10 09:11:51 +12:00
]), Response :: MODEL_INDEX_LIST );
2021-03-25 04:40:33 +13:00
});
2022-06-22 22:51:49 +12:00
App :: get ( '/v1/databases/:databaseId/collections/:collectionId/indexes/:key' )
2022-06-23 20:50:11 +12:00
-> alias ( '/v1/database/collections/:collectionId/indexes/:key' , [ 'databaseId' => 'default' ])
2021-03-26 08:52:57 +13:00
-> desc ( 'Get Index' )
-> groups ([ 'api' , 'database' ])
2021-08-14 22:16:00 +12:00
-> label ( 'scope' , 'collections.read' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.read' )
2022-08-21 14:10:21 +12:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-08-01 08:40:34 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.namespace' , 'databases' )
2021-07-18 20:19:23 +12:00
-> label ( 'sdk.method' , 'getIndex' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/get-index.md' )
2021-03-26 08:52:57 +13: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 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 20:14:27 +12: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-17 04:04:30 +13:00
-> param ( 'key' , null , new Key (), 'Index Key.' )
2021-03-26 08:52:57 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2022-08-10 14:18:18 +12:00
-> action ( function ( string $databaseId , string $collectionId , string $key , Response $response , Database $dbForProject ) {
2022-06-22 22:51:49 +12:00
2023-05-24 22:09:08 +12:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2021-03-26 08:52:57 +13:00
2022-06-22 22:51:49 +12:00
if ( $database -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 22:51:49 +12:00
}
$collection = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId );
2021-06-10 09:11:51 +12:00
2021-06-12 02:25:52 +12:00
if ( $collection -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-06-11 01:15:00 +12:00
}
2021-06-10 09:11:51 +12:00
$indexes = $collection -> getAttribute ( 'indexes' );
2021-03-26 08:52:57 +13:00
2021-08-17 07:24:15 +12:00
// Search for index
2023-07-18 23:16:33 +12:00
$indexIndex = array_search ( $key , array_map ( fn ( $idx ) => $idx [ 'key' ], $indexes ));
2021-06-10 09:11:51 +12:00
if ( $indexIndex === false ) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: INDEX_NOT_FOUND );
2021-06-10 09:11:51 +12:00
}
2022-10-25 18:31:51 +13:00
$index = $indexes [ $indexIndex ];
$index -> setAttribute ( 'collectionId' , $database -> getInternalId () . '_' . $collectionId );
2021-08-15 23:08:32 +12:00
2021-07-26 02:47:18 +12:00
$response -> dynamic ( $index , Response :: MODEL_INDEX );
2021-03-26 08:52:57 +13:00
});
2022-06-22 22:51:49 +12:00
App :: delete ( '/v1/databases/:databaseId/collections/:collectionId/indexes/:key' )
2022-06-23 20:50:11 +12:00
-> alias ( '/v1/database/collections/:collectionId/indexes/:key' , [ 'databaseId' => 'default' ])
2021-03-26 08:52:57 +13:00
-> desc ( 'Delete Index' )
-> groups ([ 'api' , 'database' ])
2021-08-14 22:16:00 +12:00
-> label ( 'scope' , 'collections.write' )
2022-06-22 22:51:49 +12:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].indexes.[indexId].delete' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'index.delete' )
2022-08-09 02:32:54 +12:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'collections.{scope}.requests.update' )
2022-08-21 14:10:21 +12:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' ])
2021-08-01 08:40:34 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_KEY ])
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.namespace' , 'databases' )
2021-03-26 08:52:57 +13:00
-> label ( 'sdk.method' , 'deleteIndex' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/delete-index.md' )
2021-03-26 08:52:57 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_NOCONTENT )
-> label ( 'sdk.response.model' , Response :: MODEL_NONE )
2022-06-22 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-09-19 22:05:42 +12: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-17 04:04:30 +13:00
-> param ( 'key' , '' , new Key (), 'Index Key.' )
2021-03-26 08:52:57 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2021-06-19 06:27:14 +12:00
-> inject ( 'database' )
2021-03-26 08:52:57 +13:00
-> inject ( 'events' )
2022-08-13 15:14:28 +12:00
-> action ( function ( string $databaseId , string $collectionId , string $key , Response $response , Database $dbForProject , EventDatabase $database , Event $events ) {
2021-03-26 08:52:57 +13:00
2023-05-24 22:09:08 +12:00
$db = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2022-06-22 22:51:49 +12:00
if ( $db -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 22:51:49 +12:00
}
$collection = $dbForProject -> getDocument ( 'database_' . $db -> getInternalId (), $collectionId );
2021-06-10 09:11:51 +12:00
2021-06-12 06:07:05 +12:00
if ( $collection -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-06-11 01:15:00 +12:00
}
2022-06-22 22:51:49 +12:00
$index = $dbForProject -> getDocument ( 'indexes' , $db -> getInternalId () . '_' . $collection -> getInternalId () . '_' . $key );
2021-06-10 09:11:51 +12:00
2021-08-23 16:06:53 +12:00
if ( empty ( $index -> getId ())) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: INDEX_NOT_FOUND );
2021-03-26 08:52:57 +13:00
}
2021-10-05 13:23:15 +13:00
// Only update status if removing available index
if ( $index -> getAttribute ( 'status' ) === 'available' ) {
2021-12-28 01:45:23 +13:00
$index = $dbForProject -> updateDocument ( 'indexes' , $index -> getId (), $index -> setAttribute ( 'status' , 'deleting' ));
2021-10-05 13:23:15 +13:00
}
2022-06-22 22:51:49 +12:00
$dbForProject -> deleteCachedDocument ( 'database_' . $db -> getInternalId (), $collectionId );
2021-08-23 16:06:53 +12:00
2021-06-19 06:27:14 +12:00
$database
2022-04-14 00:39:31 +12:00
-> setType ( DATABASE_TYPE_DELETE_INDEX )
2022-06-22 22:51:49 +12:00
-> setDatabase ( $db )
2022-04-14 00:39:31 +12:00
-> setCollection ( $collection )
2023-05-24 22:09:08 +12:00
-> setDocument ( $index );
2021-03-26 08:52:57 +13:00
$events
2022-06-22 22:51:49 +12:00
-> setParam ( 'databaseId' , $databaseId )
2022-04-14 00:39:31 +12:00
-> setParam ( 'collectionId' , $collection -> getId ())
-> setParam ( 'indexId' , $index -> getId ())
2022-08-05 18:01:25 +12:00
-> setContext ( 'collection' , $collection )
-> setContext ( 'database' , $db )
2023-05-24 22:09:08 +12:00
-> setPayload ( $response -> output ( $index , Response :: MODEL_INDEX ));
2021-03-26 08:52:57 +13:00
$response -> noContent ();
});
2022-06-22 22:51:49 +12:00
App :: post ( '/v1/databases/:databaseId/collections/:collectionId/documents' )
2022-06-23 20:50:11 +12:00
-> alias ( '/v1/database/collections/:collectionId/documents' , [ 'databaseId' => 'default' ])
2020-02-01 11:34:07 +13:00
-> desc ( 'Create Document' )
2020-06-26 06:32:12 +12:00
-> groups ([ 'api' , 'database' ])
2022-06-22 22:51:49 +12:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].documents.[documentId].create' )
2020-02-01 11:34:07 +13:00
-> label ( 'scope' , 'documents.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'document.create' )
2023-06-17 06:50:37 +12:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}/document/{response.$id}' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'documents.{scope}.requests.create' )
2022-08-21 14:10:21 +12:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' , 'collectionId:{request.collectionId}' ])
2022-08-31 15:58:32 +12:00
-> label ( 'abuse-key' , 'ip:{ip},method:{method},url:{url},userId:{userId}' )
2022-08-31 11:34:17 +12:00
-> label ( 'abuse-limit' , APP_LIMIT_WRITE_RATE_DEFAULT * 2 )
-> label ( 'abuse-time' , APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT )
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_SESSION , APP_AUTH_TYPE_KEY , APP_AUTH_TYPE_JWT ])
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.namespace' , 'databases' )
2020-02-01 11:34:07 +13:00
-> label ( 'sdk.method' , 'createDocument' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/create-document.md' )
2020-11-12 10:02:24 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_CREATED )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2021-04-08 20:39:23 +12:00
-> label ( 'sdk.response.model' , Response :: MODEL_DOCUMENT )
2023-02-10 14:06:33 +13:00
-> label ( 'sdk.offline.model' , '/databases/{databaseId}/collections/{collectionId}/documents' )
-> label ( 'sdk.offline.key' , '{documentId}' )
2022-06-22 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2023-01-21 11:22:16 +13:00
-> param ( 'documentId' , '' , new CustomId (), 'Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. 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 22:05:42 +12: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-16 04:22:48 +13:00
-> param ( 'data' , [], new JSON (), 'Document data as JSON object.' )
2022-12-21 10:43:55 +13: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, only the current user is granted all permissions. [Learn more about permissions](/docs/permissions).' , true )
2020-12-27 04:05:04 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2021-03-22 11:17:20 +13:00
-> inject ( 'user' )
2021-12-17 07:12:06 +13:00
-> inject ( 'events' )
2021-12-14 01:42:04 +13:00
-> inject ( 'mode' )
2022-08-25 18:21:15 +12: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 23:30:33 +13:00
2020-06-30 09:43:34 +12:00
$data = ( \is_string ( $data )) ? \json_decode ( $data , true ) : $data ; // Cast to JSON array
if ( empty ( $data )) {
2023-06-07 13:51:24 +12:00
throw new Exception ( Exception :: DOCUMENT_MISSING_DATA );
2020-06-30 09:43:34 +12:00
}
2020-02-01 11:34:07 +13:00
2020-06-30 09:43:34 +12:00
if ( isset ( $data [ '$id' ])) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DOCUMENT_INVALID_STRUCTURE , '$id is not allowed for creating new documents, try update instead' );
2020-06-30 09:43:34 +12:00
}
2021-10-05 23:30:33 +13:00
2022-08-24 20:50:05 +12:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2022-08-08 22:58:28 +12:00
2023-05-24 22:09:08 +12:00
if ( $database -> isEmpty () || ( ! $database -> getAttribute ( 'enabled' ) && $mode !== APP_MODE_ADMIN )) {
2022-08-16 20:30:00 +12:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-08-08 22:58:28 +12:00
}
2022-06-22 22:51:49 +12:00
$collection = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId ));
2020-02-01 11:34:07 +13:00
2021-12-18 01:51:07 +13:00
if ( $collection -> isEmpty () || ! $collection -> getAttribute ( 'enabled' )) {
if ( ! ( $mode === APP_MODE_ADMIN && Auth :: isPrivilegedUser ( Authorization :: getRoles ()))) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-12-18 01:51:07 +13:00
}
2020-06-30 09:43:34 +12:00
}
2020-02-01 11:34:07 +13:00
2022-08-23 13:42:25 +12:00
$allowedPermissions = [
Database :: PERMISSION_READ ,
Database :: PERMISSION_UPDATE ,
Database :: PERMISSION_DELETE ,
];
2022-08-16 17:54:44 +12:00
2022-08-23 13:42:25 +12: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-16 00:56:19 +12:00
if ( \is_null ( $permissions )) {
$permissions = [];
2022-08-16 01:16:20 +12:00
if ( ! empty ( $user -> getId ())) {
2022-08-16 00:56:19 +12:00
foreach ( $allowedPermissions as $permission ) {
2022-08-16 01:16:20 +12:00
$permissions [] = ( new Permission ( $permission , 'user' , $user -> getId ())) -> toString ();
2022-08-16 00:56:19 +12:00
}
}
}
2022-08-14 17:24:50 +12:00
2022-08-16 00:56:19 +12: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 23:26:38 +12:00
$permission = Permission :: parse ( $permission );
if ( $permission -> getPermission () != $type ) {
2022-08-16 00:56:19 +12:00
continue ;
}
2022-08-16 23:26:38 +12:00
$role = ( new Role (
$permission -> getRole (),
$permission -> getIdentifier (),
$permission -> getDimension ()
)) -> toString ();
2022-08-16 00:56:19 +12:00
if ( ! Authorization :: isRole ( $role )) {
2022-08-25 15:51:21 +12:00
throw new Exception ( Exception :: USER_UNAUTHORIZED , 'Permissions must be one of: (' . \implode ( ', ' , $roles ) . ')' );
2022-08-16 00:56:19 +12:00
}
}
}
2022-08-08 22:58:28 +12:00
}
2021-06-16 01:38:24 +12:00
$data [ '$collection' ] = $collection -> getId (); // Adding this param to make API easier for developers
2022-08-15 02:22:38 +12:00
$data [ '$id' ] = $documentId == 'unique()' ? ID :: unique () : $documentId ;
2022-08-02 21:18:49 +12:00
$data [ '$permissions' ] = $permissions ;
2023-03-28 22:02:49 +13:00
$document = new Document ( $data );
2020-02-01 11:34:07 +13:00
2023-03-28 22:02:49 +13:00
$checkPermissions = function ( Document $collection , Document $document , string $permission ) use ( & $checkPermissions , $dbForProject , $database ) {
$documentSecurity = $collection -> getAttribute ( 'documentSecurity' , false );
$validator = new Authorization ( $permission );
$valid = $validator -> isValid ( $collection -> getPermissionsByType ( $permission ));
if (( $permission === Database :: PERMISSION_UPDATE && ! $documentSecurity ) || ! $valid ) {
throw new Exception ( Exception :: USER_UNAUTHORIZED );
}
if ( $permission === Database :: PERMISSION_UPDATE ) {
$valid = $valid || $validator -> isValid ( $document -> getUpdate ());
if ( $documentSecurity && ! $valid ) {
throw new Exception ( Exception :: USER_UNAUTHORIZED );
}
}
$relationships = \array_filter (
$collection -> getAttribute ( 'attributes' , []),
2023-07-18 23:16:33 +12:00
fn ( $attribute ) => $attribute -> getAttribute ( 'type' ) === Database :: VAR_RELATIONSHIP
2023-03-28 22:02:49 +13:00
);
foreach ( $relationships as $relationship ) {
$related = $document -> getAttribute ( $relationship -> getAttribute ( 'key' ));
if ( empty ( $related )) {
continue ;
}
2023-04-13 15:59:57 +12:00
2023-04-14 22:03:16 +12:00
$isList = \is_array ( $related ) && \array_values ( $related ) === $related ;
if ( $isList ) {
2023-04-13 15:59:57 +12:00
$relations = $related ;
} else {
$relations = [ $related ];
2023-03-29 14:33:53 +13:00
}
2023-03-28 22:02:49 +13:00
$relatedCollectionId = $relationship -> getAttribute ( 'relatedCollection' );
$relatedCollection = Authorization :: skip (
fn () => $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $relatedCollectionId )
);
2023-04-13 15:59:57 +12:00
foreach ( $relations as & $relation ) {
if (
2023-04-21 13:44:53 +12:00
\is_array ( $relation )
&& \array_values ( $relation ) !== $relation
2023-04-13 15:59:57 +12:00
&& ! isset ( $relation [ '$id' ])
) {
$relation [ '$id' ] = ID :: unique ();
$relation = new Document ( $relation );
}
2023-03-29 14:37:56 +13:00
if ( $relation instanceof Document ) {
2023-03-28 22:02:49 +13:00
$current = Authorization :: skip (
2023-03-29 14:37:56 +13:00
fn () => $dbForProject -> getDocument ( 'database_' . $database -> getInternalId () . '_collection_' . $relatedCollection -> getInternalId (), $relation -> getId ())
2023-03-28 22:02:49 +13:00
);
2023-03-31 17:33:21 +13:00
if ( $current -> isEmpty ()) {
$type = Database :: PERMISSION_CREATE ;
2023-04-13 15:59:57 +12:00
if ( isset ( $relation [ '$id' ]) && $relation [ '$id' ] === 'unique()' ) {
2023-03-31 17:33:21 +13:00
$relation [ '$id' ] = ID :: unique ();
}
} else {
2023-04-03 22:45:10 +12:00
$relation -> removeAttribute ( '$collectionId' );
$relation -> removeAttribute ( '$databaseId' );
$relation -> setAttribute ( '$collection' , $relatedCollection -> getId ());
2023-03-31 17:33:21 +13:00
$type = Database :: PERMISSION_UPDATE ;
}
2023-03-28 22:02:49 +13:00
2023-03-29 14:37:56 +13:00
$checkPermissions ( $relatedCollection , $relation , $type );
2023-03-28 22:02:49 +13:00
}
}
2023-04-13 15:59:57 +12:00
2023-04-14 22:03:16 +12:00
if ( $isList ) {
2023-04-13 15:59:57 +12:00
$document -> setAttribute ( $relationship -> getAttribute ( 'key' ), \array_values ( $relations ));
} else {
$document -> setAttribute ( $relationship -> getAttribute ( 'key' ), \reset ( $relations ));
}
2023-03-28 22:02:49 +13:00
}
};
$checkPermissions ( $collection , $document , Database :: PERMISSION_CREATE );
try {
$document = $dbForProject -> createDocument ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (), $document );
} catch ( StructureException $exception ) {
throw new Exception ( Exception :: DOCUMENT_INVALID_STRUCTURE , $exception -> getMessage ());
} catch ( DuplicateException $exception ) {
throw new Exception ( Exception :: DOCUMENT_ALREADY_EXISTS );
}
2020-02-01 11:34:07 +13:00
2023-03-27 19:03:00 +13:00
// Add $collectionId and $databaseId for all documents
2023-03-28 22:02:49 +13:00
$processDocument = function ( Document $collection , Document $document ) use ( & $processDocument , $dbForProject , $database ) {
2023-03-27 19:03:00 +13:00
$document -> setAttribute ( '$databaseId' , $database -> getId ());
$document -> setAttribute ( '$collectionId' , $collection -> getId ());
$relationships = \array_filter (
$collection -> getAttribute ( 'attributes' , []),
2023-07-18 23:16:33 +12:00
fn ( $attribute ) => $attribute -> getAttribute ( 'type' ) === Database :: VAR_RELATIONSHIP
2023-03-27 19:03:00 +13:00
);
2023-03-28 16:10:12 +13:00
foreach ( $relationships as $relationship ) {
$related = $document -> getAttribute ( $relationship -> getAttribute ( 'key' ));
if ( empty ( $related )) {
2023-03-27 19:03:00 +13:00
continue ;
}
2023-03-28 16:10:12 +13:00
if ( ! \is_array ( $related )) {
$related = [ $related ];
}
2023-03-27 19:03:00 +13:00
2023-03-28 16:10:12 +13:00
$relatedCollectionId = $relationship -> getAttribute ( 'relatedCollection' );
$relatedCollection = Authorization :: skip (
fn () => $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $relatedCollectionId )
);
2023-03-27 19:03:00 +13:00
2023-03-29 14:37:56 +13:00
foreach ( $related as $relation ) {
2023-04-03 22:39:31 +12:00
if ( $relation instanceof Document ) {
$processDocument ( $relatedCollection , $relation );
}
2023-03-27 15:42:36 +13:00
}
}
};
2023-03-27 19:03:00 +13:00
2023-03-28 22:02:49 +13:00
$processDocument ( $collection , $document );
2023-03-27 15:42:36 +13:00
2022-04-14 00:39:31 +12:00
$events
2022-06-22 22:51:49 +12:00
-> setParam ( 'databaseId' , $databaseId )
2022-04-14 00:39:31 +12:00
-> setParam ( 'collectionId' , $collection -> getId ())
-> setParam ( 'documentId' , $document -> getId ())
2022-06-22 22:51:49 +12:00
-> setContext ( 'collection' , $collection )
2023-05-24 22:09:08 +12:00
-> setContext ( 'database' , $database );
2021-12-17 07:12:06 +13:00
2022-09-07 23:11:10 +12:00
$response
-> setStatusCode ( Response :: STATUS_CODE_CREATED )
-> dynamic ( $document , Response :: MODEL_DOCUMENT );
2020-12-27 04:05:04 +13:00
});
2020-02-01 11:34:07 +13:00
2022-06-22 22:51:49 +12:00
App :: get ( '/v1/databases/:databaseId/collections/:collectionId/documents' )
2022-06-23 20:50:11 +12:00
-> alias ( '/v1/database/collections/:collectionId/documents' , [ 'databaseId' => 'default' ])
2019-05-09 18:54:39 +12:00
-> desc ( 'List Documents' )
2020-06-26 06:32:12 +12:00
-> groups ([ 'api' , 'database' ])
2019-06-09 01:13:19 +12:00
-> label ( 'scope' , 'documents.read' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'documents.{scope}.requests.read' )
2022-08-21 14:10:21 +12:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' , 'collectionId:{request.collectionId}' ])
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_SESSION , APP_AUTH_TYPE_KEY , APP_AUTH_TYPE_JWT ])
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.namespace' , 'databases' )
2019-05-09 18:54:39 +12:00
-> label ( 'sdk.method' , 'listDocuments' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/list-documents.md' )
2020-11-12 10:02:24 +13: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 )
2023-02-10 14:06:33 +13:00
-> label ( 'sdk.offline.model' , '/databases/{databaseId}/collections/{collectionId}/documents' )
2022-06-22 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-08-25 20:14:27 +12: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).' )
2023-03-30 08:38:39 +13: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/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.' , true )
2020-12-27 04:05:04 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2021-12-14 01:42:04 +13:00
-> inject ( 'mode' )
2022-08-25 21:59:28 +12:00
-> action ( function ( string $databaseId , string $collectionId , array $queries , Response $response , Database $dbForProject , string $mode ) {
2022-06-22 22:51:49 +12:00
2023-05-24 22:09:08 +12:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2019-05-09 18:54:39 +12:00
2023-05-24 22:09:08 +12:00
if ( $database -> isEmpty () || ( ! $database -> getAttribute ( 'enabled' ) && $mode !== APP_MODE_ADMIN )) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 22:51:49 +12:00
}
2022-08-08 22:58:28 +12:00
2022-06-22 22:51:49 +12:00
$collection = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId ));
2019-05-09 18:54:39 +12:00
2023-04-19 12:34:39 +12:00
if ( ! ( $mode === APP_MODE_ADMIN && Auth :: isPrivilegedUser ( Authorization :: getRoles ()))) {
if ( ! $collection -> getAttribute ( 'documentSecurity' , false )) {
$validator = new Authorization ( Database :: PERMISSION_READ );
if ( ! $validator -> isValid ( $collection -> getRead ())) {
$collection = new Document ();
}
2021-12-18 01:51:07 +13:00
}
2020-06-30 09:43:34 +12:00
}
2020-06-22 00:12:13 +12:00
2023-04-19 12:34:39 +12:00
if ( $collection -> isEmpty () || ! $collection -> getAttribute ( 'enabled' )) {
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
}
2022-08-24 04:33:08 +12:00
// Validate queries
2023-05-17 00:56:20 +12:00
$queriesValidator = new Documents ( $collection -> getAttribute ( 'attributes' ), $collection -> getAttribute ( 'indexes' ));
2022-08-29 22:05:11 +12:00
$validQueries = $queriesValidator -> isValid ( $queries );
if ( ! $validQueries ) {
2022-08-29 22:27:56 +12:00
throw new Exception ( Exception :: GENERAL_ARGUMENT_INVALID , $queriesValidator -> getDescription ());
2022-08-20 12:47:10 +12:00
}
2021-12-29 06:57:24 +13:00
2022-08-24 03:18:59 +12:00
$queries = Query :: parseQueries ( $queries );
2020-06-30 09:43:34 +12:00
2022-08-24 03:18:59 +12:00
// Get cursor document if there was a cursor query
2023-05-01 21:18:50 +12:00
$cursor = Query :: getByType ( $queries , [ Query :: TYPE_CURSORAFTER , Query :: TYPE_CURSORBEFORE ]);
2022-08-31 11:31:43 +12:00
$cursor = reset ( $cursor );
2022-08-30 23:55:23 +12:00
if ( $cursor ) {
2022-08-24 03:18:59 +12:00
$documentId = $cursor -> getValue ();
2021-07-06 08:27:20 +12:00
2023-03-28 22:02:49 +13:00
$cursorDocument = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (), $documentId ));
2022-08-25 01:24:19 +12:00
2021-10-05 23:30:33 +13:00
if ( $cursorDocument -> isEmpty ()) {
2022-08-24 03:18:59 +12:00
throw new Exception ( Exception :: GENERAL_CURSOR_NOT_FOUND , " Document ' { $documentId } ' for the 'cursor' value not found. " );
2021-08-06 07:01:00 +12:00
}
2022-08-12 11:53:52 +12:00
2022-08-24 03:18:59 +12:00
$cursor -> setValue ( $cursorDocument );
2022-08-12 11:53:52 +12:00
}
2022-08-24 03:18:59 +12:00
$filterQueries = Query :: groupByType ( $queries )[ 'filters' ];
2023-03-24 16:46:02 +13:00
2023-04-19 12:37:41 +12:00
$documents = $dbForProject -> find ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (), $queries );
$total = $dbForProject -> count ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (), $filterQueries , APP_LIMIT_COUNT );
2021-08-12 13:26:31 +12:00
2023-03-27 19:03:00 +13:00
// Add $collectionId and $databaseId for all documents
2023-03-28 22:02:49 +13:00
$processDocument = function ( Document $collection , Document $document ) use ( & $processDocument , $dbForProject , $database ) : bool {
2023-04-19 12:37:41 +12:00
if ( $document -> isEmpty ()) {
2023-03-28 22:02:49 +13:00
return false ;
}
2023-04-19 12:37:41 +12:00
$document -> removeAttribute ( '$collection' );
2023-03-27 19:03:00 +13:00
$document -> setAttribute ( '$databaseId' , $database -> getId ());
$document -> setAttribute ( '$collectionId' , $collection -> getId ());
$relationships = \array_filter (
$collection -> getAttribute ( 'attributes' , []),
2023-07-18 23:16:33 +12:00
fn ( $attribute ) => $attribute -> getAttribute ( 'type' ) === Database :: VAR_RELATIONSHIP
2023-03-27 19:03:00 +13:00
);
2023-03-28 16:10:12 +13:00
foreach ( $relationships as $relationship ) {
$related = $document -> getAttribute ( $relationship -> getAttribute ( 'key' ));
if ( empty ( $related )) {
2023-03-27 19:03:00 +13:00
continue ;
}
2023-03-28 16:10:12 +13:00
if ( ! \is_array ( $related )) {
2023-03-28 22:02:49 +13:00
$relations = [ $related ];
} else {
$relations = $related ;
2023-03-28 16:10:12 +13:00
}
2023-03-27 19:03:00 +13:00
2023-03-28 16:10:12 +13:00
$relatedCollectionId = $relationship -> getAttribute ( 'relatedCollection' );
2023-05-24 22:09:08 +12:00
$relatedCollection = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $relatedCollectionId ));
2023-03-27 19:03:00 +13:00
2023-03-28 22:02:49 +13:00
foreach ( $relations as $index => $doc ) {
2023-03-31 17:56:25 +13:00
if ( $doc instanceof Document ) {
if ( ! $processDocument ( $relatedCollection , $doc )) {
unset ( $relations [ $index ]);
}
2023-03-28 22:02:49 +13:00
}
}
if ( \is_array ( $related )) {
$document -> setAttribute ( $relationship -> getAttribute ( 'key' ), \array_values ( $relations ));
} elseif ( empty ( $relations )) {
$document -> setAttribute ( $relationship -> getAttribute ( 'key' ), null );
2023-03-27 15:42:36 +13:00
}
}
2023-03-28 22:02:49 +13:00
return true ;
2023-03-27 15:42:36 +13:00
};
2023-05-24 22:09:08 +12:00
// The linter is forcing this indentation
2023-04-19 12:37:41 +12:00
foreach ( $documents as $document ) {
$processDocument ( $collection , $document );
2023-03-27 15:56:11 +13:00
}
2021-12-27 23:45:24 +13:00
2021-07-26 02:47:18 +12:00
$response -> dynamic ( new Document ([
2022-02-27 22:57:09 +13:00
'total' => $total ,
2021-08-12 13:26:31 +12:00
'documents' => $documents ,
2021-06-15 07:55:36 +12:00
]), Response :: MODEL_DOCUMENT_LIST );
2020-12-27 04:05:04 +13:00
});
2019-05-09 18:54:39 +12:00
2022-06-22 22:51:49 +12:00
App :: get ( '/v1/databases/:databaseId/collections/:collectionId/documents/:documentId' )
2022-06-23 20:50:11 +12:00
-> alias ( '/v1/database/collections/:collectionId/documents/:documentId' , [ 'databaseId' => 'default' ])
2019-05-09 18:54:39 +12:00
-> desc ( 'Get Document' )
2020-06-26 06:32:12 +12:00
-> groups ([ 'api' , 'database' ])
2019-06-09 01:13:19 +12:00
-> label ( 'scope' , 'documents.read' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'documents.{scope}.requests.read' )
2022-08-21 14:10:21 +12:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' , 'collectionId:{request.collectionId}' ])
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_SESSION , APP_AUTH_TYPE_KEY , APP_AUTH_TYPE_JWT ])
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.namespace' , 'databases' )
2019-05-09 18:54:39 +12:00
-> label ( 'sdk.method' , 'getDocument' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/get-document.md' )
2020-11-12 10:02:24 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2021-04-08 20:39:23 +12:00
-> label ( 'sdk.response.model' , Response :: MODEL_DOCUMENT )
2023-02-10 14:06:33 +13:00
-> label ( 'sdk.offline.model' , '/databases/{databaseId}/collections/{collectionId}/documents' )
-> label ( 'sdk.offline.key' , '{documentId}' )
2022-06-22 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-09-19 22:05:42 +12: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.' )
2023-03-23 17:32:44 +13: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). Only method allowed is select.' , true )
2020-12-27 04:05:04 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2021-12-14 01:42:04 +13:00
-> inject ( 'mode' )
2023-03-23 10:10:47 +13:00
-> action ( function ( string $databaseId , string $collectionId , string $documentId , array $queries , Response $response , Database $dbForProject , string $mode ) {
2023-05-24 22:09:08 +12:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2019-05-09 18:54:39 +12:00
2023-05-24 22:09:08 +12:00
if ( $database -> isEmpty () || ( ! $database -> getAttribute ( 'enabled' ) && $mode !== APP_MODE_ADMIN )) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 22:51:49 +12:00
}
2022-08-08 22:58:28 +12:00
2022-06-22 22:51:49 +12:00
$collection = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId ));
2019-05-09 18:54:39 +12:00
2021-12-18 01:51:07 +13:00
if ( $collection -> isEmpty () || ! $collection -> getAttribute ( 'enabled' )) {
if ( ! ( $mode === APP_MODE_ADMIN && Auth :: isPrivilegedUser ( Authorization :: getRoles ()))) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-12-18 01:51:07 +13:00
}
2021-06-11 06:19:42 +12:00
}
2023-03-23 17:32:44 +13:00
// Validate queries
2023-04-28 00:10:07 +12:00
$queriesValidator = new DocumentQueriesValidator ( $collection -> getAttribute ( 'attributes' ));
2023-03-23 17:32:44 +13:00
$validQueries = $queriesValidator -> isValid ( $queries );
if ( ! $validQueries ) {
throw new Exception ( Exception :: GENERAL_ARGUMENT_INVALID , $queriesValidator -> getDescription ());
}
2023-03-23 17:55:31 +13:00
$queries = Query :: parseQueries ( $queries );
2023-04-19 12:37:41 +12:00
$document = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (), $documentId , $queries );
2022-08-08 22:58:28 +12:00
if ( $document -> isEmpty ()) {
2022-08-16 21:07:30 +12:00
throw new Exception ( Exception :: DOCUMENT_NOT_FOUND );
2022-08-08 22:58:28 +12:00
}
2023-03-27 19:03:00 +13:00
// Add $collectionId and $databaseId for all documents
2023-03-28 22:02:49 +13:00
$processDocument = function ( Document $collection , Document $document ) use ( & $processDocument , $dbForProject , $database ) {
2023-04-19 12:37:41 +12:00
if ( $document -> isEmpty ()) {
return ;
2023-03-28 22:02:49 +13:00
}
2023-03-27 19:03:00 +13:00
$document -> setAttribute ( '$databaseId' , $database -> getId ());
$document -> setAttribute ( '$collectionId' , $collection -> getId ());
$relationships = \array_filter (
$collection -> getAttribute ( 'attributes' , []),
2023-07-18 23:16:33 +12:00
fn ( $attribute ) => $attribute -> getAttribute ( 'type' ) === Database :: VAR_RELATIONSHIP
2023-03-27 19:03:00 +13:00
);
2023-03-28 16:10:12 +13:00
foreach ( $relationships as $relationship ) {
$related = $document -> getAttribute ( $relationship -> getAttribute ( 'key' ));
if ( empty ( $related )) {
2023-03-27 19:03:00 +13:00
continue ;
}
2023-03-28 16:10:12 +13:00
if ( ! \is_array ( $related )) {
$related = [ $related ];
}
2023-03-27 19:03:00 +13:00
2023-03-28 16:10:12 +13:00
$relatedCollectionId = $relationship -> getAttribute ( 'relatedCollection' );
$relatedCollection = Authorization :: skip (
fn () => $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $relatedCollectionId )
);
2023-03-27 15:42:36 +13:00
2023-03-29 14:37:56 +13:00
foreach ( $related as $relation ) {
2023-04-03 22:39:31 +12:00
if ( $relation instanceof Document ) {
$processDocument ( $relatedCollection , $relation );
}
2023-03-27 15:42:36 +13:00
}
}
};
2023-03-27 19:03:00 +13:00
2023-03-28 22:02:49 +13:00
$processDocument ( $collection , $document );
2021-12-27 23:45:24 +13:00
2021-07-26 02:47:18 +12:00
$response -> dynamic ( $document , Response :: MODEL_DOCUMENT );
2020-12-27 04:05:04 +13:00
});
2019-05-09 18:54:39 +12:00
2022-06-22 22:51:49 +12:00
App :: get ( '/v1/databases/:databaseId/collections/:collectionId/documents/:documentId/logs' )
2022-06-23 20:50:11 +12:00
-> alias ( '/v1/database/collections/:collectionId/documents/:documentId/logs' , [ 'databaseId' => 'default' ])
2021-08-29 19:43:09 +12:00
-> desc ( 'List Document Logs' )
-> groups ([ 'api' , 'database' ])
-> label ( 'scope' , 'documents.read' )
2022-08-21 14:10:21 +12:00
-> label ( 'usage.metric' , 'documents.{scope}.requests.read' )
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' , 'collectionId:{request.collectionId}' ])
2021-08-29 19:43:09 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_ADMIN ])
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.namespace' , 'databases' )
2021-08-29 19:43:09 +12:00
-> label ( 'sdk.method' , 'listDocumentLogs' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/get-document-logs.md' )
2021-08-29 19:43:09 +12: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 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2021-12-11 01:27:11 +13:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID.' )
2022-09-19 22:05:42 +12:00
-> param ( 'documentId' , '' , new UID (), 'Document ID.' )
2023-05-17 00:56:20 +12: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/queries). Only supported methods are limit and offset' , true )
2021-08-29 19:43:09 +12:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2021-08-29 19:43:09 +12:00
-> inject ( 'locale' )
-> inject ( 'geodb' )
2022-08-24 01:03:38 +12:00
-> action ( function ( string $databaseId , string $collectionId , string $documentId , array $queries , Response $response , Database $dbForProject , Locale $locale , Reader $geodb ) {
2021-08-29 19:43:09 +12:00
2023-05-24 22:09:08 +12:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2022-06-22 22:51:49 +12:00
if ( $database -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 22:51:49 +12:00
}
2022-08-25 13:04:47 +12:00
2022-06-22 22:51:49 +12:00
$collection = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId );
2021-08-29 19:43:09 +12:00
if ( $collection -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-08-29 19:43:09 +12:00
}
2022-06-22 22:51:49 +12:00
$document = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (), $documentId );
2021-08-29 19:43:09 +12:00
if ( $document -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DOCUMENT_NOT_FOUND );
2021-08-29 19:43:09 +12:00
}
2022-08-24 01:03:38 +12:00
$queries = Query :: parseQueries ( $queries );
$grouped = Query :: groupByType ( $queries );
2022-08-30 23:55:23 +12:00
$limit = $grouped [ 'limit' ] ? ? APP_LIMIT_COUNT ;
2022-08-24 01:03:38 +12:00
$offset = $grouped [ 'offset' ] ? ? 0 ;
2021-12-28 01:45:23 +13:00
$audit = new Audit ( $dbForProject );
2022-06-22 22:51:49 +12:00
$resource = 'database/' . $databaseId . '/collection/' . $collectionId . '/document/' . $document -> getId ();
2021-11-18 23:33:42 +13:00
$logs = $audit -> getLogsByResource ( $resource , $limit , $offset );
2021-08-29 19:43:09 +12:00
$output = [];
foreach ( $logs as $i => & $log ) {
$log [ 'userAgent' ] = ( ! empty ( $log [ 'userAgent' ])) ? $log [ 'userAgent' ] : 'UNKNOWN' ;
2021-12-13 06:59:12 +13: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 19:43:09 +12:00
2021-12-13 06:59:12 +13:00
$os = $detector -> getOS ();
$client = $detector -> getClient ();
$device = $detector -> getDevice ();
2021-08-29 19:43:09 +12: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-13 06:59:12 +13: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 19:43:09 +12:00
]);
$record = $geodb -> get ( $log [ 'ip' ]);
if ( $record ) {
2022-05-24 02:54:50 +12: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 19:43:09 +12:00
} else {
$output [ $i ][ 'countryCode' ] = '--' ;
$output [ $i ][ 'countryName' ] = $locale -> getText ( 'locale.country.unknown' );
}
}
2021-11-18 23:33:42 +13:00
$response -> dynamic ( new Document ([
2022-02-27 22:57:09 +13:00
'total' => $audit -> countLogsByResource ( $resource ),
2021-11-18 23:33:42 +13:00
'logs' => $output ,
]), Response :: MODEL_LOG_LIST );
2021-08-29 19:43:09 +12:00
});
2022-06-22 22:51:49 +12:00
App :: patch ( '/v1/databases/:databaseId/collections/:collectionId/documents/:documentId' )
2022-06-23 20:50:11 +12:00
-> alias ( '/v1/database/collections/:collectionId/documents/:documentId' , [ 'databaseId' => 'default' ])
2019-05-09 18:54:39 +12:00
-> desc ( 'Update Document' )
2020-06-26 06:32:12 +12:00
-> groups ([ 'api' , 'database' ])
2022-06-22 22:51:49 +12:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].documents.[documentId].update' )
2019-06-09 01:13:19 +12:00
-> label ( 'scope' , 'documents.write' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'document.update' )
2022-08-09 02:32:54 +12:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}/document/{response.$id}' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'documents.{scope}.requests.update' )
2022-08-21 14:10:21 +12:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' , 'collectionId:{request.collectionId}' ])
2022-08-31 15:58:32 +12:00
-> label ( 'abuse-key' , 'ip:{ip},method:{method},url:{url},userId:{userId}' )
2022-08-31 11:34:17 +12:00
-> label ( 'abuse-limit' , APP_LIMIT_WRITE_RATE_DEFAULT * 2 )
-> label ( 'abuse-time' , APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT )
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_SESSION , APP_AUTH_TYPE_KEY , APP_AUTH_TYPE_JWT ])
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.namespace' , 'databases' )
2019-05-09 18:54:39 +12:00
-> label ( 'sdk.method' , 'updateDocument' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/update-document.md' )
2020-11-12 10:02:24 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_OK )
-> label ( 'sdk.response.type' , Response :: CONTENT_TYPE_JSON )
2021-04-08 20:39:23 +12:00
-> label ( 'sdk.response.model' , Response :: MODEL_DOCUMENT )
2023-02-10 14:06:33 +13:00
-> label ( 'sdk.offline.model' , '/databases/{databaseId}/collections/{collectionId}/documents' )
-> label ( 'sdk.offline.key' , '{documentId}' )
2022-06-22 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-09-19 22:05:42 +12:00
-> param ( 'collectionId' , '' , new UID (), 'Collection ID.' )
-> param ( 'documentId' , '' , new UID (), 'Document ID.' )
2022-06-09 12:49:27 +12:00
-> param ( 'data' , [], new JSON (), 'Document data as JSON object. Include only attribute and value pairs to be updated.' , true )
2022-12-21 10:43:55 +13: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 )
2023-01-20 13:36:17 +13:00
-> inject ( 'requestTimestamp' )
2020-12-27 04:05:04 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2021-12-17 07:12:06 +13:00
-> inject ( 'events' )
2021-12-14 01:42:04 +13:00
-> inject ( 'mode' )
2023-01-20 13:36:17 +13:00
-> action ( function ( string $databaseId , string $collectionId , string $documentId , string | array $data , ? array $permissions , ? \DateTime $requestTimestamp , Response $response , Database $dbForProject , Event $events , string $mode ) {
2019-05-09 18:54:39 +12:00
2022-08-08 22:58:28 +12:00
$data = ( \is_string ( $data )) ? \json_decode ( $data , true ) : $data ; // Cast to JSON array
2022-08-14 17:21:33 +12:00
if ( empty ( $data ) && \is_null ( $permissions )) {
2022-08-16 21:07:30 +12:00
throw new Exception ( Exception :: DOCUMENT_MISSING_PAYLOAD );
2022-08-08 22:58:28 +12:00
}
2023-05-24 22:09:08 +12:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2022-06-22 22:51:49 +12:00
2023-05-24 22:09:08 +12:00
if ( $database -> isEmpty () || ( ! $database -> getAttribute ( 'enabled' ) && $mode !== APP_MODE_ADMIN )) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 22:51:49 +12:00
}
2022-08-08 22:58:28 +12:00
2022-06-22 22:51:49 +12:00
$collection = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId ));
2019-09-17 07:03:24 +12:00
2021-12-18 01:51:07 +13:00
if ( $collection -> isEmpty () || ! $collection -> getAttribute ( 'enabled' )) {
if ( ! ( $mode === APP_MODE_ADMIN && Auth :: isPrivilegedUser ( Authorization :: getRoles ()))) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-12-18 01:51:07 +13:00
}
2020-06-30 09:43:34 +12:00
}
2019-05-09 18:54:39 +12:00
2022-08-25 13:04:47 +12:00
// Read permission should not be required for update
2023-03-28 16:10:12 +13:00
/** @var Document $document */
2022-08-24 20:50:05 +12:00
$document = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (), $documentId ));
2021-06-16 01:38:24 +12:00
if ( $document -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DOCUMENT_NOT_FOUND );
2020-06-30 09:43:34 +12:00
}
2019-05-09 18:54:39 +12:00
2022-08-25 15:51:21 +12: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-16 00:56:19 +12:00
// Users can only manage their own roles, API keys and Admin users can manage any
2022-08-08 22:58:28 +12:00
$roles = Authorization :: getRoles ();
2022-08-16 00:56:19 +12:00
if ( ! Auth :: isAppUser ( $roles ) && ! Auth :: isPrivilegedUser ( $roles ) && ! \is_null ( $permissions )) {
foreach ( Database :: PERMISSIONS as $type ) {
foreach ( $permissions as $permission ) {
2022-08-16 23:26:38 +12:00
$permission = Permission :: parse ( $permission );
if ( $permission -> getPermission () != $type ) {
2022-08-16 00:56:19 +12:00
continue ;
}
2022-08-16 23:26:38 +12:00
$role = ( new Role (
$permission -> getRole (),
$permission -> getIdentifier (),
$permission -> getDimension ()
)) -> toString ();
2022-08-16 00:56:19 +12:00
if ( ! Authorization :: isRole ( $role )) {
2022-08-25 15:51:21 +12:00
throw new Exception ( Exception :: USER_UNAUTHORIZED , 'Permissions must be one of: (' . \implode ( ', ' , $roles ) . ')' );
2022-08-16 00:56:19 +12:00
}
2022-08-08 22:58:28 +12:00
}
}
}
2022-08-02 21:18:49 +12:00
2022-08-25 23:46:56 +12:00
if ( \is_null ( $permissions )) {
$permissions = $document -> getPermissions () ? ? [];
}
2023-05-02 19:53:11 +12:00
$data = \array_merge ( $document -> getArrayCopy (), $data ); // Merge existing data with new data
2022-08-08 22:58:28 +12:00
$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 21:18:49 +12:00
$data [ '$permissions' ] = $permissions ;
2023-03-28 22:02:49 +13:00
$newDocument = new Document ( $data );
2020-10-31 08:53:27 +13:00
2023-07-18 23:16:33 +12:00
$checkPermissions = function ( Document $collection , Document $document , Document $old , string $permission ) use ( & $checkPermissions , $dbForProject , $database ) {
2023-03-28 22:02:49 +13:00
$documentSecurity = $collection -> getAttribute ( 'documentSecurity' , false );
$validator = new Authorization ( $permission );
$valid = $validator -> isValid ( $collection -> getPermissionsByType ( $permission ));
if ( ! $documentSecurity && ! $valid ) {
throw new Exception ( Exception :: USER_UNAUTHORIZED );
}
if ( $permission === Database :: PERMISSION_UPDATE ) {
$valid = $valid || $validator -> isValid ( $old -> getPermissionsByType ( $permission ));
if ( $documentSecurity && ! $valid ) {
throw new Exception ( Exception :: USER_UNAUTHORIZED );
}
}
2023-07-18 23:16:33 +12:00
$relationships = \array_filter (
2023-03-28 22:02:49 +13:00
$collection -> getAttribute ( 'attributes' , []),
2023-07-18 23:16:33 +12:00
function ( Document $attribute ) {
return $attribute -> getAttribute ( 'type' ) === Database :: VAR_RELATIONSHIP ;
2023-07-14 04:58:08 +12:00
}
2023-03-28 22:02:49 +13:00
);
foreach ( $relationships as $relationship ) {
$related = $document -> getAttribute ( $relationship -> getAttribute ( 'key' ));
if ( empty ( $related )) {
continue ;
}
2023-04-13 15:59:57 +12:00
2023-04-14 22:03:16 +12:00
$isList = \is_array ( $related ) && \array_values ( $related ) === $related ;
if ( $isList ) {
2023-04-13 15:59:57 +12:00
$relations = $related ;
} else {
$relations = [ $related ];
2023-03-29 14:33:53 +13:00
}
2023-03-28 22:02:49 +13:00
$relatedCollectionId = $relationship -> getAttribute ( 'relatedCollection' );
$relatedCollection = Authorization :: skip (
fn () => $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $relatedCollectionId )
2023-01-20 13:36:17 +13:00
);
2023-03-28 22:02:49 +13:00
2023-04-19 12:37:41 +12:00
foreach ( $relations as & $relation ) {
2023-07-18 23:16:33 +12:00
$skipCheckingPermission = false ;
// If the relation is an array it can be either update or create a child document.
2023-04-13 15:59:57 +12:00
if (
\is_array ( $relation )
&& \array_values ( $relation ) !== $relation
&& ! isset ( $relation [ '$id' ])
) {
$relation [ '$id' ] = ID :: unique ();
$relation = new Document ( $relation );
}
2023-03-29 14:37:56 +13:00
if ( $relation instanceof Document ) {
2023-07-18 23:16:33 +12:00
$relatedDocumentOldVersion = Authorization :: skip ( fn () => $dbForProject -> getDocument (
2023-03-28 22:02:49 +13:00
'database_' . $database -> getInternalId () . '_collection_' . $relatedCollection -> getInternalId (),
2023-03-29 14:37:56 +13:00
$relation -> getId ()
2023-03-28 22:02:49 +13:00
));
2023-03-31 17:33:21 +13:00
2023-07-18 23:16:33 +12:00
// If the child document has to be created it will need checking permissions.
if ( $relatedDocumentOldVersion -> isEmpty ()) {
2023-03-31 17:33:21 +13:00
$type = Database :: PERMISSION_CREATE ;
2023-04-13 15:59:57 +12:00
if ( isset ( $relation [ '$id' ]) && $relation [ '$id' ] === 'unique()' ) {
2023-03-31 17:33:21 +13:00
$relation [ '$id' ] = ID :: unique ();
}
} else {
$type = Database :: PERMISSION_UPDATE ;
2023-07-18 23:16:33 +12:00
$skipCheckingPermission = true ;
foreach ( $relation as $key => $value ) {
//No need to compare values of relations as for each relation we are recursively checking permission.
if ( $relatedDocumentOldVersion -> getAttribute ( $key ) instanceof Document ) {
continue ;
}
//If any of the values are different, we need to check permission.
if ( $relatedDocumentOldVersion -> getAttribute ( $key ) !== $value ) {
$skipCheckingPermission = false ;
$relation -> removeAttribute ( '$collectionId' );
$relation -> removeAttribute ( '$databaseId' );
$relation -> setAttribute ( '$collection' , $relatedCollection -> getId ());
break ;
}
}
}
if ( $skipCheckingPermission ) {
Authorization :: skip (
fn () => $checkPermissions ( $relatedCollection , $relation , $relatedDocumentOldVersion , $type )
);
} else {
$checkPermissions ( $relatedCollection , $relation , $relatedDocumentOldVersion , $type );
2023-03-31 17:33:21 +13:00
}
2023-03-28 22:02:49 +13:00
}
}
2023-04-13 15:59:57 +12:00
2023-04-14 22:03:16 +12:00
if ( $isList ) {
2023-04-13 15:59:57 +12:00
$document -> setAttribute ( $relationship -> getAttribute ( 'key' ), \array_values ( $relations ));
} else {
$document -> setAttribute ( $relationship -> getAttribute ( 'key' ), \reset ( $relations ));
}
2022-08-24 20:50:05 +12:00
}
2023-03-28 22:02:49 +13:00
};
2023-07-18 23:16:33 +12:00
$skipCheckingPermission = true ;
foreach ( $newDocument as $key => $value ) {
if ( $document -> getAttribute ( $key ) instanceof Document ) {
continue ;
}
//If any of the values are different, we need to check permission.
if ( $newDocument -> getAttribute ( $key ) !== $value ) {
$skipCheckingPermission = false ;
$newDocument -> removeAttribute ( '$collectionId' );
$newDocument -> removeAttribute ( '$databaseId' );
$newDocument -> setAttribute ( '$collection' , $collection -> getId ());
break ;
}
}
if ( $skipCheckingPermission ) {
Authorization :: skip (
fn () => $checkPermissions ( $collection , $newDocument , $document , Database :: PERMISSION_UPDATE )
);
} else {
2023-03-28 22:02:49 +13:00
$checkPermissions ( $collection , $newDocument , $document , Database :: PERMISSION_UPDATE );
2023-07-18 23:16:33 +12:00
;
}
2023-03-28 22:02:49 +13:00
try {
2023-04-19 12:37:41 +12:00
$document = $dbForProject -> withRequestTimestamp (
2023-03-28 22:02:49 +13:00
$requestTimestamp ,
2023-05-24 22:09:08 +12:00
fn () => $dbForProject -> updateDocument (
2023-03-28 22:02:49 +13:00
'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (),
$document -> getId (),
$newDocument
)
2023-04-19 12:37:41 +12:00
);
2023-03-28 22:02:49 +13:00
} catch ( AuthorizationException ) {
throw new Exception ( Exception :: USER_UNAUTHORIZED );
} catch ( DuplicateException ) {
throw new Exception ( Exception :: DOCUMENT_ALREADY_EXISTS );
} catch ( StructureException $exception ) {
throw new Exception ( Exception :: DOCUMENT_INVALID_STRUCTURE , $exception -> getMessage ());
}
2021-12-17 07:12:06 +13:00
2023-03-27 19:03:00 +13:00
// Add $collectionId and $databaseId for all documents
2023-03-28 22:02:49 +13:00
$processDocument = function ( Document $collection , Document $document ) use ( & $processDocument , $dbForProject , $database ) {
2023-03-27 19:03:00 +13:00
$document -> setAttribute ( '$databaseId' , $database -> getId ());
$document -> setAttribute ( '$collectionId' , $collection -> getId ());
2023-03-27 15:42:36 +13:00
2023-03-27 19:03:00 +13:00
$relationships = \array_filter (
$collection -> getAttribute ( 'attributes' , []),
2023-05-24 22:09:08 +12:00
fn ( $attribute ) => $attribute -> getAttribute ( 'type' ) === Database :: VAR_RELATIONSHIP
2023-03-27 19:03:00 +13:00
);
2023-03-28 16:10:12 +13:00
foreach ( $relationships as $relationship ) {
$related = $document -> getAttribute ( $relationship -> getAttribute ( 'key' ));
if ( empty ( $related )) {
2023-03-27 20:08:02 +13:00
continue ;
}
2023-03-28 16:10:12 +13:00
if ( ! \is_array ( $related )) {
$related = [ $related ];
}
2023-03-27 19:03:00 +13:00
2023-03-28 16:10:12 +13:00
$relatedCollectionId = $relationship -> getAttribute ( 'relatedCollection' );
$relatedCollection = Authorization :: skip (
fn () => $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $relatedCollectionId )
);
2023-03-27 20:08:02 +13:00
2023-03-29 14:37:56 +13:00
foreach ( $related as $relation ) {
2023-04-03 22:39:31 +12:00
if ( $relation instanceof Document ) {
$processDocument ( $relatedCollection , $relation );
}
2023-03-27 15:42:36 +13:00
}
}
};
2023-03-27 19:03:00 +13:00
2023-03-28 22:02:49 +13:00
$processDocument ( $collection , $document );
2023-03-27 15:42:36 +13:00
2022-04-14 00:39:31 +12:00
$events
2022-06-22 22:51:49 +12:00
-> setParam ( 'databaseId' , $databaseId )
2022-04-14 00:39:31 +12:00
-> setParam ( 'collectionId' , $collection -> getId ())
-> setParam ( 'documentId' , $document -> getId ())
2022-06-22 22:51:49 +12:00
-> setContext ( 'collection' , $collection )
2023-05-24 22:09:08 +12:00
-> setContext ( 'database' , $database );
2021-12-17 07:12:06 +13:00
2021-07-26 02:47:18 +12:00
$response -> dynamic ( $document , Response :: MODEL_DOCUMENT );
2020-12-27 04:05:04 +13:00
});
2019-05-09 18:54:39 +12:00
2022-06-22 22:51:49 +12:00
App :: delete ( '/v1/databases/:databaseId/collections/:collectionId/documents/:documentId' )
2022-06-23 20:50:11 +12:00
-> alias ( '/v1/database/collections/:collectionId/documents/:documentId' , [ 'databaseId' => 'default' ])
2019-05-09 18:54:39 +12:00
-> desc ( 'Delete Document' )
2020-06-26 06:32:12 +12:00
-> groups ([ 'api' , 'database' ])
2019-06-09 01:13:19 +12:00
-> label ( 'scope' , 'documents.write' )
2022-06-22 22:51:49 +12:00
-> label ( 'event' , 'databases.[databaseId].collections.[collectionId].documents.[documentId].delete' )
2022-09-05 20:00:08 +12:00
-> label ( 'audits.event' , 'document.delete' )
2022-08-09 02:32:54 +12:00
-> label ( 'audits.resource' , 'database/{request.databaseId}/collection/{request.collectionId}/document/{request.documentId}' )
2022-08-10 14:18:18 +12:00
-> label ( 'usage.metric' , 'documents.{scope}.requests.delete' )
2022-08-21 14:10:21 +12:00
-> label ( 'usage.params' , [ 'databaseId:{request.databaseId}' , 'collectionId:{request.collectionId}' ])
2022-08-31 15:58:32 +12:00
-> label ( 'abuse-key' , 'ip:{ip},method:{method},url:{url},userId:{userId}' )
2022-08-31 11:34:17 +12:00
-> label ( 'abuse-limit' , APP_LIMIT_WRITE_RATE_DEFAULT )
-> label ( 'abuse-time' , APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT )
2021-04-16 19:22:17 +12:00
-> label ( 'sdk.auth' , [ APP_AUTH_TYPE_SESSION , APP_AUTH_TYPE_KEY , APP_AUTH_TYPE_JWT ])
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.namespace' , 'databases' )
2019-05-09 18:54:39 +12:00
-> label ( 'sdk.method' , 'deleteDocument' )
2022-06-22 22:51:49 +12:00
-> label ( 'sdk.description' , '/docs/references/databases/delete-document.md' )
2020-11-12 10:02:24 +13:00
-> label ( 'sdk.response.code' , Response :: STATUS_CODE_NOCONTENT )
-> label ( 'sdk.response.model' , Response :: MODEL_NONE )
2023-02-10 14:06:33 +13:00
-> label ( 'sdk.offline.model' , '/databases/{databaseId}/collections/{collectionId}/documents' )
-> label ( 'sdk.offline.key' , '{documentId}' )
2022-06-22 22:51:49 +12:00
-> param ( 'databaseId' , '' , new UID (), 'Database ID.' )
2022-09-19 22:05:42 +12: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.' )
2023-01-20 13:36:17 +13:00
-> inject ( 'requestTimestamp' )
2020-12-27 04:05:04 +13:00
-> inject ( 'response' )
2021-12-28 01:45:23 +13:00
-> inject ( 'dbForProject' )
2020-12-27 04:05:04 +13:00
-> inject ( 'events' )
2022-01-03 23:29:15 +13:00
-> inject ( 'deletes' )
2021-12-14 01:42:04 +13:00
-> inject ( 'mode' )
2023-01-20 13:36:17 +13:00
-> action ( function ( string $databaseId , string $collectionId , string $documentId , ? \DateTime $requestTimestamp , Response $response , Database $dbForProject , Event $events , Delete $deletes , string $mode ) {
2022-06-22 22:51:49 +12:00
2023-05-24 22:09:08 +12:00
$database = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'databases' , $databaseId ));
2019-05-09 18:54:39 +12:00
2023-05-24 22:09:08 +12:00
if ( $database -> isEmpty () || ( ! $database -> getAttribute ( 'enabled' ) && $mode !== APP_MODE_ADMIN )) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DATABASE_NOT_FOUND );
2022-06-22 22:51:49 +12:00
}
2022-08-08 22:58:28 +12:00
2022-06-22 22:51:49 +12:00
$collection = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId ));
2019-05-09 18:54:39 +12:00
2021-12-18 01:51:07 +13:00
if ( $collection -> isEmpty () || ! $collection -> getAttribute ( 'enabled' )) {
if ( ! ( $mode === APP_MODE_ADMIN && Auth :: isPrivilegedUser ( Authorization :: getRoles ()))) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2021-12-18 01:51:07 +13:00
}
2020-06-30 09:43:34 +12:00
}
2022-08-25 13:04:47 +12:00
// Read permission should not be required for delete
2022-08-24 20:50:05 +12:00
$document = Authorization :: skip ( fn () => $dbForProject -> getDocument ( 'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (), $documentId ));
2021-06-11 06:19:42 +12:00
if ( $document -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: DOCUMENT_NOT_FOUND );
2020-06-30 09:43:34 +12:00
}
2019-05-09 18:54:39 +12:00
2023-03-28 22:02:49 +13:00
$checkPermissions = function ( Document $collection , Document $document ) use ( & $checkPermissions , $dbForProject , $database ) {
$documentSecurity = $collection -> getAttribute ( 'documentSecurity' , false );
$validator = new Authorization ( Database :: PERMISSION_DELETE );
2023-01-20 13:36:17 +13:00
2023-03-28 22:02:49 +13:00
$valid = $validator -> isValid ( $collection -> getDelete ());
if ( ! $documentSecurity && ! $valid ) {
2022-08-25 23:30:26 +12:00
throw new Exception ( Exception :: USER_UNAUTHORIZED );
}
2022-08-08 22:58:28 +12:00
2023-03-28 22:02:49 +13:00
$valid = $valid || $validator -> isValid ( $document -> getDelete ());
if ( $documentSecurity && ! $valid ) {
throw new Exception ( Exception :: USER_UNAUTHORIZED );
}
$relationships = \array_filter (
$collection -> getAttribute ( 'attributes' , []),
2023-05-24 22:09:08 +12:00
fn ( $attribute ) => $attribute -> getAttribute ( 'type' ) === Database :: VAR_RELATIONSHIP
2023-03-28 22:02:49 +13:00
);
foreach ( $relationships as $relationship ) {
$related = $document -> getAttribute ( $relationship -> getAttribute ( 'key' ));
if ( empty ( $related )) {
continue ;
}
2023-03-29 14:33:53 +13:00
if ( ! \is_array ( $related )) {
$related = [ $related ];
}
2023-03-28 22:02:49 +13:00
$relatedCollectionId = $relationship -> getAttribute ( 'relatedCollection' );
$relatedCollection = Authorization :: skip (
fn () => $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $relatedCollectionId )
);
2023-03-29 16:30:47 +13:00
foreach ( $related as $relation ) {
2023-03-28 22:02:49 +13:00
if (
2023-03-29 16:30:47 +13:00
$relation instanceof Document
2023-03-28 22:02:49 +13:00
&& $relationship -> getAttribute ( 'onDelete' ) === Database :: RELATION_MUTATE_CASCADE
) {
2023-03-29 16:30:47 +13:00
$checkPermissions ( $relatedCollection , $relation );
2023-03-28 22:02:49 +13:00
}
}
}
};
$checkPermissions ( $collection , $document );
2023-05-24 22:09:08 +12:00
Authorization :: skip ( fn () => $dbForProject -> withRequestTimestamp ( $requestTimestamp , function () use ( $dbForProject , $database , $collection , $documentId ) {
2023-04-06 00:54:44 +12:00
try {
$dbForProject -> deleteDocument (
'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (),
$documentId
);
} catch ( RestrictedException ) {
throw new Exception ( Exception :: DOCUMENT_DELETE_RESTRICTED );
}
}));
2023-03-28 22:02:49 +13:00
$dbForProject -> deleteCachedDocument (
'database_' . $database -> getInternalId () . '_collection_' . $collection -> getInternalId (),
$documentId
);
2021-06-11 06:19:42 +12:00
2023-03-27 19:03:00 +13:00
// Add $collectionId and $databaseId for all documents
2023-03-28 22:02:49 +13:00
$processDocument = function ( Document $collection , Document $document ) use ( & $processDocument , $dbForProject , $database ) {
2023-03-27 19:03:00 +13:00
$document -> setAttribute ( '$databaseId' , $database -> getId ());
$document -> setAttribute ( '$collectionId' , $collection -> getId ());
$relationships = \array_filter (
$collection -> getAttribute ( 'attributes' , []),
2023-05-24 22:09:08 +12:00
fn ( $attribute ) => $attribute -> getAttribute ( 'type' ) === Database :: VAR_RELATIONSHIP
2023-03-27 19:03:00 +13:00
);
2023-03-28 16:10:12 +13:00
foreach ( $relationships as $relationship ) {
$related = $document -> getAttribute ( $relationship -> getAttribute ( 'key' ));
if ( empty ( $related )) {
2023-03-27 19:03:00 +13:00
continue ;
}
2023-03-28 16:10:12 +13:00
if ( ! \is_array ( $related )) {
$related = [ $related ];
}
2023-03-27 19:03:00 +13:00
2023-03-28 16:10:12 +13:00
$relatedCollectionId = $relationship -> getAttribute ( 'relatedCollection' );
$relatedCollection = Authorization :: skip (
fn () => $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $relatedCollectionId )
);
2023-03-27 15:42:36 +13:00
2023-03-29 16:30:47 +13:00
foreach ( $related as $relation ) {
2023-04-03 22:39:31 +12:00
if ( $relation instanceof Document ) {
$processDocument ( $relatedCollection , $relation );
}
2023-03-27 15:42:36 +13:00
}
}
};
2023-03-27 19:03:00 +13:00
2023-03-28 22:02:49 +13:00
$processDocument ( $collection , $document );
2021-12-27 23:45:24 +13:00
2022-01-03 23:29:15 +13:00
$deletes
2022-04-18 08:34:32 +12:00
-> setType ( DELETE_TYPE_AUDIT )
2023-05-24 22:09:08 +12:00
-> setDocument ( $document );
2022-01-03 23:29:15 +13:00
2020-12-07 11:14:57 +13:00
$events
2022-06-22 22:51:49 +12:00
-> setParam ( 'databaseId' , $databaseId )
2022-04-14 00:39:31 +12:00
-> setParam ( 'collectionId' , $collection -> getId ())
-> setParam ( 'documentId' , $document -> getId ())
2022-06-22 22:51:49 +12:00
-> setContext ( 'collection' , $collection )
-> setContext ( 'database' , $database )
2023-05-24 22:09:08 +12:00
-> setPayload ( $response -> output ( $document , Response :: MODEL_DOCUMENT ));
2021-04-14 21:02:17 +12:00
2020-06-30 09:43:34 +12:00
$response -> noContent ();
2021-08-25 02:03:32 +12:00
});
2022-06-22 22:51:49 +12:00
App :: get ( '/v1/databases/usage' )
2022-06-23 20:50:11 +12:00
-> desc ( 'Get usage stats for the database' )
2023-04-22 05:39:01 +12:00
-> groups ([ 'api' , 'database' , 'usage' ])
2022-06-23 20:50:11 +12:00
-> 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 19:30:26 +13:00
'period' => '1h' ,
'limit' => 24 ,
2022-06-23 20:50:11 +12:00
],
'7d' => [
'period' => '1d' ,
'limit' => 7 ,
],
'30d' => [
'period' => '1d' ,
'limit' => 30 ,
],
'90d' => [
'period' => '1d' ,
'limit' => 90 ,
],
];
$metrics = [
2022-08-09 18:28:38 +12: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 20:50:11 +12: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-12 11:53:52 +12:00
Query :: equal ( 'period' , [ $period ]),
Query :: equal ( 'metric' , [ $metric ]),
Query :: limit ( $limit ),
Query :: orderDesc ( 'time' ),
]);
2022-06-23 20:50:11 +12:00
$stats [ $metric ] = [];
foreach ( $requestDocs as $requestDoc ) {
$stats [ $metric ][] = [
'value' => $requestDoc -> getAttribute ( 'value' ),
'date' => $requestDoc -> getAttribute ( 'time' ),
];
}
2022-06-22 22:51:49 +12:00
2022-06-23 20:50:11 +12: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 19:33:14 +13:00
'1h' => 3600 ,
2022-06-23 20:50:11 +12:00
'1d' => 86400 ,
};
$stats [ $metric ][] = [
'value' => 0 ,
2022-09-16 11:48:09 +12:00
'date' => DateTime :: formatTz ( DateTime :: addSeconds ( new \DateTime ( $stats [ $metric ][ $last ][ 'date' ] ? ? null ), - 1 * $diff )),
2022-06-23 20:50:11 +12:00
];
$backfill -- ;
}
2022-07-12 03:12:41 +12:00
// Added 3'rd level to Index [period, metric, time] because of order by.
2022-06-23 20:50:11 +12:00
$stats [ $metric ] = array_reverse ( $stats [ $metric ]);
2022-06-22 22:51:49 +12:00
}
2022-06-23 20:50:11 +12:00
});
$usage = new Document ([
'range' => $range ,
2022-08-20 23:20:31 +12:00
'databasesCount' => $stats [ 'databases.$all.count.total' ] ? ? [],
'documentsCount' => $stats [ 'documents.$all.count.total' ] ? ? [],
'collectionsCount' => $stats [ 'collections.$all.count.total' ] ? ? [],
2023-05-24 22:09:08 +12:00
'documentsCreate' => $stats [ 'documents.$all.requests.create' ] ? ? [],
'documentsRead' => $stats [ 'documents.$all.requests.read' ] ? ? [],
2022-08-20 23:20:31 +12:00
'documentsUpdate' => $stats [ 'documents.$all.requests.update' ] ? ? [],
'documentsDelete' => $stats [ 'documents.$all.requests.delete' ] ? ? [],
'collectionsCreate' => $stats [ 'collections.$all.requests.create' ] ? ? [],
2023-05-24 22:09:08 +12:00
'collectionsRead' => $stats [ 'collections.$all.requests.read' ] ? ? [],
2022-08-20 23:20:31 +12:00
'collectionsUpdate' => $stats [ 'collections.$all.requests.update' ] ? ? [],
'collectionsDelete' => $stats [ 'collections.$all.requests.delete' ] ? ? [],
'databasesCreate' => $stats [ 'databases.$all.requests.create' ] ? ? [],
2023-05-24 22:09:08 +12:00
'databasesRead' => $stats [ 'databases.$all.requests.read' ] ? ? [],
2022-08-20 23:20:31 +12:00
'databasesUpdate' => $stats [ 'databases.$all.requests.update' ] ? ? [],
'databasesDelete' => $stats [ 'databases.$all.requests.delete' ] ? ? [],
2022-06-23 20:50:11 +12:00
]);
}
2022-06-22 22:51:49 +12:00
2022-06-23 20:50:11 +12:00
$response -> dynamic ( $usage , Response :: MODEL_USAGE_DATABASES );
});
2022-06-22 22:51:49 +12:00
App :: get ( '/v1/databases/:databaseId/usage' )
2022-06-23 20:50:11 +12:00
-> desc ( 'Get usage stats for the database' )
2023-04-22 05:39:01 +12:00
-> groups ([ 'api' , 'database' , 'usage' ])
2022-06-23 20:50:11 +12:00
-> 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 19:30:26 +13:00
'period' => '1h' ,
'limit' => 24 ,
2022-06-23 20:50:11 +12:00
],
'7d' => [
'period' => '1d' ,
'limit' => 7 ,
],
'30d' => [
'period' => '1d' ,
'limit' => 30 ,
],
'90d' => [
'period' => '1d' ,
'limit' => 90 ,
],
];
$metrics = [
2022-08-09 18:28:38 +12:00
'collections.' . $databaseId . '.count.total' ,
'collections.' . $databaseId . '.requests.create' ,
'collections.' . $databaseId . '.requests.read' ,
'collections.' . $databaseId . '.requests.update' ,
'collections.' . $databaseId . '.requests.delete' ,
2022-08-13 17:02:18 +12:00
'documents.' . $databaseId . '.count.total' ,
2022-08-09 18:28:38 +12:00
'documents.' . $databaseId . '.requests.create' ,
'documents.' . $databaseId . '.requests.read' ,
'documents.' . $databaseId . '.requests.update' ,
'documents.' . $databaseId . '.requests.delete'
2022-06-23 20:50:11 +12: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-12 11:53:52 +12:00
Query :: equal ( 'period' , [ $period ]),
Query :: equal ( 'metric' , [ $metric ]),
Query :: limit ( $limit ),
Query :: orderDesc ( 'time' ),
]);
2022-06-23 20:50:11 +12:00
$stats [ $metric ] = [];
foreach ( $requestDocs as $requestDoc ) {
$stats [ $metric ][] = [
'value' => $requestDoc -> getAttribute ( 'value' ),
'date' => $requestDoc -> getAttribute ( 'time' ),
];
}
2022-06-22 22:51:49 +12:00
2022-06-23 20:50:11 +12: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 19:33:14 +13:00
'1h' => 3600 ,
2022-06-23 20:50:11 +12:00
'1d' => 86400 ,
};
$stats [ $metric ][] = [
'value' => 0 ,
2022-09-16 11:48:09 +12:00
'date' => DateTime :: formatTz ( DateTime :: addSeconds ( new \DateTime ( $stats [ $metric ][ $last ][ 'date' ] ? ? null ), - 1 * $diff )),
2022-06-23 20:50:11 +12:00
];
$backfill -- ;
}
// TODO@kodumbeats explore performance if query is ordered by time ASC
$stats [ $metric ] = array_reverse ( $stats [ $metric ]);
2022-06-22 22:51:49 +12:00
}
2022-06-23 20:50:11 +12:00
});
$usage = new Document ([
'range' => $range ,
2022-08-20 23:20:31 +12:00
'collectionsCount' => $stats [ " collections. { $databaseId } .count.total " ] ? ? [],
'collectionsCreate' => $stats [ " collections. { $databaseId } .requests.create " ] ? ? [],
2023-05-24 22:09:08 +12:00
'collectionsRead' => $stats [ " collections. { $databaseId } .requests.read " ] ? ? [],
2022-08-20 23:20:31 +12:00
'collectionsUpdate' => $stats [ " collections. { $databaseId } .requests.update " ] ? ? [],
'collectionsDelete' => $stats [ " collections. { $databaseId } .requests.delete " ] ? ? [],
'documentsCount' => $stats [ " documents. { $databaseId } .count.total " ] ? ? [],
2023-05-24 22:09:08 +12:00
'documentsCreate' => $stats [ " documents. { $databaseId } .requests.create " ] ? ? [],
'documentsRead' => $stats [ " documents. { $databaseId } .requests.read " ] ? ? [],
2022-08-20 23:20:31 +12:00
'documentsUpdate' => $stats [ " documents. { $databaseId } .requests.update " ] ? ? [],
'documentsDelete' => $stats [ " documents. { $databaseId } .requests.delete " ] ? ? [],
2022-06-23 20:50:11 +12:00
]);
}
2022-06-22 22:51:49 +12:00
2022-06-23 20:50:11 +12:00
$response -> dynamic ( $usage , Response :: MODEL_USAGE_DATABASE );
});
2022-06-22 22:51:49 +12:00
App :: get ( '/v1/databases/:databaseId/collections/:collectionId/usage' )
2022-07-06 11:13:48 +12:00
-> alias ( '/v1/database/:collectionId/usage' , [ 'databaseId' => 'default' ])
2022-06-23 20:50:11 +12:00
-> desc ( 'Get usage stats for a collection' )
2023-04-22 05:39:01 +12:00
-> groups ([ 'api' , 'database' , 'usage' ])
2022-06-23 20:50:11 +12:00
-> 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 22:51:49 +12:00
2022-06-23 20:50:11 +12:00
$database = $dbForProject -> getDocument ( 'databases' , $databaseId );
2022-06-22 22:51:49 +12:00
2022-06-23 20:50:11 +12:00
$collectionDocument = $dbForProject -> getDocument ( 'database_' . $database -> getInternalId (), $collectionId );
$collection = $dbForProject -> getCollection ( 'database_' . $database -> getInternalId () . '_collection_' . $collectionDocument -> getInternalId ());
if ( $collection -> isEmpty ()) {
2022-07-27 02:24:32 +12:00
throw new Exception ( Exception :: COLLECTION_NOT_FOUND );
2022-06-23 20:50:11 +12:00
}
2022-06-22 22:51:49 +12:00
2022-06-23 20:50:11 +12:00
$usage = [];
if ( App :: getEnv ( '_APP_USAGE_STATS' , 'enabled' ) == 'enabled' ) {
$periods = [
'24h' => [
2022-10-09 19:30:26 +13:00
'period' => '1h' ,
'limit' => 24 ,
2022-06-23 20:50:11 +12:00
],
'7d' => [
'period' => '1d' ,
'limit' => 7 ,
],
'30d' => [
'period' => '1d' ,
'limit' => 30 ,
],
'90d' => [
'period' => '1d' ,
'limit' => 90 ,
],
];
$metrics = [
2022-08-09 18:28:38 +12: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 20:50:11 +12: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-12 11:53:52 +12:00
Query :: equal ( 'period' , [ $period ]),
Query :: equal ( 'metric' , [ $metric ]),
Query :: limit ( $limit ),
Query :: orderDesc ( 'time' ),
]);
2022-06-23 20:50:11 +12:00
$stats [ $metric ] = [];
foreach ( $requestDocs as $requestDoc ) {
$stats [ $metric ][] = [
'value' => $requestDoc -> getAttribute ( 'value' ),
'date' => $requestDoc -> getAttribute ( 'time' ),
];
}
2022-06-22 22:51:49 +12:00
2022-06-23 20:50:11 +12: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 19:33:14 +13:00
'1h' => 3600 ,
2022-06-23 20:50:11 +12:00
'1d' => 86400 ,
};
$stats [ $metric ][] = [
'value' => 0 ,
2022-09-16 11:48:09 +12:00
'date' => DateTime :: formatTz ( DateTime :: addSeconds ( new \DateTime ( $stats [ $metric ][ $last ][ 'date' ] ? ? null ), - 1 * $diff )),
2022-06-23 20:50:11 +12:00
];
$backfill -- ;
}
$stats [ $metric ] = array_reverse ( $stats [ $metric ]);
2022-06-22 22:51:49 +12:00
}
2022-06-23 20:50:11 +12:00
});
$usage = new Document ([
'range' => $range ,
2022-08-20 23:20:31 +12:00
'documentsCount' => $stats [ " documents. { $databaseId } / { $collectionId } .count.total " ] ? ? [],
'documentsCreate' => $stats [ " documents. { $databaseId } / { $collectionId } .requests.create " ] ? ? [],
'documentsRead' => $stats [ " documents. { $databaseId } / { $collectionId } .requests.read " ] ? ? [],
2023-05-24 22:09:08 +12:00
'documentsUpdate' => $stats [ " documents. { $databaseId } / { $collectionId } .requests.update " ] ? ? [],
'documentsDelete' => $stats [ " documents. { $databaseId } / { $collectionId } .requests.delete " ? ? []]
2022-06-23 20:50:11 +12:00
]);
}
2022-06-22 22:51:49 +12:00
2022-06-23 20:50:11 +12:00
$response -> dynamic ( $usage , Response :: MODEL_USAGE_COLLECTION );
});