├── public
├── favicon.ico
├── robots.txt
├── images
│ ├── edit.gif
│ ├── pause.gif
│ ├── retry.gif
│ ├── trash.gif
│ ├── continue.gif
│ ├── loading.gif
│ ├── processing.gif
│ ├── waiting-generic.png
│ └── not_available-generic.png
├── fonts
│ ├── fontawesome-webfont.eot
│ ├── fontawesome-webfont.ttf
│ ├── fontawesome-webfont.woff
│ ├── fontawesome-webfont.woff2
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.ttf
│ ├── glyphicons-halflings-regular.woff
│ └── glyphicons-halflings-regular.woff2
├── mix-manifest.json
├── .htaccess
├── web.config
└── index.php
├── routes
├── api.php
├── console.php
├── channels.php
├── static.php
└── web.php
├── database
├── .gitignore
├── seeds
│ └── DatabaseSeeder.php
├── factories
│ └── ModelFactory.php
└── migrations
│ ├── 2014_10_12_100000_create_password_resets_table.php
│ ├── 2017_03_21_111416_create_user_activations_table.php
│ ├── 2017_03_22_153420_create_failed_jobs_table.php
│ ├── 2014_10_12_000000_create_users_table.php
│ ├── 2016_06_01_093635_create_images_tables.php
│ ├── 2017_03_22_120019_update_images_table_add_flags.php
│ ├── 2017_03_21_104911_create_user_groups_table.php
│ └── 2017_03_21_111636_create_countries_table.php
├── resources
├── assets
│ ├── sass
│ │ ├── _variables.scss
│ │ ├── app.scss
│ │ └── imagehost.scss
│ └── js
│ │ ├── app.js
│ │ └── init.js
├── views
│ ├── errors
│ │ ├── 404.blade.php
│ │ ├── 403.blade.php
│ │ ├── 402.blade.php
│ │ ├── 500.blade.php
│ │ ├── 503.blade.php
│ │ └── error.blade.php
│ ├── emails
│ │ ├── activate-plain.blade.php
│ │ ├── blocks
│ │ │ ├── call-to-action.blade.php
│ │ │ └── style.blade.php
│ │ ├── activate.blade.php
│ │ ├── template-plain.blade.php
│ │ └── template.blade.php
│ ├── my
│ │ ├── index.blade.php
│ │ ├── images.blade.php
│ │ └── albums.blade.php
│ ├── layouts
│ │ ├── blocks
│ │ │ ├── notifications.blade.php
│ │ │ ├── footer.blade.php
│ │ │ └── nav.blade.php
│ │ └── app.blade.php
│ ├── image.blade.php
│ ├── album.blade.php
│ ├── blocks
│ │ ├── embed.blade.php
│ │ └── fineuploader.blade.php
│ ├── auth
│ │ ├── passwords
│ │ │ ├── email.blade.php
│ │ │ └── reset.blade.php
│ │ ├── login.blade.php
│ │ └── register.blade.php
│ └── home.blade.php
└── lang
│ └── en
│ ├── pagination.php
│ ├── auth.php
│ ├── passwords.php
│ └── validation.php
├── storage
├── geoip
│ └── .gitignore
├── debugbar
│ └── .gitignore
├── logs
│ └── .gitignore
├── app
│ ├── public
│ │ └── .gitignore
│ └── .gitignore
└── framework
│ ├── cache
│ └── .gitignore
│ ├── testing
│ └── .gitignore
│ ├── views
│ └── .gitignore
│ ├── sessions
│ └── .gitignore
│ └── .gitignore
├── bootstrap
├── cache
│ └── .gitignore
├── autoload.php
└── app.php
├── config
├── image.php
├── view.php
├── services.php
├── broadcasting.php
├── filesystems.php
├── queue.php
├── cache.php
├── auth.php
├── database.php
├── mail.php
└── session.php
├── .gitattributes
├── tests
├── TestCase.php
├── Unit
│ └── ExampleTest.php
├── CreatesApplication.php
└── Feature
│ └── ExampleTest.php
├── .gitignore
├── app
├── Models
│ ├── UserActivation.php
│ ├── User.php
│ ├── Albums.php
│ └── Images.php
├── Http
│ ├── Middleware
│ │ ├── EncryptCookies.php
│ │ ├── VerifyCsrfToken.php
│ │ ├── TrimStrings.php
│ │ ├── AjaxMiddleware.php
│ │ ├── RedirectIfAuthenticated.php
│ │ └── AdminMiddleware.php
│ ├── Controllers
│ │ ├── HomeController.php
│ │ ├── Auth
│ │ │ ├── ForgotPasswordController.php
│ │ │ ├── ActivationController.php
│ │ │ ├── LoginController.php
│ │ │ ├── ResetPasswordController.php
│ │ │ └── RegisterController.php
│ │ ├── Controller.php
│ │ ├── Admin
│ │ │ └── AdminImagesController.php
│ │ ├── My
│ │ │ └── MyImagesController.php
│ │ └── Image
│ │ │ └── ViewImagesController.php
│ └── Kernel.php
├── Providers
│ ├── BroadcastServiceProvider.php
│ ├── AuthServiceProvider.php
│ ├── EventServiceProvider.php
│ ├── AppServiceProvider.php
│ └── RouteServiceProvider.php
├── Console
│ ├── Kernel.php
│ └── Commands
│ │ └── DeleteExpiredImages.php
├── Jobs
│ ├── SendActivationMail.php
│ └── DeleteImage.php
├── Mail
│ └── ActivateUser.php
├── Services
│ ├── Imager.php
│ ├── MetaDataService.php
│ ├── Filer.php
│ └── Guzzler.php
└── Exceptions
│ └── Handler.php
├── webpack.mix.js
├── server.php
├── .env.example
├── phpunit.xml
├── package.json
├── artisan
├── composer.json
├── readme.md
└── helpers
└── helpers.php
/public/favicon.ico:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/routes/api.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/routes/console.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/routes/channels.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/database/.gitignore:
--------------------------------------------------------------------------------
1 | *.sqlite
2 |
--------------------------------------------------------------------------------
/resources/assets/sass/_variables.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/storage/geoip/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
--------------------------------------------------------------------------------
/bootstrap/cache/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/debugbar/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
--------------------------------------------------------------------------------
/storage/logs/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow:
3 |
--------------------------------------------------------------------------------
/storage/app/public/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/app/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !public/
3 | !.gitignore
4 |
--------------------------------------------------------------------------------
/storage/framework/cache/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/framework/testing/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/framework/views/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/framework/sessions/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/config/image.php:
--------------------------------------------------------------------------------
1 | 'gd'
5 | ];
6 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 | *.css linguist-vendored
3 | *.scss linguist-vendored
4 |
--------------------------------------------------------------------------------
/public/images/edit.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bhutanio/imagehost/HEAD/public/images/edit.gif
--------------------------------------------------------------------------------
/public/images/pause.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bhutanio/imagehost/HEAD/public/images/pause.gif
--------------------------------------------------------------------------------
/public/images/retry.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bhutanio/imagehost/HEAD/public/images/retry.gif
--------------------------------------------------------------------------------
/public/images/trash.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bhutanio/imagehost/HEAD/public/images/trash.gif
--------------------------------------------------------------------------------
/public/images/continue.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bhutanio/imagehost/HEAD/public/images/continue.gif
--------------------------------------------------------------------------------
/public/images/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bhutanio/imagehost/HEAD/public/images/loading.gif
--------------------------------------------------------------------------------
/public/images/processing.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bhutanio/imagehost/HEAD/public/images/processing.gif
--------------------------------------------------------------------------------
/public/images/waiting-generic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bhutanio/imagehost/HEAD/public/images/waiting-generic.png
--------------------------------------------------------------------------------
/public/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bhutanio/imagehost/HEAD/public/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/public/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bhutanio/imagehost/HEAD/public/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/public/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bhutanio/imagehost/HEAD/public/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/public/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bhutanio/imagehost/HEAD/public/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/public/images/not_available-generic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bhutanio/imagehost/HEAD/public/images/not_available-generic.png
--------------------------------------------------------------------------------
/public/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bhutanio/imagehost/HEAD/public/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/public/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bhutanio/imagehost/HEAD/public/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/public/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bhutanio/imagehost/HEAD/public/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/public/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bhutanio/imagehost/HEAD/public/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/public/mix-manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "/js/app.js": "/js/app.6c2027a726aa56925b75.js",
3 | "/css/app.css": "/css/app.a61a775a0ae2251c98e5.css"
4 | }
--------------------------------------------------------------------------------
/storage/framework/.gitignore:
--------------------------------------------------------------------------------
1 | config.php
2 | routes.php
3 | schedule-*
4 | compiled.php
5 | services.json
6 | events.scanned.php
7 | routes.scanned.php
8 | down
9 |
--------------------------------------------------------------------------------
/routes/static.php:
--------------------------------------------------------------------------------
1 | Error 404: Page not found!
8 | @endsection
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /bower_components
3 | /public/storage
4 | /public/hot
5 | /storage/*.key
6 | /vendor
7 | /.idea
8 | Homestead.json
9 | Homestead.yaml
10 | composer.phar
11 | composer.lock
12 | .env
13 | *.map
14 | /maintenance.txt
15 | /yarn-error.log
16 | /.phpstorm.meta.php
17 | /_ide_helper.php
18 | /_ide_helper_models.php
19 |
--------------------------------------------------------------------------------
/database/seeds/DatabaseSeeder.php:
--------------------------------------------------------------------------------
1 | call(UsersTableSeeder::class);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/resources/views/errors/403.blade.php:
--------------------------------------------------------------------------------
1 | @extends('errors.error')
2 |
3 | @section('page_title')
4 | @endsection
5 |
6 | @section('error_title')
7 | Error 403: Access Denied!
8 | @endsection
9 |
10 | @section('error_message')
11 |
You are not authorized to access this page.
12 | @endsection
13 |
--------------------------------------------------------------------------------
/resources/views/emails/activate-plain.blade.php:
--------------------------------------------------------------------------------
1 | @extends('emails.template-plain')
2 |
3 | @section('content')
4 | Hi,
5 | Thank you for signing up on {{ env('SITE_NAME') }}.
6 | To complete your account activation click the link below:
7 |
8 | {{ url('/activate/'.$code) }}
9 |
10 | If the link above does not work, copy and paste it into your browser's address bar.
11 | @endsection
12 |
--------------------------------------------------------------------------------
/resources/views/errors/402.blade.php:
--------------------------------------------------------------------------------
1 | @extends('errors.error')
2 |
3 | @section('page_title')
4 | @endsection
5 |
6 | @section('error_title')
7 | Error 402: {{ $exception->getMessage() ?: 'Limit Exceeded!' }}
8 | @endsection
9 |
10 | @section('error_message')
11 | You have exceeded your limits.
12 | @endsection
13 |
--------------------------------------------------------------------------------
/app/Models/UserActivation.php:
--------------------------------------------------------------------------------
1 | belongsTo(User::class, 'user_id', 'id');
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/resources/views/emails/blocks/call-to-action.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/Http/Middleware/EncryptCookies.php:
--------------------------------------------------------------------------------
1 | setMeta('ImageZ', 'ImageZ - Free and Secure Image Hosting & Photo Sharing');
16 |
17 | return view('home');
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/resources/views/errors/500.blade.php:
--------------------------------------------------------------------------------
1 | @extends('errors.error')
2 |
3 | @section('page_title')
4 | @endsection
5 |
6 | @section('error_title')
7 | Error 500: Internal Server Error!
8 | @endsection
9 |
10 | @section('error_message')
11 | Our server encountered an internal error. Error has been logged and reported to the System Administrator.
12 | @endsection
13 |
--------------------------------------------------------------------------------
/app/Http/Middleware/TrimStrings.php:
--------------------------------------------------------------------------------
1 | assertTrue(true);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/resources/views/my/index.blade.php:
--------------------------------------------------------------------------------
1 | @extends('layouts.app')
2 |
3 | @section('content')
4 |
5 | {{ meta()->pageTitle() }}
6 |
10 |
11 | @endsection
--------------------------------------------------------------------------------
/app/Models/User.php:
--------------------------------------------------------------------------------
1 | make(Kernel::class)->bootstrap();
19 |
20 | return $app;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/Providers/BroadcastServiceProvider.php:
--------------------------------------------------------------------------------
1 | middleware('guest');
16 |
17 | parent::__construct();
18 |
19 | $this->meta->setMeta('Reset Password');
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/Models/Albums.php:
--------------------------------------------------------------------------------
1 | hasMany(Images::class, 'album_id', 'id');
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/Models/Images.php:
--------------------------------------------------------------------------------
1 |
8 |
9 |
Temporarily down for maintenance!
10 |
11 |
The hamsters powering our server are taking a break. They should be back in couple of minutes.
12 |
13 |
14 | @endsection
15 |
--------------------------------------------------------------------------------
/tests/Feature/ExampleTest.php:
--------------------------------------------------------------------------------
1 | get('/');
20 |
21 | $response->assertStatus(200);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/Http/Middleware/AjaxMiddleware.php:
--------------------------------------------------------------------------------
1 | environment() != 'local' && !$request->ajax()) {
20 | return response('Not Allowed.', 405);
21 | }
22 |
23 | return $next($request);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/resources/views/emails/activate.blade.php:
--------------------------------------------------------------------------------
1 | @extends('emails.template')
2 |
3 | @section('content')
4 | Hi,
5 | Thank you for signing up on {{ env('SITE_NAME') }}.
6 | To complete your account activation click the button below:
7 | @include('emails.blocks.call-to-action', ['cta_url'=>url('/activate/'.$code),'cta_text'=>'Activate Account'])
8 | If the button above does not work, copy and paste the link below into your browser's address bar.
9 | {{ url('/activate/'.$code) }}
10 | @endsection
11 |
--------------------------------------------------------------------------------
/resources/lang/en/pagination.php:
--------------------------------------------------------------------------------
1 | '« Previous',
17 | 'next' => 'Next »',
18 |
19 | ];
20 |
--------------------------------------------------------------------------------
/bootstrap/autoload.php:
--------------------------------------------------------------------------------
1 |
2 |
3 | Options -MultiViews
4 |
5 |
6 | RewriteEngine On
7 |
8 | # Redirect Trailing Slashes If Not A Folder...
9 | RewriteCond %{REQUEST_FILENAME} !-d
10 | RewriteRule ^(.*)/$ /$1 [L,R=301]
11 |
12 | # Handle Front Controller...
13 | RewriteCond %{REQUEST_FILENAME} !-d
14 | RewriteCond %{REQUEST_FILENAME} !-f
15 | RewriteRule ^ index.php [L]
16 |
17 | # Handle Authorization Header
18 | RewriteCond %{HTTP:Authorization} .
19 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
20 |
21 |
--------------------------------------------------------------------------------
/server.php:
--------------------------------------------------------------------------------
1 |
8 | */
9 |
10 | $uri = urldecode(
11 | parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)
12 | );
13 |
14 | // This file allows us to emulate Apache's "mod_rewrite" functionality from the
15 | // built-in PHP web server. This provides a convenient way to test a Laravel
16 | // application without having installed a "real" web server software here.
17 | if ($uri !== '/' && file_exists(__DIR__.'/public'.$uri)) {
18 | return false;
19 | }
20 |
21 | require_once __DIR__.'/public/index.php';
22 |
--------------------------------------------------------------------------------
/resources/views/layouts/blocks/notifications.blade.php:
--------------------------------------------------------------------------------
1 | @if (!empty($errors) && count($errors->all()) > 0)
2 |
3 |
×
4 |
Please check the form below for errors
5 |
6 | @endif
7 |
8 | @if($flash_message = session()->get('flash_message'))
9 |
10 |
×
11 |
{{ $flash_message['message'] }}
12 |
13 | @endif
--------------------------------------------------------------------------------
/app/Http/Middleware/RedirectIfAuthenticated.php:
--------------------------------------------------------------------------------
1 | check()) {
21 | return redirect('/');
22 | }
23 |
24 | return $next($request);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/Providers/AuthServiceProvider.php:
--------------------------------------------------------------------------------
1 | 'App\Policies\ModelPolicy',
16 | ];
17 |
18 | /**
19 | * Register any authentication / authorization services.
20 | *
21 | * @return void
22 | */
23 | public function boot()
24 | {
25 | $this->registerPolicies();
26 |
27 | //
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/Http/Middleware/AdminMiddleware.php:
--------------------------------------------------------------------------------
1 | check() && Auth::guard($guard)->user()->group_id == 1) {
21 | return $next($request);
22 | }
23 |
24 | return abort(403, 'Access Denied.');
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/resources/lang/en/auth.php:
--------------------------------------------------------------------------------
1 | 'These credentials do not match our records.',
17 | 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
18 |
19 | ];
20 |
--------------------------------------------------------------------------------
/app/Providers/EventServiceProvider.php:
--------------------------------------------------------------------------------
1 | [
16 | 'App\Listeners\EventListener',
17 | ],
18 | ];
19 |
20 | /**
21 | * Register any events for your application.
22 | *
23 | * @return void
24 | */
25 | public function boot()
26 | {
27 | parent::boot();
28 |
29 | //
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/resources/assets/sass/app.scss:
--------------------------------------------------------------------------------
1 | // Variables
2 | @import "variables";
3 |
4 | // Bootstrap
5 | $icon-font-path: "~bootstrap-sass/assets/fonts/bootstrap/";
6 | @import "node_modules/bootswatch/flatly/variables";
7 | @import "node_modules/bootstrap-sass/assets/stylesheets/bootstrap";
8 | @import "node_modules/bootswatch/flatly/bootswatch";
9 |
10 | // FontAwesome
11 | $fa-font-path: "~font-awesome/fonts";
12 | @import "node_modules/font-awesome/scss/font-awesome";
13 |
14 | // Fine-Uploader
15 | @import "node_modules/fine-uploader/fine-uploader/fine-uploader";
16 | @import "node_modules/fine-uploader/fine-uploader/fine-uploader-new";
17 | @import "node_modules/fine-uploader/fine-uploader/fine-uploader-gallery";
18 |
19 | @import "node_modules/sweetalert2/src/sweetalert2";
20 |
21 | @import "imagehost";
22 |
--------------------------------------------------------------------------------
/resources/views/emails/template-plain.blade.php:
--------------------------------------------------------------------------------
1 | @section('content')
2 | Hi there,
3 | Sometimes you just want to send a simple HTML email with a simple design and clear call to action. This is it.
4 |
5 | CALL TO ACTION LINK
6 |
7 | This is a really simple email template. Its sole purpose is to get the recipient to click the button with no distractions.
8 | Good luck! Hope it works.
9 | @show
10 |
11 | @section('signature')
12 | Best Regards,
13 | {{ env('SITE_NAME') }} Team.
14 | @show
15 |
16 | @section('footer')
17 | Terms: {{ url('about/terms') }}
18 | Privacy: {{ url('about/privacy-policy') }}
19 | Unsubscribe: {{ url('email/unsubscribe?email='.$to) }}
20 | @show
21 |
22 | @section('disclaimer')
23 | This is a service email for "{{ $to }}" containing necessary account information. Please do not reply to this message.
24 | @show
--------------------------------------------------------------------------------
/app/Http/Controllers/Controller.php:
--------------------------------------------------------------------------------
1 | meta = app(MetaDataService::class);
28 | $this->request = app('request');
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
1 | APP_ENV=production
2 | APP_KEY=
3 | APP_DEBUG=false
4 | APP_LOG_LEVEL=error
5 | APP_URL='https://example.com'
6 |
7 | APP_STORAGE=local
8 |
9 | SITE_ID=imagez
10 | SITE_NAME='ImageZ'
11 | SITE_CDN='https://example.com'
12 |
13 | DB_CONNECTION=mysql
14 | DB_HOST=127.0.0.1
15 | DB_PORT=3306
16 | DB_DATABASE=database
17 | DB_USERNAME=username
18 | DB_PASSWORD=password
19 |
20 | BROADCAST_DRIVER=log
21 | CACHE_DRIVER=file
22 | SESSION_DRIVER=file
23 | QUEUE_DRIVER=sync
24 |
25 | REDIS_HOST=127.0.0.1
26 | REDIS_PASSWORD=null
27 | REDIS_PORT=6379
28 |
29 | MAIL_DRIVER=mail
30 | MAIL_FROM='noreply@example.com'
31 |
32 | ## AWS SERVER
33 | AWS_KEY=
34 | AWS_SECRET=
35 | AWS_REGION=
36 | AWS_BUCKET=
37 |
38 | API_GOOGLE_RECAPTCHA=
39 | API_GOOGLE_RECAPTCHA_CLIENT=
40 | GOOGLE_ANALYTICS=
41 |
42 | CLOUDFLARE_USERNAME=
43 | CLOUDFLARE_API_KEY=
44 | CLOUDFLARE_ZONE_ID=
45 |
--------------------------------------------------------------------------------
/database/factories/ModelFactory.php:
--------------------------------------------------------------------------------
1 | define(App\User::class, function (Faker\Generator $faker) {
16 | static $password;
17 |
18 | return [
19 | 'name' => $faker->name,
20 | 'email' => $faker->unique()->safeEmail,
21 | 'password' => $password ?: $password = bcrypt('secret'),
22 | 'remember_token' => str_random(10),
23 | ];
24 | });
25 |
--------------------------------------------------------------------------------
/database/migrations/2014_10_12_100000_create_password_resets_table.php:
--------------------------------------------------------------------------------
1 | string('email')->index();
18 | $table->string('token');
19 | $table->timestamp('created_at')->nullable();
20 | });
21 | }
22 |
23 | /**
24 | * Reverse the migrations.
25 | *
26 | * @return void
27 | */
28 | public function down()
29 | {
30 | Schema::dropIfExists('password_resets');
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/resources/lang/en/passwords.php:
--------------------------------------------------------------------------------
1 | 'Passwords must be at least six characters and match the confirmation.',
17 | 'reset' => 'Your password has been reset!',
18 | 'sent' => 'We have e-mailed your password reset link!',
19 | 'token' => 'This password reset token is invalid.',
20 | 'user' => "We can't find a user with that e-mail address.",
21 |
22 | ];
23 |
--------------------------------------------------------------------------------
/resources/views/layouts/blocks/footer.blade.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/database/migrations/2017_03_21_111416_create_user_activations_table.php:
--------------------------------------------------------------------------------
1 | bigIncrements('id');
18 | $table->bigInteger('user_id')->unsigned()->references('id')->on('users')->onDelete('cascade');;
19 | $table->string('token', 100)->index();
20 | $table->timestamps();
21 | });
22 | }
23 |
24 | /**
25 | * Reverse the migrations.
26 | *
27 | * @return void
28 | */
29 | public function down()
30 | {
31 | Schema::dropIfExists('user_activations');
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/ActivationController.php:
--------------------------------------------------------------------------------
1 | where('token', $token)->firstOrFail();
15 | if (!empty($activation->user->id)) {
16 | $activation->user->active = true;
17 | $activation->user->save();
18 | $activation->delete();
19 | }
20 |
21 | flash('Email confirmed successfully. You may login now.', 'success');
22 | } catch (ModelNotFoundException $e) {
23 | flash('Invalid confirmation code or Account already confirmed!', 'error');
24 | }
25 |
26 | return redirect('login');
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/resources/views/my/images.blade.php:
--------------------------------------------------------------------------------
1 | @extends('layouts.app')
2 |
3 | @section('content')
4 | {{ meta()->pageTitle() }}
5 |
6 | @if($images->count())
7 |
8 | @foreach($images as $image)
9 |
10 |
11 |
12 |
13 | @endforeach
14 |
15 |
16 | @endif
17 |
18 | {!! $images->render() !!}
19 | @endsection
--------------------------------------------------------------------------------
/database/migrations/2017_03_22_153420_create_failed_jobs_table.php:
--------------------------------------------------------------------------------
1 | bigIncrements('id');
18 | $table->text('connection');
19 | $table->text('queue');
20 | $table->longText('payload');
21 | $table->longText('exception');
22 | $table->timestamp('failed_at')->useCurrent();
23 | });
24 | }
25 |
26 | /**
27 | * Reverse the migrations.
28 | *
29 | * @return void
30 | */
31 | public function down()
32 | {
33 | Schema::dropIfExists('failed_jobs');
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/public/web.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/LoginController.php:
--------------------------------------------------------------------------------
1 | middleware('guest', ['except' => 'logout']);
18 | parent::__construct();
19 |
20 | $this->meta->setMeta('Login');
21 | }
22 |
23 | protected function authenticated(Request $request, $user)
24 | {
25 | if (!$user->active) {
26 | flash('This account is not activated, Please check your email for activation link. If you did not receive the activation code, please click "forgot password" link on the login page.',
27 | 'warning');
28 |
29 | $this->guard()->logout();
30 |
31 | return redirect('login');
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/Console/Kernel.php:
--------------------------------------------------------------------------------
1 | command('imagez:delete:expired')->everyFiveMinutes();
29 | }
30 |
31 | /**
32 | * Register the Closure based commands for the application.
33 | *
34 | * @return void
35 | */
36 | protected function commands()
37 | {
38 | require base_path('routes/console.php');
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/routes/web.php:
--------------------------------------------------------------------------------
1 | 'auth'], function () {
4 | Route::group(['prefix' => 'my'], function () {
5 | Route::get('/', 'My\MyImagesController@index');
6 | Route::get('albums', 'My\MyImagesController@albums');
7 | Route::get('images', 'My\MyImagesController@images');
8 | });
9 |
10 | Route::group(['prefix' => 'admin', 'middleware' => 'admin'], function () {
11 | Route::get('/', 'Admin\AdminImagesController@index');
12 | Route::get('albums', 'Admin\AdminImagesController@albums');
13 | Route::get('images', 'Admin\AdminImagesController@images');
14 | });
15 | });
16 |
17 | Auth::routes();
18 | Route::get('activate/{token}', 'Auth\ActivationController@activate');
19 |
20 | Route::post('image/upload', 'Image\UploadImageController@ajaxUpload')->middleware(['ajax']);
21 | Route::delete('image/delete', 'Image\UploadImageController@ajaxDelete')->middleware(['ajax']);
22 |
23 | Route::post('image/create', 'Image\UploadImageController@create');
24 |
25 | Route::get('/', 'HomeController@index');
26 |
--------------------------------------------------------------------------------
/config/view.php:
--------------------------------------------------------------------------------
1 | [
17 | resource_path('views'),
18 | ],
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Compiled View Path
23 | |--------------------------------------------------------------------------
24 | |
25 | | This option determines where all the compiled Blade templates will be
26 | | stored for your application. Typically, this is within the storage
27 | | directory. However, as usual, you are free to change this value.
28 | |
29 | */
30 |
31 | 'compiled' => realpath(storage_path('framework/views')),
32 |
33 | ];
34 |
--------------------------------------------------------------------------------
/config/services.php:
--------------------------------------------------------------------------------
1 | [
18 | 'domain' => env('MAILGUN_DOMAIN'),
19 | 'secret' => env('MAILGUN_SECRET'),
20 | ],
21 |
22 | 'ses' => [
23 | 'key' => env('SES_KEY'),
24 | 'secret' => env('SES_SECRET'),
25 | 'region' => 'us-east-1',
26 | ],
27 |
28 | 'sparkpost' => [
29 | 'secret' => env('SPARKPOST_SECRET'),
30 | ],
31 |
32 | 'stripe' => [
33 | 'model' => App\Models\User::class,
34 | 'key' => env('STRIPE_KEY'),
35 | 'secret' => env('STRIPE_SECRET'),
36 | ],
37 |
38 | ];
39 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 | ./tests/Feature
14 |
15 |
16 |
17 | ./tests/Unit
18 |
19 |
20 |
21 |
22 | ./app
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/app/Jobs/SendActivationMail.php:
--------------------------------------------------------------------------------
1 | user = $user;
36 | $this->code = $code;
37 | }
38 |
39 | /**
40 | * Execute the job.
41 | *
42 | * @return void
43 | */
44 | public function handle()
45 | {
46 | if ($this->attempts() > 2) {
47 | $this->delay(min(30 * $this->attempts(), 300));
48 | }
49 |
50 | Mail::send(new ActivateUser($this->user, $this->code));
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/resources/views/image.blade.php:
--------------------------------------------------------------------------------
1 | @extends('layouts.app')
2 |
3 | @section('header_css')
4 |
5 |
6 |
7 |
8 |
9 | @endsection
10 |
11 | @section('content')
12 | {{ meta()->pageTitle() }}
13 | @if(!empty($image->image_description))
14 | {{ $image->image_description }}
15 | @endif
16 |
17 |
18 | Embed
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | @include('blocks.embed')
28 | @endsection
29 |
--------------------------------------------------------------------------------
/app/Mail/ActivateUser.php:
--------------------------------------------------------------------------------
1 | user = $user;
33 | $this->code = $code;
34 | }
35 |
36 | /**
37 | * Build the message.
38 | *
39 | * @return $this
40 | */
41 | public function build()
42 | {
43 | $this->subject = env('SITE_NAME') . ' - Account Activation Link';
44 |
45 | return $this->to($this->user->email, $this->user->username)
46 | ->view('emails.activate')
47 | ->text('emails.activate-plain')
48 | ->with([
49 | 'to' => $this->user->email,
50 | 'subject' => $this->subject,
51 | 'code' => $this->code,
52 | ]);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/resources/views/my/albums.blade.php:
--------------------------------------------------------------------------------
1 | @extends('layouts.app')
2 |
3 | @section('content')
4 | {{ meta()->pageTitle() }}
5 |
6 | @if($albums->count())
7 | @foreach($albums as $album)
8 |
9 |
10 |
14 | @foreach($album->images->slice(0,6) as $image)
15 |
16 | @endforeach
17 |
{{ $album->album_description or '' }}
18 |
19 | @endforeach
20 | @endif
21 |
22 | {!! $albums->render() !!}
23 | @endsection
--------------------------------------------------------------------------------
/database/migrations/2014_10_12_000000_create_users_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
18 | $table->string('name');
19 | $table->string('email')->unique();
20 | $table->string('password');
21 | $table->rememberToken();
22 | $table->timestamps();
23 | });
24 |
25 | DB::unprepared("INSERT INTO `users` (`id`, `name`, `email`, `password`, `remember_token`, `created_at`, `updated_at`) VALUES (NULL, 'Anonymous', 'anonymous@imagez.to', '', NULL, NULL, NULL);");
26 | DB::unprepared("INSERT INTO `users` (`id`, `name`, `email`, `password`, `remember_token`, `created_at`, `updated_at`) VALUES (NULL, 'Admin', 'admin@imagez.to', '', NULL, NULL, NULL);");
27 | }
28 |
29 | /**
30 | * Reverse the migrations.
31 | *
32 | * @return void
33 | */
34 | public function down()
35 | {
36 | Schema::dropIfExists('users');
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/resources/views/errors/error.blade.php:
--------------------------------------------------------------------------------
1 | @extends('layouts.app')
2 |
3 | @section('content')
4 |
5 |
6 |
7 |
8 | @section('error_title')
9 | {{ meta()->pageTitle() }}: Page not found!
10 | @show
11 |
12 |
13 | @section('error_message')
14 |
The requested URL was not found on this server. Make sure that the Web site address displayed in the address bar of your browser is spelled and formatted correctly.
15 | @show
16 |
17 | @section('button_back')
18 | Go Back
19 | @show
20 | @section('button_home')
21 | Go to Home Page
22 | @show
23 |
24 |
25 |
26 |
27 | @endsection
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "dev": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
5 | "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
6 | "watch-poll": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --watch-poll --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
7 | "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
8 | "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
9 | },
10 | "devDependencies": {
11 | "axios": "^0.15.3",
12 | "bootstrap-sass": "^3.3.7",
13 | "bootswatch": "^3.3.7",
14 | "cross-env": "^3.2.3",
15 | "fine-uploader": "^5.14.1",
16 | "font-awesome": "^4.7.0",
17 | "jquery": "^3.1.1",
18 | "laravel-mix": "^0.8.3",
19 | "lodash": "^4.17.4",
20 | "sweetalert2": "^6.4.4",
21 | "vue": "^2.1.10"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/Console/Commands/DeleteExpiredImages.php:
--------------------------------------------------------------------------------
1 | where('expire', '<', carbon())->get();
25 | if ($albums->count()) {
26 | foreach ($albums as $album) {
27 | if (!empty($album->images)) {
28 | foreach ($album->images as $image) {
29 | $this->info('Deleting - ' . $image->hash);
30 | dispatch(new DeleteImage($image->id));
31 | }
32 | }
33 | $album->delete();
34 | }
35 | }
36 |
37 | $images = Images::whereNull('album_id')->where('expire', '<', carbon())->get();
38 | if ($images->count()) {
39 | foreach ($images as $image) {
40 | $this->info('Deleting - ' . $image->hash);
41 | dispatch(new DeleteImage($image->id));
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/resources/views/layouts/app.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | {{ meta()->metaTitle() }}
10 | @if(meta()->description())
11 |
12 | @endif
13 |
14 | @yield('header_css')
15 |
16 |
17 |
18 |
19 | @include('layouts.blocks.nav')
20 |
21 |
22 |
23 | @include('layouts.blocks.notifications')
24 | @yield('content')
25 |
26 |
27 | @include('layouts.blocks.footer')
28 |
29 |
30 | @yield('footer_js')
31 |
32 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/ResetPasswordController.php:
--------------------------------------------------------------------------------
1 | middleware('guest');
20 |
21 | parent::__construct();
22 |
23 | $this->meta->setMeta('Reset Password');
24 | }
25 |
26 | protected function resetPassword($user, $password)
27 | {
28 | $user->forceFill([
29 | 'password' => bcrypt($password),
30 | 'remember_token' => Str::random(60),
31 | 'active' => true,
32 | ])->save();
33 |
34 | UserActivation::where('user_id', $user->id)->delete();
35 |
36 | $this->guard()->login($user);
37 | }
38 |
39 | protected function rules()
40 | {
41 | return [
42 | 'token' => 'required',
43 | 'email' => 'required|email',
44 | 'password' => 'required|confirmed|min:6',
45 | ];
46 | }
47 |
48 | protected function validationErrorMessages()
49 | {
50 | return [
51 | 'password.password_policy' => 'Choose a stronger password, at least one uppercase letter with number or symbol.',
52 | ];
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/app/Providers/AppServiceProvider.php:
--------------------------------------------------------------------------------
1 | app->singleton(\App\Services\MetaDataService::class);
32 | $this->app->singleton(\GeoIp2\Database\Reader::class, function () {
33 | return new \GeoIp2\Database\Reader(storage_path('geoip/geolite2-country.mmdb'));
34 | });
35 | }
36 |
37 | /**
38 | * Register any application services.
39 | *
40 | * @return void
41 | */
42 | public function register()
43 | {
44 | if (env('APP_DEBUG') && $this->app->environment() == 'local') {
45 | $this->app->register(\Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class);
46 | $this->app->register(\Barryvdh\Debugbar\ServiceProvider::class);
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Admin/AdminImagesController.php:
--------------------------------------------------------------------------------
1 | filer = app(Filer::class);
27 | $this->imager = app(Imager::class);
28 | }
29 |
30 | public function index()
31 | {
32 | $this->meta->setMeta('Uploads');
33 |
34 | $data = [
35 | 'url' => 'admin',
36 | 'albums' => Albums::count(),
37 | 'images' => Images::whereNull('album_id')->count(),
38 | ];
39 |
40 | return view('my.index', $data);
41 | }
42 |
43 | public function albums()
44 | {
45 | $this->meta->setMeta('Albums');
46 |
47 | $data = [
48 | 'url' => 'admin',
49 | 'albums' => Albums::with(['images'])->latest()->paginate(20),
50 | ];
51 |
52 | return view('my.albums', $data);
53 | }
54 |
55 | public function images()
56 | {
57 | $this->meta->setMeta('Images');
58 |
59 | $data = [
60 | 'url' => 'admin',
61 | 'images' => Images::whereNull('album_id')->latest()->paginate(48),
62 | ];
63 |
64 | return view('my.images', $data);
65 | }
66 | }
--------------------------------------------------------------------------------
/app/Http/Controllers/My/MyImagesController.php:
--------------------------------------------------------------------------------
1 | filer = app(Filer::class);
28 | $this->imager = app(Imager::class);
29 | }
30 |
31 | public function index()
32 | {
33 | $this->meta->setMeta('My Uploads');
34 |
35 | $data = [
36 | 'url' => 'my',
37 | 'albums' => Albums::where('created_by', Auth::id())->count(),
38 | 'images' => Images::where('created_by', Auth::id())->whereNull('album_id')->count(),
39 | ];
40 |
41 | return view('my.index', $data);
42 | }
43 |
44 | public function albums()
45 | {
46 | $this->meta->setMeta('My Albums');
47 |
48 | $data = [
49 | 'url' => 'my',
50 | 'albums' => Albums::with(['images'])->where('created_by', Auth::id())->latest()->paginate(20),
51 | ];
52 |
53 | return view('my.albums', $data);
54 | }
55 |
56 | public function images()
57 | {
58 | $this->meta->setMeta('My Images');
59 |
60 | $data = [
61 | 'url' => 'my',
62 | 'images' => Images::where('created_by', Auth::id())->whereNull('album_id')->latest()->paginate(48),
63 | ];
64 |
65 | return view('my.images', $data);
66 | }
67 | }
--------------------------------------------------------------------------------
/config/broadcasting.php:
--------------------------------------------------------------------------------
1 | env('BROADCAST_DRIVER', 'null'),
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Broadcast Connections
23 | |--------------------------------------------------------------------------
24 | |
25 | | Here you may define all of the broadcast connections that will be used
26 | | to broadcast events to other systems or over websockets. Samples of
27 | | each available type of connection are provided inside this array.
28 | |
29 | */
30 |
31 | 'connections' => [
32 |
33 | 'pusher' => [
34 | 'driver' => 'pusher',
35 | 'key' => env('PUSHER_APP_KEY'),
36 | 'secret' => env('PUSHER_APP_SECRET'),
37 | 'app_id' => env('PUSHER_APP_ID'),
38 | 'options' => [
39 | //
40 | ],
41 | ],
42 |
43 | 'redis' => [
44 | 'driver' => 'redis',
45 | 'connection' => 'default',
46 | ],
47 |
48 | 'log' => [
49 | 'driver' => 'log',
50 | ],
51 |
52 | 'null' => [
53 | 'driver' => 'null',
54 | ],
55 |
56 | ],
57 |
58 | ];
59 |
--------------------------------------------------------------------------------
/resources/views/album.blade.php:
--------------------------------------------------------------------------------
1 | @extends('layouts.app')
2 |
3 | @section('header_css')
4 |
5 |
6 |
7 |
8 |
9 | @endsection
10 |
11 | @section('content')
12 | {{ meta()->pageTitle() }}
13 | @if(!empty($album->album_description))
14 | {{ $album->album_description }}
15 | @endif
16 |
17 |
18 | Embed
19 |
20 |
21 |
22 | @foreach($images as $image)
23 |
24 | @if(!empty($image->image_title))
25 |
{{ $image->image_title }}
26 | @endif
27 |
28 | @if(!empty($image->image_description))
29 |
{{ $image->image_description }}
30 | @endif
31 |
32 | @endforeach
33 |
34 | {!! $images->render() !!}
35 |
36 | @include('blocks.embed', ['image' => $album->images])
37 | @endsection
38 |
--------------------------------------------------------------------------------
/bootstrap/app.php:
--------------------------------------------------------------------------------
1 | singleton(
30 | Illuminate\Contracts\Http\Kernel::class,
31 | App\Http\Kernel::class
32 | );
33 |
34 | $app->singleton(
35 | Illuminate\Contracts\Console\Kernel::class,
36 | App\Console\Kernel::class
37 | );
38 |
39 | $app->singleton(
40 | Illuminate\Contracts\Debug\ExceptionHandler::class,
41 | App\Exceptions\Handler::class
42 | );
43 |
44 | /*
45 | |--------------------------------------------------------------------------
46 | | Return The Application
47 | |--------------------------------------------------------------------------
48 | |
49 | | This script returns the application instance. The instance is given to
50 | | the calling script so we can separate the building of the instances
51 | | from the actual running of the application and sending responses.
52 | |
53 | */
54 |
55 | return $app;
56 |
--------------------------------------------------------------------------------
/artisan:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | make(Illuminate\Contracts\Console\Kernel::class);
32 |
33 | $status = $kernel->handle(
34 | $input = new Symfony\Component\Console\Input\ArgvInput,
35 | new Symfony\Component\Console\Output\ConsoleOutput
36 | );
37 |
38 | /*
39 | |--------------------------------------------------------------------------
40 | | Shutdown The Application
41 | |--------------------------------------------------------------------------
42 | |
43 | | Once Artisan has finished running. We will fire off the shutdown events
44 | | so that any final work may be done by the application before we shut
45 | | down the process. This is the last thing to happen to the request.
46 | |
47 | */
48 |
49 | $kernel->terminate($input, $status);
50 |
51 | exit($status);
52 |
--------------------------------------------------------------------------------
/resources/views/blocks/embed.blade.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/database/migrations/2016_06_01_093635_create_images_tables.php:
--------------------------------------------------------------------------------
1 | bigIncrements('id');
17 |
18 | $table->bigInteger('album_id')->unsigned()->nullable()->default(null);
19 | $table->index('album_id');
20 |
21 | $table->string('hash')->unique();
22 |
23 | $table->string('file_hash');
24 |
25 | $table->string('image_title')->nullable()->default(null);
26 | $table->string('image_description')->nullable()->default(null);
27 |
28 | $table->char('image_extension', '5');
29 | $table->smallInteger('image_width')->unsigned();
30 | $table->smallInteger('image_height')->unsigned();
31 | $table->bigInteger('created_by')->unsigned()->default(1);
32 | $table->index('created_by');
33 |
34 | $table->timestamps();
35 | });
36 |
37 | Schema::create('albums', function (Blueprint $table) {
38 | $table->bigIncrements('id');
39 | $table->char('hash')->unique();
40 | $table->string('album_title')->nullable()->default(null);
41 | $table->string('album_description')->nullable()->default(null);
42 |
43 | $table->bigInteger('created_by')->unsigned()->default(1);
44 | $table->index('created_by');
45 |
46 | $table->timestamps();
47 | });
48 | }
49 |
50 | /**
51 | * Reverse the migrations.
52 | *
53 | * @return void
54 | */
55 | public function down()
56 | {
57 | Schema::drop('albums');
58 | Schema::drop('images');
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/public/index.php:
--------------------------------------------------------------------------------
1 |
8 | */
9 |
10 | /*
11 | |--------------------------------------------------------------------------
12 | | Register The Auto Loader
13 | |--------------------------------------------------------------------------
14 | |
15 | | Composer provides a convenient, automatically generated class loader for
16 | | our application. We just need to utilize it! We'll simply require it
17 | | into the script here so that we don't have to worry about manual
18 | | loading any of our classes later on. It feels great to relax.
19 | |
20 | */
21 |
22 | require __DIR__.'/../bootstrap/autoload.php';
23 |
24 | /*
25 | |--------------------------------------------------------------------------
26 | | Turn On The Lights
27 | |--------------------------------------------------------------------------
28 | |
29 | | We need to illuminate PHP development, so let us turn on the lights.
30 | | This bootstraps the framework and gets it ready for use, then it
31 | | will load up this application so that we can run it and send
32 | | the responses back to the browser and delight our users.
33 | |
34 | */
35 |
36 | $app = require_once __DIR__.'/../bootstrap/app.php';
37 |
38 | /*
39 | |--------------------------------------------------------------------------
40 | | Run The Application
41 | |--------------------------------------------------------------------------
42 | |
43 | | Once we have the application, we can handle the incoming request
44 | | through the kernel, and send the associated response back to
45 | | the client's browser allowing them to enjoy the creative
46 | | and wonderful application we have prepared for them.
47 | |
48 | */
49 |
50 | $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
51 |
52 | $response = $kernel->handle(
53 | $request = Illuminate\Http\Request::capture()
54 | );
55 |
56 | $response->send();
57 |
58 | $kernel->terminate($request, $response);
59 |
--------------------------------------------------------------------------------
/resources/views/emails/template.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{ $subject }}
7 | @include('emails.blocks.style')
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | @section('content')
22 | Hi there,
23 | Sometimes you just want to send a simple HTML email with a simple design and clear call to action. This is it.
24 | @include('emails.blocks.call-to-action', ['cta_url'=>url('/'),'cta_text'=>'Call to Action'])
25 | This is a really simple email template. Its sole purpose is to get the recipient to click the button with no distractions.
26 | Good luck! Hope it works.
27 | @show
28 | @section('signature')
29 | Best Regards,
30 | {{ env('SITE_NAME') }} Team.
31 | @show
32 |
33 |
34 |
35 |
36 |
37 |
38 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/database/migrations/2017_03_22_120019_update_images_table_add_flags.php:
--------------------------------------------------------------------------------
1 | boolean('adult')->unsigned()->default(false)->after('image_height');
18 | $table->index('adult');
19 | $table->boolean('private')->unsigned()->default(true)->after('adult');
20 | $table->index('private');
21 | $table->timestamp('expire')->nullable()->after('private');
22 | $table->text('image_description')->nullable()->change();
23 | });
24 |
25 | Schema::table('albums', function (Blueprint $table) {
26 | $table->boolean('adult')->unsigned()->default(false)->after('album_description');
27 | $table->index('adult');
28 | $table->boolean('private')->unsigned()->default(true)->after('adult');
29 | $table->index('private');
30 | $table->timestamp('expire')->nullable()->after('private');
31 | $table->text('album_description')->nullable()->change();
32 | });
33 | }
34 |
35 | /**
36 | * Reverse the migrations.
37 | *
38 | * @return void
39 | */
40 | public function down()
41 | {
42 | Schema::table('albums', function (Blueprint $table) {
43 | $table->string('album_description')->nullable()->default(null)->change();
44 | $table->dropColumn(['adult', 'private', 'expire']);
45 | });
46 |
47 | Schema::table('images', function (Blueprint $table) {
48 | $table->string('image_description')->nullable()->default(null)->change();
49 | $table->dropColumn(['adult', 'private', 'expire']);
50 | });
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/app/Providers/RouteServiceProvider.php:
--------------------------------------------------------------------------------
1 | mapApiRoutes();
39 |
40 | $this->mapWebRoutes();
41 |
42 | $this->mapStaticRoutes();
43 | }
44 |
45 | /**
46 | * Define the "web" routes for the application.
47 | *
48 | * These routes all receive session state, CSRF protection, etc.
49 | *
50 | * @return void
51 | */
52 | protected function mapWebRoutes()
53 | {
54 | Route::middleware('web')
55 | ->namespace($this->namespace)
56 | ->group(base_path('routes/web.php'));
57 | }
58 |
59 | /**
60 | * Define the "api" routes for the application.
61 | *
62 | * These routes are typically stateless.
63 | *
64 | * @return void
65 | */
66 | protected function mapApiRoutes()
67 | {
68 | Route::prefix('api')
69 | ->middleware('api')
70 | ->namespace($this->namespace)
71 | ->group(base_path('routes/api.php'));
72 | }
73 |
74 | protected function mapStaticRoutes()
75 | {
76 | Route::middleware('static')
77 | ->namespace($this->namespace)
78 | ->group(base_path('routes/static.php'));
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/resources/views/auth/passwords/email.blade.php:
--------------------------------------------------------------------------------
1 | @extends('layouts.app')
2 |
3 | @section('content')
4 |
5 |
6 |
7 |
8 |
Reset Password
9 |
10 | @if (session('status'))
11 |
12 | {{ session('status') }}
13 |
14 | @endif
15 |
16 |
17 | {{ csrf_field() }}
18 |
19 |
32 |
33 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | @endsection
47 |
--------------------------------------------------------------------------------
/app/Jobs/DeleteImage.php:
--------------------------------------------------------------------------------
1 | image_id = $image_id;
23 | }
24 |
25 | /**
26 | * Execute the job.
27 | *
28 | * @return void
29 | */
30 | public function handle()
31 | {
32 | $filer = app(Filer::class);
33 | $guzzler = app(Guzzler::class);
34 | $image = Images::find($this->image_id);
35 |
36 | if ($image) {
37 | try {
38 | $cf = $guzzler->setUrl('https://api.cloudflare.com/client/v4/zones/' . env('CLOUDFLARE_ZONE_ID') . '/purge_cache')
39 | ->request('DELETE',
40 | [
41 | 'headers' => [
42 | 'X-Auth-Email' => env('CLOUDFLARE_USERNAME'),
43 | 'X-Auth-Key' => env('CLOUDFLARE_API_KEY'),
44 | 'Content-Type' => 'application/json',
45 | ],
46 | 'json' => [
47 | 'files' => [
48 | url('/i/' . $image->hash),
49 | url('/i/' . $image->hash . '.' . $image->image_extension),
50 | url('/t/' . $image->hash . '.' . $image->image_extension),
51 | ],
52 | ]
53 | ]);
54 | } catch (\Exception $e) {
55 | }
56 |
57 | $filer->type('images')->delete($image->hash . '.' . $image->image_extension);
58 | $image->delete();
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bhutanio/imagehost",
3 | "description": "A Secure and Anonymous Image Host",
4 | "keywords": [
5 | "framework",
6 | "laravel",
7 | "image",
8 | "imagehost"
9 | ],
10 | "license": "MIT",
11 | "type": "project",
12 | "require": {
13 | "php": ">=5.6.4",
14 | "laravel/framework": "5.4.*",
15 | "laravel/tinker": "~1.0",
16 | "doctrine/dbal": "2.6.*",
17 | "laravelcollective/html": "5.4.*",
18 | "predis/predis": "1.1.*",
19 | "league/flysystem-aws-s3-v3": "1.0.*",
20 | "guzzlehttp/guzzle": "6.3.*",
21 | "intervention/image": "2.4.*",
22 | "geoip2/geoip2": "2.7.*",
23 | "google/recaptcha": "1.1.*",
24 | "hoa/mime": "3.*"
25 | },
26 | "require-dev": {
27 | "barryvdh/laravel-debugbar": "^2.4",
28 | "barryvdh/laravel-ide-helper": "^2.4",
29 | "fzaninotto/faker": "~1.4",
30 | "mockery/mockery": "0.9.*",
31 | "phpunit/phpunit": "~5.7"
32 | },
33 | "autoload": {
34 | "classmap": [
35 | "database"
36 | ],
37 | "psr-4": {
38 | "App\\": "app/"
39 | },
40 | "files": [
41 | "helpers/helpers.php"
42 | ]
43 | },
44 | "autoload-dev": {
45 | "psr-4": {
46 | "Tests\\": "tests/"
47 | }
48 | },
49 | "scripts": {
50 | "post-root-package-install": [
51 | "php -r \"file_exists('.env') || copy('.env.example', '.env');\""
52 | ],
53 | "post-create-project-cmd": [
54 | "php artisan key:generate"
55 | ],
56 | "post-install-cmd": [
57 | "Illuminate\\Foundation\\ComposerScripts::postInstall",
58 | "php artisan optimize"
59 | ],
60 | "post-update-cmd": [
61 | "Illuminate\\Foundation\\ComposerScripts::postUpdate",
62 | "php artisan optimize",
63 | "wget -qO- http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz | gunzip > storage/geoip/geolite2-country.mmdb"
64 | ]
65 | },
66 | "config": {
67 | "preferred-install": "dist",
68 | "sort-packages": true
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/resources/assets/sass/imagehost.scss:
--------------------------------------------------------------------------------
1 | @function dynamic-text-color($color) {
2 | @if (lightness( $color ) > 40) {
3 | @return darken($color, 40);
4 | } @else {
5 | @return lighten($color, 40);
6 | }
7 | }
8 |
9 | body {
10 | font-size: ($font-size-base + 1);
11 | font-weight: 300;
12 | margin-top: 80px;
13 | }
14 |
15 | .page-title {
16 | margin-top: 2px;
17 | }
18 |
19 | .block {
20 | display: block;
21 | margin-bottom: 40px;
22 | padding: 20px 40px 60px 40px;
23 | border: 1px solid lighten($well-bg, 5%);
24 | background-color: $well-bg;
25 | :after {
26 | clear: both;
27 | }
28 | }
29 |
30 | .block-box {
31 | text-align: center;
32 | min-height: 200px;
33 | padding: 60px 0;
34 | .glyphicon {
35 | font-size: 48px;
36 | padding: 10px;
37 | }
38 | }
39 |
40 | .block-image {
41 | margin-bottom: 20px;
42 | background-color: lighten($well-bg, 2%);
43 | img {
44 | max-width: 100%;
45 | }
46 | h2, h3 {
47 | margin: 0;
48 | padding: 4px;
49 | font-size: 18px;
50 | }
51 | p {
52 | padding: 4px;
53 | font-size: 14px;
54 | }
55 | }
56 |
57 | .footer-top {
58 | padding: 10px 0;
59 | color: dynamic-text-color($navbar-default-bg);
60 | background: $navbar-default-bg;
61 | }
62 |
63 | .footer-bottom {
64 | margin: 10px 0;
65 | }
66 |
67 | .glyphicon-spin {
68 | -webkit-animation: spin 1000ms infinite linear;
69 | animation: spin 1000ms infinite linear;
70 | }
71 |
72 | @-webkit-keyframes spin {
73 | 0% {
74 | -webkit-transform: rotate(0deg);
75 | transform: rotate(0deg);
76 | }
77 | 100% {
78 | -webkit-transform: rotate(359deg);
79 | transform: rotate(359deg);
80 | }
81 | }
82 |
83 | @keyframes spin {
84 | 0% {
85 | -webkit-transform: rotate(0deg);
86 | transform: rotate(0deg);
87 | }
88 | 100% {
89 | -webkit-transform: rotate(359deg);
90 | transform: rotate(359deg);
91 | }
92 | }
93 |
94 | .shorten-output {
95 | margin-top: 20px;
96 | font-size: $font-size-large;
97 | }
98 |
99 | .panel-heading h1 {
100 | margin: 2px 0;
101 | font-size: $font-size-h3;
102 | }
103 |
104 | .btn_delete_image {
105 | position: absolute;
106 | bottom: 68px;
107 | right: 22px;
108 | @include opacity(0.8);
109 | }
--------------------------------------------------------------------------------
/app/Http/Kernel.php:
--------------------------------------------------------------------------------
1 | [
30 | \App\Http\Middleware\EncryptCookies::class,
31 | \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
32 | \Illuminate\Session\Middleware\StartSession::class,
33 | // \Illuminate\Session\Middleware\AuthenticateSession::class,
34 | \Illuminate\View\Middleware\ShareErrorsFromSession::class,
35 | \App\Http\Middleware\VerifyCsrfToken::class,
36 | \Illuminate\Routing\Middleware\SubstituteBindings::class,
37 | ],
38 |
39 | 'api' => [
40 | 'throttle:60,1',
41 | 'bindings',
42 | ],
43 |
44 | 'static' => [],
45 | ];
46 |
47 | /**
48 | * The application's route middleware.
49 | *
50 | * These middleware may be assigned to groups or used individually.
51 | *
52 | * @var array
53 | */
54 | protected $routeMiddleware = [
55 | 'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
56 | 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
57 | 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
58 | 'can' => \Illuminate\Auth\Middleware\Authorize::class,
59 | 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
60 | 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
61 |
62 | 'ajax' => \App\Http\Middleware\AjaxMiddleware::class,
63 | 'admin' => \App\Http\Middleware\AdminMiddleware::class,
64 | ];
65 | }
66 |
--------------------------------------------------------------------------------
/config/filesystems.php:
--------------------------------------------------------------------------------
1 | 'local',
17 |
18 | /*
19 | |--------------------------------------------------------------------------
20 | | Default Cloud Filesystem Disk
21 | |--------------------------------------------------------------------------
22 | |
23 | | Many applications store files both locally and in the cloud. For this
24 | | reason, you may specify a default "cloud" driver here. This driver
25 | | will be bound as the Cloud disk implementation in the container.
26 | |
27 | */
28 |
29 | 'cloud' => 's3',
30 |
31 | /*
32 | |--------------------------------------------------------------------------
33 | | Filesystem Disks
34 | |--------------------------------------------------------------------------
35 | |
36 | | Here you may configure as many filesystem "disks" as you wish, and you
37 | | may even configure multiple disks of the same driver. Defaults have
38 | | been setup for each driver as an example of the required options.
39 | |
40 | | Supported Drivers: "local", "ftp", "s3", "rackspace"
41 | |
42 | */
43 |
44 | 'disks' => [
45 |
46 | 'local' => [
47 | 'driver' => 'local',
48 | 'root' => storage_path('app'),
49 | ],
50 |
51 | 'tmp' => [
52 | 'driver' => 'local',
53 | 'root' => storage_path('app/tmp'),
54 | ],
55 |
56 | 'public' => [
57 | 'driver' => 'local',
58 | 'root' => storage_path('app/public'),
59 | 'url' => env('APP_URL') . '/storage',
60 | 'visibility' => 'public',
61 | ],
62 |
63 | 's3' => [
64 | 'driver' => 's3',
65 | 'key' => env('AWS_KEY'),
66 | 'secret' => env('AWS_SECRET'),
67 | 'region' => env('AWS_REGION'),
68 | 'bucket' => env('AWS_BUCKET'),
69 | ],
70 |
71 | ],
72 |
73 | ];
74 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | ## ImageHost
2 | imagehost is an online Image Hosting platform build using Laravel Framework.
3 |
4 | ### Requirement
5 | - [**PHP**](https://php.net) 5.6.4+ (**7.0** preferred)
6 | - PHP Extensions: openssl, mcrypt and mbstring, phpredis
7 | - Database server: [MySQL](https://www.mysql.com) or [**MariaDB**](https://mariadb.org)
8 | - [Redis](http://redis.io) Server
9 | - [Composer](https://getcomposer.org)
10 | - [Node.js](https://nodejs.org/) with npm
11 |
12 | ### Installation
13 | * clone the repository: `git clone https://github.com/bhutanio/imagehost.git imagehost`
14 | * create a database
15 | * create configuration env file `.env` refer to `.env.example`
16 | * install: `composer install --no-dev`
17 | * setup database tables: `php artisan migrate`
18 |
19 | ### Configuration
20 | #### Image Storage Location
21 | There are 3 locations you can configure using **APP_STORAGE** option in the **.env** file
22 | * ```APP_STORAGE=local``` : store image only in your local storage
23 | * ```APP_STORAGE=localcloud``` : store image in the cloud and keep a local cache
24 | * ```APP_STORAGE=cloud``` : store image only in the cloud
25 |
26 | #### Setup Admin Account
27 | ```bash
28 | php artisan tinker
29 | ```
30 | ```php
31 | DB::table('users')->where('id', 2)->update(['email'=>'myemail@example.com']);
32 | ```
33 | Click on **forgot password** link on the **login page** and reset password for your admin user.
34 |
35 | #### Setup Cron Job
36 | ```bash
37 | crontab -e -u www-data
38 | ```
39 | ```bash
40 | * * * * * php /home/web/imagehost/artisan schedule:run >/dev/null 2>&1
41 | */5 * * * * php /home/web/imagehost/artisan auth:clear-resets >/dev/null 2>&1
42 | ```
43 |
44 | #### Setup Supervisor
45 | ```bash
46 | nano /etc/supervisor/conf.d/imagehost.conf
47 | ```
48 | ```bash
49 | [program:imagehost-queue]
50 | process_name=%(program_name)s_%(process_num)02d
51 | command=php /home/web/imagehost/artisan queue:work --sleep=3 --tries=3
52 | autostart=true
53 | autorestart=true
54 | user=www-data
55 | numprocs=2
56 | ```
57 |
58 | #### Setup Google ReCaptcha
59 | Visit https://www.google.com/recaptcha/admin and register your site
60 |
61 | Get **Site key** and **Secret key**, add them in your .env file
62 | ```$xslt
63 | ...
64 | ## Secret Key
65 | API_GOOGLE_RECAPTCHA='SECRET KEY'
66 |
67 | ## Site Key
68 | API_GOOGLE_RECAPTCHA_CLIENT='SITE KEY'
69 | ...
70 | ```
71 |
72 | ### License
73 | imagehost is open source software licensed under the [MIT license](http://opensource.org/licenses/MIT).
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/RegisterController.php:
--------------------------------------------------------------------------------
1 | middleware('guest');
26 |
27 | parent::__construct();
28 |
29 | $this->meta->setMeta('Register');
30 | }
31 |
32 | public function register(Request $request)
33 | {
34 | $this->validator($request->all())->validate();
35 |
36 | event(new Registered($user = $this->create($request->all())));
37 |
38 | return $this->registered($request, $user)
39 | ?: redirect($this->redirectPath());
40 | }
41 |
42 | protected function registered(Request $request, User $user)
43 | {
44 | $token = hash_hmac('sha256', $user->username . $user->email . str_random(16), config('app.key'));
45 |
46 | UserActivation::create([
47 | 'user_id' => $user->id,
48 | 'token' => $token,
49 | ]);
50 |
51 | $this->dispatch(new SendActivationMail($user, $token));
52 |
53 | flash('You have been successfully registered. A confirmation email has been sent to "' . e($user->email) . '" Please confirm your email address, before you login.',
54 | 'info');
55 |
56 | return redirect('login');
57 | }
58 |
59 | protected function validator(array $data)
60 | {
61 | return Validator::make($data, [
62 | 'name' => 'required|max:255',
63 | 'email' => 'required|email|max:255|unique:users',
64 | 'password' => 'required|confirmed|min:8|max:48|password_policy',
65 | ], [
66 | 'password.password_policy' => 'Choose a stronger password, at least one uppercase letter with number or symbol.',
67 | ]);
68 | }
69 |
70 | protected function create(array $data)
71 | {
72 | return User::create([
73 | 'group_id' => $this->group_id,
74 | 'name' => $data['name'],
75 | 'email' => $data['email'],
76 | 'password' => bcrypt($data['password']),
77 | ]);
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/app/Services/Imager.php:
--------------------------------------------------------------------------------
1 | image->stream($format, $quality);
24 | }
25 |
26 | public function setImage($file, $type = null)
27 | {
28 | $this->type($type);
29 | $this->image = Image::make($file);
30 |
31 | return $this;
32 | }
33 |
34 | public function getColor()
35 | {
36 | return $this->image->resize(1, 1)->pickColor(0, 0, 'hex');
37 | }
38 |
39 | public function getInfo()
40 | {
41 | return [
42 | 'mime' => $this->image->mime(),
43 | 'width' => $this->image->width(),
44 | 'height' => $this->image->height(),
45 | 'extension' => $this->image->extension,
46 | 'filename' => $this->image->filename,
47 | 'filesize' => $this->image->filesize(),
48 | ];
49 | }
50 |
51 | public function crop($width, $height)
52 | {
53 | $this->image->crop($width, $height);
54 |
55 | return $this;
56 | }
57 |
58 | public function resize($width, $height, $aspect_ratio = true, $upscale = true)
59 | {
60 | $this->image->resize($width, $height, function ($constraint) use ($aspect_ratio, $upscale) {
61 | if ($aspect_ratio) {
62 | $constraint->aspectRatio();
63 | }
64 | if ($upscale) {
65 | $constraint->upsize();
66 | }
67 | });
68 |
69 | return $this;
70 | }
71 |
72 | /**
73 | * @param $width
74 | * @param null $height
75 | * @param string $position top-left|top|top-right|left|center|right|bottom-left|bottom|bottom-right
76 | *
77 | * @return $this
78 | */
79 | public function fit($width, $height = null, $position = 'center')
80 | {
81 | $this->image->fit($width, $height, null, $position);
82 |
83 | return $this;
84 | }
85 |
86 | public function response($format = null, $quality = 90)
87 | {
88 | return $this->image->response($format, $quality);
89 | }
90 |
91 | public function __call($method, $parameters)
92 | {
93 | $this->image = call_user_func_array([$this->image, $method], $parameters);
94 |
95 | return $this;
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/app/Exceptions/Handler.php:
--------------------------------------------------------------------------------
1 | expectsJson()) {
34 | return $this->respondJsonException($request, $exception);
35 | }
36 |
37 | if ($exception instanceof TokenMismatchException) {
38 | return $this->handleTokenMismatch($request, $exception);
39 | }
40 |
41 | return parent::render($request, $exception);
42 | }
43 |
44 | protected function unauthenticated($request, AuthenticationException $exception)
45 | {
46 | if ($request->expectsJson()) {
47 | return response()->json(['error' => 'Unauthenticated.'], 401);
48 | }
49 |
50 | return redirect()->guest(route('login'));
51 | }
52 |
53 | private function respondJsonException($request, $exception)
54 | {
55 | if (method_exists($exception, 'getStatusCode')) {
56 | return response()->json($exception->getMessage(), $exception->getStatusCode());
57 | }
58 |
59 | if ($exception instanceof AuthorizationException) {
60 | return response()->json('Unauthorized Action', 403);
61 | }
62 |
63 | return response()->json('Internal Server Error', 500);
64 | }
65 |
66 | private function handleTokenMismatch($request, TokenMismatchException $exception)
67 | {
68 | if ($request->expectsJson()) {
69 | return response()->json('Your session has expired. Please try again.', 401);
70 | }
71 |
72 | flash('Your session has expired. Please try again.', 'warning');
73 |
74 | return redirect()->back()->withInput($request->except('_token'));
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/config/queue.php:
--------------------------------------------------------------------------------
1 | env('QUEUE_DRIVER', 'sync'),
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Queue Connections
23 | |--------------------------------------------------------------------------
24 | |
25 | | Here you may configure the connection information for each server that
26 | | is used by your application. A default configuration has been added
27 | | for each back-end shipped with Laravel. You are free to add more.
28 | |
29 | */
30 |
31 | 'connections' => [
32 |
33 | 'sync' => [
34 | 'driver' => 'sync',
35 | ],
36 |
37 | 'database' => [
38 | 'driver' => 'database',
39 | 'table' => 'jobs',
40 | 'queue' => 'default',
41 | 'retry_after' => 90,
42 | ],
43 |
44 | 'beanstalkd' => [
45 | 'driver' => 'beanstalkd',
46 | 'host' => 'localhost',
47 | 'queue' => 'default',
48 | 'retry_after' => 90,
49 | ],
50 |
51 | 'sqs' => [
52 | 'driver' => 'sqs',
53 | 'key' => 'your-public-key',
54 | 'secret' => 'your-secret-key',
55 | 'prefix' => 'https://sqs.us-east-1.amazonaws.com/your-account-id',
56 | 'queue' => 'your-queue-name',
57 | 'region' => 'us-east-1',
58 | ],
59 |
60 | 'redis' => [
61 | 'driver' => 'redis',
62 | 'connection' => 'default',
63 | 'queue' => 'default',
64 | 'retry_after' => 90,
65 | ],
66 |
67 | ],
68 |
69 | /*
70 | |--------------------------------------------------------------------------
71 | | Failed Queue Jobs
72 | |--------------------------------------------------------------------------
73 | |
74 | | These options configure the behavior of failed queue job logging so you
75 | | can control which database and table are used to store the jobs that
76 | | have failed. You may change them to any database / table you wish.
77 | |
78 | */
79 |
80 | 'failed' => [
81 | 'database' => env('DB_CONNECTION', 'mysql'),
82 | 'table' => 'failed_jobs',
83 | ],
84 |
85 | ];
86 |
--------------------------------------------------------------------------------
/resources/views/layouts/blocks/nav.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 | {{--
--}}
12 | {{--Home --}}
13 | {{-- --}}
14 |
15 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/config/cache.php:
--------------------------------------------------------------------------------
1 | env('CACHE_DRIVER', 'file'),
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Cache Stores
23 | |--------------------------------------------------------------------------
24 | |
25 | | Here you may define all of the cache "stores" for your application as
26 | | well as their drivers. You may even define multiple stores for the
27 | | same cache driver to group types of items stored in your caches.
28 | |
29 | */
30 |
31 | 'stores' => [
32 |
33 | 'apc' => [
34 | 'driver' => 'apc',
35 | ],
36 |
37 | 'array' => [
38 | 'driver' => 'array',
39 | ],
40 |
41 | 'database' => [
42 | 'driver' => 'database',
43 | 'table' => 'cache',
44 | 'connection' => null,
45 | ],
46 |
47 | 'file' => [
48 | 'driver' => 'file',
49 | 'path' => storage_path('framework/cache/data'),
50 | ],
51 |
52 | 'memcached' => [
53 | 'driver' => 'memcached',
54 | 'persistent_id' => env('MEMCACHED_PERSISTENT_ID'),
55 | 'sasl' => [
56 | env('MEMCACHED_USERNAME'),
57 | env('MEMCACHED_PASSWORD'),
58 | ],
59 | 'options' => [
60 | // Memcached::OPT_CONNECT_TIMEOUT => 2000,
61 | ],
62 | 'servers' => [
63 | [
64 | 'host' => env('MEMCACHED_HOST', '127.0.0.1'),
65 | 'port' => env('MEMCACHED_PORT', 11211),
66 | 'weight' => 100,
67 | ],
68 | ],
69 | ],
70 |
71 | 'redis' => [
72 | 'driver' => 'redis',
73 | 'connection' => 'default',
74 | ],
75 |
76 | ],
77 |
78 | /*
79 | |--------------------------------------------------------------------------
80 | | Cache Key Prefix
81 | |--------------------------------------------------------------------------
82 | |
83 | | When utilizing a RAM based store such as APC or Memcached, there might
84 | | be other applications utilizing the same cache. So, we'll specify a
85 | | value to get prefixed to all our keys so we can avoid collisions.
86 | |
87 | */
88 |
89 | 'prefix' => env('SITE_ID', 'laravel'),
90 |
91 | ];
92 |
--------------------------------------------------------------------------------
/app/Services/MetaDataService.php:
--------------------------------------------------------------------------------
1 | request = $request;
18 |
19 | $this->meta_title = $this->getDefaultTitle();
20 | $this->setDefaultMeta();
21 | }
22 |
23 | public function setMeta($page_title = null, $meta_title = null, $description = null, $icon = null)
24 | {
25 | $this->pageTitle($page_title);
26 | $this->metaTitle($meta_title);
27 | if (empty($meta_title)) {
28 | if ($page = $this->request->get('page')) {
29 | if ($page > 1) {
30 | $page_title .= ' (Page ' . $page . ')';
31 | }
32 | }
33 |
34 | $this->metaTitle($page_title . ' - ' . $this->meta_title);
35 | }
36 | $this->description($description);
37 | $this->icon($icon);
38 | }
39 |
40 | public function setTheme($theme = null, $color = null)
41 | {
42 | }
43 |
44 | public function metaTitle($title = null)
45 | {
46 | if ($title) {
47 | $this->meta_title = $title;
48 | }
49 |
50 | return $this->meta_title;
51 | }
52 |
53 | public function pageTitle($title = null)
54 | {
55 | if ($title) {
56 | $this->page_title = $title;
57 | }
58 |
59 | return $this->page_title;
60 | }
61 |
62 | public function description($description = null)
63 | {
64 | if ($description) {
65 | $this->description = $description;
66 | }
67 |
68 | return $this->description;
69 | }
70 |
71 | public function canonical($url = null)
72 | {
73 | if ($url) {
74 | $this->canonical = $url;
75 | }
76 |
77 | return $this->canonical;
78 | }
79 |
80 | public function icon($icon = null)
81 | {
82 | if ($icon) {
83 | $this->icon = $icon;
84 | }
85 |
86 | return $this->icon;
87 | }
88 |
89 | private function setDefaultMeta()
90 | {
91 | // switch ($this->request->getRequestUri()) {
92 | // case '/login':
93 | // $this->setMeta('Login');
94 | // break;
95 | // case '/register':
96 | // $this->setMeta('Register');
97 | // break;
98 | // case '/password/reset':
99 | // $this->setMeta('Reset Password');
100 | // break;
101 | // }
102 | }
103 |
104 | /**
105 | * @return mixed
106 | */
107 | private function getDefaultTitle()
108 | {
109 | return env('SITE_NAME') ?: 'Site Name';
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Image/ViewImagesController.php:
--------------------------------------------------------------------------------
1 | filer = app(Filer::class);
27 | $this->imager = app(Imager::class);
28 | }
29 |
30 | public function album($hash)
31 | {
32 | $album = Albums::where('hash', $hash)->with(['images'])->firstOrFail();
33 | $images = Images::where('album_id', $album->id)->paginate(20);
34 | $this->meta->setMeta(($album->album_title ? $album->album_title : 'Album ' . $album->hash));
35 |
36 | return view('album', compact('album', 'images'));
37 | }
38 |
39 | public function image($hash)
40 | {
41 | $extension = str_contains($hash, '.');
42 | if ($extension) {
43 | return $this->imageFile($hash);
44 | }
45 |
46 | $image = Images::where('hash', $hash)->firstOrFail();
47 | $this->meta->setMeta(($image->image_title ? $image->image_title : 'Image ' . $image->hash));
48 |
49 | return view('image', compact('image'));
50 | }
51 |
52 | public function thumbnail($hash)
53 | {
54 | if ($hash) {
55 | return $this->imageFile($hash, true);
56 | }
57 |
58 | abort(404, 'Image Not Found!');
59 | }
60 |
61 | private function imageFile($filename, $thumb = false)
62 | {
63 | $hash = explode('.', $filename)[0];
64 | $image = Images::where('hash', $hash)->firstOrFail();
65 |
66 | $file_content = $this->filer->type('images')->get($filename);
67 | if (empty($file_content)) {
68 | abort(404, 'Image Not Found');
69 | }
70 |
71 | $image_file = $this->imager->setImage($file_content);
72 |
73 | $response = response($file_content);
74 | if ($thumb) {
75 | $image_file->fit(300, 170);
76 | $response = response($image_file->image->encode());
77 | }
78 |
79 | $headers = [
80 | 'Content-Type' => extension_to_mime($image->image_extension),
81 | ];
82 |
83 | if ($image->private) {
84 | $headers['X-Robots-Tag'] = 'noindex, noarchive';
85 | }
86 |
87 | if ($image->expire) {
88 | $headers['Cache-Control'] = 'public,max-age=' . (carbon($image->expire)->diffInSeconds()) . ',s-maxage=' . (carbon($image->expire)->diffInSeconds());
89 | $response->setExpires(carbon($image->expire));
90 | } else {
91 | $headers['Cache-Control'] = 'public,max-age=' . (3600 * 24 * 30) . ',s-maxage=' . (3600 * 24 * 30);
92 | $response->setExpires(carbon()->addDays(30));
93 | }
94 |
95 | return $response->withHeaders($headers);
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/helpers/helpers.php:
--------------------------------------------------------------------------------
1 | flash('flash_message', [
24 | 'type' => $type,
25 | 'message' => $message,
26 | ]);
27 | }
28 |
29 | function asset_cdn($path)
30 | {
31 | return asset($path);
32 | }
33 |
34 | function human_size($bytes, $decimals = 2)
35 | {
36 | $bytes = (int)$bytes;
37 | $size = [' B', ' KB', ' MB', ' GB', ' TB', ' PB', ' EB', ' ZB', ' YB'];
38 | $factor = (int)floor((strlen($bytes) - 1) / 3);
39 |
40 | return number_format(($bytes / pow(1024, $factor)), $decimals) . @$size[$factor];
41 | }
42 |
43 | function computer_size($number, $size = null)
44 | {
45 | if (!$size) {
46 | preg_match('/([0-9.]{0,9})\s?([bkmgtpezy]{1,2})/i', $number, $guess_size);
47 | if (isset($guess_size[1]) && isset($guess_size[2])) {
48 | $number = $guess_size[1];
49 | $size = $guess_size[2];
50 | }
51 | }
52 |
53 | $size = strtolower($size);
54 | $bytes = (float)$number;
55 | $factors = ['b' => 0, 'kb' => 1, 'mb' => 2, 'gb' => 3, 'tb' => 4, 'pb' => 5, 'eb' => 6, 'zb' => 7, 'yb' => 8];
56 |
57 | if (isset($factors[$size])) {
58 | return (float)number_format($bytes * pow(1024, $factors[$size]), 2, '.', '');
59 | }
60 |
61 | return $bytes;
62 | }
63 |
64 | function image_embed_codes($images, $type = null)
65 | {
66 | $embed = '';
67 | if (!($images instanceof \Illuminate\Support\Collection)) {
68 | $images = [$images];
69 | }
70 |
71 | foreach ($images as $image) {
72 | $thumb_url = asset_cdn('t/' . $image->hash . '.' . $image->image_extension);
73 | $image_url = asset_cdn('i/' . $image->hash . '.' . $image->image_extension);
74 | if ($type == 'html') {
75 | $embed .= ' ';
76 | } elseif ($type == 'bbcode') {
77 | $embed .= '[url=' . $image_url . '][img]' . $thumb_url . '[/img][/url]';
78 | } else {
79 | $embed .= $image_url . "\n";
80 | }
81 | }
82 |
83 | $embed = rtrim($embed, "\n");
84 |
85 | return $embed;
86 | }
87 |
88 | function mime_to_extension($mime)
89 | {
90 | try {
91 | $extension = \Hoa\Mime\Mime::getExtensionsFromMime($mime);
92 | } catch (\Exception $e) {
93 | }
94 |
95 | if (!empty($extension) && is_array($extension)) {
96 | if ($extension[0] == 'jpeg') {
97 | return 'jpg';
98 | }
99 |
100 | return $extension[0];
101 | }
102 |
103 | return null;
104 | }
105 |
106 | function extension_to_mime($extension)
107 | {
108 | return \Hoa\Mime\Mime::getMimeFromExtension($extension);
109 | }
110 |
--------------------------------------------------------------------------------
/resources/views/auth/login.blade.php:
--------------------------------------------------------------------------------
1 | @extends('layouts.app')
2 |
3 | @section('content')
4 |
5 |
6 |
7 |
8 |
Login
9 |
10 |
11 | {{ csrf_field() }}
12 |
13 |
26 |
27 |
40 |
41 |
50 |
51 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | @endsection
69 |
--------------------------------------------------------------------------------
/resources/views/emails/blocks/style.blade.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/views/home.blade.php:
--------------------------------------------------------------------------------
1 | @extends('layouts.app')
2 |
3 | @section('content')
4 |
5 |
Upload and share images securely with {{ env('SITE_NAME') }}!
6 |
Select the images and click upload.
7 |
8 | {!! Form::open(['files'=>true, 'url'=>url('image/create'), 'id'=>'form_upload', 'class' => 'form-horizontal', 'role'=>'form']) !!}
9 |
10 |
15 |
16 |
21 |
22 |
27 |
28 |
36 |
46 |
47 |
63 |
64 |
69 |
70 | {!! Form::close() !!}
71 |
72 | @include('blocks.fineuploader')
73 | @endsection
74 |
--------------------------------------------------------------------------------
/resources/views/blocks/fineuploader.blade.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/config/auth.php:
--------------------------------------------------------------------------------
1 | [
17 | 'guard' => 'web',
18 | 'passwords' => 'users',
19 | ],
20 |
21 | /*
22 | |--------------------------------------------------------------------------
23 | | Authentication Guards
24 | |--------------------------------------------------------------------------
25 | |
26 | | Next, you may define every authentication guard for your application.
27 | | Of course, a great default configuration has been defined for you
28 | | here which uses session storage and the Eloquent user provider.
29 | |
30 | | All authentication drivers have a user provider. This defines how the
31 | | users are actually retrieved out of your database or other storage
32 | | mechanisms used by this application to persist your user's data.
33 | |
34 | | Supported: "session", "token"
35 | |
36 | */
37 |
38 | 'guards' => [
39 | 'web' => [
40 | 'driver' => 'session',
41 | 'provider' => 'users',
42 | ],
43 |
44 | 'api' => [
45 | 'driver' => 'token',
46 | 'provider' => 'users',
47 | ],
48 | ],
49 |
50 | /*
51 | |--------------------------------------------------------------------------
52 | | User Providers
53 | |--------------------------------------------------------------------------
54 | |
55 | | All authentication drivers have a user provider. This defines how the
56 | | users are actually retrieved out of your database or other storage
57 | | mechanisms used by this application to persist your user's data.
58 | |
59 | | If you have multiple user tables or models you may configure multiple
60 | | sources which represent each model / table. These sources may then
61 | | be assigned to any extra authentication guards you have defined.
62 | |
63 | | Supported: "database", "eloquent"
64 | |
65 | */
66 |
67 | 'providers' => [
68 | 'users' => [
69 | 'driver' => 'eloquent',
70 | 'model' => App\Models\User::class,
71 | ],
72 |
73 | // 'users' => [
74 | // 'driver' => 'database',
75 | // 'table' => 'users',
76 | // ],
77 | ],
78 |
79 | /*
80 | |--------------------------------------------------------------------------
81 | | Resetting Passwords
82 | |--------------------------------------------------------------------------
83 | |
84 | | You may specify multiple password reset configurations if you have more
85 | | than one user table or model in the application and you want to have
86 | | separate password reset settings based on the specific user types.
87 | |
88 | | The expire time is the number of minutes that the reset token should be
89 | | considered valid. This security feature keeps tokens short-lived so
90 | | they have less time to be guessed. You may change this as needed.
91 | |
92 | */
93 |
94 | 'passwords' => [
95 | 'users' => [
96 | 'provider' => 'users',
97 | 'table' => 'password_resets',
98 | 'expire' => 60,
99 | ],
100 | ],
101 |
102 | ];
103 |
--------------------------------------------------------------------------------
/resources/views/auth/passwords/reset.blade.php:
--------------------------------------------------------------------------------
1 | @extends('layouts.app')
2 |
3 | @section('content')
4 |
5 |
6 |
7 |
8 |
Reset Password
9 |
10 |
11 | @if (session('status'))
12 |
13 | {{ session('status') }}
14 |
15 | @endif
16 |
17 |
18 | {{ csrf_field() }}
19 |
20 |
21 |
22 |
35 |
36 |
49 |
50 |
62 |
63 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | @endsection
77 |
--------------------------------------------------------------------------------
/resources/views/auth/register.blade.php:
--------------------------------------------------------------------------------
1 | @extends('layouts.app')
2 |
3 | @section('content')
4 |
5 |
6 |
7 |
8 |
Register
9 |
10 |
11 | {{ csrf_field() }}
12 |
13 |
26 |
27 |
40 |
41 |
54 |
55 |
62 |
63 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | @endsection
77 |
--------------------------------------------------------------------------------
/database/migrations/2017_03_21_104911_create_user_groups_table.php:
--------------------------------------------------------------------------------
1 | increments('id')->unsigned();
18 | $table->string('group');
19 | $table->string('group_code');
20 | $table->text('description')->nullable();
21 | });
22 |
23 | DB::table('user_groups')->delete();
24 | $user_groups = [
25 | [
26 | 'group' => "Super Admin",
27 | 'group_code' => "SU",
28 | ],
29 | [
30 | 'group' => "Admin",
31 | 'group_code' => "ADMIN",
32 | ],
33 | [
34 | 'group' => "Moderator",
35 | 'group_code' => "MODERATOR",
36 | ],
37 | [
38 | 'group' => "Staff",
39 | 'group_code' => "STAFF",
40 | ],
41 | [
42 | 'group' => "Member",
43 | 'group_code' => "MEMBER",
44 | ],
45 | [
46 | 'group' => "Banned",
47 | 'group_code' => "BANNED",
48 | ],
49 | [
50 | 'group' => "Deleted",
51 | 'group_code' => "DELETED",
52 | ],
53 | ];
54 | DB::table('user_groups')->insert($user_groups);
55 |
56 | Schema::table('users', function (Blueprint $table) {
57 | $table->bigIncrements('id')->change();
58 | $table->integer('group_id')->unsigned()->after('id');
59 | $table->boolean('active')->unsigned()->default(false)->after('password');
60 | });
61 |
62 | DB::table('users')->update([
63 | 'active' => true,
64 | 'group_id' => 5,
65 | ]);
66 |
67 | \App\Models\User::where('id', 2)->update(['group_id' => 1]);
68 |
69 | Schema::table('users', function (Blueprint $table) {
70 | $table->foreign('group_id')->references('id')->on('user_groups');
71 | });
72 |
73 | Schema::create('user_profile', function (Blueprint $table) {
74 | $table->bigIncrements('id')->unsigned();
75 | $table->bigInteger('user_id')->unsigned();
76 | $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
77 | $table->string('name')->nullable();
78 | $table->mediumText('welcome')->nullable();
79 | $table->date('birthday')->nullable();
80 | $table->enum('gender', ['male', 'female', 'other'])->nullable();
81 | $table->integer('country_id')->nullable();
82 | $table->string('city')->nullable();
83 | $table->string('facebook')->nullable();
84 | $table->string('twitter')->nullable();
85 | $table->string('signature')->nullable();
86 | $table->timestamps();
87 | });
88 | }
89 |
90 | /**
91 | * Reverse the migrations.
92 | *
93 | * @return void
94 | */
95 | public function down()
96 | {
97 | Schema::disableForeignKeyConstraints();
98 |
99 | Schema::table('users', function (Blueprint $table) {
100 | $table->dropForeign(['group_id']);
101 | });
102 |
103 | Schema::table('users', function (Blueprint $table) {
104 | $table->dropColumn(['group_id', 'active']);
105 | });
106 |
107 | Schema::enableForeignKeyConstraints();
108 |
109 | Schema::dropIfExists('user_profile');
110 | Schema::dropIfExists('user_groups');
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/config/database.php:
--------------------------------------------------------------------------------
1 | env('DB_CONNECTION', 'mysql'),
17 |
18 | /*
19 | |--------------------------------------------------------------------------
20 | | Database Connections
21 | |--------------------------------------------------------------------------
22 | |
23 | | Here are each of the database connections setup for your application.
24 | | Of course, examples of configuring each database platform that is
25 | | supported by Laravel is shown below to make development simple.
26 | |
27 | |
28 | | All database work in Laravel is done through the PHP PDO facilities
29 | | so make sure you have the driver for your particular database of
30 | | choice installed on your machine before you begin development.
31 | |
32 | */
33 |
34 | 'connections' => [
35 |
36 | 'sqlite' => [
37 | 'driver' => 'sqlite',
38 | 'database' => env('DB_DATABASE', database_path('database.sqlite')),
39 | 'prefix' => '',
40 | ],
41 |
42 | 'mysql' => [
43 | 'driver' => 'mysql',
44 | 'host' => env('DB_HOST', '127.0.0.1'),
45 | 'port' => env('DB_PORT', '3306'),
46 | 'database' => env('DB_DATABASE', 'forge'),
47 | 'username' => env('DB_USERNAME', 'forge'),
48 | 'password' => env('DB_PASSWORD', ''),
49 | 'unix_socket' => env('DB_SOCKET', ''),
50 | 'charset' => 'utf8mb4',
51 | 'collation' => 'utf8mb4_unicode_ci',
52 | 'prefix' => '',
53 | 'strict' => false,
54 | 'engine' => null,
55 | ],
56 |
57 | 'pgsql' => [
58 | 'driver' => 'pgsql',
59 | 'host' => env('DB_HOST', '127.0.0.1'),
60 | 'port' => env('DB_PORT', '5432'),
61 | 'database' => env('DB_DATABASE', 'forge'),
62 | 'username' => env('DB_USERNAME', 'forge'),
63 | 'password' => env('DB_PASSWORD', ''),
64 | 'charset' => 'utf8',
65 | 'prefix' => '',
66 | 'schema' => 'public',
67 | 'sslmode' => 'prefer',
68 | ],
69 |
70 | ],
71 |
72 | /*
73 | |--------------------------------------------------------------------------
74 | | Migration Repository Table
75 | |--------------------------------------------------------------------------
76 | |
77 | | This table keeps track of all the migrations that have already run for
78 | | your application. Using this information, we can determine which of
79 | | the migrations on disk haven't actually been run in the database.
80 | |
81 | */
82 |
83 | 'migrations' => 'migrations',
84 |
85 | /*
86 | |--------------------------------------------------------------------------
87 | | Redis Databases
88 | |--------------------------------------------------------------------------
89 | |
90 | | Redis is an open source, fast, and advanced key-value store that also
91 | | provides a richer set of commands than a typical key-value systems
92 | | such as APC or Memcached. Laravel makes it easy to dig right in.
93 | |
94 | */
95 |
96 | 'redis' => [
97 |
98 | 'client' => 'phpredis',
99 |
100 | 'default' => [
101 | 'host' => env('REDIS_HOST', '127.0.0.1'),
102 | 'password' => env('REDIS_PASSWORD', null),
103 | 'port' => env('REDIS_PORT', 6379),
104 | // 'database' => 0,
105 | 'timeout' => 5,
106 | 'read_timeout' => 60,
107 | ],
108 |
109 | ],
110 |
111 | ];
112 |
--------------------------------------------------------------------------------
/config/mail.php:
--------------------------------------------------------------------------------
1 | env('MAIL_DRIVER', 'smtp'),
20 |
21 | /*
22 | |--------------------------------------------------------------------------
23 | | SMTP Host Address
24 | |--------------------------------------------------------------------------
25 | |
26 | | Here you may provide the host address of the SMTP server used by your
27 | | applications. A default option is provided that is compatible with
28 | | the Mailgun mail service which will provide reliable deliveries.
29 | |
30 | */
31 |
32 | 'host' => env('MAIL_HOST', 'smtp.mailgun.org'),
33 |
34 | /*
35 | |--------------------------------------------------------------------------
36 | | SMTP Host Port
37 | |--------------------------------------------------------------------------
38 | |
39 | | This is the SMTP port used by your application to deliver e-mails to
40 | | users of the application. Like the host we have set this value to
41 | | stay compatible with the Mailgun e-mail application by default.
42 | |
43 | */
44 |
45 | 'port' => env('MAIL_PORT', 587),
46 |
47 | /*
48 | |--------------------------------------------------------------------------
49 | | Global "From" Address
50 | |--------------------------------------------------------------------------
51 | |
52 | | You may wish for all e-mails sent by your application to be sent from
53 | | the same address. Here, you may specify a name and address that is
54 | | used globally for all e-mails that are sent by your application.
55 | |
56 | */
57 |
58 | 'from' => [
59 | 'address' => env('MAIL_FROM', 'hello@example.com'),
60 | 'name' => env('SITE_NAME', 'Example'),
61 | ],
62 |
63 | /*
64 | |--------------------------------------------------------------------------
65 | | E-Mail Encryption Protocol
66 | |--------------------------------------------------------------------------
67 | |
68 | | Here you may specify the encryption protocol that should be used when
69 | | the application send e-mail messages. A sensible default using the
70 | | transport layer security protocol should provide great security.
71 | |
72 | */
73 |
74 | 'encryption' => env('MAIL_ENCRYPTION', 'tls'),
75 |
76 | /*
77 | |--------------------------------------------------------------------------
78 | | SMTP Server Username
79 | |--------------------------------------------------------------------------
80 | |
81 | | If your SMTP server requires a username for authentication, you should
82 | | set it here. This will get used to authenticate with your server on
83 | | connection. You may also set the "password" value below this one.
84 | |
85 | */
86 |
87 | 'username' => env('MAIL_USERNAME'),
88 |
89 | 'password' => env('MAIL_PASSWORD'),
90 |
91 | /*
92 | |--------------------------------------------------------------------------
93 | | Sendmail System Path
94 | |--------------------------------------------------------------------------
95 | |
96 | | When using the "sendmail" driver to send e-mails, we will need to know
97 | | the path to where Sendmail lives on this server. A default path has
98 | | been provided here, which will work well on most of your systems.
99 | |
100 | */
101 |
102 | 'sendmail' => '/usr/sbin/sendmail -bs',
103 |
104 | /*
105 | |--------------------------------------------------------------------------
106 | | Markdown Mail Settings
107 | |--------------------------------------------------------------------------
108 | |
109 | | If you are using Markdown based email rendering, you may configure your
110 | | theme and component paths here, allowing you to customize the design
111 | | of the emails. Or, you may simply stick with the Laravel defaults!
112 | |
113 | */
114 |
115 | 'markdown' => [
116 | 'theme' => 'default',
117 |
118 | 'paths' => [
119 | resource_path('views/vendor/mail'),
120 | ],
121 | ],
122 |
123 | ];
124 |
--------------------------------------------------------------------------------
/resources/assets/js/init.js:
--------------------------------------------------------------------------------
1 | if (typeof jQuery === 'undefined') {
2 | throw new Error('Requires jQuery')
3 | }
4 |
5 | import swal from "sweetalert2";
6 |
7 | const CSRFTOKEN = $('meta[name=_token]').attr('content');
8 | const BASEURL = $('meta[name=_base_url]').attr('content');
9 |
10 | +(function ($) {
11 | 'use strict';
12 |
13 | $(window).on('load resize', function () {
14 | $('#content-area').css('min-height', $(window).height() - ($('header').height() + $('footer').height() + 80) + 'px');
15 | });
16 |
17 | // Tooltip
18 | $('[data-toggle="tooltip"]').tooltip({'container': 'body'});
19 |
20 | // Popover
21 | $('[data-toggle="popover"]').popover();
22 |
23 | let btn_upload = $('#btn_upload');
24 | let btn_upload_disable = function () {
25 | if (!btn_upload.prop('disabled')) {
26 | $('input[name="qqfile"]').addClass('disabled').attr('disabled', 'disabled');
27 | btn_upload.addClass('disabled').attr('disabled', 'disabled').before(' ');
28 | }
29 | };
30 | let btn_upload_enable = function () {
31 | if (btn_upload.prop('disabled')) {
32 | $('.save-spinner').remove();
33 | $('input[name="qqfile"]').removeClass('disabled').removeAttribute('disabled');
34 | btn_upload.removeClass('disabled').removeAttribute('disabled');
35 | }
36 | };
37 |
38 | let fuploader = $('#images_fileuploader').fineUploader({
39 | template: "upload-template",
40 | thumbnails: {
41 | placeholders: {
42 | waitingPath: BASEURL + "/images/waiting-generic.png",
43 | notAvailablePath: BASEURL + "/images/not_available-generic.png"
44 | }
45 | },
46 | request: {
47 | endpoint: BASEURL + '/image/upload',
48 | params: {_token: CSRFTOKEN}
49 | },
50 | editFilename: {
51 | enabled: false
52 | },
53 | retry: {
54 | enableAuto: false
55 | },
56 | chunking: {
57 | enabled: false
58 | },
59 | deleteFile: {
60 | enabled: true,
61 | method: "DELETE",
62 | endpoint: BASEURL + '/image/delete',
63 | params: {_token: CSRFTOKEN}
64 | },
65 | autoUpload: false,
66 | validation: {
67 | allowedExtensions: ['jpeg', 'jpg', 'gif', 'png'],
68 | sizeLimit: 67108864 // 64 Mb
69 | },
70 | callbacks: {
71 | onError: function (id, name, errorReason) {
72 | let fileEl = fuploader.fineUploader("getItemByFileId", id);
73 | fileEl.find('.upload-error')
74 | .removeClass('hidden')
75 | .find('.error-msg').text('Error: ' + errorReason);
76 | btn_upload_enable();
77 | },
78 |
79 | onUpload: function (id, name) {
80 | btn_upload_disable();
81 | },
82 |
83 | onComplete: function (id, name, response) {
84 | if (response.success) {
85 | let image_id = response.imageId;
86 | let fileEl = fuploader.fineUploader("getItemByFileId", id),
87 | imageEl = fileEl.find(".uploaded-image");
88 |
89 | imageEl.html(' ');
90 | fuploader.fineUploader("setUuid", id, image_id);
91 | } else {
92 | btn_upload_enable();
93 | }
94 | },
95 |
96 | onAllComplete: function (s, f) {
97 | if (s.length > 0) {
98 | $('#form_upload').submit();
99 | }
100 | }
101 | }
102 | });
103 |
104 | btn_upload.click(function (e) {
105 | fuploader.fineUploader('uploadStoredFiles');
106 | e.preventDefault();
107 | });
108 |
109 | $('.btn_delete_album, .btn_delete_image').click(function (e) {
110 | let album_id = $(this).data('album-id');
111 | let image_id = $(this).data('image-id');
112 |
113 | let delete_type = 'Album';
114 | let data_id = album_id;
115 | if (!isNaN(image_id)) {
116 | delete_type = 'Image';
117 | data_id = image_id;
118 | }
119 |
120 | swal({
121 | title: 'Delete this ' + delete_type + '?',
122 | text: 'Are you sure, you want to delete this ' + delete_type + '?',
123 | type: 'warning',
124 | showCancelButton: true,
125 | confirmButtonText: 'Delete',
126 | cancelButtonText: 'Cancel',
127 | confirmButtonColor: '#d33',
128 | cancelButtonColor: '#3085d6',
129 | allowOutsideClick: false,
130 | showLoaderOnConfirm: true,
131 | preConfirm: function () {
132 | return new Promise(function (resolve, reject) {
133 | return $.ajax({
134 | url: BASEURL + '/image/delete',
135 | type: 'DELETE',
136 | data: {'_token': CSRFTOKEN, 'action': delete_type, 'id': data_id},
137 | dataType: 'json'
138 | }).done(function (msg) {
139 | resolve();
140 | }).fail(function (jqXHR) {
141 | reject('Error: ' + ((jqXHR.responseJSON) ? jqXHR.responseJSON : jqXHR.statusText));
142 | });
143 | });
144 | }
145 | }).then(function () {
146 | swal(delete_type + " Deleted!", delete_type + " deleted successfully.", "success");
147 | }, function () {
148 | swal.resetDefaults()
149 | });
150 |
151 | e.preventDefault();
152 | })
153 |
154 | })(jQuery);
--------------------------------------------------------------------------------
/resources/lang/en/validation.php:
--------------------------------------------------------------------------------
1 | 'The :attribute must be accepted.',
17 | 'active_url' => 'The :attribute is not a valid URL.',
18 | 'after' => 'The :attribute must be a date after :date.',
19 | 'after_or_equal' => 'The :attribute must be a date after or equal to :date.',
20 | 'alpha' => 'The :attribute may only contain letters.',
21 | 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.',
22 | 'alpha_num' => 'The :attribute may only contain letters and numbers.',
23 | 'array' => 'The :attribute must be an array.',
24 | 'before' => 'The :attribute must be a date before :date.',
25 | 'before_or_equal' => 'The :attribute must be a date before or equal to :date.',
26 | 'between' => [
27 | 'numeric' => 'The :attribute must be between :min and :max.',
28 | 'file' => 'The :attribute must be between :min and :max kilobytes.',
29 | 'string' => 'The :attribute must be between :min and :max characters.',
30 | 'array' => 'The :attribute must have between :min and :max items.',
31 | ],
32 | 'boolean' => 'The :attribute field must be true or false.',
33 | 'confirmed' => 'The :attribute confirmation does not match.',
34 | 'date' => 'The :attribute is not a valid date.',
35 | 'date_format' => 'The :attribute does not match the format :format.',
36 | 'different' => 'The :attribute and :other must be different.',
37 | 'digits' => 'The :attribute must be :digits digits.',
38 | 'digits_between' => 'The :attribute must be between :min and :max digits.',
39 | 'dimensions' => 'The :attribute has invalid image dimensions.',
40 | 'distinct' => 'The :attribute field has a duplicate value.',
41 | 'email' => 'The :attribute must be a valid email address.',
42 | 'exists' => 'The selected :attribute is invalid.',
43 | 'file' => 'The :attribute must be a file.',
44 | 'filled' => 'The :attribute field must have a value.',
45 | 'image' => 'The :attribute must be an image.',
46 | 'in' => 'The selected :attribute is invalid.',
47 | 'in_array' => 'The :attribute field does not exist in :other.',
48 | 'integer' => 'The :attribute must be an integer.',
49 | 'ip' => 'The :attribute must be a valid IP address.',
50 | 'json' => 'The :attribute must be a valid JSON string.',
51 | 'max' => [
52 | 'numeric' => 'The :attribute may not be greater than :max.',
53 | 'file' => 'The :attribute may not be greater than :max kilobytes.',
54 | 'string' => 'The :attribute may not be greater than :max characters.',
55 | 'array' => 'The :attribute may not have more than :max items.',
56 | ],
57 | 'mimes' => 'The :attribute must be a file of type: :values.',
58 | 'mimetypes' => 'The :attribute must be a file of type: :values.',
59 | 'min' => [
60 | 'numeric' => 'The :attribute must be at least :min.',
61 | 'file' => 'The :attribute must be at least :min kilobytes.',
62 | 'string' => 'The :attribute must be at least :min characters.',
63 | 'array' => 'The :attribute must have at least :min items.',
64 | ],
65 | 'not_in' => 'The selected :attribute is invalid.',
66 | 'numeric' => 'The :attribute must be a number.',
67 | 'present' => 'The :attribute field must be present.',
68 | 'regex' => 'The :attribute format is invalid.',
69 | 'required' => 'The :attribute field is required.',
70 | 'required_if' => 'The :attribute field is required when :other is :value.',
71 | 'required_unless' => 'The :attribute field is required unless :other is in :values.',
72 | 'required_with' => 'The :attribute field is required when :values is present.',
73 | 'required_with_all' => 'The :attribute field is required when :values is present.',
74 | 'required_without' => 'The :attribute field is required when :values is not present.',
75 | 'required_without_all' => 'The :attribute field is required when none of :values are present.',
76 | 'same' => 'The :attribute and :other must match.',
77 | 'size' => [
78 | 'numeric' => 'The :attribute must be :size.',
79 | 'file' => 'The :attribute must be :size kilobytes.',
80 | 'string' => 'The :attribute must be :size characters.',
81 | 'array' => 'The :attribute must contain :size items.',
82 | ],
83 | 'string' => 'The :attribute must be a string.',
84 | 'timezone' => 'The :attribute must be a valid zone.',
85 | 'unique' => 'The :attribute has already been taken.',
86 | 'uploaded' => 'The :attribute failed to upload.',
87 | 'url' => 'The :attribute format is invalid.',
88 |
89 | /*
90 | |--------------------------------------------------------------------------
91 | | Custom Validation Language Lines
92 | |--------------------------------------------------------------------------
93 | |
94 | | Here you may specify custom validation messages for attributes using the
95 | | convention "attribute.rule" to name the lines. This makes it quick to
96 | | specify a specific custom language line for a given attribute rule.
97 | |
98 | */
99 |
100 | 'custom' => [
101 | 'attribute-name' => [
102 | 'rule-name' => 'custom-message',
103 | ],
104 | ],
105 |
106 | /*
107 | |--------------------------------------------------------------------------
108 | | Custom Validation Attributes
109 | |--------------------------------------------------------------------------
110 | |
111 | | The following language lines are used to swap attribute place-holders
112 | | with something more reader friendly such as E-Mail Address instead
113 | | of "email". This simply helps us make messages a little cleaner.
114 | |
115 | */
116 |
117 | 'attributes' => [],
118 |
119 | ];
120 |
--------------------------------------------------------------------------------
/config/session.php:
--------------------------------------------------------------------------------
1 | env('SESSION_DRIVER', 'file'),
20 |
21 | /*
22 | |--------------------------------------------------------------------------
23 | | Session Lifetime
24 | |--------------------------------------------------------------------------
25 | |
26 | | Here you may specify the number of minutes that you wish the session
27 | | to be allowed to remain idle before it expires. If you want them
28 | | to immediately expire on the browser closing, set that option.
29 | |
30 | */
31 |
32 | 'lifetime' => 120,
33 |
34 | 'expire_on_close' => false,
35 |
36 | /*
37 | |--------------------------------------------------------------------------
38 | | Session Encryption
39 | |--------------------------------------------------------------------------
40 | |
41 | | This option allows you to easily specify that all of your session data
42 | | should be encrypted before it is stored. All encryption will be run
43 | | automatically by Laravel and you can use the Session like normal.
44 | |
45 | */
46 |
47 | 'encrypt' => false,
48 |
49 | /*
50 | |--------------------------------------------------------------------------
51 | | Session File Location
52 | |--------------------------------------------------------------------------
53 | |
54 | | When using the native session driver, we need a location where session
55 | | files may be stored. A default has been set for you but a different
56 | | location may be specified. This is only needed for file sessions.
57 | |
58 | */
59 |
60 | 'files' => storage_path('framework/sessions'),
61 |
62 | /*
63 | |--------------------------------------------------------------------------
64 | | Session Database Connection
65 | |--------------------------------------------------------------------------
66 | |
67 | | When using the "database" or "redis" session drivers, you may specify a
68 | | connection that should be used to manage these sessions. This should
69 | | correspond to a connection in your database configuration options.
70 | |
71 | */
72 |
73 | 'connection' => null,
74 |
75 | /*
76 | |--------------------------------------------------------------------------
77 | | Session Database Table
78 | |--------------------------------------------------------------------------
79 | |
80 | | When using the "database" session driver, you may specify the table we
81 | | should use to manage the sessions. Of course, a sensible default is
82 | | provided for you; however, you are free to change this as needed.
83 | |
84 | */
85 |
86 | 'table' => 'sessions',
87 |
88 | /*
89 | |--------------------------------------------------------------------------
90 | | Session Cache Store
91 | |--------------------------------------------------------------------------
92 | |
93 | | When using the "apc" or "memcached" session drivers, you may specify a
94 | | cache store that should be used for these sessions. This value must
95 | | correspond with one of the application's configured cache stores.
96 | |
97 | */
98 |
99 | 'store' => null,
100 |
101 | /*
102 | |--------------------------------------------------------------------------
103 | | Session Sweeping Lottery
104 | |--------------------------------------------------------------------------
105 | |
106 | | Some session drivers must manually sweep their storage location to get
107 | | rid of old sessions from storage. Here are the chances that it will
108 | | happen on a given request. By default, the odds are 2 out of 100.
109 | |
110 | */
111 |
112 | 'lottery' => [2, 100],
113 |
114 | /*
115 | |--------------------------------------------------------------------------
116 | | Session Cookie Name
117 | |--------------------------------------------------------------------------
118 | |
119 | | Here you may change the name of the cookie used to identify a session
120 | | instance by ID. The name specified here will get used every time a
121 | | new session cookie is created by the framework for every driver.
122 | |
123 | */
124 |
125 | 'cookie' => 'laravel_session',
126 |
127 | /*
128 | |--------------------------------------------------------------------------
129 | | Session Cookie Path
130 | |--------------------------------------------------------------------------
131 | |
132 | | The session cookie path determines the path for which the cookie will
133 | | be regarded as available. Typically, this will be the root path of
134 | | your application but you are free to change this when necessary.
135 | |
136 | */
137 |
138 | 'path' => '/',
139 |
140 | /*
141 | |--------------------------------------------------------------------------
142 | | Session Cookie Domain
143 | |--------------------------------------------------------------------------
144 | |
145 | | Here you may change the domain of the cookie used to identify a session
146 | | in your application. This will determine which domains the cookie is
147 | | available to in your application. A sensible default has been set.
148 | |
149 | */
150 |
151 | 'domain' => env('SESSION_DOMAIN', null),
152 |
153 | /*
154 | |--------------------------------------------------------------------------
155 | | HTTPS Only Cookies
156 | |--------------------------------------------------------------------------
157 | |
158 | | By setting this option to true, session cookies will only be sent back
159 | | to the server if the browser has a HTTPS connection. This will keep
160 | | the cookie from being sent to you if it can not be done securely.
161 | |
162 | */
163 |
164 | 'secure' => env('SESSION_SECURE_COOKIE', false),
165 |
166 | /*
167 | |--------------------------------------------------------------------------
168 | | HTTP Access Only
169 | |--------------------------------------------------------------------------
170 | |
171 | | Setting this value to true will prevent JavaScript from accessing the
172 | | value of the cookie and the cookie will only be accessible through
173 | | the HTTP protocol. You are free to modify this option if needed.
174 | |
175 | */
176 |
177 | 'http_only' => true,
178 |
179 | ];
180 |
--------------------------------------------------------------------------------
/app/Services/Filer.php:
--------------------------------------------------------------------------------
1 | manager = app('filesystem');
24 |
25 | $this->storage_local = $this->manager->disk('local');
26 | $this->storage_cloud = $this->manager->disk(config('filesystems.cloud'));
27 | $this->storage_tmp = $this->manager->disk('tmp');
28 |
29 | $this->setStorage();
30 | }
31 |
32 | /**
33 | * @param string $type
34 | *
35 | * @return self
36 | */
37 | public function type($type)
38 | {
39 | $this->file_type = $type;
40 | $this->file_path = $type . DIRECTORY_SEPARATOR;
41 |
42 | if ($this->isLocal()) {
43 | $this->full_path = config('filesystems.disks.local.root');
44 | }
45 |
46 | $this->setStorage();
47 |
48 | if ($type == 'tmp' || $type == 'temp') {
49 | $this->file_path = '';
50 | $this->storage = $this->storage_tmp;
51 | $this->full_path = config('filesystems.disks.tmp.root');
52 | }
53 |
54 | return $this;
55 | }
56 |
57 | /**
58 | * @param string $file
59 | *
60 | * @return string
61 | */
62 | public function path($file)
63 | {
64 | if ($this->isLocal()) {
65 | return $this->full_path . DIRECTORY_SEPARATOR . $this->file_path . $file;
66 | }
67 |
68 | return $this->file_path . $file;
69 | }
70 |
71 | /**
72 | * @param string $file
73 | *
74 | * @return mixed
75 | */
76 | public function size($file)
77 | {
78 | if ($this->has($file)) {
79 | return $this->storage->size($this->file_path . $file);
80 | }
81 |
82 | return false;
83 | }
84 |
85 | /**
86 | * @param $file
87 | *
88 | * @return mixed
89 | */
90 | public function has($file)
91 | {
92 | return $this->storage->exists($this->file_path . $file) ? true : $this->sync($file);
93 | }
94 |
95 | /**
96 | * @param $file
97 | *
98 | * @return mixed
99 | */
100 | public function get($file)
101 | {
102 | if ($this->has($file)) {
103 | return $this->storage->get($this->file_path . $file);
104 | }
105 | if ($this->sync($file)) {
106 | return $this->storage->get($this->file_path . $file);
107 | }
108 |
109 | return false;
110 | }
111 |
112 | /**
113 | * @param $file
114 | * @param $contents
115 | *
116 | * @return bool
117 | */
118 | public function put($file, $contents)
119 | {
120 | $saved = $this->storage->put($this->file_path . $file, $contents);
121 |
122 | if ($saved) {
123 | $this->sync($file);
124 | }
125 |
126 | return $saved;
127 | }
128 |
129 | /**
130 | * @param $source
131 | * @param $destination
132 | *
133 | * @return bool
134 | */
135 | public function copy($source, $destination)
136 | {
137 | $this->storage->copy($source, $this->file_path . $destination);
138 | $this->sync($destination);
139 | }
140 |
141 | /**
142 | * @param $source
143 | * @param $destination
144 | *
145 | * @return bool
146 | */
147 | public function move($source, $destination)
148 | {
149 | $this->storage->move($source, $this->file_path . $destination);
150 | $this->sync($destination);
151 | }
152 |
153 | /**
154 | * @param $file
155 | *
156 | * @return bool
157 | */
158 | public function delete($file)
159 | {
160 | if ($this->file_type != 'tmp' && $this->shouldSync()) {
161 | $cloud_delete = false;
162 | if ($this->storage_cloud->exists($this->file_path . $file)) {
163 | $cloud_delete = $this->storage_cloud->delete($this->file_path . $file);
164 | }
165 | $local_delete = false;
166 | if ($this->storage_local->exists($this->file_path . $file)) {
167 | $local_delete = $this->storage_local->delete($this->file_path . $file);
168 | }
169 |
170 | return $cloud_delete || $local_delete;
171 | }
172 |
173 | if ($this->has($file)) {
174 | return $this->storage->delete($this->file_path . $file);
175 | }
176 |
177 | return false;
178 | }
179 |
180 | /**
181 | * @param $file
182 | *
183 | * @return bool
184 | */
185 | public function sync($file)
186 | {
187 | if ($this->file_type == 'tmp') {
188 | return false;
189 | }
190 |
191 | if ($this->shouldSync()) {
192 | if ($this->storage_local->exists($this->file_path . $file)) {
193 | if ($this->storage_cloud->exists($this->file_path . $file)) {
194 | return true;
195 | } else {
196 | return $this->storage_cloud->put($this->file_path . $file, $this->storage_local->get($this->file_path . $file));
197 | }
198 | }
199 | if ($this->storage_cloud->exists($this->file_path . $file)) {
200 | if ($this->storage_local->exists($this->file_path . $file)) {
201 | return true;
202 | } else {
203 | return $this->storage_local->put($this->file_path . $file, $this->storage_cloud->get($this->file_path . $file));
204 | }
205 | }
206 | }
207 |
208 | return false;
209 | }
210 |
211 | protected function isLocal()
212 | {
213 | if ($this->storage_type == 'local' || $this->storage_type == 'localcloud') {
214 | return true;
215 | }
216 |
217 | return false;
218 | }
219 |
220 | protected function shouldSync()
221 | {
222 | if ($this->storage_type == 'localcloud') {
223 | return true;
224 | }
225 |
226 | return false;
227 | }
228 |
229 | private function setStorage()
230 | {
231 | switch (env('APP_STORAGE', 'local')) {
232 | case 'local':
233 | $this->storage = $this->storage_local;
234 | $this->storage_type = 'local';
235 | break;
236 | case 'localcloud':
237 | $this->storage = $this->storage_local;
238 | $this->storage_type = 'localcloud';
239 | break;
240 | case 'cloud':
241 | $this->storage = $this->storage_cloud;
242 | $this->storage_type = 'cloud';
243 | break;
244 | }
245 | }
246 | }
247 |
--------------------------------------------------------------------------------
/database/migrations/2017_03_21_111636_create_countries_table.php:
--------------------------------------------------------------------------------
1 | increments('id')->unsigned();
18 | $table->char('code', 2);
19 | $table->string('country');
20 | $table->char('continent', 4);
21 | });
22 |
23 | DB::unprepared("INSERT INTO `countries` (`code`, `country`, `continent`) VALUES
24 | ('AF', 'Afghanistan', 'AS'),
25 | ('AX', 'Aland Islands', 'EU'),
26 | ('AL', 'Albania', 'EU'),
27 | ('DZ', 'Algeria', 'AF'),
28 | ('AS', 'American Samoa', 'OC'),
29 | ('AD', 'Andorra', 'EU'),
30 | ('AO', 'Angola', 'AF'),
31 | ('AI', 'Anguilla', 'NA'),
32 | ('AQ', 'Antarctica', 'AN'),
33 | ('AG', 'Antigua and Barbuda', 'NA'),
34 | ('AR', 'Argentina', 'SA'),
35 | ('AM', 'Armenia', 'AS'),
36 | ('AW', 'Aruba', 'NA'),
37 | ('AU', 'Australia', 'OC'),
38 | ('AT', 'Austria', 'EU'),
39 | ('AZ', 'Azerbaijan', 'AS'),
40 | ('BS', 'Bahamas', 'NA'),
41 | ('BH', 'Bahrain', 'AS'),
42 | ('BD', 'Bangladesh', 'AS'),
43 | ('BB', 'Barbados', 'NA'),
44 | ('BY', 'Belarus', 'EU'),
45 | ('BE', 'Belgium', 'EU'),
46 | ('BZ', 'Belize', 'NA'),
47 | ('BJ', 'Benin', 'AF'),
48 | ('BM', 'Bermuda', 'NA'),
49 | ('BT', 'Bhutan', 'AS'),
50 | ('BO', 'Bolivia', 'SA'),
51 | ('BQ', 'Bonaire, Saint Eustatius and Saba ', 'NA'),
52 | ('BA', 'Bosnia and Herzegovina', 'EU'),
53 | ('BW', 'Botswana', 'AF'),
54 | ('BV', 'Bouvet Island', 'AN'),
55 | ('BR', 'Brazil', 'SA'),
56 | ('IO', 'British Indian Ocean Territory', 'AS'),
57 | ('VG', 'British Virgin Islands', 'NA'),
58 | ('BN', 'Brunei', 'AS'),
59 | ('BG', 'Bulgaria', 'EU'),
60 | ('BF', 'Burkina Faso', 'AF'),
61 | ('BI', 'Burundi', 'AF'),
62 | ('KH', 'Cambodia', 'AS'),
63 | ('CM', 'Cameroon', 'AF'),
64 | ('CA', 'Canada', 'NA'),
65 | ('CV', 'Cape Verde', 'AF'),
66 | ('KY', 'Cayman Islands', 'NA'),
67 | ('CF', 'Central African Republic', 'AF'),
68 | ('TD', 'Chad', 'AF'),
69 | ('CL', 'Chile', 'SA'),
70 | ('CN', 'China', 'AS'),
71 | ('CX', 'Christmas Island', 'AS'),
72 | ('CC', 'Cocos Islands', 'AS'),
73 | ('CO', 'Colombia', 'SA'),
74 | ('KM', 'Comoros', 'AF'),
75 | ('CK', 'Cook Islands', 'OC'),
76 | ('CR', 'Costa Rica', 'NA'),
77 | ('HR', 'Croatia', 'EU'),
78 | ('CU', 'Cuba', 'NA'),
79 | ('CW', 'Curacao', 'NA'),
80 | ('CY', 'Cyprus', 'EU'),
81 | ('CZ', 'Czech Republic', 'EU'),
82 | ('CD', 'Democratic Republic of the Congo', 'AF'),
83 | ('DK', 'Denmark', 'EU'),
84 | ('DJ', 'Djibouti', 'AF'),
85 | ('DM', 'Dominica', 'NA'),
86 | ('DO', 'Dominican Republic', 'NA'),
87 | ('TL', 'East Timor', 'OC'),
88 | ('EC', 'Ecuador', 'SA'),
89 | ('EG', 'Egypt', 'AF'),
90 | ('SV', 'El Salvador', 'NA'),
91 | ('GQ', 'Equatorial Guinea', 'AF'),
92 | ('ER', 'Eritrea', 'AF'),
93 | ('EE', 'Estonia', 'EU'),
94 | ('ET', 'Ethiopia', 'AF'),
95 | ('FK', 'Falkland Islands', 'SA'),
96 | ('FO', 'Faroe Islands', 'EU'),
97 | ('FJ', 'Fiji', 'OC'),
98 | ('FI', 'Finland', 'EU'),
99 | ('FR', 'France', 'EU'),
100 | ('GF', 'French Guiana', 'SA'),
101 | ('PF', 'French Polynesia', 'OC'),
102 | ('TF', 'French Southern Territories', 'AN'),
103 | ('GA', 'Gabon', 'AF'),
104 | ('GM', 'Gambia', 'AF'),
105 | ('GE', 'Georgia', 'AS'),
106 | ('DE', 'Germany', 'EU'),
107 | ('GH', 'Ghana', 'AF'),
108 | ('GI', 'Gibraltar', 'EU'),
109 | ('GR', 'Greece', 'EU'),
110 | ('GL', 'Greenland', 'NA'),
111 | ('GD', 'Grenada', 'NA'),
112 | ('GP', 'Guadeloupe', 'NA'),
113 | ('GU', 'Guam', 'OC'),
114 | ('GT', 'Guatemala', 'NA'),
115 | ('GG', 'Guernsey', 'EU'),
116 | ('GN', 'Guinea', 'AF'),
117 | ('GW', 'GuineaBissau', 'AF'),
118 | ('GY', 'Guyana', 'SA'),
119 | ('HT', 'Haiti', 'NA'),
120 | ('HM', 'Heard Island and McDonald Islands', 'AN'),
121 | ('HN', 'Honduras', 'NA'),
122 | ('HK', 'Hong Kong', 'AS'),
123 | ('HU', 'Hungary', 'EU'),
124 | ('IS', 'Iceland', 'EU'),
125 | ('IN', 'India', 'AS'),
126 | ('ID', 'Indonesia', 'AS'),
127 | ('IR', 'Iran', 'AS'),
128 | ('IQ', 'Iraq', 'AS'),
129 | ('IE', 'Ireland', 'EU'),
130 | ('IM', 'Isle of Man', 'EU'),
131 | ('IL', 'Israel', 'AS'),
132 | ('IT', 'Italy', 'EU'),
133 | ('CI', 'Ivory Coast', 'AF'),
134 | ('JM', 'Jamaica', 'NA'),
135 | ('JP', 'Japan', 'AS'),
136 | ('JE', 'Jersey', 'EU'),
137 | ('JO', 'Jordan', 'AS'),
138 | ('KZ', 'Kazakhstan', 'AS'),
139 | ('KE', 'Kenya', 'AF'),
140 | ('KI', 'Kiribati', 'OC'),
141 | ('XK', 'Kosovo', 'EU'),
142 | ('KW', 'Kuwait', 'AS'),
143 | ('KG', 'Kyrgyzstan', 'AS'),
144 | ('LA', 'Laos', 'AS'),
145 | ('LV', 'Latvia', 'EU'),
146 | ('LB', 'Lebanon', 'AS'),
147 | ('LS', 'Lesotho', 'AF'),
148 | ('LR', 'Liberia', 'AF'),
149 | ('LY', 'Libya', 'AF'),
150 | ('LI', 'Liechtenstein', 'EU'),
151 | ('LT', 'Lithuania', 'EU'),
152 | ('LU', 'Luxembourg', 'EU'),
153 | ('MO', 'Macao', 'AS'),
154 | ('MK', 'Macedonia', 'EU'),
155 | ('MG', 'Madagascar', 'AF'),
156 | ('MW', 'Malawi', 'AF'),
157 | ('MY', 'Malaysia', 'AS'),
158 | ('MV', 'Maldives', 'AS'),
159 | ('ML', 'Mali', 'AF'),
160 | ('MT', 'Malta', 'EU'),
161 | ('MH', 'Marshall Islands', 'OC'),
162 | ('MQ', 'Martinique', 'NA'),
163 | ('MR', 'Mauritania', 'AF'),
164 | ('MU', 'Mauritius', 'AF'),
165 | ('YT', 'Mayotte', 'AF'),
166 | ('MX', 'Mexico', 'NA'),
167 | ('FM', 'Micronesia', 'OC'),
168 | ('MD', 'Moldova', 'EU'),
169 | ('MC', 'Monaco', 'EU'),
170 | ('MN', 'Mongolia', 'AS'),
171 | ('ME', 'Montenegro', 'EU'),
172 | ('MS', 'Montserrat', 'NA'),
173 | ('MA', 'Morocco', 'AF'),
174 | ('MZ', 'Mozambique', 'AF'),
175 | ('MM', 'Myanmar', 'AS'),
176 | ('NA', 'Namibia', 'AF'),
177 | ('NR', 'Nauru', 'OC'),
178 | ('NP', 'Nepal', 'AS'),
179 | ('NL', 'Netherlands', 'EU'),
180 | ('AN', 'Netherlands Antilles', 'NA'),
181 | ('NC', 'New Caledonia', 'OC'),
182 | ('NZ', 'New Zealand', 'OC'),
183 | ('NI', 'Nicaragua', 'NA'),
184 | ('NE', 'Niger', 'AF'),
185 | ('NG', 'Nigeria', 'AF'),
186 | ('NU', 'Niue', 'OC'),
187 | ('NF', 'Norfolk Island', 'OC'),
188 | ('KP', 'North Korea', 'AS'),
189 | ('MP', 'Northern Mariana Islands', 'OC'),
190 | ('NO', 'Norway', 'EU'),
191 | ('OM', 'Oman', 'AS'),
192 | ('PK', 'Pakistan', 'AS'),
193 | ('PW', 'Palau', 'OC'),
194 | ('PS', 'Palestinian Territory', 'AS'),
195 | ('PA', 'Panama', 'NA'),
196 | ('PG', 'Papua New Guinea', 'OC'),
197 | ('PY', 'Paraguay', 'SA'),
198 | ('PE', 'Peru', 'SA'),
199 | ('PH', 'Philippines', 'AS'),
200 | ('PN', 'Pitcairn', 'OC'),
201 | ('PL', 'Poland', 'EU'),
202 | ('PT', 'Portugal', 'EU'),
203 | ('PR', 'Puerto Rico', 'NA'),
204 | ('QA', 'Qatar', 'AS'),
205 | ('CG', 'Republic of the Congo', 'AF'),
206 | ('RE', 'Reunion', 'AF'),
207 | ('RO', 'Romania', 'EU'),
208 | ('RU', 'Russia', 'EU'),
209 | ('RW', 'Rwanda', 'AF'),
210 | ('BL', 'Saint Barthelemy', 'NA'),
211 | ('SH', 'Saint Helena', 'AF'),
212 | ('KN', 'Saint Kitts and Nevis', 'NA'),
213 | ('LC', 'Saint Lucia', 'NA'),
214 | ('MF', 'Saint Martin', 'NA'),
215 | ('PM', 'Saint Pierre and Miquelon', 'NA'),
216 | ('VC', 'Saint Vincent and the Grenadines', 'NA'),
217 | ('WS', 'Samoa', 'OC'),
218 | ('SM', 'San Marino', 'EU'),
219 | ('ST', 'Sao Tome and Principe', 'AF'),
220 | ('SA', 'Saudi Arabia', 'AS'),
221 | ('SN', 'Senegal', 'AF'),
222 | ('RS', 'Serbia', 'EU'),
223 | ('CS', 'Serbia and Montenegro', 'EU'),
224 | ('SC', 'Seychelles', 'AF'),
225 | ('SL', 'Sierra Leone', 'AF'),
226 | ('SG', 'Singapore', 'AS'),
227 | ('SX', 'Sint Maarten', 'NA'),
228 | ('SK', 'Slovakia', 'EU'),
229 | ('SI', 'Slovenia', 'EU'),
230 | ('SB', 'Solomon Islands', 'OC'),
231 | ('SO', 'Somalia', 'AF'),
232 | ('ZA', 'South Africa', 'AF'),
233 | ('GS', 'South Georgia and the South Sandwich Islands', 'AN'),
234 | ('KR', 'South Korea', 'AS'),
235 | ('SS', 'South Sudan', 'AF'),
236 | ('ES', 'Spain', 'EU'),
237 | ('LK', 'Sri Lanka', 'AS'),
238 | ('SD', 'Sudan', 'AF'),
239 | ('SR', 'Suriname', 'SA'),
240 | ('SJ', 'Svalbard and Jan Mayen', 'EU'),
241 | ('SZ', 'Swaziland', 'AF'),
242 | ('SE', 'Sweden', 'EU'),
243 | ('CH', 'Switzerland', 'EU'),
244 | ('SY', 'Syria', 'AS'),
245 | ('TW', 'Taiwan', 'AS'),
246 | ('TJ', 'Tajikistan', 'AS'),
247 | ('TZ', 'Tanzania', 'AF'),
248 | ('TH', 'Thailand', 'AS'),
249 | ('TG', 'Togo', 'AF'),
250 | ('TK', 'Tokelau', 'OC'),
251 | ('TO', 'Tonga', 'OC'),
252 | ('TT', 'Trinidad and Tobago', 'NA'),
253 | ('TN', 'Tunisia', 'AF'),
254 | ('TR', 'Turkey', 'AS'),
255 | ('TM', 'Turkmenistan', 'AS'),
256 | ('TC', 'Turks and Caicos Islands', 'NA'),
257 | ('TV', 'Tuvalu', 'OC'),
258 | ('VI', 'U.S. Virgin Islands', 'NA'),
259 | ('UG', 'Uganda', 'AF'),
260 | ('UA', 'Ukraine', 'EU'),
261 | ('AE', 'United Arab Emirates', 'AS'),
262 | ('GB', 'United Kingdom', 'EU'),
263 | ('US', 'United States', 'NA'),
264 | ('UM', 'United States Minor Outlying Islands', 'OC'),
265 | ('UY', 'Uruguay', 'SA'),
266 | ('UZ', 'Uzbekistan', 'AS'),
267 | ('VU', 'Vanuatu', 'OC'),
268 | ('VA', 'Vatican', 'EU'),
269 | ('VE', 'Venezuela', 'SA'),
270 | ('VN', 'Vietnam', 'AS'),
271 | ('WF', 'Wallis and Futuna', 'OC'),
272 | ('EH', 'Western Sahara', 'AF'),
273 | ('YE', 'Yemen', 'AS'),
274 | ('ZM', 'Zambia', 'AF'),
275 | ('ZW', 'Zimbabwe', 'AF');
276 | ");
277 | }
278 |
279 | /**
280 | * Reverse the migrations.
281 | *
282 | * @return void
283 | */
284 | public function down()
285 | {
286 | Schema::dropIfExists('countries');
287 | }
288 | }
289 |
--------------------------------------------------------------------------------
/app/Services/Guzzler.php:
--------------------------------------------------------------------------------
1 | client = new GuzzleClient($config);
63 | }
64 |
65 | /**
66 | * Set URL for HTTP requests.
67 | *
68 | * @param string $url
69 | *
70 | * @return self
71 | */
72 | public function setUrl($url)
73 | {
74 | $this->url = $url;
75 |
76 | return $this;
77 | }
78 |
79 | /**
80 | * Set basic HTTP authentication.
81 | *
82 | * @param $username string
83 | * @param $password string
84 | *
85 | * @return self
86 | */
87 | public function setAuth($username, $password)
88 | {
89 | $this->query['auth'] = [$username, $password];
90 |
91 | return $this;
92 | }
93 |
94 | /**
95 | * Return response headers.
96 | *
97 | * @return array
98 | */
99 | public function getHeader()
100 | {
101 | return $this->header;
102 | }
103 |
104 | /**
105 | * Return response body.
106 | *
107 | * @return string
108 | */
109 | public function getBody()
110 | {
111 | return $this->body;
112 | }
113 |
114 | /**
115 | * Cache response keyed by url.
116 | *
117 | * @param $duration
118 | * @param $cache_id
119 | *
120 | * @return self
121 | */
122 | public function cache($duration, $cache_id = null)
123 | {
124 | $this->cached = $duration;
125 | if ($cache_id) {
126 | $this->cache_id = $this->cache_prefix . $cache_id;
127 | }
128 |
129 | return $this;
130 | }
131 |
132 | /**
133 | * Perform a request.
134 | *
135 | * @param string $method
136 | * @param array $options
137 | *
138 | * @return self
139 | */
140 | public function request($method, array $options = [])
141 | {
142 | if ($method == 'GET' && $this->getCache()) {
143 | return $this;
144 | }
145 |
146 | $this->response = $this->client->request($method, $this->url, $this->mergeOptions($options));
147 | $this->status_code = $this->response->getStatusCode();
148 | $this->header = $this->response->getHeaders();
149 | $this->body = (string)$this->response->getBody();
150 |
151 | if ($method == 'GET' && $this->cached) {
152 | $this->putCache();
153 | }
154 |
155 | return $this;
156 | }
157 |
158 | /**
159 | * Perform get request.
160 | *
161 | * @param array $options
162 | *
163 | * @return self
164 | */
165 | public function get(array $options = [])
166 | {
167 | return $this->request('GET', $options);
168 | }
169 |
170 | /**
171 | * Perform post request.
172 | *
173 | * @param array $options
174 | *
175 | * @return self
176 | */
177 | public function post(array $options = [])
178 | {
179 | return $this->request('POST', $options);
180 | }
181 |
182 | /**
183 | * Get the instance as an array.
184 | *
185 | * @return array
186 | */
187 | public function toArray()
188 | {
189 | if ($this->body && $this->isJson($this->body)) {
190 | return json_decode($this->body, true);
191 | }
192 |
193 | return;
194 | }
195 |
196 | /**
197 | * Convert the object to its JSON representation.
198 | *
199 | * @param int $options
200 | *
201 | * @return string
202 | */
203 | public function toJson($options = 0)
204 | {
205 | if ($this->body && $this->isJson($this->body)) {
206 | return json_encode(json_decode($this->body));
207 | }
208 |
209 | return;
210 | }
211 |
212 | /**
213 | * Attach query to the request.
214 | *
215 | * @param array $query
216 | *
217 | * @return self
218 | */
219 | public function withQuery(array $query)
220 | {
221 | if (!empty($this->query['query'])) {
222 | $this->query['query'] = array_merge($this->query['query'], $query);
223 |
224 | return $this;
225 | }
226 |
227 | $this->query = array_merge($this->query, ['query' => $query]);
228 |
229 | return $this;
230 | }
231 |
232 | /**
233 | * Attach data stream to the request.
234 | *
235 | * @param $body
236 | *
237 | * @return self
238 | */
239 | public function withBody($body)
240 | {
241 | $this->query = array_merge($this->query, ['body' => $body]);
242 |
243 | return $this;
244 | }
245 |
246 | /**
247 | * Attach form data to the request.
248 | *
249 | * @param array $form ['field_name'=>'value', ...]
250 | *
251 | * @return self
252 | */
253 | public function withForm(array $form)
254 | {
255 | if (!empty($this->query['form_params'])) {
256 | $this->query['form_params'] = array_merge($this->query['form_params'], $form);
257 |
258 | return $this;
259 | }
260 |
261 | $this->query = array_merge($this->query, ['form_params' => $form]);
262 |
263 | return $this;
264 | }
265 |
266 | /**
267 | * Attach multipart form data to the request.
268 | *
269 | * @param array $form [[name, contents, filename], ...]
270 | *
271 | * @return self
272 | */
273 | public function withMultiForm(array $form)
274 | {
275 | if (!empty($this->query['multipart'])) {
276 | $this->query['multipart'] = array_merge($this->query['multipart'], $form);
277 |
278 | return $this;
279 | }
280 |
281 | $this->query = array_merge($this->query, ['multipart' => $form]);
282 |
283 | return $this;
284 | }
285 |
286 | /**
287 | * Attach file as multipart form data to the request.
288 | *
289 | * @param array $file [name, contents, filename]
290 | *
291 | * @return self
292 | */
293 | public function withFile(array $file)
294 | {
295 | return $this->withMultiForm([$file]);
296 | }
297 |
298 | public function getStatusCode()
299 | {
300 | return $this->status_code;
301 | }
302 |
303 | public function unCache()
304 | {
305 | if ($this->cached) {
306 | $this->getCacheId();
307 | Cache::forget($this->cache_id);
308 | }
309 | }
310 |
311 | private function putCache()
312 | {
313 | if ($this->cached && $this->header && $this->body) {
314 | $this->getCacheId();
315 |
316 | $data = [
317 | 'url' => $this->url,
318 | 'query' => $this->query,
319 | 'status_code' => $this->status_code,
320 | 'header' => $this->header,
321 | 'body' => $this->body,
322 | ];
323 | Cache::put($this->cache_id, $data, $this->cached);
324 | }
325 | }
326 |
327 | private function getCache()
328 | {
329 | if ($this->cached) {
330 | $this->getCacheId();
331 |
332 | $data = Cache::get($this->cache_id);
333 | if ($data && is_array($data)) {
334 | $this->status_code = $data['status_code'];
335 | $this->query = $data['query'];
336 | $this->header = $data['header'];
337 | $this->body = $data['body'];
338 |
339 | return true;
340 | }
341 | }
342 |
343 | return false;
344 | }
345 |
346 | private function isJson($string)
347 | {
348 | json_decode($string);
349 |
350 | return json_last_error() === JSON_ERROR_NONE;
351 | }
352 |
353 | private function mergeOptions($options)
354 | {
355 | if (!empty($this->query)) {
356 | if (!empty($this->query['multipart']) && !empty($this->query['form_params'])) {
357 | $form_params = $this->query['form_params'];
358 | foreach ($form_params as $key => $value) {
359 | $form_param = [
360 | 'name' => $key,
361 | 'contents' => $value,
362 | ];
363 | array_push($this->query['multipart'], $form_param);
364 | }
365 | unset($this->query['form_params']);
366 | }
367 |
368 | return array_merge_recursive($options, $this->query);
369 | }
370 |
371 | return $options;
372 | }
373 |
374 | private function getCacheId()
375 | {
376 | if (empty($this->cache_id)) {
377 | $query_string = '';
378 | if (!empty($this->query['query'])) {
379 | $query_string = '?' . http_build_query($this->query['query']);
380 | }
381 | $this->cache_id = $this->cache_prefix . md5($this->url . $query_string);
382 | }
383 | }
384 | }
385 |
--------------------------------------------------------------------------------