1
0
Fork 0
mirror of synced 2024-05-20 20:52:36 +12:00

Enabled code upload

This commit is contained in:
Eldad Fux 2020-07-14 23:33:52 +03:00
parent d5b33e229e
commit 436300439d
12 changed files with 92 additions and 22 deletions

View file

@ -14,6 +14,8 @@ use Appwrite\Database\Database;
use Appwrite\Database\Document;
use Appwrite\Database\Validator\Authorization;
use Appwrite\Network\Validator\Origin;
use Appwrite\Storage\Device\Local;
use Appwrite\Storage\Storage;
Config::setParam('domainVerification', false);
Config::setParam('cookieDomain', 'localhost');
@ -87,6 +89,8 @@ App::init(function ($utopia, $request, $response, $console, $project, $user, $lo
: '.'.$request->getHostname()
);
Storage::setDevice('local', new Local(APP_STORAGE_UPLOADS.'/app-'.$project->getId()));
/*
* Security Headers
*

View file

@ -2,6 +2,11 @@
use Appwrite\Database\Database;
use Appwrite\Database\Validator\UID;
use Appwrite\Storage\Storage;
use Appwrite\Storage\Validator\File;
use Appwrite\Storage\Validator\FileSize;
use Appwrite\Storage\Validator\FileType;
use Appwrite\Storage\Validator\Upload;
use Appwrite\Task\Validator\Cron;
use Utopia\App;
use Utopia\Response;
@ -215,13 +220,50 @@ App::post('/v1/functions/:functionId/tags')
->label('sdk.description', '/docs/references/functions/create-tag.md')
->param('functionId', '', function () { return new UID(); }, 'Function unique ID.')
->param('command', '', function () { return new Text('1028'); }, 'Code execution command.')
->param('code', '', function () { return new Text(128); }, 'Code package. Use the '.APP_NAME.' code packager to create a deployable package file.')
->action(function ($functionId, $command, $code, $response, $projectDB) {
// ->param('code', '', function () { return new Text(128); }, 'Code package. Use the '.APP_NAME.' code packager to create a deployable package file.')
->param('code', [], function () { return new File(); }, 'Gzip file containing your code.', false)
->action(function ($functionId, $command, $code, $request, $response, $projectDB) {
$function = $projectDB->getDocument($functionId);
if (empty($function->getId()) || Database::SYSTEM_COLLECTION_FUNCTIONS != $function->getCollection()) {
throw new Exception('Function not found', 404);
}
$file = $request->getFiles('code');
$device = Storage::getDevice('local');
$fileType = new FileType([FileType::FILE_TYPE_GZIP]);
$fileSize = new FileSize(App::getEnv('_APP_STORAGE_LIMIT', 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);
}
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));
if (!$device->upload($file['tmp_name'], $path)) { // TODO deprecate 'upload' and replace with 'move'
throw new Exception('Failed moving file', 500);
}
$tag = $projectDB->createDocument([
'$collection' => Database::SYSTEM_COLLECTION_TAGS,
@ -232,7 +274,8 @@ App::post('/v1/functions/:functionId/tags')
'dateCreated' => time(),
'functionId' => $function->getId(),
'command' => $command,
'code' => $code,
'codePath' => $path,
'codeSize' => $size,
]);
if (false === $tag) {
@ -243,7 +286,7 @@ App::post('/v1/functions/:functionId/tags')
->setStatusCode(Response::STATUS_CODE_CREATED)
->json($tag->getArrayCopy())
;
}, ['response', 'projectDB']);
}, ['request', 'response', 'projectDB']);
App::get('/v1/functions/:functionId/tags')
->groups(['api', 'functions'])

View file

@ -23,10 +23,6 @@ use Appwrite\Resize\Resize;
use Appwrite\OpenSSL\OpenSSL;
use Utopia\Config\Config;
App::init(function ($project) {
Storage::setDevice('local', new Local(APP_STORAGE_UPLOADS.'/app-'.$project->getId()));
}, ['project'], 'storage');
App::post('/v1/storage/files')
->desc('Create File')
->groups(['api', 'storage'])
@ -38,7 +34,7 @@ App::post('/v1/storage/files')
->label('sdk.description', '/docs/references/storage/create-file.md')
->label('sdk.consumes', 'multipart/form-data')
->label('sdk.methodType', 'upload')
->param('file', [], function () { return new File(); }, 'Binary File.', false)
->param('file', [], function () { return new File(); }, 'Binary file.', false)
->param('read', [], function () { return new ArrayList(new Text(64)); }, 'An array of strings with read permissions. By default no user is granted with any read permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->param('write', [], function () { return new ArrayList(new Text(64)); }, '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.')
->action(function ($file, $read, $write, $request, $response, $user, $projectDB, $webhooks, $audits, $usage) {

View file

@ -6,7 +6,7 @@ sdk
.setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
;
let promise = sdk.functions.createTag('[FUNCTION_ID]', '[COMMAND]', '[CODE]');
let promise = sdk.functions.createTag('[FUNCTION_ID]', '[COMMAND]', document.getElementById('uploader').files[0]);
promise.then(function (response) {
console.log(response); // Success

View file

@ -2149,7 +2149,7 @@
*
* @param {string} functionId
* @param {string} command
* @param {string} code
* @param {File} code
* @throws {Error}
* @return {Promise}
*/
@ -2180,7 +2180,7 @@
return http
.post(path, {
'content-type': 'application/json',
'content-type': 'multipart/form-data',
}, payload);
},

View file

@ -187,7 +187,7 @@ if(command===undefined){throw new Error('Missing required parameter: "command"')
if(code===undefined){throw new Error('Missing required parameter: "code"')}
let path='/functions/{functionId}/tags'.replace(new RegExp('{functionId}','g'),functionId);let payload={};if(command){payload.command=command}
if(code){payload.code=code}
return http.post(path,{'content-type':'application/json',},payload)},getTag:function(functionId,tagId){if(functionId===undefined){throw new Error('Missing required parameter: "functionId"')}
return http.post(path,{'content-type':'multipart/form-data',},payload)},getTag:function(functionId,tagId){if(functionId===undefined){throw new Error('Missing required parameter: "functionId"')}
if(tagId===undefined){throw new Error('Missing required parameter: "tagId"')}
let path='/functions/{functionId}/tags/{tagId}'.replace(new RegExp('{functionId}','g'),functionId).replace(new RegExp('{tagId}','g'),tagId);let payload={};return http.get(path,{'content-type':'application/json',},payload)},deleteTag:function(functionId,tagId){if(functionId===undefined){throw new Error('Missing required parameter: "functionId"')}
if(tagId===undefined){throw new Error('Missing required parameter: "tagId"')}

View file

@ -739,11 +739,11 @@ declare namespace Appwrite {
*
* @param {string} functionId
* @param {string} command
* @param {string} code
* @param {File} code
* @throws {Error}
* @return {Promise}
*/
createTag(functionId: string, command: string, code: string): Promise<object>;
createTag(functionId: string, command: string, code: File): Promise<object>;
/**
* Get Tag

View file

@ -90,9 +90,32 @@ $events = array_keys($this->getParam('events', []));
<h1>Deploy a New Tag</h1>
<footer>
<button type="submit">Create</button> &nbsp; <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
</footer>
<form
data-analytics-event="submit"
data-analytics-category="console"
data-analytics-label="Create Function Tag"
data-service="functions.createTag"
data-scope="sdk"
data-event="submit"
data-success="alert,trigger,reset"
data-success-param-alert-text="Created function tag successfully"
data-success-param-trigger-events="functions.createTag"
data-failure="alert"
data-failure-param-alert-text="Failed to create function tag"
data-failure-param-alert-classname="error">
<input type="hidden" name="functionId" data-ls-bind="{{router.params.id}}" />
<label for="tag-command">Command</label>
<input type="text" id="tag-command" name="command" required autocomplete="off" class="margin-bottom" placeholder="node main.js" />
<label for="tag-code">Gzipped Code</label>
<input type="file" name="code" id="tag-code" size="1" required class="margin-bottom-xl">
<footer>
<button type="submit">Create</button> &nbsp; <button data-ui-modal-close="" type="button" class="reverse">Cancel</button>
</footer>
</form>
</div>
</div>

View file

@ -201,7 +201,7 @@ if(command===undefined){throw new Error('Missing required parameter: "command"')
if(code===undefined){throw new Error('Missing required parameter: "code"');}
let path='/functions/{functionId}/tags'.replace(new RegExp('{functionId}','g'),functionId);let payload={};if(command){payload['command']=command;}
if(code){payload['code']=code;}
return http.post(path,{'content-type':'application/json',},payload);},getTag:function(functionId,tagId){if(functionId===undefined){throw new Error('Missing required parameter: "functionId"');}
return http.post(path,{'content-type':'multipart/form-data',},payload);},getTag:function(functionId,tagId){if(functionId===undefined){throw new Error('Missing required parameter: "functionId"');}
if(tagId===undefined){throw new Error('Missing required parameter: "tagId"');}
let path='/functions/{functionId}/tags/{tagId}'.replace(new RegExp('{functionId}','g'),functionId).replace(new RegExp('{tagId}','g'),tagId);let payload={};return http.get(path,{'content-type':'application/json',},payload);},deleteTag:function(functionId,tagId){if(functionId===undefined){throw new Error('Missing required parameter: "functionId"');}
if(tagId===undefined){throw new Error('Missing required parameter: "tagId"');}

View file

@ -201,7 +201,7 @@ if(command===undefined){throw new Error('Missing required parameter: "command"')
if(code===undefined){throw new Error('Missing required parameter: "code"');}
let path='/functions/{functionId}/tags'.replace(new RegExp('{functionId}','g'),functionId);let payload={};if(command){payload['command']=command;}
if(code){payload['code']=code;}
return http.post(path,{'content-type':'application/json',},payload);},getTag:function(functionId,tagId){if(functionId===undefined){throw new Error('Missing required parameter: "functionId"');}
return http.post(path,{'content-type':'multipart/form-data',},payload);},getTag:function(functionId,tagId){if(functionId===undefined){throw new Error('Missing required parameter: "functionId"');}
if(tagId===undefined){throw new Error('Missing required parameter: "tagId"');}
let path='/functions/{functionId}/tags/{tagId}'.replace(new RegExp('{functionId}','g'),functionId).replace(new RegExp('{tagId}','g'),tagId);let payload={};return http.get(path,{'content-type':'application/json',},payload);},deleteTag:function(functionId,tagId){if(functionId===undefined){throw new Error('Missing required parameter: "functionId"');}
if(tagId===undefined){throw new Error('Missing required parameter: "tagId"');}

View file

@ -2149,7 +2149,7 @@
*
* @param {string} functionId
* @param {string} command
* @param {string} code
* @param {File} code
* @throws {Error}
* @return {Promise}
*/
@ -2180,7 +2180,7 @@
return http
.post(path, {
'content-type': 'application/json',
'content-type': 'multipart/form-data',
}, payload);
},

View file

@ -13,6 +13,7 @@ class FileType extends Validator
const FILE_TYPE_JPEG = 'jpeg';
const FILE_TYPE_GIF = 'gif';
const FILE_TYPE_PNG = 'png';
const FILE_TYPE_GZIP = 'gz';
/**
* File Type Binaries.
@ -23,6 +24,7 @@ class FileType extends Validator
self::FILE_TYPE_JPEG => "\xFF\xD8\xFF",
self::FILE_TYPE_GIF => 'GIF',
self::FILE_TYPE_PNG => "\x89\x50\x4e\x47\x0d\x0a",
self::FILE_TYPE_GZIP => "application/x-gzip",
);
/**
@ -76,6 +78,8 @@ class FileType extends Validator
$bytes = \fgets($handle, 8);
var_dump($bytes);
foreach ($this->whiteList as $key) {
if (\strpos($bytes, $this->types[$key]) === 0) {
\fclose($handle);