src folder refactoring

This commit is contained in:
Peter Papp
2021-07-18 14:43:50 +02:00
parent fc952d089b
commit 5046071f3a
134 changed files with 11976 additions and 42 deletions

View File

@@ -0,0 +1,9 @@
<?php
namespace App;
use Illuminate\Foundation\Application;
class BaseApplication extends Application
{
protected $namespace = 'App\\';
}

View File

@@ -0,0 +1,895 @@
<?php
namespace App\Console\Commands;
use App\Models\File;
use App\Models\User;
use App\Models\Share;
use App\Models\Folder;
use App\Models\Setting;
use Illuminate\Support\Str;
use App\Services\SetupService;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;
use Illuminate\Foundation\Testing\WithFaker;
class SetupDevEnvironment extends Command
{
use WithFaker;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'setup:dev';
protected $license = 'Extended';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Set up development environment with demo data';
private $setup;
public function __construct()
{
parent::__construct();
$this->setUpFaker();
$this->setup = resolve(SetupService::class);
}
/**
* Execute the console command.
* return @void
*/
public function handle(): void
{
$this->info('Setting up development environment');
$this->info('Creating system directories...');
$this->setup->create_directories();
$this->info('Migrating Databases...');
$this->migrate_and_generate();
$this->info('Storing default settings and content...');
$this->store_default_settings();
$this->setup->seed_default_pages();
$this->setup->seed_default_settings($this->license);
$this->setup->seed_default_language();
$this->info('Creating default admin...');
$this->create_admin();
$this->info('Creating demo users...');
$this->create_demo_users();
$this->info('Creating default admin content...');
$this->create_admin_default_content();
$this->create_share_records();
$this->info('Clearing application cache...');
$this->clear_cache();
$this->info('Dispatching jobs...');
$this->call('queue:work', [
'--stop-when-empty' => true,
]);
$this->info('Everything is done, congratulations! 🥳🥳🥳');
}
/**
* Create default admin account
*/
private function create_admin(): void
{
$user = User::forceCreate([
'role' => 'admin',
'email' => 'howdy@hi5ve.digital',
'password' => bcrypt('vuefilemanager'),
'email_verified_at' => now(),
]);
$user
->settings()
->create([
'avatar' => 'avatars/avatar-01.png',
'storage_capacity' => 5,
'name' => 'Jane Doe',
'address' => $this->faker->address,
'state' => $this->faker->state,
'city' => $this->faker->city,
'postal_code' => $this->faker->postcode,
'country' => $this->faker->randomElement(['SK', 'CZ', 'DE', 'FR']),
'phone_number' => $this->faker->phoneNumber,
'timezone' => $this->faker->randomElement(['+1.0', '+2.0', '+3.0']),
]);
Storage::putFileAs('avatars', storage_path('demo/avatars/avatar-01.png'), 'avatar-01.png', 'private');
// Show user credentials
$this->info('Default admin account created. Email: howdy@hi5ve.digital and Password: vuefilemanager');
}
/**
* Create default admin account
*/
private function create_demo_users(): void
{
collect([
[
'avatar' => 'avatar-02.png',
],
[
'avatar' => 'avatar-03.png',
],
])->each(function ($user) {
$newbie = User::forceCreate([
'role' => 'user',
'email' => $this->faker->email,
'password' => bcrypt('vuefilemanager'),
'email_verified_at' => now(),
]);
$newbie
->settings()
->create([
'avatar' => "avatars/{$user['avatar']}",
'storage_capacity' => 5,
'name' => $this->faker->name,
'address' => $this->faker->address,
'state' => $this->faker->state,
'city' => $this->faker->city,
'postal_code' => $this->faker->postcode,
'country' => $this->faker->randomElement(['SK', 'CZ', 'DE', 'FR']),
'phone_number' => $this->faker->phoneNumber,
'timezone' => $this->faker->randomElement(['+1.0', '+2.0', '+3.0']),
]);
Storage::putFileAs('avatars', storage_path("demo/avatars/{$user['avatar']}"), $user['avatar'], 'private');
$this->info("Generated user with email: $newbie->email and Password: vuefilemanager");
});
}
/**
* Create default admin content
*/
private function create_admin_default_content(): void
{
$user = User::whereEmail('howdy@hi5ve.digital')
->first();
// 1.
$shared_folder = Folder::factory(Folder::class)
->create([
'user_id' => $user->id,
'author' => 'user',
'name' => 'Shared Folder',
'emoji' => [
'codes' => '1F680',
'char' => '🚀',
'name' => 'rocket',
'category' => 'Travel & Places (transport-air)',
'group' => 'Travel & Places',
'subgroup' => 'transport-air',
],
'created_at' => now(),
]);
Share::factory(Share::class)
->create([
'type' => 'folder',
'item_id' => $shared_folder->id,
'user_id' => $user->id,
'permission' => 'editor',
'is_protected' => false,
'password' => null,
'expire_in' => null,
]);
$peters_files = Folder::factory(Folder::class)
->create([
'user_id' => $user->id,
'parent_id' => $shared_folder->id,
'author' => 'visitor',
'name' => "Peter's Files",
]);
// 2.
$random_pics = Folder::factory(Folder::class)
->create([
'user_id' => $user->id,
'author' => 'user',
'name' => 'Random Pics',
'emoji' => [
'codes' => '1F4F7',
'char' => '📷',
'name' => 'camera',
'category' => 'Objects (light & video)',
'group' => 'Objects',
'subgroup' => 'light & video',
],
'created_at' => now()->subMinutes(1),
]);
$nature = Folder::factory(Folder::class)
->create([
'user_id' => $user->id,
'parent_id' => $random_pics->id,
'author' => 'user',
'name' => 'Nature',
'emoji' => [
'codes' => '26F0',
'char' => '⛰',
'name' => 'mountain',
'category' => 'Travel & Places (place-geographic)',
'group' => 'Travel & Places',
'subgroup' => 'place-geographic',
],
]);
$apartments = Folder::factory(Folder::class)
->create([
'user_id' => $user->id,
'parent_id' => $random_pics->id,
'author' => 'user',
'name' => 'Apartments',
'emoji' => [
'codes' => '1F3E0',
'char' => '🏠',
'name' => 'house',
'category' => 'Travel & Places (place-building)',
'group' => 'Travel & Places',
'subgroup' => 'place-building',
],
]);
// 3.
$playable_media = Folder::factory(Folder::class)
->create([
'user_id' => $user->id,
'author' => 'user',
'name' => 'Playable Media',
'created_at' => now()->subMinutes(2),
]);
$video = Folder::factory(Folder::class)
->create([
'user_id' => $user->id,
'parent_id' => $playable_media->id,
'author' => 'user',
'name' => 'Video',
]);
$audio = Folder::factory(Folder::class)
->create([
'user_id' => $user->id,
'parent_id' => $playable_media->id,
'author' => 'user',
'name' => 'Audio',
]);
// 4.
$multi_level = Folder::factory(Folder::class)
->create([
'user_id' => $user->id,
'author' => 'user',
'name' => 'Multi Level Folder',
'created_at' => now()->subMinutes(3),
]);
$first_level = Folder::factory(Folder::class)
->create([
'user_id' => $user->id,
'parent_id' => $multi_level->id,
'author' => 'user',
'name' => 'First Level',
]);
$second_level = Folder::factory(Folder::class)
->create([
'user_id' => $user->id,
'parent_id' => $first_level->id,
'author' => 'user',
'name' => 'Second Level',
]);
$third_level = Folder::factory(Folder::class)
->create([
'user_id' => $user->id,
'parent_id' => $second_level->id,
'author' => 'user',
'name' => 'Third Level',
]);
// 5.
$documents = Folder::factory(Folder::class)
->create([
'user_id' => $user->id,
'author' => 'user',
'name' => 'Documents',
'created_at' => now()->subMinutes(4),
]);
Share::factory(Share::class)
->create([
'type' => 'folder',
'item_id' => $documents->id,
'user_id' => $user->id,
'permission' => 'editor',
'is_protected' => false,
'password' => null,
'expire_in' => null,
]);
// 6.
$videohive = Folder::factory(Folder::class)
->create([
'user_id' => $user->id,
'author' => 'user',
'name' => 'Videohive by MakingCG',
'created_at' => now()->subMinutes(5),
]);
$user
->favouriteFolders()
->sync([
$shared_folder->id,
$random_pics->id,
$documents->id,
$peters_files->id,
]);
// Get documents to root directory
collect([
[
'name' => 'Random Document',
'basename' => 'Licence.pdf',
'mimetype' => 'pdf',
],
[
'name' => 'School Report',
'basename' => 'Project Notes.pdf',
'mimetype' => 'pdf',
],
[
'name' => 'Personal Savings',
'basename' => 'School Report.pages',
'mimetype' => 'pages',
],
[
'name' => 'Top Secret Files',
'basename' => 'Stories of the Night Skies.pages',
'mimetype' => 'pages',
],
])
->each(function ($file) use ($user) {
$basename = Str::random(12) . '-' . $file['basename'];
// Copy file into app storage
Storage::putFileAs("files/$user->id", storage_path("demo/documents/{$file['basename']}"), $basename, 'private');
// Create file record
File::create([
'folder_id' => null,
'user_id' => $user->id,
'name' => $file['name'],
'basename' => $basename,
'type' => 'file',
'author' => 'user',
'mimetype' => $file['mimetype'],
'filesize' => rand(1000000, 4000000),
'created_at' => now()->subMinutes(rand(1, 5)),
]);
});
// Get documents to documents folder
collect([
[
'name' => 'Home Improvement',
'basename' => 'Licence.pdf',
'mimetype' => 'pdf',
],
[
'name' => 'Project Notes',
'basename' => 'Project Notes.pdf',
'mimetype' => 'pdf',
],
[
'name' => 'Personal Savings',
'basename' => 'School Report.pages',
'mimetype' => 'pages',
],
[
'name' => 'License',
'basename' => 'Stories of the Night Skies.pages',
'mimetype' => 'pages',
],
])
->each(function ($file) use ($user, $documents) {
$basename = Str::random(12) . '-' . $file['basename'];
// Copy file into app storage
Storage::putFileAs("files/$user->id", storage_path("demo/documents/{$file['basename']}"), $basename, 'private');
// Create file record
File::create([
'folder_id' => $documents->id,
'user_id' => $user->id,
'name' => $file['name'],
'basename' => $basename,
'type' => 'file',
'author' => 'user',
'mimetype' => $file['mimetype'],
'filesize' => rand(1000000, 4000000),
'created_at' => now()->subMinutes(rand(1, 5)),
]);
});
// Get documents to shared folder
collect([
[
'name' => 'Home plan',
'basename' => 'Licence.pdf',
'mimetype' => 'pdf',
],
[
'name' => 'Software Licence',
'basename' => 'Project Notes.pdf',
'mimetype' => 'pdf',
],
])
->each(function ($file) use ($user, $shared_folder) {
$basename = Str::random(12) . '-' . $file['basename'];
// Copy file into app storage
Storage::putFileAs("files/$user->id", storage_path("demo/documents/{$file['basename']}"), $basename, 'private');
// Create file record
File::create([
'folder_id' => $shared_folder->id,
'user_id' => $user->id,
'name' => $file['name'],
'basename' => $basename,
'type' => 'file',
'author' => 'user',
'mimetype' => $file['mimetype'],
'filesize' => rand(1000000, 4000000),
'created_at' => now()->subMinutes(rand(1, 5)),
]);
});
// Get documents to peter's files folder
collect([
[
'name' => 'Project Backup',
'basename' => 'Licence.pdf',
'mimetype' => 'pdf',
],
[
'name' => 'Yearly report',
'basename' => 'Project Notes.pdf',
'mimetype' => 'pdf',
],
[
'name' => 'Work Update',
'basename' => 'School Report.pages',
'mimetype' => 'pages',
],
[
'name' => 'Person Writing on Notebook',
'basename' => 'Stories of the Night Skies.pages',
'mimetype' => 'pages',
],
[
'name' => 'Blank Business Composition Computer',
'basename' => 'Licence.pdf',
'mimetype' => 'pdf',
],
[
'name' => '2020 April - Export',
'basename' => 'Project Notes.pdf',
'mimetype' => 'pdf',
],
[
'name' => 'Ballpen Blur Close Up Computer',
'basename' => 'School Report.pages',
'mimetype' => 'pages',
],
])
->each(function ($file) use ($user, $peters_files) {
$basename = Str::random(12) . '-' . $file['basename'];
// Copy file into app storage
Storage::putFileAs("files/$user->id", storage_path("demo/documents/{$file['basename']}"), $basename, 'private');
// Create file record
File::create([
'folder_id' => $peters_files->id,
'user_id' => $user->id,
'name' => $file['name'],
'basename' => $basename,
'type' => 'file',
'author' => 'visitor',
'mimetype' => $file['mimetype'],
'filesize' => rand(1000000, 4000000),
'created_at' => now()->subMinutes(rand(1, 5)),
]);
});
// Get videos
collect([
'Apple Watch App Video Promotion.mp4',
'Professional 3D Device Pack for Element 3D.mp4',
'Smart Watch 3D Device Pack for Element 3D.mp4',
'Sphere Bound 3D Titles.mp4',
])
->each(function ($file) use ($user, $videohive) {
$basename = Str::random(12) . '-' . $file;
// Copy file into app storage
Storage::putFileAs("files/$user->id", storage_path("demo/video/$file"), $basename, 'private');
// Create file record
File::create([
'folder_id' => $videohive->id,
'user_id' => $user->id,
'name' => $file,
'basename' => $basename,
'type' => 'video',
'author' => 'user',
'mimetype' => 'mp4',
'filesize' => rand(1000000, 4000000),
'created_at' => now()->subMinutes(rand(1, 5)),
]);
});
// Get video into video folder
collect([
'Apple Watch App Video Promotion.mp4',
])
->each(function ($file) use ($user, $video) {
$basename = Str::random(12) . '-' . $file;
// Copy file into app storage
Storage::putFileAs("files/$user->id", storage_path("demo/video/$file"), $basename, 'private');
// Create file record
File::create([
'folder_id' => $video->id,
'user_id' => $user->id,
'name' => $file,
'basename' => $basename,
'type' => 'video',
'author' => 'user',
'mimetype' => 'mp4',
'filesize' => rand(1000000, 4000000),
'created_at' => now()->subMinutes(rand(1, 5)),
]);
});
// Get audios
collect([
'D-Block & S-te-Fan - Bla Bla.mp3',
])
->each(function ($file) use ($user, $audio) {
$basename = Str::random(12) . '-' . $file;
// Copy file into app storage
Storage::putFileAs("files/$user->id", storage_path("demo/audio/$file"), $basename, 'private');
// Create file record
File::create([
'folder_id' => $audio->id,
'user_id' => $user->id,
'name' => $file,
'basename' => $basename,
'type' => 'audio',
'author' => 'user',
'mimetype' => 'mp3',
'filesize' => rand(1000000, 4000000),
'created_at' => now()->subMinutes(rand(1, 5)),
]);
});
// Get meme gallery
collect([
'Eggcited bro.jpg',
'Get a Rest.jpg',
'Get Your Shit Together.jpg',
'Happiness is when you are right beside me.jpg',
'Have a Nice Day.jpg',
'It Works On My Machine.jpg',
'I am Just Trying to shine.jpg',
'It Works On My Machine.jpg',
'Missing you It is Pig Time.jpg',
'Sofishticated.jpg',
'whaaaaat.jpg',
'You Are My Sunshine.jpg',
])
->each(function ($file) use ($user) {
$basename = Str::random(12) . '-' . $file;
// Copy file into app storage
Storage::putFileAs("files/$user->id", storage_path("demo/images/memes/$file"), $basename, 'private');
Storage::putFileAs("files/$user->id", storage_path("demo/images/memes/thumbnail-$file"), "thumbnail-$basename", 'private');
// Create file record
File::create([
'folder_id' => null,
'user_id' => $user->id,
'name' => $file,
'basename' => $basename,
'type' => 'image',
'author' => 'user',
'mimetype' => 'jpg',
'filesize' => rand(1000000, 4000000),
'thumbnail' => "thumbnail-$basename",
'created_at' => now()->subMinutes(rand(1, 5)),
]);
});
// Get apartments gallery
collect([
'Apartment Architecture Ceiling Chairs.jpg',
'Apartment Chair.jpg',
'Apartment Contemporary Couch Curtains.jpg',
'Brown Wooden Center Table.jpg',
'Home.jpg',
'Kitchen Appliances.jpg',
'Kitchen Island.jpg',
])
->each(function ($file) use ($user, $apartments) {
$basename = Str::random(12) . '-' . $file;
// Copy file into app storage
Storage::putFileAs("files/$user->id", storage_path("demo/images/apartments/$file"), $basename, 'private');
Storage::putFileAs("files/$user->id", storage_path("demo/images/apartments/thumbnail-$file"), "thumbnail-$basename", 'private');
// Create file record
File::create([
'folder_id' => $apartments->id,
'user_id' => $user->id,
'name' => $file,
'basename' => $basename,
'type' => 'image',
'author' => 'user',
'mimetype' => 'jpg',
'filesize' => rand(1000000, 4000000),
'thumbnail' => "thumbnail-$basename",
'created_at' => now()->subMinutes(rand(1, 5)),
]);
});
// Get nature gallery
collect([
'Bird Patterncolorful Green.jpg',
'Close Up Of Peacock.jpg',
'Close Up Photography Of Tiger.jpg',
'Cold Nature Cute Ice.jpg',
'Landscape Photo of Forest.jpg',
'Photo of Hawksbill Sea Turtle.jpg',
'Photo Of Reindeer in The Snow.jpg',
'View Of Elephant in Water.jpg',
'Waterfall Between Trees.jpg',
'Wildlife Photography of Elephant During Golden Hour.jpg',
'Yellow Animal Eyes Fur.jpg',
])
->each(function ($file) use ($user, $nature) {
$basename = Str::random(12) . '-' . $file;
// Copy file into app storage
Storage::putFileAs("files/$user->id", storage_path("demo/images/nature/$file"), $basename, 'private');
Storage::putFileAs("files/$user->id", storage_path("demo/images/nature/thumbnail-$file"), "thumbnail-$basename", 'private');
// Create file record
File::create([
'folder_id' => $nature->id,
'user_id' => $user->id,
'name' => $file,
'basename' => $basename,
'type' => 'image',
'author' => 'user',
'mimetype' => 'jpg',
'filesize' => rand(1000000, 4000000),
'thumbnail' => "thumbnail-$basename",
'created_at' => now()->subMinutes(rand(1, 5)),
]);
});
}
private function create_share_records(): void
{
$user = User::whereEmail('howdy@hi5ve.digital')
->first();
$images = File::whereType('image')
->whereFolderId(null)
->take(3)
->pluck('id');
$images->each(function ($id) use ($user) {
Share::create([
'user_id' => $user->id,
'item_id' => $id,
'type' => 'file',
'is_protected' => false,
'permission' => 'editor',
'password' => null,
'expire_in' => null,
]);
});
$files = File::whereType('file')
->whereFolderId(null)
->take(2)
->pluck('id');
$files->each(function ($id) use ($user) {
Share::create([
'user_id' => $user->id,
'item_id' => $id,
'type' => 'file',
'is_protected' => false,
'permission' => 'editor',
'password' => null,
'expire_in' => null,
]);
});
}
/**
* Store main app settings into database
*/
private function store_default_settings(): void
{
// Get options
collect([
[
'name' => 'setup_wizard_database',
'value' => 1,
],
[
'name' => 'app_title',
'value' => 'VueFileManager',
],
[
'name' => 'app_description',
'value' => 'Your self-hosted storage cloud software powered by Laravel and Vue',
],
[
'name' => 'app_logo',
'value' => 'system/logo.svg',
],
[
'name' => 'app_logo_horizontal',
'value' => 'system/logo-horizontal.svg',
],
[
'name' => 'app_favicon',
'value' => 'system/favicon.png',
],
[
'name' => 'app_og_image',
'value' => 'system/og-image.jpg',
],
[
'name' => 'app_touch_icon',
'value' => 'system/touch-icon.png',
],
[
'name' => 'google_analytics',
'value' => '',
],
[
'name' => 'contact_email',
'value' => '',
],
[
'name' => 'registration',
'value' => 1,
],
[
'name' => 'user_verification',
'value' => 1,
],
[
'name' => 'payments_active',
'value' => 1,
],
[
'name' => 'storage_limitation',
'value' => 1,
],
[
'name' => 'storage_default',
'value' => 5,
],
[
'name' => 'setup_wizard_success',
'value' => 1,
],
[
'name' => 'license',
'value' => $this->license,
],
[
'name' => 'purchase_code',
'value' => '26b889eb-3602-4bf2-beb3-3sc378fcf484',
],
[
'name' => 'billing_address',
'value' => 'Palo Alto 20',
],
[
'name' => 'billing_city',
'value' => 'Palo Alto',
],
[
'name' => 'billing_country',
'value' => 'US',
],
[
'name' => 'billing_name',
'value' => 'VueFileManager Inc.',
],
[
'name' => 'billing_phone_number',
'value' => '312343141243214',
],
[
'name' => 'billing_postal_code',
'value' => '43213',
],
[
'name' => 'billing_state',
'value' => 'California',
],
[
'name' => 'billing_vat_number',
'value' => '41241241234',
],
])->each(function ($col) {
Setting::forceCreate([
'name' => $col['name'],
'value' => $col['value'],
]);
});
// Get system images
collect(['logo.svg', 'logo-horizontal.svg', 'favicon.png', 'og-image.jpg', 'touch-icon.png'])
->each(function ($file) {
Storage::putFileAs('system', storage_path("demo/app/$file"), $file, 'private');
});
}
/**
* Migrate database and generate application keys
*/
private function migrate_and_generate(): void
{
// Migrate database
$this->call('migrate:fresh', [
'--force' => true,
]);
// Generate app key
$this->call('key:generate', [
'--force' => true,
]);
}
/**
* Clear app cache
*/
private function clear_cache(): void
{
$this->call('cache:clear');
$this->call('config:clear');
$this->call('view:clear');
}
}

View File

@@ -0,0 +1,227 @@
<?php
namespace App\Console\Commands;
use App\Models\User;
use App\Models\Setting;
use App\Services\SetupService;
use Illuminate\Console\Command;
class SetupProdEnvironment extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'setup:prod';
protected $license = 'Extended';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Set up production environment';
private $setup;
public function __construct()
{
parent::__construct();
$this->setup = resolve(SetupService::class);
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$this->info('Setting up production environment');
$this->info('Creating system directories...');
$this->setup->create_directories();
$this->info('Migrating Databases...');
$this->migrate_and_generate();
$this->info('Storing default settings and content...');
$this->store_default_settings();
$this->setup->seed_default_pages();
$this->setup->seed_default_settings($this->license);
$this->setup->seed_default_language();
$this->info('Creating default admin...');
$this->create_admin();
$this->info('Clearing application cache...');
$this->clear_cache();
$this->info('Everything is done, congratulations! 🥳🥳🥳');
}
/**
* Store main app settings into database
*/
private function store_default_settings(): void
{
// Get options
collect([
[
'name' => 'setup_wizard_database',
'value' => 1,
],
[
'name' => 'app_title',
'value' => 'VueFileManager',
],
[
'name' => 'app_description',
'value' => 'Your self-hosted storage cloud software powered by Laravel and Vue',
],
[
'name' => 'app_logo',
'value' => null,
],
[
'name' => 'app_logo_horizontal',
'value' => null,
],
[
'name' => 'app_favicon',
'value' => null,
],
[
'name' => 'app_og_image',
'value' => null,
],
[
'name' => 'app_touch_icon',
'value' => null,
],
[
'name' => 'google_analytics',
'value' => null,
],
[
'name' => 'contact_email',
'value' => null,
],
[
'name' => 'registration',
'value' => 0,
],
[
'name' => 'user_verification',
'value' => 1,
],
[
'name' => 'storage_limitation',
'value' => 1,
],
[
'name' => 'storage_default',
'value' => 5,
],
[
'name' => 'setup_wizard_success',
'value' => 1,
],
[
'name' => 'license',
'value' => $this->license,
],
[
'name' => 'purchase_code',
'value' => '26b889eb-3602-4bf2-beb3-3sc378fcf484',
],
[
'name' => 'billing_address',
'value' => null,
],
[
'name' => 'billing_city',
'value' => null,
],
[
'name' => 'billing_country',
'value' => null,
],
[
'name' => 'billing_name',
'value' => null,
],
[
'name' => 'billing_phone_number',
'value' => null,
],
[
'name' => 'billing_postal_code',
'value' => null,
],
[
'name' => 'billing_state',
'value' => null,
],
[
'name' => 'billing_vat_number',
'value' => null,
],
])->each(function ($col) {
Setting::forceCreate([
'name' => $col['name'],
'value' => $col['value'],
]);
});
}
/**
* Create default admin account
*/
private function create_admin(): void
{
$user = User::forceCreate([
'role' => 'admin',
'email' => 'howdy@hi5ve.digital',
'password' => bcrypt('vuefilemanager'),
'email_verified_at' => now(),
]);
$user
->settings()
->create([
'storage_capacity' => 5,
'name' => 'Admin',
]);
// Show user credentials
$this->info('Default admin account created. Email: howdy@hi5ve.digital and Password: vuefilemanager');
}
/**
* Migrate database and generate application keys
*/
private function migrate_and_generate(): void
{
// Migrate database
$this->call('migrate:fresh', [
'--force' => true,
]);
// Generate app key
$this->call('key:generate', [
'--force' => true,
]);
}
/**
* Clear app cache
*/
private function clear_cache(): void
{
$this->call('cache:clear');
$this->call('config:clear');
$this->call('view:clear');
}
}

View File

@@ -0,0 +1,73 @@
<?php
namespace App\Console;
use App\Services\SchedulerService;
use Illuminate\Console\Scheduling\Schedule;
use App\Console\Commands\SetupDevEnvironment;
use App\Console\Commands\SetupProdEnvironment;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
SetupDevEnvironment::class,
SetupProdEnvironment::class,
];
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
$scheduler = resolve(SchedulerService::class);
$schedule->call(function () use ($scheduler) {
$scheduler->delete_expired_shared_links();
})->everyTenMinutes();
$schedule->call(function () use ($scheduler) {
$scheduler->delete_old_zips();
if (! is_storage_driver(['local'])) {
$scheduler->delete_failed_files();
}
})->everySixHours();
$schedule->call(function () use ($scheduler) {
$scheduler->delete_unverified_users();
})->daily();
// Run queue jobs every minute
$schedule->command('queue:work --stop-when-empty')
->everyMinute()
->withoutOverlapping();
// Backup app database daily
$schedule->command('backup:clean')
->daily()
->at('01:00');
$schedule->command('backup:run --only-db')
->daily()
->at('01:30');
}
/**
* Register the commands for the application.
*
* @return void
*/
protected function commands()
{
$this->load(__DIR__ . '/Commands');
require base_path('routes/console.php');
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace App\Exceptions;
use Throwable;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that are not reported.
*
* @var array
*/
protected $dontReport = [
];
/**
* A list of the inputs that are never flashed for validation exceptions.
*
* @var array
*/
protected $dontFlash = [
'password',
'password_confirmation',
];
/**
* Report or log an exception.
*
* @param \Throwable $exception
* @return void
*
* @throws \Exception
*/
public function report(Throwable $exception)
{
parent::report($exception);
}
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Throwable $exception
* @return \Symfony\Component\HttpFoundation\Response
*
* @throws \Throwable
*/
public function render($request, Throwable $exception)
{
if ($exception instanceof ModelNotFoundException) {
return response()
->redirectTo('/not-found')->setStatusCode(404);
}
return parent::render($request, $exception);
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
}

68
src/App/Http/Kernel.php Normal file
View File

@@ -0,0 +1,68 @@
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* @var array
*/
protected $middleware = [
// \App\Http\Middleware\TrustHosts::class,
\App\Http\Middleware\TrustProxies::class,
\Fruitcake\Cors\HandleCors::class,
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
];
/**
* The application's route middleware groups.
*
* @var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
EnsureFrontendRequestsAreStateful::class,
//'throttle:api',
//\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* @var array
*/
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
];
}

View File

@@ -0,0 +1,53 @@
<?php
namespace App\Providers;
use Illuminate\Support\Facades\App;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
try {
$app_locale = get_setting('language') ?? 'en';
} catch (\PDOException $exception) {
$app_locale = 'en';
}
// Set locale for application
app()->setLocale($app_locale);
// Set locale for carbon dates
setlocale(LC_TIME, $app_locale . '_' . mb_strtoupper($app_locale));
// Get all migrations with all directories
$this->loadMigrationsFrom(
$this->get_migration_paths()
);
}
/**
* @return array
*/
private function get_migration_paths(): array
{
$mainPath = database_path('migrations');
$directories = glob($mainPath . '/*', GLOB_ONLYDIR);
return array_merge([$mainPath], $directories);
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
//use Laravel\Passport\Passport;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
// 'App\Model' => 'App\Policies\ModelPolicy',
];
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
// Define admin maintenance gate
Gate::define('maintenance', function ($user) {
return $user->role === 'admin';
});
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Broadcast;
class BroadcastServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Broadcast::routes();
require base_path('routes/channels.php');
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Event;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
];
/**
* Register any events for your application.
*
* @return void
*/
public function boot()
{
parent::boot();
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace App\Providers;
use Illuminate\Http\Request;
use Laravel\Fortify\Fortify;
use Illuminate\Support\ServiceProvider;
use Illuminate\Cache\RateLimiting\Limit;
use App\Actions\Fortify\ResetUserPassword;
use App\Actions\Fortify\UpdateUserPassword;
use Illuminate\Support\Facades\RateLimiter;
use App\Actions\Fortify\UpdateUserProfileInformation;
class FortifyServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Fortify::updateUserProfileInformationUsing(UpdateUserProfileInformation::class);
Fortify::updateUserPasswordsUsing(UpdateUserPassword::class);
Fortify::resetUserPasswordsUsing(ResetUserPassword::class);
RateLimiter::for('login', function (Request $request) {
return Limit::perMinute(20)->by($request->email.$request->ip());
});
RateLimiter::for('two-factor', function (Request $request) {
return Limit::perMinute(5)->by($request->session()->get('login.id'));
});
}
}

View File

@@ -0,0 +1,123 @@
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
class RouteServiceProvider extends ServiceProvider
{
/**
* This namespace is applied to your controller routes.
*
* In addition, it is set as the URL generator's root namespace.
*
* @var string
*/
protected $namespace = null;
/**
* The path to the "home" route for your application.
*
* @var string
*/
public const HOME = '/home';
/**
* Define the routes for the application.
*
* @return void
*/
public function map()
{
$this->mapApiRoutes();
$this->mapShareRoutes();
$this->mapAdminApiRoutes();
$this->mapSetupWizardApiRoutes();
$this->mapUserApiRoutes();
$this->mapMaintenanceRoutes();
$this->mapFileRoutes();
$this->mapWebRoutes();
}
/**
* Define the "web" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
*
* @return void
*/
protected function mapWebRoutes()
{
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
}
protected function mapMaintenanceRoutes()
{
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/maintenance.php'));
}
protected function mapFileRoutes()
{
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/file.php'));
}
/**
* Define the "api" routes for the application.
*
* These routes are typically stateless.
*
* @return void
*/
protected function mapApiRoutes()
{
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
}
protected function mapShareRoutes()
{
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/share.php'));
}
protected function mapAdminApiRoutes()
{
Route::prefix('api/admin')
->middleware(['api', 'auth:sanctum'])
->namespace($this->namespace)
->group(base_path('routes/admin.php'));
}
protected function mapUserApiRoutes()
{
Route::prefix('api/user')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/user.php'));
}
protected function mapSetupWizardApiRoutes()
{
Route::prefix('api/setup')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/setup.php'));
}
}

View File

@@ -0,0 +1,79 @@
<?php
namespace App\Actions\Fortify;
use App\Models\User;
use App\Models\Setting;
use App\Models\UserSettings;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Validation\Rule;
use App\Http\Controllers\Controller;
use Illuminate\Auth\Events\Registered;
use Illuminate\Support\Facades\Validator;
use Illuminate\Contracts\Auth\StatefulGuard;
class CreateNewUserAction extends Controller
{
use PasswordValidationRules;
public function __construct(
protected StatefulGuard $guard
) {
}
/**
* Validate and create a newly registered user.
*/
public function __invoke(Request $request): Response
{
$settings = Setting::whereIn('name', [
'storage_default', 'registration',
])
->pluck('value', 'name');
// Check if account registration is enabled
if (! intval($settings['registration'])) {
abort(401);
}
Validator::make($request->all(), [
'name' => ['required', 'string', 'max:255'],
'email' => [
'required',
'string',
'email',
'max:255',
Rule::unique(User::class),
],
'password' => $this->passwordRules(),
])->validate();
$user = User::create([
'email' => $request->email,
'password' => bcrypt($request->password),
]);
UserSettings::unguard();
$user
->settings()
->create([
'name' => $request->name,
'storage_capacity' => $settings['storage_default'],
]);
if (! get_setting('user_verification')) {
$user->markEmailAsVerified();
}
UserSettings::reguard();
event(new Registered($user));
if (! get_setting('user_verification')) {
$this->guard->login($user);
}
return response('User registered successfully', 201);
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Actions\Fortify;
use Laravel\Fortify\Rules\Password;
trait PasswordValidationRules
{
/**
* Get the validation rules used to validate passwords.
*
* @return array
*/
protected function passwordRules()
{
return ['required', 'string', new Password, 'confirmed'];
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace App\Actions\Fortify;
use Illuminate\Support\Facades\Validator;
use Laravel\Fortify\Contracts\ResetsUserPasswords;
class ResetUserPassword implements ResetsUserPasswords
{
use PasswordValidationRules;
/**
* Validate and reset the user's forgotten password.
*
* @param mixed $user
* @param array $input
* @return void
*/
public function reset($user, array $input)
{
Validator::make($input, [
'password' => $this->passwordRules(),
])->validate();
$user->forceFill([
'password' => bcrypt($input['password']),
])->save();
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace App\Actions\Fortify;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Laravel\Fortify\Contracts\UpdatesUserPasswords;
class UpdateUserPassword implements UpdatesUserPasswords
{
use PasswordValidationRules;
/**
* Validate and update the user's password.
*
* @param mixed $user
* @param array $input
* @return void
* @throws \Illuminate\Validation\ValidationException
*/
public function update($user, array $input)
{
Validator::make($input, [
'current_password' => ['required', 'string'],
'password' => $this->passwordRules(),
])->after(function ($validator) use ($user, $input) {
if (! isset($input['current_password']) || ! Hash::check($input['current_password'], $user->password)) {
$validator->errors()->add('current_password', __('The provided password does not match your current password.'));
}
})->validateWithBag('updatePassword');
$user->forceFill([
'password' => bcrypt($input['password']),
])->save();
}
}

View File

@@ -0,0 +1,60 @@
<?php
namespace App\Actions\Fortify;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\Validator;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Laravel\Fortify\Contracts\UpdatesUserProfileInformation;
class UpdateUserProfileInformation implements UpdatesUserProfileInformation
{
/**
* Validate and update the given user's profile information.
*
* @param mixed $user
* @param array $input
* @return void
*/
public function update($user, array $input)
{
Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
'email' => [
'required',
'string',
'email',
'max:255',
Rule::unique('users')->ignore($user->id),
],
])->validateWithBag('updateProfileInformation');
if ($input['email'] !== $user->email &&
$user instanceof MustVerifyEmail) {
$this->updateVerifiedUser($user, $input);
} else {
$user->forceFill([
'name' => $input['name'],
'email' => $input['email'],
])->save();
}
}
/**
* Update the given verified user's profile information.
*
* @param mixed $user
* @param array $input
* @return void
*/
protected function updateVerifiedUser($user, array $input)
{
$user->forceFill([
'name' => $input['name'],
'email' => $input['email'],
'email_verified_at' => null,
])->save();
$user->sendEmailVerificationNotification();
}
}

View File

@@ -0,0 +1,205 @@
<?php
namespace App\Http\Controllers\User;
use App\Models\User;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use App\Services\DemoService;
use Illuminate\Http\Response;
use App\Http\Controllers\Controller;
use App\Http\Resources\UserResource;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\RedirectResponse;
use Laravel\Sanctum\PersonalAccessToken;
use App\Http\Resources\InvoiceCollection;
use Illuminate\Support\Facades\Validator;
use App\Http\Resources\UserStorageResource;
use Illuminate\Contracts\Routing\ResponseFactory;
use App\Http\Requests\User\UpdateUserPasswordRequest;
use App\Http\Requests\User\UserCreateAccessTokenRequest;
class AccountController extends Controller
{
/**
* AccountController constructor.
*/
public function __construct()
{
$this->demo = resolve(DemoService::class);
}
/**
* Get all user data to frontend
*
* @return UserResource
*/
public function user()
{
return new UserResource(
Auth::user()
);
}
/**
* 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()
);
}
/**
* Update user settings relationship
*
* @param Request $request
* @return ResponseFactory|\Illuminate\Http\Response
*/
public function update_user_settings(Request $request)
{
// Validate request
// TODO: pridat validator do requestu
$validator = Validator::make($request->all(), [
'avatar' => 'sometimes|file',
'name' => 'string',
'value' => 'string',
]);
// Return error
if ($validator->fails()) {
abort(400, 'Bad input');
}
// Get user
$user = Auth::user();
// Check if is demo
abort_if(is_demo_account('howdy@hi5ve.digital'), 204, 'Done.');
// Update avatar
if ($request->hasFile('avatar')) {
$user
->settings()
->update([
'avatar' => store_avatar($request, 'avatar'),
]);
return response('Saved!', 204);
}
$user
->settings()
->update(
make_single_input($request)
);
return response('Saved!', 204);
}
/**
* Change user password
*
* @param Request $request
* @return ResponseFactory|\Illuminate\Http\Response
*/
public function change_password(UpdateUserPasswordRequest $request)
{
// Get user
$user = Auth::user();
// Check if is demo
abort_if(is_demo_account('howdy@hi5ve.digital'), 204, 'Done.');
// Change and store new password
$user->password = bcrypt($request->input('password'));
$user->save();
return response('Changed!', 204);
}
/**
* Get all user tokens
*/
public function tokens(): Response
{
return response(
Auth::user()->tokens()->get(),
200
);
}
public function create_token(UserCreateAccessTokenRequest $request): Response
{
// Check if is demo
abort_if(is_demo_account('howdy@hi5ve.digital'), 201, [
'name' => 'token',
'token' => Str::random(40),
'abilities' => '["*"]',
'tokenable_id' => Str::uuid(),
'updated_at' => now(),
'created_at' => now(),
'id' => Str::random(40),
]);
$token = Auth::user()->createToken($request->input('name'));
return response($token, 201);
}
public function revoke_token(PersonalAccessToken $token): Response
{
// Check if is demo
abort_if(is_demo_account('howdy@hi5ve.digital'), 204, 'Deleted!');
if (Auth::id() !== $token->tokenable_id) {
return response('Unauthorized', 401);
}
$token->delete();
return response('Deleted!', 204);
}
public function email_verification(string $id, Request $request): RedirectResponse | Response
{
if (! $request->hasValidSignature()) {
return response('Invalid or expired url provided.', 401);
}
$user = User::find($id);
if (! $user->hasVerifiedEmail()) {
$user->markEmailAsVerified();
}
return redirect()->to('/successfully-verified');
}
public function resend_verification_email(Request $request): Response
{
$user = User::whereEmail($request->input('email'))->first();
if ($user->hasVerifiedEmail()) {
return response('Email was already verified.', 204);
}
$user->sendEmailVerificationNotification();
return response('Email verification link sent to your email', 204);
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Models\User;
use App\Http\Controllers\Controller;
use App\Http\Requests\Auth\CheckAccountRequest;
class AuthController extends Controller
{
/**
* Check if user account exist
*
* @param CheckAccountRequest $request
* @return mixed
*/
public function check_account(CheckAccountRequest $request)
{
// Get User
$user = User::whereEmail($request->email)
->first();
if (! $user) {
return response(__t('user_not_fount'), 404);
}
return [
'name' => $user->settings->name,
'avatar' => $user->settings->avatar,
'verified' => $user->email_verified_at ? true : false,
];
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\ConfirmsPasswords;
class ConfirmPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Confirm Password Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password confirmations and
| uses a simple trait to include the behavior. You're free to explore
| this trait and override any functions that require customization.
|
*/
use ConfirmsPasswords;
/**
* Where to redirect users when the intended url fails.
*
* @var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace App\Http\Controllers\Auth;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Lang;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
class ForgotPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset emails and
| includes a trait which assists in sending these notifications from
| your application to your users. Feel free to explore this trait.
|
*/
use SendsPasswordResetEmails;
/**
* Get the response for a successful password reset link.
*
* @param \Illuminate\Http\Request $request
* @param string $response
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
*/
protected function sendResetLinkResponse(Request $request, $response)
{
return response(['message' => Lang::get($response)]);
}
/**
* Get the response for a failed password reset link.
*
* @param \Illuminate\Http\Request $request
* @param string $response
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
*/
protected function sendResetLinkFailedResponse(Request $request, $response)
{
return response(['message' => Lang::get($response)], 422);
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* @var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
}

View File

@@ -0,0 +1,55 @@
<?php
namespace App\Http\Controllers\Auth;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Lang;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\ResetsPasswords;
class ResetPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset requests
| and uses a simple trait to include this behavior. You're free to
| explore this trait and override any methods you wish to tweak.
|
*/
use ResetsPasswords;
/**
* Where to redirect users after resetting their password.
*
* @var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
/**
* Get the response for a successful password reset.
*
* @param \Illuminate\Http\Request $request
* @param string $response
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
*/
protected function sendResetResponse(Request $request, $response)
{
return response(['message' => Lang::get($response)]);
}
/**
* Get the response for a failed password reset.
*
* @param \Illuminate\Http\Request $request
* @param string $response
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
*/
protected function sendResetFailedResponse(Request $request, $response)
{
return response(['error' => Lang::get($response)], 422);
}
}

View File

@@ -0,0 +1,41 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\VerifiesEmails;
class VerificationController extends Controller
{
/*
|--------------------------------------------------------------------------
| Email Verification Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling email verification for any
| user that recently registered with the application. Emails may also
| be re-sent if the user didn't receive the original email message.
|
*/
use VerifiesEmails;
/**
* Where to redirect users after verification.
*
* @var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
$this->middleware('signed')->only('verify');
$this->middleware('throttle:6,1')->only('verify', 'resend');
}
}

View File

@@ -0,0 +1,278 @@
<?php
namespace App\Models;
use ByteUnits\Metric;
use Illuminate\Support\Str;
use Laravel\Cashier\Billable;
use App\Services\HelperService;
use App\Services\StripeService;
use Laravel\Sanctum\HasApiTokens;
use Kyslik\ColumnSortable\Sortable;
use App\Notifications\ResetPassword;
use Illuminate\Support\Facades\Storage;
use Illuminate\Notifications\Notifiable;
use Laravel\Fortify\TwoFactorAuthenticatable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements MustVerifyEmail
{
use TwoFactorAuthenticatable;
use HasApiTokens;
use Notifiable;
use HasFactory;
use Billable;
use Sortable;
protected $guarded = [
'id',
'role',
];
protected $fillable = [
'email', 'password',
];
protected $hidden = [
'password', 'remember_token',
];
protected $casts = [
'id' => 'string',
'email_verified_at' => 'datetime',
];
protected $appends = [
'used_capacity',
'storage',
];
public $sortable = [
'id',
'name',
'role',
'created_at',
'storage_capacity',
];
public $incrementing = false;
protected $keyType = 'string';
/**
* Get tax rate id for user
*
* @return array
*/
public function taxRates()
{
// Get tax rates
$rates = collect(resolve(StripeService::class)->getTaxRates());
// Find tax rate
$user_tax_rate = $rates->first(function ($item) {
return $item['country'] === $this->settings->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()
{
$user_capacity = $this->files_with_trashed->map(function ($item) {
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 Folder::with(['folders.shared', 'shared:token,id,item_id,permission,is_protected,expire_in'])
->where('parent_id', null)
->where('user_id', $this->id)
->sortable()
->get();
}
/**
* Set user billing info
*
* @param $billing
* @return UserSettings
*/
public function setBilling($billing)
{
$this->settings()->update([
'address' => $billing['billing_address'],
'city' => $billing['billing_city'],
'country' => $billing['billing_country'],
'name' => $billing['billing_name'],
'phone_number' => $billing['billing_phone_number'],
'postal_code' => $billing['billing_postal_code'],
'state' => $billing['billing_state'],
]);
return $this->settings;
}
/**
* Send the password reset notification.
*
* @param string $token
* @return void
*/
public function sendPasswordResetNotification($token)
{
$this->notify(new ResetPassword($token));
}
/**
* Record user upload filesize
*
* @param $file_size
*/
public function record_upload($file_size)
{
$now = now();
$record = Traffic::whereYear('created_at', '=', $now->year)
->whereMonth('created_at', '=', $now->month)
->firstOrCreate([
'user_id' => $this->id,
]);
$record->update([
'upload' => $record->upload + $file_size,
]);
}
/**
* Record user download filesize
*
* @param $file_size
*/
public function record_download($file_size)
{
$now = now();
$record = Traffic::whereYear('created_at', '=', $now->year)
->whereMonth('created_at', '=', $now->month)
->firstOrCreate([
'user_id' => $this->id,
]);
$record->update([
'download' => $record->download + $file_size,
]);
}
/**
* Get user favourites folder
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function favouriteFolders()
{
return $this->belongsToMany(Folder::class, 'favourite_folder', 'user_id', 'folder_id', 'id', 'id')
->with('shared:token,id,item_id,permission,is_protected,expire_in');
}
/**
* Get 5 latest uploads
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany|\Illuminate\Database\Query\Builder
*/
public function latest_uploads()
{
return $this->hasMany(File::class)->with(['parent:id,name'])->take(40);
}
/**
* Get all user files
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function files()
{
return $this->hasMany(File::class);
}
/**
* Get all user files
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function files_with_trashed()
{
return $this->hasMany(File::class)->withTrashed();
}
/**
* Get user attributes
*
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function settings()
{
return $this->hasOne(UserSettings::class);
}
/**
* Model Events
*/
protected static function boot()
{
parent::boot();
static::creating(function ($user) {
$user->id = Str::uuid();
// Create user directory for his files
Storage::makeDirectory("files/$user->id");
});
static::deleted(function ($user) {
resolve(HelperService::class)
->erase_user_data($user);
});
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Storage;
class UserSettings extends Model
{
public $timestamps = false;
protected $guarded = [
'id',
'storage_capacity',
];
/**
* Format avatar to full url
*
* @return \Illuminate\Contracts\Routing\UrlGenerator|string
*/
public function getAvatarAttribute()
{
// Get avatar from external storage
if ($this->attributes['avatar'] && ! is_storage_driver('local')) {
return Storage::temporaryUrl($this->attributes['avatar'], now()->addDay());
}
// Get avatar from local storage
if ($this->attributes['avatar']) {
return url('/' . $this->attributes['avatar']);
}
return url('/assets/images/default-avatar.png');
}
}

View File

@@ -0,0 +1,66 @@
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Notifications\Messages\MailMessage;
class ResetPassword extends Notification
{
use Queueable;
private $token;
/**
* Create a new notification instance.
*
* @param $token
*/
public function __construct($token)
{
$this->token = $token;
}
/**
* 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)
{
$reset_url = url('/create-new-password?token=' . $this->token);
$app_name = get_setting('app_title') ?? 'VueFileManager';
return (new MailMessage)
->subject(__t('reset_password_subject') . $app_name)
->greeting(__t('reset_password_greeting'))
->line(__t('reset_password_line_1'))
->action(__t('reset_password_action'), $reset_url)
->line(__t('reset_password_line_2'))
->salutation(__t('salutation') . ', ' . $app_name);
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
];
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace App\Http\Requests\Auth;
use Illuminate\Foundation\Http\FormRequest;
class CheckAccountRequest 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',
];
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace App\Http\Requests\User;
use Illuminate\Foundation\Http\FormRequest;
class UpdateUserPasswordRequest 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 [
'password' => 'required|string|min:6|confirmed',
];
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace App\Http\Requests\User;
use Illuminate\Foundation\Http\FormRequest;
class UserCreateAccessTokenRequest 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 [
'name' => 'required|string|min:3',
];
}
}

View File

@@ -0,0 +1,66 @@
<?php
namespace App\Http\Resources;
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)
{
// TODO: zrefaktorovat
return [
'data' => [
'id' => $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,
'email' => is_demo() ? obfuscate_email($this->email) : $this->email,
'role' => $this->role,
'two_factor_authentication' => $this->two_factor_secret ? true : false,
'folders' => $this->folder_tree,
'storage' => $this->storage,
'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' => $this->id,
'type' => 'settings',
'attributes' => [
'avatar' => $this->settings->avatar,
'name' => $this->settings->name,
'address' => $this->settings->address,
'state' => $this->settings->state,
'city' => $this->settings->city,
'postal_code' => $this->settings->postal_code,
'country' => $this->settings->country,
'phone_number' => $this->settings->phone_number,
'timezone' => $this->settings->timezone,
],
],
],
'favourites' => [
'data' => [
'id' => $this->id,
'type' => 'favourite_folders',
'attributes' => [
'folders' => $this->favouriteFolders->makeHidden(['pivot']),
],
],
],
],
],
];
}
}

View File

@@ -0,0 +1,88 @@
<?php
namespace App\Http\Resources;
use App\Models\File;
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 = File::where('user_id', $this->id)
->where('type', 'image')->get()->map(function ($item) {
return (int) $item->getRawOriginal('filesize');
})->sum();
// Get all audios
$audios = File::where('user_id', $this->id)
->where('type', 'audio')->get()->map(function ($item) {
return (int) $item->getRawOriginal('filesize');
})->sum();
// Get all videos
$videos = File::where('user_id', $this->id)
->where('type', 'video')->get()->map(function ($item) {
return (int) $item->getRawOriginal('filesize');
})->sum();
// Get all documents
$documents = File::where('user_id', $this->id)
->whereIn('mimetype', $document_mimetypes)->get()->map(function ($item) {
return (int) $item->getRawOriginal('filesize');
})->sum();
// Get all other files
$others = File::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,42 @@
<?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)
{
$active_subscription = $this->subscription('main')
->asStripeSubscription();
// TODO: vybrat z cache
$subscription = resolve('App\Services\StripeService')
->getPlan($this->subscription('main')->stripe_plan);
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($active_subscription['canceled_at'], '%d. %B. %Y'),
'created_at' => format_date($active_subscription['current_period_start'], '%d. %B. %Y'),
'ends_at' => format_date($active_subscription['current_period_end'], '%d. %B. %Y'),
],
],
];
}
}

View File

@@ -0,0 +1,22 @@
<?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,
];
}
}