Merge branch 'master' into api

# Conflicts:
#	.env.testing
#	public/mix-manifest.json
#	src/Domain/RemoteUpload/Controllers/UploadFilesRemotelyForUploadRequestController.php
This commit is contained in:
Čarodej
2022-05-11 09:00:42 +02:00
83 changed files with 803 additions and 472 deletions

View File

@@ -23,7 +23,7 @@ class SetupWebsocketEnvironment extends Command
public function handle(): void
{
// Get allowed origins
$origins = $this->ask('Type host of which you want to allow incoming requests. If you want to accept multiple hosts, separate them with comma(,)');
$origins = $this->ask('Type the host of your VueFileManager front-end application to allow connection with your websocket server. If you want to accept multiple hosts, separate them with comma(,)');
// Store origins to the .env file
setEnvironmentValue([

View File

@@ -94,10 +94,15 @@ class UserLimitation extends Model
$totalUsedEmails = $memberEmails->merge($InvitationEmails)
->unique();
// Get usage in percent
$percentage = (int) $this->max_team_members === 0
? 100
: ($totalUsedEmails->count() / $this->max_team_members) * 100;
return [
'use' => $totalUsedEmails->count(),
'total' => (int) $this->max_team_members,
'percentage' => ($totalUsedEmails->count() / $this->max_team_members) * 100,
'percentage' => $percentage,
'meta' => [
'allowed_emails' => $totalUsedEmails,
],

View File

@@ -2,11 +2,11 @@
namespace Domain\Files\Actions;
use App\Users\Models\User;
use Illuminate\Support\Str;
use Domain\Files\Models\File;
use Illuminate\Support\Facades\Storage;
use Domain\Files\Requests\UploadRequest;
use Domain\Traffic\Actions\RecordUploadAction;
use League\Flysystem\UnableToRetrieveMetadata;
class ProcessFileAction
{
@@ -26,19 +26,29 @@ class ProcessFileAction
public function __invoke(
UploadRequest $request,
User $user,
string $chunkPath,
) {
string $name,
): File {
// Get local disk instance
$localDisk = Storage::disk('local');
// Get file data
$size = $localDisk->size($chunkPath);
$mimetype = $localDisk->mimeType($chunkPath);
$name = Str::uuid() . '.' . $request->input('extension');
// Get file path
$filePath = "files/$user->id/$name";
// Get upload limit
// Get file size
$size = $localDisk->size($filePath);
// Get upload limit size
$uploadLimit = get_settings('upload_limit');
// Get mimetype
try {
$fileType = getFileType(
$localDisk->mimeType($filePath)
);
} catch (UnableToRetrieveMetadata $e) {
$fileType = 'file';
}
// File size handling
if ($uploadLimit && $size > format_bytes($uploadLimit)) {
abort(413);
@@ -47,26 +57,24 @@ class ProcessFileAction
// Check if user has enough space to upload file
if (! $user->canUpload($size)) {
// Delete file from chunk directory
$localDisk->delete($chunkPath);
// Set up response
$response = response([
'type' => 'error',
'message' => __t('user_action_not_allowed'),
], 401);
$localDisk->delete($filePath);
// Abort code
abort($response);
abort(
response([
'type' => 'error',
'message' => __t('user_action_not_allowed'),
], 401)
);
}
// Move file to user directory
$localDisk->move($chunkPath, "files/$user->id/$name");
if ($fileType === 'image') {
// Create multiple image thumbnails
($this->createImageThumbnail)($name, $user->id);
// Create multiple image thumbnails
($this->createImageThumbnail)($name, $user->id);
// Store exif data if exists
$exif = ($this->storeExifData)("files/$user->id/$name");
// Store exif data if exists
$exif = ($this->storeExifData)($filePath);
}
// Move file to external storage
match (config('filesystems.default')) {
@@ -78,7 +86,7 @@ class ProcessFileAction
// Create new file
$file = File::create([
'mimetype' => $request->input('extension'),
'type' => getFileType($mimetype),
'type' => $fileType,
'parent_id' => ($this->getFileParentId)($request, $user->id),
'name' => $request->input('name'),
'basename' => $name,
@@ -88,7 +96,10 @@ class ProcessFileAction
]);
// Attach file into the exif data
$exif?->update(['file_id' => $file->id]);
if ($fileType === 'image') {
$exif?->update(['file_id' => $file->id]);
}
// Return new file
return $file;

View File

@@ -1,7 +1,6 @@
<?php
namespace Domain\Files\Actions;
use Log;
use Str;
use Storage;
use Exception;
@@ -31,7 +30,7 @@ class StoreExifDataAction
$exif = json_decode(json_encode($exifRaw));
return Exif::create([
'file_id' => Str::uuid(), // TODO: temporary store to prevent crash before app will be successfully upgraded
'file_id' => Str::uuid(),
'date_time_original' => $exif->DateTimeOriginal ?? null,
'artist' => $exif->OwnerName ?? null,
'width' => $exif->COMPUTED->Width ?? null,
@@ -53,8 +52,6 @@ class StoreExifDataAction
'latitude_ref' => $exif->GPSLatitudeRef ?? null,
]);
} catch (Exception $error) {
Log::error('Unable to get exif data');
return null;
}
}

View File

@@ -1,6 +1,8 @@
<?php
namespace Domain\Files\Controllers;
use Storage;
use Illuminate\Support\Str;
use Domain\Folders\Models\Folder;
use App\Http\Controllers\Controller;
use Domain\Files\Requests\UploadRequest;
@@ -42,8 +44,14 @@ class UploadFileController extends Controller
->user
: auth()->user();
// Get file name
$name = Str::uuid() . '.' . $request->input('extension');
// Move file to user directory
Storage::disk('local')->move($chunkPath, "files/$user->id/$name");
// Process file
$file = ($this->processFie)($request, $user, $chunkPath);
$file = ($this->processFie)($request, $user, $name);
return response(new FileResource($file), 201);
}

View File

@@ -1,6 +1,8 @@
<?php
namespace Domain\Files\Controllers;
use Str;
use Storage;
use Domain\Sharing\Models\Share;
use App\Http\Controllers\Controller;
use Domain\Files\Requests\UploadRequest;
@@ -53,8 +55,14 @@ class VisitorUploadFileController extends Controller
// Proceed after last chunk
if ($request->boolean('is_last')) {
// Get file name
$name = Str::uuid() . '.' . $request->input('extension');
// Move file to user directory
Storage::disk('local')->move($chunkPath, "files/{$shared->user->id}/$name");
// Process file
$file = ($this->processFie)($request, $shared->user, $chunkPath);
$file = ($this->processFie)($request, $shared->user, $name);
// Set public access url
$file->setSharedPublicUrl($shared->token);

View File

@@ -2,6 +2,7 @@
namespace Domain\Localization\Actions;
use DB;
use Artisan;
class UpdateLanguageTranslationsAction
{
@@ -10,9 +11,11 @@ class UpdateLanguageTranslationsAction
collect($list)
->each(
fn (...$item) => DB::table('language_translations')
->where('lang', 'en')
->where('key', $item[1])
->update(['value' => $item[0]])
->where('lang', 'en')
->where('key', $item[1])
->update(['value' => $item[0]])
);
Artisan::call('cache:clear');
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace Domain\Settings\Actions;
use ErrorException;
use VueFileManager\Subscription\Support\EngineManager;
use VueFileManager\Subscription\Domain\Plans\DTO\CreateFixedPlanData;
class TestPayPalConnectionAction
{
public function __construct(
public EngineManager $subscription
) {
}
public function __invoke($credentials)
{
try {
// Set temporary stripe connection
config([
'subscription.credentials.paypal' => [
'secret' => $credentials['secret'],
'id' => $credentials['key'],
'webhook_id' => $credentials['webhook'],
'is_live' => $credentials['live'],
],
]);
// Define test plan
$data = CreateFixedPlanData::fromArray([
'type' => 'fixed',
'name' => 'Test Plan',
'description' => null,
'features' => [
'max_storage_amount' => 200,
'max_team_members' => 20,
],
'currency' => 'EUR',
'amount' => 99,
'interval' => 'month',
]);
// Create test plan
$plan = $this->subscription
->driver('paypal')
->createFixedPlan($data);
// Delete plan
$this->subscription
->driver('paypal')
->deletePlan($plan['id']);
} catch (ErrorException $error) {
abort(
response()->json([
'type' => 'service-connection-error',
'title' => 'Service Connection Error',
'message' => $error->getMessage(),
], 401)
);
}
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace Domain\Settings\Actions;
use ErrorException;
use VueFileManager\Subscription\Support\EngineManager;
use VueFileManager\Subscription\Domain\Plans\DTO\CreateFixedPlanData;
class TestPaystackConnectionAction
{
public function __construct(
public EngineManager $subscription
) {
}
public function __invoke($credentials)
{
try {
// Set temporary paystack connection
config([
'subscription.credentials.paystack' => [
'secret' => $credentials['secret'],
'public_key' => $credentials['key'],
],
]);
// Define test plan
$data = CreateFixedPlanData::fromArray([
'type' => 'fixed',
'name' => 'Test Plan',
'description' => null,
'features' => [
'max_storage_amount' => 200,
'max_team_members' => 20,
],
'currency' => 'ZAR',
'amount' => 99999,
'interval' => 'month',
]);
// Create test plan
$plan = $this->subscription
->driver('paystack')
->createFixedPlan($data);
// Delete plan
$this->subscription
->driver('paystack')
->deletePlan($plan['id']);
} catch (ErrorException $error) {
abort(
response()->json([
'type' => 'service-connection-error',
'title' => 'Service Connection Error',
'message' => $error->getMessage(),
], 401)
);
}
}
}

View File

@@ -0,0 +1,60 @@
<?php
namespace Domain\Settings\Actions;
use ErrorException;
use VueFileManager\Subscription\Support\EngineManager;
use VueFileManager\Subscription\Domain\Plans\DTO\CreateFixedPlanData;
class TestStripeConnectionAction
{
public function __construct(
public EngineManager $subscription
) {
}
public function __invoke($credentials)
{
try {
// Set temporary stripe connection
config([
'subscription.credentials.stripe' => [
'secret' => $credentials['secret'],
'public_key' => $credentials['key'],
'webhook_key' => $credentials['webhook'],
],
]);
// Define test plan
$data = CreateFixedPlanData::fromArray([
'type' => 'fixed',
'name' => 'Test Plan',
'description' => null,
'features' => [
'max_storage_amount' => 200,
'max_team_members' => 20,
],
'currency' => 'EUR',
'amount' => 99,
'interval' => 'month',
]);
// Create test plan
$plan = $this->subscription
->driver('stripe')
->createFixedPlan($data);
// Delete plan
$this->subscription
->driver('stripe')
->deletePlan($plan['id']);
} catch (ErrorException $error) {
abort(
response()->json([
'type' => 'service-connection-error',
'title' => 'Service Connection Error',
'message' => $error->getMessage(),
], 401)
);
}
}
}

View File

@@ -26,7 +26,7 @@ class StoreBroadcastServiceCredentialsController
'PUSHER_APP_CLUSTER' => $request->input('cluster'),
'PUSHER_APP_HOST' => '',
'PUSHER_APP_PORT' => '',
'PUSHER_APP_TLS' => true,
'PUSHER_APP_TLS' => 'true',
],
'native' => [
'BROADCAST_DRIVER' => 'pusher',

View File

@@ -4,10 +4,20 @@ namespace Domain\Settings\Controllers;
use Artisan;
use Illuminate\Http\Response;
use Domain\Settings\Models\Setting;
use Domain\Settings\Actions\TestPayPalConnectionAction;
use Domain\Settings\Actions\TestStripeConnectionAction;
use Domain\Settings\Actions\TestPaystackConnectionAction;
use Domain\Settings\Requests\StorePaymentServiceCredentialsRequest;
class StorePaymentServiceCredentialsController
{
public function __construct(
public TestPaystackConnectionAction $testPaystackConnection,
public TestStripeConnectionAction $testStripeConnection,
public TestPayPalConnectionAction $testPayPalConnection,
) {
}
/**
* Configure stripe additionally
*/
@@ -43,6 +53,26 @@ class StorePaymentServiceCredentialsController
// Get and store credentials
if (! app()->runningUnitTests()) {
// Test payment gateway connection
match ($request->input('service')) {
'paystack' => ($this->testPaystackConnection)([
'key' => $request->input('key'),
'secret' => $request->input('secret'),
]),
'stripe' => ($this->testStripeConnection)([
'key' => $request->input('key'),
'secret' => $request->input('secret'),
'webhook' => $request->input('webhook'),
]),
'paypal' => ($this->testPayPalConnection)([
'key' => $request->input('key'),
'secret' => $request->input('secret'),
'webhook' => $request->input('webhook'),
'live' => $request->has('live') ? (string) $request->input('live') : $PayPalDefaultMode,
]),
default => null
};
$credentials = [
'stripe' => [
'STRIPE_PUBLIC_KEY' => $request->input('key'),

View File

@@ -27,7 +27,7 @@ class StoreDatabaseCredentialsController extends Controller
'port' => $request->input('port'),
'database' => $request->input('name'),
'username' => $request->input('username'),
'password' => $request->input('password'),
'password' => $request->input('password') ?? '',
],
]);
@@ -51,7 +51,7 @@ class StoreDatabaseCredentialsController extends Controller
'DB_PORT' => $request->input('port'),
'DB_DATABASE' => $request->input('name'),
'DB_USERNAME' => $request->input('username'),
'DB_PASSWORD' => $request->input('password'),
'DB_PASSWORD' => $request->input('password') ?? '',
]);
Artisan::call('config:cache');

View File

@@ -92,7 +92,7 @@ class StoreEnvironmentSettingsController extends Controller
'PUSHER_APP_CLUSTER' => $request->input('broadcast.cluster'),
'PUSHER_APP_HOST' => '',
'PUSHER_APP_PORT' => '',
'PUSHER_APP_TLS' => true,
'PUSHER_APP_TLS' => 'true',
],
'native' => [
'BROADCAST_DRIVER' => 'pusher',

View File

@@ -28,7 +28,7 @@ class StoreDatabaseCredentialsRequest extends FormRequest
'port' => 'required|string',
'name' => 'required|string',
'username' => 'required|string',
'password' => 'required|string',
'password' => 'nullable|sometimes|string',
];
}
}

View File

@@ -2,6 +2,8 @@
namespace Domain\UploadRequest\Controllers;
use DB;
use Storage;
use Illuminate\Support\Str;
use Domain\Folders\Models\Folder;
use Domain\Files\Resources\FileResource;
use Domain\Files\Actions\ProcessFileAction;
@@ -40,8 +42,14 @@ class UploadFilesForUploadRequestController
// Proceed after last chunk
if ($request->boolean('is_last')) {
// Get file name
$name = Str::uuid() . '.' . $request->input('extension');
// Move file to user directory
Storage::disk('local')->move($chunkPath, "files/{$uploadRequest->user->id}/$name");
// Process file
$file = ($this->processFie)($request, $uploadRequest->user, $chunkPath);
$file = ($this->processFie)($request, $uploadRequest->user, $name);
// Set public access url
$file->setUploadRequestPublicUrl($uploadRequest->id);

View File

@@ -22,6 +22,13 @@ class UpgradingVersionsController
) {
}
public function upgrade_to_2_1_2(): void
{
($this->updateLanguageStrings)([
'allow_recaptcha' => 'Allow ReCaptcha v3',
]);
}
public function upgrade_to_2_1_1(): void
{
($this->upgradeDatabase)();

View File

@@ -236,9 +236,9 @@ if (! function_exists('setEnvironmentValue')) {
if ($keyPosition) {
$endOfLinePosition = strpos($str, "\n", $keyPosition);
$oldLine = substr($str, $keyPosition, $endOfLinePosition - $keyPosition);
$str = str_replace($oldLine, "{$envKey}={$envValue}", $str);
$str = str_replace($oldLine, "{$envKey}=\"{$envValue}\"", $str);
} else {
$str .= "\n$envKey=$envValue";
$str .= "\n$envKey=\"$envValue\"";
}
}
}