diff --git a/app/Helpers/ConfigHelper.php b/app/Helpers/ConfigHelper.php index 7e369dc..ef43239 100644 --- a/app/Helpers/ConfigHelper.php +++ b/app/Helpers/ConfigHelper.php @@ -92,6 +92,7 @@ class ConfigHelper 'app_name' => trans('global.app_name'), 'date_format' => $this->allowedDateFormats()[0], 'default_album_view' => $this->allowedAlbumViews()[0], + 'enable_visitor_hits' => false, 'hotlink_protection' => false, 'items_per_page' => 12, 'items_per_page_admin' => 10, diff --git a/app/Http/Controllers/Admin/DefaultController.php b/app/Http/Controllers/Admin/DefaultController.php index 89b44e0..49e39ed 100644 --- a/app/Http/Controllers/Admin/DefaultController.php +++ b/app/Http/Controllers/Admin/DefaultController.php @@ -62,6 +62,7 @@ class DefaultController extends Controller ]; $checkboxKeys = [ 'allow_self_registration', + 'enable_visitor_hits', 'hotlink_protection', 'recaptcha_enabled_registration', 'remove_copyright', diff --git a/app/Http/Controllers/Gallery/AlbumController.php b/app/Http/Controllers/Gallery/AlbumController.php index cbfdc9d..1d2ea51 100644 --- a/app/Http/Controllers/Gallery/AlbumController.php +++ b/app/Http/Controllers/Gallery/AlbumController.php @@ -9,6 +9,7 @@ use App\Helpers\ConfigHelper; use App\Helpers\DbHelper; use App\Http\Controllers\Controller; use App\Http\Requests; +use App\VisitorHit; use Illuminate\Http\Request; use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\DB; @@ -38,6 +39,18 @@ class AlbumController extends Controller } } + // Record the visit to the album + if (UserConfig::get('enable_visitor_hits')) + { + DB::transaction(function () use ($album, $request, $requestedView) + { + $album->hits++; + $album->save(); + + VisitorHit::fromRequest($request, $album->id, null, $requestedView); + }); + } + if ($album->photos()->count() == 0) { $requestedView = 'empty'; @@ -57,11 +70,6 @@ class AlbumController extends Controller ->get(); } - DB::transaction(function () use ($album) { - $album->hits++; - $album->save(); - }); - return Theme::render(sprintf('gallery.album_%s', $requestedView), [ 'album' => $album, 'allowed_views' => $validViews, diff --git a/app/Http/Controllers/Gallery/DefaultController.php b/app/Http/Controllers/Gallery/DefaultController.php index c2a0ca8..9ae139c 100644 --- a/app/Http/Controllers/Gallery/DefaultController.php +++ b/app/Http/Controllers/Gallery/DefaultController.php @@ -7,8 +7,10 @@ use App\Facade\Theme; use App\Facade\UserConfig; use App\Helpers\DbHelper; use App\Http\Controllers\Controller; +use App\VisitorHit; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\DB; class DefaultController extends Controller { @@ -17,6 +19,15 @@ class DefaultController extends Controller $albums = DbHelper::getAlbumsForCurrentUser(); $resetStatus = $request->session()->get('status'); + // Record the visit to the index (no album or photo to record a hit against though) + if (UserConfig::get('enable_visitor_hits')) + { + DB::transaction(function () use ($request) + { + VisitorHit::fromRequest($request); + }); + } + return Theme::render('gallery.index', [ 'albums' => $albums, 'info' => $request->session()->get('info'), diff --git a/app/Http/Controllers/Gallery/PhotoController.php b/app/Http/Controllers/Gallery/PhotoController.php index 7f7586f..d735bf4 100644 --- a/app/Http/Controllers/Gallery/PhotoController.php +++ b/app/Http/Controllers/Gallery/PhotoController.php @@ -11,6 +11,7 @@ use app\Http\Controllers\Admin\AlbumController; use App\Http\Controllers\Controller; use App\Http\Middleware\VerifyCsrfToken; use App\Photo; +use App\VisitorHit; use Guzzle\Http\Mimetypes; use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\DB; @@ -58,14 +59,21 @@ class PhotoController extends Controller $this->authorizeForUser($this->getUser(), 'photo.download_original', $photo); } + // Record the visit to the photo + if (UserConfig::get('enable_visitor_hits')) + { + DB::transaction(function () use ($album, $photo, $request, $thumbnail) + { + $photo->hits_download++; + $photo->save(); + + VisitorHit::fromRequest($request, $album->id, $photo->id, (is_null($thumbnail) ? 'original' : $thumbnail)); + }); + } + $photoStream = $album->getAlbumSource()->fetchPhotoContent($photo, $thumbnail); $mimeType = Mimetypes::getInstance()->fromFilename($photo->storage_file_name); - DB::transaction(function () use ($photo) { - $photo->hits_download++; - $photo->save(); - }); - return response()->stream( function() use ($photoStream) { @@ -101,10 +109,17 @@ class PhotoController extends Controller $returnAlbumUrl = $referer; } - DB::transaction(function () use ($photo) { - $photo->hits++; - $photo->save(); - }); + // Record the visit to the photo + if (UserConfig::get('enable_visitor_hits')) + { + DB::transaction(function () use ($album, $photo, $request) + { + $photo->hits++; + $photo->save(); + + VisitorHit::fromRequest($request, $album->id, $photo->id); + }); + } return Theme::render('gallery.photo', [ 'album' => $album, diff --git a/app/VisitorHit.php b/app/VisitorHit.php index 5347fce..dd61b64 100644 --- a/app/VisitorHit.php +++ b/app/VisitorHit.php @@ -3,8 +3,38 @@ namespace App; use Illuminate\Database\Eloquent\Model; +use Illuminate\Http\Request; +use Illuminate\Support\Facades\Auth; class VisitorHit extends Model { - // + /** + * The attributes that are mass assignable. + * + * @var array + */ + protected $fillable = [ + 'album_id', 'photo_id', 'user_id', 'view_style', 'hit_at', 'ip_address', 'user_agent', 'session_identifier', 'uri' + ]; + + public static function fromRequest(Request $request, $albumID = null, $photoID = null, $viewStyle = null) + { + $hit = new VisitorHit(); + $hit->album_id = $albumID; + $hit->photo_id = $photoID; + $hit->view_style = $viewStyle; + $hit->hit_at = new \DateTime(); + $hit->uri = $request->getRequestUri(); + $hit->ip_address = substr($request->getClientIp(), 0, 255); + $hit->user_agent = substr($request->headers->get('User-Agent'), 0, 255); + $hit->session_identifier = $request->getSession()->getId(); + + if (!is_null(Auth::user())) + { + $hit->user_id = Auth::user()->id; + } + + $hit->save(); + return $hit; + } } diff --git a/database/migrations/2017_04_16_095641_create_visitor_hits_table.php b/database/migrations/2017_04_16_095641_create_visitor_hits_table.php index 1d983e9..41c87f9 100644 --- a/database/migrations/2017_04_16_095641_create_visitor_hits_table.php +++ b/database/migrations/2017_04_16_095641_create_visitor_hits_table.php @@ -18,10 +18,12 @@ class CreateVisitorHitsTable extends Migration $table->unsignedInteger('album_id')->nullable(); $table->unsignedBigInteger('photo_id')->nullable(); $table->unsignedInteger('user_id')->nullable(); - $table->string('album_view')->nullable(); + $table->string('view_style')->nullable(); $table->timestamp('hit_at'); $table->string('ip_address'); $table->string('user_agent'); + $table->string('session_identifier'); + $table->string('uri', 500); $table->foreign('album_id') ->references('id')->on('albums') diff --git a/database/migrations/2017_04_16_095657_attach_hit_columns.php b/database/migrations/2017_04_16_095657_attach_hit_columns.php index 3a1ca59..50e9c35 100644 --- a/database/migrations/2017_04_16_095657_attach_hit_columns.php +++ b/database/migrations/2017_04_16_095657_attach_hit_columns.php @@ -31,7 +31,7 @@ class AttachHitColumns extends Migration public function down() { Schema::table('photos', function (Blueprint $table) { - $table->bigInteger('hits_download'); + $table->dropColumn('hits_download'); $table->dropColumn('hits'); }); diff --git a/resources/lang/en/admin.php b/resources/lang/en/admin.php index 077eee1..da371d1 100644 --- a/resources/lang/en/admin.php +++ b/resources/lang/en/admin.php @@ -123,6 +123,13 @@ return [ 'security_text' => 'You can assign permissions on this album to either groups (recommended) or directly to users.', 'security_users_heading' => 'User Permissions', 'settings' => [ + 'analytics_cookie_link_1' => 'Information about the EU Cookie Law directive', + 'analytics_cookie_link_2' => 'Cookie Consent by Insites', + 'analytics_cookie_warning_1' => 'If you are based in Europe and you enable visitor tracking, you will need to comply with the EU Cookie Law. The easiest way to do so is using a script like Cookie Consent by Insites.', + 'analytics_cookie_warning_2' => 'You can add Javascript like that provided by Cookie Consent in the code box below.', + 'analytics_enable_visitor_hits' => 'Enable built-in visitor hit tracking', + 'analytics_enable_visitor_hits_description' => 'Visitor hits to the public gallery will be recorded in the Blue Twilight database, allowing for analysis such as the most popular album/photo.', + 'analytics_tab' => 'Analytics', 'security_allow_self_registration' => 'Allow self-registration', 'security_allow_self_registration_description' => 'With this option enabled, users can sign up for their own accounts. You can grant permissions to accounts to allow users to upload their own photos or manage yours.' ], @@ -189,7 +196,7 @@ return [ 'user_groups_tab' => 'Groups', 'user_pending' => 'Pending activation', 'users_title' => 'User accounts', - 'visitor_analytics_heading' => 'Visitor analytics', + 'visitor_analytics_heading' => 'External analytics', 'visitor_analytics_p' => 'If you would like to analyse your visitor\'s activity using Google Analytics, Piwik or other real-time user monitoring services, please copy and paste the tracking code in the box below.', 'visitor_analytics_p2' => 'This code will appear at the end of your site\'s body tag. Remember to include the "script" tags.' ]; \ No newline at end of file diff --git a/resources/views/themes/base/admin/settings.blade.php b/resources/views/themes/base/admin/settings.blade.php index c0da396..44d5915 100644 --- a/resources/views/themes/base/admin/settings.blade.php +++ b/resources/views/themes/base/admin/settings.blade.php @@ -22,6 +22,7 @@ @include(Theme::viewName('partials.tab'), ['active_tab' => 'general', 'tab_name' => 'general', 'tab_icon' => 'info-circle', 'tab_text' => trans('admin.settings_general_tab')]) @include(Theme::viewName('partials.tab'), ['active_tab' => 'general', 'tab_name' => 'email', 'tab_icon' => 'envelope', 'tab_text' => trans('admin.settings_email_tab')]) @include(Theme::viewName('partials.tab'), ['active_tab' => 'general', 'tab_name' => 'security', 'tab_icon' => 'lock', 'tab_text' => trans('admin.settings_security_tab')]) + @include(Theme::viewName('partials.tab'), ['active_tab' => 'general', 'tab_name' => 'analytics', 'tab_icon' => 'line-chart', 'tab_text' => trans('admin.settings.analytics_tab')]) {{-- Tab panes --}} @@ -90,15 +91,6 @@ - -
-
- @lang('admin.visitor_analytics_heading') -

@lang('admin.visitor_analytics_p')

-

@lang('admin.visitor_analytics_p2')

- - -
{{-- E-mail --}} @@ -269,6 +261,33 @@ + + {{-- Analytics --}} +
+
+

@lang('admin.settings.analytics_cookie_warning_1')

+

@lang('admin.settings.analytics_cookie_warning_2')

+

+ @lang('admin.settings.analytics_cookie_link_1')
+ @lang('admin.settings.analytics_cookie_link_2') +

+
+
+ +
+
+
+ @lang('admin.visitor_analytics_heading') +

@lang('admin.visitor_analytics_p')

+

@lang('admin.visitor_analytics_p2')

+ + +
+