Storage support for local disk (#165)
* Storage support for local disk * UI change ai feature page --------- Co-authored-by: Julien Nahum <julien@nahum.net>
This commit is contained in:
parent
c42c7ca97c
commit
3c71be5d45
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Content;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Controllers\Forms\PublicFormController;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
class FileUploadController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Upload file to local temp
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return \Illuminate\Http\JsonResponse
|
||||||
|
*/
|
||||||
|
public function upload(Request $request)
|
||||||
|
{
|
||||||
|
$uuid = (string) Str::uuid();
|
||||||
|
$path = $request->file('file')->storeAs(PublicFormController::TMP_FILE_UPLOAD_PATH, $uuid);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'uuid' => $uuid,
|
||||||
|
'key' => $path
|
||||||
|
], 201);
|
||||||
|
}
|
||||||
|
}
|
|
@ -177,12 +177,12 @@ class FormController extends Controller
|
||||||
|
|
||||||
// Make sure we retrieve the file in tmp storage, move it to persistent
|
// Make sure we retrieve the file in tmp storage, move it to persistent
|
||||||
$fileName = PublicFormController::TMP_FILE_UPLOAD_PATH.'/'.$fileNameParser->uuid;;
|
$fileName = PublicFormController::TMP_FILE_UPLOAD_PATH.'/'.$fileNameParser->uuid;;
|
||||||
if (!Storage::disk('s3')->exists($fileName)) {
|
if (!Storage::exists($fileName)) {
|
||||||
// File not found, we skip
|
// File not found, we skip
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
$newPath = self::ASSETS_UPLOAD_PATH.'/'.$fileNameParser->getMovedFileName();
|
$newPath = self::ASSETS_UPLOAD_PATH.'/'.$fileNameParser->getMovedFileName();
|
||||||
Storage::disk('s3')->move($fileName, $newPath);
|
Storage::move($fileName, $newPath);
|
||||||
|
|
||||||
return $this->success([
|
return $this->success([
|
||||||
'message' => 'File uploaded.',
|
'message' => 'File uploaded.',
|
||||||
|
@ -199,12 +199,12 @@ class FormController extends Controller
|
||||||
$this->authorize('view', $form);
|
$this->authorize('view', $form);
|
||||||
|
|
||||||
$path = Str::of(PublicFormController::FILE_UPLOAD_PATH)->replace('?', $form->id).'/'.$fileName;
|
$path = Str::of(PublicFormController::FILE_UPLOAD_PATH)->replace('?', $form->id).'/'.$fileName;
|
||||||
if (!Storage::disk('s3')->exists($path)) {
|
if (!Storage::exists($path)) {
|
||||||
return $this->error([
|
return $this->error([
|
||||||
'message' => 'File not found.'
|
'message' => 'File not found.'
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->to(Storage::disk('s3')->temporaryUrl($path, now()->addMinutes(5)));
|
return redirect()->to(Storage::temporaryUrl($path, now()->addMinutes(5)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,14 +57,14 @@ class FormSubmissionController extends Controller
|
||||||
$fileName = Str::of(PublicFormController::FILE_UPLOAD_PATH)->replace('?', $id).'/'
|
$fileName = Str::of(PublicFormController::FILE_UPLOAD_PATH)->replace('?', $id).'/'
|
||||||
.urldecode($fileName);
|
.urldecode($fileName);
|
||||||
|
|
||||||
if (!Storage::disk('s3')->exists($fileName)) {
|
if (!Storage::exists($fileName)) {
|
||||||
return $this->error([
|
return $this->error([
|
||||||
'message' => 'File not found.',
|
'message' => 'File not found.',
|
||||||
], 404);
|
], 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect(
|
return redirect(
|
||||||
Storage::disk('s3')->temporaryUrl($fileName, now()->addMinute())
|
Storage::temporaryUrl($fileName, now()->addMinute())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,14 +66,14 @@ class PublicFormController extends Controller
|
||||||
public function showAsset($assetFileName)
|
public function showAsset($assetFileName)
|
||||||
{
|
{
|
||||||
$path = FormController::ASSETS_UPLOAD_PATH.'/'.$assetFileName;
|
$path = FormController::ASSETS_UPLOAD_PATH.'/'.$assetFileName;
|
||||||
if (!Storage::disk('s3')->exists($path)) {
|
if (!Storage::exists($path)) {
|
||||||
return $this->error([
|
return $this->error([
|
||||||
'message' => 'File not found.',
|
'message' => 'File not found.',
|
||||||
'file_name' => $assetFileName
|
'file_name' => $assetFileName
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->to(Storage::disk('s3')->temporaryUrl($path, now()->addMinutes(5)));
|
return redirect()->to(Storage::temporaryUrl($path, now()->addMinutes(5)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function answer(AnswerFormRequest $request)
|
public function answer(AnswerFormRequest $request)
|
||||||
|
|
|
@ -13,6 +13,7 @@ class VerifyCsrfToken extends Middleware
|
||||||
*/
|
*/
|
||||||
protected $except = [
|
protected $except = [
|
||||||
'stripe/webhook',
|
'stripe/webhook',
|
||||||
'vapor/signed-storage-url'
|
'vapor/signed-storage-url',
|
||||||
|
'upload-file'
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,7 +140,7 @@ class StoreFormSubmissionJob implements ShouldQueue
|
||||||
private function isSkipForUpload($value)
|
private function isSkipForUpload($value)
|
||||||
{
|
{
|
||||||
$newPath = Str::of(PublicFormController::FILE_UPLOAD_PATH)->replace('?', $this->form->id);
|
$newPath = Str::of(PublicFormController::FILE_UPLOAD_PATH)->replace('?', $this->form->id);
|
||||||
return Storage::disk('s3')->exists($newPath.'/'.$value);
|
return Storage::exists($newPath.'/'.$value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -165,7 +165,7 @@ class StoreFormSubmissionJob implements ShouldQueue
|
||||||
|
|
||||||
// Make sure we retrieve the file in tmp storage, move it to persistent
|
// Make sure we retrieve the file in tmp storage, move it to persistent
|
||||||
$fileName = PublicFormController::TMP_FILE_UPLOAD_PATH.'/'.$fileNameParser->uuid;
|
$fileName = PublicFormController::TMP_FILE_UPLOAD_PATH.'/'.$fileNameParser->uuid;
|
||||||
if (!Storage::disk('s3')->exists($fileName)) {
|
if (!Storage::exists($fileName)) {
|
||||||
// File not found, we skip
|
// File not found, we skip
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -178,7 +178,7 @@ class StoreFormSubmissionJob implements ShouldQueue
|
||||||
'form_id' => $this->form->id,
|
'form_id' => $this->form->id,
|
||||||
'form_slug' => $this->form->slug,
|
'form_slug' => $this->form->slug,
|
||||||
]);
|
]);
|
||||||
Storage::disk('s3')->move($fileName, $completeNewFilename);
|
Storage::move($fileName, $completeNewFilename);
|
||||||
|
|
||||||
return $fileNameParser->getMovedFileName();
|
return $fileNameParser->getMovedFileName();
|
||||||
}
|
}
|
||||||
|
@ -193,7 +193,7 @@ class StoreFormSubmissionJob implements ShouldQueue
|
||||||
$newPath = Str::of(PublicFormController::FILE_UPLOAD_PATH)->replace('?', $this->form->id);
|
$newPath = Str::of(PublicFormController::FILE_UPLOAD_PATH)->replace('?', $this->form->id);
|
||||||
$completeNewFilename = $newPath.'/'.$fileName;
|
$completeNewFilename = $newPath.'/'.$fileName;
|
||||||
|
|
||||||
Storage::disk('s3')->put($completeNewFilename, base64_decode(explode(',', $value)[1]));
|
Storage::put($completeNewFilename, base64_decode(explode(',', $value)[1]));
|
||||||
|
|
||||||
return $fileName;
|
return $fileName;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,8 @@ use Illuminate\Support\ServiceProvider;
|
||||||
use Laravel\Cashier\Cashier;
|
use Laravel\Cashier\Cashier;
|
||||||
use Laravel\Dusk\DuskServiceProvider;
|
use Laravel\Dusk\DuskServiceProvider;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Support\Facades\URL;
|
||||||
class AppServiceProvider extends ServiceProvider
|
class AppServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -18,6 +19,16 @@ class AppServiceProvider extends ServiceProvider
|
||||||
*/
|
*/
|
||||||
public function boot()
|
public function boot()
|
||||||
{
|
{
|
||||||
|
if(config('filesystems.default') === 'local'){
|
||||||
|
Storage::disk('local')->buildTemporaryUrlsUsing(function ($path, $expiration, $options) {
|
||||||
|
return URL::temporarySignedRoute(
|
||||||
|
'local.temp',
|
||||||
|
$expiration,
|
||||||
|
array_merge($options, ['path' => $path])
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
JsonResource::withoutWrapping();
|
JsonResource::withoutWrapping();
|
||||||
Cashier::calculateTaxes();
|
Cashier::calculateTaxes();
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ class StorageFile implements Rule
|
||||||
// This is use when updating a record, and file uploads aren't changed.
|
// This is use when updating a record, and file uploads aren't changed.
|
||||||
if($this->form){
|
if($this->form){
|
||||||
$newPath = Str::of(PublicFormController::FILE_UPLOAD_PATH)->replace('?', $this->form->id);
|
$newPath = Str::of(PublicFormController::FILE_UPLOAD_PATH)->replace('?', $this->form->id);
|
||||||
if(Storage::disk('s3')->exists($newPath.'/'.$value)){
|
if(Storage::exists($newPath.'/'.$value)){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,13 +62,16 @@
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="mt-6 sm:mt-8 flex">
|
<div class="mt-6 sm:mt-8 flex text-center justify-center lg:justify-start">
|
||||||
<v-button v-if="!authenticated" class="mr-1" :to="{ name: 'forms.create.guest' }" :arrow="true">
|
<v-button v-if="!authenticated" class="mr-2 block" :to="{ name: 'forms.create.guest' }" :arrow="true">
|
||||||
Get started for free
|
Get started for free
|
||||||
</v-button>
|
</v-button>
|
||||||
<v-button v-else class="mr-1" :to="{ name: 'forms.create' }" :arrow="true">
|
<v-button v-else class="mr-2 block" :to="{ name: 'forms.create' }" :arrow="true">
|
||||||
Get started for free
|
Get started for free
|
||||||
</v-button>
|
</v-button>
|
||||||
|
<v-button color="light-gray" class="mr-1 block" :to="{ name: 'aiformbuilder' }">
|
||||||
|
Learn more
|
||||||
|
</v-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,26 @@ Vue.mixin({
|
||||||
* Store a file in S3 and return its UUID, key, and other information.
|
* Store a file in S3 and return its UUID, key, and other information.
|
||||||
*/
|
*/
|
||||||
async storeFile (file, options = {}) {
|
async storeFile (file, options = {}) {
|
||||||
|
if(!window.config.s3_enabled) { // If not s3 then upload to local temp
|
||||||
|
if (typeof options.progress === 'undefined') {
|
||||||
|
options.progress = () => {}
|
||||||
|
}
|
||||||
|
const cleanAxios = axios.create()
|
||||||
|
let formData = new FormData();
|
||||||
|
formData.append('file', file);
|
||||||
|
const response = await cleanAxios.post('/upload-file', formData, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'multipart/form-data'
|
||||||
|
},
|
||||||
|
onUploadProgress: (progressEvent) => {
|
||||||
|
options.progress(progressEvent.loaded / progressEvent.total)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
response.data.extension = file.name.split('.').pop()
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
|
||||||
const response = await axios.post(options.signedStorageUrl ? options.signedStorageUrl : '/vapor/signed-storage-url', {
|
const response = await axios.post(options.signedStorageUrl ? options.signedStorageUrl : '/vapor/signed-storage-url', {
|
||||||
bucket: options.bucket || '',
|
bucket: options.bucket || '',
|
||||||
content_type: options.contentType || file.type,
|
content_type: options.contentType || file.type,
|
||||||
|
|
|
@ -13,7 +13,8 @@
|
||||||
'google_analytics_code' => config('services.google_analytics_code'),
|
'google_analytics_code' => config('services.google_analytics_code'),
|
||||||
'amplitude_code' => config('services.amplitude_code'),
|
'amplitude_code' => config('services.amplitude_code'),
|
||||||
'crisp_website_id' => config('services.crisp_website_id'),
|
'crisp_website_id' => config('services.crisp_website_id'),
|
||||||
'ai_features_enabled' => !is_null(config('services.openai.api_key'))
|
'ai_features_enabled' => !is_null(config('services.openai.api_key')),
|
||||||
|
's3_enabled' => config('filesystems.default') === 's3'
|
||||||
];
|
];
|
||||||
@endphp
|
@endphp
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
@ -22,4 +24,17 @@ Route::post(
|
||||||
'/vapor/signed-storage-url',
|
'/vapor/signed-storage-url',
|
||||||
[\App\Http\Controllers\Content\SignedStorageUrlController::class, 'store']
|
[\App\Http\Controllers\Content\SignedStorageUrlController::class, 'store']
|
||||||
)->middleware([]);
|
)->middleware([]);
|
||||||
|
Route::post(
|
||||||
|
'/upload-file',
|
||||||
|
[\App\Http\Controllers\Content\FileUploadController::class, 'upload']
|
||||||
|
)->middleware([]);
|
||||||
|
Route::get('local/temp/{path}', function (Request $request, string $path){
|
||||||
|
if (!$request->hasValidSignature()) {
|
||||||
|
abort(401);
|
||||||
|
}
|
||||||
|
$response = Response::make(Storage::get($path), 200);
|
||||||
|
$response->header("Content-Type", Storage::mimeType($path));
|
||||||
|
return $response;
|
||||||
|
})->where('path', '(.*)')->name('local.temp');
|
||||||
|
|
||||||
Route::get('/sitemap.xml', [\App\Http\Controllers\SitemapController::class, 'getSitemap'])->name('sitemap');
|
Route::get('/sitemap.xml', [\App\Http\Controllers\SitemapController::class, 'getSitemap'])->name('sitemap');
|
||||||
|
|
Loading…
Reference in New Issue