Shared link expiration backend

Redirect from sign in page when user is logged
Updated README.md
This commit is contained in:
Peter Papp
2020-08-26 07:29:28 +02:00
parent 6f300ba1d5
commit 2b08d7801b
87 changed files with 355 additions and 155 deletions

View File

@@ -23,7 +23,8 @@ But, it can't be done without you, development is more and more complicated and
- [Recover Failed Installation](#installation-failed) - [Recover Failed Installation](#installation-failed)
- [Update Guide](#update-guide) - [Update Guide](#update-guide)
- [Instructions](#instructions) - [Instructions](#instructions)
- [Update from 1.7.x to 1.7.7 & 1.7.8](#update-from-17x-to-177-&178) - [Update from 1.7.8 to 1.7.9](#update-from-178-to-179)
- [Update from 1.7.x to 1.7.8](#update-from-17x-to-178)
- [Update from 1.6.x to 1.7](#update-from-16x-to-17) - [Update from 1.6.x to 1.7](#update-from-16x-to-17)
- [Payments](#payments) - [Payments](#payments)
- [Get your active plans](#get-your-active-plans) - [Get your active plans](#get-your-active-plans)
@@ -104,6 +105,13 @@ At first step you have to verify your purchase code. **Subscription service with
That was the hardest part of installation proces. Please follow instructions in every step of Setup Wizard to successfully install VueFileManager. That was the hardest part of installation proces. Please follow instructions in every step of Setup Wizard to successfully install VueFileManager.
#### 7. Set up Cron
Add the following Cron entry to your server
```
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
```
## PHP Configuration ## PHP Configuration
There are several PHP settings good to know to setup before you try upload any file. Please set these values in your php.ini, we provide minimal setup for you. When you set `-1` then you set infinity limits. There are several PHP settings good to know to setup before you try upload any file. Please set these values in your php.ini, we provide minimal setup for you. When you set `-1` then you set infinity limits.
@@ -203,7 +211,17 @@ Follow this steps:
- Upload and replace all the files on your server with what's inside the app folder. - Upload and replace all the files on your server with what's inside the app folder.
- Restore your `.env` config file on your server. - Restore your `.env` config file on your server.
## Update from 1.7.x to 1.7.7 & 1.7.8 ## Update from 1.7.8 to 1.7.9
After uploaded new files, log in as admin to the app and go to `your-domain.com/upgrade-database`. This will upgrade your database on the background.
After that, **update path to your project in command below** and add the following **Cron** entry to your server:
```
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
```
That's all.
## Update from 1.7.x to 1.7.8
If you are upgrading app to 1.7.7 from 1.7.x, make sure you have copied new /vendor folder or if you are using terminal or git, run `composer update` command to update your vendors. If you are upgrading app to 1.7.7 from 1.7.x, make sure you have copied new /vendor folder or if you are using terminal or git, run `composer update` command to update your vendors.
## Update from 1.6.x to 1.7 ## Update from 1.6.x to 1.7

View File

@@ -6,6 +6,8 @@ use App\Console\Commands\Deploy;
use App\Console\Commands\SetupDevEnvironment; use App\Console\Commands\SetupDevEnvironment;
use App\Console\Commands\SetupProductionEnvironment; use App\Console\Commands\SetupProductionEnvironment;
use App\Console\Commands\UpgradeApp; use App\Console\Commands\UpgradeApp;
use App\Share;
use Carbon\Carbon;
use Illuminate\Console\Scheduling\Schedule; use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel; use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
@@ -23,13 +25,14 @@ class Kernel extends ConsoleKernel
/** /**
* Define the application's command schedule. * Define the application's command schedule.
* *
* @param \Illuminate\Console\Scheduling\Schedule $schedule * @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void * @return void
*/ */
protected function schedule(Schedule $schedule) protected function schedule(Schedule $schedule)
{ {
// $schedule->command('inspire') $schedule->call(function () {
// ->hourly(); $this->delete_expired_shared_links();
})->hourly();
} }
/** /**
@@ -39,8 +42,28 @@ class Kernel extends ConsoleKernel
*/ */
protected function commands() protected function commands()
{ {
$this->load(__DIR__.'/Commands'); $this->load(__DIR__ . '/Commands');
require base_path('routes/console.php'); require base_path('routes/console.php');
} }
/**
* Get and delete expired shared links
*/
protected function delete_expired_shared_links(): void
{
// Get all shares with expiration time
$shares = Share::whereNotNull('expire_in')->get();
$shares->each(function ($share) {
// Get dates
$created_at = Carbon::parse($share->created_at);
// If time was over, then delete share record
if ($created_at->diffInHours(Carbon::now()) >= $share->expire_in) {
$share->delete();
}
});
}
} }

View File

@@ -69,12 +69,12 @@ class BrowseController extends Controller
->pluck('item_id'); ->pluck('item_id');
// Get folders and files // Get folders and files
$folders = FileManagerFolder::with(['parent', 'shared:token,id,item_id,permission,protected']) $folders = FileManagerFolder::with(['parent', 'shared:token,id,item_id,permission,protected,expire_in'])
->where('user_id', $user_id) ->where('user_id', $user_id)
->whereIn('unique_id', $folder_ids) ->whereIn('unique_id', $folder_ids)
->get(); ->get();
$files = FileManagerFile::with(['parent', 'shared:token,id,item_id,permission,protected']) $files = FileManagerFile::with(['parent', 'shared:token,id,item_id,permission,protected,expire_in'])
->where('user_id', $user_id) ->where('user_id', $user_id)
->whereIn('unique_id', $file_ids) ->whereIn('unique_id', $file_ids)
->get(); ->get();
@@ -145,13 +145,13 @@ class BrowseController extends Controller
} }
// Get folders and files // Get folders and files
$folders = FileManagerFolder::with(['parent', 'shared:token,id,item_id,permission,protected']) $folders = FileManagerFolder::with(['parent', 'shared:token,id,item_id,permission,protected,expire_in'])
->where('user_id', $user_id) ->where('user_id', $user_id)
->where('parent_id', $unique_id) ->where('parent_id', $unique_id)
->orderBy('created_at', 'DESC') ->orderBy('created_at', 'DESC')
->get(); ->get();
$files = FileManagerFile::with(['parent', 'shared:token,id,item_id,permission,protected']) $files = FileManagerFile::with(['parent', 'shared:token,id,item_id,permission,protected,expire_in'])
->where('user_id', $user_id) ->where('user_id', $user_id)
->where('folder_id', $unique_id) ->where('folder_id', $unique_id)
->orderBy('created_at', 'DESC') ->orderBy('created_at', 'DESC')
@@ -217,7 +217,7 @@ class BrowseController extends Controller
// Get user id // Get user id
$user_id = Auth::id(); $user_id = Auth::id();
return FileManagerFile::with(['shared:token,id,item_id,permission,protected']) return FileManagerFile::with(['shared:token,id,item_id,permission,protected,expire_in'])
->where('user_id', $user_id) ->where('user_id', $user_id)
->where('unique_id', $unique_id) ->where('unique_id', $unique_id)
->firstOrFail(); ->firstOrFail();

View File

@@ -51,6 +51,7 @@ class ShareController extends Controller
'protected' => $request->isPassword, 'protected' => $request->isPassword,
'permission' => $request->permission, 'permission' => $request->permission,
'item_id' => $request->unique_id, 'item_id' => $request->unique_id,
'expire_in' => $request->expiration,
'user_id' => Auth::id(), 'user_id' => Auth::id(),
'token' => $token, 'token' => $token,
]; ];
@@ -77,6 +78,7 @@ class ShareController extends Controller
$shared->update([ $shared->update([
'permission' => $request->permission, 'permission' => $request->permission,
'protected' => $request->protected, 'protected' => $request->protected,
'expire_in' => $request->expiration,
'password' => $request->password ? Hash::make($request->password) : $shared->password, 'password' => $request->password ? Hash::make($request->password) : $shared->password,
]); ]);

View File

@@ -7,6 +7,7 @@ use App\Page;
use App\Setting; use App\Setting;
use Artisan; use Artisan;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Schema;
class UpgradeAppController extends Controller class UpgradeAppController extends Controller
{ {
@@ -123,4 +124,28 @@ class UpgradeAppController extends Controller
return response('Done', 200); return response('Done', 200);
} }
/**
* Upgrade database
*/
public function upgrade_database()
{
/*
* Upgrade expire_in in shares table
*
* @since v1.7.9
*/
if (! Schema::hasColumn('shares', 'expire_in')) {
$command = Artisan::call('migrate');
if ($command === 0) {
echo 'Operation was successful.';
}
if ($command === 1) {
echo 'Operation failed.';
}
}
}
} }

View File

@@ -28,6 +28,7 @@ class CreateShareRequest extends FormRequest
'isPassword' => 'required|boolean', 'isPassword' => 'required|boolean',
'unique_id' => 'required|integer', 'unique_id' => 'required|integer',
'type' => 'required|string', 'type' => 'required|string',
'expiration' => 'integer|nullable',
'permission' => 'string', 'permission' => 'string',
'password' => 'string', 'password' => 'string',
]; ];

View File

@@ -27,6 +27,7 @@ class UpdateShareRequest extends FormRequest
return [ return [
'protected' => 'required|boolean', 'protected' => 'required|boolean',
'permission' => 'nullable|string', 'permission' => 'nullable|string',
'expiration' => 'integer|nullable',
'password' => 'string', 'password' => 'string',
]; ];
} }

View File

@@ -22,6 +22,7 @@ class ShareResource extends JsonResource
'permission' => $this->permission, 'permission' => $this->permission,
'protected' => (int) $this->protected, 'protected' => (int) $this->protected,
'item_id' => (int) $this->item_id, 'item_id' => (int) $this->item_id,
'expire_in' => (int) $this->expire_in,
'token' => $this->token, 'token' => $this->token,
'link' => $this->link, 'link' => $this->link,
'type' => $this->type, 'type' => $this->type,

View File

@@ -194,7 +194,7 @@ class User extends Authenticatable
*/ */
public function getFolderTreeAttribute() public function getFolderTreeAttribute()
{ {
return FileManagerFolder::with(['folders.shared', 'shared:token,id,item_id,permission,protected']) return FileManagerFolder::with(['folders.shared', 'shared:token,id,item_id,permission,protected,expire_in'])
->where('parent_id', 0) ->where('parent_id', 0)
->where('user_id', $this->id) ->where('user_id', $this->id)
->get(); ->get();
@@ -259,7 +259,7 @@ class User extends Authenticatable
*/ */
public function favourite_folders() public function favourite_folders()
{ {
return $this->belongsToMany(FileManagerFolder::class, 'favourite_folder', 'user_id', 'folder_unique_id', 'id', 'unique_id')->with('shared:token,id,item_id,permission,protected'); return $this->belongsToMany(FileManagerFolder::class, 'favourite_folder', 'user_id', 'folder_unique_id', 'id', 'unique_id')->with('shared:token,id,item_id,permission,protected,expire_in');
} }
/** /**

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddExpirationAtAttributeToSharesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('shares', function (Blueprint $table) {
$table->integer('expire_in')->after('password')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('shares', function (Blueprint $table) {
//
});
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[42],{584:function(e,t,r){"use strict";r.r(t);var n=r(7);function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}var c={name:"SetupWizard",computed:function(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){i(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}({},Object(n.b)(["config"])),mounted:function(){"setup-done"!==this.config.installation&&"quiet-update"!==this.config.installation||this.$router.push({name:"SignIn"})}},u=r(0),a=Object(u.a)(c,(function(){var e=this.$createElement;return(this._self._c||e)("router-view")}),[],!1,null,null,null);t.default=a.exports}}]); (window.webpackJsonp=window.webpackJsonp||[]).push([[42],{556:function(e,t,r){"use strict";r.r(t);var n=r(7);function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}var c={name:"SetupWizard",computed:function(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){i(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}({},Object(n.b)(["config"])),mounted:function(){"setup-done"!==this.config.installation&&"quiet-update"!==this.config.installation||this.$router.push({name:"SignIn"})}},u=r(0),a=Object(u.a)(c,(function(){var e=this.$createElement;return(this._self._c||e)("router-view")}),[],!1,null,null,null);t.default=a.exports}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
public/js/main.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -1,35 +1,25 @@
{ {
"/chunks/files~chunks/shared-files~chunks/shared-page~chunks/trash.js": "/chunks/files~chunks/shared-files~chunks/shared-page~chunks/trash.js",
"/js/main.js": "/js/main.js", "/js/main.js": "/js/main.js",
"/css/app.css": "/css/app.css", "/css/app.css": "/css/app.css",
"/chunks/admin.js": "/chunks/admin.js", "/chunks/admin.js": "/chunks/admin.js",
"/chunks/admin-account.js": "/chunks/admin-account.js", "/chunks/admin-account.js": "/chunks/admin-account.js",
"/chunks/admin-account~chunks/app-appearance~chunks/app-billings~chunks/app-email~chunks/app-index~chu~2d9ff916.js": "/chunks/admin-account~chunks/app-appearance~chunks/app-billings~chunks/app-email~chunks/app-index~chu~2d9ff916.js",
"/chunks/admin-account~chunks/app-setup~chunks/billings-detail~chunks/create-new-password~chunks/datab~01aef58e.js": "/chunks/admin-account~chunks/app-setup~chunks/billings-detail~chunks/create-new-password~chunks/datab~01aef58e.js",
"/chunks/admin~chunks/files~chunks/settings~chunks/shared-files~chunks/trash.js": "/chunks/admin~chunks/files~chunks/settings~chunks/shared-files~chunks/trash.js",
"/chunks/app-appearance.js": "/chunks/app-appearance.js", "/chunks/app-appearance.js": "/chunks/app-appearance.js",
"/chunks/app-appearance~chunks/app-billings~chunks/app-email~chunks/app-index~chunks/app-others~chunks~605f4c49.js": "/chunks/app-appearance~chunks/app-billings~chunks/app-email~chunks/app-index~chunks/app-others~chunks~605f4c49.js",
"/chunks/app-appearance~chunks/app-billings~chunks/app-email~chunks/app-index~chunks/app-others~chunks~8cc7d96f.js": "/chunks/app-appearance~chunks/app-billings~chunks/app-email~chunks/app-index~chunks/app-others~chunks~8cc7d96f.js",
"/chunks/app-appearance~chunks/app-billings~chunks/app-email~chunks/app-index~chunks/app-others~chunks~b9e5655a.js": "/chunks/app-appearance~chunks/app-billings~chunks/app-email~chunks/app-index~chunks/app-others~chunks~b9e5655a.js",
"/chunks/app-billings.js": "/chunks/app-billings.js", "/chunks/app-billings.js": "/chunks/app-billings.js",
"/chunks/app-email.js": "/chunks/app-email.js", "/chunks/app-email.js": "/chunks/app-email.js",
"/chunks/app-index.js": "/chunks/app-index.js", "/chunks/app-index.js": "/chunks/app-index.js",
"/chunks/app-others.js": "/chunks/app-others.js", "/chunks/app-others.js": "/chunks/app-others.js",
"/chunks/app-payments.js": "/chunks/app-payments.js", "/chunks/app-payments.js": "/chunks/app-payments.js",
"/chunks/app-settings.js": "/chunks/app-settings.js", "/chunks/app-settings.js": "/chunks/app-settings.js",
"/chunks/app-settings~chunks/dashboard~chunks/invoices~chunks/page-edit~chunks/pages~chunks/plan~chunk~8a0e1d25.js": "/chunks/app-settings~chunks/dashboard~chunks/invoices~chunks/page-edit~chunks/pages~chunks/plan~chunk~8a0e1d25.js",
"/chunks/app-setup.js": "/chunks/app-setup.js", "/chunks/app-setup.js": "/chunks/app-setup.js",
"/chunks/billings-detail.js": "/chunks/billings-detail.js", "/chunks/billings-detail.js": "/chunks/billings-detail.js",
"/chunks/contact-us.js": "/chunks/contact-us.js", "/chunks/contact-us.js": "/chunks/contact-us.js",
"/chunks/contact-us~chunks/dynamic-page~chunks/landing-page.js": "/chunks/contact-us~chunks/dynamic-page~chunks/landing-page.js",
"/chunks/create-new-password.js": "/chunks/create-new-password.js", "/chunks/create-new-password.js": "/chunks/create-new-password.js",
"/chunks/dashboard.js": "/chunks/dashboard.js", "/chunks/dashboard.js": "/chunks/dashboard.js",
"/chunks/dashboard~chunks/invoices~chunks/pages~chunks/plan-subscribers~chunks/plans~chunks/settings-i~0e2a0654.js": "/chunks/dashboard~chunks/invoices~chunks/pages~chunks/plan-subscribers~chunks/plans~chunks/settings-i~0e2a0654.js",
"/chunks/database.js": "/chunks/database.js", "/chunks/database.js": "/chunks/database.js",
"/chunks/dynamic-page.js": "/chunks/dynamic-page.js", "/chunks/dynamic-page.js": "/chunks/dynamic-page.js",
"/chunks/environment-setup.js": "/chunks/environment-setup.js", "/chunks/environment-setup.js": "/chunks/environment-setup.js",
"/chunks/files.js": "/chunks/files.js", "/chunks/files.js": "/chunks/files.js",
"/chunks/files~chunks/settings-subscription~chunks/shared-files~chunks/shared-page~chunks/trash~chunks~3ea7670b.js": "/chunks/files~chunks/settings-subscription~chunks/shared-files~chunks/shared-page~chunks/trash~chunks~3ea7670b.js",
"/chunks/files~chunks/shared-files~chunks/shared-page~chunks/trash.js": "/chunks/files~chunks/shared-files~chunks/shared-page~chunks/trash.js",
"/chunks/forgotten-password.js": "/chunks/forgotten-password.js", "/chunks/forgotten-password.js": "/chunks/forgotten-password.js",
"/chunks/installation-disclaimer.js": "/chunks/installation-disclaimer.js", "/chunks/installation-disclaimer.js": "/chunks/installation-disclaimer.js",
"/chunks/invoices.js": "/chunks/invoices.js", "/chunks/invoices.js": "/chunks/invoices.js",
@@ -44,7 +34,6 @@
"/chunks/plan-subscribers.js": "/chunks/plan-subscribers.js", "/chunks/plan-subscribers.js": "/chunks/plan-subscribers.js",
"/chunks/plans.js": "/chunks/plans.js", "/chunks/plans.js": "/chunks/plans.js",
"/chunks/profile.js": "/chunks/profile.js", "/chunks/profile.js": "/chunks/profile.js",
"/chunks/profile~chunks/settings-password.js": "/chunks/profile~chunks/settings-password.js",
"/chunks/purchase-code.js": "/chunks/purchase-code.js", "/chunks/purchase-code.js": "/chunks/purchase-code.js",
"/chunks/settings.js": "/chunks/settings.js", "/chunks/settings.js": "/chunks/settings.js",
"/chunks/settings-create-payment-methods.js": "/chunks/settings-create-payment-methods.js", "/chunks/settings-create-payment-methods.js": "/chunks/settings-create-payment-methods.js",
@@ -64,7 +53,6 @@
"/chunks/trash.js": "/chunks/trash.js", "/chunks/trash.js": "/chunks/trash.js",
"/chunks/upgrade.js": "/chunks/upgrade.js", "/chunks/upgrade.js": "/chunks/upgrade.js",
"/chunks/upgrade-billing.js": "/chunks/upgrade-billing.js", "/chunks/upgrade-billing.js": "/chunks/upgrade-billing.js",
"/chunks/upgrade-billing~chunks/upgrade-plan.js": "/chunks/upgrade-billing~chunks/upgrade-plan.js",
"/chunks/upgrade-plan.js": "/chunks/upgrade-plan.js", "/chunks/upgrade-plan.js": "/chunks/upgrade-plan.js",
"/chunks/user.js": "/chunks/user.js", "/chunks/user.js": "/chunks/user.js",
"/chunks/user-create.js": "/chunks/user-create.js", "/chunks/user-create.js": "/chunks/user-create.js",
@@ -74,7 +62,5 @@
"/chunks/user-password.js": "/chunks/user-password.js", "/chunks/user-password.js": "/chunks/user-password.js",
"/chunks/user-storage.js": "/chunks/user-storage.js", "/chunks/user-storage.js": "/chunks/user-storage.js",
"/chunks/user-subscription.js": "/chunks/user-subscription.js", "/chunks/user-subscription.js": "/chunks/user-subscription.js",
"/chunks/users.js": "/chunks/users.js", "/chunks/users.js": "/chunks/users.js"
"/js/main.f24b569f92d899b00643.hot-update.js": "/js/main.f24b569f92d899b00643.hot-update.js",
"/js/main.ea6fa811b950bdc666de.hot-update.js": "/js/main.ea6fa811b950bdc666de.hot-update.js"
} }

View File

@@ -1,6 +1,7 @@
<template> <template>
<div class="action-button"> <div class="action-button">
<FontAwesomeIcon class="icon" :icon="icon" /> <x-icon size="12" class="icon" v-if="icon === 'x'"></x-icon>
<edit-2-icon size="12" class="icon" v-if="icon === 'pencil-alt'"></edit-2-icon>
<span class="label"> <span class="label">
<slot></slot> <slot></slot>
</span> </span>
@@ -8,9 +9,15 @@
</template> </template>
<script> <script>
import { Edit2Icon, XIcon } from 'vue-feather-icons'
export default { export default {
name: 'ActionButton', name: 'ActionButton',
props: ['icon'], props: ['icon'],
components: {
Edit2Icon,
XIcon,
}
} }
</script> </script>
@@ -23,18 +30,17 @@
.label { .label {
@include font-size(12); @include font-size(12);
color: $theme;
font-weight: 600; font-weight: 600;
text-decoration: underline;
} }
.icon { .icon {
@include font-size(10); @include font-size(10);
vertical-align: middle;
display: inline-block; display: inline-block;
margin-right: 2px; margin-right: 2px;
path { path, circle, line {
fill: $theme; stroke: $theme;
} }
} }
} }

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="select-box"> <div class="select-box">
<div class="box-item" <div class="box-item"
:class="{'selected': item.value === value}" :class="{'selected': item.value === input}"
@click="getSelectedValue(item)" @click="getSelectedValue(item)"
v-for="(item, i) in data" :key="i" v-for="(item, i) in data" :key="i"
> >
@@ -13,21 +13,28 @@
<script> <script>
export default { export default {
name: 'SelectBoxInput', name: 'SelectBoxInput',
props: ['data'], props: [
'data',
'value',
],
data() { data() {
return { return {
value: undefined, input: undefined,
} }
}, },
methods: { methods: {
getSelectedValue(item) { getSelectedValue(item) {
if (! this.value || this.value !== item.value) if (! this.input || this.input !== item.value)
this.value = item.value this.input = item.value
else else
this.value = undefined this.input = undefined
this.$emit('input', this.value) this.$emit('input', this.input)
} }
},
created() {
if (this.value)
this.input = this.value
} }
} }
</script> </script>
@@ -41,14 +48,21 @@
.select-box { .select-box {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
flex-wrap: wrap;
flex-direction: row;
margin-bottom: 10px;
.box-item { .box-item {
padding: 12px 14px; margin-bottom: 10px;
padding: 12px 4px;
text-align: center;
background: $light_background; background: $light_background;
border-radius: 8px; border-radius: 8px;
font-weight: 700; font-weight: 700;
border: 2px solid $light_background; border: 2px solid $light_background;
cursor: pointer; cursor: pointer;
flex-direction: column;
flex-basis: 55px;
.box-value { .box-value {
@include font-size(15); @include font-size(15);
@@ -65,6 +79,15 @@
} }
} }
@media only screen and (max-width: 960px) {
.select-box {
.box-item {
flex-basis: calc(34% - 10px);
}
}
}
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {

View File

@@ -33,11 +33,17 @@
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span> <span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider> </ValidationProvider>
<!--Set expiration--> <!--More options-->
<div class="input-wrapper"> <div class="more-options" v-if="isMoreOptions">
<label class="input-label">{{ $t('shared_form.label_expiration') }}:</label>
<SelectBoxInput v-model="shareOptions.expiration" :data="expirationList" class="box"/> <!--Set expiration-->
<div class="input-wrapper">
<label class="input-label">{{ $t('shared_form.label_expiration') }}:</label>
<SelectBoxInput v-model="shareOptions.expiration" :data="expirationList" class="box"/>
</div>
</div> </div>
<ActionButton @click.native="moreOptions" :icon="isMoreOptions ? 'x' : 'pencil-alt'">{{ moreOptionsTitle }}</ActionButton>
</ValidationObserver> </ValidationObserver>
<!--Copy generated link--> <!--Copy generated link-->
@@ -80,6 +86,7 @@
import SwitchInput from '@/components/Others/Forms/SwitchInput' import SwitchInput from '@/components/Others/Forms/SwitchInput'
import SelectInput from '@/components/Others/Forms/SelectInput' import SelectInput from '@/components/Others/Forms/SelectInput'
import ThumbnailItem from '@/components/Others/ThumbnailItem' import ThumbnailItem from '@/components/Others/ThumbnailItem'
import ActionButton from '@/components/Others/ActionButton'
import CopyInput from '@/components/Others/Forms/CopyInput' import CopyInput from '@/components/Others/Forms/CopyInput'
import ButtonBase from '@/components/FilesView/ButtonBase' import ButtonBase from '@/components/FilesView/ButtonBase'
import {required} from 'vee-validate/dist/rules' import {required} from 'vee-validate/dist/rules'
@@ -94,6 +101,7 @@
ValidationObserver, ValidationObserver,
SelectBoxInput, SelectBoxInput,
ThumbnailItem, ThumbnailItem,
ActionButton,
PopupWrapper, PopupWrapper,
PopupActions, PopupActions,
PopupContent, PopupContent,
@@ -105,7 +113,10 @@
required, required,
}, },
computed: { computed: {
...mapGetters(['permissionOptions']), ...mapGetters([
'permissionOptions',
'expirationList',
]),
itemTypeTitle() { itemTypeTitle() {
return this.pickedItem && this.pickedItem.type === 'folder' ? this.$t('types.folder') : this.$t('types.file') return this.pickedItem && this.pickedItem.type === 'folder' ? this.$t('types.folder') : this.$t('types.file')
}, },
@@ -114,40 +125,13 @@
}, },
submitButtonText() { submitButtonText() {
return this.isGeneratedShared ? this.$t('shared_form.button_done') : this.$t('shared_form.button_generate') return this.isGeneratedShared ? this.$t('shared_form.button_done') : this.$t('shared_form.button_generate')
},
moreOptionsTitle() {
return this.isMoreOptions ? this.$t('shared_form.button_close_options') : this.$t('shared_form.button_more_options')
} }
}, },
data() { data() {
return { return {
expirationList: [
{
label: this.$t('shared_form.expiration_hour', {value: 1}),
value: '1',
},
{
label: this.$t('shared_form.expiration_hour', {value: 2}),
value: '2',
},
{
label: this.$t('shared_form.expiration_hour', {value: 6}),
value: '6',
},
{
label: this.$t('shared_form.expiration_hour', {value: 12}),
value: '12',
},
{
label: this.$t('shared_form.expiration_day', {value: 1}),
value: '24',
},
{
label: this.$t('shared_form.expiration_day', {value: 2}),
value: '48',
},
{
label: this.$t('shared_form.expiration_day', {value: 7}),
value: '168',
},
],
shareOptions: { shareOptions: {
isPassword: false, isPassword: false,
expiration: undefined, expiration: undefined,
@@ -160,9 +144,16 @@
shareLink: undefined, shareLink: undefined,
isGeneratedShared: false, isGeneratedShared: false,
isLoading: false, isLoading: false,
isMoreOptions: false,
} }
}, },
methods: { methods: {
moreOptions() {
this.isMoreOptions = ! this.isMoreOptions
if (! this.isMoreOptions)
this.shareOptions.expiration = undefined
},
async submitShareOptions() { async submitShareOptions() {
// If shared was generated, then close popup // If shared was generated, then close popup
@@ -224,10 +215,12 @@
permission: undefined, permission: undefined,
password: undefined, password: undefined,
isPassword: false, isPassword: false,
expiration: undefined,
type: undefined, type: undefined,
unique_id: undefined, unique_id: undefined,
} }
this.isGeneratedShared = false this.isGeneratedShared = false
this.isMoreOptions = false
this.shareLink = undefined this.shareLink = undefined
}, 150) }, 150)
}) })
@@ -239,6 +232,10 @@
@import "@assets/vue-file-manager/_inapp-forms.scss"; @import "@assets/vue-file-manager/_inapp-forms.scss";
@import '@assets/vue-file-manager/_forms'; @import '@assets/vue-file-manager/_forms';
.more-options {
margin-bottom: 10px;
}
.input-wrapper { .input-wrapper {
&.password { &.password {

View File

@@ -31,7 +31,7 @@
<label class="input-label">{{ $t('shared_form.label_password_protection') }}:</label> <label class="input-label">{{ $t('shared_form.label_password_protection') }}:</label>
<SwitchInput v-model="shareOptions.isProtected" :state="shareOptions.isProtected" class="switch"/> <SwitchInput v-model="shareOptions.isProtected" :state="shareOptions.isProtected" class="switch"/>
</div> </div>
<ActionButton v-if="(pickedItem.shared.protected && canChangePassword) && shareOptions.isProtected" @click.native="changePassword" icon="pencil-alt">{{ $t('popup_share_edit.change_pass') }}</ActionButton> <ActionButton v-if="(pickedItem.shared.protected && canChangePassword) && shareOptions.isProtected" @click.native="changePassword" class="change-password">{{ $t('popup_share_edit.change_pass') }}</ActionButton>
</div> </div>
<!--Set password--> <!--Set password-->
@@ -40,6 +40,18 @@
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span> <span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider> </ValidationProvider>
<!--More options-->
<div class="more-options" v-if="isMoreOptions">
<!--Set expiration-->
<div class="input-wrapper">
<label class="input-label">{{ $t('shared_form.label_expiration') }}:</label>
<SelectBoxInput v-model="shareOptions.expiration" :data="expirationList" :value="shareOptions.expiration" class="box"/>
</div>
</div>
<ActionButton @click.native="moreOptions" :icon="isMoreOptions || shareOptions.expiration ? 'x' : 'pencil-alt'">{{ moreOptionsTitle }}</ActionButton>
</ValidationObserver> </ValidationObserver>
</PopupContent> </PopupContent>
@@ -68,6 +80,7 @@
<script> <script>
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full' import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
import SelectBoxInput from '@/components/Others/Forms/SelectBoxInput'
import PopupWrapper from '@/components/Others/Popup/PopupWrapper' import PopupWrapper from '@/components/Others/Popup/PopupWrapper'
import PopupActions from '@/components/Others/Popup/PopupActions' import PopupActions from '@/components/Others/Popup/PopupActions'
import PopupContent from '@/components/Others/Popup/PopupContent' import PopupContent from '@/components/Others/Popup/PopupContent'
@@ -88,6 +101,7 @@
components: { components: {
ValidationProvider, ValidationProvider,
ValidationObserver, ValidationObserver,
SelectBoxInput,
ThumbnailItem, ThumbnailItem,
ActionButton, ActionButton,
PopupWrapper, PopupWrapper,
@@ -101,7 +115,12 @@
required, required,
}, },
computed: { computed: {
...mapGetters(['user', 'permissionOptions', 'currentFolder']), ...mapGetters([
'permissionOptions',
'expirationList',
'currentFolder',
'user',
]),
isFolder() { isFolder() {
return this.pickedItem && this.pickedItem.type === 'folder' return this.pickedItem && this.pickedItem.type === 'folder'
}, },
@@ -114,18 +133,28 @@
isSharedLocation() { isSharedLocation() {
return this.currentFolder && this.currentFolder.location === 'shared' return this.currentFolder && this.currentFolder.location === 'shared'
}, },
moreOptionsTitle() {
return this.isMoreOptions ? this.$t('shared_form.button_close_options') : this.$t('shared_form.button_more_options')
}
}, },
data() { data() {
return { return {
isConfirmedDestroy: false,
canChangePassword: false,
shareOptions: undefined, shareOptions: undefined,
pickedItem: undefined, pickedItem: undefined,
isLoading: false, isMoreOptions: false,
isDeleting: false, isDeleting: false,
canChangePassword: false, isLoading: false,
isConfirmedDestroy: false,
} }
}, },
methods: { methods: {
moreOptions() {
this.isMoreOptions = ! this.isMoreOptions
if (! this.isMoreOptions)
this.shareOptions.expiration = undefined
},
changePassword() { changePassword() {
this.canChangePassword = false this.canChangePassword = false
}, },
@@ -187,22 +216,22 @@
.post('/api/share/' + this.shareOptions.token, { .post('/api/share/' + this.shareOptions.token, {
permission: this.shareOptions.permission, permission: this.shareOptions.permission,
protected: this.shareOptions.isProtected, protected: this.shareOptions.isProtected,
expiration: this.shareOptions.expiration,
password: this.shareOptions.password ? this.shareOptions.password : undefined, password: this.shareOptions.password ? this.shareOptions.password : undefined,
_method: 'patch' _method: 'patch'
}) })
.then(response => { .then(response => {
// End loading
this.isLoading = false
// Update shared data // Update shared data
this.$store.commit('UPDATE_SHARED_ITEM', response.data.data.attributes) this.$store.commit('UPDATE_SHARED_ITEM', response.data.data.attributes)
events.$emit('popup:close') events.$emit('popup:close')
}) })
.catch(error => { .catch(() => {
// todo: catch errors this.$isSomethingWrong()
})
.finally(() => {
// End loading // End loading
this.isLoading = false this.isLoading = false
@@ -222,11 +251,15 @@
// Store shared options // Store shared options
this.shareOptions = { this.shareOptions = {
token: args.item.shared.token, token: args.item.shared.token,
expiration: args.item.shared.expire_in,
isProtected: args.item.shared.protected, isProtected: args.item.shared.protected,
permission: args.item.shared.permission, permission: args.item.shared.permission,
password: undefined, password: undefined,
} }
if (args.item.shared.expire_in)
this.isMoreOptions = true
this.canChangePassword = args.item.shared.protected this.canChangePassword = args.item.shared.protected
}) })
@@ -256,6 +289,11 @@
} }
} }
.change-password {
opacity: 0.7;
text-decoration: underline;
}
.item-thumbnail { .item-thumbnail {
margin-bottom: 20px; margin-bottom: 20px;
} }

View File

@@ -52,7 +52,7 @@ const Helpers = {
} }
Vue.prototype.$getImage = function (source) { Vue.prototype.$getImage = function (source) {
return source ? '/' + source : '' return source ? this.$store.getters.config.host + '/' + source : ''
} }
Vue.prototype.$getCreditCardBrand = function (brand) { Vue.prototype.$getCreditCardBrand = function (brand) {

View File

@@ -626,6 +626,8 @@
"visitor": "仅可以查看或下载文件" "visitor": "仅可以查看或下载文件"
}, },
"shared_form": { "shared_form": {
"button_more_options": "More Options",
"button_close_options": "Close Options",
"button_done": "太好了!", "button_done": "太好了!",
"button_generate": "生成分享链接", "button_generate": "生成分享链接",
"label_password_protection": "密码保护", "label_password_protection": "密码保护",

View File

@@ -626,6 +626,8 @@
"visitor": "Can only view and download" "visitor": "Can only view and download"
}, },
"shared_form": { "shared_form": {
"button_more_options": "More Options",
"button_close_options": "Close Options",
"button_done": "Awesome, Im done!", "button_done": "Awesome, Im done!",
"button_generate": "Generate Link", "button_generate": "Generate Link",
"label_password_protection": "Password Protected", "label_password_protection": "Password Protected",

View File

@@ -626,6 +626,8 @@
"visitor": "Môže len vidieť a sťahovať súbory" "visitor": "Môže len vidieť a sťahovať súbory"
}, },
"shared_form": { "shared_form": {
"button_more_options": "Viac nastavení",
"button_close_options": "Zavrieť viac možností",
"button_done": "Super, som hotový!", "button_done": "Super, som hotový!",
"button_generate": "Vygenerovať link", "button_generate": "Vygenerovať link",
"label_password_protection": "Chrániť heslom", "label_password_protection": "Chrániť heslom",

View File

@@ -263,9 +263,39 @@ const defaultState = {
{label: 'Zambia', value: 'ZM'}, {label: 'Zambia', value: 'ZM'},
{label: 'Zimbabwe', value: 'ZW'} {label: 'Zimbabwe', value: 'ZW'}
], ],
expirationList: [
{
label: i18n.t('shared_form.expiration_hour', {value: 1}),
value: 1,
},
{
label: i18n.t('shared_form.expiration_hour', {value: 2}),
value: 2,
},
{
label: i18n.t('shared_form.expiration_hour', {value: 6}),
value: 6,
},
{
label: i18n.t('shared_form.expiration_hour', {value: 12}),
value: 12,
},
{
label: i18n.t('shared_form.expiration_day', {value: 1}),
value: 24,
},
{
label: i18n.t('shared_form.expiration_day', {value: 2}),
value: 48,
},
{
label: i18n.t('shared_form.expiration_day', {value: 7}),
value: 168,
},
],
} }
const actions = { const actions = {
changePreviewType: ({commit, dispatch, state, getters}) => { changePreviewType: ({commit, state}) => {
// Get preview type // Get preview type
let previewType = state.FilePreviewType == 'grid' ? 'list' : 'grid' let previewType = state.FilePreviewType == 'grid' ? 'list' : 'grid'
@@ -320,6 +350,7 @@ const mutations = {
const getters = { const getters = {
fileInfoVisible: state => state.fileInfoPanelVisible, fileInfoVisible: state => state.fileInfoPanelVisible,
FilePreviewType: state => state.FilePreviewType, FilePreviewType: state => state.FilePreviewType,
expirationList: state => state.expirationList,
homeDirectory: state => state.homeDirectory, homeDirectory: state => state.homeDirectory,
requestedPlan: state => state.requestedPlan, requestedPlan: state => state.requestedPlan,
countries: state => state.countries, countries: state => state.countries,

View File

@@ -17,6 +17,10 @@ const actions = {
.then((response) => { .then((response) => {
resolve(response) resolve(response)
// Redirect user if is logged
if (router.currentRoute.name === 'SignIn')
router.push({ name: 'Files' })
commit('RETRIEVE_USER', response.data) commit('RETRIEVE_USER', response.data)
}).catch((error) => { }).catch((error) => {

View File

@@ -2,7 +2,7 @@
<PageTab :is-loading="isLoading" class="form-fixed-width"> <PageTab :is-loading="isLoading" class="form-fixed-width">
<!--Personal Information--> <!--Personal Information-->
<PageTabGroup> <PageTabGroup v-if="! isLoading">
<div class="form block-form"> <div class="form block-form">
<FormLabel>{{ $t('admin_settings.appearance.section_general') }}</FormLabel> <FormLabel>{{ $t('admin_settings.appearance.section_general') }}</FormLabel>

View File

@@ -52,11 +52,11 @@
} }
.input-label { .input-label {
@include font-size(12); @include font-size(14);
color: $text; color: $text;
font-weight: 700; font-weight: 700;
display: block; display: block;
margin-bottom: 5px; margin-bottom: 8px;
} }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {

View File

@@ -32,10 +32,16 @@ Route::group(['middleware' => ['auth:api', 'auth.shared', 'auth.master', 'scope:
Route::get('/file/{name}', 'FileAccessController@get_file')->name('file'); Route::get('/file/{name}', 'FileAccessController@get_file')->name('file');
}); });
// Get user invoice
Route::group(['middleware' => ['auth:api', 'auth.master', 'scope:master']], function () { Route::group(['middleware' => ['auth:api', 'auth.master', 'scope:master']], function () {
Route::get('/invoice/{customer}/{token}', 'Admin\InvoiceController@show'); Route::get('/invoice/{customer}/{token}', 'Admin\InvoiceController@show');
}); });
// Admin system tools
Route::group(['middleware' => ['auth:api', 'auth.master', 'auth.admin', 'scope:master']], function () {
Route::get('/upgrade-database', 'General\UpgradeAppController@upgrade_database');
});
// Get og site for web crawlers // Get og site for web crawlers
if( Crawler::isCrawler()) { if( Crawler::isCrawler()) {
Route::get('/shared/{token}', 'AppFunctionsController@og_site'); Route::get('/shared/{token}', 'AppFunctionsController@og_site');