#15: Expanded the hit tracking to include basic information like IP address, user agent, album/photo/user and the album/photo view being accessed. Added a config option to disable the visitor tracking, and a new tab called Analytics in the settings album. Also added links to Cookie Consent.

This commit is contained in:
Andy Heathershaw 2017-04-17 15:45:25 +01:00
parent def4a28b10
commit e93e4d2413
10 changed files with 121 additions and 27 deletions

View File

@ -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,

View File

@ -62,6 +62,7 @@ class DefaultController extends Controller
];
$checkboxKeys = [
'allow_self_registration',
'enable_visitor_hits',
'hotlink_protection',
'recaptcha_enabled_registration',
'remove_copyright',

View File

@ -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,

View File

@ -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'),

View File

@ -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,

View File

@ -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;
}
}

View File

@ -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')

View File

@ -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');
});

View File

@ -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.'
];

View File

@ -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')])
</ul>
{{-- Tab panes --}}
@ -90,15 +91,6 @@
</label>
</div>
</fieldset>
<hr/>
<fieldset>
<legend>@lang('admin.visitor_analytics_heading')</legend>
<p>@lang('admin.visitor_analytics_p')</p>
<p>@lang('admin.visitor_analytics_p2')</p>
<textarea class="form-control" rows="10" name="analytics_code">{{ old('analytics_code', $config['analytics_code']) }}</textarea>
</fieldset>
</div>
{{-- E-mail --}}
@ -269,6 +261,33 @@
</div>
</fieldset>
</div>
{{-- Analytics --}}
<div role="tabpanel" class="tab-pane" id="analytics-tab">
<div class="alert alert-warning">
<p>@lang('admin.settings.analytics_cookie_warning_1')</p>
<p>@lang('admin.settings.analytics_cookie_warning_2')</p>
<p class="mb-0">
<a href="https://www.cookielaw.org/the-cookie-law/" target="_blank">@lang('admin.settings.analytics_cookie_link_1')</a><br/>
<a href="https://cookieconsent.insites.com/" target="_blank">@lang('admin.settings.analytics_cookie_link_2')</a>
</p>
</div>
<div class="checkbox mt-4">
<label>
<input type="checkbox" name="enable_visitor_hits" @if (old('enable_visitor_hits', UserConfig::get('enable_visitor_hits')))checked="checked"@endif>
<strong>@lang('admin.settings.analytics_enable_visitor_hits')</strong><br/>
@lang('admin.settings.analytics_enable_visitor_hits_description')
</label>
</div>
<hr/>
<fieldset>
<legend>@lang('admin.visitor_analytics_heading')</legend>
<p>@lang('admin.visitor_analytics_p')</p>
<p>@lang('admin.visitor_analytics_p2')</p>
<textarea class="form-control" rows="10" name="analytics_code">{{ old('analytics_code', $config['analytics_code']) }}</textarea>
</fieldset>
</div>
</div>
<div class="pull-right" style="margin-top: 15px;">