create file for bucket and test
This commit is contained in:
parent
e530d633dc
commit
d7a6c47b98
|
@ -24,6 +24,7 @@ use Appwrite\Utopia\Response;
|
|||
use Utopia\Config\Config;
|
||||
use Utopia\Validator\Integer;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Storage\Validator\FileType;
|
||||
|
||||
App::post('/v1/storage/buckets')
|
||||
->desc('Create storage bucket')
|
||||
|
@ -245,6 +246,153 @@ App::delete('/v1/storage/buckets/:bucketId')
|
|||
$response->noContent();
|
||||
});
|
||||
|
||||
App::post('/v1/storage/buckets/:bucketId/files')
|
||||
->desc('Create File')
|
||||
->groups(['api', 'storage'])
|
||||
->label('scope', 'files.write')
|
||||
->label('event', 'storage.files.create')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
|
||||
->label('sdk.namespace', 'storage')
|
||||
->label('sdk.method', 'createFile')
|
||||
->label('sdk.description', '/docs/references/storage/create-file.md')
|
||||
->label('sdk.request.type', 'multipart/form-data')
|
||||
->label('sdk.methodType', 'upload')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_FILE)
|
||||
->param('bucketId', null, new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](/docs/server/storage#createBucket).')
|
||||
->param('file', [], new File(), 'Binary file.', false)
|
||||
->param('read', null, new ArrayList(new Text(64)), 'An array of strings with read permissions. By default only the current user is granted with read permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.', true)
|
||||
->param('write', null, new ArrayList(new Text(64)), 'An array of strings with write permissions. By default only the current user is granted with write permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.', true)
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('dbForInternal')
|
||||
->inject('user')
|
||||
->inject('audits')
|
||||
->inject('usage')
|
||||
->action(function ($bucketId, $file, $read, $write, $request, $response, $dbForInternal, $user, $audits, $usage) {
|
||||
/** @var Utopia\Swoole\Request $request */
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Database $dbForInternal */
|
||||
/** @var Appwrite\Database\Document $user */
|
||||
/** @var Appwrite\Event\Event $audits */
|
||||
/** @var Appwrite\Event\Event $usage */
|
||||
|
||||
$bucket = $dbForInternal->getDocument('buckets',$bucketId);
|
||||
|
||||
if($bucket->isEmpty()) {
|
||||
throw new Exception("Unable to find the bucket", 404);
|
||||
}
|
||||
|
||||
$file = $request->getFiles('file');
|
||||
|
||||
/*
|
||||
* Validators
|
||||
*/
|
||||
$fileType = new FileType($bucket->getAttribute('allowedFileExtensions', ['*']));
|
||||
$fileSize = new FileSize($bucket->getAttribute('maximumFileSize', 0));
|
||||
$upload = new Upload();
|
||||
|
||||
if (empty($file)) {
|
||||
throw new Exception('No file sent', 400);
|
||||
}
|
||||
|
||||
// Make sure we handle a single file and multiple files the same way
|
||||
$file['name'] = (\is_array($file['name']) && isset($file['name'][0])) ? $file['name'][0] : $file['name'];
|
||||
$file['tmp_name'] = (\is_array($file['tmp_name']) && isset($file['tmp_name'][0])) ? $file['tmp_name'][0] : $file['tmp_name'];
|
||||
$file['size'] = (\is_array($file['size']) && isset($file['size'][0])) ? $file['size'][0] : $file['size'];
|
||||
|
||||
// Check if file type is allowed (feature for project settings?)
|
||||
if (!$fileType->isValid($file['tmp_name'])) {
|
||||
throw new Exception('File type not allowed', 400);
|
||||
}
|
||||
|
||||
if (!$fileSize->isValid($file['size'])) { // Check if file size is exceeding allowed limit
|
||||
throw new Exception('File size not allowed', 400);
|
||||
}
|
||||
|
||||
$device = Storage::getDevice('files');
|
||||
|
||||
if (!$upload->isValid($file['tmp_name'])) {
|
||||
throw new Exception('Invalid file', 403);
|
||||
}
|
||||
|
||||
// Save to storage
|
||||
$size = $device->getFileSize($file['tmp_name']);
|
||||
$path = $device->getPath(\uniqid().'.'.\pathinfo($file['name'], PATHINFO_EXTENSION));
|
||||
$path = $bucket->getId() . '/' . $path;
|
||||
|
||||
if (!$device->upload($file['tmp_name'], $path)) { // TODO deprecate 'upload' and replace with 'move'
|
||||
throw new Exception('Failed moving file', 500);
|
||||
}
|
||||
|
||||
$mimeType = $device->getFileMimeType($path); // Get mime-type before compression and encryption
|
||||
|
||||
if (App::getEnv('_APP_STORAGE_ANTIVIRUS') === 'enabled' && $bucket->getAttribute('antiVirus', true)) { // Check if scans are enabled
|
||||
$antiVirus = new Network(App::getEnv('_APP_STORAGE_ANTIVIRUS_HOST', 'clamav'),
|
||||
(int) App::getEnv('_APP_STORAGE_ANTIVIRUS_PORT', 3310));
|
||||
|
||||
if (!$antiVirus->fileScan($path)) {
|
||||
$device->delete($path);
|
||||
throw new Exception('Invalid file', 403);
|
||||
}
|
||||
}
|
||||
|
||||
// Compression
|
||||
$compressor = new GZIP();
|
||||
$data = $device->read($path);
|
||||
$data = $compressor->compress($data);
|
||||
|
||||
if($bucket->getAttribute('encryption', true)) {
|
||||
$key = App::getEnv('_APP_OPENSSL_KEY_V1');
|
||||
$iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM));
|
||||
$data = OpenSSL::encrypt($data, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag);
|
||||
}
|
||||
|
||||
if (!$device->write($path, $data, $mimeType)) {
|
||||
throw new Exception('Failed to save file', 500);
|
||||
}
|
||||
|
||||
$sizeActual = $device->getFileSize($path);
|
||||
|
||||
$data = [
|
||||
'$read' => (is_null($read) && !$user->isEmpty()) ? ['user:'.$user->getId()] : $read ?? [], // By default set read permissions for user
|
||||
'$write' => (is_null($write) && !$user->isEmpty()) ? ['user:'.$user->getId()] : $write ?? [], // By default set write permissions for user
|
||||
'dateCreated' => \time(),
|
||||
'bucketId' => $bucket->getId(),
|
||||
'name' => $file['name'],
|
||||
'path' => $path,
|
||||
'signature' => $device->getFileHash($path),
|
||||
'mimeType' => $mimeType,
|
||||
'sizeOriginal' => $size,
|
||||
'sizeActual' => $sizeActual,
|
||||
'algorithm' => $compressor->getName(),
|
||||
'comment' => '',
|
||||
];
|
||||
|
||||
if($bucket->getAttribute('encryption', true)) {
|
||||
$data['openSSLVersion'] = '1';
|
||||
$data['openSSLCipher'] = OpenSSL::CIPHER_AES_128_GCM;
|
||||
$data['openSSLTag'] = \bin2hex($tag);
|
||||
$data['openSSLIV'] = \bin2hex($iv);
|
||||
}
|
||||
|
||||
$file = $dbForInternal->createDocument('files', new Document());
|
||||
|
||||
$audits
|
||||
->setParam('event', 'storage.files.create')
|
||||
->setParam('resource', 'storage/files/'.$file->getId())
|
||||
;
|
||||
|
||||
$usage
|
||||
->setParam('storage', $sizeActual)
|
||||
;
|
||||
|
||||
$response->setStatusCode(Response::STATUS_CODE_CREATED);
|
||||
$response->dynamic2($file, Response::MODEL_FILE);
|
||||
;
|
||||
});
|
||||
|
||||
App::post('/v1/storage/files')
|
||||
->desc('Create File')
|
||||
->groups(['api', 'storage'])
|
||||
|
|
|
@ -8,6 +8,46 @@ use Utopia\Image\Image;
|
|||
|
||||
trait StorageBase
|
||||
{
|
||||
public function testCreateBucketFile($data):array
|
||||
{
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$bucket = $this->client->call(Client::METHOD_POST, '/storage/buckets', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'name' => 'Test Bucket',
|
||||
]);
|
||||
var_dump($bucket);
|
||||
$this->assertEquals(201, $bucket['headers']['status-code']);
|
||||
$this->assertNotEmpty($bucket['body']['$id']);
|
||||
|
||||
$bucketId = $bucket['body']['$id'];
|
||||
|
||||
$file = $this->client->call(Client::METHOD_POST, '/storage/' . $bucketId .'/files', array_merge([
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'),
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:all'],
|
||||
]);
|
||||
|
||||
$this->assertEquals($file['headers']['status-code'], 201);
|
||||
$this->assertNotEmpty($file['body']['$id']);
|
||||
$this->assertIsInt($file['body']['dateCreated']);
|
||||
$this->assertEquals('logo.png', $file['body']['name']);
|
||||
$this->assertEquals('image/png', $file['body']['mimeType']);
|
||||
$this->assertEquals(47218, $file['body']['sizeOriginal']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
return ['fileId' => $file['body']['$id']];
|
||||
}
|
||||
|
||||
public function testCreateFile():array
|
||||
{
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue