Merge branch 'feat-storage-buckets' into feat-large-file
This commit is contained in:
commit
eb2968256a
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)
|
||||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->inject('dbForExternal')
|
||||
->inject('audits')
|
||||
->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 Utopia\Database\Database $dbForInternal */
|
||||
/** @var Utopia\Database\Database $dbForExternal */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$bucketId = $bucketId === 'unique()' ? $dbForInternal->getId() : $bucketId;
|
||||
try {
|
||||
$dbForInternal->createCollection('bucket_' . $bucketId, [
|
||||
$dbForExternal->createCollection('bucket_' . $bucketId, [
|
||||
new Document([
|
||||
'$id' => 'dateCreated',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
|
@ -527,14 +529,16 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
|||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->inject('dbForExternal')
|
||||
->inject('user')
|
||||
->inject('audits')
|
||||
->inject('usage')
|
||||
->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 Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Utopia\Database\Database $dbForExternal */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
@ -581,7 +585,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
|||
$size = (\is_array($file['size']) && isset($file['size'][0])) ? $file['size'][0] : $file['size'];
|
||||
|
||||
$contentRange = $request->getHeader('content-range');
|
||||
$fileId = $fileId === 'unique()' ? $dbForInternal->getId() : $fileId;
|
||||
$fileId = $fileId === 'unique()' ? $$dbForExternal->getId() : $fileId;
|
||||
$chunk = 1;
|
||||
$chunks = 1;
|
||||
|
||||
|
@ -624,7 +628,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
|||
$path = $device->getPath($fileId . '.' . \pathinfo($fileName, PATHINFO_EXTENSION));
|
||||
$path = str_ireplace($device->getRoot(), $device->getRoot() . DIRECTORY_SEPARATOR . $bucket->getId(), $path); // Add bucket id to path after root
|
||||
|
||||
$file = $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
$file = $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
|
||||
if (!$file->isEmpty()) {
|
||||
$chunks = $file->getAttribute('chunksTotal', 1);
|
||||
|
@ -712,11 +716,11 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
|||
'search' => implode(' ', [$fileId, $fileName,]),
|
||||
]);
|
||||
if($permissionBucket) {
|
||||
$file = Authorization::skip(function() use ($dbForInternal, $bucketId, $doc) {
|
||||
return $dbForInternal->createDocument('bucket_' . $bucketId, $doc);
|
||||
$file = Authorization::skip(function() use ($dbForExternal, $bucketId, $doc) {
|
||||
return $dbForExternal->createDocument('bucket_' . $bucketId, $doc);
|
||||
});
|
||||
} else {
|
||||
$file = $dbForInternal->createDocument('bucket_' . $bucketId, $doc);
|
||||
$file = $dbForExternal->createDocument('bucket_' . $bucketId, $doc);
|
||||
}
|
||||
} else {
|
||||
$file = $file
|
||||
|
@ -733,11 +737,11 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
|||
->setAttribute('chunksUploaded', $chunksUploaded);
|
||||
|
||||
if($permissionBucket) {
|
||||
$file = Authorization::skip(function() use ($dbForInternal, $bucketId, $fileId, $file) {
|
||||
return $dbForInternal->updateDocument('bucket_' . $bucketId, $fileId, $file);
|
||||
$file = Authorization::skip(function() use ($dbForExternal, $bucketId, $fileId, $file) {
|
||||
return $dbForExternal->updateDocument('bucket_' . $bucketId, $fileId, $file);
|
||||
});
|
||||
} else {
|
||||
$file = $dbForInternal->updateDocument('bucket_' . $bucketId, $fileId, $file);
|
||||
$file = $dbForExternal->updateDocument('bucket_' . $bucketId, $fileId, $file);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -770,22 +774,22 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
|||
'search' => implode(' ', [$fileId, $fileName,]),
|
||||
]);
|
||||
if($permissionBucket) {
|
||||
$file = Authorization::skip(function() use ($dbForInternal, $bucketId, $doc) {
|
||||
return $dbForInternal->createDocument('bucket_' . $bucketId, $doc);
|
||||
$file = Authorization::skip(function() use ($dbForExternal, $bucketId, $doc) {
|
||||
return $dbForExternal->createDocument('bucket_' . $bucketId, $doc);
|
||||
});
|
||||
} else {
|
||||
$file = $dbForInternal->createDocument('bucket_' . $bucketId, $doc);
|
||||
$file = $dbForExternal->createDocument('bucket_' . $bucketId, $doc);
|
||||
}
|
||||
} else {
|
||||
$file = $file
|
||||
->setAttribute('chunksUploaded', $chunksUploaded);
|
||||
|
||||
if($permissionBucket) {
|
||||
$file = Authorization::skip(function() use ($dbForInternal, $bucketId, $fileId, $file) {
|
||||
return $dbForInternal->updateDocument('bucket_' . $bucketId, $fileId, $file);
|
||||
$file = Authorization::skip(function() use ($dbForExternal, $bucketId, $fileId, $file) {
|
||||
return $dbForExternal->updateDocument('bucket_' . $bucketId, $fileId, $file);
|
||||
});
|
||||
} else {
|
||||
$file = $dbForInternal->updateDocument('bucket_' . $bucketId, $fileId, $file);
|
||||
$file = $dbForExternal->updateDocument('bucket_' . $bucketId, $fileId, $file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -834,11 +838,13 @@ App::get('/v1/storage/buckets/:bucketId/files')
|
|||
->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true)
|
||||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->inject('dbForExternal')
|
||||
->inject('usage')
|
||||
->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 Utopia\Database\Database $dbForInternal */
|
||||
/** @var Utopia\Database\Database $dbForExternal */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$bucket = $dbForInternal->getDocument('buckets', $bucketId);
|
||||
|
@ -864,11 +870,11 @@ App::get('/v1/storage/buckets/:bucketId/files')
|
|||
|
||||
if (!empty($cursor)) {
|
||||
if($bucket->getAttribute('permission') ==='bucket') {
|
||||
$cursorFile = Authorization::skip(function() use ($dbForInternal, $bucket, $cursor) {
|
||||
return $dbForInternal->getDocument('bucket_' . $bucket->getId(), $cursor);
|
||||
$cursorFile = Authorization::skip(function() use ($dbForExternal, $bucket, $cursor) {
|
||||
return $dbForExternal->getDocument('bucket_' . $bucket->getId(), $cursor);
|
||||
});
|
||||
} else {
|
||||
$cursorFile = $dbForInternal->getDocument('bucket_' . $bucket->getId(), $cursor);
|
||||
$cursorFile = $dbForExternal->getDocument('bucket_' . $bucket->getId(), $cursor);
|
||||
}
|
||||
|
||||
if ($cursorFile->isEmpty()) {
|
||||
|
@ -883,11 +889,11 @@ App::get('/v1/storage/buckets/:bucketId/files')
|
|||
}
|
||||
|
||||
if($bucket->getAttribute('permission') === 'bucket') {
|
||||
$files = Authorization::skip(function() use ($dbForInternal, $bucketId, $queries, $limit, $offset, $cursor, $cursorDirection, $orderType) {
|
||||
return $dbForInternal->find('bucket_' . $bucketId, $queries, $limit, $offset, [], [$orderType], $cursorFile ?? null, $cursorDirection);
|
||||
$files = Authorization::skip(function() use ($dbForExternal, $bucketId, $queries, $limit, $offset, $cursor, $cursorDirection, $orderType) {
|
||||
return $dbForExternal->find('bucket_' . $bucketId, $queries, $limit, $offset, [], [$orderType], $cursorFile ?? null, $cursorDirection);
|
||||
});
|
||||
} 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
|
||||
|
@ -897,7 +903,7 @@ App::get('/v1/storage/buckets/:bucketId/files')
|
|||
|
||||
$response->dynamic(new Document([
|
||||
'files' => $files,
|
||||
'sum' => $dbForInternal->count('bucket_' . $bucketId, $queries, APP_LIMIT_COUNT),
|
||||
'sum' => $dbForExternal->count('bucket_' . $bucketId, $queries, APP_LIMIT_COUNT),
|
||||
]), Response::MODEL_FILE_LIST);
|
||||
});
|
||||
|
||||
|
@ -917,11 +923,13 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId')
|
|||
->param('fileId', '', new UID(), 'File unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->inject('dbForExternal')
|
||||
->inject('usage')
|
||||
->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 Utopia\Database\Database $dbForInternal */
|
||||
/** @var Utopia\Database\Database $dbForExternal */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$bucket = $dbForInternal->getDocument('buckets', $bucketId);
|
||||
|
@ -940,11 +948,11 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId')
|
|||
}
|
||||
|
||||
if($bucket->getAttribute('permission') === 'bucket') {
|
||||
$file = Authorization::skip(function() use ($dbForInternal, $bucketId, $fileId) {
|
||||
return $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
$file = Authorization::skip(function() use ($dbForExternal, $bucketId, $fileId) {
|
||||
return $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
});
|
||||
} else {
|
||||
$file = $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
$file = $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
}
|
||||
|
||||
if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) {
|
||||
|
@ -986,13 +994,15 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
|||
->inject('response')
|
||||
->inject('project')
|
||||
->inject('dbForInternal')
|
||||
->inject('dbForExternal')
|
||||
->inject('usage')
|
||||
->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 Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $project */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Utopia\Database\Database $dbForExternal */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$storage = 'files';
|
||||
|
@ -1032,11 +1042,11 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
|||
|
||||
if($bucket->getAttribute('permission')==='bucket') {
|
||||
// skip authorization
|
||||
$file = Authorization::skip(function () use ($dbForInternal, $bucketId, $fileId) {
|
||||
return $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
$file = Authorization::skip(function () use ($dbForExternal, $bucketId, $fileId) {
|
||||
return $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
});
|
||||
} else {
|
||||
$file = $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
$file = $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
}
|
||||
|
||||
if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) {
|
||||
|
@ -1158,12 +1168,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
|||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->inject('dbForExternal')
|
||||
->inject('usage')
|
||||
->inject('mode')
|
||||
->action(function ($bucketId, $fileId, $request, $response, $dbForInternal, $usage, $mode) {
|
||||
->action(function ($bucketId, $fileId, $request, $response, $dbForInternal, $dbForExternal, $usage, $mode) {
|
||||
/** @var Utopia\Swoole\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Utopia\Database\Database $dbForExternal */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
||||
$bucket = $dbForInternal->getDocument('buckets', $bucketId);
|
||||
|
@ -1182,11 +1194,11 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
|||
}
|
||||
|
||||
if($bucket->getAttribute('permission') === 'bucket') {
|
||||
$file = Authorization::skip(function() use ($dbForInternal, $fileId, $bucketId) {
|
||||
return $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
$file = Authorization::skip(function() use ($dbForExternal, $fileId, $bucketId) {
|
||||
return $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
});
|
||||
} else {
|
||||
$file = $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
$file = $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
}
|
||||
|
||||
if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) {
|
||||
|
@ -1295,9 +1307,10 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
|||
->inject('response')
|
||||
->inject('request')
|
||||
->inject('dbForInternal')
|
||||
->inject('dbForExternal')
|
||||
->inject('usage')
|
||||
->inject('mode')
|
||||
->action(function ($bucketId, $fileId, $response, $request, $dbForInternal, $usage, $mode) {
|
||||
->action(function ($bucketId, $fileId, $response, $request, $dbForInternal, $dbForExternal, $usage, $mode) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Swoole\Request $request */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
|
@ -1319,11 +1332,11 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
|||
}
|
||||
|
||||
if($bucket->getAttribute('permission') === 'bucket') {
|
||||
$file = Authorization::skip(function() use ($dbForInternal, $fileId, $bucketId) {
|
||||
return $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
$file = Authorization::skip(function() use ($dbForExternal, $fileId, $bucketId) {
|
||||
return $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
});
|
||||
} else {
|
||||
$file = $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
$file = $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
}
|
||||
|
||||
$mimes = Config::getParam('storage-mimes');
|
||||
|
@ -1447,10 +1460,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.')
|
||||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->inject('dbForExternal')
|
||||
->inject('audits')
|
||||
->inject('usage')
|
||||
->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 Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
|
@ -1472,11 +1486,11 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
|
|||
}
|
||||
|
||||
if($bucket->getAttribute('permission') === 'bucket') {
|
||||
$file = Authorization::skip(function() use ($dbForInternal, $fileId, $bucketId) {
|
||||
return $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
$file = Authorization::skip(function() use ($dbForExternal, $fileId, $bucketId) {
|
||||
return $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
});
|
||||
} else {
|
||||
$file = $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
$file = $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
}
|
||||
|
||||
if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) {
|
||||
|
@ -1484,14 +1498,14 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
|
|||
}
|
||||
|
||||
if($bucket->getAttribute('permission') === 'bucket') {
|
||||
$file = Authorization::skip(function() use ($dbForInternal, $fileId, $bucketId, $file, $read, $write) {
|
||||
return $dbForInternal->updateDocument('bucket_' . $bucketId, $fileId, $file
|
||||
$file = Authorization::skip(function() use ($dbForExternal, $fileId, $bucketId, $file, $read, $write) {
|
||||
return $dbForExternal->updateDocument('bucket_' . $bucketId, $fileId, $file
|
||||
->setAttribute('$read', $read)
|
||||
->setAttribute('$write', $write)
|
||||
);
|
||||
});
|
||||
} else {
|
||||
$file = $dbForInternal->updateDocument('bucket_' . $bucketId, $fileId, $file
|
||||
$file = $dbForExternal->updateDocument('bucket_' . $bucketId, $fileId, $file
|
||||
->setAttribute('$read', $read)
|
||||
->setAttribute('$write', $write)
|
||||
);
|
||||
|
@ -1526,13 +1540,15 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
|
|||
->param('fileId', '', new UID(), 'File unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->inject('dbForExternal')
|
||||
->inject('events')
|
||||
->inject('audits')
|
||||
->inject('usage')
|
||||
->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 Utopia\Database\Database $dbForInternal */
|
||||
/** @var Utopia\Database\Database $dbForExternal */
|
||||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Stats\Stats $usage */
|
||||
|
@ -1553,11 +1569,11 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
|
|||
}
|
||||
|
||||
if($bucket->getAttribute('permission') === 'bucket') {
|
||||
$file = Authorization::skip(function() use ($dbForInternal, $fileId, $bucketId) {
|
||||
return $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
$file = Authorization::skip(function() use ($dbForExternal, $fileId, $bucketId) {
|
||||
return $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
});
|
||||
} else {
|
||||
$file = $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
$file = $dbForExternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
}
|
||||
|
||||
if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) {
|
||||
|
@ -1568,11 +1584,11 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
|
|||
|
||||
if ($device->delete($file->getAttribute('path', ''))) {
|
||||
if($bucket->getAttribute('permission') === 'bucket') {
|
||||
$deleted = Authorization::skip(function() use ($dbForInternal, $fileId, $bucketId) {
|
||||
return $dbForInternal->deleteDocument('bucket_' . $bucketId, $fileId);
|
||||
$deleted = Authorization::skip(function() use ($dbForExternal, $fileId, $bucketId) {
|
||||
return $dbForExternal->deleteDocument('bucket_' . $bucketId, $fileId);
|
||||
});
|
||||
} else {
|
||||
$deleted = $dbForInternal->deleteDocument('bucket_' . $bucketId, $fileId);
|
||||
$deleted = $dbForExternal->deleteDocument('bucket_' . $bucketId, $fileId);
|
||||
}
|
||||
if (!$deleted) {
|
||||
throw new Exception('Failed to remove file from DB', 500);
|
||||
|
@ -1638,8 +1654,18 @@ App::get('/v1/storage/usage')
|
|||
];
|
||||
|
||||
$metrics = [
|
||||
'storage.total',
|
||||
'storage.files.count'
|
||||
"storage.tags.total",
|
||||
"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 = [];
|
||||
|
@ -1653,7 +1679,7 @@ App::get('/v1/storage/usage')
|
|||
new Query('period', Query::TYPE_EQUAL, [$period]),
|
||||
new Query('metric', Query::TYPE_EQUAL, [$metric]),
|
||||
], $limit, 0, ['time'], [Database::ORDER_DESC]);
|
||||
|
||||
|
||||
$stats[$metric] = [];
|
||||
foreach ($requestDocs as $requestDoc) {
|
||||
$stats[$metric][] = [
|
||||
|
@ -1682,8 +1708,18 @@ App::get('/v1/storage/usage')
|
|||
|
||||
$usage = new Document([
|
||||
'range' => $range,
|
||||
'storage' => $stats['storage.total'],
|
||||
'files' => $stats['storage.files.count']
|
||||
'filesStorage' => $stats['storage.files.total'],
|
||||
'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'],
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -1737,6 +1773,7 @@ App::get('/v1/storage/:bucketId/usage')
|
|||
|
||||
$metrics = [
|
||||
"storage.buckets.$bucketId.files.count",
|
||||
"storage.buckets.$bucketId.files.total",
|
||||
"storage.buckets.$bucketId.files.create",
|
||||
"storage.buckets.$bucketId.files.read",
|
||||
"storage.buckets.$bucketId.files.update",
|
||||
|
@ -1749,12 +1786,11 @@ App::get('/v1/storage/:bucketId/usage')
|
|||
foreach ($metrics as $metric) {
|
||||
$limit = $periods[$range]['limit'];
|
||||
$period = $periods[$range]['period'];
|
||||
|
||||
$requestDocs = $dbForInternal->find('stats', [
|
||||
new Query('period', Query::TYPE_EQUAL, [$period]),
|
||||
new Query('metric', Query::TYPE_EQUAL, [$metric]),
|
||||
], $limit, 0, ['time'], [Database::ORDER_DESC]);
|
||||
|
||||
|
||||
$stats[$metric] = [];
|
||||
foreach ($requestDocs as $requestDoc) {
|
||||
$stats[$metric][] = [
|
||||
|
@ -1783,6 +1819,7 @@ App::get('/v1/storage/:bucketId/usage')
|
|||
|
||||
$usage = new Document([
|
||||
'range' => $range,
|
||||
'filesStorage' => $stats["storage.buckets.$bucketId.files.total"],
|
||||
'filesCount' => $stats["storage.buckets.$bucketId.files.count"],
|
||||
'filesCreate' => $stats["storage.buckets.$bucketId.files.create"],
|
||||
'filesRead' => $stats["storage.buckets.$bucketId.files.read"],
|
||||
|
|
|
@ -315,6 +315,36 @@ App::get('/console/storage')
|
|||
->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')
|
||||
->groups(['web', 'console'])
|
||||
->label('permission', 'public')
|
||||
|
|
|
@ -66,7 +66,7 @@ const APP_LIMIT_ANTIVIRUS = 20971520; //20MB
|
|||
const APP_LIMIT_ENCRYPTION = 20971520; //20MB
|
||||
const APP_LIMIT_COMPRESSION = 20971520; //20MB
|
||||
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_ENUM = 'enum';
|
||||
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;
|
||||
$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');
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,10 @@ use Utopia\Database\Validator\Authorization;
|
|||
* storage.buckets.read
|
||||
* storage.buckets.update
|
||||
* storage.buckets.delete
|
||||
* storage.files.create
|
||||
* storage.files.read
|
||||
* storage.files.update
|
||||
* storage.files.delete
|
||||
* storage.buckets.{bucketId}.files.create
|
||||
* storage.buckets.{bucketId}.files.read
|
||||
* storage.buckets.{bucketId}.files.update
|
||||
|
@ -69,6 +73,7 @@ use Utopia\Database\Validator\Authorization;
|
|||
* users.count
|
||||
* storage.buckets.count
|
||||
* storage.files.count
|
||||
* storage.buckets.{bucketId}.files.count
|
||||
* database.collections.count
|
||||
* database.documents.count
|
||||
* database.collections.{collectionId}.documents.count
|
||||
|
@ -161,6 +166,18 @@ $cli
|
|||
'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' => [
|
||||
'table' => 'appwrite_usage_storage_files_create',
|
||||
'groupBy' => 'bucketId',
|
||||
|
@ -387,19 +404,19 @@ $cli
|
|||
foreach ($projects as $project) {
|
||||
$projectId = $project->getId();
|
||||
|
||||
// Get total storage
|
||||
// storage.tags.total
|
||||
$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
|
||||
$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);
|
||||
if ($document->isEmpty()) {
|
||||
$dbForProject->createDocument('stats', new Document([
|
||||
'$id' => $id,
|
||||
'period' => '30m',
|
||||
'time' => $time,
|
||||
'metric' => 'storage.total',
|
||||
'metric' => 'storage.tags.total',
|
||||
'value' => $storageTotal,
|
||||
'type' => 1,
|
||||
]));
|
||||
|
@ -419,7 +436,7 @@ $cli
|
|||
'$id' => $id,
|
||||
'period' => '1d',
|
||||
'time' => $time,
|
||||
'metric' => 'storage.total',
|
||||
'metric' => 'storage.tags.total',
|
||||
'value' => $storageTotal,
|
||||
'type' => 1,
|
||||
]));
|
||||
|
@ -449,7 +466,11 @@ $cli
|
|||
'namespace' => 'internal',
|
||||
'subCollections' => [
|
||||
'files' => [
|
||||
'namespace' => 'internal',
|
||||
'namespace' => 'external',
|
||||
'collectionPrefix' => 'bucket_',
|
||||
'sum' => [
|
||||
'field' => 'sizeOriginal'
|
||||
]
|
||||
],
|
||||
]
|
||||
]
|
||||
|
@ -511,6 +532,7 @@ $cli
|
|||
|
||||
$latestParent = null;
|
||||
$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
|
||||
$dbForProject->setNamespace("project_{$projectId}_{$options['namespace']}");
|
||||
|
@ -525,7 +547,7 @@ $cli
|
|||
foreach ($parents as $parent) {
|
||||
foreach ($subCollections as $subCollection => $subOptions) { // Sub collection counts, like database.collections.collectionId.documents.count
|
||||
$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
|
||||
|
||||
|
@ -571,6 +593,55 @@ $cli
|
|||
$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));
|
||||
|
@ -623,7 +694,50 @@ $cli
|
|||
);
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
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">
|
||||
<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>
|
||||
|
@ -15,320 +10,202 @@ $fileLimitHuman = $this->getParam('fileLimitHuman', 0);
|
|||
<div class="zone xl">
|
||||
<ul class="phases clear" data-ui-phases data-selected="{{router.params.tab}}">
|
||||
<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"
|
||||
data-service="storage.listFiles"
|
||||
data-event="submit"
|
||||
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"
|
||||
<div class="margin-top"
|
||||
data-service="storage.listBuckets"
|
||||
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="{{router.params.offset}}"
|
||||
data-param-order-type="DESC"
|
||||
data-scope="sdk"
|
||||
data-name="project-files">
|
||||
data-name="project-buckets">
|
||||
|
||||
<div data-ls-if="0 == {{project-files.sum}}" class="box margin-bottom">
|
||||
<h3 class="margin-bottom-small text-bold">No Files Found</h3>
|
||||
<div data-ls-if="(!{{project-buckets.sum}})" class="box dashboard margin-bottom">
|
||||
<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>
|
||||
|
||||
<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 data-ls-if="0 != {{project-buckets.sum}}">
|
||||
<ul data-ls-loop="project-buckets.buckets" data-ls-as="bucket" data-ls-append="" class="tiles cell-3 margin-bottom-small">
|
||||
<li class="margin-bottom">
|
||||
<a data-ls-attrs="href=/console/storage/bucket?id={{bucket.$id}}&project={{router.params.project}}" class="box">
|
||||
<div data-ls-bind="{{bucket.name}}" class="text-one-liner margin-bottom text-bold"> </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>
|
||||
|
||||
<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>
|
||||
<i class="icon-right-open"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="pull-end text-align-center paging">
|
||||
<form
|
||||
data-service="storage.listFiles"
|
||||
data-service="storage.listBuckets"
|
||||
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-name="project-buckets"
|
||||
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>
|
||||
<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>
|
||||
|
||||
<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
|
||||
data-service="storage.listFiles"
|
||||
data-service="storage.listBuckets"
|
||||
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-name="project-buckets"
|
||||
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>
|
||||
<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>
|
||||
</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>
|
||||
|
||||
<h1>Upload File</h1>
|
||||
<h1>New Bucket</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-analytics-label="Create Storage Bucket"
|
||||
data-service="storage.createBucket"
|
||||
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-success="alert,reset,redirect,trigger"
|
||||
data-success-param-alert-text="Bucket created successfully"
|
||||
data-success-param-redirect-url="/console/storage/bucket/settings?id={{serviceData.$id}}&project={{router.params.project}}"
|
||||
data-success-param-trigger-events="storage.createBucket"
|
||||
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">
|
||||
<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
|
||||
type="hidden"
|
||||
data-custom-id
|
||||
data-id-type="auto"
|
||||
data-validator="storage.getFile"
|
||||
data-validator="storage.getBucket"
|
||||
required
|
||||
maxlength="36"
|
||||
pattern="^[a-zA-Z0-9][a-zA-Z0-9_-]{1,36}$"
|
||||
name="fileId"
|
||||
id="fileId" />
|
||||
name="bucketId" />
|
||||
|
||||
<label for="file-read">File</label>
|
||||
<input type="file" name="file" id="file-file" size="1" required>
|
||||
<label for="bucket-name">Name</label>
|
||||
<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>
|
||||
<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>
|
||||
<hr />
|
||||
|
||||
<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>
|
||||
<button type="submit">Create</button> <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<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'"
|
||||
|
||||
</li>
|
||||
|
||||
<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'"
|
||||
data-service="storage.getUsage"
|
||||
data-event="submit"
|
||||
data-name="usage"
|
||||
data-param-range="90d">
|
||||
<button class="tick">90d</button>
|
||||
</form>
|
||||
<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>
|
||||
<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.getUsage"
|
||||
data-event="submit"
|
||||
data-name="usage">
|
||||
<button class="tick">30d</button>
|
||||
</form>
|
||||
<form class="pull-end margin-start-small margin-top-small" data-ls-if="{{usage.range}} !== '30d'"
|
||||
data-service="storage.getUsage"
|
||||
data-event="submit"
|
||||
data-name="usage">
|
||||
<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>
|
||||
<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.getUsage"
|
||||
data-event="submit"
|
||||
data-name="usage"
|
||||
data-param-range="24h">
|
||||
<button class="tick">24h</button>
|
||||
</form>
|
||||
<form class="pull-end margin-start-small margin-top-small" data-ls-if="{{usage.range}} !== '24h'"
|
||||
data-service="storage.getUsage"
|
||||
data-event="submit"
|
||||
data-name="usage"
|
||||
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>
|
||||
<button class="tick pull-end margin-start-small margin-top-small" data-ls-if="{{usage.range}} === '24h'" disabled>24h</button>
|
||||
|
||||
<h2>Usage</h2>
|
||||
<h2>Usage</h2>
|
||||
|
||||
<div
|
||||
data-service="storage.getUsage"
|
||||
data-event="load"
|
||||
data-name="usage">
|
||||
<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-forms-chart="Total Files=files" data-height="140" data-show-y-axis="true" />
|
||||
<div
|
||||
data-service="storage.getUsage"
|
||||
data-event="load"
|
||||
data-name="usage">
|
||||
<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="chart background-image-no border-no margin-bottom-no">
|
||||
<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>
|
||||
|
||||
<ul class="chart-notes margin-bottom-large">
|
||||
<li>Total Files <span data-ls-bind="({{usage.files|statsGetLast|statsTotal}})"></span></li>
|
||||
</ul>
|
||||
|
||||
<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-forms-chart="Total Storage=storage" data-height="140" data-show-y-axis="true" />
|
||||
<ul class="chart-notes margin-top-small margin-bottom-large">
|
||||
<li>Total Files</li>
|
||||
<li>Total Buckets</li>
|
||||
<!-- <li>Total Storage <span data-ls-bind="({{usage.filesStorage|statsGetLast|statsTotal}})"></span></li> -->
|
||||
</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="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="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>
|
||||
|
||||
<ul class="chart-notes 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>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<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>
|
||||
|
||||
<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>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
152
composer.lock
generated
152
composer.lock
generated
|
@ -489,16 +489,16 @@
|
|||
},
|
||||
{
|
||||
"name": "guzzlehttp/guzzle",
|
||||
"version": "7.4.0",
|
||||
"version": "7.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/guzzle.git",
|
||||
"reference": "868b3571a039f0ebc11ac8f344f4080babe2cb94"
|
||||
"reference": "ee0a041b1760e6a53d2a39c8c34115adc2af2c79"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/868b3571a039f0ebc11ac8f344f4080babe2cb94",
|
||||
"reference": "868b3571a039f0ebc11ac8f344f4080babe2cb94",
|
||||
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/ee0a041b1760e6a53d2a39c8c34115adc2af2c79",
|
||||
"reference": "ee0a041b1760e6a53d2a39c8c34115adc2af2c79",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -507,7 +507,7 @@
|
|||
"guzzlehttp/psr7": "^1.8.3 || ^2.1",
|
||||
"php": "^7.2.5 || ^8.0",
|
||||
"psr/http-client": "^1.0",
|
||||
"symfony/deprecation-contracts": "^2.2"
|
||||
"symfony/deprecation-contracts": "^2.2 || ^3.0"
|
||||
},
|
||||
"provide": {
|
||||
"psr/http-client-implementation": "1.0"
|
||||
|
@ -593,7 +593,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/guzzle/guzzle/issues",
|
||||
"source": "https://github.com/guzzle/guzzle/tree/7.4.0"
|
||||
"source": "https://github.com/guzzle/guzzle/tree/7.4.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -609,7 +609,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-10-18T09:52:00+00:00"
|
||||
"time": "2021-12-06T18:43:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/promises",
|
||||
|
@ -1591,25 +1591,25 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/deprecation-contracts",
|
||||
"version": "v2.5.0",
|
||||
"version": "v3.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/deprecation-contracts.git",
|
||||
"reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8"
|
||||
"reference": "c726b64c1ccfe2896cb7df2e1331c357ad1c8ced"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/6f981ee24cf69ee7ce9736146d1c57c2780598a8",
|
||||
"reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8",
|
||||
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/c726b64c1ccfe2896cb7df2e1331c357ad1c8ced",
|
||||
"reference": "c726b64c1ccfe2896cb7df2e1331c357ad1c8ced",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1"
|
||||
"php": ">=8.0.2"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "2.5-dev"
|
||||
"dev-main": "3.0-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/contracts",
|
||||
|
@ -1638,7 +1638,7 @@
|
|||
"description": "A generic function and convention to trigger deprecation notices",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.0"
|
||||
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.0.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1654,7 +1654,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-07-12T14:48:14+00:00"
|
||||
"time": "2021-11-01T23:48:49+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
|
@ -2554,7 +2554,7 @@
|
|||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/storage",
|
||||
"reference": "88ed83274542ba3c9d34c5dabd17e0cfb480519d"
|
||||
"reference": "c47611b3a4a36c674c16e9720e86187452eb1cc2"
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0",
|
||||
|
@ -2570,6 +2570,11 @@
|
|||
"Utopia\\Storage\\": "src/Storage"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Utopia\\Tests\\": "tests/Storage"
|
||||
}
|
||||
},
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
|
@ -2587,7 +2592,7 @@
|
|||
"upf",
|
||||
"utopia"
|
||||
],
|
||||
"time": "2021-12-03T04:31:08+00:00"
|
||||
"time": "2021-12-09T07:34:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/swoole",
|
||||
|
@ -3033,6 +3038,77 @@
|
|||
},
|
||||
"time": "2021-11-12T11:09:38+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/pcre",
|
||||
"version": "1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/pcre.git",
|
||||
"reference": "3d322d715c43a1ac36c7fe215fa59336265500f2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/pcre/zipball/3d322d715c43a1ac36c7fe215fa59336265500f2",
|
||||
"reference": "3d322d715c43a1ac36c7fe215fa59336265500f2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.3.2 || ^7.0 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^1",
|
||||
"phpstan/phpstan-strict-rules": "^1.1",
|
||||
"symfony/phpunit-bridge": "^4.2 || ^5"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Composer\\Pcre\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jordi Boggiano",
|
||||
"email": "j.boggiano@seld.be",
|
||||
"homepage": "http://seld.be"
|
||||
}
|
||||
],
|
||||
"description": "PCRE wrapping library that offers type-safe preg_* replacements.",
|
||||
"keywords": [
|
||||
"PCRE",
|
||||
"preg",
|
||||
"regex",
|
||||
"regular expression"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/composer/pcre/issues",
|
||||
"source": "https://github.com/composer/pcre/tree/1.0.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://packagist.com",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/composer",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-12-06T15:17:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/semver",
|
||||
"version": "3.2.6",
|
||||
|
@ -3116,25 +3192,27 @@
|
|||
},
|
||||
{
|
||||
"name": "composer/xdebug-handler",
|
||||
"version": "2.0.2",
|
||||
"version": "2.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/xdebug-handler.git",
|
||||
"reference": "84674dd3a7575ba617f5a76d7e9e29a7d3891339"
|
||||
"reference": "6555461e76962fd0379c444c46fd558a0fcfb65e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/xdebug-handler/zipball/84674dd3a7575ba617f5a76d7e9e29a7d3891339",
|
||||
"reference": "84674dd3a7575ba617f5a76d7e9e29a7d3891339",
|
||||
"url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6555461e76962fd0379c444c46fd558a0fcfb65e",
|
||||
"reference": "6555461e76962fd0379c444c46fd558a0fcfb65e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer/pcre": "^1",
|
||||
"php": "^5.3.2 || ^7.0 || ^8.0",
|
||||
"psr/log": "^1 || ^2 || ^3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^0.12.55",
|
||||
"symfony/phpunit-bridge": "^4.2 || ^5"
|
||||
"phpstan/phpstan": "^1.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.1",
|
||||
"symfony/phpunit-bridge": "^4.2 || ^5.0 || ^6.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
@ -3160,7 +3238,7 @@
|
|||
"support": {
|
||||
"irc": "irc://irc.freenode.org/composer",
|
||||
"issues": "https://github.com/composer/xdebug-handler/issues",
|
||||
"source": "https://github.com/composer/xdebug-handler/tree/2.0.2"
|
||||
"source": "https://github.com/composer/xdebug-handler/tree/2.0.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -3176,7 +3254,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-07-31T17:03:58+00:00"
|
||||
"time": "2021-12-08T13:07:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "dnoegel/php-xdg-base-dir",
|
||||
|
@ -4007,16 +4085,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpspec/prophecy",
|
||||
"version": "1.14.0",
|
||||
"version": "v1.15.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpspec/prophecy.git",
|
||||
"reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e"
|
||||
"reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e",
|
||||
"reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/bbcd7380b0ebf3961ee21409db7b38bc31d69a13",
|
||||
"reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -4068,22 +4146,22 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/phpspec/prophecy/issues",
|
||||
"source": "https://github.com/phpspec/prophecy/tree/1.14.0"
|
||||
"source": "https://github.com/phpspec/prophecy/tree/v1.15.0"
|
||||
},
|
||||
"time": "2021-09-10T09:02:12+00:00"
|
||||
"time": "2021-12-08T12:19:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "9.2.9",
|
||||
"version": "9.2.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "f301eb1453c9e7a1bc912ee8b0ea9db22c60223b"
|
||||
"reference": "d5850aaf931743067f4bfc1ae4cbd06468400687"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f301eb1453c9e7a1bc912ee8b0ea9db22c60223b",
|
||||
"reference": "f301eb1453c9e7a1bc912ee8b0ea9db22c60223b",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d5850aaf931743067f4bfc1ae4cbd06468400687",
|
||||
"reference": "d5850aaf931743067f4bfc1ae4cbd06468400687",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -4139,7 +4217,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.9"
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.10"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -4147,7 +4225,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2021-11-19T15:21:02+00:00"
|
||||
"time": "2021-12-05T09:12:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
|
|
|
@ -3870,11 +3870,10 @@
|
|||
};
|
||||
this.storage = {
|
||||
/**
|
||||
* List Files
|
||||
* List buckets
|
||||
*
|
||||
* 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).
|
||||
* Get a list of all the storage buckets. You can use the query params to
|
||||
* filter your results.
|
||||
*
|
||||
* @param {string} search
|
||||
* @param {number} limit
|
||||
|
@ -3885,8 +3884,219 @@
|
|||
* @throws {AppwriteException}
|
||||
* @returns {Promise}
|
||||
*/
|
||||
listFiles: (search, limit, offset, cursor, cursorDirection, orderType) => __awaiter(this, void 0, void 0, function* () {
|
||||
let path = '/storage/files';
|
||||
listBuckets: (search, limit, offset, cursor, cursorDirection, orderType) => __awaiter(this, void 0, void 0, function* () {
|
||||
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 = {};
|
||||
if (typeof search !== 'undefined') {
|
||||
payload['search'] = search;
|
||||
|
@ -3918,21 +4128,25 @@
|
|||
* assigned to read and write access unless he has passed custom values for
|
||||
* read and write arguments.
|
||||
*
|
||||
* @param {string} bucketId
|
||||
* @param {string} fileId
|
||||
* @param {File} file
|
||||
* @param {string[]} read
|
||||
* @param {string[]} write
|
||||
* @param {string} read
|
||||
* @param {string} write
|
||||
* @throws {AppwriteException}
|
||||
* @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') {
|
||||
throw new AppwriteException('Missing required parameter: "fileId"');
|
||||
}
|
||||
if (typeof file === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "file"');
|
||||
}
|
||||
let path = '/storage/files';
|
||||
let path = '/storage/buckets/{bucketId}/files'.replace('{bucketId}', bucketId);
|
||||
let payload = {};
|
||||
if (typeof fileId !== 'undefined') {
|
||||
payload['fileId'] = fileId;
|
||||
|
@ -3957,15 +4171,19 @@
|
|||
* Get a file by its unique ID. This endpoint response returns a JSON object
|
||||
* with the file metadata.
|
||||
*
|
||||
* @param {string} bucketId
|
||||
* @param {string} fileId
|
||||
* @throws {AppwriteException}
|
||||
* @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') {
|
||||
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 = {};
|
||||
const uri = new URL(this.config.endpoint + path);
|
||||
return yield this.call('get', uri, {
|
||||
|
@ -3978,13 +4196,17 @@
|
|||
* Update a file by its unique ID. Only users with write permissions have
|
||||
* access to update this resource.
|
||||
*
|
||||
* @param {string} bucketId
|
||||
* @param {string} fileId
|
||||
* @param {string[]} read
|
||||
* @param {string[]} write
|
||||
* @param {string} read
|
||||
* @param {string} write
|
||||
* @throws {AppwriteException}
|
||||
* @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') {
|
||||
throw new AppwriteException('Missing required parameter: "fileId"');
|
||||
}
|
||||
|
@ -3994,7 +4216,7 @@
|
|||
if (typeof write === 'undefined') {
|
||||
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 = {};
|
||||
if (typeof read !== 'undefined') {
|
||||
payload['read'] = read;
|
||||
|
@ -4013,15 +4235,19 @@
|
|||
* Delete a file by its unique ID. Only users with write permissions have
|
||||
* access to delete this resource.
|
||||
*
|
||||
* @param {string} bucketId
|
||||
* @param {string} fileId
|
||||
* @throws {AppwriteException}
|
||||
* @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') {
|
||||
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 = {};
|
||||
const uri = new URL(this.config.endpoint + path);
|
||||
return yield this.call('delete', uri, {
|
||||
|
@ -4035,15 +4261,19 @@
|
|||
* 'Content-Disposition: attachment' header that tells the browser to start
|
||||
* downloading the file to user downloads directory.
|
||||
*
|
||||
* @param {string} bucketId
|
||||
* @param {string} fileId
|
||||
* @throws {AppwriteException}
|
||||
* @returns {URL}
|
||||
*/
|
||||
getFileDownload: (fileId) => {
|
||||
getFileDownload: (bucketId, fileId) => {
|
||||
if (typeof bucketId === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "bucketId"');
|
||||
}
|
||||
if (typeof fileId === 'undefined') {
|
||||
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 = {};
|
||||
const uri = new URL(this.config.endpoint + path);
|
||||
payload['project'] = this.config.project;
|
||||
|
@ -4060,6 +4290,7 @@
|
|||
* and spreadsheets, will return the file icon image. You can also pass query
|
||||
* string arguments for cutting and resizing your preview image.
|
||||
*
|
||||
* @param {string} bucketId
|
||||
* @param {string} fileId
|
||||
* @param {number} width
|
||||
* @param {number} height
|
||||
|
@ -4075,11 +4306,14 @@
|
|||
* @throws {AppwriteException}
|
||||
* @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') {
|
||||
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 = {};
|
||||
if (typeof width !== 'undefined') {
|
||||
payload['width'] = width;
|
||||
|
@ -4128,15 +4362,19 @@
|
|||
* download method but returns with no 'Content-Disposition: attachment'
|
||||
* header.
|
||||
*
|
||||
* @param {string} bucketId
|
||||
* @param {string} fileId
|
||||
* @throws {AppwriteException}
|
||||
* @returns {URL}
|
||||
*/
|
||||
getFileView: (fileId) => {
|
||||
getFileView: (bucketId, fileId) => {
|
||||
if (typeof bucketId === 'undefined') {
|
||||
throw new AppwriteException('Missing required parameter: "bucketId"');
|
||||
}
|
||||
if (typeof fileId === 'undefined') {
|
||||
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 = {};
|
||||
const uri = new URL(this.config.endpoint + path);
|
||||
payload['project'] = this.config.project;
|
||||
|
|
|
@ -183,6 +183,13 @@ window.ls.filter
|
|||
|
||||
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) {
|
||||
return (!!$value);
|
||||
})
|
||||
|
|
|
@ -160,8 +160,17 @@ window.ls.router
|
|||
scope: "console",
|
||||
project: true
|
||||
})
|
||||
.add("/console/storage/:tab", {
|
||||
template: "/console/storage?version=" + APP_ENV.CACHEBUSTER,
|
||||
.add("/console/storage/bucket", {
|
||||
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",
|
||||
project: true
|
||||
})
|
||||
|
|
|
@ -51,8 +51,9 @@
|
|||
display: showYAxis,
|
||||
min: 0,
|
||||
ticks: {
|
||||
count: ticksCount,
|
||||
fontColor: "#8f8f8f"
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
|
@ -67,7 +68,7 @@
|
|||
mode: "index",
|
||||
intersect: false,
|
||||
caretPadding: 0
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -113,8 +114,8 @@
|
|||
config.options.scales.y.ticks.stepSize = highest / ticksCount;
|
||||
config.options.scales.y.max = highest;
|
||||
}
|
||||
|
||||
if (chart) {
|
||||
|
||||
if(chart) {
|
||||
chart.destroy();
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -50,6 +50,7 @@ abstract class Migration
|
|||
'0.10.4' => 'V09',
|
||||
'0.11.0' => 'V10',
|
||||
'0.12.0' => 'V10',
|
||||
'0.13.0' => 'V10',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
@ -23,6 +23,13 @@ class UsageBuckets extends Model
|
|||
'example' => new \stdClass,
|
||||
'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', [
|
||||
'type' => Response::MODEL_METRIC_LIST,
|
||||
'description' => 'Aggregated stats for files created.',
|
||||
|
|
|
@ -16,20 +16,90 @@ class UsageStorage extends Model
|
|||
'default' => '',
|
||||
'example' => '30d',
|
||||
])
|
||||
->addRule('storage', [
|
||||
->addRule('filesStorage', [
|
||||
'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' => [],
|
||||
'example' => new \stdClass,
|
||||
'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,
|
||||
'description' => 'Aggregated stats for total number of files.',
|
||||
'default' => [],
|
||||
'example' => new \stdClass,
|
||||
'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(count($response['body']), 3);
|
||||
$this->assertEquals(count($response['body']), 13);
|
||||
$this->assertEquals($response['body']['range'], '24h');
|
||||
$this->assertIsArray($response['body']['storage']);
|
||||
$this->assertIsArray($response['body']['files']);
|
||||
$this->assertIsArray($response['body']['filesStorage']);
|
||||
$this->assertIsArray($response['body']['filesCount']);
|
||||
}
|
||||
|
||||
public function testGetStorageBucketUsage()
|
||||
|
@ -93,12 +93,13 @@ class StorageConsoleClientTest extends Scope
|
|||
]);
|
||||
|
||||
$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->assertIsArray($response['body']['filesCount']);
|
||||
$this->assertIsArray($response['body']['filesCreate']);
|
||||
$this->assertIsArray($response['body']['filesRead']);
|
||||
$this->assertIsArray($response['body']['filesUpdate']);
|
||||
$this->assertIsArray($response['body']['filesDelete']);
|
||||
$this->assertIsArray($response['body']['filesStorage']);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue