Ability to set expiration for shared link

If user is logged in, after visit SignIn page will be redirected to files page
This commit is contained in:
Peter Papp
2020-08-26 08:17:49 +02:00
89 changed files with 463 additions and 100 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)
- [Update Guide](#update-guide)
- [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)
- [Payments](#payments)
- [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.
#### 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
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.
- 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/service/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.
## 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\SetupProductionEnvironment;
use App\Console\Commands\UpgradeApp;
use App\Share;
use Carbon\Carbon;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
@@ -23,13 +25,14 @@ class Kernel extends ConsoleKernel
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
// $schedule->command('inspire')
// ->hourly();
$schedule->call(function () {
$this->delete_expired_shared_links();
})->hourly();
}
/**
@@ -39,8 +42,28 @@ class Kernel extends ConsoleKernel
*/
protected function commands()
{
$this->load(__DIR__.'/Commands');
$this->load(__DIR__ . '/Commands');
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');
// 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)
->whereIn('unique_id', $folder_ids)
->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)
->whereIn('unique_id', $file_ids)
->get();
@@ -145,13 +145,13 @@ class BrowseController extends Controller
}
// 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('parent_id', $unique_id)
->orderBy('created_at', 'DESC')
->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('folder_id', $unique_id)
->orderBy('created_at', 'DESC')
@@ -217,7 +217,7 @@ class BrowseController extends Controller
// Get user 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('unique_id', $unique_id)
->firstOrFail();

View File

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

View File

@@ -7,6 +7,7 @@ use App\Page;
use App\Setting;
use Artisan;
use Illuminate\Http\Request;
use Schema;
class UpgradeAppController extends Controller
{
@@ -123,4 +124,52 @@ class UpgradeAppController extends Controller
return response('Done', 200);
}
/**
* Start maintenance mode
*/
public function up() {
$command = Artisan::call('up');
if ($command === 0) {
echo 'System is in production mode';
}
}
/**
* End maintenance mode
*/
public function down() {
$command = Artisan::call('down');
if ($command === 0) {
echo 'System is in maintenance mode';
}
}
/**
* 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', [
'--force' => true
]);
if ($command === 0) {
echo 'Operation was successful.';
}
if ($command === 1) {
echo 'Operation failed.';
}
}
}
}

View File

@@ -32,7 +32,8 @@ class FileSharingController extends Controller
public function index($token)
{
// Get shared token
$shared = get_shared($token);
$shared = Share::where(\DB::raw('BINARY `token`'), $token)
->first();
if (! $shared) {
return view("index");

View File

@@ -12,6 +12,8 @@ class CheckForMaintenanceMode extends Middleware
* @var array
*/
protected $except = [
//
'/service/upgrade-database',
'/service/down',
'/service/up',
];
}

View File

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

View File

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

View File

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

View File

@@ -194,7 +194,7 @@ class User extends Authenticatable
*/
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('user_id', $this->id)
->get();
@@ -259,7 +259,7 @@ class User extends Authenticatable
*/
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

@@ -2,7 +2,7 @@
return [
'version' => '1.7.8',
'version' => '1.7.9',
// Define size of chunk uploaded by MB. E.g. integer 128 means chunk size will be 128MB.
'chunk_size' => env('CHUNK_SIZE', '128'),

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

View File

@@ -0,0 +1,95 @@
<template>
<div class="select-box">
<div class="box-item"
:class="{'selected': item.value === input}"
@click="getSelectedValue(item)"
v-for="(item, i) in data" :key="i"
>
<span class="box-value">{{ item.label }}</span>
</div>
</div>
</template>
<script>
export default {
name: 'SelectBoxInput',
props: [
'data',
'value',
],
data() {
return {
input: undefined,
}
},
methods: {
getSelectedValue(item) {
if (! this.input || this.input !== item.value)
this.input = item.value
else
this.input = undefined
this.$emit('input', this.input)
}
},
created() {
if (this.value)
this.input = this.value
}
}
</script>
<style lang="scss" scoped>
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
@import "@assets/vue-file-manager/_inapp-forms.scss";
@import "@assets/vue-file-manager/_forms.scss";
.select-box {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
flex-direction: row;
margin-bottom: 10px;
.box-item {
margin-bottom: 10px;
padding: 12px 4px;
text-align: center;
background: $light_background;
border-radius: 8px;
font-weight: 700;
border: 2px solid $light_background;
cursor: pointer;
flex-direction: column;
flex-basis: 55px;
.box-value {
@include font-size(15);
}
&.selected {
background: rgba($theme, .1);
border-color: $theme;
.box-value {
color: $theme;
}
}
}
}
@media only screen and (max-width: 960px) {
.select-box {
.box-item {
flex-basis: calc(34% - 10px);
}
}
}
@media (prefers-color-scheme: dark) {
}
</style>

View File

@@ -32,6 +32,18 @@
<input v-model="shareOptions.password" :class="{'is-error': errors[0]}" type="text" :placeholder="$t('page_sign_in.placeholder_password')">
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</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" class="box"/>
</div>
</div>
<ActionButton @click.native="moreOptions" :icon="isMoreOptions ? 'x' : 'pencil-alt'">{{ moreOptionsTitle }}</ActionButton>
</ValidationObserver>
<!--Copy generated link-->
@@ -66,6 +78,7 @@
<script>
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 PopupActions from '@/components/Others/Popup/PopupActions'
import PopupContent from '@/components/Others/Popup/PopupContent'
@@ -73,6 +86,7 @@
import SwitchInput from '@/components/Others/Forms/SwitchInput'
import SelectInput from '@/components/Others/Forms/SelectInput'
import ThumbnailItem from '@/components/Others/ThumbnailItem'
import ActionButton from '@/components/Others/ActionButton'
import CopyInput from '@/components/Others/Forms/CopyInput'
import ButtonBase from '@/components/FilesView/ButtonBase'
import {required} from 'vee-validate/dist/rules'
@@ -85,7 +99,9 @@
components: {
ValidationProvider,
ValidationObserver,
SelectBoxInput,
ThumbnailItem,
ActionButton,
PopupWrapper,
PopupActions,
PopupContent,
@@ -97,7 +113,10 @@
required,
},
computed: {
...mapGetters(['permissionOptions']),
...mapGetters([
'permissionOptions',
'expirationList',
]),
itemTypeTitle() {
return this.pickedItem && this.pickedItem.type === 'folder' ? this.$t('types.folder') : this.$t('types.file')
},
@@ -106,12 +125,16 @@
},
submitButtonText() {
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() {
return {
shareOptions: {
isPassword: false,
expiration: undefined,
password: undefined,
permission: undefined,
type: undefined,
@@ -121,9 +144,16 @@
shareLink: undefined,
isGeneratedShared: false,
isLoading: false,
isMoreOptions: false,
}
},
methods: {
moreOptions() {
this.isMoreOptions = ! this.isMoreOptions
if (! this.isMoreOptions)
this.shareOptions.expiration = undefined
},
async submitShareOptions() {
// If shared was generated, then close popup
@@ -185,10 +215,12 @@
permission: undefined,
password: undefined,
isPassword: false,
expiration: undefined,
type: undefined,
unique_id: undefined,
}
this.isGeneratedShared = false
this.isMoreOptions = false
this.shareLink = undefined
}, 150)
})
@@ -200,6 +232,10 @@
@import "@assets/vue-file-manager/_inapp-forms.scss";
@import '@assets/vue-file-manager/_forms';
.more-options {
margin-bottom: 10px;
}
.input-wrapper {
&.password {

View File

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

View File

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

View File

@@ -626,11 +626,16 @@
"visitor": "仅可以查看或下载文件"
},
"shared_form": {
"button_more_options": "More Options",
"button_close_options": "Close Options",
"button_done": "太好了!",
"button_generate": "生成分享链接",
"label_password_protection": "密码保护",
"label_permission": "权限",
"label_shared_url": "分享链接",
"label_expiration": "Link Expiration",
"expiration_hour": "{value}h.",
"expiration_day": "{value}d.",
"placeholder_permission": "请设置权限"
},
"sidebar": {

View File

@@ -626,11 +626,16 @@
"visitor": "Can only view and download"
},
"shared_form": {
"button_more_options": "More Options",
"button_close_options": "Close Options",
"button_done": "Awesome, Im done!",
"button_generate": "Generate Link",
"label_password_protection": "Password Protected",
"label_permission": "Permission",
"label_shared_url": "Share url",
"label_expiration": "Link Expiration",
"expiration_hour": "{value}h.",
"expiration_day": "{value}d.",
"placeholder_permission": "Select your permission"
},
"sidebar": {

View File

@@ -626,11 +626,16 @@
"visitor": "Môže len vidieť a sťahovať súbory"
},
"shared_form": {
"button_more_options": "Viac nastavení",
"button_close_options": "Zavrieť viac možností",
"button_done": "Super, som hotový!",
"button_generate": "Vygenerovať link",
"label_password_protection": "Chrániť heslom",
"label_permission": "Oprávnenie",
"label_shared_url": "Zdieľací odkaz",
"label_expiration": "Expirácia Linku",
"expiration_hour": "{value}h.",
"expiration_day": "{value}d.",
"placeholder_permission": "Zvoľte oprávnenia"
},
"sidebar": {

View File

@@ -263,9 +263,39 @@ const defaultState = {
{label: 'Zambia', value: 'ZM'},
{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 = {
changePreviewType: ({commit, dispatch, state, getters}) => {
changePreviewType: ({commit, state}) => {
// Get preview type
let previewType = state.FilePreviewType == 'grid' ? 'list' : 'grid'
@@ -320,6 +350,7 @@ const mutations = {
const getters = {
fileInfoVisible: state => state.fileInfoPanelVisible,
FilePreviewType: state => state.FilePreviewType,
expirationList: state => state.expirationList,
homeDirectory: state => state.homeDirectory,
requestedPlan: state => state.requestedPlan,
countries: state => state.countries,

View File

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

View File

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

View File

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

View File

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