Merge pull request #2398 from appwrite/feat-sb-uis
This commit is contained in:
commit
70b6e88aec
19 changed files with 1237 additions and 350 deletions
1
app/config/specs/0.13.x.client.json
Normal file
1
app/config/specs/0.13.x.client.json
Normal file
File diff suppressed because one or more lines are too long
1
app/config/specs/0.13.x.console.json
Normal file
1
app/config/specs/0.13.x.console.json
Normal file
File diff suppressed because one or more lines are too long
1
app/config/specs/0.13.x.server.json
Normal file
1
app/config/specs/0.13.x.server.json
Normal file
File diff suppressed because one or more lines are too long
|
@ -58,17 +58,19 @@ App::post('/v1/storage/buckets')
|
||||||
->param('antiVirus', true, new Boolean(), 'Is virus scanning enabled? For file size above ' . Storage::human(APP_LIMIT_ANTIVIRUS) . ' AntiVirus scanning is skipped even if it\'s enabled', true)
|
->param('antiVirus', true, new Boolean(), 'Is virus scanning enabled? For file size above ' . Storage::human(APP_LIMIT_ANTIVIRUS) . ' AntiVirus scanning is skipped even if it\'s enabled', true)
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->inject('dbForInternal')
|
->inject('dbForInternal')
|
||||||
|
->inject('dbForExternal')
|
||||||
->inject('audits')
|
->inject('audits')
|
||||||
->inject('usage')
|
->inject('usage')
|
||||||
->action(function ($bucketId, $name, $permission, $read, $write, $maximumFileSize, $allowedFileExtensions, $enabled, $adapter, $encryption, $antiVirus, $response, $dbForInternal, $audits, $usage) {
|
->action(function ($bucketId, $name, $permission, $read, $write, $maximumFileSize, $allowedFileExtensions, $enabled, $adapter, $encryption, $antiVirus, $response, $dbForInternal, $dbForExternal, $audits, $usage) {
|
||||||
/** @var Appwrite\Utopia\Response $response */
|
/** @var Appwrite\Utopia\Response $response */
|
||||||
/** @var Utopia\Database\Database $dbForInternal */
|
/** @var Utopia\Database\Database $dbForInternal */
|
||||||
|
/** @var Utopia\Database\Database $dbForExternal */
|
||||||
/** @var Appwrite\Event\Event $audits */
|
/** @var Appwrite\Event\Event $audits */
|
||||||
/** @var Appwrite\Stats\Stats $usage */
|
/** @var Appwrite\Stats\Stats $usage */
|
||||||
|
|
||||||
$bucketId = $bucketId === 'unique()' ? $dbForInternal->getId() : $bucketId;
|
$bucketId = $bucketId === 'unique()' ? $dbForInternal->getId() : $bucketId;
|
||||||
try {
|
try {
|
||||||
$dbForInternal->createCollection('bucket_' . $bucketId, [
|
$dbForExternal->createCollection('bucket_' . $bucketId, [
|
||||||
new Document([
|
new Document([
|
||||||
'$id' => 'dateCreated',
|
'$id' => 'dateCreated',
|
||||||
'type' => Database::VAR_INTEGER,
|
'type' => Database::VAR_INTEGER,
|
||||||
|
@ -505,14 +507,16 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||||
->inject('request')
|
->inject('request')
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->inject('dbForInternal')
|
->inject('dbForInternal')
|
||||||
|
->inject('dbForExternal')
|
||||||
->inject('user')
|
->inject('user')
|
||||||
->inject('audits')
|
->inject('audits')
|
||||||
->inject('usage')
|
->inject('usage')
|
||||||
->inject('mode')
|
->inject('mode')
|
||||||
->action(function ($bucketId, $fileId, $file, $read, $write, $request, $response, $dbForInternal, $user, $audits, $usage, $mode) {
|
->action(function ($bucketId, $fileId, $file, $read, $write, $request, $response, $dbForInternal, $dbForExternal, $user, $audits, $usage, $mode) {
|
||||||
/** @var Utopia\Swoole\Request $request */
|
/** @var Utopia\Swoole\Request $request */
|
||||||
/** @var Appwrite\Utopia\Response $response */
|
/** @var Appwrite\Utopia\Response $response */
|
||||||
/** @var Utopia\Database\Database $dbForInternal */
|
/** @var Utopia\Database\Database $dbForInternal */
|
||||||
|
/** @var Utopia\Database\Database $dbForExternal */
|
||||||
/** @var Utopia\Database\Document $user */
|
/** @var Utopia\Database\Document $user */
|
||||||
/** @var Appwrite\Event\Event $audits */
|
/** @var Appwrite\Event\Event $audits */
|
||||||
/** @var Appwrite\Stats\Stats $usage */
|
/** @var Appwrite\Stats\Stats $usage */
|
||||||
|
@ -638,11 +642,11 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if($bucket->getAttribute('permission') === 'bucket') {
|
if($bucket->getAttribute('permission') === 'bucket') {
|
||||||
$file = Authorization::skip(function() use ($dbForInternal, $bucket, $data) {
|
$file = Authorization::skip(function() use ($dbForExternal, $bucket, $data) {
|
||||||
return $dbForInternal->createDocument('bucket_' . $bucket->getId(), new Document($data));
|
return $dbForExternal->createDocument('bucket_' . $bucket->getId(), new Document($data));
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
$file = $dbForInternal->createDocument('bucket_' . $bucket->getId(), new Document($data));
|
$file = $dbForExternal->createDocument('bucket_' . $bucket->getId(), new Document($data));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -691,11 +695,13 @@ App::get('/v1/storage/buckets/:bucketId/files')
|
||||||
->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true)
|
->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true)
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->inject('dbForInternal')
|
->inject('dbForInternal')
|
||||||
|
->inject('dbForExternal')
|
||||||
->inject('usage')
|
->inject('usage')
|
||||||
->inject('mode')
|
->inject('mode')
|
||||||
->action(function ($bucketId, $search, $limit, $offset, $cursor, $cursorDirection, $orderType, $response, $dbForInternal, $usage, $mode) {
|
->action(function ($bucketId, $search, $limit, $offset, $cursor, $cursorDirection, $orderType, $response, $dbForInternal, $dbForExternal, $usage, $mode) {
|
||||||
/** @var Appwrite\Utopia\Response $response */
|
/** @var Appwrite\Utopia\Response $response */
|
||||||
/** @var Utopia\Database\Database $dbForInternal */
|
/** @var Utopia\Database\Database $dbForInternal */
|
||||||
|
/** @var Utopia\Database\Database $dbForExternal */
|
||||||
/** @var Appwrite\Stats\Stats $usage */
|
/** @var Appwrite\Stats\Stats $usage */
|
||||||
|
|
||||||
$bucket = $dbForInternal->getDocument('buckets', $bucketId);
|
$bucket = $dbForInternal->getDocument('buckets', $bucketId);
|
||||||
|
@ -721,11 +727,11 @@ App::get('/v1/storage/buckets/:bucketId/files')
|
||||||
|
|
||||||
if (!empty($cursor)) {
|
if (!empty($cursor)) {
|
||||||
if($bucket->getAttribute('permission') ==='bucket') {
|
if($bucket->getAttribute('permission') ==='bucket') {
|
||||||
$cursorFile = Authorization::skip(function() use ($dbForInternal, $bucket, $cursor) {
|
$cursorFile = Authorization::skip(function() use ($dbForExternal, $bucket, $cursor) {
|
||||||
return $dbForInternal->getDocument('bucket_' . $bucket->getId(), $cursor);
|
return $dbForExternal->getDocument('bucket_' . $bucket->getId(), $cursor);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
$cursorFile = $dbForInternal->getDocument('bucket_' . $bucket->getId(), $cursor);
|
$cursorFile = $dbForExternal->getDocument('bucket_' . $bucket->getId(), $cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($cursorFile->isEmpty()) {
|
if ($cursorFile->isEmpty()) {
|
||||||
|
@ -740,11 +746,11 @@ App::get('/v1/storage/buckets/:bucketId/files')
|
||||||
}
|
}
|
||||||
|
|
||||||
if($bucket->getAttribute('permission') === 'bucket') {
|
if($bucket->getAttribute('permission') === 'bucket') {
|
||||||
$files = Authorization::skip(function() use ($dbForInternal, $bucketId, $queries, $limit, $offset, $cursor, $cursorDirection, $orderType) {
|
$files = Authorization::skip(function() use ($dbForExternal, $bucketId, $queries, $limit, $offset, $cursor, $cursorDirection, $orderType) {
|
||||||
return $dbForInternal->find('bucket_' . $bucketId, $queries, $limit, $offset, [], [$orderType], $cursorFile ?? null, $cursorDirection);
|
return $dbForExternal->find('bucket_' . $bucketId, $queries, $limit, $offset, [], [$orderType], $cursorFile ?? null, $cursorDirection);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
$files = $dbForInternal->find('bucket_' . $bucketId, $queries, $limit, $offset, [], [$orderType], $cursorFile ?? null, $cursorDirection);
|
$files = $dbForExternal->find('bucket_' . $bucketId, $queries, $limit, $offset, [], [$orderType], $cursorFile ?? null, $cursorDirection);
|
||||||
}
|
}
|
||||||
|
|
||||||
$usage
|
$usage
|
||||||
|
@ -754,7 +760,7 @@ App::get('/v1/storage/buckets/:bucketId/files')
|
||||||
|
|
||||||
$response->dynamic(new Document([
|
$response->dynamic(new Document([
|
||||||
'files' => $files,
|
'files' => $files,
|
||||||
'sum' => $dbForInternal->count('bucket_' . $bucketId, $queries, APP_LIMIT_COUNT),
|
'sum' => $dbForExternal->count('bucket_' . $bucketId, $queries, APP_LIMIT_COUNT),
|
||||||
]), Response::MODEL_FILE_LIST);
|
]), Response::MODEL_FILE_LIST);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -774,11 +780,13 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||||
->param('fileId', '', new UID(), 'File unique ID.')
|
->param('fileId', '', new UID(), 'File unique ID.')
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->inject('dbForInternal')
|
->inject('dbForInternal')
|
||||||
|
->inject('dbForExternal')
|
||||||
->inject('usage')
|
->inject('usage')
|
||||||
->inject('mode')
|
->inject('mode')
|
||||||
->action(function ($bucketId, $fileId, $response, $dbForInternal, $usage, $mode) {
|
->action(function ($bucketId, $fileId, $response, $dbForInternal, $dbForExternal, $usage, $mode) {
|
||||||
/** @var Appwrite\Utopia\Response $response */
|
/** @var Appwrite\Utopia\Response $response */
|
||||||
/** @var Utopia\Database\Database $dbForInternal */
|
/** @var Utopia\Database\Database $dbForInternal */
|
||||||
|
/** @var Utopia\Database\Database $dbForExternal */
|
||||||
/** @var Appwrite\Stats\Stats $usage */
|
/** @var Appwrite\Stats\Stats $usage */
|
||||||
|
|
||||||
$bucket = $dbForInternal->getDocument('buckets', $bucketId);
|
$bucket = $dbForInternal->getDocument('buckets', $bucketId);
|
||||||
|
@ -797,11 +805,11 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||||
}
|
}
|
||||||
|
|
||||||
if($bucket->getAttribute('permission') === 'bucket') {
|
if($bucket->getAttribute('permission') === 'bucket') {
|
||||||
$file = Authorization::skip(function() use ($dbForInternal, $bucketId, $fileId) {
|
$file = Authorization::skip(function() use ($dbForExternal, $bucketId, $fileId) {
|
||||||
return $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
return $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
$file = $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
$file = $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) {
|
if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) {
|
||||||
|
@ -843,13 +851,15 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->inject('project')
|
->inject('project')
|
||||||
->inject('dbForInternal')
|
->inject('dbForInternal')
|
||||||
|
->inject('dbForExternal')
|
||||||
->inject('usage')
|
->inject('usage')
|
||||||
->inject('mode')
|
->inject('mode')
|
||||||
->action(function ($bucketId, $fileId, $width, $height, $gravity, $quality, $borderWidth, $borderColor, $borderRadius, $opacity, $rotation, $background, $output, $request, $response, $project, $dbForInternal, $usage, $mode) {
|
->action(function ($bucketId, $fileId, $width, $height, $gravity, $quality, $borderWidth, $borderColor, $borderRadius, $opacity, $rotation, $background, $output, $request, $response, $project, $dbForInternal, $dbForExternal, $usage, $mode) {
|
||||||
/** @var Utopia\Swoole\Request $request */
|
/** @var Utopia\Swoole\Request $request */
|
||||||
/** @var Appwrite\Utopia\Response $response */
|
/** @var Appwrite\Utopia\Response $response */
|
||||||
/** @var Utopia\Database\Document $project */
|
/** @var Utopia\Database\Document $project */
|
||||||
/** @var Utopia\Database\Database $dbForInternal */
|
/** @var Utopia\Database\Database $dbForInternal */
|
||||||
|
/** @var Utopia\Database\Database $dbForExternal */
|
||||||
/** @var Appwrite\Stats\Stats $usage */
|
/** @var Appwrite\Stats\Stats $usage */
|
||||||
|
|
||||||
$storage = 'files';
|
$storage = 'files';
|
||||||
|
@ -889,11 +899,11 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
||||||
|
|
||||||
if($bucket->getAttribute('permission')==='bucket') {
|
if($bucket->getAttribute('permission')==='bucket') {
|
||||||
// skip authorization
|
// skip authorization
|
||||||
$file = Authorization::skip(function () use ($dbForInternal, $bucketId, $fileId) {
|
$file = Authorization::skip(function () use ($dbForExternal, $bucketId, $fileId) {
|
||||||
return $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
return $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
$file = $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
$file = $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) {
|
if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) {
|
||||||
|
@ -1014,11 +1024,13 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
||||||
->param('fileId', '', new UID(), 'File unique ID.')
|
->param('fileId', '', new UID(), 'File unique ID.')
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->inject('dbForInternal')
|
->inject('dbForInternal')
|
||||||
|
->inject('dbForExternal')
|
||||||
->inject('usage')
|
->inject('usage')
|
||||||
->inject('mode')
|
->inject('mode')
|
||||||
->action(function ($bucketId, $fileId, $response, $dbForInternal, $usage, $mode) {
|
->action(function ($bucketId, $fileId, $response, $dbForInternal, $dbForExternal, $usage, $mode) {
|
||||||
/** @var Appwrite\Utopia\Response $response */
|
/** @var Appwrite\Utopia\Response $response */
|
||||||
/** @var Utopia\Database\Database $dbForInternal */
|
/** @var Utopia\Database\Database $dbForInternal */
|
||||||
|
/** @var Utopia\Database\Database $dbForExternal */
|
||||||
/** @var Appwrite\Stats\Stats $usage */
|
/** @var Appwrite\Stats\Stats $usage */
|
||||||
|
|
||||||
$bucket = $dbForInternal->getDocument('buckets', $bucketId);
|
$bucket = $dbForInternal->getDocument('buckets', $bucketId);
|
||||||
|
@ -1037,11 +1049,11 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
||||||
}
|
}
|
||||||
|
|
||||||
if($bucket->getAttribute('permission') === 'bucket') {
|
if($bucket->getAttribute('permission') === 'bucket') {
|
||||||
$file = Authorization::skip(function() use ($dbForInternal, $fileId, $bucketId) {
|
$file = Authorization::skip(function() use ($dbForExternal, $fileId, $bucketId) {
|
||||||
return $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
return $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
$file = $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
$file = $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) {
|
if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) {
|
||||||
|
@ -1103,9 +1115,10 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
||||||
->param('fileId', '', new UID(), 'File unique ID.')
|
->param('fileId', '', new UID(), 'File unique ID.')
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->inject('dbForInternal')
|
->inject('dbForInternal')
|
||||||
|
->inject('dbForExternal')
|
||||||
->inject('usage')
|
->inject('usage')
|
||||||
->inject('mode')
|
->inject('mode')
|
||||||
->action(function ($bucketId, $fileId, $response, $dbForInternal, $usage, $mode) {
|
->action(function ($bucketId, $fileId, $response, $dbForInternal, $dbForExternal, $usage, $mode) {
|
||||||
/** @var Appwrite\Utopia\Response $response */
|
/** @var Appwrite\Utopia\Response $response */
|
||||||
/** @var Utopia\Database\Database $dbForInternal */
|
/** @var Utopia\Database\Database $dbForInternal */
|
||||||
/** @var Appwrite\Stats\Stats $usage */
|
/** @var Appwrite\Stats\Stats $usage */
|
||||||
|
@ -1126,11 +1139,11 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
||||||
}
|
}
|
||||||
|
|
||||||
if($bucket->getAttribute('permission') === 'bucket') {
|
if($bucket->getAttribute('permission') === 'bucket') {
|
||||||
$file = Authorization::skip(function() use ($dbForInternal, $fileId, $bucketId) {
|
$file = Authorization::skip(function() use ($dbForExternal, $fileId, $bucketId) {
|
||||||
return $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
return $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
$file = $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
$file = $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||||
}
|
}
|
||||||
|
|
||||||
$mimes = Config::getParam('storage-mimes');
|
$mimes = Config::getParam('storage-mimes');
|
||||||
|
@ -1205,10 +1218,11 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||||
->param('write', null, new Permissions(), 'An array of strings with write permissions. By default no user is granted with any write permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
|
->param('write', null, new Permissions(), 'An array of strings with write permissions. By default no user is granted with any write permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->inject('dbForInternal')
|
->inject('dbForInternal')
|
||||||
|
->inject('dbForExternal')
|
||||||
->inject('audits')
|
->inject('audits')
|
||||||
->inject('usage')
|
->inject('usage')
|
||||||
->inject('mode')
|
->inject('mode')
|
||||||
->action(function ($bucketId, $fileId, $read, $write, $response, $dbForInternal, $audits, $usage, $mode) {
|
->action(function ($bucketId, $fileId, $read, $write, $response, $dbForInternal, $dbForExternal, $audits, $usage, $mode) {
|
||||||
/** @var Appwrite\Utopia\Response $response */
|
/** @var Appwrite\Utopia\Response $response */
|
||||||
/** @var Utopia\Database\Database $dbForInternal */
|
/** @var Utopia\Database\Database $dbForInternal */
|
||||||
/** @var Appwrite\Event\Event $audits */
|
/** @var Appwrite\Event\Event $audits */
|
||||||
|
@ -1230,11 +1244,11 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||||
}
|
}
|
||||||
|
|
||||||
if($bucket->getAttribute('permission') === 'bucket') {
|
if($bucket->getAttribute('permission') === 'bucket') {
|
||||||
$file = Authorization::skip(function() use ($dbForInternal, $fileId, $bucketId) {
|
$file = Authorization::skip(function() use ($dbForExternal, $fileId, $bucketId) {
|
||||||
return $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
return $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
$file = $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
$file = $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) {
|
if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) {
|
||||||
|
@ -1242,14 +1256,14 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||||
}
|
}
|
||||||
|
|
||||||
if($bucket->getAttribute('permission') === 'bucket') {
|
if($bucket->getAttribute('permission') === 'bucket') {
|
||||||
$file = Authorization::skip(function() use ($dbForInternal, $fileId, $bucketId, $file, $read, $write) {
|
$file = Authorization::skip(function() use ($dbForExternal, $fileId, $bucketId, $file, $read, $write) {
|
||||||
return $dbForInternal->updateDocument('bucket_' . $bucketId, $fileId, $file
|
return $dbForExternal->updateDocument('bucket_' . $bucketId, $fileId, $file
|
||||||
->setAttribute('$read', $read)
|
->setAttribute('$read', $read)
|
||||||
->setAttribute('$write', $write)
|
->setAttribute('$write', $write)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
$file = $dbForInternal->updateDocument('bucket_' . $bucketId, $fileId, $file
|
$file = $dbForExternal->updateDocument('bucket_' . $bucketId, $fileId, $file
|
||||||
->setAttribute('$read', $read)
|
->setAttribute('$read', $read)
|
||||||
->setAttribute('$write', $write)
|
->setAttribute('$write', $write)
|
||||||
);
|
);
|
||||||
|
@ -1284,13 +1298,15 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||||
->param('fileId', '', new UID(), 'File unique ID.')
|
->param('fileId', '', new UID(), 'File unique ID.')
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->inject('dbForInternal')
|
->inject('dbForInternal')
|
||||||
|
->inject('dbForExternal')
|
||||||
->inject('events')
|
->inject('events')
|
||||||
->inject('audits')
|
->inject('audits')
|
||||||
->inject('usage')
|
->inject('usage')
|
||||||
->inject('mode')
|
->inject('mode')
|
||||||
->action(function ($bucketId, $fileId, $response, $dbForInternal, $events, $audits, $usage, $mode) {
|
->action(function ($bucketId, $fileId, $response, $dbForInternal, $dbForExternal, $events, $audits, $usage, $mode) {
|
||||||
/** @var Appwrite\Utopia\Response $response */
|
/** @var Appwrite\Utopia\Response $response */
|
||||||
/** @var Utopia\Database\Database $dbForInternal */
|
/** @var Utopia\Database\Database $dbForInternal */
|
||||||
|
/** @var Utopia\Database\Database $dbForExternal */
|
||||||
/** @var Appwrite\Event\Event $events */
|
/** @var Appwrite\Event\Event $events */
|
||||||
/** @var Appwrite\Event\Event $audits */
|
/** @var Appwrite\Event\Event $audits */
|
||||||
/** @var Appwrite\Stats\Stats $usage */
|
/** @var Appwrite\Stats\Stats $usage */
|
||||||
|
@ -1311,11 +1327,11 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||||
}
|
}
|
||||||
|
|
||||||
if($bucket->getAttribute('permission') === 'bucket') {
|
if($bucket->getAttribute('permission') === 'bucket') {
|
||||||
$file = Authorization::skip(function() use ($dbForInternal, $fileId, $bucketId) {
|
$file = Authorization::skip(function() use ($dbForExternal, $fileId, $bucketId) {
|
||||||
return $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
return $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
$file = $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
$file = $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) {
|
if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) {
|
||||||
|
@ -1326,11 +1342,11 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||||
|
|
||||||
if ($device->delete($file->getAttribute('path', ''))) {
|
if ($device->delete($file->getAttribute('path', ''))) {
|
||||||
if($bucket->getAttribute('permission') === 'bucket') {
|
if($bucket->getAttribute('permission') === 'bucket') {
|
||||||
$deleted = Authorization::skip(function() use ($dbForInternal, $fileId, $bucketId) {
|
$deleted = Authorization::skip(function() use ($dbForExternal, $fileId, $bucketId) {
|
||||||
return $dbForInternal->deleteDocument('bucket_' . $bucketId, $fileId);
|
return $dbForExternal->deleteDocument('bucket_' . $bucketId, $fileId);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
$deleted = $dbForInternal->deleteDocument('bucket_' . $bucketId, $fileId);
|
$deleted = $dbForExternal->deleteDocument('bucket_' . $bucketId, $fileId);
|
||||||
}
|
}
|
||||||
if (!$deleted) {
|
if (!$deleted) {
|
||||||
throw new Exception('Failed to remove file from DB', 500);
|
throw new Exception('Failed to remove file from DB', 500);
|
||||||
|
@ -1394,8 +1410,18 @@ App::get('/v1/storage/usage')
|
||||||
];
|
];
|
||||||
|
|
||||||
$metrics = [
|
$metrics = [
|
||||||
'storage.total',
|
"storage.tags.total",
|
||||||
'storage.files.count'
|
"storage.files.total",
|
||||||
|
"storage.files.count",
|
||||||
|
"storage.buckets.count",
|
||||||
|
"storage.buckets.create",
|
||||||
|
"storage.buckets.read",
|
||||||
|
"storage.buckets.update",
|
||||||
|
"storage.buckets.delete",
|
||||||
|
"storage.files.create",
|
||||||
|
"storage.files.read",
|
||||||
|
"storage.files.update",
|
||||||
|
"storage.files.delete",
|
||||||
];
|
];
|
||||||
|
|
||||||
$stats = [];
|
$stats = [];
|
||||||
|
@ -1438,8 +1464,18 @@ App::get('/v1/storage/usage')
|
||||||
|
|
||||||
$usage = new Document([
|
$usage = new Document([
|
||||||
'range' => $range,
|
'range' => $range,
|
||||||
'storage' => $stats['storage.total'],
|
'filesStorage' => $stats['storage.files.total'],
|
||||||
'files' => $stats['storage.files.count']
|
'tagsStorage' => $stats['storage.tags.total'],
|
||||||
|
'filesCount' => $stats['storage.files.count'],
|
||||||
|
'bucketsCount' => $stats['storage.buckets.count'],
|
||||||
|
'bucketsCreate' => $stats['storage.buckets.create'],
|
||||||
|
'bucketsRead' => $stats['storage.buckets.read'],
|
||||||
|
'bucketsUpdate' => $stats['storage.buckets.update'],
|
||||||
|
'bucketsDelete' => $stats['storage.buckets.delete'],
|
||||||
|
'filesCreate' => $stats['storage.files.create'],
|
||||||
|
'filesRead' => $stats['storage.files.read'],
|
||||||
|
'filesUpdate' => $stats['storage.files.update'],
|
||||||
|
'filesDelete' => $stats['storage.files.delete'],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1493,6 +1529,7 @@ App::get('/v1/storage/:bucketId/usage')
|
||||||
|
|
||||||
$metrics = [
|
$metrics = [
|
||||||
"storage.buckets.$bucketId.files.count",
|
"storage.buckets.$bucketId.files.count",
|
||||||
|
"storage.buckets.$bucketId.files.total",
|
||||||
"storage.buckets.$bucketId.files.create",
|
"storage.buckets.$bucketId.files.create",
|
||||||
"storage.buckets.$bucketId.files.read",
|
"storage.buckets.$bucketId.files.read",
|
||||||
"storage.buckets.$bucketId.files.update",
|
"storage.buckets.$bucketId.files.update",
|
||||||
|
@ -1505,7 +1542,6 @@ App::get('/v1/storage/:bucketId/usage')
|
||||||
foreach ($metrics as $metric) {
|
foreach ($metrics as $metric) {
|
||||||
$limit = $periods[$range]['limit'];
|
$limit = $periods[$range]['limit'];
|
||||||
$period = $periods[$range]['period'];
|
$period = $periods[$range]['period'];
|
||||||
|
|
||||||
$requestDocs = $dbForInternal->find('stats', [
|
$requestDocs = $dbForInternal->find('stats', [
|
||||||
new Query('period', Query::TYPE_EQUAL, [$period]),
|
new Query('period', Query::TYPE_EQUAL, [$period]),
|
||||||
new Query('metric', Query::TYPE_EQUAL, [$metric]),
|
new Query('metric', Query::TYPE_EQUAL, [$metric]),
|
||||||
|
@ -1539,6 +1575,7 @@ App::get('/v1/storage/:bucketId/usage')
|
||||||
|
|
||||||
$usage = new Document([
|
$usage = new Document([
|
||||||
'range' => $range,
|
'range' => $range,
|
||||||
|
'filesStorage' => $stats["storage.buckets.$bucketId.files.total"],
|
||||||
'filesCount' => $stats["storage.buckets.$bucketId.files.count"],
|
'filesCount' => $stats["storage.buckets.$bucketId.files.count"],
|
||||||
'filesCreate' => $stats["storage.buckets.$bucketId.files.create"],
|
'filesCreate' => $stats["storage.buckets.$bucketId.files.create"],
|
||||||
'filesRead' => $stats["storage.buckets.$bucketId.files.read"],
|
'filesRead' => $stats["storage.buckets.$bucketId.files.read"],
|
||||||
|
|
|
@ -315,6 +315,36 @@ App::get('/console/storage')
|
||||||
->setParam('body', $page);
|
->setParam('body', $page);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
App::get('/console/storage/bucket')
|
||||||
|
->groups(['web', 'console'])
|
||||||
|
->label('permission', 'public')
|
||||||
|
->label('scope', 'console')
|
||||||
|
->param('id', '', new UID(), 'Bucket unique ID.')
|
||||||
|
->inject('response')
|
||||||
|
->inject('layout')
|
||||||
|
->action(function ($id, $response, $layout) {
|
||||||
|
/** @var Appwrite\Utopia\Response $response */
|
||||||
|
/** @var Utopia\View $layout */
|
||||||
|
|
||||||
|
$page = new View(__DIR__.'/../../views/console/storage/bucket.phtml');
|
||||||
|
$page
|
||||||
|
->setParam('home', App::getEnv('_APP_HOME', 0))
|
||||||
|
->setParam('fileLimit', App::getEnv('_APP_STORAGE_LIMIT', 0))
|
||||||
|
->setParam('fileLimitHuman', Storage::human(App::getEnv('_APP_STORAGE_LIMIT', 0)))
|
||||||
|
;
|
||||||
|
|
||||||
|
$layout
|
||||||
|
->setParam('title', APP_NAME.' - Storage Bucket')
|
||||||
|
->setParam('body', $page)
|
||||||
|
;
|
||||||
|
|
||||||
|
$response
|
||||||
|
->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
|
||||||
|
->addHeader('Expires', 0)
|
||||||
|
->addHeader('Pragma', 'no-cache')
|
||||||
|
;
|
||||||
|
});
|
||||||
|
|
||||||
App::get('/console/users')
|
App::get('/console/users')
|
||||||
->groups(['web', 'console'])
|
->groups(['web', 'console'])
|
||||||
->label('permission', 'public')
|
->label('permission', 'public')
|
||||||
|
|
|
@ -66,7 +66,7 @@ const APP_LIMIT_ANTIVIRUS = 20971520; //20MB
|
||||||
const APP_LIMIT_ENCRYPTION = 20971520; //20MB
|
const APP_LIMIT_ENCRYPTION = 20971520; //20MB
|
||||||
const APP_LIMIT_COMPRESSION = 20971520; //20MB
|
const APP_LIMIT_COMPRESSION = 20971520; //20MB
|
||||||
const APP_CACHE_BUSTER = 181;
|
const APP_CACHE_BUSTER = 181;
|
||||||
const APP_VERSION_STABLE = '0.12.0';
|
const APP_VERSION_STABLE = '0.13.0';
|
||||||
const APP_DATABASE_ATTRIBUTE_EMAIL = 'email';
|
const APP_DATABASE_ATTRIBUTE_EMAIL = 'email';
|
||||||
const APP_DATABASE_ATTRIBUTE_ENUM = 'enum';
|
const APP_DATABASE_ATTRIBUTE_ENUM = 'enum';
|
||||||
const APP_DATABASE_ATTRIBUTE_IP = 'ip';
|
const APP_DATABASE_ATTRIBUTE_IP = 'ip';
|
||||||
|
|
|
@ -30,7 +30,7 @@ $cli
|
||||||
$production = ($git) ? (Console::confirm('Type "Appwrite" to push code to production git repos') == 'Appwrite') : false;
|
$production = ($git) ? (Console::confirm('Type "Appwrite" to push code to production git repos') == 'Appwrite') : false;
|
||||||
$message = ($git) ? Console::confirm('Please enter your commit message:') : '';
|
$message = ($git) ? Console::confirm('Please enter your commit message:') : '';
|
||||||
|
|
||||||
if(!in_array($version, ['0.6.x', '0.7.x', '0.8.x', '0.9.x', '0.10.x', '0.11.x', '0.12.x'])) {
|
if(!in_array($version, ['0.6.x', '0.7.x', '0.8.x', '0.9.x', '0.10.x', '0.11.x', '0.12.x', '0.13.x'])) {
|
||||||
throw new Exception('Unknown version given');
|
throw new Exception('Unknown version given');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,10 @@ use Utopia\Database\Validator\Authorization;
|
||||||
* storage.buckets.read
|
* storage.buckets.read
|
||||||
* storage.buckets.update
|
* storage.buckets.update
|
||||||
* storage.buckets.delete
|
* storage.buckets.delete
|
||||||
|
* storage.files.create
|
||||||
|
* storage.files.read
|
||||||
|
* storage.files.update
|
||||||
|
* storage.files.delete
|
||||||
* storage.buckets.{bucketId}.files.create
|
* storage.buckets.{bucketId}.files.create
|
||||||
* storage.buckets.{bucketId}.files.read
|
* storage.buckets.{bucketId}.files.read
|
||||||
* storage.buckets.{bucketId}.files.update
|
* storage.buckets.{bucketId}.files.update
|
||||||
|
@ -69,6 +73,7 @@ use Utopia\Database\Validator\Authorization;
|
||||||
* users.count
|
* users.count
|
||||||
* storage.buckets.count
|
* storage.buckets.count
|
||||||
* storage.files.count
|
* storage.files.count
|
||||||
|
* storage.buckets.{bucketId}.files.count
|
||||||
* database.collections.count
|
* database.collections.count
|
||||||
* database.documents.count
|
* database.documents.count
|
||||||
* database.collections.{collectionId}.documents.count
|
* database.collections.{collectionId}.documents.count
|
||||||
|
@ -161,6 +166,18 @@ $cli
|
||||||
'storage.buckets.delete' => [
|
'storage.buckets.delete' => [
|
||||||
'table' => 'appwrite_usage_storage_buckets_delete',
|
'table' => 'appwrite_usage_storage_buckets_delete',
|
||||||
],
|
],
|
||||||
|
'storage.files.create' => [
|
||||||
|
'table' => 'appwrite_usage_storage_files_create',
|
||||||
|
],
|
||||||
|
'storage.files.read' => [
|
||||||
|
'table' => 'appwrite_usage_storage_files_read',
|
||||||
|
],
|
||||||
|
'storage.files.update' => [
|
||||||
|
'table' => 'appwrite_usage_storage_files_update',
|
||||||
|
],
|
||||||
|
'storage.files.delete' => [
|
||||||
|
'table' => 'appwrite_usage_storage_files_delete',
|
||||||
|
],
|
||||||
'storage.buckets.bucketId.files.create' => [
|
'storage.buckets.bucketId.files.create' => [
|
||||||
'table' => 'appwrite_usage_storage_files_create',
|
'table' => 'appwrite_usage_storage_files_create',
|
||||||
'groupBy' => 'bucketId',
|
'groupBy' => 'bucketId',
|
||||||
|
@ -387,19 +404,19 @@ $cli
|
||||||
foreach ($projects as $project) {
|
foreach ($projects as $project) {
|
||||||
$projectId = $project->getId();
|
$projectId = $project->getId();
|
||||||
|
|
||||||
// Get total storage
|
// storage.tags.total
|
||||||
$dbForProject->setNamespace('project_' . $projectId . '_internal');
|
$dbForProject->setNamespace('project_' . $projectId . '_internal');
|
||||||
$storageTotal = $dbForProject->sum('files', 'sizeOriginal') + $dbForProject->sum('tags', 'size');
|
$storageTotal = (int) $dbForProject->sum('tags', 'size');
|
||||||
|
|
||||||
$time = (int) (floor(time() / 1800) * 1800); // Time rounded to nearest 30 minutes
|
$time = (int) (floor(time() / 1800) * 1800); // Time rounded to nearest 30 minutes
|
||||||
$id = \md5($time . '_30m_storage.total'); //Construct unique id for each metric using time, period and metric
|
$id = \md5($time . '_30m_storage.tags.total'); //Construct unique id for each metric using time, period and metric
|
||||||
$document = $dbForProject->getDocument('stats', $id);
|
$document = $dbForProject->getDocument('stats', $id);
|
||||||
if ($document->isEmpty()) {
|
if ($document->isEmpty()) {
|
||||||
$dbForProject->createDocument('stats', new Document([
|
$dbForProject->createDocument('stats', new Document([
|
||||||
'$id' => $id,
|
'$id' => $id,
|
||||||
'period' => '30m',
|
'period' => '30m',
|
||||||
'time' => $time,
|
'time' => $time,
|
||||||
'metric' => 'storage.total',
|
'metric' => 'storage.tags.total',
|
||||||
'value' => $storageTotal,
|
'value' => $storageTotal,
|
||||||
'type' => 1,
|
'type' => 1,
|
||||||
]));
|
]));
|
||||||
|
@ -419,7 +436,7 @@ $cli
|
||||||
'$id' => $id,
|
'$id' => $id,
|
||||||
'period' => '1d',
|
'period' => '1d',
|
||||||
'time' => $time,
|
'time' => $time,
|
||||||
'metric' => 'storage.total',
|
'metric' => 'storage.tags.total',
|
||||||
'value' => $storageTotal,
|
'value' => $storageTotal,
|
||||||
'type' => 1,
|
'type' => 1,
|
||||||
]));
|
]));
|
||||||
|
@ -449,7 +466,11 @@ $cli
|
||||||
'namespace' => 'internal',
|
'namespace' => 'internal',
|
||||||
'subCollections' => [
|
'subCollections' => [
|
||||||
'files' => [
|
'files' => [
|
||||||
'namespace' => 'internal',
|
'namespace' => 'external',
|
||||||
|
'collectionPrefix' => 'bucket_',
|
||||||
|
'sum' => [
|
||||||
|
'field' => 'sizeOriginal'
|
||||||
|
]
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
@ -511,6 +532,7 @@ $cli
|
||||||
|
|
||||||
$latestParent = null;
|
$latestParent = null;
|
||||||
$subCollectionCounts = []; //total project level count of sub collections
|
$subCollectionCounts = []; //total project level count of sub collections
|
||||||
|
$subCollectionTotals = []; //total project level sum of sub collections
|
||||||
|
|
||||||
do { // Loop over all the parent collection document for each sub collection
|
do { // Loop over all the parent collection document for each sub collection
|
||||||
$dbForProject->setNamespace("project_{$projectId}_{$options['namespace']}");
|
$dbForProject->setNamespace("project_{$projectId}_{$options['namespace']}");
|
||||||
|
@ -525,7 +547,7 @@ $cli
|
||||||
foreach ($parents as $parent) {
|
foreach ($parents as $parent) {
|
||||||
foreach ($subCollections as $subCollection => $subOptions) { // Sub collection counts, like database.collections.collectionId.documents.count
|
foreach ($subCollections as $subCollection => $subOptions) { // Sub collection counts, like database.collections.collectionId.documents.count
|
||||||
$dbForProject->setNamespace("project_{$projectId}_{$subOptions['namespace']}");
|
$dbForProject->setNamespace("project_{$projectId}_{$subOptions['namespace']}");
|
||||||
$count = $dbForProject->count($parent->getId());
|
$count = $dbForProject->count(($subOptions['collectionPrefix'] ?? '') . $parent->getId());
|
||||||
|
|
||||||
$subCollectionCounts[$subCollection] = ($subCollectionCounts[$subCollection] ?? 0) + $count; // Project level counts for sub collections like database.documents.count
|
$subCollectionCounts[$subCollection] = ($subCollectionCounts[$subCollection] ?? 0) + $count; // Project level counts for sub collections like database.documents.count
|
||||||
|
|
||||||
|
@ -571,6 +593,55 @@ $cli
|
||||||
$document->setAttribute('value', $count)
|
$document->setAttribute('value', $count)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if sum calculation is required
|
||||||
|
$sum = $subOptions['sum'] ?? [];
|
||||||
|
if(empty($sum)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$dbForProject->setNamespace("project_{$projectId}_{$subOptions['namespace']}");
|
||||||
|
$total = (int) $dbForProject->sum(($subOptions['collectionPrefix'] ?? '') . $parent->getId(), $sum['field']);
|
||||||
|
|
||||||
|
$subCollectionTotals[$subCollection] = ($ssubCollectionTotals[$subCollection] ?? 0) + $total; // Project level sum for sub collections like storage.total
|
||||||
|
|
||||||
|
$dbForProject->setNamespace("project_{$projectId}_internal");
|
||||||
|
|
||||||
|
$metric = empty($metricPrefix) ? "{$collection}.{$parent->getId()}.{$subCollection}.total" : "{$metricPrefix}.{$collection}.{$parent->getId()}.{$subCollection}.total";
|
||||||
|
$time = (int) (floor(time() / 1800) * 1800); // Time rounded to nearest 30 minutes
|
||||||
|
$id = \md5($time . '_30m_' . $metric); //Construct unique id for each metric using time, period and metric
|
||||||
|
$document = $dbForProject->getDocument('stats', $id);
|
||||||
|
if ($document->isEmpty()) {
|
||||||
|
$dbForProject->createDocument('stats', new Document([
|
||||||
|
'$id' => $id,
|
||||||
|
'time' => $time,
|
||||||
|
'period' => '30m',
|
||||||
|
'metric' => $metric,
|
||||||
|
'value' => $total,
|
||||||
|
'type' => 1,
|
||||||
|
]));
|
||||||
|
} else {
|
||||||
|
$dbForProject->updateDocument('stats', $document->getId(),
|
||||||
|
$document->setAttribute('value', $total));
|
||||||
|
}
|
||||||
|
|
||||||
|
$time = (int) (floor(time() / 86400) * 86400); // Time rounded to nearest day
|
||||||
|
$id = \md5($time . '_1d_' . $metric); //Construct unique id for each metric using time, period and metric
|
||||||
|
$document = $dbForProject->getDocument('stats', $id);
|
||||||
|
if ($document->isEmpty()) {
|
||||||
|
$dbForProject->createDocument('stats', new Document([
|
||||||
|
'$id' => $id,
|
||||||
|
'time' => $time,
|
||||||
|
'period' => '1d',
|
||||||
|
'metric' => $metric,
|
||||||
|
'value' => $total,
|
||||||
|
'type' => 1,
|
||||||
|
]));
|
||||||
|
} else {
|
||||||
|
$dbForProject->updateDocument('stats', $document->getId(),
|
||||||
|
$document->setAttribute('value', $total));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (!empty($parents));
|
} while (!empty($parents));
|
||||||
|
@ -623,6 +694,49 @@ $cli
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserting project level sums for sub collections like storage.total
|
||||||
|
*/
|
||||||
|
foreach ($subCollectionTotals as $subCollection => $count) {
|
||||||
|
$dbForProject->setNamespace("project_{$projectId}_internal");
|
||||||
|
|
||||||
|
$metric = empty($metricPrefix) ? "{$subCollection}.total" : "{$metricPrefix}.{$subCollection}.total";
|
||||||
|
|
||||||
|
$time = (int) (floor(time() / 1800) * 1800); // Time rounded to nearest 30 minutes
|
||||||
|
$id = \md5($time . '_30m_' . $metric); //Construct unique id for each metric using time, period and metric
|
||||||
|
$document = $dbForProject->getDocument('stats', $id);
|
||||||
|
if ($document->isEmpty()) {
|
||||||
|
$dbForProject->createDocument('stats', new Document([
|
||||||
|
'$id' => $id,
|
||||||
|
'time' => $time,
|
||||||
|
'period' => '30m',
|
||||||
|
'metric' => $metric,
|
||||||
|
'value' => $count,
|
||||||
|
'type' => 1,
|
||||||
|
]));
|
||||||
|
} else {
|
||||||
|
$dbForProject->updateDocument('stats', $document->getId(),
|
||||||
|
$document->setAttribute('value', $count));
|
||||||
|
}
|
||||||
|
|
||||||
|
$time = (int) (floor(time() / 86400) * 86400); // Time rounded to nearest day
|
||||||
|
$id = \md5($time . '_1d_' . $metric); //Construct unique id for each metric using time, period and metric
|
||||||
|
$document = $dbForProject->getDocument('stats', $id);
|
||||||
|
if ($document->isEmpty()) {
|
||||||
|
$dbForProject->createDocument('stats', new Document([
|
||||||
|
'$id' => $id,
|
||||||
|
'time' => $time,
|
||||||
|
'period' => '1d',
|
||||||
|
'metric' => $metric,
|
||||||
|
'value' => $count,
|
||||||
|
'type' => 1,
|
||||||
|
]));
|
||||||
|
} else {
|
||||||
|
$dbForProject->updateDocument('stats', $document->getId(),
|
||||||
|
$document->setAttribute('value', $count));
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (\Exception$e) {
|
} catch (\Exception$e) {
|
||||||
Console::warning("Failed to save database counters data for project {$collection}: {$e->getMessage()}");
|
Console::warning("Failed to save database counters data for project {$collection}: {$e->getMessage()}");
|
||||||
}
|
}
|
||||||
|
|
492
app/views/console/storage/bucket.phtml
Normal file
492
app/views/console/storage/bucket.phtml
Normal file
|
@ -0,0 +1,492 @@
|
||||||
|
<?php
|
||||||
|
$home = $this->getParam('home', '');
|
||||||
|
$fileLimit = $this->getParam('fileLimit', 0);
|
||||||
|
$fileLimitHuman = $this->getParam('fileLimitHuman', 0);
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div
|
||||||
|
data-service="storage.getBucket"
|
||||||
|
data-param-bucket-id="{{router.params.id}}"
|
||||||
|
data-scope="sdk"
|
||||||
|
data-event="load,storage.updateBucket"
|
||||||
|
data-name="project-bucket">
|
||||||
|
|
||||||
|
<div class="cover">
|
||||||
|
<h1 class="zone xl margin-bottom-large">
|
||||||
|
<a data-ls-attrs="href=/console/storage?project={{router.params.project}}" class="back text-size-small link-return-animation--start"><i class="icon-left-open"></i> Storage</a>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<span data-ls-bind="{{project-bucket.name}}"> </span>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div data-ui-modal class="modal width-large box close" data-button-hide="on" data-open-event="open-json">
|
||||||
|
<button type="button" class="close pull-end" data-ui-modal-close=""><i class="icon-cancel"></i></button>
|
||||||
|
|
||||||
|
<h2>JSON View</h2>
|
||||||
|
|
||||||
|
<div class="margin-bottom">
|
||||||
|
<input type="hidden" data-ls-bind="{{project-bucket}}" data-forms-code />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="zone xl">
|
||||||
|
<ul class="phases clear" data-ui-phases data-selected="{{router.params.tab}}">
|
||||||
|
<li data-state="/console/storage/bucket?id={{router.params.id}}&project={{router.params.project}}">
|
||||||
|
<h2 class="margin-bottom">Files</h2>
|
||||||
|
|
||||||
|
<form class="box padding-small margin-bottom search"
|
||||||
|
data-service="storage.listFiles"
|
||||||
|
data-event="submit"
|
||||||
|
data-param-bucket-id="{{router.params.id}}"
|
||||||
|
data-param-search="{{router.params.search}}"
|
||||||
|
data-param-limit="<?php echo APP_PAGING_LIMIT; ?>"
|
||||||
|
data-param-offset=""
|
||||||
|
data-param-order-type="DESC"
|
||||||
|
data-scope="sdk"
|
||||||
|
data-name="project-files"
|
||||||
|
data-success="state"
|
||||||
|
data-success-param-state-keys="search,offset">
|
||||||
|
<div class="row thin responsive">
|
||||||
|
<div class="col span-10">
|
||||||
|
<input name="search" id="searchFiles" type="search" autocomplete="off" placeholder="Search" class="margin-bottom-no" data-ls-bind="{{router.params.search}}">
|
||||||
|
</div>
|
||||||
|
<div class="col span-2 desktops-only">
|
||||||
|
<button class="fill" title="Search" aria-label="Search">Search</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div
|
||||||
|
data-service="storage.listFiles"
|
||||||
|
data-event="load,storage.createFile,storage.updateFile,storage.deleteFile"
|
||||||
|
data-param-bucket-id="{{router.params.id}}"
|
||||||
|
data-param-search="{{router.params.search}}"
|
||||||
|
data-param-limit="<?php echo APP_PAGING_LIMIT; ?>"
|
||||||
|
data-param-offset="{{router.params.offset}}"
|
||||||
|
data-param-order-type="DESC"
|
||||||
|
data-scope="sdk"
|
||||||
|
data-name="project-files">
|
||||||
|
|
||||||
|
<div data-ls-if="0 == {{project-files.sum}}" class="box margin-bottom">
|
||||||
|
<h3 class="margin-bottom-small text-bold">No Files Found</h3>
|
||||||
|
|
||||||
|
<p class="margin-bottom-no">Upload your first file to get started</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div data-ls-if="0 != {{project-files.sum}}">
|
||||||
|
<div class="margin-bottom-small text-align-end text-size-small text-fade"><span data-ls-bind="{{project-files.sum}}"></span> files found</div>
|
||||||
|
|
||||||
|
<div class="box margin-bottom">
|
||||||
|
<table class="vertical">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th width="40"></th>
|
||||||
|
<th>Filename</th>
|
||||||
|
<th width="140">Type</th>
|
||||||
|
<th width="100">Size</th>
|
||||||
|
<th width="120">Created</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody data-ls-loop="project-files.files" data-ls-as="file">
|
||||||
|
<tr>
|
||||||
|
<td class="hide">
|
||||||
|
<img src="" data-ls-attrs="src={{env.ENDPOINT}}/v1/storage/buckets/{{router.params.id}}/files/{{file.$id}}/preview?width=65&height=65&project={{router.params.project}}&mode=admin" class="pull-start avatar" width="30" height="30" loading="lazy" />
|
||||||
|
</td>
|
||||||
|
<td data-title="Name: " class="text-one-liner" data-ls-attrs="title={{file.name}}" >
|
||||||
|
<div data-ui-modal class="box modal sticky-footer width-large close" data-button-text="{{file.name}}" data-button-class="link" data-button-element="span">
|
||||||
|
<button type="button" class="close pull-end" data-ui-modal-close=""><i class="icon-cancel"></i></button>
|
||||||
|
|
||||||
|
<h1>Update File</h1>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<div class="row responsive modalize">
|
||||||
|
<div class="col span-8">
|
||||||
|
<form class="strip"
|
||||||
|
data-analytics
|
||||||
|
data-analytics-activity
|
||||||
|
data-analytics-event="submit"
|
||||||
|
data-analytics-category="console"
|
||||||
|
data-analytics-label="Update Storage File"
|
||||||
|
data-service="storage.updateFile"
|
||||||
|
data-event="file-update-{{file.$id}}"
|
||||||
|
data-scope="sdk"
|
||||||
|
data-success="alert,trigger"
|
||||||
|
data-success-param-alert-text="File updated successfully"
|
||||||
|
data-success-param-trigger-events="storage.updateFile"
|
||||||
|
data-failure="alert"
|
||||||
|
data-failure-param-alert-text="Failed to update file"
|
||||||
|
data-failure-param-alert-classname="error">
|
||||||
|
|
||||||
|
<label for="files-fileId">File ID</label>
|
||||||
|
<div class="input-copy">
|
||||||
|
<input data-forms-copy type="text" data-ls-attrs="id=file-id-{{file.$id}}" name="fileId" disabled data-ls-bind="{{file.$id}}" />
|
||||||
|
</div>
|
||||||
|
<input type="hidden" data-ls-attrs="id=file-bucketId-{{file.$id}}" name="bucketId" data-ls-bind="{{file.bucketId}}">
|
||||||
|
|
||||||
|
<label for="file-read">Read Access (<a data-ls-attrs="href={{env.HOME}}/docs/permissions" target="_blank" rel="noopener">Learn more</a>)</label>
|
||||||
|
<input type="hidden" data-ls-attrs="id=file-read-{{file.$id}}" name="read" data-forms-tags data-cast-to="json" data-ls-bind="{{file.$read}}" placeholder="User ID, Team ID or Role" />
|
||||||
|
<div class="text-fade text-size-xs margin-top-negative-small margin-bottom">Add 'role:all' for wildcard access</div>
|
||||||
|
|
||||||
|
<label for="file-write">Write Access (<a data-ls-attrs="href={{env.HOME}}/docs/permissions" target="_blank" rel="noopener">Learn more</a>)</label>
|
||||||
|
<input type="hidden" data-ls-attrs="id=file-write-{{file.$id}}" name="write" data-forms-tags data-cast-to="json" data-ls-bind="{{file.$write}}" placeholder="User ID, Team ID or Role" />
|
||||||
|
<div class="text-fade text-size-xs margin-top-negative-small margin-bottom">Add 'role:all' for wildcard access</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<form class="strip"
|
||||||
|
data-analytics
|
||||||
|
data-analytics-activity
|
||||||
|
data-analytics-event="submit"
|
||||||
|
data-analytics-category="console"
|
||||||
|
data-analytics-label="Delete File"
|
||||||
|
data-service="storage.deleteFile"
|
||||||
|
data-scope="sdk"
|
||||||
|
data-event="file-delete-{{file.$id}}"
|
||||||
|
data-confirm="Are you sure you want to delete this file?"
|
||||||
|
data-success="alert,trigger"
|
||||||
|
data-success-param-alert-text="Deleted file successfully"
|
||||||
|
data-success-param-trigger-events="storage.deleteFile"
|
||||||
|
data-failure="alert"
|
||||||
|
data-failure-param-alert-text="Failed to delete file"
|
||||||
|
data-failure-param-alert-classname="error">
|
||||||
|
|
||||||
|
<input type="hidden" name="bucketId" data-ls-bind="{{file.bucketId}}" />
|
||||||
|
<input type="hidden" name="fileId" data-ls-bind="{{file.$id}}" />
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="col span-4 text-size-small">
|
||||||
|
<div class="margin-bottom-small">File Preview</div>
|
||||||
|
|
||||||
|
<div class="margin-bottom-small">
|
||||||
|
<img src="" class="file-preview" data-ls-attrs="src={{env.ENDPOINT}}/v1/storage/buckets/{{router.params.id}}/files/{{file.$id}}/preview?width=350&height=250&project={{router.params.project}}&mode=admin" loading="lazy" width="225" height="160" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="margin-bottom-tiny">
|
||||||
|
<a href="" data-ls-attrs="href={{env.ENDPOINT}}/v1/storage/buckets/{{router.params.id}}/files/{{file.$id}}/view?project={{router.params.project}}&mode=admin" target="_blank" rel="noopener"><i class="icon-angle-circled-right margin-start-negative-tiny margin-end-tiny"></i> New Window <i class="icon-link-ext"></i></a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="margin-bottom-small">
|
||||||
|
<a href="" data-ls-attrs="href={{env.ENDPOINT}}/v1/storage/buckets/{{router.params.id}}/files/{{file.$id}}/download?project={{router.params.project}}&mode=admin" target="_blank" rel="noopener"><i class="icon-angle-circled-right margin-start-negative-tiny margin-end-tiny"></i> Download <i class="icon-link-ext"></i></a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="margin-bottom-tiny">
|
||||||
|
<i class="icon-angle-circled-right margin-start-negative-tiny margin-end-tiny"></i> Type: <span data-ls-bind="{{file.mimeType}}"></span>
|
||||||
|
</div>
|
||||||
|
<div class="margin-bottom-tiny">
|
||||||
|
<i class="icon-angle-circled-right margin-start-negative-tiny margin-end-tiny"></i> Size: <span data-ls-bind="{{file.sizeOriginal|humanFileSize}}"></span>
|
||||||
|
<span data-ls-bind="{{file.sizeOriginal|humanFileUnit}}"></span>
|
||||||
|
</div>
|
||||||
|
<div class="margin-bottom">
|
||||||
|
<i class="icon-angle-circled-right margin-start-negative-tiny margin-end-tiny"></i> Created at: <span data-ls-bind="{{file.dateCreated|dateText}}"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<button class="link pull-end text-danger" data-ls-ui-trigger="file-delete-{{file.$id}},modal-close">Delete File</button>
|
||||||
|
<button type="button" data-ls-ui-trigger="file-update-{{file.$id}},modal-close">Update</button> <button data-ui-modal-close="" type="button" class="reverse desktops-only-inline tablets-only-inline">Cancel</button>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td data-title="Type: ">
|
||||||
|
<span class="text-fade text-size-small" data-ls-bind="{{file.mimeType}}"></span>
|
||||||
|
</td>
|
||||||
|
<td data-title="Size: ">
|
||||||
|
<span class="text-fade text-size-small" data-ls-bind="{{file.sizeOriginal|humanFileSize}}"></span>
|
||||||
|
<span class="text-fade text-size-small" data-ls-bind="{{file.sizeOriginal|humanFileUnit}}"></span>
|
||||||
|
</td>
|
||||||
|
<td data-title="Created: ">
|
||||||
|
<span class="text-fade text-size-small" data-ls-bind="{{file.dateCreated|dateText}}"></span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pull-end text-align-center paging">
|
||||||
|
<form
|
||||||
|
data-service="storage.listFiles"
|
||||||
|
data-event="submit"
|
||||||
|
data-param-search="{{router.params.search}}"
|
||||||
|
data-param-limit="<?php echo APP_PAGING_LIMIT; ?>"
|
||||||
|
data-param-order-type="DESC"
|
||||||
|
data-scope="sdk"
|
||||||
|
data-name="project-files"
|
||||||
|
data-success="state"
|
||||||
|
data-success-param-state-keys="search,offset">
|
||||||
|
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-sum="{{project-files.sum}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-files.sum|pageTotal}}"></span>
|
||||||
|
|
||||||
|
<form
|
||||||
|
data-service="storage.listFiles"
|
||||||
|
data-event="submit"
|
||||||
|
data-param-search="{{router.params.search}}"
|
||||||
|
data-param-limit="<?php echo APP_PAGING_LIMIT; ?>"
|
||||||
|
data-param-order-type="DESC"
|
||||||
|
data-scope="sdk"
|
||||||
|
data-name="project-files"
|
||||||
|
data-success="state"
|
||||||
|
data-success-param-state-keys="search,offset">
|
||||||
|
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-sum="{{project-files.sum}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div data-ui-modal class="box modal sticky-footer close" data-button-text="Add File">
|
||||||
|
<button type="button" class="close pull-end" data-ui-modal-close=""><i class="icon-cancel"></i></button>
|
||||||
|
|
||||||
|
<h1>Upload File</h1>
|
||||||
|
|
||||||
|
<form
|
||||||
|
data-analytics
|
||||||
|
data-analytics-activity
|
||||||
|
data-analytics-event="submit"
|
||||||
|
data-analytics-category="console"
|
||||||
|
data-analytics-label="Create Storage File"
|
||||||
|
data-service="storage.createFile"
|
||||||
|
data-event="submit"
|
||||||
|
data-scope="sdk"
|
||||||
|
data-loading="Uploading File..."
|
||||||
|
data-success="alert,trigger,reset"
|
||||||
|
data-success-param-alert-text="File uploaded successfully"
|
||||||
|
data-success-param-trigger-events="storage.createFile"
|
||||||
|
data-failure="alert"
|
||||||
|
data-failure-param-alert-text="Failed to upload file"
|
||||||
|
data-failure-param-alert-classname="error">
|
||||||
|
<input type="hidden" name="bucketId" id="files-bucketId" data-ls-bind="{{router.params.id}}">
|
||||||
|
|
||||||
|
<label for="fileId">File ID</label>
|
||||||
|
<input
|
||||||
|
type="hidden"
|
||||||
|
data-custom-id
|
||||||
|
data-id-type="auto"
|
||||||
|
data-validator="storage.getFile"
|
||||||
|
required
|
||||||
|
maxlength="36"
|
||||||
|
name="fileId"
|
||||||
|
id="fileId" />
|
||||||
|
|
||||||
|
<label for="file-read">File</label>
|
||||||
|
<input type="file" name="file" id="file-file" size="1" required>
|
||||||
|
|
||||||
|
<div class="text-fade text-size-xs margin-top-negative-small margin-bottom">(Max file size allowed: <?php echo $fileLimitHuman; ?>)</div>
|
||||||
|
|
||||||
|
<label for="file-read">Read Access (<a data-ls-attrs="href={{env.HOME}}/docs/permissions" target="_blank" rel="noopener">Learn more</a>)</label>
|
||||||
|
<input type="hidden" id="file-read" name="read" data-forms-tags data-cast-to="json" value="<?php echo htmlentities(json_encode(['role:all'])); ?>" placeholder="User ID, Team ID or Role" />
|
||||||
|
<div class="text-fade text-size-xs margin-top-negative-small margin-bottom">Add 'role:all' for wildcard access</div>
|
||||||
|
|
||||||
|
<label for="file-write">Write Access (<a data-ls-attrs="href={{env.HOME}}/docs/permissions" target="_blank" rel="noopener">Learn more</a>)</label>
|
||||||
|
<input type="hidden" id="file-write" name="write" data-forms-tags data-cast-to="json" value="" placeholder="User ID, Team ID or Role" />
|
||||||
|
<div class="text-fade text-size-xs margin-top-negative-small margin-bottom">Add 'role:all' for wildcard access</div>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<button type="submit">Create</button> <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
|
||||||
|
</footer>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li data-state="/console/storage/bucket/usage?id={{router.params.id}}&project={{router.params.project}}">
|
||||||
|
<form
|
||||||
|
class="pull-end margin-start-small margin-top-small" data-ls-if="{{usage.range}} !== '90d'"
|
||||||
|
data-service="storage.getBucketUsage"
|
||||||
|
data-event="submit"
|
||||||
|
data-name="usage"
|
||||||
|
data-param-bucket-id="{{router.params.id}}"
|
||||||
|
data-param-range="90d">
|
||||||
|
<button class="tick">90d</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<button class="tick pull-end margin-start-small margin-top-small" data-ls-if="{{usage.range}} === '90d'" disabled>90d</button>
|
||||||
|
|
||||||
|
<form
|
||||||
|
class="pull-end margin-start-small margin-top-small" data-ls-if="{{usage.range}} !== '30d'"
|
||||||
|
data-service="storage.getBucketUsage"
|
||||||
|
data-event="submit"
|
||||||
|
data-name="usage"
|
||||||
|
data-param-bucket-id="{{router.params.id}}">
|
||||||
|
<button class="tick">30d</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<button class="tick pull-end margin-start-small margin-top-small" data-ls-if="{{usage.range}} === '30d'" disabled>30d</button>
|
||||||
|
|
||||||
|
<form
|
||||||
|
class="pull-end margin-start-small margin-top-small" data-ls-if="{{usage.range}} !== '24h'"
|
||||||
|
data-service="storage.getBucketUsage"
|
||||||
|
data-event="submit"
|
||||||
|
data-name="usage"
|
||||||
|
data-param-bucket-id="{{router.params.id}}"
|
||||||
|
data-param-range="24h">
|
||||||
|
<button class="tick">24h</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<button class="tick pull-end margin-start-small margin-top-small" data-ls-if="{{usage.range}} === '24h'" disabled>24h</button>
|
||||||
|
|
||||||
|
<h2>Usage</h2>
|
||||||
|
|
||||||
|
<div data-service="storage.getBucketUsage" data-event="load" data-name="usage" data-param-bucket-id="{{router.params.id}}">
|
||||||
|
<h3 class="margin-bottom-tiny">Files</h3>
|
||||||
|
<p class="text-fade">Count of files over time</p>
|
||||||
|
<div class="box margin-bottom-small">
|
||||||
|
<div class="margin-start-negative-small margin-end-negative-small margin-top-negative-small margin-bottom-negative-small">
|
||||||
|
<div class="chart background-image-no border-no margin-bottom-no">
|
||||||
|
<input type="hidden" data-ls-bind="{{usage}}" data-show-y-axis="true" data-forms-chart="Files=filesCount" data-height="140" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="chart-notes margin-bottom-large">
|
||||||
|
<li>Files </li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3 class="margin-bottom-tiny">Operations</h3>
|
||||||
|
<p class="text-fade">Count of files create, read, update and delete operations over time</p>
|
||||||
|
<div class="box margin-bottom-small">
|
||||||
|
<div class="margin-start-negative-small margin-end-negative-small margin-top-negative-small margin-bottom-negative-small">
|
||||||
|
<div class="chart background-image-no border-no margin-bottom-no">
|
||||||
|
<input type="hidden" data-ls-bind="{{usage}}" data-show-y-axis="true" data-forms-chart="Create=filesCreate,Read=filesRead,Updated=filesUpdate,Deleted=filesDelete" data-colors="create,read,update,delete" data-height="140" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="chart-notes crud margin-bottom-large">
|
||||||
|
<li>Create</li>
|
||||||
|
<li>Read</li>
|
||||||
|
<li>Update</li>
|
||||||
|
<li>Delete</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li data-state="/console/storage/bucket/settings?id={{router.params.id}}&project={{router.params.project}}">
|
||||||
|
<h2>Settings</h2>
|
||||||
|
|
||||||
|
<div class="row responsive margin-top-negative">
|
||||||
|
<div class="col span-8 margin-bottom">
|
||||||
|
<form
|
||||||
|
data-analytics
|
||||||
|
data-analytics-activity
|
||||||
|
data-analytics-event="submit"
|
||||||
|
data-analytics-category="console"
|
||||||
|
data-analytics-label="Update Storage Bucket"
|
||||||
|
data-service="storage.updateBucket"
|
||||||
|
data-scope="sdk"
|
||||||
|
data-event="submit"
|
||||||
|
data-param-bucket-id="{{router.params.id}}"
|
||||||
|
data-success="alert,trigger"
|
||||||
|
data-success-param-alert-text="Updated bucket successfully"
|
||||||
|
data-success-param-trigger-events="storage.updateBucket"
|
||||||
|
data-failure="alert"
|
||||||
|
data-failure-param-alert-text="Failed to update bucket"
|
||||||
|
data-failure-param-alert-classname="error">
|
||||||
|
|
||||||
|
<label> </label>
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
|
<label for="bucket-name">Name</label>
|
||||||
|
<input name="name" id="bucket-name" type="text" autocomplete="off" data-ls-bind="{{project-bucket.name}}" data-forms-text-direction required placeholder="Bucket Name" maxlength="128" />
|
||||||
|
|
||||||
|
<label for="bucket-maximum-file-size">Maximum File Size (bytes) <span class="tooltip small" data-tooltip="Limit file size allowed in the bucket."><i class="icon-info-circled"></i></span></label>
|
||||||
|
<input name="maximumFileSize" id="bucket-maximum-file-size" type="number" autocomplete="off" data-ls-bind="{{project-bucket.maximumFileSize}}" min="1" data-cast-to="integer" />
|
||||||
|
|
||||||
|
<div class="margin-bottom">
|
||||||
|
<input name="enabled" type="hidden" data-forms-switch data-cast-to="boolean" data-ls-bind="{{project-bucket.enabled}}" /> Enabled <span class="tooltip" data-tooltip="Mark whether bucket is enabled"><i class="icon-info-circled"></i></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="margin-bottom">
|
||||||
|
<input name="encryption" type="hidden" data-forms-switch data-cast-to="boolean" data-ls-bind="{{project-bucket.encryption}}" /> Encryption <span class="tooltip" data-tooltip="Mark whether bucket is encrypted"><i class="icon-info-circled"></i></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="margin-bottom">
|
||||||
|
<input name="antiVirus" type="hidden" data-forms-switch data-cast-to="boolean" data-ls-bind="{{project-bucket.antiVirus}}" /> Anti Virus <span class="tooltip" data-tooltip="Mark whether anti virus scanning is enabled"><i class="icon-info-circled"></i></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label for="bucket-allowedFileExtensions">Allowed File Extensions</label>
|
||||||
|
<input type="hidden" id="bucket-allowedFileExtensions" name="allowedFileExtensions" data-forms-tags data-cast-to="json" data-ls-bind="{{project-bucket.allowedFileExtensions}}" placeholder="Allowed file extensions (pdf, mp4)" />
|
||||||
|
<div class="text-fade text-size-xs margin-top-negative-small margin-bottom">Leave empty to allow all.</div>
|
||||||
|
|
||||||
|
|
||||||
|
<label class="margin-bottom-small">Permissions</label>
|
||||||
|
|
||||||
|
<p class="text-fade text-size-small">Choose the permissions model for this bucket.</p>
|
||||||
|
|
||||||
|
<hr class="margin-top-small" />
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col span-1"><input name="permission" value="file" type="radio" class="margin-top-no" data-ls-bind="{{project-bucket.permission}}" /></div>
|
||||||
|
<div class="col span-11">
|
||||||
|
<b>File Level</b>
|
||||||
|
<p class="text-fade margin-top-tiny">With File Level permissions, you have granular access control over every file. Users will only be able to access files for which they have explicit permissions.</p>
|
||||||
|
<p class="text-fade margin-top-tiny">In this permission level file permissions take precedence and bucket permissions are ignored.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col span-1"><input name="permission" value="bucket" type="radio" class="margin-top-tiny" data-ls-bind="{{project-bucket.permission}}" /></div>
|
||||||
|
<div class="col span-11">
|
||||||
|
<b>Bucket Level</b>
|
||||||
|
<p class="text-fade margin-top-tiny">With Bucket Level permissions, you assign permissions only once in the bucket.</p>
|
||||||
|
<p class="text-fade margin-top-tiny">In this permission level permissions assigned to bucket takes the precedence and file permissions are ignored</p>
|
||||||
|
<div data-ls-if="{{project-bucket.permission}} == 'bucket'">
|
||||||
|
|
||||||
|
<label for="bucket-read">Read Access <span class="text-size-small">(<a data-ls-attrs="href={{env.HOME}}/docs/permissions" target="_blank" rel="noopener">Learn more</a>)</span></label>
|
||||||
|
<input type="hidden" id="bucket-read" name="read" data-forms-tags data-cast-to="json" data-ls-bind="{{project-bucket.$permissions.read}}" placeholder="User ID, Team ID or Role" />
|
||||||
|
<div class="text-fade text-size-xs margin-top-negative-small margin-bottom">Add * for wildcard access</div>
|
||||||
|
|
||||||
|
<label for="bucket-write">Write Access <span class="text-size-small">(<a data-ls-attrs="href={{env.HOME}}/docs/permissions" target="_blank" rel="noopener">Learn more</a>)</label>
|
||||||
|
<input type="hidden" id="bucket-write" name="write" data-forms-tags data-cast-to="json" data-ls-bind="{{project-bucket.$permissions.write}}" placeholder="User ID, Team ID or Role" />
|
||||||
|
<div class="text-fade text-size-xs margin-top-negative-small margin-bottom">Add * for wildcard access</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr class="margin-top-no" />
|
||||||
|
|
||||||
|
<button>Update</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col span-4 sticky-top">
|
||||||
|
<label>Bucket ID</label>
|
||||||
|
<div class="input-copy margin-bottom">
|
||||||
|
<input id="id" type="text" autocomplete="off" placeholder="" data-ls-bind="{{project-bucket.$id}}" disabled data-forms-copy class="margin-bottom-no" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="margin-bottom-large text-fade text-size-small">
|
||||||
|
<li class="margin-bottom-small"><i class="icon-angle-circled-right margin-start-tiny margin-end-tiny"></i> <button data-ls-ui-trigger="open-json" class="link text-size-small">View as JSON</button></li>
|
||||||
|
<li class="margin-bottom-small"><i class="icon-angle-circled-right margin-start-tiny margin-end-tiny"></i> Last Updated: <span data-ls-bind="{{project-bucket.dateUpdated|dateText}}"></span></li>
|
||||||
|
<li class="margin-bottom-small"><i class="icon-angle-circled-right margin-start-tiny margin-end-tiny"></i> Created: <span data-ls-bind="{{project-bucket.dateCreated|dateText}}"></span></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<form name="storage.deleteBucket" class="margin-bottom"
|
||||||
|
data-analytics
|
||||||
|
data-analytics-activity
|
||||||
|
data-analytics-event="submit"
|
||||||
|
data-analytics-category="console"
|
||||||
|
data-analytics-label="Delete Storage Bucket"
|
||||||
|
data-service="storage.deleteBucket"
|
||||||
|
data-event="submit"
|
||||||
|
data-param-bucket-id="{{router.params.id}}"
|
||||||
|
data-confirm="Are you sure you want to delete this bucket?"
|
||||||
|
data-success="alert,trigger,redirect"
|
||||||
|
data-success-param-alert-text="Bucket deleted successfully"
|
||||||
|
data-success-param-trigger-events="storage.deleteBucket"
|
||||||
|
data-success-param-redirect-url="/console/storage?project={{router.params.project}}"
|
||||||
|
data-failure="alert"
|
||||||
|
data-failure-param-alert-text="Failed to delete bucket"
|
||||||
|
data-failure-param-alert-classname="error">
|
||||||
|
|
||||||
|
<button type="submit" class="danger fill">Delete Bucket</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
|
@ -1,8 +1,3 @@
|
||||||
<?php
|
|
||||||
$home = $this->getParam('home', '');
|
|
||||||
$fileLimit = $this->getParam('fileLimit', 0);
|
|
||||||
$fileLimitHuman = $this->getParam('fileLimitHuman', 0);
|
|
||||||
?>
|
|
||||||
<div class="cover">
|
<div class="cover">
|
||||||
<h1 class="zone xl margin-bottom-large">
|
<h1 class="zone xl margin-bottom-large">
|
||||||
<a data-ls-attrs="href=/console/home?project={{router.params.project}}" class="back text-size-small link-return-animation--start"><i class="icon-left-open"></i> Home</a>
|
<a data-ls-attrs="href=/console/home?project={{router.params.project}}" class="back text-size-small link-return-animation--start"><i class="icon-left-open"></i> Home</a>
|
||||||
|
@ -15,260 +10,115 @@ $fileLimitHuman = $this->getParam('fileLimitHuman', 0);
|
||||||
<div class="zone xl">
|
<div class="zone xl">
|
||||||
<ul class="phases clear" data-ui-phases data-selected="{{router.params.tab}}">
|
<ul class="phases clear" data-ui-phases data-selected="{{router.params.tab}}">
|
||||||
<li data-state="/console/storage?project={{router.params.project}}">
|
<li data-state="/console/storage?project={{router.params.project}}">
|
||||||
<h2 class="margin-bottom">Files</h2>
|
<h2>Buckets</h2>
|
||||||
|
|
||||||
<form class="box padding-small margin-bottom search"
|
<div class="margin-top"
|
||||||
data-service="storage.listFiles"
|
data-service="storage.listBuckets"
|
||||||
data-event="submit"
|
data-event="load,storage.createBucket,storage.updateBucket,storage.deleteBucket"
|
||||||
data-param-search="{{router.params.search}}"
|
|
||||||
data-param-limit="<?php echo APP_PAGING_LIMIT; ?>"
|
|
||||||
data-param-offset=""
|
|
||||||
data-param-order-type="DESC"
|
|
||||||
data-scope="sdk"
|
|
||||||
data-name="project-files"
|
|
||||||
data-success="state"
|
|
||||||
data-success-param-state-keys="search,offset">
|
|
||||||
<div class="row thin responsive">
|
|
||||||
<div class="col span-10">
|
|
||||||
<input name="search" id="searchFiles" type="search" autocomplete="off" placeholder="Search" class="margin-bottom-no" data-ls-bind="{{router.params.search}}">
|
|
||||||
</div>
|
|
||||||
<div class="col span-2 desktops-only">
|
|
||||||
<button class="fill" title="Search" aria-label="Search">Search</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div
|
|
||||||
data-service="storage.listFiles"
|
|
||||||
data-event="load,storage.createFile,storage.updateFile,storage.deleteFile"
|
|
||||||
data-param-search="{{router.params.search}}"
|
data-param-search="{{router.params.search}}"
|
||||||
data-param-limit="<?php echo APP_PAGING_LIMIT; ?>"
|
data-param-limit="<?php echo APP_PAGING_LIMIT; ?>"
|
||||||
data-param-offset="{{router.params.offset}}"
|
data-param-offset="{{router.params.offset}}"
|
||||||
data-param-order-type="DESC"
|
data-param-order-type="DESC"
|
||||||
data-scope="sdk"
|
data-scope="sdk"
|
||||||
data-name="project-files">
|
data-name="project-buckets">
|
||||||
|
|
||||||
<div data-ls-if="0 == {{project-files.sum}}" class="box margin-bottom">
|
<div data-ls-if="(!{{project-buckets.sum}})" class="box dashboard margin-bottom">
|
||||||
<h3 class="margin-bottom-small text-bold">No Files Found</h3>
|
<div class="margin-bottom-small margin-top-small margin-end margin-start">
|
||||||
|
<h3 class="margin-bottom-small text-bold">No Buckets Found</h3>
|
||||||
|
|
||||||
<p class="margin-bottom-no">Upload your first file to get started</p>
|
<p class="margin-bottom-no">You haven't created any buckets for your project yet.</p>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div data-ls-if="0 != {{project-files.sum}}">
|
|
||||||
<div class="margin-bottom-small text-align-end text-size-small text-fade"><span data-ls-bind="{{project-files.sum}}"></span> files found</div>
|
|
||||||
|
|
||||||
<div class="box margin-bottom">
|
|
||||||
<table class="vertical">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th width="40"></th>
|
|
||||||
<th>Filename</th>
|
|
||||||
<th width="140">Type</th>
|
|
||||||
<th width="100">Size</th>
|
|
||||||
<th width="120">Created</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody data-ls-loop="project-files.files" data-ls-as="file">
|
|
||||||
<tr>
|
|
||||||
<td class="hide">
|
|
||||||
<img src="" data-ls-attrs="src={{env.ENDPOINT}}/v1/storage/files/{{file.$id}}/preview?width=65&height=65&project={{router.params.project}}&mode=admin" class="pull-start avatar" width="30" height="30" loading="lazy" />
|
|
||||||
</td>
|
|
||||||
<td data-title="Name: " class="text-one-liner" data-ls-attrs="title={{file.name}}" >
|
|
||||||
<div data-ui-modal class="box modal sticky-footer width-large close" data-button-text="{{file.name}}" data-button-class="link" data-button-element="span">
|
|
||||||
<button type="button" class="close pull-end" data-ui-modal-close=""><i class="icon-cancel"></i></button>
|
|
||||||
|
|
||||||
<h1>Update File</h1>
|
|
||||||
|
|
||||||
<hr />
|
|
||||||
|
|
||||||
<div class="row responsive modalize">
|
|
||||||
<div class="col span-8">
|
|
||||||
<form class="strip"
|
|
||||||
data-analytics
|
|
||||||
data-analytics-activity
|
|
||||||
data-analytics-event="submit"
|
|
||||||
data-analytics-category="console"
|
|
||||||
data-analytics-label="Update Storage File"
|
|
||||||
data-service="storage.updateFile"
|
|
||||||
data-event="file-update-{{file.$id}}"
|
|
||||||
data-scope="sdk"
|
|
||||||
data-success="alert,trigger"
|
|
||||||
data-success-param-alert-text="File updated successfully"
|
|
||||||
data-success-param-trigger-events="storage.updateFile"
|
|
||||||
data-failure="alert"
|
|
||||||
data-failure-param-alert-text="Failed to update file"
|
|
||||||
data-failure-param-alert-classname="error">
|
|
||||||
|
|
||||||
<label for="files-fileId">File ID</label>
|
|
||||||
<div class="input-copy">
|
|
||||||
<input data-forms-copy type="text" data-ls-attrs="id=file-id-{{file.$id}}" name="fileId" disabled data-ls-bind="{{file.$id}}" />
|
|
||||||
</div>
|
|
||||||
<input type="hidden" data-ls-attrs="id=file-folderId-{{file.$id}}" name="folderId" data-cast-to="integer" value="1">
|
|
||||||
|
|
||||||
<label for="file-read">Read Access (<a data-ls-attrs="href={{env.HOME}}/docs/permissions" target="_blank" rel="noopener">Learn more</a>)</label>
|
|
||||||
<input type="hidden" data-ls-attrs="id=file-read-{{file.$id}}" name="read" data-forms-tags data-cast-to="json" data-ls-bind="{{file.$read}}" placeholder="User ID, Team ID or Role" />
|
|
||||||
<div class="text-fade text-size-xs margin-top-negative-small margin-bottom">Add 'role:all' for wildcard access</div>
|
|
||||||
|
|
||||||
<label for="file-write">Write Access (<a data-ls-attrs="href={{env.HOME}}/docs/permissions" target="_blank" rel="noopener">Learn more</a>)</label>
|
|
||||||
<input type="hidden" data-ls-attrs="id=file-write-{{file.$id}}" name="write" data-forms-tags data-cast-to="json" data-ls-bind="{{file.$write}}" placeholder="User ID, Team ID or Role" />
|
|
||||||
<div class="text-fade text-size-xs margin-top-negative-small margin-bottom">Add 'role:all' for wildcard access</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<form class="strip"
|
|
||||||
data-analytics
|
|
||||||
data-analytics-activity
|
|
||||||
data-analytics-event="submit"
|
|
||||||
data-analytics-category="console"
|
|
||||||
data-analytics-label="Delete File"
|
|
||||||
data-service="storage.deleteFile"
|
|
||||||
data-scope="sdk"
|
|
||||||
data-event="file-delete-{{file.$id}}"
|
|
||||||
data-confirm="Are you sure you want to delete this file?"
|
|
||||||
data-success="alert,trigger"
|
|
||||||
data-success-param-alert-text="Deleted file successfully"
|
|
||||||
data-success-param-trigger-events="storage.deleteFile"
|
|
||||||
data-failure="alert"
|
|
||||||
data-failure-param-alert-text="Failed to delete file"
|
|
||||||
data-failure-param-alert-classname="error">
|
|
||||||
|
|
||||||
<input type="hidden" name="fileId" data-ls-bind="{{file.$id}}" />
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="col span-4 text-size-small">
|
|
||||||
<div class="margin-bottom-small">File Preview</div>
|
|
||||||
|
|
||||||
<div class="margin-bottom-small">
|
|
||||||
<img src="" class="file-preview" data-ls-attrs="src={{env.ENDPOINT}}/v1/storage/files/{{file.$id}}/preview?width=350&height=250&project={{router.params.project}}&mode=admin" loading="lazy" width="225" height="160" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="margin-bottom-tiny">
|
|
||||||
<a href="" data-ls-attrs="href={{env.ENDPOINT}}/v1/storage/files/{{file.$id}}/view?project={{router.params.project}}&mode=admin" target="_blank" rel="noopener"><i class="icon-angle-circled-right margin-start-negative-tiny margin-end-tiny"></i> New Window <i class="icon-link-ext"></i></a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="margin-bottom-small">
|
|
||||||
<a href="" data-ls-attrs="href={{env.ENDPOINT}}/v1/storage/files/{{file.$id}}/download?project={{router.params.project}}&mode=admin" target="_blank" rel="noopener"><i class="icon-angle-circled-right margin-start-negative-tiny margin-end-tiny"></i> Download <i class="icon-link-ext"></i></a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="margin-bottom-tiny">
|
|
||||||
<i class="icon-angle-circled-right margin-start-negative-tiny margin-end-tiny"></i> Type: <span data-ls-bind="{{file.mimeType}}"></span>
|
|
||||||
</div>
|
|
||||||
<div class="margin-bottom-tiny">
|
|
||||||
<i class="icon-angle-circled-right margin-start-negative-tiny margin-end-tiny"></i> Size: <span data-ls-bind="{{file.sizeOriginal|humanFileSize}}"></span>
|
|
||||||
<span data-ls-bind="{{file.sizeOriginal|humanFileUnit}}"></span>
|
|
||||||
</div>
|
|
||||||
<div class="margin-bottom">
|
|
||||||
<i class="icon-angle-circled-right margin-start-negative-tiny margin-end-tiny"></i> Created at: <span data-ls-bind="{{file.dateCreated|dateText}}"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<footer>
|
<div data-ls-if="0 != {{project-buckets.sum}}">
|
||||||
<button class="link pull-end text-danger" data-ls-ui-trigger="file-delete-{{file.$id}},modal-close">Delete File</button>
|
<ul data-ls-loop="project-buckets.buckets" data-ls-as="bucket" data-ls-append="" class="tiles cell-3 margin-bottom-small">
|
||||||
<button type="button" data-ls-ui-trigger="file-update-{{file.$id}},modal-close">Update</button> <button data-ui-modal-close="" type="button" class="reverse desktops-only-inline tablets-only-inline">Cancel</button>
|
<li class="margin-bottom">
|
||||||
</footer>
|
<a data-ls-attrs="href=/console/storage/bucket?id={{bucket.$id}}&project={{router.params.project}}" class="box">
|
||||||
</div>
|
<div data-ls-bind="{{bucket.name}}" class="text-one-liner margin-bottom text-bold"> </div>
|
||||||
</td>
|
|
||||||
<td data-title="Type: ">
|
<i class="icon-right-open"></i>
|
||||||
<span class="text-fade text-size-small" data-ls-bind="{{file.mimeType}}"></span>
|
</a>
|
||||||
</td>
|
</li>
|
||||||
<td data-title="Size: ">
|
</ul>
|
||||||
<span class="text-fade text-size-small" data-ls-bind="{{file.sizeOriginal|humanFileSize}}"></span>
|
|
||||||
<span class="text-fade text-size-small" data-ls-bind="{{file.sizeOriginal|humanFileUnit}}"></span>
|
|
||||||
</td>
|
|
||||||
<td data-title="Created: ">
|
|
||||||
<span class="text-fade text-size-small" data-ls-bind="{{file.dateCreated|dateText}}"></span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="pull-end text-align-center paging">
|
<div class="pull-end text-align-center paging">
|
||||||
<form
|
<form
|
||||||
data-service="storage.listFiles"
|
data-service="storage.listBuckets"
|
||||||
data-event="submit"
|
data-event="submit"
|
||||||
data-param-search="{{router.params.search}}"
|
data-param-search="{{router.params.search}}"
|
||||||
data-param-limit="<?php echo APP_PAGING_LIMIT; ?>"
|
data-param-limit="<?php echo APP_PAGING_LIMIT; ?>"
|
||||||
data-param-order-type="DESC"
|
data-param-order-type="DESC"
|
||||||
data-scope="sdk"
|
data-scope="sdk"
|
||||||
data-name="project-files"
|
data-name="project-buckets"
|
||||||
data-success="state"
|
data-success="state"
|
||||||
data-success-param-state-keys="search,offset">
|
data-success-param-state-keys="search,offset">
|
||||||
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-sum="{{project-files.sum}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
|
<button name="offset" data-paging-back data-offset="{{router.params.offset}}" data-sum="{{project-buckets.sum}}" class="margin-end round small" aria-label="Back"><i class="icon-left-open"></i></button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-files.sum|pageTotal}}"></span>
|
<span data-ls-bind="{{router.params.offset|pageCurrent}} / {{project-buckets.sum|pageTotal}}"></span>
|
||||||
|
|
||||||
<form
|
<form
|
||||||
data-service="storage.listFiles"
|
data-service="storage.listBuckets"
|
||||||
data-event="submit"
|
data-event="submit"
|
||||||
data-param-search="{{router.params.search}}"
|
data-param-search="{{router.params.search}}"
|
||||||
data-param-limit="<?php echo APP_PAGING_LIMIT; ?>"
|
data-param-limit="<?php echo APP_PAGING_LIMIT; ?>"
|
||||||
data-param-order-type="DESC"
|
data-param-order-type="DESC"
|
||||||
data-scope="sdk"
|
data-scope="sdk"
|
||||||
data-name="project-files"
|
data-name="project-buckets"
|
||||||
data-success="state"
|
data-success="state"
|
||||||
data-success-param-state-keys="search,offset">
|
data-success-param-state-keys="search,offset">
|
||||||
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-sum="{{project-files.sum}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
|
<button name="offset" data-paging-next data-offset="{{router.params.offset}}" data-sum="{{project-buckets.sum}}" class="margin-start round small" aria-label="Next"><i class="icon-right-open"></i></button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div data-ui-modal class="box modal sticky-footer close" data-button-text="Add File">
|
<div data-ui-modal class="modal close box sticky-footer" data-button-text="Add Bucket">
|
||||||
<button type="button" class="close pull-end" data-ui-modal-close=""><i class="icon-cancel"></i></button>
|
<button type="button" class="close pull-end" data-ui-modal-close=""><i class="icon-cancel"></i></button>
|
||||||
|
|
||||||
<h1>Upload File</h1>
|
<h1>New Bucket</h1>
|
||||||
|
|
||||||
<form
|
<form
|
||||||
data-analytics
|
data-analytics
|
||||||
data-analytics-activity
|
data-analytics-activity
|
||||||
data-analytics-event="submit"
|
data-analytics-event="submit"
|
||||||
data-analytics-category="console"
|
data-analytics-category="console"
|
||||||
data-analytics-label="Create Storage File"
|
data-analytics-label="Create Storage Bucket"
|
||||||
data-service="storage.createFile"
|
data-service="storage.createBucket"
|
||||||
data-event="submit"
|
data-event="submit"
|
||||||
data-scope="sdk"
|
data-scope="sdk"
|
||||||
data-loading="Uploading File..."
|
data-success="alert,reset,redirect,trigger"
|
||||||
data-success="alert,trigger,reset"
|
data-success-param-alert-text="Bucket created successfully"
|
||||||
data-success-param-alert-text="File uploaded successfully"
|
data-success-param-redirect-url="/console/storage/bucket/settings?id={{serviceData.$id}}&project={{router.params.project}}"
|
||||||
data-success-param-trigger-events="storage.createFile"
|
data-success-param-trigger-events="storage.createBucket"
|
||||||
data-failure="alert"
|
data-failure="alert"
|
||||||
data-failure-param-alert-text="Failed to upload file"
|
data-failure-param-alert-text="Failed to create bucket"
|
||||||
data-failure-param-alert-classname="error">
|
data-failure-param-alert-classname="error">
|
||||||
<input type="hidden" name="folderId" id="files-folderId" data-cast-to="integer" value="1">
|
|
||||||
|
|
||||||
<label for="fileId">File ID</label>
|
<label for="bucket-id">Bucket ID</label>
|
||||||
<input
|
<input
|
||||||
type="hidden"
|
type="hidden"
|
||||||
data-custom-id
|
data-custom-id
|
||||||
data-id-type="auto"
|
data-id-type="auto"
|
||||||
data-validator="storage.getFile"
|
data-validator="storage.getBucket"
|
||||||
required
|
required
|
||||||
maxlength="36"
|
maxlength="36"
|
||||||
pattern="^[a-zA-Z0-9][a-zA-Z0-9_-]{1,36}$"
|
name="bucketId" />
|
||||||
name="fileId"
|
|
||||||
id="fileId" />
|
|
||||||
|
|
||||||
<label for="file-read">File</label>
|
<label for="bucket-name">Name</label>
|
||||||
<input type="file" name="file" id="file-file" size="1" required>
|
<input type="text" class="full-width" id="bucket-name" name="name" required autocomplete="off" maxlength="128" />
|
||||||
|
|
||||||
<div class="text-fade text-size-xs margin-top-negative-small margin-bottom">(Max file size allowed: <?php echo $fileLimitHuman; ?>)</div>
|
<input type="hidden" id="bucket-permission" name="permission" required value="file" />
|
||||||
|
<input type="hidden" id="bucket-read" name="read" required data-cast-to="json" value="<?php echo htmlentities(json_encode([])); ?>" />
|
||||||
|
<input type="hidden" id="bucket-write" name="write" required data-cast-to="json" value="<?php echo htmlentities(json_encode([])); ?>" />
|
||||||
|
|
||||||
<label for="file-read">Read Access (<a data-ls-attrs="href={{env.HOME}}/docs/permissions" target="_blank" rel="noopener">Learn more</a>)</label>
|
<hr />
|
||||||
<input type="hidden" id="file-read" name="read" data-forms-tags data-cast-to="json" value="<?php echo htmlentities(json_encode(['role:all'])); ?>" placeholder="User ID, Team ID or Role" />
|
|
||||||
<div class="text-fade text-size-xs margin-top-negative-small margin-bottom">Add 'role:all' for wildcard access</div>
|
|
||||||
|
|
||||||
<label for="file-write">Write Access (<a data-ls-attrs="href={{env.HOME}}/docs/permissions" target="_blank" rel="noopener">Learn more</a>)</label>
|
|
||||||
<input type="hidden" id="file-write" name="write" data-forms-tags data-cast-to="json" value="" placeholder="User ID, Team ID or Role" />
|
|
||||||
<div class="text-fade text-size-xs margin-top-negative-small margin-bottom">Add 'role:all' for wildcard access</div>
|
|
||||||
|
|
||||||
<footer>
|
|
||||||
<button type="submit">Create</button> <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
|
<button type="submit">Create</button> <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
|
||||||
</footer>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li data-state="/console/storage/usage?project={{router.params.project}}">
|
<li data-state="/console/storage/usage?project={{router.params.project}}">
|
||||||
<form class="pull-end margin-start-small margin-top-small" data-ls-if="{{usage.range}} !== '90d'"
|
<form class="pull-end margin-start-small margin-top-small" data-ls-if="{{usage.range}} !== '90d'"
|
||||||
data-service="storage.getUsage"
|
data-service="storage.getUsage"
|
||||||
|
@ -305,30 +155,57 @@ $fileLimitHuman = $this->getParam('fileLimitHuman', 0);
|
||||||
data-service="storage.getUsage"
|
data-service="storage.getUsage"
|
||||||
data-event="load"
|
data-event="load"
|
||||||
data-name="usage">
|
data-name="usage">
|
||||||
<div class="box margin-bottom-small">
|
<h3 class="margin-bottom-tiny">Objects</h3>
|
||||||
|
<p class="text-fade">Count of buckets, files and total storage used over time</p>
|
||||||
|
<div class="box">
|
||||||
<div class="margin-start-negative-small margin-end-negative-small margin-top-negative-small margin-bottom-negative-small">
|
<div class="margin-start-negative-small margin-end-negative-small margin-top-negative-small margin-bottom-negative-small">
|
||||||
<div class="chart background-image-no border-no margin-bottom-no">
|
<div class="chart background-image-no border-no margin-bottom-no">
|
||||||
<input type="hidden" data-ls-bind="{{usage}}" data-forms-chart="Total Files=files" data-height="140" data-show-y-axis="true" />
|
<input type="hidden" data-ls-bind="{{usage}}" data-show-y-axis="true" data-forms-chart="Total Files=filesCount,Total Buckets=bucketsCount" data-height="140" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<ul class="chart-notes margin-top-small margin-bottom-large">
|
||||||
<ul class="chart-notes margin-bottom-large">
|
<li>Total Files</li>
|
||||||
<li>Total Files <span data-ls-bind="({{usage.files|statsGetLast|statsTotal}})"></span></li>
|
<li>Total Buckets</li>
|
||||||
|
<!-- <li>Total Storage <span data-ls-bind="({{usage.filesStorage|statsGetLast|statsTotal}})"></span></li> -->
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<!-- CRUDS class for graph fixed colors, use color codes from Docs for CRUD operations -->
|
||||||
|
<h3 class="margin-bottom-tiny">Buckets</h3>
|
||||||
|
<p class="text-fade">Count of bucket create, read, update and delete operations over time</p>
|
||||||
<div class="box margin-bottom-small">
|
<div class="box margin-bottom-small">
|
||||||
<div class="margin-start-negative-small margin-end-negative-small margin-top-negative-small margin-bottom-negative-small">
|
<div class="margin-start-negative-small margin-end-negative-small margin-top-negative-small margin-bottom-negative-small">
|
||||||
<div class="chart background-image-no border-no margin-bottom-no">
|
<div class="chart background-image-no border-no crud margin-bottom-no">
|
||||||
<input type="hidden" data-ls-bind="{{usage}}" data-forms-chart="Total Storage=storage" data-height="140" data-show-y-axis="true" />
|
<input type="hidden" data-ls-bind="{{usage}}" data-forms-chart="Buckets create=bucketsCreate,Buckets read=bucketsRead,Buckets update=bucketsUpdate,Buckets delete=bucketsDelete" data-show-y-axis="true" data-colors="create,read,update,delete" data-height="140" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul class="chart-notes margin-bottom-large">
|
<ul class="chart-notes crud margin-bottom-large">
|
||||||
<li>Total Storage (<span data-ls-bind="{{usage.storage|statsGetLast|humanFileSize}}"></span> <span data-ls-bind="{{usage.storage|statsGetLast|humanFileUnit}}"></span>)</li>
|
<li class="green">Create</li>
|
||||||
|
<li class="green">Read</li>
|
||||||
|
<li class="green">Update</li>
|
||||||
|
<li class="green">Delete</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3 class="margin-bottom-tiny">Files</h3>
|
||||||
|
<p class="text-fade">Count of file create, read, update and delete operations over time</p>
|
||||||
|
<div class="box margin-bottom-small">
|
||||||
|
<div class="margin-start-negative-small margin-end-negative-small margin-top-negative-small margin-bottom-negative-small">
|
||||||
|
<div class="chart background-image-no border-no crud margin-bottom-no">
|
||||||
|
<input type="hidden" data-ls-bind="{{usage}}" data-forms-chart="Files create=filesCreate,Files read=filesRead,Files update=filesUpdate,Files delete=filesDelete" data-show-y-axis="true" data-colors="create,read,update,delete" data-height="140" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="chart-notes crud margin-bottom-large">
|
||||||
|
<li class="green">Create</li>
|
||||||
|
<li class="green">Read</li>
|
||||||
|
<li class="green">Update</li>
|
||||||
|
<li class="green">Delete</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
14
composer.lock
generated
14
composer.lock
generated
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "7e24a95bc534ed39b042f19b27268de9",
|
"content-hash": "de8b7360734c246c97d8cee4779983e3",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "adhocore/jwt",
|
"name": "adhocore/jwt",
|
||||||
|
@ -2138,16 +2138,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "utopia-php/database",
|
"name": "utopia-php/database",
|
||||||
"version": "0.12.0",
|
"version": "0.10.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/utopia-php/database.git",
|
"url": "https://github.com/utopia-php/database.git",
|
||||||
"reference": "102ee1d21fd55fc92dc7a07b60672a98ae49be26"
|
"reference": "9b4697612a2cd1ad55beeb6a02570f6ffe26dc1e"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/102ee1d21fd55fc92dc7a07b60672a98ae49be26",
|
"url": "https://api.github.com/repos/utopia-php/database/zipball/9b4697612a2cd1ad55beeb6a02570f6ffe26dc1e",
|
||||||
"reference": "102ee1d21fd55fc92dc7a07b60672a98ae49be26",
|
"reference": "9b4697612a2cd1ad55beeb6a02570f6ffe26dc1e",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -2195,9 +2195,9 @@
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/utopia-php/database/issues",
|
"issues": "https://github.com/utopia-php/database/issues",
|
||||||
"source": "https://github.com/utopia-php/database/tree/0.12.0"
|
"source": "https://github.com/utopia-php/database/tree/0.10.1"
|
||||||
},
|
},
|
||||||
"time": "2021-11-24T14:53:22+00:00"
|
"time": "2021-11-02T15:10:39+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "utopia-php/domains",
|
"name": "utopia-php/domains",
|
||||||
|
|
|
@ -3870,11 +3870,10 @@
|
||||||
};
|
};
|
||||||
this.storage = {
|
this.storage = {
|
||||||
/**
|
/**
|
||||||
* List Files
|
* List buckets
|
||||||
*
|
*
|
||||||
* Get a list of all the user files. You can use the query params to filter
|
* Get a list of all the storage buckets. You can use the query params to
|
||||||
* your results. On admin mode, this endpoint will return a list of all of the
|
* filter your results.
|
||||||
* project's files. [Learn more about different API modes](/docs/admin).
|
|
||||||
*
|
*
|
||||||
* @param {string} search
|
* @param {string} search
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
|
@ -3885,8 +3884,219 @@
|
||||||
* @throws {AppwriteException}
|
* @throws {AppwriteException}
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
listFiles: (search, limit, offset, cursor, cursorDirection, orderType) => __awaiter(this, void 0, void 0, function* () {
|
listBuckets: (search, limit, offset, cursor, cursorDirection, orderType) => __awaiter(this, void 0, void 0, function* () {
|
||||||
let path = '/storage/files';
|
let path = '/storage/buckets';
|
||||||
|
let payload = {};
|
||||||
|
if (typeof search !== 'undefined') {
|
||||||
|
payload['search'] = search;
|
||||||
|
}
|
||||||
|
if (typeof limit !== 'undefined') {
|
||||||
|
payload['limit'] = limit;
|
||||||
|
}
|
||||||
|
if (typeof offset !== 'undefined') {
|
||||||
|
payload['offset'] = offset;
|
||||||
|
}
|
||||||
|
if (typeof cursor !== 'undefined') {
|
||||||
|
payload['cursor'] = cursor;
|
||||||
|
}
|
||||||
|
if (typeof cursorDirection !== 'undefined') {
|
||||||
|
payload['cursorDirection'] = cursorDirection;
|
||||||
|
}
|
||||||
|
if (typeof orderType !== 'undefined') {
|
||||||
|
payload['orderType'] = orderType;
|
||||||
|
}
|
||||||
|
const uri = new URL(this.config.endpoint + path);
|
||||||
|
return yield this.call('get', uri, {
|
||||||
|
'content-type': 'application/json',
|
||||||
|
}, payload);
|
||||||
|
}),
|
||||||
|
/**
|
||||||
|
* Create storage bucket
|
||||||
|
*
|
||||||
|
* Create a new storage bucket.
|
||||||
|
*
|
||||||
|
* @param {string} bucketId
|
||||||
|
* @param {string} name
|
||||||
|
* @param {string} permission
|
||||||
|
* @param {string} read
|
||||||
|
* @param {string} write
|
||||||
|
* @param {number} maximumFileSize
|
||||||
|
* @param {string[]} allowedFileExtensions
|
||||||
|
* @param {boolean} enabled
|
||||||
|
* @param {string} adapter
|
||||||
|
* @param {boolean} encryption
|
||||||
|
* @param {boolean} antiVirus
|
||||||
|
* @throws {AppwriteException}
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
createBucket: (bucketId, name, permission, read, write, maximumFileSize, allowedFileExtensions, enabled, adapter, encryption, antiVirus) => __awaiter(this, void 0, void 0, function* () {
|
||||||
|
if (typeof bucketId === 'undefined') {
|
||||||
|
throw new AppwriteException('Missing required parameter: "bucketId"');
|
||||||
|
}
|
||||||
|
if (typeof name === 'undefined') {
|
||||||
|
throw new AppwriteException('Missing required parameter: "name"');
|
||||||
|
}
|
||||||
|
if (typeof permission === 'undefined') {
|
||||||
|
throw new AppwriteException('Missing required parameter: "permission"');
|
||||||
|
}
|
||||||
|
let path = '/storage/buckets';
|
||||||
|
let payload = {};
|
||||||
|
if (typeof bucketId !== 'undefined') {
|
||||||
|
payload['bucketId'] = bucketId;
|
||||||
|
}
|
||||||
|
if (typeof name !== 'undefined') {
|
||||||
|
payload['name'] = name;
|
||||||
|
}
|
||||||
|
if (typeof permission !== 'undefined') {
|
||||||
|
payload['permission'] = permission;
|
||||||
|
}
|
||||||
|
if (typeof read !== 'undefined') {
|
||||||
|
payload['read'] = read;
|
||||||
|
}
|
||||||
|
if (typeof write !== 'undefined') {
|
||||||
|
payload['write'] = write;
|
||||||
|
}
|
||||||
|
if (typeof maximumFileSize !== 'undefined') {
|
||||||
|
payload['maximumFileSize'] = maximumFileSize;
|
||||||
|
}
|
||||||
|
if (typeof allowedFileExtensions !== 'undefined') {
|
||||||
|
payload['allowedFileExtensions'] = allowedFileExtensions;
|
||||||
|
}
|
||||||
|
if (typeof enabled !== 'undefined') {
|
||||||
|
payload['enabled'] = enabled;
|
||||||
|
}
|
||||||
|
if (typeof adapter !== 'undefined') {
|
||||||
|
payload['adapter'] = adapter;
|
||||||
|
}
|
||||||
|
if (typeof encryption !== 'undefined') {
|
||||||
|
payload['encryption'] = encryption;
|
||||||
|
}
|
||||||
|
if (typeof antiVirus !== 'undefined') {
|
||||||
|
payload['antiVirus'] = antiVirus;
|
||||||
|
}
|
||||||
|
const uri = new URL(this.config.endpoint + path);
|
||||||
|
return yield this.call('post', uri, {
|
||||||
|
'content-type': 'application/json',
|
||||||
|
}, payload);
|
||||||
|
}),
|
||||||
|
/**
|
||||||
|
* Get Bucket
|
||||||
|
*
|
||||||
|
* Get a storage bucket by its unique ID. This endpoint response returns a
|
||||||
|
* JSON object with the storage bucket metadata.
|
||||||
|
*
|
||||||
|
* @param {string} bucketId
|
||||||
|
* @throws {AppwriteException}
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
getBucket: (bucketId) => __awaiter(this, void 0, void 0, function* () {
|
||||||
|
if (typeof bucketId === 'undefined') {
|
||||||
|
throw new AppwriteException('Missing required parameter: "bucketId"');
|
||||||
|
}
|
||||||
|
let path = '/storage/buckets/{bucketId}'.replace('{bucketId}', bucketId);
|
||||||
|
let payload = {};
|
||||||
|
const uri = new URL(this.config.endpoint + path);
|
||||||
|
return yield this.call('get', uri, {
|
||||||
|
'content-type': 'application/json',
|
||||||
|
}, payload);
|
||||||
|
}),
|
||||||
|
/**
|
||||||
|
* Update Bucket
|
||||||
|
*
|
||||||
|
* Update a storage bucket by its unique ID.
|
||||||
|
*
|
||||||
|
* @param {string} bucketId
|
||||||
|
* @param {string} name
|
||||||
|
* @param {string} read
|
||||||
|
* @param {string} write
|
||||||
|
* @param {number} maximumFileSize
|
||||||
|
* @param {string[]} allowedFileExtensions
|
||||||
|
* @param {boolean} enabled
|
||||||
|
* @param {boolean} encryption
|
||||||
|
* @param {boolean} antiVirus
|
||||||
|
* @throws {AppwriteException}
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
updateBucket: (bucketId, name, read, write, maximumFileSize, allowedFileExtensions, enabled, encryption, antiVirus) => __awaiter(this, void 0, void 0, function* () {
|
||||||
|
if (typeof bucketId === 'undefined') {
|
||||||
|
throw new AppwriteException('Missing required parameter: "bucketId"');
|
||||||
|
}
|
||||||
|
if (typeof name === 'undefined') {
|
||||||
|
throw new AppwriteException('Missing required parameter: "name"');
|
||||||
|
}
|
||||||
|
let path = '/storage/buckets/{bucketId}'.replace('{bucketId}', bucketId);
|
||||||
|
let payload = {};
|
||||||
|
if (typeof name !== 'undefined') {
|
||||||
|
payload['name'] = name;
|
||||||
|
}
|
||||||
|
if (typeof read !== 'undefined') {
|
||||||
|
payload['read'] = read;
|
||||||
|
}
|
||||||
|
if (typeof write !== 'undefined') {
|
||||||
|
payload['write'] = write;
|
||||||
|
}
|
||||||
|
if (typeof maximumFileSize !== 'undefined') {
|
||||||
|
payload['maximumFileSize'] = maximumFileSize;
|
||||||
|
}
|
||||||
|
if (typeof allowedFileExtensions !== 'undefined') {
|
||||||
|
payload['allowedFileExtensions'] = allowedFileExtensions;
|
||||||
|
}
|
||||||
|
if (typeof enabled !== 'undefined') {
|
||||||
|
payload['enabled'] = enabled;
|
||||||
|
}
|
||||||
|
if (typeof encryption !== 'undefined') {
|
||||||
|
payload['encryption'] = encryption;
|
||||||
|
}
|
||||||
|
if (typeof antiVirus !== 'undefined') {
|
||||||
|
payload['antiVirus'] = antiVirus;
|
||||||
|
}
|
||||||
|
const uri = new URL(this.config.endpoint + path);
|
||||||
|
return yield this.call('put', uri, {
|
||||||
|
'content-type': 'application/json',
|
||||||
|
}, payload);
|
||||||
|
}),
|
||||||
|
/**
|
||||||
|
* Delete Bucket
|
||||||
|
*
|
||||||
|
* Delete a storage bucket by its unique ID.
|
||||||
|
*
|
||||||
|
* @param {string} bucketId
|
||||||
|
* @throws {AppwriteException}
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
deleteBucket: (bucketId) => __awaiter(this, void 0, void 0, function* () {
|
||||||
|
if (typeof bucketId === 'undefined') {
|
||||||
|
throw new AppwriteException('Missing required parameter: "bucketId"');
|
||||||
|
}
|
||||||
|
let path = '/storage/buckets/{bucketId}'.replace('{bucketId}', bucketId);
|
||||||
|
let payload = {};
|
||||||
|
const uri = new URL(this.config.endpoint + path);
|
||||||
|
return yield this.call('delete', uri, {
|
||||||
|
'content-type': 'application/json',
|
||||||
|
}, payload);
|
||||||
|
}),
|
||||||
|
/**
|
||||||
|
* List Files
|
||||||
|
*
|
||||||
|
* Get a list of all the user files. You can use the query params to filter
|
||||||
|
* your results. On admin mode, this endpoint will return a list of all of the
|
||||||
|
* project's files. [Learn more about different API modes](/docs/admin).
|
||||||
|
*
|
||||||
|
* @param {string} bucketId
|
||||||
|
* @param {string} search
|
||||||
|
* @param {number} limit
|
||||||
|
* @param {number} offset
|
||||||
|
* @param {string} cursor
|
||||||
|
* @param {string} cursorDirection
|
||||||
|
* @param {string} orderType
|
||||||
|
* @throws {AppwriteException}
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
listFiles: (bucketId, search, limit, offset, cursor, cursorDirection, orderType) => __awaiter(this, void 0, void 0, function* () {
|
||||||
|
if (typeof bucketId === 'undefined') {
|
||||||
|
throw new AppwriteException('Missing required parameter: "bucketId"');
|
||||||
|
}
|
||||||
|
let path = '/storage/buckets/{bucketId}/files'.replace('{bucketId}', bucketId);
|
||||||
let payload = {};
|
let payload = {};
|
||||||
if (typeof search !== 'undefined') {
|
if (typeof search !== 'undefined') {
|
||||||
payload['search'] = search;
|
payload['search'] = search;
|
||||||
|
@ -3918,21 +4128,25 @@
|
||||||
* assigned to read and write access unless he has passed custom values for
|
* assigned to read and write access unless he has passed custom values for
|
||||||
* read and write arguments.
|
* read and write arguments.
|
||||||
*
|
*
|
||||||
|
* @param {string} bucketId
|
||||||
* @param {string} fileId
|
* @param {string} fileId
|
||||||
* @param {File} file
|
* @param {File} file
|
||||||
* @param {string[]} read
|
* @param {string} read
|
||||||
* @param {string[]} write
|
* @param {string} write
|
||||||
* @throws {AppwriteException}
|
* @throws {AppwriteException}
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
createFile: (fileId, file, read, write) => __awaiter(this, void 0, void 0, function* () {
|
createFile: (bucketId, fileId, file, read, write) => __awaiter(this, void 0, void 0, function* () {
|
||||||
|
if (typeof bucketId === 'undefined') {
|
||||||
|
throw new AppwriteException('Missing required parameter: "bucketId"');
|
||||||
|
}
|
||||||
if (typeof fileId === 'undefined') {
|
if (typeof fileId === 'undefined') {
|
||||||
throw new AppwriteException('Missing required parameter: "fileId"');
|
throw new AppwriteException('Missing required parameter: "fileId"');
|
||||||
}
|
}
|
||||||
if (typeof file === 'undefined') {
|
if (typeof file === 'undefined') {
|
||||||
throw new AppwriteException('Missing required parameter: "file"');
|
throw new AppwriteException('Missing required parameter: "file"');
|
||||||
}
|
}
|
||||||
let path = '/storage/files';
|
let path = '/storage/buckets/{bucketId}/files'.replace('{bucketId}', bucketId);
|
||||||
let payload = {};
|
let payload = {};
|
||||||
if (typeof fileId !== 'undefined') {
|
if (typeof fileId !== 'undefined') {
|
||||||
payload['fileId'] = fileId;
|
payload['fileId'] = fileId;
|
||||||
|
@ -3957,15 +4171,19 @@
|
||||||
* Get a file by its unique ID. This endpoint response returns a JSON object
|
* Get a file by its unique ID. This endpoint response returns a JSON object
|
||||||
* with the file metadata.
|
* with the file metadata.
|
||||||
*
|
*
|
||||||
|
* @param {string} bucketId
|
||||||
* @param {string} fileId
|
* @param {string} fileId
|
||||||
* @throws {AppwriteException}
|
* @throws {AppwriteException}
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
getFile: (fileId) => __awaiter(this, void 0, void 0, function* () {
|
getFile: (bucketId, fileId) => __awaiter(this, void 0, void 0, function* () {
|
||||||
|
if (typeof bucketId === 'undefined') {
|
||||||
|
throw new AppwriteException('Missing required parameter: "bucketId"');
|
||||||
|
}
|
||||||
if (typeof fileId === 'undefined') {
|
if (typeof fileId === 'undefined') {
|
||||||
throw new AppwriteException('Missing required parameter: "fileId"');
|
throw new AppwriteException('Missing required parameter: "fileId"');
|
||||||
}
|
}
|
||||||
let path = '/storage/files/{fileId}'.replace('{fileId}', fileId);
|
let path = '/storage/buckets/{bucketId}/files/{fileId}'.replace('{bucketId}', bucketId).replace('{fileId}', fileId);
|
||||||
let payload = {};
|
let payload = {};
|
||||||
const uri = new URL(this.config.endpoint + path);
|
const uri = new URL(this.config.endpoint + path);
|
||||||
return yield this.call('get', uri, {
|
return yield this.call('get', uri, {
|
||||||
|
@ -3978,13 +4196,17 @@
|
||||||
* Update a file by its unique ID. Only users with write permissions have
|
* Update a file by its unique ID. Only users with write permissions have
|
||||||
* access to update this resource.
|
* access to update this resource.
|
||||||
*
|
*
|
||||||
|
* @param {string} bucketId
|
||||||
* @param {string} fileId
|
* @param {string} fileId
|
||||||
* @param {string[]} read
|
* @param {string} read
|
||||||
* @param {string[]} write
|
* @param {string} write
|
||||||
* @throws {AppwriteException}
|
* @throws {AppwriteException}
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
updateFile: (fileId, read, write) => __awaiter(this, void 0, void 0, function* () {
|
updateFile: (bucketId, fileId, read, write) => __awaiter(this, void 0, void 0, function* () {
|
||||||
|
if (typeof bucketId === 'undefined') {
|
||||||
|
throw new AppwriteException('Missing required parameter: "bucketId"');
|
||||||
|
}
|
||||||
if (typeof fileId === 'undefined') {
|
if (typeof fileId === 'undefined') {
|
||||||
throw new AppwriteException('Missing required parameter: "fileId"');
|
throw new AppwriteException('Missing required parameter: "fileId"');
|
||||||
}
|
}
|
||||||
|
@ -3994,7 +4216,7 @@
|
||||||
if (typeof write === 'undefined') {
|
if (typeof write === 'undefined') {
|
||||||
throw new AppwriteException('Missing required parameter: "write"');
|
throw new AppwriteException('Missing required parameter: "write"');
|
||||||
}
|
}
|
||||||
let path = '/storage/files/{fileId}'.replace('{fileId}', fileId);
|
let path = '/storage/buckets/{bucketId}/files/{fileId}'.replace('{bucketId}', bucketId).replace('{fileId}', fileId);
|
||||||
let payload = {};
|
let payload = {};
|
||||||
if (typeof read !== 'undefined') {
|
if (typeof read !== 'undefined') {
|
||||||
payload['read'] = read;
|
payload['read'] = read;
|
||||||
|
@ -4013,15 +4235,19 @@
|
||||||
* Delete a file by its unique ID. Only users with write permissions have
|
* Delete a file by its unique ID. Only users with write permissions have
|
||||||
* access to delete this resource.
|
* access to delete this resource.
|
||||||
*
|
*
|
||||||
|
* @param {string} bucketId
|
||||||
* @param {string} fileId
|
* @param {string} fileId
|
||||||
* @throws {AppwriteException}
|
* @throws {AppwriteException}
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
deleteFile: (fileId) => __awaiter(this, void 0, void 0, function* () {
|
deleteFile: (bucketId, fileId) => __awaiter(this, void 0, void 0, function* () {
|
||||||
|
if (typeof bucketId === 'undefined') {
|
||||||
|
throw new AppwriteException('Missing required parameter: "bucketId"');
|
||||||
|
}
|
||||||
if (typeof fileId === 'undefined') {
|
if (typeof fileId === 'undefined') {
|
||||||
throw new AppwriteException('Missing required parameter: "fileId"');
|
throw new AppwriteException('Missing required parameter: "fileId"');
|
||||||
}
|
}
|
||||||
let path = '/storage/files/{fileId}'.replace('{fileId}', fileId);
|
let path = '/storage/buckets/{bucketId}/files/{fileId}'.replace('{bucketId}', bucketId).replace('{fileId}', fileId);
|
||||||
let payload = {};
|
let payload = {};
|
||||||
const uri = new URL(this.config.endpoint + path);
|
const uri = new URL(this.config.endpoint + path);
|
||||||
return yield this.call('delete', uri, {
|
return yield this.call('delete', uri, {
|
||||||
|
@ -4035,15 +4261,19 @@
|
||||||
* 'Content-Disposition: attachment' header that tells the browser to start
|
* 'Content-Disposition: attachment' header that tells the browser to start
|
||||||
* downloading the file to user downloads directory.
|
* downloading the file to user downloads directory.
|
||||||
*
|
*
|
||||||
|
* @param {string} bucketId
|
||||||
* @param {string} fileId
|
* @param {string} fileId
|
||||||
* @throws {AppwriteException}
|
* @throws {AppwriteException}
|
||||||
* @returns {URL}
|
* @returns {URL}
|
||||||
*/
|
*/
|
||||||
getFileDownload: (fileId) => {
|
getFileDownload: (bucketId, fileId) => {
|
||||||
|
if (typeof bucketId === 'undefined') {
|
||||||
|
throw new AppwriteException('Missing required parameter: "bucketId"');
|
||||||
|
}
|
||||||
if (typeof fileId === 'undefined') {
|
if (typeof fileId === 'undefined') {
|
||||||
throw new AppwriteException('Missing required parameter: "fileId"');
|
throw new AppwriteException('Missing required parameter: "fileId"');
|
||||||
}
|
}
|
||||||
let path = '/storage/files/{fileId}/download'.replace('{fileId}', fileId);
|
let path = '/storage/buckets/{bucketId}/files/{fileId}/download'.replace('{bucketId}', bucketId).replace('{fileId}', fileId);
|
||||||
let payload = {};
|
let payload = {};
|
||||||
const uri = new URL(this.config.endpoint + path);
|
const uri = new URL(this.config.endpoint + path);
|
||||||
payload['project'] = this.config.project;
|
payload['project'] = this.config.project;
|
||||||
|
@ -4060,6 +4290,7 @@
|
||||||
* and spreadsheets, will return the file icon image. You can also pass query
|
* and spreadsheets, will return the file icon image. You can also pass query
|
||||||
* string arguments for cutting and resizing your preview image.
|
* string arguments for cutting and resizing your preview image.
|
||||||
*
|
*
|
||||||
|
* @param {string} bucketId
|
||||||
* @param {string} fileId
|
* @param {string} fileId
|
||||||
* @param {number} width
|
* @param {number} width
|
||||||
* @param {number} height
|
* @param {number} height
|
||||||
|
@ -4075,11 +4306,14 @@
|
||||||
* @throws {AppwriteException}
|
* @throws {AppwriteException}
|
||||||
* @returns {URL}
|
* @returns {URL}
|
||||||
*/
|
*/
|
||||||
getFilePreview: (fileId, width, height, gravity, quality, borderWidth, borderColor, borderRadius, opacity, rotation, background, output) => {
|
getFilePreview: (bucketId, fileId, width, height, gravity, quality, borderWidth, borderColor, borderRadius, opacity, rotation, background, output) => {
|
||||||
|
if (typeof bucketId === 'undefined') {
|
||||||
|
throw new AppwriteException('Missing required parameter: "bucketId"');
|
||||||
|
}
|
||||||
if (typeof fileId === 'undefined') {
|
if (typeof fileId === 'undefined') {
|
||||||
throw new AppwriteException('Missing required parameter: "fileId"');
|
throw new AppwriteException('Missing required parameter: "fileId"');
|
||||||
}
|
}
|
||||||
let path = '/storage/files/{fileId}/preview'.replace('{fileId}', fileId);
|
let path = '/storage/buckets/{bucketId}/files/{fileId}/preview'.replace('{bucketId}', bucketId).replace('{fileId}', fileId);
|
||||||
let payload = {};
|
let payload = {};
|
||||||
if (typeof width !== 'undefined') {
|
if (typeof width !== 'undefined') {
|
||||||
payload['width'] = width;
|
payload['width'] = width;
|
||||||
|
@ -4128,15 +4362,19 @@
|
||||||
* download method but returns with no 'Content-Disposition: attachment'
|
* download method but returns with no 'Content-Disposition: attachment'
|
||||||
* header.
|
* header.
|
||||||
*
|
*
|
||||||
|
* @param {string} bucketId
|
||||||
* @param {string} fileId
|
* @param {string} fileId
|
||||||
* @throws {AppwriteException}
|
* @throws {AppwriteException}
|
||||||
* @returns {URL}
|
* @returns {URL}
|
||||||
*/
|
*/
|
||||||
getFileView: (fileId) => {
|
getFileView: (bucketId, fileId) => {
|
||||||
|
if (typeof bucketId === 'undefined') {
|
||||||
|
throw new AppwriteException('Missing required parameter: "bucketId"');
|
||||||
|
}
|
||||||
if (typeof fileId === 'undefined') {
|
if (typeof fileId === 'undefined') {
|
||||||
throw new AppwriteException('Missing required parameter: "fileId"');
|
throw new AppwriteException('Missing required parameter: "fileId"');
|
||||||
}
|
}
|
||||||
let path = '/storage/files/{fileId}/view'.replace('{fileId}', fileId);
|
let path = '/storage/buckets/{bucketId}/files/{fileId}/view'.replace('{bucketId}', bucketId).replace('{fileId}', fileId);
|
||||||
let payload = {};
|
let payload = {};
|
||||||
const uri = new URL(this.config.endpoint + path);
|
const uri = new URL(this.config.endpoint + path);
|
||||||
payload['project'] = this.config.project;
|
payload['project'] = this.config.project;
|
||||||
|
|
|
@ -183,6 +183,13 @@ window.ls.filter
|
||||||
|
|
||||||
return $value[$value.length - 1].value;
|
return $value[$value.length - 1].value;
|
||||||
})
|
})
|
||||||
|
.add("statsGetLast", function ($value) {
|
||||||
|
if (!$value || $value.length < 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value[$value.length - 1].value;
|
||||||
|
})
|
||||||
.add("isEmpty", function ($value) {
|
.add("isEmpty", function ($value) {
|
||||||
return (!!$value);
|
return (!!$value);
|
||||||
})
|
})
|
||||||
|
|
|
@ -160,8 +160,17 @@ window.ls.router
|
||||||
scope: "console",
|
scope: "console",
|
||||||
project: true
|
project: true
|
||||||
})
|
})
|
||||||
.add("/console/storage/:tab", {
|
.add("/console/storage/bucket", {
|
||||||
template: "/console/storage?version=" + APP_ENV.CACHEBUSTER,
|
template: function(window) {
|
||||||
|
return window.location.pathname + window.location.search + '&version=' + APP_ENV.CACHEBUSTER;
|
||||||
|
},
|
||||||
|
scope: "console",
|
||||||
|
project: true
|
||||||
|
})
|
||||||
|
.add("/console/storage/bucket/:tab", {
|
||||||
|
template: function(window) {
|
||||||
|
return window.location.pathname + window.location.search + '&version=' + APP_ENV.CACHEBUSTER;
|
||||||
|
},
|
||||||
scope: "console",
|
scope: "console",
|
||||||
project: true
|
project: true
|
||||||
})
|
})
|
||||||
|
|
|
@ -51,8 +51,9 @@
|
||||||
display: showYAxis,
|
display: showYAxis,
|
||||||
min: 0,
|
min: 0,
|
||||||
ticks: {
|
ticks: {
|
||||||
|
count: ticksCount,
|
||||||
fontColor: "#8f8f8f"
|
fontColor: "#8f8f8f"
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
plugins: {
|
plugins: {
|
||||||
|
@ -67,7 +68,7 @@
|
||||||
mode: "index",
|
mode: "index",
|
||||||
intersect: false,
|
intersect: false,
|
||||||
caretPadding: 0
|
caretPadding: 0
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -50,6 +50,7 @@ abstract class Migration
|
||||||
'0.10.4' => 'V09',
|
'0.10.4' => 'V09',
|
||||||
'0.11.0' => 'V10',
|
'0.11.0' => 'V10',
|
||||||
'0.12.0' => 'V10',
|
'0.12.0' => 'V10',
|
||||||
|
'0.13.0' => 'V10',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -23,6 +23,13 @@ class UsageBuckets extends Model
|
||||||
'example' => new \stdClass,
|
'example' => new \stdClass,
|
||||||
'array' => true
|
'array' => true
|
||||||
])
|
])
|
||||||
|
->addRule('filesStorage', [
|
||||||
|
'type' => Response::MODEL_METRIC_LIST,
|
||||||
|
'description' => 'Aggregated stats for total storage of files in this bucket.',
|
||||||
|
'default' => [],
|
||||||
|
'example' => new \stdClass,
|
||||||
|
'array' => true
|
||||||
|
])
|
||||||
->addRule('filesCreate', [
|
->addRule('filesCreate', [
|
||||||
'type' => Response::MODEL_METRIC_LIST,
|
'type' => Response::MODEL_METRIC_LIST,
|
||||||
'description' => 'Aggregated stats for files created.',
|
'description' => 'Aggregated stats for files created.',
|
||||||
|
|
|
@ -16,20 +16,90 @@ class UsageStorage extends Model
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'example' => '30d',
|
'example' => '30d',
|
||||||
])
|
])
|
||||||
->addRule('storage', [
|
->addRule('filesStorage', [
|
||||||
'type' => Response::MODEL_METRIC_LIST,
|
'type' => Response::MODEL_METRIC_LIST,
|
||||||
'description' => 'Aggregated stats for the occupied storage size (in bytes).',
|
'description' => 'Aggregated stats for the occupied storage size by files (in bytes).',
|
||||||
'default' => [],
|
'default' => [],
|
||||||
'example' => new \stdClass,
|
'example' => new \stdClass,
|
||||||
'array' => true
|
'array' => true
|
||||||
])
|
])
|
||||||
->addRule('files', [
|
->addRule('tagsStorage', [
|
||||||
|
'type' => Response::MODEL_METRIC_LIST,
|
||||||
|
'description' => 'Aggregated stats for the occupied storage size by tags (in bytes).',
|
||||||
|
'default' => [],
|
||||||
|
'example' => new \stdClass,
|
||||||
|
'array' => true
|
||||||
|
])
|
||||||
|
->addRule('filesCount', [
|
||||||
'type' => Response::MODEL_METRIC_LIST,
|
'type' => Response::MODEL_METRIC_LIST,
|
||||||
'description' => 'Aggregated stats for total number of files.',
|
'description' => 'Aggregated stats for total number of files.',
|
||||||
'default' => [],
|
'default' => [],
|
||||||
'example' => new \stdClass,
|
'example' => new \stdClass,
|
||||||
'array' => true
|
'array' => true
|
||||||
])
|
])
|
||||||
|
->addRule('bucketsCount', [
|
||||||
|
'type' => Response::MODEL_METRIC_LIST,
|
||||||
|
'description' => 'Aggregated stats for total number of buckets.',
|
||||||
|
'default' => [],
|
||||||
|
'example' => new \stdClass,
|
||||||
|
'array' => true
|
||||||
|
])
|
||||||
|
->addRule('bucketsCreate', [
|
||||||
|
'type' => Response::MODEL_METRIC_LIST,
|
||||||
|
'description' => 'Aggregated stats for buckets created.',
|
||||||
|
'default' => [],
|
||||||
|
'example' => new \stdClass,
|
||||||
|
'array' => true
|
||||||
|
])
|
||||||
|
->addRule('bucketsRead', [
|
||||||
|
'type' => Response::MODEL_METRIC_LIST,
|
||||||
|
'description' => 'Aggregated stats for buckets read.',
|
||||||
|
'default' => [],
|
||||||
|
'example' => new \stdClass,
|
||||||
|
'array' => true
|
||||||
|
])
|
||||||
|
->addRule('bucketsUpdate', [
|
||||||
|
'type' => Response::MODEL_METRIC_LIST,
|
||||||
|
'description' => 'Aggregated stats for buckets updated.',
|
||||||
|
'default' => [],
|
||||||
|
'example' => new \stdClass,
|
||||||
|
'array' => true
|
||||||
|
])
|
||||||
|
->addRule('bucketsDelete', [
|
||||||
|
'type' => Response::MODEL_METRIC_LIST,
|
||||||
|
'description' => 'Aggregated stats for buckets deleted.',
|
||||||
|
'default' => [],
|
||||||
|
'example' => new \stdClass,
|
||||||
|
'array' => true
|
||||||
|
])
|
||||||
|
->addRule('filesCreate', [
|
||||||
|
'type' => Response::MODEL_METRIC_LIST,
|
||||||
|
'description' => 'Aggregated stats for files created.',
|
||||||
|
'default' => [],
|
||||||
|
'example' => new \stdClass,
|
||||||
|
'array' => true
|
||||||
|
])
|
||||||
|
->addRule('filesRead', [
|
||||||
|
'type' => Response::MODEL_METRIC_LIST,
|
||||||
|
'description' => 'Aggregated stats for files read.',
|
||||||
|
'default' => [],
|
||||||
|
'example' => new \stdClass,
|
||||||
|
'array' => true
|
||||||
|
])
|
||||||
|
->addRule('filesUpdate', [
|
||||||
|
'type' => Response::MODEL_METRIC_LIST,
|
||||||
|
'description' => 'Aggregated stats for files updated.',
|
||||||
|
'default' => [],
|
||||||
|
'example' => new \stdClass,
|
||||||
|
'array' => true
|
||||||
|
])
|
||||||
|
->addRule('filesDelete', [
|
||||||
|
'type' => Response::MODEL_METRIC_LIST,
|
||||||
|
'description' => 'Aggregated stats for files deleted.',
|
||||||
|
'default' => [],
|
||||||
|
'example' => new \stdClass,
|
||||||
|
'array' => true
|
||||||
|
])
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,10 +38,10 @@ class StorageConsoleClientTest extends Scope
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertEquals($response['headers']['status-code'], 200);
|
$this->assertEquals($response['headers']['status-code'], 200);
|
||||||
$this->assertEquals(count($response['body']), 3);
|
$this->assertEquals(count($response['body']), 13);
|
||||||
$this->assertEquals($response['body']['range'], '24h');
|
$this->assertEquals($response['body']['range'], '24h');
|
||||||
$this->assertIsArray($response['body']['storage']);
|
$this->assertIsArray($response['body']['filesStorage']);
|
||||||
$this->assertIsArray($response['body']['files']);
|
$this->assertIsArray($response['body']['filesCount']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetStorageBucketUsage()
|
public function testGetStorageBucketUsage()
|
||||||
|
@ -93,12 +93,13 @@ class StorageConsoleClientTest extends Scope
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertEquals($response['headers']['status-code'], 200);
|
$this->assertEquals($response['headers']['status-code'], 200);
|
||||||
$this->assertEquals(count($response['body']), 6);
|
$this->assertEquals(count($response['body']), 7);
|
||||||
$this->assertEquals($response['body']['range'], '24h');
|
$this->assertEquals($response['body']['range'], '24h');
|
||||||
$this->assertIsArray($response['body']['filesCount']);
|
$this->assertIsArray($response['body']['filesCount']);
|
||||||
$this->assertIsArray($response['body']['filesCreate']);
|
$this->assertIsArray($response['body']['filesCreate']);
|
||||||
$this->assertIsArray($response['body']['filesRead']);
|
$this->assertIsArray($response['body']['filesRead']);
|
||||||
$this->assertIsArray($response['body']['filesUpdate']);
|
$this->assertIsArray($response['body']['filesUpdate']);
|
||||||
$this->assertIsArray($response['body']['filesDelete']);
|
$this->assertIsArray($response['body']['filesDelete']);
|
||||||
|
$this->assertIsArray($response['body']['filesStorage']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue