Compare commits

...

107 Commits

Author SHA1 Message Date
Peter Papp
3e6e046dfc folder delete fix 2020-08-19 06:10:07 +02:00
Peter Papp
5f5caae9e7 updated language files, cache clear button loading 2020-08-18 15:12:34 +02:00
Peter Papp
93a7542502 - Moved chunk size option to .env
- Added ability into App Settings to flush application cache
- Renew password page logo fix
- removed put|patch|delete methods from axios and replaced by faking these methods to support incompatible shared hostings where you can't install php extension to support these methods.
- Getting unique_ids fix
2020-08-18 10:21:24 +02:00
Peter Papp
5c2326e492 fixed non-vuefilemanager stripe plans loading 2020-08-17 10:04:47 +02:00
Peter Papp
47faadef51 strip non-asci characters from filename 2020-08-17 08:42:22 +02:00
Peter Papp
aa26501100 - added support for custom local storage path 2020-08-17 07:38:58 +02:00
Peter Papp
d333d53e9c - added eu-central to setup wizard for backblaze regions 2020-08-17 05:55:50 +02:00
Peter Papp
4a9f040c32 - added chunks 2020-08-14 10:22:41 +02:00
Peter Papp
13de58fdbd - relative chunks path 2020-08-14 10:21:57 +02:00
Peter Papp
40111b95c1 - frontend build with included chunks 2020-08-14 10:13:57 +02:00
Peter Papp
f03c6edec1 - code splitting with vue router 2020-08-14 10:02:24 +02:00
Peter Papp
840898ec9a - added region list to setup wizard
- dark mode disabled input fix
- fixed deprecated scopes
- updated screenshots for SaaS version
2020-08-14 08:39:11 +02:00
Peter Papp
a906a98cce frontend build 2020-08-13 10:58:43 +02:00
Peter Papp
962b76dd8b fix email setup 2020-08-13 10:57:29 +02:00
Peter Papp
23bbae8a74 meta description fix 2020-08-11 08:46:03 +02:00
carodej
8e93a92fcc updated readme 2020-08-07 16:33:30 +02:00
carodej
4393fc6f12 clear kernel 2020-08-07 10:57:04 +02:00
carodej
cba38b58c3 removed deprecated commands 2020-08-07 10:55:32 +02:00
carodej
1ff43b3557 added htaccess to redirect domain root to /public folder 2020-08-07 09:38:22 +02:00
carodej
bfc2253f4d set version 2020-08-05 16:54:26 +02:00
carodej
fb790200d4 bug fixes 2020-08-05 16:51:44 +02:00
carodej
fc2c4de50f additional text logo fix 2020-07-31 08:37:21 +02:00
carodej
a947882449 Merge branch 'master' of github.com:MakingCG/vue-filemanager-laravel
* 'master' of github.com:MakingCG/vue-filemanager-laravel:
  Update README.md
2020-07-30 09:01:34 +02:00
carodej
192b843a85 Merge branch 'dev'
* dev:
  v1.7.3 rc.1
  chunk upload and multipart upload beta.2
  chunk upload and multipart upload beta.1
  multipart upload build
  multipart upload
  chunk upload
  chunk upload
2020-07-30 08:58:19 +02:00
carodej
cd0627e8b8 v1.7.3 rc.1 2020-07-30 08:47:05 +02:00
carodej
46256f6332 chunk upload and multipart upload beta.2 2020-07-29 16:33:42 +02:00
Peter Papp
9935db4bb1 Update README.md 2020-07-29 16:33:05 +02:00
carodej
18761eb5b3 chunk upload and multipart upload beta.1 2020-07-29 12:29:30 +02:00
carodej
bf8db1be52 multipart upload build 2020-07-28 17:01:14 +02:00
carodej
9fea65bd52 multipart upload 2020-07-28 16:57:54 +02:00
carodej
fe8e329fea chunk upload 2020-07-27 17:40:16 +02:00
carodej
6ac543128e chunk upload 2020-07-27 17:28:55 +02:00
carodej
3a643da14e Updated readme 2020-07-24 09:07:41 +02:00
carodej
8cbc0d65dc download butten centered 2020-07-22 18:29:04 +02:00
carodej
4ac81f1ceb fixed urls when external storage is used 2020-07-22 18:12:26 +02:00
carodej
032f4f357a set smtp as default in setup wizard 2020-07-22 10:13:04 +02:00
carodej
35e1262676 Added some hints to setup wizard, new validation rules and readme update 2020-07-22 09:28:13 +02:00
carodej
5c86f4dbb3 SignUp button fixed and updated readme 2020-07-21 19:28:47 +02:00
carodej
a32b87334f Merge branch 'master' of github.com:MakingCG/vue-filemanager-laravel
* 'master' of github.com:MakingCG/vue-filemanager-laravel:
  Allow S3 compatible systems
2020-07-21 09:44:42 +02:00
carodej
4858d82ce3 Merge branch 'dev'
* dev: (38 commits)
  v1.7 RC.2
  v1.7 RC.1
  v1.7 beta.8
  README updated
  v1.7 beta.7
  v1.7 beta.6
  v1.7 beta.ť
  v1.7 beta.4
  v1.7 beta.3
  v1.7 beta.2
  v1.7 beta.1
  v1.7 alpha.4
  v1.7 alpha.3 build
  v1.7 alpha.3
  v1.7 alpha.2 build
  v1.7 alpha.2
  alpha v1.7 alpha.1
  bugfixes
  index options added
  translations update
  ...
2020-07-21 09:44:23 +02:00
carodej
6f6115d5cb v1.7 RC.2 2020-07-21 09:27:57 +02:00
carodej
b67297f160 v1.7 RC.1 2020-07-20 16:03:39 +02:00
carodej
6f95fc2565 v1.7 beta.8 2020-07-20 08:54:57 +02:00
carodej
827b34e1dd README updated 2020-07-19 17:27:24 +02:00
carodej
35543e6f06 v1.7 beta.7 2020-07-18 16:25:29 +02:00
carodej
6c96fe2f46 v1.7 beta.6 2020-07-18 09:15:19 +02:00
carodej
9ce64b2d58 v1.7 beta.ť 2020-07-17 08:39:01 +02:00
carodej
caa586ceb4 v1.7 beta.4 2020-07-17 08:34:28 +02:00
carodej
59b6dfb841 v1.7 beta.3 2020-07-16 16:51:27 +02:00
carodej
abe7f0dafd v1.7 beta.2 2020-07-16 11:02:58 +02:00
carodej
eeada5468b v1.7 beta.1 2020-07-16 10:26:41 +02:00
carodej
6b36480097 v1.7 alpha.4 2020-07-15 11:50:32 +02:00
carodej
25d15390ef v1.7 alpha.3 build 2020-07-15 09:40:15 +02:00
carodej
7ff7decbb6 v1.7 alpha.3 2020-07-15 09:36:38 +02:00
carodej
4cbdea4143 v1.7 alpha.2 build 2020-07-15 08:47:08 +02:00
carodej
38da639e26 v1.7 alpha.2 2020-07-15 08:34:52 +02:00
carodej
b1860eac21 alpha v1.7 alpha.1 2020-07-14 17:31:04 +02:00
carodej
c9d300769c bugfixes 2020-07-14 10:34:42 +02:00
carodej
2ae60003d6 index options added 2020-07-13 09:49:25 +02:00
carodej
a74c1c7b6e translations update 2020-07-12 11:02:21 +02:00
carodej
3c3a18cf6b translations update 2020-07-10 17:05:30 +02:00
carodej
5bd6455f7f responsivity update 2020-07-09 16:52:00 +02:00
carodej
5a9f5813c8 dark mode update 2020-07-09 10:56:17 +02:00
carodej
a43f0e6908 landing page 2020-07-08 09:07:11 +02:00
carodej
5a5125967f dashboard include 2020-07-05 09:14:17 +02:00
carodej
e1ebb70035 frontend update 2020-07-03 08:34:10 +02:00
carodej
05bc598405 frontend update 2020-07-02 18:04:10 +02:00
carodej
2764fd6dd5 setup wizard update 2020-07-02 12:31:14 +02:00
carodej
a98625876d Setup wizard update 2020-07-01 11:01:54 +02:00
carodej
aedc98cc8b setup wizard init 2020-06-29 10:09:42 +02:00
carodej
a2dfc627a7 frontend & backend update 2020-06-22 16:46:02 +02:00
carodej
a2cab6198e frontend & backend update 2020-06-19 08:03:29 +02:00
Carlos Ferreira
766368bace Allow S3 compatible systems
By specifying endpoint, one can use S3 compatible systems like Backblaze or Wasabi.
2020-06-12 15:00:22 +02:00
carodej
fee2cef980 fileview xscroller fix 2020-06-09 18:10:27 +02:00
carodej
95bc310def backend update 2020-06-09 18:06:04 +02:00
carodej
0b7bc27a5f Merge branch 'svg-fix' into dev
* svg-fix:
  fix with svg and scrolling
  v1.6.2 released
  v1.6.1
2020-06-05 17:39:00 +02:00
Peter Papp
bc7950b245 Merge pull request #14 from MakingCG/svg-fix
fix with svg and scrolling
2020-06-05 17:29:06 +02:00
carodej
321bac6c9f fix with svg and scrolling 2020-06-05 17:26:41 +02:00
carodej
cffdc3ced9 frontend/backend update 2020-06-05 16:48:11 +02:00
carodej
ca14838212 frontend update 2020-06-03 10:58:44 +02:00
carodej
331ee52ea3 frontend update 2020-06-02 07:13:44 +02:00
carodej
16c3625b0b frontend fix 2020-05-31 19:54:42 +02:00
carodej
6392ce1727 v1.6.2 released 2020-05-31 19:48:22 +02:00
carodej
181f090901 v1.6.1 2020-05-31 10:04:49 +02:00
carodej
61a8849e2d SaaS frontend update 2020-05-29 17:37:23 +02:00
carodej
252b6fd0bf v1.6 released 2020-05-28 13:00:54 +02:00
carodej
a76d1dec3b user management v1.6-alpha.1 2020-05-27 10:22:33 +02:00
carodej
143aca64dc Merge branch 'dev'
* dev:
  v1.5.2
2020-05-22 10:22:23 +02:00
carodej
3dc3f37cf6 v1.5.2 2020-05-22 10:20:55 +02:00
carodej
deff8d8741 Merge branch 'dev'
* dev:
  v1.5.1-beta.2
  v1.5.1-beta.1
2020-05-22 09:59:05 +02:00
carodej
beae4277ca v1.5.1-beta.2 2020-05-22 09:48:26 +02:00
carodej
be7d1bdc73 v1.5.1-beta.1 2020-05-22 09:40:34 +02:00
carodej
2eaf399441 Merge branch 'dev'
* dev:
  v1.5-beta.3
  v1.5-beta.2
  v1.5-beta.1
  v1.5-alpha.11
  v1.5-alpha.10
  v1.5-alpha.9
  v1.5-alpha.8
  v1.5-alpha.7
  v1.5-alpha.6
  v1.5-alpha.5
  v1.5-alpha.4
  v1.5-alpha.3
  v1.5-alpha.2
  v1.5-alpha.1
2020-05-19 17:52:07 +02:00
carodej
65f902fbcf v1.5-beta.3 2020-05-19 17:49:49 +02:00
carodej
5df0fa93b3 v1.5-beta.2 2020-05-19 11:27:47 +02:00
carodej
67b9416f64 v1.5-beta.1 2020-05-19 09:52:04 +02:00
carodej
8255597fd5 v1.5-alpha.11 2020-05-19 08:29:34 +02:00
carodej
633bef7660 v1.5-alpha.10 2020-05-18 12:37:33 +02:00
carodej
dfe4991177 v1.5-alpha.9 2020-05-18 09:32:34 +02:00
carodej
8daa05f710 v1.5-alpha.8 2020-05-16 17:52:24 +02:00
carodej
62434bcedb v1.5-alpha.7 2020-05-16 17:35:50 +02:00
carodej
6272f62e85 v1.5-alpha.6 2020-05-16 17:22:45 +02:00
carodej
4c8028696f v1.5-alpha.5 2020-05-16 17:12:38 +02:00
carodej
355f6a96ff v1.5-alpha.4 2020-05-16 12:18:37 +02:00
carodej
bdcfc26af7 v1.5-alpha.3 2020-05-16 12:11:17 +02:00
carodej
d2c4f2aa23 v1.5-alpha.2 2020-05-16 12:04:28 +02:00
carodej
41656235fc v1.5-alpha.1 2020-05-15 17:31:25 +02:00
410 changed files with 47555 additions and 6451 deletions

View File

@@ -1,12 +1,14 @@
APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_NAME=VueFileManager
APP_ENV=production
APP_KEY=base64:sB1YuKsbWv7MdWugb9ZsYBqv2QZJ+QOuHZHEddOsUuo=
APP_DEBUG=true
APP_URL=http://localhost
APP_DEMO=false
LOG_CHANNEL=stack
SCOUT_DRIVER=tntsearch
FILESYSTEM_DRIVER=local
FILESYSTEM_DRIVER=
CHUNK_SIZE=128
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
@@ -25,18 +27,18 @@ REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=null
MAIL_FROM_NAME="${APP_NAME}"
MAIL_DRIVER=
MAIL_HOST=
MAIL_PORT=
MAIL_USERNAME=
MAIL_PASSWORD=
MAIL_ENCRYPTION=
MAIL_FROM_ADDRESS="${MAIL_USERNAME}"
MAIL_FROM_NAME="${MAIL_USERNAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_DEFAULT_REGION=
AWS_BUCKET=
DO_SPACES_KEY=
@@ -45,13 +47,26 @@ DO_SPACES_ENDPOINT=
DO_SPACES_REGION=
DO_SPACES_BUCKET=
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1
WASABI_KEY=
WASABI_SECRET=
WASABI_ENDPOINT=
WASABI_REGION=
WASABI_BUCKET=
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
BACKBLAZE_KEY=
BACKBLAZE_SECRET=
BACKBLAZE_ENDPOINT=
BACKBLAZE_REGION=
BACKBLAZE_BUCKET=
PASSPORT_CLIENT_ID=
PASSPORT_CLIENT_SECRET=
APP_DEPLOY_SECRET=
CASHIER_LOGGER=stack
CASHIER_CURRENCY=
STRIPE_KEY=
STRIPE_SECRET=
STRIPE_WEBHOOK_SECRET=
CASHIER_PAYMENT_NOTIFICATION=App\Notifications\ConfirmPayment

4
.gitignore vendored
View File

@@ -3,11 +3,15 @@
/public/storage
/storage/*.key
/storage/*.index
/storage/framework/cache/*
/vendor
/resources/babel.babel
.idea
.env
.env.backup
.phpunit.result.cache
.phpstorm.meta.php
_ide_helper.php
Homestead.json
Homestead.yaml
npm-debug.log

3
.htaccess Normal file
View File

@@ -0,0 +1,3 @@
RewriteEngine on
RewriteCond %{REQUEST_URI} !^public
RewriteRule ^(.*)$ public/$1 [L]

BIN
.rnd

Binary file not shown.

356
README.md
View File

@@ -1,48 +1,358 @@
### Documentation
[Read online documentation](https://vuefilemanager.com/docs/)
![logo](https://vuefilemanager.com/assets/images/vuefilemanager-horizontal-logo.svg)
# Private Cloud Storage Build on Laravel & Vue.js
### Installation setup
## Supporting VueFileManager
Hi, we are trying make the best experience with VueFileManager. There is a lot things to do, and a lot of features we can make.
Run these commands to install vendors:
But, it can't be done without you, development is more and more complicated and we have to hire new colleagues to help with it. There is couple way you can support us, and then, we support you with all great new features which can be. Thanks you for participating on this awesome software!
- [Buy me a Coffe](https://www.buymeacoffee.com/pepe)
- [One-time donation via PayPal](https://www.paypal.me/peterpapp)
- [Become a backer or sponsor on Patreon](https://www.patreon.com/vuefilemanager)
- [Purchase Licence on CodeCanyon](https://codecanyon.net/item/vue-file-manager-with-laravel-backend/25815986)
## Contents
- [Installation](#installation)
- [Server Requirements](#server-requirements)
- [Installation](#installation)
- [PHP Configuration](#php-configuration)
- [Chunk Upload](#chunk-upload)
- [Nginx Configuration](#nginx-configuration)
- [Apache Configuration](#apache-configuration)
- [Recover Failed Installation](#installation-failed)
- [Regular Update](#regular-update)
- [Update from 1.6.x to 1.7 ](#update-from-16x-to-17)
- [Payments](#payments)
- [Get your active plans](#get-your-active-plans)
- [Manage Failed Payments](#manage-failed-payments)
- [Tax Rates](#tax-rates)
- [Developers](#developers)
- [Running development environment on your localhost](#running-development-environment-on-your-localhost)
- [Supported Storages](#supported-storages)
- [How to Create New Language](#how-to-create-new-language)
- [Others](#others)
- [Changelog](#changelog)
- [GitHub Repository](#github-repository)
- [Support](#support)
- [Security Vulnerabilities](#security-vulnerabilities)
# Installation
## Server Requirements
**For running app make sure you have installed:**
- PHP >= 7.2.5 version
- MySQL 5.6+
- Nginx or Apache
**These PHP Extensions are required:**
- GD
- BCMath
- PDO
- SQLite
- Ctype
- Fileinfo
- JSON
- Mbstring
- OpenSSL
- Tokenizer
- XML
- Exif
## Installation
#### 1. Upload files on your server
Copy project files to web root folder of your domain. It's mostly located in `html`, `www` or `public_html` folder name.
#### 2. Configure your web root folder
Configure your web server's document root to point to the public directory of the files you previously uploaded. For example, if you've uploaded the files in `html` folder, your domain root directory should be changed to `html/project_files/public` folder or anything else where domain root is in project `/public` directory.
Please don't try go to `yourdomain.com/public` URL address, you will have issue to verify your purchase code, this is not correct domain root setup, you must do this in your webhosting settings panel.
![Domain Root](https://vuefilemanager.com/assets/images/domain-root.jpg)
#### 3. Check your .env file
Make sure `.env` file was uploaded. This type of file can be hidden in default.
#### 3.1 When you install from GitHub
When you download repository from GitHub, you have to rename your `.env.example` file to `.env`. Then run command below in your terminal to install vendors. Composer is required.
```
composer install
```
#### 4. Set write permissions
Set `755` permission (CHMOD) to these file and folders directory within all children subdirectories:
- /bootstrap/cache
- /storage
- /.env
#### 5. Open your application in your web browser
Then open your application in web browser. If everything works fine, you will be redirect to setup wizard installation process.
At first step you have to verify your purchase code. **Subscription service with stripe payments is available only for Extended License.** If you can't verify your purchase code, check, if you did previously steps correctly.
#### 6. Follow setup wizard steps
That was the hardest part of installation proces. Please follow instructions in every step of Setup Wizard to successfully install VueFileManager.
## 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.
```
npm install
memory_limit = 512M
upload_max_filesize = 128M
post_max_size = 128M
max_file_uploads = 50
max_execution_time = 3600
```
Setup your database in .env and run this command:
## Chunk & Multipart Upload
VueFileManager in default supporting chunk upload. Default chunk upload size is `128MB`. If you wish change this default value, go to `/config/vuefilemanager.php` and change `chunk_size` attribute.
When you use external storage, and upload large files, to prevent failing upload process make sure you have enough space in your application space and set higher `max_execution_time` in your php.ini to move your files to external storage.
## Nginx Configuration
If you running VueFileManager undex Nginx, don't forget set this value in your `nginx.conf` file:
```
php artisan setup:prod
http {
client_max_body_size 1024M;
}
```
It automatically:
* Migrate database
* Generate Application key
* Create Passport Encryption keys
* Create Password grant client
* Create Personal access client
Then, copy generated password grant client `Client ID`, `Client secret` and paste it to .env files here:
And example Nginx config for your domain:
```
PASSPORT_CLIENT_ID=<your_passport_client_id>
PASSPORT_CLIENT_SECRET=<your_passport_client_secret>
server {
listen 80;
listen [::]:80;
# Log files for Debugging
access_log /var/log/nginx/laravel-access.log;
error_log /var/log/nginx/laravel-error.log;
# Webroot Directory for Laravel project
root /var/www/vuefilemanager/public;
index index.php index.html index.htm;
# Your Domain Name
server_name example.com;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# PHP-FPM Configuration Nginx
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php7.3-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
```
For sending forgoten password request via email, fill your mail driver in .env
### Run Application
To start server on your localhost, run this command
## Apache Configuration
Make sure you have enabled mod_rewrite. There is an example config for running VueFileManager under apache:
```
<VirtualHost example.com:80>
DocumentRoot /var/www/vuefilemanager/public
ServerName example.com
<Directory "/var/www/vuefilemanager/public">
AllowOverride All
allow from all
Options +Indexes
Require all granted
</Directory>
RewriteEngine on
RewriteCond %{SERVER_NAME} =example.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
```
## Installation Failed
What to do when installation fail and you can't continue, at first, try to fix issue why installation fail. Probably missing PHP extension or permissions wasn't set correctly.
At worst scenarios, to reset Setup Wizard, delete all tables in your previously created database, delete content of `/storage/framework/cache`. Then replace content in your `.env` file from `.env.example` file.
After these steps, installation will be reseted.
## Regular Update
- `Don't forget create backup of your database and storage before make any changes in your production application.`
- `If you serve your files in local storage driver pay attention and don't delete your /storage folder`
Follow this steps:
- Make a backup of the .env config file located on your server.
- 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 VueFileManager from 1.6.x to 1.7
`Don't forget create backup of your database and storage before make any changes in your production application.`
For those, who purchase extended licence, place these lines at the end of your `/.env` file:
```
CASHIER_LOGGER=stack
CASHIER_CURRENCY=
STRIPE_KEY=
STRIPE_SECRET=
STRIPE_WEBHOOK_SECRET=
CASHIER_PAYMENT_NOTIFICATION=App\Notifications\ConfirmPayment
```
Then follow this steps:
- Make sure you have PHP >= 7.2.5 version
- Make a backup of the .env config file located on your server.
- Upload and replace all the files on your server with what's inside the app folder.
- Restore your `.env` config file on your server.
- Go to https://your-domain.com/upgrade and follow the setup wizard instructions.
# Payments
VueFileManager is packed with **Stripe** payment options. To configure Stripe, you will be asked in Setup Wizard to set up. Or, if you skip this installation process, you will find stripe set up in you admin `Dashboard / Settings / Payments`.
## Get your active plans
Would you like to get your subscription plans for your custom front-end page? Create GET request and get all your active plans:
```
GET /api/public/pricing
```
## Manage Failed Payments
VueFileManager manage failed payments with additional email notification. But, there is more you can do for better User Experience. There is some additionals option in Stripe, look on [prevent failed payments](https://dashboard.stripe.com/settings/billing/automatic).
## Tax Rates
You are able to manage tax rates. When adding a new tax rate, if no Region is specified, the tax rate will apply to everyone. Add a [ISO 3166-1 alpha-2 country code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements) to the Region field if you wish to apply taxes per country.
Just log in to your stripe dashboard, and you will find taxes under `Dashboard / Products / Tax Rates`.
# Developers
## Running development environment on your localhost
When you download repository from GitHub, you have to rename your `.env.example` file to `.env`. Then run command below in your terminal to install vendors. Composer is required.
```
composer install
```
Set your `APP_ENV` to local mode, in default, it's in production mode.
```
APP_ENV=local
```
Also, to debug application, set `APP_DEBUG` on true:
```
APP_DEBUG=true
```
To start server on your localhost, run command below. Then go to your generated localhost URL by terminal, and follow Setup Wizard steps to configure VueFileManager.
```
php artisan serve
```
To compiles and hot-reloads for development, run this command
To develop your Vue front-end, you have to install npm modules by this command:
```
npm install
```
To compiles and hot-reloads for front-end development. Then run this command:
```
npm run hot
```
To compiles for production, run this command
To compiles for production build, run this command
```
npm run prod
```
That's all, happy coding! :tada: :tada: :tada:
## Supported Storages
VueFileManager support these storages for your files:
- [Amazon Web Services S3](https://aws.amazon.com/s3/)
- [Digital Ocean Spaces](https://www.digitalocean.com/products/spaces/)
- [Object Cloud Storage by Wasabi](https://wasabi.com/)
- [Backblaze B2 Cloud Storage](https://www.backblaze.com/b2/cloud-storage.html)
- Your local disk
In case of installation process, you will be able to set storage driver and credentials. After this, you can change your credentials later in `/.env` file.
To set or change your storage driver, you have to edit `FILESYSTEM_DRIVER` in your `/.env` file. Supported drivers are `s3`, `spaces`, `wasabi`,`backblaze` or `local`:
```
FILESYSTEM_DRIVER=local
```
Then you can find corresponding credentials options for your storage driver like key, secret, region in `/.env` file.
## How to Create New Language
VueFileManager front-end support i18n standard for localization. This mean, you can translate app to any language
### How to create translation for Vue Front-End
Go to `/resources/js/i18n/lang` And make copy of `en.json` and rename it to your local name (eg: Slovak language has 'sk' shortcut, it means `sk.json`). If you have created your copy, then feel free to translate this file.
Open `/resources/js/i18n/index.js` import your new language and assign it to languages object:
```
import Vue from 'vue';
import VueI18n from 'vue-i18n';
import en from './lang/en.json'
import sk from './lang/sk.json'
Vue.use(VueI18n);
const i18n = new VueI18n({
locale: config.locale,
messages: Object.assign({
en,
sk
}),
});
export default i18n;
```
After this, you have to compile language to your application code via this command in your terminal:
```
npm run prod
```
### How to Create Translation for Laravel Back-End
Go to `/resources/lang/` And make copy of `en` folder and rename it to your local name (eg: Slovak language has 'sk' shortcut, it means `sk`). If you have created your copy, then feel free to translate this file.
### Set locale
To set your locale in app, go to `/config/app.php` and set your locale string in `locale` option:
```
'locale' => 'YOUR_LOCALE',
```
**Small hint:** We use for translating localizations this awesome software, [check it](https://www.codeandweb.com/babeledit).
# Others
## Changelog
Refer to the [Changelog](https://vuefilemanager.com/changelog) for a full history of the project.
## GitHub Repository
[Join our GitHub repository](https://vuefilemanager.com/github-access) to submit your issues or suggestions, track VueFileManager progress and get new updates as fast as possible.
## Support
The following support channels are available at your fingertips:
- [CodeCanyon support message](https://codecanyon.net/item/vue-file-manager-with-laravel-backend/25815986/support)
- [GitHub repository](https://vuefilemanager.com/github-access)
## Security Vulnerabilities
If you discover a security vulnerability within this project, please send an e-mail to [peterpapp@makingcg.com](peterpapp@makingcg.com). All security vulnerabilities will be promptly addressed.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,66 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
class Deploy extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'deploy:production';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Automatic deployment for production';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
// Start deployment
$this->info('Running auto deployment');
$this->call('down');
// Exec commands
exec('git pull origin ' . config('app.deploy_branch'));
//exec('composer update --no-interaction --prefer-dist');
$this->migrateDatabase();
// Stop deployment
$this->call('up');
$this->info('Everything is done, congratulations! 🥳🥳🥳');
Log::info('Application was updated!');
}
/**
* Migrate database
*/
public function migrateDatabase()
{
$this->call('migrate', [
'--force' => true,
]);
}
}

View File

@@ -1,117 +0,0 @@
<?php
namespace App\Console\Commands;
use App\User;
use Illuminate\Console\Command;
class SetupDevEnvironment extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'setup:dev';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Setting production environment';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$this->info('Setting up production environment');
$this->migrateDatabase();
$this->generateKey();
$this->createPassportKeys();
$this->createPassportClientPassword();
$this->createPassportClientPersonal();
$this->createDefaultUser();
$this->info('Everything is done, congratulations! 🥳🥳🥳');
}
/**
* Migrate database
*/
public function generateKey()
{
$this->call('key:generate');
}
/**
* Migrate database
*/
public function migrateDatabase()
{
$this->call('migrate:fresh');
}
/**
* Create Passport Encryption keys
*/
public function createPassportKeys()
{
$this->call('passport:keys', [
'--force' => true
]);
}
/**
* Create Password grant client
*/
public function createPassportClientPassword()
{
$this->call('passport:client', [
'--password' => true,
'--name' => 'vuefilemanager',
]);
$this->alert('Please copy these first password grant Client ID & Client secret above to your /.env file.');
}
/**
* Create Personal access client
*/
public function createPassportClientPersonal()
{
$this->call('passport:client', [
'--personal' => true,
'--name' => 'shared',
]);
}
/**
* Create Default User
*/
public function createDefaultUser()
{
$user = User::create([
'name' => 'Jane Doe',
'email' => 'howdy@hi5ve.digital',
'password' => \Hash::make('secret'),
]);
$this->info('Test user created. Email: ' . $user->email . ' Password: secret');
}
}

View File

@@ -1,101 +0,0 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class SetupProductionEnvironment extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'setup:prod';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Setting production environment';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$this->info('Setting up production environment');
$this->migrateDatabase();
$this->generateKey();
$this->createPassportKeys();
$this->createPassportClientPassword();
$this->createPassportClientPersonal();
$this->info('Everything is done, congratulations! 🥳🥳🥳');
}
/**
* Migrate database
*/
public function generateKey()
{
$this->call('key:generate');
}
/**
* Migrate database
*/
public function migrateDatabase()
{
$this->call('migrate:fresh');
}
/**
* Create Passport Encryption keys
*/
public function createPassportKeys()
{
$this->call('passport:keys', [
'--force' => true
]);
}
/**
* Create Password grant client
*/
public function createPassportClientPassword()
{
$this->call('passport:client', [
'--password' => true,
'--name' => 'vuefilemanager',
]);
$this->alert('Please copy these first password grant Client ID & Client secret above to your /.env file.');
}
/**
* Create Personal access client
*/
public function createPassportClientPersonal()
{
$this->call('passport:client', [
'--personal' => true,
'--name' => 'shared',
]);
}
}

View File

@@ -2,8 +2,10 @@
namespace App\Console;
use App\Console\Commands\Deploy;
use App\Console\Commands\SetupDevEnvironment;
use App\Console\Commands\SetupProductionEnvironment;
use App\Console\Commands\UpgradeApp;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
@@ -15,8 +17,7 @@ class Kernel extends ConsoleKernel
* @var array
*/
protected $commands = [
SetupProductionEnvironment::class,
SetupDevEnvironment::class,
Deploy::class,
];
/**

View File

@@ -2,8 +2,8 @@
namespace App\Exceptions;
use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Throwable;
class Handler extends ExceptionHandler
{
@@ -29,12 +29,12 @@ class Handler extends ExceptionHandler
/**
* Report or log an exception.
*
* @param \Exception $exception
* @param \Throwable $exception
* @return void
*
* @throws \Exception
*/
public function report(Exception $exception)
public function report(Throwable $exception)
{
parent::report($exception);
}
@@ -43,13 +43,13 @@ class Handler extends ExceptionHandler
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $exception
* @param \Throwable $exception
* @return \Symfony\Component\HttpFoundation\Response
*
* @throws \Exception
* @throws \Throwable
*/
public function render($request, Exception $exception)
public function render($request, Throwable $exception)
{
return parent::render($request, $exception);
}
}
}

View File

@@ -116,14 +116,14 @@ class FileManagerFile extends Model
*/
public function getThumbnailAttribute()
{
// Get thumbnail from s3
if ($this->attributes['thumbnail'] && is_storage_driver(['s3', 'spaces'])) {
// Get thumbnail from external storage
if ($this->attributes['thumbnail'] && is_storage_driver(['s3', 'spaces', 'wasabi', 'backblaze'])) {
return Storage::temporaryUrl('file-manager/' . $this->attributes['thumbnail'], now()->addDay());
return Storage::temporaryUrl('file-manager/' . $this->attributes['thumbnail'], now()->addHour());
}
// Get thumbnail from local storage
if ($this->attributes['thumbnail'] && is_storage_driver('local')) {
if ($this->attributes['thumbnail']) {
// Thumbnail route
$route = route('thumbnail', ['name' => $this->attributes['thumbnail']]);
@@ -145,31 +145,30 @@ class FileManagerFile extends Model
*/
public function getFileUrlAttribute()
{
// Get file from s3
if (is_storage_driver(['s3', 'spaces'])) {
// Get file from external storage
if (is_storage_driver(['s3', 'spaces', 'wasabi', 'backblaze'])) {
$file_pretty_name = get_pretty_name($this->attributes['basename'], $this->attributes['name'], $this->attributes['mimetype']);
$header = [
"ResponseAcceptRanges" => "bytes",
"ResponseContentType" => $this->attributes['mimetype'],
"ResponseContentLength" => $this->attributes['filesize'],
"ResponseContentRange" => "bytes 0-600/" . $this->attributes['filesize'],
'ResponseContentDisposition' => 'attachment; filename=' . $this->attributes['name'] . '.' . $this->attributes['mimetype'],
'ResponseContentDisposition' => 'attachment; filename=' . $file_pretty_name,
];
return Storage::temporaryUrl('file-manager/' . $this->attributes['basename'], now()->addDay(), $header);
}
// Get thumbnail from local storage
if (is_storage_driver('local')) {
$route = route('file', ['name' => $this->attributes['basename']]);
$route = route('file', ['name' => $this->attributes['basename']]);
if ($this->public_access) {
return $route . '/public/' . $this->public_access;
}
return $route;
if ($this->public_access) {
return $route . '/public/' . $this->public_access;
}
return $route;
}
/**

View File

@@ -0,0 +1,66 @@
<?php
namespace App\Http\Controllers\Admin;
use App\FileManagerFile;
use App\Http\Controllers\Controller;
use App\Http\Resources\UsersCollection;
use App\Services\StripeService;
use App\Setting;
use App\User;
use ByteUnits\Metric;
use Illuminate\Http\Request;
use Laravel\Cashier\Subscription;
class DashboardController extends Controller
{
/**
* DashboardController constructor.
*/
public function __construct(StripeService $stripe)
{
$this->stripe = $stripe;
}
/**
* Get data for dashboard
*
* @return array
*/
public function index()
{
// Get total users
$total_users = User::all()->count();
// Get total used space
$total_used_space = FileManagerFile::all()->map(function ($item) {
return (int)$item->getRawOriginal('filesize');
})->sum();
// Get total premium users
$total_premium_users = Subscription::where('stripe_status', 'active')->get()->count();
// Get License
$license = Setting::where('name', 'license')->first();
return [
'license' => $license ? $license->value : null,
'app_version' => config('vuefilemanager.version'),
'total_users' => $total_users,
'total_used_space' => Metric::bytes($total_used_space)->format(),
'total_premium_users' => $total_premium_users,
];
}
/**
* Get the newest users
*
* @return UsersCollection
*/
public function new_registrations()
{
return new UsersCollection(
User::take(7)->orderByDesc('created_at')->get()
);
}
}

View File

@@ -0,0 +1,52 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Http\Resources\InvoiceAdminCollection;
use App\Http\Resources\InvoiceResource;
use App\Invoice;
use App\Services\StripeService;
use App\Setting;
use Illuminate\Http\Request;
class InvoiceController extends Controller
{
/**
* PlanController constructor.
*/
public function __construct(StripeService $stripe)
{
$this->stripe = $stripe;
}
/**
* Get all invoices
*
* @return InvoiceAdminCollection
*/
public function index()
{
return new InvoiceAdminCollection(
$this->stripe->getInvoices()['data']
);
}
/**
* Get single invoice by $token
*
* @param $customer
* @param $token
* @return InvoiceResource
*/
public function show($customer, $token)
{
$settings = json_decode(Setting::all()->pluck('value', 'name')->toJson());
$invoice = $this->stripe->getUserInvoice($customer, $token);
return view('vuefilemanager.invoice')
->with('settings', $settings)
->with('invoice', $invoice);
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Http\Resources\PageCollection;
use App\Http\Resources\PageResource;
use App\Http\Tools\Demo;
use App\Page;
use Illuminate\Http\Request;
class PagesController extends Controller
{
/**
* Get all pages
*
* @return PageCollection
*/
public function index()
{
return new PageCollection(
Page::all()
);
}
/**
* Get page resource
*
* @param $slug
* @return PageResource
*/
public function show($slug)
{
return new PageResource(
Page::where('slug', $slug)->first()
);
}
/**
* Update page content
*
* @param Request $request
* @param $slug
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
*/
public function update(Request $request, $slug)
{
// Check if is demo
if (env('APP_DEMO')) {
return Demo::response_204();
}
// Get page
$page = Page::where('slug', $slug)->first();
// Update page
$page->update(make_single_input($request));
return response('Done', 204);
}
}

View File

@@ -0,0 +1,159 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Http\Resources\PlanCollection;
use App\Http\Resources\PlanResource;
use App\Http\Resources\UserResource;
use App\Http\Resources\UsersCollection;
use App\Http\Tools\Demo;
use App\Plan;
use App\Services\StripeService;
use App\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Laravel\Cashier\Subscription;
use Rinvex\Subscriptions\Models\PlanFeature;
class PlanController extends Controller
{
/**
* PlanController constructor.
*/
public function __construct(StripeService $stripe)
{
$this->stripe = $stripe;
}
/**
* Get all plans
*
* @return PlanCollection
*/
public function index()
{
// Store or Get plans to cache
if (Cache::has('plans')) {
$plans = Cache::get('plans');
} else {
$plans = Cache::rememberForever('plans', function () {
return $this->stripe->getPlans();
});
}
return new PlanCollection($plans);
}
/**
* Get plan record
*
* @param $id
* @return PlanResource
*/
public function show($id)
{
// Store or Get plan to cache
if (Cache::has('plan-' . $id)) {
$plan = Cache::get('plan-' . $id);
} else {
$plan = Cache::rememberForever('plan-' . $id, function () use ($id) {
return $this->stripe->getPlan($id);
});
}
return new PlanResource($plan);
}
/**
* Create new plan
*
* @param Request $request
* @return PlanResource
*/
public function store(Request $request)
{
// Check if is demo
if (env('APP_DEMO')) {
if (Cache::has('plan-starter-pack')) {
$plan = Cache::get('plan-starter-pack');
} else {
$plan = Cache::rememberForever('plan-starter-pack', function () {
return $this->stripe->getPlan('starter-pack');
});
}
return new PlanResource($plan);
}
$plan = new PlanResource(
$this->stripe->createPlan($request)
);
// Clear cached plans
cache_forget_many(['plans', 'pricing']);
return $plan;
}
/**
* Update plan attribute
*
* @param Request $request
* @param $id
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
// Check if is demo
if (env('APP_DEMO')) {
return Demo::response_204();
}
// Update plan
$this->stripe->updatePlan($request, $id);
// Clear cached plans
cache_forget_many(['plans', 'pricing', 'plan-' . $id]);
return response('Saved!', 204);
}
/**
* Delete plan
*
* @param $id
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
*/
public function delete($id)
{
// Check if is demo
if (env('APP_DEMO')) {
return Demo::response_204();
}
// Delete plan
$this->stripe->deletePlan($id);
// Clear cached plans
cache_forget_many(['plans', 'pricing']);
return response('Done!', 204);
}
/**
* Get subscriptions
*
* @param $id
* @return mixed
*/
public function subscribers($id)
{
$subscribers = Subscription::where('stripe_plan', $id)->pluck('user_id');
return new UsersCollection(
User::findMany($subscribers)
);
}
}

View File

@@ -0,0 +1,274 @@
<?php
namespace App\Http\Controllers\Admin;
use App\FileManagerFile;
use App\FileManagerFolder;
use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\ChangeRoleRequest;
use App\Http\Requests\Admin\ChangeStorageCapacityRequest;
use App\Http\Requests\Admin\CreateUserByAdmin;
use App\Http\Requests\Admin\DeleteUserRequest;
use App\Http\Resources\InvoiceCollection;
use App\Http\Resources\UsersCollection;
use App\Http\Resources\UserResource;
use App\Http\Resources\UserStorageResource;
use App\Http\Resources\UserSubscription;
use App\Http\Tools\Demo;
use App\Services\StripeService;
use App\Share;
use App\User;
use App\UserSettings;
use Illuminate\Contracts\Routing\ResponseFactory;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Str;
use Storage;
class UserController extends Controller
{
public function __construct(StripeService $stripe)
{
$this->stripe = $stripe;
}
/**
* Get user details
*
* @param $id
* @return UserResource
*/
public function details($id)
{
return new UserResource(
User::findOrFail($id)
);
}
/**
* Get user storage details
*
* @param $id
* @return UserStorageResource
*/
public function storage($id)
{
return new UserStorageResource(
User::findOrFail($id)
);
}
/**
* Get user storage details
*
* @return InvoiceCollection
*/
public function invoices($id)
{
$user = User::find($id);
return new InvoiceCollection(
$this->stripe->getUserInvoices($user)
);
}
/**
* Get user subscription details
*
* @param $id
* @return UserSubscription
*/
public function subscription($id)
{
$user = User::find($id);
if (! $user->stripeId()) {
return response('User is not stripe customer', 404);
}
return new UserSubscription(
User::find($id)
);
}
/**
* Get all users
*
* @return UsersCollection
*/
public function users()
{
return new UsersCollection(
User::all()
);
}
/**
* Change user role
*
* @param ChangeRoleRequest $request
* @param $id
* @return UserResource
*/
public function change_role(ChangeRoleRequest $request, $id)
{
$user = User::findOrFail($id);
// Demo preview
if (env('APP_DEMO') && $id == 1) {
return new UserResource($user);
}
// Update user role
$user->role = $request->input('attributes.role');
$user->save();
return new UserResource($user);
}
/**
* Change user storage capacity
*
* @param ChangeStorageCapacityRequest $request
* @param $id
* @return UserStorageResource
*/
public function change_storage_capacity(ChangeStorageCapacityRequest $request, $id)
{
$user = User::findOrFail($id);
$user->settings()->update($request->input('attributes'));
return new UserStorageResource($user);
}
/**
* Send user password reset link
*
* @param $id
* @return ResponseFactory|\Illuminate\Http\Response
*/
public function send_password_reset_email($id)
{
$user = User::findOrFail($id);
// Demo preview
if (env('APP_DEMO')) {
return response('Done!', 204);
}
// Get password token
$token = Password::getRepository()->create($user);
// Send user email
$user->sendPasswordResetNotification($token);
return response('Done!', 204);
}
/**
* Create new user by admin
*
* @param CreateUserByAdmin $request
* @return UserResource
*/
public function create_user(CreateUserByAdmin $request)
{
// Store avatar
if ($request->hasFile('avatar')) {
$avatar = store_avatar($request->file('avatar'), 'avatars');
}
// Create user
$user = User::forceCreate([
'avatar' => $request->hasFile('avatar') ? $avatar : null,
'name' => $request->name,
'role' => $request->role,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
// Create settings
UserSettings::forceCreate([
'user_id' => $user->id,
'storage_capacity' => $request->storage_capacity,
]);
return new UserResource($user);
}
/**
* Delete user with all user data
*
* @param DeleteUserRequest $request
* @param $id
* @return ResponseFactory|\Illuminate\Http\Response
* @throws \Exception
*/
public function delete_user(DeleteUserRequest $request, $id)
{
$user = User::findOrFail($id);
if ($user->subscribed('main')) {
abort(202, 'You can\'t delete this account while user have active subscription.');
}
// Demo preview
if (env('APP_DEMO')) {
return response('Done!', 204);
}
// Check for self deleted account
if ($user->id === Auth::id()) {
abort(406, 'You can\'t delete your account');
}
// Validate user name
if ($user->name !== $request->input('data.name')) abort(403);
$shares = Share::where('user_id', $user->id)->get();
$files = FileManagerFile::withTrashed()
->where('user_id', $user->id)
->get();
$folders = FileManagerFolder::withTrashed()
->where('user_id', $user->id)
->get();
// Remove all files and thumbnails
$files->each(function ($file) {
// Delete file
Storage::delete('/file-manager/' . $file->basename);
// Delete thumbnail if exist
if (!is_null($file->thumbnail)) {
Storage::delete('/file-manager/' . $file->getRawOriginal('thumbnail'));
}
// Delete file permanently
$file->forceDelete();
});
// Remove avatar
if ($user->avatar) {
Storage::delete('/avatars/' . $user->avatar);
}
// Remove folders & shares
$folders->each->forceDelete();
$shares->each->forceDelete();
// Remove favourites
$user->settings->delete();
$user->favourite_folders()->sync([]);
// Delete user
$user->delete();
return response('Done!', 204);
}
}

View File

@@ -2,13 +2,48 @@
namespace App\Http\Controllers;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Auth;
use App\Content;
use App\Http\Requests\PublicPages\SendMessageRequest;
use App\Http\Resources\PageResource;
use App\Http\Tools\Demo;
use App\Mail\SendSupportForm;
use App\Page;
use App\Setting;
use Artisan;
use Doctrine\DBAL\Driver\PDOException;
use Illuminate\Http\Request;
use Response;
use Illuminate\Support\Facades\Mail;
use Schema;
class AppFunctionsController extends Controller
{
/**
* List of allowed settings to get from public request
*
* @var array
*/
private $whitelist = [
'footer_content',
'get_started_description',
'get_started_title',
'pricing_description',
'pricing_title',
'feature_description_3',
'feature_title_3',
'feature_description_2',
'feature_title_2',
'feature_description_1',
'feature_title_1',
'features_description',
'features_title',
'header_description',
'header_title',
'section_get_started',
'section_pricing_content',
'section_feature_boxes',
'section_features',
];
/**
* Show index page
*
@@ -16,6 +51,133 @@ class AppFunctionsController extends Controller
*/
public function index()
{
return view("index");
try {
// Try to connect to database
\DB::getPdo();
// Check settings table
$settings_table = Schema::hasTable('settings');
$users_table = Schema::hasTable('users');
// If settings table don't exist, then run migrations
if ($users_table && !$settings_table) {
Artisan::call('migrate', [
'--force' => true
]);
}
// Get settings
$upgraded = Setting::where('name', 'latest_upgrade')->first();
// Get connection string
if ($upgraded && $upgraded->value !== '1.7') {
$connection = 'quiet-update';
} else if (!$upgraded) {
$connection = 'quiet-update';
} else {
$connection = $this->get_setup_status();
}
// Get all settings
$settings = Setting::all();
// Get legal pages
$legal = Page::whereIn('slug', ['terms-of-service', 'privacy-policy', 'cookie-policy'])
->get(['visibility', 'title', 'slug']);
} catch (PDOException $e) {
$connection = 'setup-database';
$settings = null;
}
return view("index")
->with('settings', $settings ? json_decode($settings->pluck('value', 'name')->toJson()) : null)
->with('legal', isset($legal) ? $legal : null)
->with('installation', $connection);
}
/**
* Check if setup wizard was passed
*
* @return string
*/
private function get_setup_status(): string
{
$setup_success = get_setting('setup_wizard_success');
$connection = boolval($setup_success) ? 'setup-done' : 'setup-disclaimer';
return $connection;
}
/**
* Send contact message from pages
*
* @param SendMessageRequest $request
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
*/
public function contact_form(SendMessageRequest $request)
{
// Get receiver email
$receiver = Setting::where('name', 'contact_email')->first();
// Send message
Mail::to($receiver->value)->send(new SendSupportForm($request->all()));
return response('Done', 200);
}
/**
* Get single page content
*
* @param $slug
* @return PageResource
*/
public function get_page($slug)
{
return new PageResource(
Page::where('slug', $slug)->first()
);
}
/**
* Get selected settings from public route
*
* @param Request $request
* @return mixed
*/
public function get_settings(Request $request)
{
$column = $request->get('column');
if (strpos($column, '|') !== false) {
$columns = collect(explode('|', $column));
$columns->each(function ($column) {
if (!in_array($column, $this->whitelist)) abort(401);
});
return Setting::whereIn('name', $columns)->pluck('value', 'name');
}
if (!in_array($column, $this->whitelist)) abort(401);
return Setting::where('name', $column)->pluck('value', 'name');
}
/**
* Clear application cache
*/
public function flush_cache()
{
// Check if is demo
if (env('APP_DEMO')) {
return Demo::response_204();
}
Artisan::call('cache:clear');
Artisan::call('config:clear');
Artisan::call('config:cache');
}
}

View File

@@ -3,7 +3,9 @@
namespace App\Http\Controllers\Auth;
use App\Http\Requests\Auth\CheckAccountRequest;
use App\Setting;
use App\User;
use App\UserSettings;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
@@ -19,20 +21,21 @@ class AuthController extends Controller
* @param Request $request
* @return mixed
*/
public function check_account(CheckAccountRequest $request) {
public function check_account(CheckAccountRequest $request)
{
// Get User
$user = User::where('email', $request->input('email'))->select(['name', 'avatar'])->first();
// Return user info
if ($user) return [
'name' => $user->name,
'name' => $user->name,
'avatar' => $user->avatar,
];
// Abort with 404, user not found
return abort('404', __('vuefilemanager.user_not_fount'));
}
/**
* Login user
*
@@ -41,17 +44,16 @@ class AuthController extends Controller
*/
public function login(Request $request)
{
$response = Route::dispatch(self::make_request($request));
$response = Route::dispatch(self::make_login_request($request));
if ($response->isSuccessful()) {
$data = json_decode($response->content(), true);
return response('Login Successfull!', 200)->cookie('access_token', $data['access_token'], 43200);
} else {
return $response;
}
return $response;
}
/**
@@ -62,34 +64,41 @@ class AuthController extends Controller
*/
public function register(Request $request)
{
$settings = Setting::whereIn('name', ['storage_default', 'registration'])->pluck('value', 'name');
// Check if account registration is enabled
if (! config('vuefilemanager.registration') ) abort(401);
if (! intval($settings['registration'])) abort(401);
// Validate request
$request->validate([
'name' => ['required', 'string', 'max:255'],
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'password' => ['required', 'string', 'min:6', 'confirmed'],
]);
// Create user
User::create([
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
$response = Route::dispatch(self::make_request($request));
// Create settings
UserSettings::forceCreate([
'user_id' => $user->id,
'storage_capacity' => $settings['storage_default'],
]);
$response = Route::dispatch(self::make_login_request($request));
if ($response->isSuccessful()) {
$data = json_decode($response->content(), true);
return response('Register Successfull!', 200)->cookie('access_token', $data['access_token'], 43200);
} else {
return $response;
}
return $response;
}
/**
@@ -100,7 +109,7 @@ class AuthController extends Controller
public function logout()
{
// Demo preview
if (is_demo( Auth::id())) {
if (is_demo(Auth::id())) {
return response('Logout successfull', 204)
->cookie('access_token', '', -1);
}
@@ -112,18 +121,17 @@ class AuthController extends Controller
$token->delete();
});
return response('Logout successfull', 204)
return response('Logout successful', 204)
->cookie('access_token', '', -1);
}
/**
* Make request for get user token
* Make login request for get access token
*
* @param Request $request
* @param string $provider
* @return Request
*/
private static function make_request($request)
private static function make_login_request($request)
{
$request->request->add([
'grant_type' => 'password',

View File

@@ -0,0 +1,44 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Artisan;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\UnauthorizedException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
class DeployController extends Controller
{
/**
* Get web hook payload and verify request
*
* @param Request $request
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
*/
public function github(Request $request) {
if (($signature = $request->headers->get('X-Hub-Signature')) == null) {
throw new BadRequestHttpException('Header not set');
}
$signature_parts = explode('=', $signature);
if (count($signature_parts) != 2) {
throw new BadRequestHttpException('signature has invalid format');
}
$known_signature = hash_hmac('sha1', $request->getContent(), config('app.deploy_secret'));
if (! hash_equals($known_signature, $signature_parts[1])) {
throw new UnauthorizedException('Could not verify request signature ' . $signature_parts[1]);
}
// Run deploying
Artisan::call('deploy:production');
Log::info('The GitHub webhook was accepted');
return response('The GitHub webhook was accepted', 202);
}
}

View File

@@ -36,6 +36,25 @@ class FileAccessController extends Controller
return Storage::download($path, $basename);
}
/**
* Get system image
*
* @param $basename
* @return mixed
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
*/
public function get_system_image($basename)
{
// Get file path
$path = '/system/' . $basename;
// Check if file exist
if (!Storage::exists($path)) abort(404);
// Return avatar
return Storage::download($path, $basename);
}
/**
* Get file
*
@@ -82,7 +101,7 @@ class FileAccessController extends Controller
$shared = get_shared($token);
// Abort if shared is protected
if ($shared->protected) {
if ((int) $shared->protected) {
abort(403, "Sorry, you don't have permission");
}
@@ -135,7 +154,7 @@ class FileAccessController extends Controller
$shared = get_shared($token);
// Abort if thumbnail is protected
if ($shared->protected) {
if ((int) $shared->protected) {
abort(403, "Sorry, you don't have permission");
}
@@ -178,8 +197,7 @@ class FileAccessController extends Controller
*/
private function download_file($file)
{
// Format pretty filename
$file_pretty_name = $file->name . '.' . $file->mimetype;
$file_pretty_name = get_pretty_name($file->basename, $file->name, $file->mimetype);
// Get file path
$path = '/file-manager/' . $file->basename;
@@ -206,12 +224,12 @@ class FileAccessController extends Controller
private function thumbnail_file($file)
{
// Get file path
$path = '/file-manager/' . $file->getOriginal('thumbnail');
$path = '/file-manager/' . $file->getRawOriginal('thumbnail');
// Check if file exist
if (!Storage::exists($path)) abort(404);
// Return image thumbnail
return Storage::download($path, $file->getOriginal('thumbnail'));
return Storage::download($path, $file->getRawOriginal('thumbnail'));
}
}

View File

@@ -3,6 +3,7 @@
namespace App\Http\Controllers\FileBrowser;
use App\Http\Requests\FileBrowser\SearchRequest;
use App\User;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\Controller;
@@ -27,17 +28,19 @@ class BrowseController extends Controller
// Get folders and files
$folders_trashed = FileManagerFolder::onlyTrashed()
->with(['trashed_folders'])
->with(['trashed_folders', 'parent'])
->where('user_id', $user_id)
->get(['parent_id', 'unique_id', 'name']);
$folders = FileManagerFolder::onlyTrashed()
->with(['parent'])
->where('user_id', $user_id)
->whereIn('unique_id', filter_folders_ids($folders_trashed))
->get();
// Get files trashed
$files_trashed = FileManagerFile::onlyTrashed()
->with(['parent'])
->where('user_id', $user_id)
->whereNotIn('folder_id', array_values(array_unique(recursiveFind($folders_trashed->toArray(), 'unique_id'))))
->get();
@@ -80,6 +83,35 @@ class BrowseController extends Controller
return collect([$folders, $files])->collapse();
}
/**
* Get latest user uploads
*
* @return mixed
*/
public function latest() {
// Get User
$user = User::with(['latest_uploads'])
->where('id', Auth::id())
->first();
return $user->latest_uploads->makeHidden(['user_id', 'basename']);
}
/**
* Get participant uploads
*
* @return mixed
*/
public function participant_uploads() {
// Get User
$uploads = FileManagerFile::with(['parent'])->where('user_id', Auth::id())
->whereUserScope('editor')->orderBy('created_at', 'DESC')->get();
return $uploads;
}
/**
* Get directory with files
*
@@ -97,14 +129,14 @@ class BrowseController extends Controller
// Get folders and files
$folders = FileManagerFolder::onlyTrashed()
->where('user_id', $user_id)
->with('parent')
->where('user_id', $user_id)
->where('parent_id', $unique_id)
->get();
$files = FileManagerFile::onlyTrashed()
->where('user_id', $user_id)
->with('parent')
->where('user_id', $user_id)
->where('folder_id', $unique_id)
->get();
@@ -116,11 +148,13 @@ class BrowseController extends Controller
$folders = FileManagerFolder::with(['parent', 'shared:token,id,item_id,permission,protected'])
->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'])
->where('user_id', $user_id)
->where('folder_id', $unique_id)
->orderBy('created_at', 'DESC')
->get();
// Collect folders and files to single array

View File

@@ -179,7 +179,7 @@ class EditItemsController extends Controller
if ($request->user()->tokenCan('editor')) {
// Prevent force delete for non-master users
if ($request->force_delete) abort('401');
if ($request->input('data.force_delete')) abort('401');
// check if shared_token cookie exist
if (!$request->hasCookie('shared_token')) abort('401');
@@ -188,10 +188,10 @@ class EditItemsController extends Controller
$shared = get_shared($request->cookie('shared_token'));
// Get file|folder item
$item = get_item($request->type, $unique_id, Auth::id());
$item = get_item($request->input('data.type'), $unique_id, Auth::id());
// Check access to requested directory
if ($request->type === 'folder') {
if ($request->input('data.type') === 'folder') {
Guardian::check_item_access($item->unique_id, $shared);
} else {
Guardian::check_item_access($item->folder_id, $shared);
@@ -228,10 +228,10 @@ class EditItemsController extends Controller
if (!is_editor($shared)) abort(403);
// Get file|folder item
$item = get_item($request->type, $unique_id, $shared->user_id);
$item = get_item($request->input('data.type'), $unique_id, $shared->user_id);
// Check access to requested item
if ($request->type === 'folder') {
if ($request->input('data.type') === 'folder') {
Guardian::check_item_access($item->unique_id, $shared);
} else {
Guardian::check_item_access($item->folder_id, $shared);
@@ -245,7 +245,7 @@ class EditItemsController extends Controller
}
/**
* Delete file for authenticated master|editor user
* Upload file for authenticated master|editor user
*
* @param UploadRequest $request
* @return FileManagerFile|Model
@@ -258,11 +258,6 @@ class EditItemsController extends Controller
return Demo::upload($request);
}
// Check if user can upload
if (config('vuefilemanager.limit_storage_by_capacity') && user_storage_percentage() >= 100) {
abort(423, 'You exceed your storage limit!');
}
// Check permission to upload for authenticated editor
if ($request->user()->tokenCan('editor')) {

View File

@@ -39,10 +39,10 @@ class FavouriteController extends Controller
if ($folder->user_id !== $user->id) abort(403);
// Add folder to user favourites
$user->favourites()->syncWithoutDetaching($request->unique_id);
$user->favourite_folders()->syncWithoutDetaching($request->unique_id);
// Return updated favourites
return $user->favourites->makeHidden(['pivot']);
return $user->favourite_folders;
}
/**
@@ -61,9 +61,9 @@ class FavouriteController extends Controller
}
// Remove folder from user favourites
$user->favourites()->detach($unique_id);
$user->favourite_folders()->detach($unique_id);
// Return updated favourites
return $user->favourites->makeHidden(['pivot']);
return $user->favourite_folders;
}
}

View File

@@ -42,7 +42,7 @@ class TrashController extends Controller
Storage::delete('/file-manager/' . $file->basename);
// Delete thumbnail if exist
if ($file->thumbnail) Storage::delete('/file-manager/' . $file->getOriginal('thumbnail'));
if ($file->thumbnail) Storage::delete('/file-manager/' . $file->getRawOriginal('thumbnail'));
// Delete file permanently
$file->forceDelete();

View File

@@ -0,0 +1,48 @@
<?php
namespace App\Http\Controllers\General;
use App\Http\Controllers\Controller;
use App\Http\Resources\PricingCollection;
use App\Services\StripeService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
class PricingController extends Controller
{
/**
* PlanController constructor.
*/
public function __construct(StripeService $stripe)
{
$this->stripe = $stripe;
}
/**
* Get all active plans
*
* @return PricingCollection
*/
public function index()
{
if (Cache::has('pricing')) {
// Get pricing from cache
$pricing = Cache::get('pricing');
} else {
// Store pricing to cache
$pricing = Cache::rememberForever('pricing', function () {
return $this->stripe->getActivePlans();
});
}
// Format pricing to collection
$collection = new PricingCollection($pricing);
// Sort and return pricing
return $collection->sortBy('product.metadata.capacity')
->values()
->all();
}
}

View File

@@ -0,0 +1,578 @@
<?php
namespace App\Http\Controllers\General;
use App\Http\Controllers\Controller;
use App\Http\Requests\SetupWizard\CreateAdminRequest;
use App\Http\Requests\SetupWizard\StoreAppSetupRequest;
use App\Http\Requests\SetupWizard\StoreDatabaseCredentialsRequest;
use App\Http\Requests\SetupWizard\StoreEnvironmentSetupRequest;
use App\Http\Requests\SetupWizard\StoreStripeBillingRequest;
use App\Http\Requests\SetupWizard\StoreStripeCredentialsRequest;
use App\Http\Requests\SetupWizard\StoreStripePlansRequest;
use App\Page;
use App\Services\StripeService;
use App\Setting;
use App\User;
use App\UserSettings;
use Artisan;
use Cartalyst\Stripe\Exception\UnauthorizedException;
use Doctrine\DBAL\Driver\PDOException;
use Illuminate\Contracts\Routing\ResponseFactory;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Str;
use Schema;
use Stripe;
use Symfony\Component\HttpKernel\Exception\HttpException;
class SetupWizardController extends Controller
{
/**
* Inject Stripe Service
*/
public function __construct(StripeService $stripe)
{
$this->stripe = $stripe;
}
/**
* Verify Envato purchase code
*
* @param Request $request
* @return ResponseFactory|\Illuminate\Http\Response|mixed
*/
public function verify_purchase_code(Request $request)
{
// Check setup status
if ($this->get_setup_status()) abort(410, 'Gone');
// Verify purchase code
$response = Http::get('https://verify.vuefilemanager.com/api/verify-code/' . $request->purchaseCode);
if ($response->successful()) {
return $response;
}
return response('Purchase code is invalid.', 400);
}
/**
* Set up database credentials
*
* @param StoreDatabaseCredentialsRequest $request
* @return ResponseFactory|\Illuminate\Http\Response
*/
public function setup_database(StoreDatabaseCredentialsRequest $request)
{
// Check setup status
if ($this->get_setup_status()) abort(410, 'Gone');
try {
// Set temporary database connection
config(['database.connections.test.driver' => $request->connection]);
config(['database.connections.test.host' => $request->host]);
config(['database.connections.test.port' => $request->port]);
config(['database.connections.test.database' => $request->name]);
config(['database.connections.test.username' => $request->username]);
config(['database.connections.test.password' => $request->password]);
// Test connection
\DB::connection('test')->getPdo();
} catch (PDOException $e) {
throw new HttpException(500, $e->getMessage());
}
setEnvironmentValue([
'DB_CONNECTION' => $request->connection,
'DB_HOST' => $request->host,
'DB_PORT' => $request->port,
'DB_DATABASE' => $request->name,
'DB_USERNAME' => $request->username,
'DB_PASSWORD' => $request->password,
]);
// Clear cache
Artisan::call('config:cache');
// Set up application
$this->set_up_application();
// Store setup wizard progress
Setting::create([
'name' => 'setup_wizard_database',
'value' => 1,
]);
return response('Done', 200);
}
/**
* Store and test stripe credentials
*
* @param StoreStripeCredentialsRequest $request
* @return ResponseFactory|\Illuminate\Http\Response
*/
public function store_stripe_credentials(StoreStripeCredentialsRequest $request)
{
// Check setup status
if ($this->get_setup_status()) abort(410, 'Gone');
// Create stripe instance
$stripe = Stripe::make($request->secret, '2020-03-02');
// Try to get stripe account details
try {
$stripe->account()->details();
} catch (UnauthorizedException $e) {
throw new HttpException(401, $e->getMessage());
}
// Get options
$settings = collect([
[
'name' => 'stripe_currency',
'value' => $request->currency,
],
[
'name' => 'payments_configured',
'value' => 1,
],
[
'name' => 'payments_active',
'value' => 1,
],
]);
// Store options
$settings->each(function ($col) {
Setting::updateOrCreate(['name' => $col['name']], $col);
});
// Set stripe credentials to .env
setEnvironmentValue([
'CASHIER_CURRENCY' => $request->currency,
'STRIPE_KEY' => $request->key,
'STRIPE_SECRET' => $request->secret,
'STRIPE_WEBHOOK_SECRET' => $request->webhookSecret,
]);
// Clear cache
Artisan::call('config:cache');
return response('Done', 200);
}
/**
* Store Stripe billings
*
* @param StoreStripeBillingRequest $request
* @return ResponseFactory|\Illuminate\Http\Response
*/
public function store_stripe_billings(StoreStripeBillingRequest $request)
{
// Check setup status
if ($this->get_setup_status()) abort(410, 'Gone');
// Get options
$settings = collect([
[
'name' => 'billing_phone_number',
'value' => $request->billing_phone_number,
],
[
'name' => 'billing_postal_code',
'value' => $request->billing_postal_code,
],
[
'name' => 'billing_vat_number',
'value' => $request->billing_vat_number,
],
[
'name' => 'billing_address',
'value' => $request->billing_address,
],
[
'name' => 'billing_country',
'value' => $request->billing_country,
],
[
'name' => 'billing_state',
'value' => $request->billing_state,
],
[
'name' => 'billing_city',
'value' => $request->billing_city,
],
[
'name' => 'billing_name',
'value' => $request->billing_name,
],
]);
// Store options
$settings->each(function ($col) {
Setting::updateOrCreate(['name' => $col['name']], $col);
});
// Clear cache
Artisan::call('config:cache');
return response('Done', 200);
}
/**
* Create Stripe subscription plan
*
* @param StoreStripePlansRequest $request
*/
public function store_stripe_plans(StoreStripePlansRequest $request)
{
// Check setup status
if ($this->get_setup_status()) abort(410, 'Gone');
foreach ($request->input('plans') as $plan) {
$this->stripe->createPlan($plan);
}
}
/**
* Store environment setup
*
* @param StoreEnvironmentSetupRequest $request
* @return string
*/
public function store_environment_setup(StoreEnvironmentSetupRequest $request)
{
// Check setup status
if ($this->get_setup_status()) abort(410, 'Gone');
$storage_driver = $request->input('storage.driver');
if ($storage_driver === 'local') {
setEnvironmentValue([
'FILESYSTEM_DRIVER' => 'local',
]);
}
if ($storage_driver === 's3') {
setEnvironmentValue([
'FILESYSTEM_DRIVER' => $request->input('storage.driver'),
'AWS_ACCESS_KEY_ID' => $request->input('storage.key'),
'AWS_SECRET_ACCESS_KEY' => $request->input('storage.secret'),
'AWS_DEFAULT_REGION' => $request->input('storage.region'),
'AWS_BUCKET' => $request->input('storage.bucket'),
]);
}
if ($storage_driver === 'spaces') {
setEnvironmentValue([
'FILESYSTEM_DRIVER' => $request->input('storage.driver'),
'DO_SPACES_KEY' => $request->input('storage.key'),
'DO_SPACES_SECRET' => $request->input('storage.secret'),
'DO_SPACES_ENDPOINT' => $request->input('storage.endpoint'),
'DO_SPACES_REGION' => $request->input('storage.region'),
'DO_SPACES_BUCKET' => $request->input('storage.bucket'),
]);
}
if ($storage_driver === 'wasabi') {
setEnvironmentValue([
'FILESYSTEM_DRIVER' => $request->input('storage.driver'),
'WASABI_KEY' => $request->input('storage.key'),
'WASABI_SECRET' => $request->input('storage.secret'),
'WASABI_ENDPOINT' => $request->input('storage.endpoint'),
'WASABI_REGION' => $request->input('storage.region'),
'WASABI_BUCKET' => $request->input('storage.bucket'),
]);
}
if ($storage_driver === 'backblaze') {
setEnvironmentValue([
'FILESYSTEM_DRIVER' => $request->input('storage.driver'),
'BACKBLAZE_KEY' => $request->input('storage.key'),
'BACKBLAZE_SECRET' => $request->input('storage.secret'),
'BACKBLAZE_ENDPOINT' => $request->input('storage.endpoint'),
'BACKBLAZE_REGION' => $request->input('storage.region'),
'BACKBLAZE_BUCKET' => $request->input('storage.bucket'),
]);
}
setEnvironmentValue([
'MAIL_DRIVER' => $request->input('mail.driver'),
'MAIL_HOST' => $request->input('mail.host'),
'MAIL_PORT' => $request->input('mail.port'),
'MAIL_USERNAME' => $request->input('mail.username'),
'MAIL_PASSWORD' => $request->input('mail.password'),
'MAIL_ENCRYPTION' => $request->input('mail.encryption'),
]);
// Clear cache
Artisan::call('config:cache');
return response('Done', 200);
}
/**
* Store app settings
* @param StoreAppSetupRequest $request
* @return ResponseFactory|\Illuminate\Http\Response
*/
public function store_app_settings(StoreAppSetupRequest $request)
{
// Check setup status
if ($this->get_setup_status()) abort(410, 'Gone');
// Store Logo
if ($request->hasFile('logo')) {
$logo = store_system_image($request->file('logo'), 'system');
}
// Store Logo horizontal
if ($request->hasFile('logo_horizontal')) {
$logo_horizontal = store_system_image($request->file('logo_horizontal'), 'system');
}
// Store favicon
if ($request->hasFile('favicon')) {
$favicon = store_system_image($request->file('favicon'), 'system');
}
// Get options
$settings = collect([
[
'name' => 'app_title',
'value' => $request->title,
],
[
'name' => 'app_description',
'value' => $request->description,
],
[
'name' => 'app_logo',
'value' => $request->hasFile('logo') ? $logo : null,
],
[
'name' => 'app_logo_horizontal',
'value' => $request->hasFile('logo_horizontal') ? $logo_horizontal : null,
],
[
'name' => 'app_favicon',
'value' => $request->hasFile('favicon') ? $favicon : null,
],
[
'name' => 'google_analytics',
'value' => $request->googleAnalytics,
],
[
'name' => 'contact_email',
'value' => $request->contactMail,
],
[
'name' => 'registration',
'value' => $request->userRegistration,
],
[
'name' => 'storage_limitation',
'value' => $request->storageLimitation,
],
[
'name' => 'storage_default',
'value' => $request->defaultStorage ? $request->defaultStorage : 5,
],
]);
// Store options
$settings->each(function ($col) {
Setting::updateOrCreate(['name' => $col['name']], $col);
});
setEnvironmentValue([
'APP_NAME' => Str::camel($request->title),
]);
return response('Done', 200);
}
/**
* Create and login admin account
*
* @param Request $request
* @return ResponseFactory|\Illuminate\Http\Response|\Symfony\Component\HttpFoundation\Response
*/
public function create_admin_account(Request $request)
{
// Check setup status
if ($this->get_setup_status()) abort(410, 'Gone');
// Validate request
$request->validate([
'email' => 'required|string|email|unique:users',
'password' => 'required|string|min:6|confirmed',
'name' => 'required|string',
'purchase_code' => 'required|string',
'license' => 'required|string',
'avatar' => 'sometimes|file',
]);
// Store avatar
if ($request->hasFile('avatar')) {
$avatar = store_avatar($request->file('avatar'), 'avatars');
}
// Create user
$user = User::forceCreate([
'avatar' => $request->hasFile('avatar') ? $avatar : null,
'name' => $request->name,
'role' => 'admin',
'email' => $request->email,
'password' => Hash::make($request->password),
]);
// Get default storage capacity
$storage_capacity = Setting::where('name', 'storage_default')->first();
// Create settings
UserSettings::forceCreate([
'user_id' => $user->id,
'storage_capacity' => $storage_capacity->value,
]);
// Store setup wizard progress
Setting::updateOrCreate([
'name' => 'setup_wizard_success',
'value' => 1,
]);
// Store License
Setting::updateOrCreate([
'name' => 'license',
'value' => $request->license,
]);
// Store Purchase Code
Setting::updateOrCreate([
'name' => 'purchase_code',
'value' => $request->purchase_code,
]);
// Create legal pages and index content
if ($request->license === 'Extended') {
$pages = collect(config('content.pages'));
$content = collect(config('content.content'));
$content->each(function ($content) {
Setting::updateOrCreate($content);
});
$pages->each(function ($page) {
Page::updateOrCreate($page);
});
}
// Retrieve access token
$response = Route::dispatch(self::make_login_request($request));
// Send access token to user if request is successful
if ($response->isSuccessful()) {
$data = json_decode($response->content(), true);
return response('Admin was created', 200)->cookie('access_token', $data['access_token'], 43200);
}
return $response;
}
/**
* Migrate database and generate necessary things
*/
private function set_up_application()
{
// Generate app key
Artisan::call('key:generate', [
'--force' => true
]);
// Migrate database
Artisan::call('migrate:fresh', [
'--force' => true
]);
// Create Passport Keys
Artisan::call('passport:keys', [
'--force' => true
]);
// Create Password grant client
Artisan::call('passport:client', [
'--password' => true,
'--name' => 'vuefilemanager',
]);
// Create Personal access client
Artisan::call('passport:client', [
'--personal' => true,
'--name' => 'shared',
]);
// Get generated client
$client = \DB::table('oauth_clients')->where('name', '=', 'vuefilemanager')->first();
// Set passport client to .env
setEnvironmentValue([
'PASSPORT_CLIENT_ID' => $client->id,
'PASSPORT_CLIENT_SECRET' => $client->secret,
]);
}
/**
* Make login request for get access token
*
* @param Request $request
* @return Request
*/
private static function make_login_request($request)
{
$request->request->add([
'grant_type' => 'password',
'client_id' => config('services.passport.client_id'),
'client_secret' => config('services.passport.client_secret'),
'username' => $request->email,
'password' => $request->password,
'scope' => 'master',
]);
return Request::create(url('/oauth/token'), 'POST', $request->all());
}
/**
* Get setup wizard status
*
* @return |null
*/
private function get_setup_status()
{
try {
// Check database connections
DB::getPdo();
// Get setup_wizard status
return Schema::hasTable('settings') ? Setting::where('name', 'setup_wizard_success')->first() : false;
} catch (PDOException $e) {
return false;
}
}
}

View File

@@ -0,0 +1,126 @@
<?php
namespace App\Http\Controllers\General;
use App\Http\Controllers\Controller;
use App\Page;
use App\Setting;
use Artisan;
use Illuminate\Http\Request;
class UpgradeAppController extends Controller
{
/**
* Upgrade account from 1.6 to 1.7
*
* @param Request $request
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
*/
public function upgrade(Request $request)
{
$upgraded = Setting::where('name', 'latest_upgrade')->first();
if ($upgraded && $upgraded->value === '1.7') abort(401);
// Create legal pages and index content
if ($request->license === 'Extended') {
$pages = collect(config('content.pages'));
$content = collect(config('content.content'));
$content->each(function ($content) {
Setting::updateOrCreate($content);
});
$pages->each(function ($page) {
Page::updateOrCreate($page);
});
}
// Store Logo
if ($request->hasFile('logo')) {
$logo = store_system_image($request->file('logo'), 'system');
}
// Store Logo horizontal
if ($request->hasFile('logo_horizontal')) {
$logo_horizontal = store_system_image($request->file('logo_horizontal'), 'system');
}
// Store favicon
if ($request->hasFile('favicon')) {
$favicon = store_system_image($request->file('favicon'), 'system');
}
// Get options
$settings = collect([
[
'name' => 'setup_wizard_database',
'value' => 1,
],
[
'name' => 'setup_wizard_success',
'value' => 1,
],
[
'name' => 'license',
'value' => $request->license,
],
[
'name' => 'purchase_code',
'value' => $request->purchase_code,
],
[
'name' => 'app_title',
'value' => $request->title,
],
[
'name' => 'app_description',
'value' => $request->description,
],
[
'name' => 'app_logo',
'value' => $request->hasFile('logo') ? $logo : null,
],
[
'name' => 'app_logo_horizontal',
'value' => $request->hasFile('logo_horizontal') ? $logo_horizontal : null,
],
[
'name' => 'app_favicon',
'value' => $request->hasFile('favicon') ? $favicon : null,
],
[
'name' => 'google_analytics',
'value' => $request->googleAnalytics,
],
[
'name' => 'contact_email',
'value' => $request->contactMail,
],
[
'name' => 'registration',
'value' => $request->userRegistration,
],
[
'name' => 'storage_limitation',
'value' => $request->storageLimitation,
],
[
'name' => 'storage_default',
'value' => $request->defaultStorage ? $request->defaultStorage : 5,
],
[
'name' => 'latest_upgrade',
'value' => '1.7',
],
]);
// Store options
$settings->each(function ($col) {
Setting::updateOrCreate(['name' => $col['name']], $col);
});
return response('Done', 200);
}
}

View File

@@ -0,0 +1,154 @@
<?php
namespace App\Http\Controllers;
use App\Http\Tools\Demo;
use App\Setting;
use Artisan;
use Stripe;
use Cartalyst\Stripe\Exception\UnauthorizedException;
use Illuminate\Http\Request;
use Symfony\Component\HttpKernel\Exception\HttpException;
class SettingController extends Controller
{
/**
* Get table content
*
* @param Request $request
* @return mixed
*/
public function show(Request $request)
{
$column = $request->get('column');
if (strpos($column, '|') !== false) {
$columns = explode('|', $column);
return Setting::whereIn('name', $columns)->pluck('value', 'name');
}
return Setting::where('name', $column)->pluck('value', 'name');
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function update(Request $request)
{
// Check if is demo
if (env('APP_DEMO')) {
return Demo::response_204();
}
// Store image if exist
if ($request->hasFile($request->name)) {
// Store image
$image_path = store_system_image($request->file($request->name), 'system');
// Find and update image path
Setting::updateOrCreate(['name' => $request->name], [
'value' => $image_path
]);
return response('Done', 204);
}
// Find and update variable
Setting::updateOrCreate(['name' => $request->name], [
'value' => $request->value
]);
return response('Done', 204);
}
/**
* Set new email credentials to .env file
*
* @param Request $request
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
*/
public function set_email(Request $request)
{
// Check if is demo
if (env('APP_DEMO')) {
return Demo::response_204();
}
setEnvironmentValue([
'MAIL_DRIVER' => $request->input('driver'),
'MAIL_HOST' => $request->input('host'),
'MAIL_PORT' => $request->input('port'),
'MAIL_USERNAME' => $request->input('username'),
'MAIL_PASSWORD' => $request->input('password'),
'MAIL_ENCRYPTION' => $request->input('encryption'),
]);
// Clear config cache
Artisan::call('config:clear');
Artisan::call('config:cache');
return response('Done', 204);
}
/**
* Configure stripe additionally
*
* @param Request $request
*/
public function set_stripe(Request $request)
{
// Get stripe status
$is_stripe = get_setting('payments_configured');
// Check setup status
if ($is_stripe) abort(401, 'Gone');
// Create stripe instance
$stripe = Stripe::make($request->secret, '2020-03-02');
// Try to get stripe account details
try {
$stripe->account()->details();
} catch (UnauthorizedException $e) {
throw new HttpException(401, $e->getMessage());
}
// Get options
$settings = collect([
[
'name' => 'stripe_currency',
'value' => $request->currency,
],
[
'name' => 'payments_configured',
'value' => 1,
],
[
'name' => 'payments_active',
'value' => 1,
],
]);
// Store options
$settings->each(function ($col) {
Setting::updateOrCreate(['name' => $col['name']], $col);
});
// Set stripe credentials to .env
setEnvironmentValue([
'CASHIER_CURRENCY' => $request->currency,
'STRIPE_KEY' => $request->key,
'STRIPE_SECRET' => $request->secret,
'STRIPE_WEBHOOK_SECRET' => $request->webhookSecret,
]);
// Clear cache
Artisan::call('config:cache');
}
}

View File

@@ -6,6 +6,8 @@ use App\Http\Controllers\Controller;
use App\Http\Requests\Share\AuthenticateShareRequest;
use App\Http\Resources\ShareResource;
use App\Http\Tools\Guardian;
use App\Setting;
use http\Env\Response;
use Illuminate\Contracts\View\Factory;
use Illuminate\Support\Facades\Cookie;
use Illuminate\Support\Facades\DB;
@@ -17,6 +19,7 @@ use App\FileManagerFolder;
use App\FileManagerFile;
use App\User;
use App\Share;
use Illuminate\Support\Facades\Storage;
class FileSharingController extends Controller
{
@@ -32,7 +35,7 @@ class FileSharingController extends Controller
$shared = Share::where(\DB::raw('BINARY `token`'), $token)
->first();
if (!$shared) {
if (! $shared) {
return view("index");
}
@@ -40,14 +43,59 @@ class FileSharingController extends Controller
Cookie::queue('shared_access_token', '', -1);
// Set cookies
if ($shared->protected) {
if ((int) $shared->protected) {
// Set shared token
Cookie::queue('shared_token', $token, 43200);
}
// Check if shared is image file and then show it
if ($shared->type === 'file' && ! (int) $shared->protected) {
$image = FileManagerFile::where('user_id', $shared->user_id)
->where('type', 'image')
->where('unique_id', $shared->item_id)
->first();
if ($image) {
return $this->show_image($image);
}
}
// Get all settings
$settings = Setting::all();
// Return page index
return view("index");
return view("index")
->with('settings', $settings ? json_decode($settings->pluck('value', 'name')->toJson()) : null);
}
/**
* Get image from storage and show it
*
* @param $file
* @return \Symfony\Component\HttpFoundation\StreamedResponse
*/
private function show_image($file)
{
// Format pretty filename
$file_pretty_name = $file->name . '.' . $file->mimetype;
// Get file path
$path = '/file-manager/' . $file->basename;
// Check if file exist
if (!Storage::exists($path)) abort(404);
$header = [
"Content-Type" => Storage::mimeType($path),
"Content-Length" => Storage::size($path),
"Accept-Ranges" => "bytes",
"Content-Range" => "bytes 0-600/" . Storage::size($path),
];
// Get file
return Storage::response($path, $file_pretty_name, $header);
}
/**
@@ -117,7 +165,7 @@ class FileSharingController extends Controller
$shared = Share::where(DB::raw('BINARY `token`'), $token)->firstOrFail();
// Abort if folder is protected
if ($shared->protected) {
if ((int) $shared->protected) {
abort(403, "Sorry, you don't have permission");
}
@@ -148,7 +196,7 @@ class FileSharingController extends Controller
$shared = Share::where(DB::raw('BINARY `token`'), $token)->firstOrFail();
// Abort if file is protected
if ($shared->protected) {
if ((int) $shared->protected) {
abort(403, "Sorry, you don't have permission");
}
@@ -298,7 +346,7 @@ class FileSharingController extends Controller
$shared = get_shared($token);
// Abort if folder is protected
if ($shared->protected) {
if ((int) $shared->protected) {
abort(403, "Sorry, you don't have permission");
}

View File

@@ -2,6 +2,12 @@
namespace App\Http\Controllers\User;
use App\FileManagerFile;
use App\FileManagerFolder;
use App\Http\Resources\InvoiceCollection;
use App\Http\Resources\StorageDetailResource;
use App\Http\Resources\UserResource;
use App\Http\Resources\UserStorageResource;
use App\Http\Tools\Demo;
use Illuminate\Contracts\Routing\ResponseFactory;
use Illuminate\Support\Facades\Validator;
@@ -17,25 +23,36 @@ class AccountController extends Controller
/**
* Get all user data to frontend
*
* @return array
* @return UserResource
*/
public function user()
{
// Get User
$user = User::with(['favourites', 'latest_uploads'])
->where('id', Auth::id())
->first();
return new UserResource(
Auth::user()
);
}
return [
'user' => $user->only(['name', 'email', 'avatar']),
'favourites' => $user->favourites->makeHidden(['pivot']),
'latest_uploads' => $user->latest_uploads->makeHidden(['user_id', 'basename']),
'storage' => [
'used' => Metric::bytes($user->used_capacity)->format(),
'capacity' => format_gigabytes(config('vuefilemanager.user_storage_capacity')),
'percentage' => get_storage_fill_percentage($user->used_capacity, config('vuefilemanager.user_storage_capacity')),
],
];
/**
* Get storage details
*
* @return UserStorageResource
*/
public function storage()
{
return new UserStorageResource(
Auth::user()
);
}
/**
* Get user invoices
*
* @return InvoiceCollection
*/
public function invoices() {
return new InvoiceCollection(
Auth::user()->invoices()
);
}
/**
@@ -48,9 +65,9 @@ class AccountController extends Controller
{
// Validate request
$validator = Validator::make($request->all(), [
'avatar' => 'file',
'name' => 'string',
'value' => 'string',
'avatar' => 'file',
'name' => 'string',
'value' => 'string',
]);
// Return error
@@ -59,10 +76,12 @@ class AccountController extends Controller
// Get user
$user = Auth::user();
// Check if is demo
if (is_demo($user->id)) {
return Demo::response_204();
}
// Update data
if ($request->hasFile('avatar')) {
// Update avatar
@@ -80,6 +99,29 @@ class AccountController extends Controller
return response('Saved!', 204);
}
/**
* Update user settings relationship
*
* @param Request $request
* @return ResponseFactory|\Illuminate\Http\Response
*/
public function update_user_settings(Request $request)
{
// TODO: validation
// Get user
$user = Auth::user();
// Check if is demo
if (is_demo($user->id)) {
return Demo::response_204();
}
// Update text data
$user->settings->update(make_single_input($request));
return response('Saved!', 204);
}
/**
* Change user password
*

View File

@@ -0,0 +1,172 @@
<?php
namespace App\Http\Controllers\User;
use App\Http\Controllers\Controller;
use App\Http\Requests\Payments\RegisterNewPaymentMethodRequest;
use App\Http\Resources\PaymentCardCollection;
use App\Http\Resources\PaymentCardResource;
use App\Http\Resources\PaymentDefaultCardResource;
use App\Http\Tools\Demo;
use App\Services\StripeService;
use Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Laravel\Cashier\PaymentMethod;
class PaymentMethodsController extends Controller
{
/**
* PaymentMethodsController constructor.
*/
public function __construct(StripeService $stripe)
{
$this->stripe = $stripe;
}
/**
* Get user payment methods grouped by default and others
*
* @return array
*/
public function index()
{
$user = Auth::user();
if (!$user->hasPaymentMethod()) {
return abort(204, 'User don\'t have any payment methods');
}
$slug_payment_methods = 'payment-methods-user-' . $user->id;
$slug_default_payment_method = 'default-payment-methods-user-' . $user->id;
if (Cache::has($slug_payment_methods) && Cache::has($slug_default_payment_method)) {
$defaultPaymentMethod = Cache::get($slug_default_payment_method);
$paymentMethodsMapped = Cache::get($slug_payment_methods);
} else {
// Get default payment method
$defaultPaymentMethod = Cache::rememberForever($slug_default_payment_method, function () use ($user) {
$defaultPaymentMethodObject = $user->defaultPaymentMethod();
return $defaultPaymentMethodObject instanceof PaymentMethod
? $defaultPaymentMethodObject->asStripePaymentMethod()
: $defaultPaymentMethodObject;
});
// filter payment methods without default payment
$paymentMethodsMapped = Cache::rememberForever($slug_payment_methods, function () use ($defaultPaymentMethod, $user) {
$paymentMethods = $user->paymentMethods()->filter(function ($paymentMethod) use ($defaultPaymentMethod) {
return $paymentMethod->id !== $defaultPaymentMethod->id;
});
// Get payment methods
return $paymentMethods->map(function ($paymentMethod) {
return $paymentMethod->asStripePaymentMethod();
})->values()->all();
});
}
if (!$user->card_brand || !$user->stripe_id || is_null($paymentMethodsMapped) && is_null($paymentMethodsMapped)) {
return [
'default' => null,
'others' => [],
];
}
return [
'default' => $defaultPaymentMethod instanceof PaymentMethod
? new PaymentCardResource($defaultPaymentMethod)
: new PaymentDefaultCardResource($defaultPaymentMethod),
'others' => new PaymentCardCollection($paymentMethodsMapped),
];
}
/**
* Update default payment method
*
* @param Request $request
* @param $id
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
*/
public function update($id)
{
$user = Auth::user();
// Check if is demo
if (is_demo($user->id)) {
return Demo::response_204();
}
// Update DefaultPayment Method
$user->updateDefaultPaymentMethod($id);
// Sync default payment method
$user->updateDefaultPaymentMethodFromStripe();
// Clear cached payment methods
cache_forget_many([
'payment-methods-user-' . $user->id,
'default-payment-methods-user-' . $user->id
]);
return response('Done', 204);
}
/**
* Register new payment method for user
*
* @param Request $request
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
*/
public function store(RegisterNewPaymentMethodRequest $request)
{
// Get user
$user = Auth::user();
// Check if is demo
if (is_demo($user->id)) {
return response('Done', 201);
}
// Register new payment method
$this->stripe->registerNewPaymentMethod($request, $user);
return response('Done', 201);
}
/**
* Delete user payment method
*
*/
public function delete($id)
{
$user = Auth::user();
// Check if is demo
if (is_demo($user->id)) {
return Demo::response_204();
}
// Get payment method
$paymentMethod = $user->findPaymentMethod($id);
// Delete payment method
$paymentMethod->delete();
// Sync default payment method
$user->updateDefaultPaymentMethodFromStripe();
// Clear cached payment methods
cache_forget_many([
'payment-methods-user-' . $user->id,
'default-payment-methods-user-' . $user->id
]);
return response('Done!', 204);
}
}

View File

@@ -0,0 +1,154 @@
<?php
namespace App\Http\Controllers\User;
use App\Http\Controllers\Controller;
use App\Http\Requests\Subscription\StoreUpgradeAccountRequest;
use App\Http\Resources\UserSubscription;
use App\Http\Tools\Demo;
use App\Invoice;
use App\Services\StripeService;
use Auth;
use Cartalyst\Stripe\Exception\CardErrorException;
use Illuminate\Contracts\Routing\ResponseFactory;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Laravel\Cashier\Exceptions\IncompletePayment;
use Symfony\Component\HttpKernel\Exception\HttpException;
class SubscriptionController extends Controller
{
private $stripe;
/**
* SubscriptionController constructor.
* @param $payment
*/
public function __construct(StripeService $stripe)
{
$this->stripe = $stripe;
}
/**
* Generate setup intent
*
* @return \Stripe\SetupIntent
*/
public function stripe_setup_intent()
{
$user = Auth::user();
return $this->stripe->getSetupIntent($user);
}
/**
* Get user subscription detail
*
* @return array
*/
public function show()
{
$user = Auth::user();
if (! $user->subscription('main')) {
return abort(204, 'User don\'t have any subscription');
}
$slug_user_subscription = 'subscription-user-' . $user->id;
if (Cache::has($slug_user_subscription)) {
return Cache::get($slug_user_subscription);
}
return Cache::rememberForever($slug_user_subscription, function () {
return new UserSubscription(
Auth::user()
);
});
}
/**
* Upgrade account to subscription
*
* @param StoreUpgradeAccountRequest $request
* @return ResponseFactory|\Illuminate\Http\Response
*/
public function upgrade(StoreUpgradeAccountRequest $request)
{
// Get user
$user = Auth::user();
// Check if is demo
if (is_demo($user->id)) {
return Demo::response_204();
}
// Forget user subscription
Cache::forget('subscription-user-' . $user->id);
// Get requested plan
$plan = $this->stripe->getPlan($request->input('plan.data.id'));
// Set user billing
$user->setBilling($request->input('billing'));
// Update stripe customer billing info
$this->stripe->updateCustomerDetails($user);
// Make subscription
$this->stripe->createOrReplaceSubscription($request, $user);
// Update user storage limit
$user->settings()->update([
'storage_capacity' => $plan['product']['metadata']['capacity']
]);
return response('Done!', 204);
}
/**
* Cancel Subscription
*
* @return ResponseFactory|\Illuminate\Http\Response
*/
public function cancel()
{
$user = Auth::user();
// Check if is demo
if (is_demo($user->id)) {
return Demo::response_204();
}
// Cancel subscription
$user->subscription('main')->cancel();
// Forget user subscription
Cache::forget('subscription-user-' . $user->id);
return response('Done!', 204);
}
/**
* Resume Subscription
*
* @return ResponseFactory|\Illuminate\Http\Response
*/
public function resume()
{
$user = Auth::user();
// Check if is demo
if (is_demo($user->id)) {
return Demo::response_204();
}
// Resume subscription
$user->subscription('main')->resume();
// Forget user subscription
Cache::forget('subscription-user-' . $user->id);
return response('Done!', 204);
}
}

View File

@@ -0,0 +1,68 @@
<?php
namespace App\Http\Controllers;
use App\Services\StripeService;
use App\Setting;
use App\User;
use Illuminate\Http\Request;
use Laravel\Cashier\Http\Controllers\WebhookController as CashierController;
class WebhookController extends CashierController
{
public function __construct(StripeService $stripe)
{
$this->stripe = $stripe;
}
/**
* Handle a cancelled customer from a Stripe subscription.
*
* @param array $payload
* @return \Symfony\Component\HttpFoundation\Response
*/
public function handleCustomerSubscriptionDeleted($payload)
{
if ($user = $this->getUserByStripeId($payload['data']['object']['customer'])) {
$user->subscriptions->filter(function ($subscription) use ($payload) {
return $subscription->stripe_id === $payload['data']['object']['id'];
})->each(function ($subscription) {
$subscription->markAsCancelled();
});
}
// Get user
$user = User::where('stripe_id', $payload['data']['object']['customer'])->firstOrFail();
// Get default storage capacity
$default_storage = Setting::where('name', 'storage_default')->first();
// Update storage capacity
$user->settings()->update(['storage_capacity' => $default_storage->value]);
return $this->successMethod();
}
/**
* Handle Invoice Payment Succeeded
*
* @param $payload
* @return \Symfony\Component\HttpFoundation\Response
*/
public function handleInvoicePaymentSucceeded($payload)
{
// Get user
$user = User::where('stripe_id', $payload['data']['object']['customer'])->firstOrFail();
// Get requested plan
$plan = $this->stripe->getPlan($user->subscription('main')->stripe_plan);
// Update user storage limit
$user->settings()->update([
'storage_capacity' => $plan['product']['metadata']['capacity']
]);
return $this->successMethod();
}
}

View File

@@ -0,0 +1,531 @@
<?php
use App\FileManagerFile;
use App\FileManagerFolder;
use App\Setting;
use App\Share;
use ByteUnits\Metric;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Intervention\Image\ImageManagerStatic as Image;
/**
* Obfuscate email
*
* @param $email
* @return string
*/
function obfuscate_email($email)
{
$em = explode("@", $email);
$name = implode('@', array_slice($em, 0, count($em) - 1));
$len = floor(strlen($name) / 2);
return substr($name, 0, $len) . str_repeat('*', $len) . "@" . end($em);
}
/**
* Get single value from settings table
*
* @param $setting
* @return |null
*/
function get_setting($setting)
{
$row = Setting::where('name', $setting)->first();
return $row ? $row->value : null;
}
/**
* Create paragraph from text
*
* @param $str
* @return mixed|null|string|string[]
*/
function add_paragraphs($str)
{
// Trim whitespace
if (($str = trim($str)) === '') return '';
// Standardize newlines
$str = str_replace(array("\r\n", "\r"), "\n", $str);
// Trim whitespace on each line
$str = preg_replace('~^[ \t]+~m', '', $str);
$str = preg_replace('~[ \t]+$~m', '', $str);
// The following regexes only need to be executed if the string contains html
if ($html_found = (strpos($str, '<') !== FALSE)) {
// Elements that should not be surrounded by p tags
$no_p = '(?:p|div|article|header|aside|hgroup|canvas|output|progress|section|figcaption|audio|video|nav|figure|footer|video|details|main|menu|summary|h[1-6r]|ul|ol|li|blockquote|d[dlt]|pre|t[dhr]|t(?:able|body|foot|head)|c(?:aption|olgroup)|form|s(?:elect|tyle)|a(?:ddress|rea)|ma(?:p|th))';
// Put at least two linebreaks before and after $no_p elements
$str = preg_replace('~^<' . $no_p . '[^>]*+>~im', "\n$0", $str);
$str = preg_replace('~</' . $no_p . '\s*+>$~im', "$0\n", $str);
}
// Do the <p> magic!
$str = '<p>' . trim($str) . '</p>';
$str = preg_replace('~\n{2,}~', "</p>\n\n<p>", $str);
// The following regexes only need to be executed if the string contains html
if ($html_found !== FALSE) {
// Remove p tags around $no_p elements
$str = preg_replace('~<p>(?=</?' . $no_p . '[^>]*+>)~i', '', $str);
$str = preg_replace('~(</?' . $no_p . '[^>]*+>)</p>~i', '$1', $str);
}
// Convert single linebreaks to <br />
$str = preg_replace('~(?<!\n)\n(?!\n)~', "<br>\n", $str);
return $str;
}
/**
* Set environment value
*
* @param $key
* @param $value
* @return bool
*/
function setEnvironmentValue(array $values)
{
$envFile = app()->environmentFilePath();
$str = file_get_contents($envFile);
if (count($values) > 0) {
foreach ($values as $envKey => $envValue) {
$str .= "\n"; // In case the searched variable is in the last line without \n
$keyPosition = strpos($str, "{$envKey}=");
$endOfLinePosition = strpos($str, "\n", $keyPosition);
$oldLine = substr($str, $keyPosition, $endOfLinePosition - $keyPosition);
// If key does not exist, add it
$str = str_replace($oldLine, "{$envKey}={$envValue}", $str);
}
}
$str = substr($str, 0, -1);
if (!file_put_contents($envFile, $str)) return false;
return true;
}
/**
* Get invoice number
*
* @return string
*/
function get_invoice_number()
{
$invoices = \App\Invoice::all();
if ($invoices->isEmpty()) {
return Carbon::now()->year . '001';
} else {
return (int)$invoices->last()->order + 1;
}
}
/**
* Forget many cache keys at once
* @param $cache
*/
function cache_forget_many($cache)
{
foreach ($cache as $item) {
\Illuminate\Support\Facades\Cache::forget($item);
}
}
/**
* Get app version from config
*
* @return \Illuminate\Config\Repository|mixed
*/
function get_storage()
{
return env('FILESYSTEM_DRIVER');
}
/**
* Check if is running AWS s3 as storage
*
* @return bool
*/
function is_storage_driver($driver)
{
if (is_array($driver)) {
return in_array(config('filesystems.default'), $driver);
}
return config('filesystems.default') === $driver;
}
/**
* Get app version from config
*
* @return \Illuminate\Config\Repository|mixed
*/
function get_version()
{
return config('vuefilemanager.version');
}
/**
* Check if is demo
*
* @return mixed
*/
function is_demo($user_id)
{
return env('APP_DEMO', false) && $user_id === 1;
}
/**
* Get folder or file item
*
* @param $type
* @param $unique_id
* @param $user_id
* @return \Illuminate\Database\Eloquent\Builder|Model
*/
function get_item($type, $unique_id, $user_id)
{
if ($type === 'folder') {
// Return folder item
return FileManagerFolder::where('unique_id', $unique_id)
->where('user_id', $user_id)
->firstOrFail();
}
// Return file item
return FileManagerFile::where('unique_id', $unique_id)
->where('user_id', $user_id)
->firstOrFail();
}
/**
* Get shared token
*
* @param $token
* @return \Illuminate\Database\Eloquent\Builder|Model
*/
function get_shared($token)
{
return Share::where(DB::raw('BINARY `token`'), $token)
->firstOrFail();
}
/**
* Check if shared permission is editor
*
* @param $shared
* @return bool
*/
function is_editor($shared)
{
return $shared->permission === 'editor';
}
/**
* Get unique id
*
* @return int
*/
function get_unique_id(): int
{
// Get files and folders
$folders = FileManagerFolder::withTrashed()->latest();
$files = FileManagerFile::withTrashed()->latest();
// Get last ids
$folders_unique = ! $folders->first() ? 0 : (int) $folders->first()->unique_id;
$files_unique = ! $files->first() ? 0 : (int) $files->first()->unique_id;
// Count new unique id
$unique_id = $folders_unique > $files_unique ? $folders_unique + 1 : $files_unique + 1;
return $unique_id;
}
/**
* Store user avatar to storage
*
* @param $image
* @param $path
* @return string
*/
function store_avatar($image, $path)
{
// Get directory
$path = check_directory($path);
// Store avatar
$image_path = Str::random(8) . '-' . $image->getClientOriginalName();
// Create intervention image
$img = Image::make($image->getRealPath());
// Generate thumbnail
$img->fit('150', '150')->stream();
// Store thumbnail to disk
Storage::put($path . '/' . $image_path, $img);
// Return path to image
return $path . '/' . $image_path;
}
/**
* Store system image
*
* @param $image
* @param $path
* @return string
*/
function store_system_image($image, $path)
{
// Get directory
$path = check_directory($path);
// Store avatar
$image_path = Str::random(8) . '-' . str_replace(' ', '', $image->getClientOriginalName());
// Store image to disk
Storage::putFileAs($path, $image, $image_path);
// Return path to image
return $path . '/' . $image_path;
}
/**
* Check if directory exist, if no, then create it
*
* @param $directory
* @return mixed
*/
function check_directory($directory)
{
if (!Storage::exists($directory)) {
Storage::makeDirectory($directory);
}
return $directory;
}
/**
* Make input from request
*
* @param $request
* @return array
*/
function make_single_input($request)
{
// Create container
$data = [];
// Add data to array
$data[$request->name] = $request->value;
// Return input
return $data;
}
/**
* Format integer to gigabytes
*
* @param $gigabytes
* @return string
*/
function format_gigabytes($gigabytes)
{
if ($gigabytes >= 1000) {
return Metric::gigabytes($gigabytes)->format('Tb/');
} else {
return Metric::gigabytes($gigabytes)->format('GB/');
}
}
/**
* Convert megabytes to bytes
*
* @param $megabytes
* @return int|string
*/
function format_bytes($megabytes)
{
return Metric::megabytes($megabytes)->numberOfBytes();
}
/**
* Get storage usage in percent
*
* @param $used
* @param $capacity
* @return string
*/
function get_storage_fill_percentage($used, $capacity)
{
// Format gigabytes to bytes
$total = intval(Metric::gigabytes($capacity)->numberOfBytes());
// Count progress
$progress = ($used * 100) / $total;
// Return in 2 decimal
return number_format((float)$progress, 2, '.', '');
}
/**
* Get user capacity fill by percentage
*
* @return string
*/
function user_storage_percentage($id, $additionals = null)
{
$user = \App\User::findOrFail($id);
$used = $user->used_capacity;
if ($additionals) {
$used = $user->used_capacity + $additionals;
}
return get_storage_fill_percentage($used, $user->settings->storage_capacity);
}
/**
* Find all key values in recursive array
*
* @param array $array
* @param $needle
* @return array
*/
function recursiveFind(array $array, $needle)
{
$iterator = new RecursiveArrayIterator($array);
$recursive = new RecursiveIteratorIterator($iterator, RecursiveIteratorIterator::SELF_FIRST);
$aHitList = array();
foreach ($recursive as $key => $value) {
if ($key === $needle) {
array_push($aHitList, $value);
}
}
return $aHitList;
}
/**
* Get values which appears only once in array
* @param $arr
* @return array
*/
function appeared_once($arr)
{
$array_count_values = array_count_values($arr);
$single_time_comming_values_array = [];
foreach ($array_count_values as $key => $val) {
if ($val == 1) {
$single_time_comming_values_array[] = $key;
}
}
return $single_time_comming_values_array;
}
/**
* @param $folders
* @return array
*/
function filter_folders_ids($folders, $by_column = 'unique_id')
{
$folder_unique_ids = recursiveFind($folders->toArray(), $by_column);
return appeared_once($folder_unique_ids);
}
/**
* Format localized date
*
* @param $date
* @param string $format
* @return string
*/
function format_date($date, $format = '%d. %B. %Y, %H:%M')
{
$start = Carbon::parse($date);
return $start->formatLocalized($format);
}
/**
* Get file type from mimetype
*
* @param $file
* @return string
*/
function get_file_type($file_mimetype)
{
// Get mimetype from file
$mimetype = explode('/', $file_mimetype);
switch ($mimetype[0]) {
case 'image':
return 'image';
break;
case 'video':
return 'video';
break;
case 'audio':
return 'audio';
break;
default:
return 'file';
}
}
/**
* Get file type from mimetype
*
* @param $mimetype
* @return mixed
*/
function get_file_type_from_mimetype($mimetype)
{
return explode('/', $mimetype)[1];
}
/**
* Format pretty name file
*
* @param $basename
* @param $name
* @param $mimetype
* @return string
*/
function get_pretty_name($basename, $name, $mimetype)
{
$file_extension = substr(strrchr($basename, '.'), 1);
if (strpos($name, $file_extension) !== false) {
return $name;
}
if ($file_extension) {
return $name . '.' . $file_extension;
}
return $name . '.' . $mimetype;
}

View File

@@ -0,0 +1,23 @@
<?php
/**
* Check if current user subscribed plan is highest
*
* @param $id
* @param $subscribed_capacity
* @return int
*/
function is_highest_plan($plan)
{
$plans = app('rinvex.subscriptions.plan')->all();
$unsubscribed = $plans->filter(function ($item) use ($plan) {
return $item->id !== $plan->id;
});
$capacities = $unsubscribed->map(function ($item) {
return $item->features->first()->value;
});
return max(Arr::flatten($capacities)) < $plan->features->first()->value ? 1 : 0;
}

View File

@@ -2,6 +2,7 @@
namespace App\Http;
use App\Http\Middleware\AdminCheck;
use App\Http\Middleware\CookieAuth;
use App\Http\Middleware\LastCheck;
use App\Http\Middleware\SharedAuth;
@@ -58,6 +59,7 @@ class Kernel extends HttpKernel
protected $routeMiddleware = [
'auth.master' => CookieAuth::class,
'auth.shared' => SharedAuth::class,
'auth.admin' => AdminCheck::class,
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,

View File

@@ -0,0 +1,40 @@
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class SendSupportForm extends Mailable
{
use Queueable, SerializesModels;
private $request;
/**
* Create a new message instance.
*
* @return void
*/
public function __construct($request)
{
$this->request = $request;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
$from = config('mail.from')['address'];
return $this->from($from)
->replyTo($this->request['email'])
->subject('New Contact Message from ' . $this->request['email'])
->view('mails.contact-message')
->with('request', $this->request);
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Gate;
class AdminCheck
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
// Check if user have access to administration settings
if ( ! Gate::allows('admin-settings')) {
abort(403, 'You don\'t have access for this operation!');
}
return $next($request);
}
}

View File

@@ -19,6 +19,7 @@ class VerifyCsrfToken extends Middleware
* @var array
*/
protected $except = [
//
'/deploy',
'/stripe/*',
];
}

View File

@@ -0,0 +1,68 @@
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use Laravel\Cashier\Payment;
class ConfirmPayment extends Notification implements ShouldQueue
{
use Queueable;
/**
* The PaymentIntent identifier.
*
* @var string
*/
public $paymentId;
/**
* The payment amount.
*
* @var string
*/
public $amount;
/**
* Create a new payment confirmation notification.
*
* @param \Laravel\Cashier\Payment $payment
* @return void
*/
public function __construct(Payment $payment)
{
$this->paymentId = $payment->id;
$this->amount = $payment->amount();
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
$url = route('cashier.payment', ['id' => $this->paymentId]);
return (new MailMessage)
->subject(__('cashier.confirm_payment'))
->greeting(__('cashier.confirm_amount', ['amount' => $this->amount]))
->line(__('cashier.confirm_description'))
->action(__('cashier.confirm_button'), $url);
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
class ChangeRoleRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'attributes' => 'required|array',
'attributes.role' => 'required|string'
];
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
class ChangeStorageCapacityRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'attributes' => 'required|array',
'attributes.storage_capacity' => 'required|digits_between:1,9'
];
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
class CreateUserByAdmin extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6|confirmed',
'name' => 'required|string|max:255',
'storage_capacity' => 'required|digits_between:1,9',
'role' => 'required|string',
'avatar' => 'sometimes|file',
];
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
class DeleteUserRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'data.name' => 'required|string|max:255',
];
}
}

View File

@@ -25,8 +25,8 @@ class DeleteItemRequest extends FormRequest
public function rules()
{
return [
'type' => 'required|string',
'force_delete' => 'required|boolean',
'data.type' => 'required|string',
'data.force_delete' => 'required|boolean',
];
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace App\Http\Requests\Payments;
use Illuminate\Foundation\Http\FormRequest;
class RegisterNewPaymentMethodRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'token' => 'required|string',
'default' => 'required|boolean'
];
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace App\Http\Requests\PublicPages;
use Illuminate\Foundation\Http\FormRequest;
class SendMessageRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'email' => 'required|email',
'message' => 'required|string',
];
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace App\Http\Requests\SetupWizard;
use Illuminate\Foundation\Http\FormRequest;
class StoreAppSetupRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'title' => 'required|string',
'description' => 'required|string',
'logo' => 'sometimes|file',
'favicon' => 'sometimes|file',
'contactMail' => 'required|email',
'googleAnalytics' => 'sometimes|string',
'defaultStorage' => 'sometimes|digits_between:1,9',
'userRegistration' => 'required|boolean',
'storageLimitation' => 'required|boolean',
];
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace App\Http\Requests\SetupWizard;
use Illuminate\Foundation\Http\FormRequest;
class StoreDatabaseCredentialsRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'connection' => 'required|string',
'host' => 'required|string',
'port' => 'required|string',
'name' => 'required|string',
'username' => 'required|string',
'password' => 'required|string',
];
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace App\Http\Requests\SetupWizard;
use Illuminate\Foundation\Http\FormRequest;
class StoreEnvironmentSetupRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'storage' => 'required|array',
'storage.driver' => 'required|string',
'storage.key' => 'sometimes|nullable|string',
'storage.secret' => 'sometimes|nullable|string',
'storage.endpoint' => 'sometimes|nullable|string',
'storage.region' => 'sometimes|nullable|string',
'storage.bucket' => 'sometimes|nullable|string',
'mail' => 'required|array',
'mail.driver' => 'required|string',
'mail.host' => 'required|string',
'mail.port' => 'required|string',
'mail.username' => 'required|string',
'mail.password' => 'required|string',
'mail.encryption' => 'required|string',
];
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace App\Http\Requests\SetupWizard;
use Illuminate\Foundation\Http\FormRequest;
class StoreStripeBillingRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'billing_phone_number' => 'sometimes|nullable|string',
'billing_postal_code' => 'required|string',
'billing_vat_number' => 'required|string',
'billing_address' => 'required|string',
'billing_country' => 'required|string',
'billing_state' => 'required|string',
'billing_city' => 'required|string',
'billing_name' => 'required|string',
];
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace App\Http\Requests\SetupWizard;
use Illuminate\Foundation\Http\FormRequest;
class StoreStripeCredentialsRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'currency' => 'required|string',
'webhookSecret' => 'required|string',
'secret' => 'required|string',
'key' => 'required|string',
];
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace App\Http\Requests\SetupWizard;
use Illuminate\Foundation\Http\FormRequest;
class StoreStripePlansRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'plans' => 'required|array',
'plans.*.type' => 'required|string',
'plans.*.attributes.name' => 'required|string',
'plans.*.attributes.price' => 'required|string',
'plans.*.attributes.description' => 'sometimes|nullable|string',
'plans.*.attributes.capacity' => 'required|digits_between:1,9',
];
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace App\Http\Requests\Subscription;
use Illuminate\Foundation\Http\FormRequest;
class StoreUpgradeAccountRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
// Billings
'billing' => 'required|array',
'billing.billing_address' => 'required|string',
'billing.billing_city' => 'required|string',
'billing.billing_country' => 'required|string',
'billing.billing_name' => 'required|string',
'billing.billing_phone_number' => 'required|string',
'billing.billing_postal_code' => 'required|string',
'billing.billing_state' => 'required|string',
// Payment
'payment' => 'required|array',
'payment.type' => 'required|string',
'payment.meta' => 'required|sometimes|array',
'payment.meta.pm' => 'required|sometimes|string',
// Plan
'plan.data' => 'required|array',
'plan.data.attributes' => 'required|array',
'plan.data.attributes.capacity' => 'required|digits_between:1,9',
'plan.data.attributes.capacity_formatted' => 'required|string',
'plan.data.attributes.currency' => 'required|string',
'plan.data.attributes.description' => 'required|string',
'plan.data.attributes.name' => 'required|string',
'plan.data.attributes.price' => 'required|string',
'plan.data.id' => 'required|string',
'plan.data.type' => 'required|string',
];
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class GatewayCollection extends ResourceCollection
{
public $collects = GatewayResource::class;
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'data' => $this->collection,
];
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class GatewayResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'data' => [
'id' => (string)$this->id,
'type' => 'gateways',
'attributes' => [
'status' => $this->status,
'sandbox' => $this->sandbox,
'name' => $this->name,
'slug' => $this->slug,
'logo' => $this->logo,
'client_id' => $this->client_id,
'secret' => $this->secret,
'webhook' => $this->webhook,
'payment_processed' => $this->payment_processed,
'optional' => $this->optional,
]
]
];
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class InvoiceAdminCollection extends ResourceCollection
{
public $collects = InvoiceAdminResource::class;
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'data' => $this->collection,
];
}
}

View File

@@ -0,0 +1,65 @@
<?php
namespace App\Http\Resources;
use App\User;
use Illuminate\Http\Resources\Json\JsonResource;
use Laravel\Cashier\Cashier;
class InvoiceAdminResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
$user = User::where('stripe_id', $this['customer'])->first();
return [
'data' => [
'id' => $this['id'],
'type' => 'invoices',
'attributes' => [
'customer' => $this['customer'],
'total' => Cashier::formatAmount($this['total']),
'currency' => $this['currency'],
'created_at_formatted' => format_date($this['created']),
'created_at' => $this['created'],
'order' => $this['number'],
'user_id' => $user ? $user->id : null,
'client' => [
'billing_address' => $this['customer_address'],
'billing_name' => $this['customer_name'],
'billing_phone_number' => $this['customer_phone'],
],
'bag' => [
'amount' => $this['lines']['data'][0]['amount'],
'currency' => $this['lines']['data'][0]['currency'],
'type' => $this['lines']['data'][0]['type'],
'description' => $this['lines']['data'][0]['description'],
],
'seller' => null,
]
],
$this->mergeWhen($user, function () use ($user) {
return [
'relationships' => [
'user' => [
'data' => [
'id' => (string)$user->id,
'type' => 'user',
'attributes' => [
'name' => $user->name,
'avatar' => $user->avatar,
]
]
]
]
];
}),
];
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class InvoiceCollection extends ResourceCollection
{
public $collects = InvoiceResource::class;
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'data' => $this->collection,
];
}
}

View File

@@ -0,0 +1,80 @@
<?php
namespace App\Http\Resources;
use App\User;
use Illuminate\Http\Resources\Json\JsonResource;
class InvoiceResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
$user = User::where('stripe_id', $this->customer)->first();
$invoice_items = [];
$invoice_subscriptions = [];
// Format bag
foreach ($this->invoiceItems() as $item) {
array_push($invoice_items, [
'amount' => $item->total(),
'description' => $item->description,
'currency' => $item->currency,
'type' => $item->type,
]);
}
// Format bag
foreach ($this->subscriptions() as $item) {
array_push($invoice_subscriptions, [
'amount' => $item->total(),
'description' => $item->description,
'currency' => $item->currency,
'type' => $item->type,
]);
}
return [
'data' => [
'id' => $this->id,
'type' => 'invoices',
'attributes' => [
'customer' => $this->customer,
'total' => $this->total(),
'currency' => $this->currency,
'created_at_formatted' => format_date($this->date(), '%d. %B. %Y'),
'created_at' => $this->created,
'order' => $this->number,
'user_id' => $user ? $user->id : null,
'client' => [
'billing_address' => $this->customer_address,
'billing_name' => $this->customer_name,
'billing_phone_number' => $this->customer_phone,
],
'seller' => null,
'invoice_items' => $invoice_items,
'invoice_subscriptions' => $invoice_subscriptions,
]
],
$this->mergeWhen($user, [
'relationships' => [
'user' => [
'data' => [
'id' => (string)$user->id,
'type' => 'user',
'attributes' => [
'name' => $user->name,
'avatar' => $user->avatar,
]
]
]
]
]),
];
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class PageCollection extends ResourceCollection
{
public $collects = PageResource::class;
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'data' => $this->collection,
];
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class PageResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'data' => [
'id' => $this->id,
'type' => 'pages',
'attributes' => [
'visibility' => $this->visibility,
'title' => $this->title,
'slug' => $this->slug,
'content' => $this->content,
'content_formatted' => add_paragraphs($this->content),
]
],
];
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class PaymentCardCollection extends ResourceCollection
{
public $collects = PaymentCardResource::class;
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'data' => $this->collection,
];
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class PaymentCardResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'data' => [
'id' => (string)$this['id'],
'type' => 'payment_method',
'attributes' => [
'provider' => 'stripe',
'card_id' => $this['id'],
'brand' => strtolower($this['card']['brand']),
'last4' => $this['card']['last4'],
'exp_month' => $this['card']['exp_month'],
'exp_year' => $this['card']['exp_year'],
'created_at' => format_date($this['created_at'], '%d. %B. %Y'),
'status' => 'active',
'default' => 0,
]
]
];
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class PaymentDefaultCardResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'data' => [
'id' => (string)$this['id'],
'type' => 'payment_method',
'attributes' => [
'provider' => 'stripe',
'card_id' => $this['id'],
'brand' => isset($this['brand']) ? strtolower($this['brand']) : strtolower($this['card']['brand']),
'last4' => isset($this['last4']) ? $this['last4'] : $this['card']['last4'],
'exp_month' => isset($this['exp_month']) ? $this['exp_month'] : $this['card']['exp_month'],
'exp_year' => isset($this['exp_year']) ? $this['exp_year'] : $this['card']['exp_year'],
'created_at' => format_date($this['created_at'], '%d. %B. %Y'),
'status' => 'active',
'default' => 0,
]
]
];
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class PlanCollection extends ResourceCollection
{
public $collects = PlanResource::class;
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'data' => $this->collection,
];
}
}

View File

@@ -0,0 +1,41 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
use Laravel\Cashier\Cashier;
use Laravel\Cashier\Subscription;
class PlanResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
// Get subscribers
$subscriber_count = Subscription::where('stripe_plan', $this['plan']['id'])->where('stripe_status', 'active')->get();
return [
'data' => [
'id' => $this['plan']['id'],
'type' => 'plans',
'attributes' => [
'subscribers' => $subscriber_count->count(),
'status' => $this['plan']['active'] ? 1 : 0,
'name' => $this['product']['name'],
'description' => $this['product']['description'],
'price' => $this['plan']['amount'],
'price_formatted' => Cashier::formatAmount($this['plan']['amount']),
'capacity_formatted' => format_gigabytes($this['product']['metadata']['capacity']),
'capacity' => (int) $this['product']['metadata']['capacity'],
'created_at_formatted' => format_date($this['plan']['created']),
'created_at' => $this['plan']['created'],
]
]
];
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class PricingCollection extends ResourceCollection
{
public $collects = PricingResource::class;
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'data' => $this->collection,
];
}
}

View File

@@ -0,0 +1,68 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
use Laravel\Cashier\Cashier;
class PricingResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'data' => [
'id' => $this['plan']['id'],
'type' => 'plans',
'attributes' => [
'name' => $this['product']['name'],
'description' => $this['product']['description'],
'price' => Cashier::formatAmount($this['plan']['amount']),
'capacity_formatted' => format_gigabytes($this['product']['metadata']['capacity']),
'capacity' => (int)$this['product']['metadata']['capacity'],
'currency' => config('cashier.currency'),
'tax_rates' => $this->get_tax_rates(),
]
]
];
}
/**
* Get plan tax rates
*
* @return array
*/
private function get_tax_rates(): array
{
$stripe = resolve('App\Services\StripeService');
$rates_puplic = [];
// Get tax rates
$rates = $stripe->getTaxRates();
foreach ($rates as $rate) {
// Continue when is not active
if (!$rate['active']) continue;
// Calculate tax
$tax = $this['plan']['amount'] * ($rate['percentage'] / 100);
array_push($rates_puplic, [
'id' => $rate['id'],
'active' => $rate['active'],
'jurisdiction' => $rate['jurisdiction'],
'percentage' => $rate['percentage'],
'plan_price_formatted' => Cashier::formatAmount(round($this['plan']['amount'] + $tax)),
]);
}
return $rates_puplic;
}
}

View File

@@ -20,8 +20,8 @@ class ShareResource extends JsonResource
'type' => 'shares',
'attributes' => [
'permission' => $this->permission,
'protected' => $this->protected,
'item_id' => $this->item_id,
'protected' => (int) $this->protected,
'item_id' => (int) $this->item_id,
'token' => $this->token,
'link' => $this->link,
'type' => $this->type,

View File

@@ -0,0 +1,83 @@
<?php
namespace App\Http\Resources;
use App\Services\StripeService;
use App\User;
use Cartalyst\Stripe\Api\PaymentMethods;
use Faker\Factory;
use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'data' => [
'id' => (string)$this->id,
'type' => 'user',
'attributes' => [
'storage_capacity' => $this->settings->storage_capacity,
'subscription' => $this->subscribed('main'),
'incomplete_payment' => $this->hasIncompletePayment('main') ? route('cashier.payment', $this->subscription('main')->latestPayment()->id) : null,
'stripe_customer' => is_null($this->stripe_id) ? false : true,
'name' => $this->name,
'email' => env('APP_DEMO') ? obfuscate_email($this->email) : $this->email,
'avatar' => $this->avatar,
'role' => $this->role,
'created_at_formatted' => format_date($this->created_at, '%d. %B. %Y'),
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
]
],
'relationships' => [
'settings' => [
'data' => [
'id' => (string)$this->settings->id,
'type' => 'settings',
'attributes' => [
'billing_name' => $this->settings->billing_name,
'billing_address' => $this->settings->billing_address,
'billing_state' => $this->settings->billing_state,
'billing_city' => $this->settings->billing_city,
'billing_postal_code' => $this->settings->billing_postal_code,
'billing_country' => $this->settings->billing_country,
'billing_phone_number' => $this->settings->billing_phone_number,
]
]
],
'storage' => [
'data' => [
'id' => '1',
'type' => 'storage',
'attributes' => $this->storage
]
],
'favourites' => [
'data' => [
'id' => '1',
'type' => 'folders_favourite',
'attributes' => [
'folders' => $this->favourite_folders->makeHidden(['pivot'])
],
],
],
'tree' => [
'data' => [
'id' => '1',
'type' => 'folders_tree',
'attributes' => [
'folders' => $this->folder_tree
],
],
]
]
];
}
}

View File

@@ -0,0 +1,89 @@
<?php
namespace App\Http\Resources;
use App\FileManagerFile;
use ByteUnits\Metric;
use Illuminate\Http\Resources\Json\JsonResource;
class UserStorageResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
$document_mimetypes = [
'pdf', 'numbers', 'xlsx', 'xls', 'txt', 'md', 'rtf', 'pptx', 'ppt', 'odt', 'ods', 'odp', 'epub', 'docx', 'doc', 'csv', 'pages'
];
// Get all images
$images = FileManagerFile::where('user_id', $this->id)
->where('type', 'image')->get()->map(function ($item) {
return (int)$item->getRawOriginal('filesize');
})->sum();
// Get all audios
$audios = FileManagerFile::where('user_id', $this->id)
->where('type', 'audio')->get()->map(function ($item) {
return (int)$item->getRawOriginal('filesize');
})->sum();
// Get all videos
$videos = FileManagerFile::where('user_id', $this->id)
->where('type', 'video')->get()->map(function ($item) {
return (int)$item->getRawOriginal('filesize');
})->sum();
// Get all documents
$documents = FileManagerFile::where('user_id', $this->id)
->whereIn('mimetype', $document_mimetypes)->get()->map(function ($item) {
return (int)$item->getRawOriginal('filesize');
})->sum();
// Get all other files
$others = FileManagerFile::where('user_id', $this->id)
->whereNotIn('mimetype', $document_mimetypes)
->whereNotIn('type', ['audio', 'video', 'image'])
->get()->map(function ($item) {
return (int)$item->getRawOriginal('filesize');
})->sum();
return [
'data' => [
'id' => (string)$this->id,
'type' => 'storage',
'attributes' => [
'used' => Metric::bytes($this->used_capacity)->format(),
'capacity' => format_gigabytes($this->settings->storage_capacity),
'percentage' => (float)get_storage_fill_percentage($this->used_capacity, $this->settings->storage_capacity),
],
'meta' => [
'images' => [
'used' => Metric::bytes($images)->format(),
'percentage' => (float)get_storage_fill_percentage($images, $this->settings->storage_capacity),
],
'audios' => [
'used' => Metric::bytes($audios)->format(),
'percentage' => (float)get_storage_fill_percentage($audios, $this->settings->storage_capacity),
],
'videos' => [
'used' => Metric::bytes($videos)->format(),
'percentage' => (float)get_storage_fill_percentage($videos, $this->settings->storage_capacity),
],
'documents' => [
'used' => Metric::bytes($documents)->format(),
'percentage' => (float)get_storage_fill_percentage($documents, $this->settings->storage_capacity),
],
'others' => [
'used' => Metric::bytes($others)->format(),
'percentage' => (float)get_storage_fill_percentage($others, $this->settings->storage_capacity),
],
]
]
];
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class UserSubscription extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
$stripe = resolve('App\Services\StripeService');
$active_subscription = $this->subscription('main')->asStripeSubscription();
// Get subscription details
$subscription = $stripe->getPlan($this->subscription('main')->stripe_plan);
// Retrieve the timestamp from Stripe
$current_period_end = $active_subscription["current_period_end"];
$current_period_start = $active_subscription["current_period_start"];
$canceled_at = $active_subscription["canceled_at"];
return [
'data' => [
'id' => $subscription['plan']['id'],
'type' => 'subscription',
'attributes' => [
'incomplete' => $this->subscription('main')->incomplete(),
'active' => $this->subscription('main')->active(),
'canceled' => $this->subscription('main')->cancelled(),
'name' => $subscription['product']['name'],
'capacity' => (int)$subscription['product']['metadata']['capacity'],
'capacity_formatted' => format_gigabytes($subscription['product']['metadata']['capacity']),
'slug' => $subscription['plan']['id'],
'canceled_at' => format_date($canceled_at, '%d. %B. %Y'),
'created_at' => format_date($current_period_start, '%d. %B. %Y'),
'ends_at' => format_date($current_period_end, '%d. %B. %Y'),
]
]
];
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class UsersCollection extends ResourceCollection
{
public $collects = UserResource::class;
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'data' => $this->collection,
];
}
}

View File

@@ -102,7 +102,7 @@ class Demo
$filename = Str::random() . '-' . str_replace(' ', '', $file->getClientOriginalName());
$thumbnail = null;
$filesize = $file->getSize();
$filetype = get_file_type($file);
$filetype = get_file_type($file->getMimeType());
return [
'id' => random_int(1000, 9999),
@@ -138,6 +138,6 @@ class Demo
*/
public static function favourites($user) {
return $user->favourites->makeHidden(['pivot']);
return $user->favourite_folders->makeHidden(['pivot']);
}
}

View File

@@ -8,11 +8,17 @@ use App\FileManagerFile;
use App\FileManagerFolder;
use App\Http\Requests\FileFunctions\RenameItemRequest;
use App\User;
use Aws\Exception\MultipartUploadException;
use Aws\S3\MultipartUploader;
use Carbon\Carbon;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Intervention\Image\ImageManagerStatic as Image;
use Symfony\Component\HttpKernel\Exception\HttpException;
class Editor
@@ -30,11 +36,12 @@ class Editor
$user_scope = is_null($shared) ? $request->user()->token()->scopes[0] : 'editor';
$name = $request->has('name') ? $request->input('name') : 'New Folder';
$user_id = is_null($shared) ? Auth::id() : $shared->user_id;
$unique_id = get_unique_id();
// Create folder
$folder = FileManagerFolder::create([
'parent_id' => $request->parent_id,
'unique_id' => get_unique_id(),
'unique_id' => $unique_id,
'user_scope' => $user_scope,
'user_id' => $user_id,
'type' => 'folder',
@@ -85,7 +92,7 @@ class Editor
$user = is_null($shared) ? Auth::user() : User::findOrFail($shared->user_id);
// Delete folder
if ($request->type === 'folder') {
if ($request->input('data.type') === 'folder') {
// Get folder
$folder = FileManagerFolder::withTrashed()
@@ -106,7 +113,7 @@ class Editor
}
// Force delete children files
if ($request->force_delete) {
if ($request->input('data.force_delete')) {
// Get children folder ids
$child_folders = filter_folders_ids($folder->trashed_folders, 'unique_id');
@@ -124,7 +131,7 @@ class Editor
Storage::delete('/file-manager/' . $file->basename);
// Delete thumbnail if exist
if (!is_null($file->thumbnail)) Storage::delete('/file-manager/' . $file->getOriginal('thumbnail'));
if (!is_null($file->thumbnail)) Storage::delete('/file-manager/' . $file->getRawOriginal('thumbnail'));
// Delete file permanently
$file->forceDelete();
@@ -135,10 +142,10 @@ class Editor
}
// Soft delete items
if (!$request->force_delete) {
if (!$request->input('data.force_delete')) {
// Remove folder from user favourites
$user->favourites()->detach($unique_id);
$user->favourite_folders()->detach($unique_id);
// Soft delete folder record
$folder->delete();
@@ -146,7 +153,7 @@ class Editor
}
// Delete item
if ($request->type !== 'folder') {
if ($request->input('data.type') !== 'folder') {
// Get file
$file = FileManagerFile::withTrashed()
@@ -166,20 +173,20 @@ class Editor
}
// Force delete file
if ($request->force_delete) {
if ($request->input('data.force_delete')) {
// Delete file
Storage::delete('/file-manager/' . $file->basename);
// Delete thumbnail if exist
if ($file->thumbnail) Storage::delete('/file-manager/' . $file->getOriginal('thumbnail'));
if ($file->thumbnail) Storage::delete('/file-manager/' . $file->getRawOriginal('thumbnail'));
// Delete file permanently
$file->forceDelete();
}
// Soft delete file
if (!$request->force_delete) {
if (!$request->input('data.force_delete')) {
// Soft delete file
$file->delete();
@@ -187,75 +194,6 @@ class Editor
}
}
/**
* Upload file
*
* @param $request
* @param null $shared
* @return FileManagerFile|\Illuminate\Database\Eloquent\Model
* @throws \Exception
*/
public static function upload($request, $shared = null)
{
// Get user data
$user_scope = is_null($shared) ? $request->user()->token()->scopes[0] : 'editor';
$user_id = is_null($shared) ? Auth::id() : $shared->user_id;
// Get parent_id from request
$folder_id = $request->parent_id === 0 ? 0 : $request->parent_id;
$file = $request->file('file');
// File
$filename = Str::random() . '-' . str_replace(' ', '', $file->getClientOriginalName());
$filetype = get_file_type($file);
$filesize = $file->getSize();
$directory = 'file-manager';
$thumbnail = null;
// create directory if not exist
if (!Storage::exists($directory)) {
Storage::makeDirectory($directory);
}
// Store to disk
Storage::putFileAs($directory, $file, $filename, 'private');
// Create image thumbnail
if ($filetype == 'image') {
// Get thumbnail name
$thumbnail = 'thumbnail-' . $filename;
// Create intervention image
$image = Image::make($file->getRealPath())->orientate();
// Resize image
$image->resize(256, null, function ($constraint) {
$constraint->aspectRatio();
})->stream();
// Store thumbnail to disk
Storage::put($directory . '/' . $thumbnail, $image);
}
// Store file
$options = [
'name' => pathinfo($file->getClientOriginalName())['filename'],
'mimetype' => $file->getClientOriginalExtension(),
'unique_id' => get_unique_id(),
'user_scope' => $user_scope,
'folder_id' => $folder_id,
'thumbnail' => $thumbnail,
'basename' => $filename,
'filesize' => $filesize,
'type' => $filetype,
'user_id' => $user_id,
];
// Return new file
return FileManagerFile::create($options);
}
/**
* Move folder or file to new location
*
@@ -291,4 +229,259 @@ class Editor
]);
}
}
/**
* Upload file
*
* @param $request
* @param null $shared
* @return FileManagerFile|\Illuminate\Database\Eloquent\Model
* @throws \Exception
*/
public static function upload($request, $shared = null)
{
// Get parent_id from request
$file = $request->file('file');
// Check or create directories
self::check_directories(['chunks', 'file-manager']);
// File name
$user_file_name = basename('chunks/' . substr($file->getClientOriginalName(), 17), '.part');
$disk_file_name = basename('chunks/' . $file->getClientOriginalName(), '.part');
$temp_filename = $file->getClientOriginalName();
// Generate file
File::append(config('filesystems.disks.local.root') . '/chunks/' . $temp_filename, $file->get());
// If last then process file
if ($request->boolean('is_last')) {
$disk_local = Storage::disk('local');
$unique_id = get_unique_id();
// Get user data
$user_scope = is_null($shared) ? $request->user()->token()->scopes[0] : 'editor';
$user_id = is_null($shared) ? Auth::id() : $shared->user_id;
// File Info
$file_size = $disk_local->size('chunks/' . $temp_filename);
$file_mimetype = $disk_local->mimeType('chunks/' . $temp_filename);
// Check if user has enough space to upload file
self::check_user_storage_capacity($user_id, $file_size, $temp_filename);
// Create thumbnail
$thumbnail = self::get_image_thumbnail('chunks/' . $temp_filename, $disk_file_name);
// Move finished file from chunk to file-manager directory
$disk_local->move('chunks/' . $temp_filename, 'file-manager/' . $disk_file_name);
// Move files to external storage
if (!is_storage_driver(['local'])) {
// Clear failed uploads if exists
self::clear_failed_files();
// Move file to external storage service
self::move_to_external_storage($disk_file_name, $thumbnail);
}
// Store file
$options = [
'mimetype' => get_file_type_from_mimetype($file_mimetype),
'type' => get_file_type($file_mimetype),
'folder_id' => $request->parent_id,
'name' => $user_file_name,
'unique_id' => $unique_id,
'basename' => $disk_file_name,
'user_scope' => $user_scope,
'thumbnail' => $thumbnail,
'filesize' => $file_size,
'user_id' => $user_id,
];
// Return new file
return FileManagerFile::create($options);
}
}
/**
* Clear failed files
*/
private static function clear_failed_files()
{
$local_disk = Storage::disk('local');
// Get all files from storage
$files = collect([
$local_disk->allFiles('file-manager'),
$local_disk->allFiles('chunks')
])->collapse();
$files->each(function ($file) use ($local_disk) {
// Get the file's last modification time.
$last_modified = $local_disk->lastModified($file);
// Get diffInHours
$diff = Carbon::parse($last_modified)->diffInHours(Carbon::now());
// Delete if file is in local storage more than 24 hours
if ($diff > 24) {
Log::info('Failed file or chunk ' . $file . ' deleted.');
// Delete file from local storage
$local_disk->delete($file);
}
});
}
/**
* Move file to external storage if is set
*
* @param string $filename
* @param string|null $thumbnail
*/
private static function move_to_external_storage(string $filename, ?string $thumbnail): void
{
$disk_local = Storage::disk('local');
foreach ([$filename, $thumbnail] as $file) {
// Check if file exist
if (!$file) continue;
// Get file size
$filesize = $disk_local->size('file-manager/' . $file);
// If file is bigger than 5.2MB then run multipart upload
if ($filesize > 5242880) {
// Get driver
$driver = \Storage::getDriver();
// Get adapter
$adapter = $driver->getAdapter();
// Get client
$client = $adapter->getClient();
// Prepare the upload parameters.
$uploader = new MultipartUploader($client, config('filesystems.disks.local.root') . '/file-manager/' . $file, [
'bucket' => $adapter->getBucket(),
'key' => 'file-manager/' . $file
]);
try {
// Upload content
$uploader->upload();
} catch (MultipartUploadException $e) {
// Write error log
Log::error($e->getMessage());
// Delete file after error
$disk_local->delete('file-manager/' . $file);
throw new HttpException(409, $e->getMessage());
}
} else {
// Stream file object to s3
Storage::putFileAs('file-manager', config('filesystems.disks.local.root') . '/file-manager/' . $file, $file, 'private');
}
// Delete file after upload
$disk_local->delete('file-manager/' . $file);
}
}
/**
* Check if directories 'chunks' and 'file-manager exist', if no, then create
*
* @param $directories
*/
private static function check_directories($directories): void
{
foreach ($directories as $directory) {
if (!Storage::disk('local')->exists($directory)) {
Storage::disk('local')->makeDirectory($directory);
}
if (!is_storage_driver(['local'])) {
if (!Storage::exists($directory)) {
Storage::makeDirectory($directory);
}
}
}
}
/**
* Create thumbnail for images
*
* @param string $file_path
* @param string $filename
* @param $file
* @return string|null
*/
private static function get_image_thumbnail(string $file_path, string $filename)
{
$local_disk = Storage::disk('local');
// Create thumbnail from image
if (in_array($local_disk->mimeType($file_path), ['image/gif', 'image/jpeg', 'image/jpg', 'image/png', 'image/webp'])) {
// Get thumbnail name
$thumbnail = 'thumbnail-' . $filename;
// Create intervention image
$image = Image::make(config('filesystems.disks.local.root') . '/' . $file_path)->orientate();
// Resize image
$image->resize(512, null, function ($constraint) {
$constraint->aspectRatio();
})->stream();
// Store thumbnail to disk
$local_disk->put('file-manager/' . $thumbnail, $image);
}
// Return thumbnail as svg file
if ($local_disk->mimeType($file_path) === 'image/svg+xml') {
$thumbnail = $filename;
}
return $thumbnail ?? null;
}
/**
* Check if user has enough space to upload file
*
* @param $user_id
* @param int $file_size
* @param $temp_filename
*/
private static function check_user_storage_capacity($user_id, int $file_size, $temp_filename): void
{
// Get user storage percentage and get storage_limitation setting
$user_storage_used = user_storage_percentage($user_id, $file_size);
$storage_limitation = get_setting('storage_limitation');
// Check if user can upload
if ($storage_limitation && $user_storage_used >= 100) {
// Delete file
Storage::disk('local')->delete('chunks/' . $temp_filename);
// Abort uploading
abort(423, 'You exceed your storage limit!');
}
}
}

View File

@@ -1,317 +0,0 @@
<?php
use App\FileManagerFile;
use App\FileManagerFolder;
use App\Share;
use ByteUnits\Metric;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Intervention\Image\ImageManagerStatic as Image;
/**
* Get app version from config
*
* @return \Illuminate\Config\Repository|mixed
*/
function get_storage() {
return env('FILESYSTEM_DRIVER');
}
/**
* Check if is running AWS s3 as storage
*
* @return bool
*/
function is_storage_driver($driver) {
if (is_array($driver)) {
return in_array(env('FILESYSTEM_DRIVER'), $driver);
}
return env('FILESYSTEM_DRIVER') === $driver;
}
/**
* Get app version from config
*
* @return \Illuminate\Config\Repository|mixed
*/
function get_version() {
return config('vuefilemanager.version');
}
/**
* Check if is demo
*
* @return mixed
*/
function is_demo($user_id) {
return env('APP_DEMO', false) && $user_id === 1;
}
/**
* Get folder or file item
*
* @param $type
* @param $unique_id
* @param $user_id
* @return \Illuminate\Database\Eloquent\Builder|Model
*/
function get_item($type, $unique_id, $user_id) {
if ($type === 'folder') {
// Return folder item
return FileManagerFolder::where('unique_id', $unique_id)
->where('user_id', $user_id)
->firstOrFail();
}
// Return file item
return FileManagerFile::where('unique_id', $unique_id)
->where('user_id', $user_id)
->firstOrFail();
}
/**
* Get shared token
*
* @param $token
* @return \Illuminate\Database\Eloquent\Builder|Model
*/
function get_shared($token) {
return Share::where(DB::raw('BINARY `token`'), $token)
->firstOrFail();
}
/**
* Check if shared permission is editor
*
* @param $shared
* @return bool
*/
function is_editor($shared) {
return $shared->permission === 'editor';
}
/**
* Get unique id
*
* @return int
*/
function get_unique_id(): int
{
// Get files and folders
$folders = FileManagerFolder::withTrashed()->get();
$files = FileManagerFile::withTrashed()->get();
// Get last ids
$folders_unique = $folders->isEmpty() ? 0 : $folders->last()->unique_id;
$files_unique = $files->isEmpty() ? 0 : $files->last()->unique_id;
// Count new unique id
$unique_id = $folders_unique > $files_unique ? $folders_unique + 1 : $files_unique + 1;
return $unique_id;
}
/**
* Store user avatar to storage
*
* @param $image
* @param $path
* @return string
*/
function store_avatar($image, $path)
{
// Get directory
$path = check_directory($path);
// Store avatar
$image_path = Str::random(8) . '-' . $image->getClientOriginalName();
// Create intervention image
$img = Image::make($image->getRealPath());
// Generate thumbnail
$img->fit('150', '150')->stream();
// Store thumbnail to disk
Storage::put($path . '/' . $image_path, $img);
// Return path to image
return $path . '/' . $image_path;
}
/**
* Check if directory exist, if no, then create it
*
* @param $directory
* @return mixed
*/
function check_directory($directory)
{
if (!Storage::exists($directory)) {
Storage::makeDirectory($directory);
}
return $directory;
}
/**
* Make input from request
*
* @param $request
* @return array
*/
function make_single_input($request)
{
// Create container
$data = [];
// Add data to array
$data[$request->name] = $request->value;
// Return input
return $data;
}
/**
* Format integer to gigabytes
*
* @param $gigabytes
* @return string
*/
function format_gigabytes($megabytes)
{
return Metric::megabytes($megabytes)->format();
}
/**
* Get storage usage in percent
*
* @param $used
* @param $capacity
* @return string
*/
function get_storage_fill_percentage($used, $capacity)
{
// Format gigabytes to bytes
$total = intval(Metric::megabytes($capacity)->numberOfBytes());
// Count progress
$progress = ($used * 100) / $total;
// Return in 2 decimal
return number_format((float)$progress, 2, '.', '');
}
/**
* Get user capacity fill percentage
*
* @return string
*/
function user_storage_percentage()
{
$user = Auth::user();
return get_storage_fill_percentage($user->used_capacity, config('vuefilemanager.user_storage_capacity'));
}
/**
* Find all key values in recursive array
*
* @param array $array
* @param $needle
* @return array
*/
function recursiveFind(array $array, $needle)
{
$iterator = new RecursiveArrayIterator($array);
$recursive = new RecursiveIteratorIterator($iterator, RecursiveIteratorIterator::SELF_FIRST);
$aHitList = array();
foreach ($recursive as $key => $value) {
if ($key === $needle) {
array_push($aHitList, $value);
}
}
return $aHitList;
}
/**
* Get values which appears only once in array
* @param $arr
* @return array
*/
function appeared_once($arr)
{
$array_count_values = array_count_values($arr);
$single_time_comming_values_array = [];
foreach ($array_count_values as $key => $val) {
if ($val == 1) {
$single_time_comming_values_array[] = $key;
}
}
return $single_time_comming_values_array;
}
/**
* @param $folders
* @return array
*/
function filter_folders_ids($folders, $by_column = 'unique_id')
{
$folder_unique_ids = recursiveFind($folders->toArray(), $by_column);
return appeared_once($folder_unique_ids);
}
/**
* Format localized date
*
* @param $date
* @param string $format
* @return string
*/
function format_date($date, $format = '%d. %B. %Y, %H:%M')
{
$start = Carbon::parse($date);
return $start->formatLocalized($format);
}
/**
* Get file type from mimetype
*
* @param $file
* @return string
*/
function get_file_type($file)
{
// Get mimetype from file
$mimetype = explode('/', $file->getMimeType());
switch ($mimetype[0]) {
case 'image':
return 'image';
break;
case 'video':
return 'video';
break;
case 'audio':
return 'audio';
break;
default:
return 'file';
}
}

64
app/Invoice.php Normal file
View File

@@ -0,0 +1,64 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
/**
* App\Invoice
*
* @property int $id
* @property string $token
* @property string $order
* @property string|null $provider
* @property string $user_id
* @property string $plan_id
* @property array $seller
* @property array $client
* @property array $bag
* @property string|null $notes
* @property string $total
* @property string $currency
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read \App\User|null $user
* @method static \Illuminate\Database\Eloquent\Builder|\App\Invoice newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|\App\Invoice newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|\App\Invoice query()
* @method static \Illuminate\Database\Eloquent\Builder|\App\Invoice whereBag($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Invoice whereClient($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Invoice whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Invoice whereCurrency($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Invoice whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Invoice whereNotes($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Invoice whereOrder($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Invoice wherePlanId($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Invoice whereProvider($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Invoice whereSeller($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Invoice whereToken($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Invoice whereTotal($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Invoice whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Invoice whereUserId($value)
* @mixin \Eloquent
*/
class Invoice extends Model
{
protected $guarded = [
'id'
];
protected $casts = [
'seller' => 'array',
'client' => 'array',
'bag' => 'array',
];
/**
* Get user instance
*
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function user() {
return $this->hasOne(User::class, 'id', 'user_id');
}
}

View File

@@ -43,10 +43,12 @@ class ResetPassword extends Notification
$reset_url = url('/create-new-password?token=' . $this->token);
return (new MailMessage)
->subject('Reset password for your account on ' . config('vuefilemanager.app_name'))
->line('You are receiving this email because we received a password reset request for your account.')
->action('Reset Password', $reset_url)
->line('If you did not request a password reset, no further action is required.');
->subject(__('vuefilemanager.reset_password_subject') . config('vuefilemanager.app_name'))
->greeting(__('vuefilemanager.reset_password_greeting'))
->line(__('vuefilemanager.reset_password_line_1'))
->action(__('vuefilemanager.reset_password_action'), $reset_url)
->line(__('vuefilemanager.reset_password_line_2'))
->salutation(__('vuefilemanager.salutation') . ', ' . config('vuefilemanager.app_name'));
}
/**

12
app/Page.php Normal file
View File

@@ -0,0 +1,12 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Page extends Model
{
public $timestamps = false;
protected $guarded = ['id'];
}

42
app/PaymentGateway.php Normal file
View File

@@ -0,0 +1,42 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
/**
* App\PaymentGateway
*
* @property int $id
* @property int $status
* @property int $sandbox
* @property string $name
* @property string $slug
* @property string $logo
* @property string|null $client_id
* @property string|null $secret
* @property string|null $webhook
* @property string|null $optional
* @property int|null $payment_processed
* @method static \Illuminate\Database\Eloquent\Builder|\App\PaymentGateway newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|\App\PaymentGateway newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|\App\PaymentGateway query()
* @method static \Illuminate\Database\Eloquent\Builder|\App\PaymentGateway whereClientId($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\PaymentGateway whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\PaymentGateway whereLogo($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\PaymentGateway whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\PaymentGateway whereOptional($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\PaymentGateway wherePaymentProcessed($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\PaymentGateway whereSandbox($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\PaymentGateway whereSecret($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\PaymentGateway whereSlug($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\PaymentGateway whereStatus($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\PaymentGateway whereWebhook($value)
* @mixin \Eloquent
*/
class PaymentGateway extends Model
{
protected $guarded = ['id'];
public $timestamps = false;
}

View File

@@ -5,6 +5,9 @@ namespace App\Providers;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\ServiceProvider;
use Laravel\Passport\Console\ClientCommand;
use Laravel\Passport\Console\InstallCommand;
use Laravel\Passport\Console\KeysCommand;
class AppServiceProvider extends ServiceProvider
{
@@ -31,5 +34,12 @@ class AppServiceProvider extends ServiceProvider
// Set locale for carbon dates
setlocale(LC_TIME, $get_time_locale);
// Install passport commands
$this->commands([
InstallCommand::class,
ClientCommand::class,
KeysCommand::class,
]);
}
}

View File

@@ -26,6 +26,11 @@ class AuthServiceProvider extends ServiceProvider
{
$this->registerPolicies();
// Define admin settings gate
Gate::define('admin-settings', function ($user) {
return $user->role === 'admin';
});
Passport::routes();
Passport::tokensCan([

View File

@@ -0,0 +1,385 @@
<?php
namespace App\Services;
use App\User;
use Artisan;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Laravel\Cashier\Exceptions\IncompletePayment;
use Laravel\Cashier\Exceptions\PaymentActionRequired;
use Stripe;
use Symfony\Component\HttpKernel\Exception\HttpException;
class StripeService
{
/**
* Stripe Service constructor.
*/
public function __construct()
{
$this->stripe = Stripe::make(config('cashier.secret'), '2020-03-02');
}
/**
* Get Stripe account details
*
* @return mixed
*/
public function getAccountDetails()
{
$account = $this->stripe->account()->details();
return $account;
}
/**
* Get setup intent
*
* @param $user
* @return mixed
*/
public function getSetupIntent($user)
{
// Create stripe customer if not exist
$user->createOrGetStripeCustomer();
// Return setup intent
return $user->createSetupIntent();
}
/**
* Get tax rate ids
* @return array
*/
public function getTaxRates()
{
$tax_rates = $this->stripe->taxRates()->all();
return $tax_rates['data'];
}
/**
* Get default payment option or set new default payment
*
* @param $request
* @param $user
* @return mixed
*/
public function getOrSetDefaultPaymentMethod($request, $user)
{
// Check payment method
if (!$request->has('payment.meta.pm') && $user->hasDefaultPaymentMethod()) {
// Get default payment
return $user->defaultPaymentMethod()->paymentMethod;
}
// Clear cached payment methods
cache_forget_many([
'payment-methods-user-' . $user->id,
'default-payment-methods-user-' . $user->id
]);
if ($request->has('payment.meta.pm') && $user->hasDefaultPaymentMethod()) {
// Set new payment
return $user->addPaymentMethod($request->input('payment.meta.pm'))->paymentMethod;
} else if ($request->has('payment.meta.pm') && !$user->hasDefaultPaymentMethod()) {
// Set new payment
return $user->updateDefaultPaymentMethod($request->input('payment.meta.pm'))->paymentMethod;
} else {
throw new HttpException(400, 'Something went wrong.');
}
}
/**
* Register new payment method
*
* @param $request
* @param $user
* @return mixed
*/
public function registerNewPaymentMethod($request, $user)
{
// Clear cached payment methods
cache_forget_many([
'payment-methods-user-' . $user->id,
'default-payment-methods-user-' . $user->id
]);
// Set new payment method
$user->addPaymentMethod($request->token)->paymentMethod;
// Set new default payment
if ($request->default) {
$user->updateDefaultPaymentMethod($request->token)->paymentMethod;
}
}
/**
* Create new subscription or replace by new subscription
*
* @param $request
* @param $user
* @param $paymentMethod
* @return \Illuminate\Http\RedirectResponse
*/
public function createOrReplaceSubscription($request, $user)
{
try {
// Get payment method
$paymentMethod = $this->getOrSetDefaultPaymentMethod($request, $user);
// Check if user have subscription
if ($user->subscribed('main')) {
// Change subscription plan
$user->subscription('main')->skipTrial()->swap($request->input('plan.data.id'));
} else {
// Create subscription
$user->newSubscription('main', $request->input('plan.data.id'))->create($paymentMethod);
}
} catch (IncompletePayment $exception) {
if ($exception instanceof PaymentActionRequired) {
$cashier_route = route('cashier.payment', [$exception->payment->id, 'redirect' => url('/settings/subscription')]);
throw new HttpException(402, $cashier_route);
} else {
throw new HttpException(400, $exception->getMessage());
}
}
}
/**
* Update customer details
*
* @param $user
*/
public function updateCustomerDetails($user)
{
$user->updateStripeCustomer([
'name' => $user->settings->billing_name,
'phone' => $user->settings->billing_phone_number,
'address' => [
'line1' => $user->settings->billing_address,
'city' => $user->settings->billing_city,
'country' => $user->settings->billing_country,
'postal_code' => $user->settings->billing_postal_code,
'state' => $user->settings->billing_state,
]
]);
}
/**
* Get all plans
*
* @return mixed
*/
public function getPlans()
{
// Get stripe plans
$stripe_plans = $this->stripe->plans()->all();
// Plans container
$plans = [];
foreach ($stripe_plans['data'] as $plan) {
// Get stripe product
$product = $this->stripe->products()->find($plan['product']);
// Push data to $plan container
if ($product['active'] && isset($product['metadata']['capacity'])) {
array_push($plans, [
'plan' => $plan,
'product' => $product,
]);
}
}
return $plans;
}
/**
* Get all active plans
*
* @return mixed
*/
public function getActivePlans()
{
// Get stripe plans
$stripe_plans = $this->stripe->plans()->all();
// Plans container
$plans = [];
foreach ($stripe_plans['data'] as $plan) {
if ($plan['active']) {
// Get stripe product
$product = $this->stripe->products()->find($plan['product']);
// Push data to $plan container
if ($product['active'] && isset($product['metadata']['capacity'])) {
array_push($plans, [
'plan' => $plan,
'product' => $product,
]);
}
}
}
return $plans;
}
/**
* Get plan details
*
* @param $id
* @return mixed
*/
public function getPlan($id)
{
$plan = $this->stripe->plans()->find($id);
$product = $this->stripe->products()->find($plan['product']);
return compact('plan', 'product');
}
/**
* Create plan
*
* @param $data
* @return mixed
*/
public function createPlan($data)
{
if ($data instanceof Request) {
$plan = [
'name' => $data->input('attributes.name'),
'description' => $data->input('attributes.description'),
'price' => $data->input('attributes.price'),
'capacity' => $data->input('attributes.capacity'),
];
} else {
$plan = [
'name' => $data['attributes']['name'],
'description' => $data['attributes']['description'],
'price' => $data['attributes']['price'],
'capacity' => $data['attributes']['capacity'],
];
}
$product = $this->stripe->products()->create([
'name' => $plan['name'],
'description' => $plan['description'],
'metadata' => [
'capacity' => $plan['capacity']
]
]);
$plan = $this->stripe->plans()->create([
'id' => Str::slug($plan['name']),
'amount' => $plan['price'],
'currency' => config('cashier.currency'),
'interval' => 'month',
'product' => $product['id'],
]);
return compact('plan', 'product');
}
/**
* Update plan
*
* @param $request
* @param $id
*/
public function updatePlan($request, $id)
{
$plan_colls = ['is_active', 'price'];
$product_colls = ['name', 'description', 'capacity'];
$plan = $this->stripe->plans()->find($id);
// Update product
if (in_array($request->name, $product_colls)) {
if ($request->name === 'capacity') {
$this->stripe->products()->update($plan['product'], ['metadata' => ['capacity' => $request->value]]);
}
if ($request->name === 'name') {
$this->stripe->products()->update($plan['product'], ['name' => $request->value]);
}
if ($request->name === 'description') {
$this->stripe->products()->update($plan['product'], ['description' => $request->value]);
}
}
// Update plan
if (in_array($request->name, $plan_colls)) {
if ($request->name === 'is_active') {
$this->stripe->plans()->update($id, ['active' => $request->value]);
}
}
}
/**
* Delete plan
*
* @param $slug
*/
public function deletePlan($slug)
{
$this->stripe->plans()->delete($slug);
}
/**
* Get all user invoices
*
* @param $user
* @return mixed
*/
public function getUserInvoices($user)
{
return $user->invoices();
}
/**
* Get user invoice by id
*
* @param $id
* @return \Laravel\Cashier\Invoice|null
*/
public function getUserInvoice($customer, $id)
{
$user = User::where('stripe_id', $customer)->firstOrFail();
return $user->findInvoice($id);
}
/**
* Get all invoices
*
* @return mixed
*/
public function getInvoices()
{
return $this->stripe->invoices()->all();
}
}

12
app/Setting.php Normal file
View File

@@ -0,0 +1,12 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Setting extends Model
{
public $timestamps = false;
protected $guarded = ['id'];
}

View File

@@ -10,7 +10,10 @@ use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Storage;
use Laravel\Cashier\Billable;
use Laravel\Passport\HasApiTokens;
use Rinvex\Subscriptions\Traits\HasSubscriptions;
/**
* App\User
@@ -52,10 +55,32 @@ use Laravel\Passport\HasApiTokens;
* @method static \Illuminate\Database\Eloquent\Builder|\App\User whereRememberToken($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\User whereUpdatedAt($value)
* @mixin \Eloquent
* @property string $role
* @property string|null $stripe_id
* @property string|null $card_brand
* @property string|null $card_last_four
* @property string|null $trial_ends_at
* @property-read \Illuminate\Database\Eloquent\Collection|\App\FileManagerFolder[] $favourite_folders
* @property-read int|null $favourite_folders_count
* @property-read mixed $folder_tree
* @property-read mixed $storage
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Invoice[] $invoices
* @property-read int|null $invoices_count
* @property-read int|null $payment_cards_count
* @property-read \App\UserSettings|null $settings
* @property-read \Illuminate\Database\Eloquent\Collection|\Laravel\Cashier\Subscription[] $subscriptions
* @property-read int|null $subscriptions_count
* @method static \Illuminate\Database\Eloquent\Builder|\App\User whereCardBrand($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\User whereCardLastFour($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\User whereRole($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\User whereStripeId($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\User whereTrialEndsAt($value)
*/
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
use HasApiTokens, Notifiable, Billable;
protected $guarded = ['id', 'role'];
/**
* The attributes that are mass assignable.
@@ -82,27 +107,87 @@ class User extends Authenticatable
*/
protected $casts = [
'email_verified_at' => 'datetime',
'favourites' => 'array',
];
protected $appends = [
'used_capacity'
'used_capacity', 'storage'
];
/**
* Get tax rate id for user
*
* @return array
*/
public function taxRates()
{
$stripe = resolve('App\Services\StripeService');
// Get tax rates
$rates = collect($stripe->getTaxRates());
// Find tax rate
$user_tax_rate = $rates->first(function ($item) {
return $item['jurisdiction'] === $this->settings->billing_country && $item['active'];
});
return $user_tax_rate ? [$user_tax_rate['id']] : [];
}
/**
* Get user used storage details
*
* @return mixed
*/
public function getStorageAttribute()
{
// Get storage limitation setup
$storage_limitation = get_setting('storage_limitation');
$is_storage_limit = $storage_limitation ? $storage_limitation : 1;
// Get user storage usage
if (! $is_storage_limit) {
return [
'used' => $this->used_capacity,
'used_formatted' => Metric::bytes($this->used_capacity)->format(),
];
}
return [
'used' => (float)get_storage_fill_percentage($this->used_capacity, $this->settings->storage_capacity),
'used_formatted' => get_storage_fill_percentage($this->used_capacity, $this->settings->storage_capacity) . '%',
'capacity' => $this->settings->storage_capacity,
'capacity_formatted' => format_gigabytes($this->settings->storage_capacity),
];
}
/**
* Get user used storage capacity in bytes
*
* @return mixed
*/
public function getUsedCapacityAttribute() {
public function getUsedCapacityAttribute()
{
$user_capacity = $this->files_with_trashed->map(function ($item) {
return $item->getOriginal();
return $item->getRawOriginal();
})->sum('filesize');
return $user_capacity;
}
/**
* Get user full folder tree
*
* @return \Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection
*/
public function getFolderTreeAttribute()
{
return FileManagerFolder::with(['folders.shared', 'shared:token,id,item_id,permission,protected'])
->where('parent_id', 0)
->where('user_id', $this->id)
->get();
}
/**
* Format avatar to full url
*
@@ -110,6 +195,13 @@ class User extends Authenticatable
*/
public function getAvatarAttribute()
{
// Get avatar from external storage
if ($this->attributes['avatar'] && is_storage_driver(['s3', 'spaces', 'wasabi', 'backblaze'])) {
return Storage::temporaryUrl($this->attributes['avatar'], now()->addDay());
}
// Get avatar from local storage
if ($this->attributes['avatar']) {
return url('/' . $this->attributes['avatar']);
}
@@ -117,6 +209,27 @@ class User extends Authenticatable
return url('/assets/images/' . 'default-avatar.png');
}
/**
* Set user billing info
*
* @param $billing
* @return UserSettings
*/
public function setBilling($billing)
{
$this->settings()->update([
'billing_address' => $billing['billing_address'],
'billing_city' => $billing['billing_city'],
'billing_country' => $billing['billing_country'],
'billing_name' => $billing['billing_name'],
'billing_phone_number' => $billing['billing_phone_number'],
'billing_postal_code' => $billing['billing_postal_code'],
'billing_state' => $billing['billing_state'],
]);
return $this->settings;
}
/**
* Send the password reset notification.
*
@@ -133,9 +246,9 @@ class User extends Authenticatable
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function favourites()
public function favourite_folders()
{
return $this->belongsToMany(FileManagerFolder::class, 'favourite_folder', 'user_id', 'folder_unique_id', 'id', 'unique_id')->select(['unique_id', 'name', 'type']);
return $this->belongsToMany(FileManagerFolder::class, 'favourite_folder', 'user_id', 'folder_unique_id', 'id', 'unique_id')->with('shared:token,id,item_id,permission,protected');
}
/**
@@ -143,9 +256,9 @@ class User extends Authenticatable
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany|\Illuminate\Database\Query\Builder
*/
public function latest_uploads() {
return $this->hasMany(FileManagerFile::class)->orderBy('created_at', 'DESC')->take(7);
public function latest_uploads()
{
return $this->hasMany(FileManagerFile::class)->with(['parent'])->orderBy('created_at', 'DESC')->take(40);
}
/**
@@ -153,8 +266,8 @@ class User extends Authenticatable
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function files() {
public function files()
{
return $this->hasMany(FileManagerFile::class);
}
@@ -163,8 +276,18 @@ class User extends Authenticatable
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function files_with_trashed() {
public function files_with_trashed()
{
return $this->hasMany(FileManagerFile::class)->withTrashed();
}
/**
* Get user attributes
*
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function settings()
{
return $this->hasOne(UserSettings::class);
}
}

12
app/UserSettings.php Normal file
View File

@@ -0,0 +1,12 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class UserSettings extends Model
{
public $timestamps = false;
protected $guarded = ['id', 'storage_capacity'];
}

View File

@@ -9,26 +9,29 @@
"license": "MIT",
"require": {
"php": "^7.2",
"cartalyst/stripe-laravel": "^12.0",
"doctrine/dbal": "^2.10",
"fideloper/proxy": "^4.0",
"fruitcake/laravel-cors": "^1.0",
"gabrielelana/byte-units": "^0.5.0",
"intervention/image": "^2.5",
"laravel/framework": "^6.2",
"laravel/cashier": "^12.0",
"laravel/framework": "^7.0",
"laravel/passport": "^8.4",
"laravel/scout": "^7.2",
"laravel/tinker": "^2.0",
"laravel/ui": "^2.0",
"league/flysystem-aws-s3-v3": "^1.0",
"league/flysystem-cached-adapter": "^1.0",
"teamtnt/laravel-scout-tntsearch-driver": "^7.2"
"teamtnt/laravel-scout-tntsearch-driver": "^8.3"
},
"require-dev": {
"barryvdh/laravel-ide-helper": "^2.7",
"facade/ignition": "^1.4",
"facade/ignition": "^2.0",
"fzaninotto/faker": "^1.4",
"mockery/mockery": "^1.0",
"nunomaduro/collision": "^3.0",
"phpunit/phpunit": "^8.0"
"nunomaduro/collision": "^4.1",
"phpunit/phpunit": "^8.5"
},
"config": {
"optimize-autoloader": true,
@@ -49,7 +52,8 @@
"database/factories"
],
"files": [
"app/Http/helpers.php"
"app/Http//Helpers/helpers.php",
"app/Http//Helpers/subscription.php"
]
},
"autoload-dev": {

3489
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -164,6 +164,7 @@ return [
TeamTNT\Scout\TNTSearchScoutServiceProvider::class,
Intervention\Image\ImageServiceProvider::class,
Laravel\Passport\PassportServiceProvider::class,
/*
* Package Service Providers...
@@ -193,73 +194,102 @@ return [
'aliases' => [
'App' => Illuminate\Support\Facades\App::class,
'Arr' => Illuminate\Support\Arr::class,
'Artisan' => Illuminate\Support\Facades\Artisan::class,
'Auth' => Illuminate\Support\Facades\Auth::class,
'Blade' => Illuminate\Support\Facades\Blade::class,
'Broadcast' => Illuminate\Support\Facades\Broadcast::class,
'Bus' => Illuminate\Support\Facades\Bus::class,
'Cache' => Illuminate\Support\Facades\Cache::class,
'Config' => Illuminate\Support\Facades\Config::class,
'Cookie' => Illuminate\Support\Facades\Cookie::class,
'Crypt' => Illuminate\Support\Facades\Crypt::class,
'DB' => Illuminate\Support\Facades\DB::class,
'Eloquent' => Illuminate\Database\Eloquent\Model::class,
'Event' => Illuminate\Support\Facades\Event::class,
'File' => Illuminate\Support\Facades\File::class,
'Gate' => Illuminate\Support\Facades\Gate::class,
'Hash' => Illuminate\Support\Facades\Hash::class,
'Lang' => Illuminate\Support\Facades\Lang::class,
'Log' => Illuminate\Support\Facades\Log::class,
'Mail' => Illuminate\Support\Facades\Mail::class,
'App' => Illuminate\Support\Facades\App::class,
'Arr' => Illuminate\Support\Arr::class,
'Artisan' => Illuminate\Support\Facades\Artisan::class,
'Auth' => Illuminate\Support\Facades\Auth::class,
'Blade' => Illuminate\Support\Facades\Blade::class,
'Broadcast' => Illuminate\Support\Facades\Broadcast::class,
'Bus' => Illuminate\Support\Facades\Bus::class,
'Cache' => Illuminate\Support\Facades\Cache::class,
'Config' => Illuminate\Support\Facades\Config::class,
'Cookie' => Illuminate\Support\Facades\Cookie::class,
'Crypt' => Illuminate\Support\Facades\Crypt::class,
'DB' => Illuminate\Support\Facades\DB::class,
'Eloquent' => Illuminate\Database\Eloquent\Model::class,
'Event' => Illuminate\Support\Facades\Event::class,
'File' => Illuminate\Support\Facades\File::class,
'Gate' => Illuminate\Support\Facades\Gate::class,
'Hash' => Illuminate\Support\Facades\Hash::class,
'Lang' => Illuminate\Support\Facades\Lang::class,
'Log' => Illuminate\Support\Facades\Log::class,
'Mail' => Illuminate\Support\Facades\Mail::class,
'Notification' => Illuminate\Support\Facades\Notification::class,
'Password' => Illuminate\Support\Facades\Password::class,
'Queue' => Illuminate\Support\Facades\Queue::class,
'Redirect' => Illuminate\Support\Facades\Redirect::class,
'Redis' => Illuminate\Support\Facades\Redis::class,
'Request' => Illuminate\Support\Facades\Request::class,
'Response' => Illuminate\Support\Facades\Response::class,
'Route' => Illuminate\Support\Facades\Route::class,
'Schema' => Illuminate\Support\Facades\Schema::class,
'Session' => Illuminate\Support\Facades\Session::class,
'Storage' => Illuminate\Support\Facades\Storage::class,
'Str' => Illuminate\Support\Str::class,
'URL' => Illuminate\Support\Facades\URL::class,
'Validator' => Illuminate\Support\Facades\Validator::class,
'View' => Illuminate\Support\Facades\View::class,
'Image' => Intervention\Image\Facades\Image::class
'Password' => Illuminate\Support\Facades\Password::class,
'Queue' => Illuminate\Support\Facades\Queue::class,
'Redirect' => Illuminate\Support\Facades\Redirect::class,
'Redis' => Illuminate\Support\Facades\Redis::class,
'Request' => Illuminate\Support\Facades\Request::class,
'Response' => Illuminate\Support\Facades\Response::class,
'Route' => Illuminate\Support\Facades\Route::class,
'Schema' => Illuminate\Support\Facades\Schema::class,
'Session' => Illuminate\Support\Facades\Session::class,
'Storage' => Illuminate\Support\Facades\Storage::class,
'Str' => Illuminate\Support\Str::class,
'URL' => Illuminate\Support\Facades\URL::class,
'Validator' => Illuminate\Support\Facades\Validator::class,
'View' => Illuminate\Support\Facades\View::class,
'Image' => Intervention\Image\Facades\Image::class,
'Stripe' => Cartalyst\Stripe\Laravel\Facades\Stripe::class,
],
'deploy_secret' => env('APP_DEPLOY_SECRET'),
'deploy_branch' => env('APP_DEPLOY_BRANCH'),
'debug_blacklist' => [
'_ENV' => [
'_ENV' => [
'APP_KEY',
'DB_USERNAME',
'DB_PASSWORD',
'REDIS_PASSWORD',
'MAIL_PASSWORD',
'PUSHER_APP_KEY',
'PUSHER_APP_SECRET',
'PASSPORT_CLIENT_ID',
'PASSPORT_CLIENT_SECRET',
'AWS_SECRET_ACCESS_KEY',
'AWS_ACCESS_KEY_ID',
'AWS_SECRET_ACCESS_KEY',
'DO_SPACES_KEY',
'DO_SPACES_SECRET',
'WASABI_KEY',
'WASABI_SECRET',
'BACKBLAZE_KEY',
'BACKBLAZE_SECRET',
],
'_SERVER' => [
'APP_KEY',
'DB_USERNAME',
'DB_PASSWORD',
'REDIS_PASSWORD',
'MAIL_PASSWORD',
'PUSHER_APP_KEY',
'PUSHER_APP_SECRET',
'PASSPORT_CLIENT_ID',
'PASSPORT_CLIENT_SECRET',
'AWS_ACCESS_KEY_ID',
'AWS_SECRET_ACCESS_KEY',
'AWS_ACCESS_KEY_ID',
'DO_SPACES_KEY',
'DO_SPACES_SECRET',
'WASABI_KEY',
'WASABI_SECRET',
'BACKBLAZE_KEY',
'BACKBLAZE_SECRET',
],
'_POST' => [
'_POST' => [
'password',
],
],

129
config/cashier.php Normal file
View File

@@ -0,0 +1,129 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Stripe Keys
|--------------------------------------------------------------------------
|
| The Stripe publishable key and secret key give you access to Stripe's
| API. The "publishable" key is typically used when interacting with
| Stripe.js while the "secret" key accesses private API endpoints.
|
*/
'key' => env('STRIPE_KEY'),
'secret' => env('STRIPE_SECRET'),
/*
|--------------------------------------------------------------------------
| Cashier Path
|--------------------------------------------------------------------------
|
| This is the base URI path where Cashier's views, such as the payment
| verification screen, will be available from. You're free to tweak
| this path according to your preferences and application design.
|
*/
'path' => env('CASHIER_PATH', 'stripe'),
/*
|--------------------------------------------------------------------------
| Stripe Webhooks
|--------------------------------------------------------------------------
|
| Your Stripe webhook secret is used to prevent unauthorized requests to
| your Stripe webhook handling controllers. The tolerance setting will
| check the drift between the current time and the signed request's.
|
*/
'webhook' => [
'secret' => env('STRIPE_WEBHOOK_SECRET'),
'tolerance' => env('STRIPE_WEBHOOK_TOLERANCE', 300),
],
/*
|--------------------------------------------------------------------------
| Cashier Model
|--------------------------------------------------------------------------
|
| This is the model in your application that implements the Billable trait
| provided by Cashier. It will serve as the primary model you use while
| interacting with Cashier related methods, subscriptions, and so on.
|
*/
'model' => env('CASHIER_MODEL', App\User::class),
/*
|--------------------------------------------------------------------------
| Currency
|--------------------------------------------------------------------------
|
| This is the default currency that will be used when generating charges
| from your application. Of course, you are welcome to use any of the
| various world currencies that are currently supported via Stripe.
|
*/
'currency' => env('CASHIER_CURRENCY', 'usd'),
/*
|--------------------------------------------------------------------------
| Currency Locale
|--------------------------------------------------------------------------
|
| This is the default locale in which your money values are formatted in
| for display. To utilize other locales besides the default en locale
| verify you have the "intl" PHP extension installed on the system.
|
*/
'currency_locale' => env('CASHIER_CURRENCY_LOCALE', 'en'),
/*
|--------------------------------------------------------------------------
| Payment Confirmation Notification
|--------------------------------------------------------------------------
|
| If this setting is enabled, Cashier will automatically notify customers
| whose payments require additional verification. You should listen to
| Stripe's webhooks in order for this feature to function correctly.
|
*/
'payment_notification' => env('CASHIER_PAYMENT_NOTIFICATION'),
/*
|--------------------------------------------------------------------------
| Invoice Paper Size
|--------------------------------------------------------------------------
|
| This option is the default paper size for all invoices generated using
| Cashier. You are free to customize this settings based on the usual
| paper size used by the customers using your Laravel applications.
|
| Supported sizes: 'letter', 'legal', 'A4'
|
*/
'paper' => env('CASHIER_PAPER', 'letter'),
/*
|--------------------------------------------------------------------------
| Stripe Logger
|--------------------------------------------------------------------------
|
| This setting defines which logging channel will be used by the Stripe
| library to write log messages. You are free to specify any of your
| logging channels listed inside the "logging" configuration file.
|
*/
'logger' => env('CASHIER_LOGGER'),
];

102
config/content.php Normal file
View File

@@ -0,0 +1,102 @@
<?php
return [
'pages' => [
[
'visibility' => 1,
'title' => 'Terms of Service',
'slug' => 'terms-of-service',
'content' => 'Laoreet cum hendrerit iaculis arcu phasellus congue et elementum, pharetra risus imperdiet aptent posuere rutrum parturient blandit, dapibus tellus ridiculus potenti aliquam sociis turpis. Nullam commodo eget laoreet risus cursus vel placerat, in dapibus sociis gravida faucibus sodales, fringilla potenti elit semper iaculis ullamcorper. Dignissim vulputate pretium montes pellentesque mollis, consectetur adipiscing curabitur semper sem rhoncus, litora viverra curae proin.',
],
[
'visibility' => 1,
'title' => 'Privacy Policy',
'slug' => 'privacy-policy',
'content' => 'Sit orci justo augue maecenas laoreet consectetur natoque magnis in viverra sagittis, himenaeos urna facilisis mus proin primis diam accumsan tristique inceptos. Primis quisque posuere sit praesent lobortis feugiat semper convallis facilisis, vivamus gravida ligula nostra curae eu donec duis parturient senectus, arcu dolor viverra penatibus natoque cum nisi commodo. Litora sociis mauris justo nullam suspendisse mattis maecenas nascetur congue phasellus cras ultricies posuere donec, dapibus egestas diam lacus ornare montes senectus tincidunt eu taciti sed consequat.',
],
[
'visibility' => 1,
'title' => 'Cookie Policy',
'slug' => 'cookie-policy',
'content' => 'Metus penatibus ligula dolor natoque non habitasse laoreet facilisis, libero vivamus eget semper vulputate interdum integer, phasellus lorem enim blandit consectetur nullam sollicitudin. Hendrerit interdum luctus ut in molestie himenaeos eros cum laoreet parturient est, eu lectus hac et netus viverra dictumst congue elit sem senectus litora, fames scelerisque adipiscing inceptos fringilla montes sociosqu suscipit auctor potenti. Elementum lacus vulputate viverra ac morbi ligula ipsum facilisi, sit eu imperdiet lacinia congue dis vitae.',
],
],
'content' => [
[
'name' => 'section_features',
'value' => '1',
],
[
'name' => 'section_feature_boxes',
'value' => '1',
],
[
'name' => 'section_pricing_content',
'value' => '1',
],
[
'name' => 'section_get_started',
'value' => '1',
],
[
'name' => 'header_title',
'value' => 'Simple <span style="color: #41B883">&</span> Powerful Personal Cloud Storage',
],
[
'name' => 'header_description',
'value' => 'Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Trully freedom.',
],
[
'name' => 'features_title',
'value' => 'The Fastest Growing <span style="color: #41B883">File Manager</span> on the CodeCanyon Market',
],
[
'name' => 'features_description',
'value' => 'Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Trully freedom.',
],
[
'name' => 'feature_title_1',
'value' => 'Truly Freedom',
],
[
'name' => 'feature_description_1',
'value' => 'You have full control over VueFileManager, no third authorities will control your service or usage, only you.',
],
[
'name' => 'feature_title_2',
'value' => 'The Sky is the Limit',
],
[
'name' => 'feature_description_2',
'value' => 'VueFileManager is cloud storage software. You have to install and running application on your own server hosting.',
],
[
'name' => 'feature_title_3',
'value' => 'No Monthly Fees',
],
[
'name' => 'feature_description_3',
'value' => 'When you running VueFileManager on your own server hosting, anybody can\'t control your content or resell your user data. Your data is safe.',
],
[
'name' => 'pricing_title',
'value' => 'Pick the <span style="color: #41B883;">Best Plan</span> For Your Needs',
],
[
'name' => 'pricing_description',
'value' => 'Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Trully freedom.',
],
[
'name' => 'get_started_title',
'value' => 'Ready to Get <span style="color: #41B883">Started</span><br> With Us?',
],
[
'name' => 'get_started_description',
'value' => 'Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Trully freedom.',
],
[
'name' => 'footer_content',
'value' => '© 2020 Simple & Powerful Personal Cloud Storage. Developed by <a href="https://hi5ve.digital" target="_blank">Hi5Ve.Digital</a>',
],
],
];

View File

@@ -61,7 +61,7 @@ return [
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'url' => env('AWS_URL'),
'endpoint' => env('AWS_URL'),
],
'spaces' => [
@@ -73,6 +73,24 @@ return [
'bucket' => env('DO_SPACES_BUCKET'),
],
'wasabi' => [
'driver' => 's3',
'key' => env('WASABI_KEY'),
'secret' => env('WASABI_SECRET'),
'endpoint' => env('WASABI_ENDPOINT'),
'region' => env('WASABI_REGION'),
'bucket' => env('WASABI_BUCKET'),
],
'backblaze' => [
'driver' => 's3',
'key' => env('BACKBLAZE_KEY'),
'secret' => env('BACKBLAZE_SECRET'),
'endpoint' => env('BACKBLAZE_ENDPOINT'),
'region' => env('BACKBLAZE_REGION'),
'bucket' => env('BACKBLAZE_BUCKET'),
],
],
];

View File

@@ -34,5 +34,4 @@ return [
'client_id' => env('PASSPORT_CLIENT_ID'),
'client_secret' => env('PASSPORT_CLIENT_SECRET'),
],
];

View File

@@ -166,7 +166,7 @@ return [
|
*/
'secure' => env('SESSION_SECURE_COOKIE', false),
'secure' => env('SESSION_SECURE_COOKIE', null),
/*
|--------------------------------------------------------------------------

View File

@@ -2,20 +2,8 @@
return [
'version' => '1.4.2',
'version' => '1.7.6',
// Your app name
'app_name' => 'VueFileManager',
// Your app logo
'app_logo' => '/assets/images/hero.svg',
// Enable or disable user account registration
'registration' => true,
// Limit your storage size for every user if this option is enabled
'limit_storage_by_capacity' => true,
// Define user storage capacity in MB. E.g. value 2000 is 2.00GB
'user_storage_capacity' => 300,
// 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,12 @@
<?php
/** @var \Illuminate\Database\Eloquent\Factory $factory */
use App\Setting;
use Faker\Generator as Faker;
$factory->define(Setting::class, function (Faker $faker) {
return [
//
];
});

View File

@@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateOauthAuthCodesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('oauth_auth_codes', function (Blueprint $table) {
$table->string('id', 100)->primary();
$table->unsignedBigInteger('user_id')->index();
$table->unsignedBigInteger('client_id');
$table->text('scopes')->nullable();
$table->boolean('revoked');
$table->dateTime('expires_at')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('oauth_auth_codes');
}
}

View File

@@ -0,0 +1,37 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateOauthAccessTokensTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('oauth_access_tokens', function (Blueprint $table) {
$table->string('id', 100)->primary();
$table->unsignedBigInteger('user_id')->nullable()->index();
$table->unsignedBigInteger('client_id');
$table->string('name')->nullable();
$table->text('scopes')->nullable();
$table->boolean('revoked');
$table->timestamps();
$table->dateTime('expires_at')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('oauth_access_tokens');
}
}

Some files were not shown because too many files have changed in this diff Show More