#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:
parent
def4a28b10
commit
e93e4d2413
@ -92,6 +92,7 @@ class ConfigHelper
|
|||||||
'app_name' => trans('global.app_name'),
|
'app_name' => trans('global.app_name'),
|
||||||
'date_format' => $this->allowedDateFormats()[0],
|
'date_format' => $this->allowedDateFormats()[0],
|
||||||
'default_album_view' => $this->allowedAlbumViews()[0],
|
'default_album_view' => $this->allowedAlbumViews()[0],
|
||||||
|
'enable_visitor_hits' => false,
|
||||||
'hotlink_protection' => false,
|
'hotlink_protection' => false,
|
||||||
'items_per_page' => 12,
|
'items_per_page' => 12,
|
||||||
'items_per_page_admin' => 10,
|
'items_per_page_admin' => 10,
|
||||||
|
@ -62,6 +62,7 @@ class DefaultController extends Controller
|
|||||||
];
|
];
|
||||||
$checkboxKeys = [
|
$checkboxKeys = [
|
||||||
'allow_self_registration',
|
'allow_self_registration',
|
||||||
|
'enable_visitor_hits',
|
||||||
'hotlink_protection',
|
'hotlink_protection',
|
||||||
'recaptcha_enabled_registration',
|
'recaptcha_enabled_registration',
|
||||||
'remove_copyright',
|
'remove_copyright',
|
||||||
|
@ -9,6 +9,7 @@ use App\Helpers\ConfigHelper;
|
|||||||
use App\Helpers\DbHelper;
|
use App\Helpers\DbHelper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests;
|
use App\Http\Requests;
|
||||||
|
use App\VisitorHit;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\App;
|
use Illuminate\Support\Facades\App;
|
||||||
use Illuminate\Support\Facades\DB;
|
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)
|
if ($album->photos()->count() == 0)
|
||||||
{
|
{
|
||||||
$requestedView = 'empty';
|
$requestedView = 'empty';
|
||||||
@ -57,11 +70,6 @@ class AlbumController extends Controller
|
|||||||
->get();
|
->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
DB::transaction(function () use ($album) {
|
|
||||||
$album->hits++;
|
|
||||||
$album->save();
|
|
||||||
});
|
|
||||||
|
|
||||||
return Theme::render(sprintf('gallery.album_%s', $requestedView), [
|
return Theme::render(sprintf('gallery.album_%s', $requestedView), [
|
||||||
'album' => $album,
|
'album' => $album,
|
||||||
'allowed_views' => $validViews,
|
'allowed_views' => $validViews,
|
||||||
|
@ -7,8 +7,10 @@ use App\Facade\Theme;
|
|||||||
use App\Facade\UserConfig;
|
use App\Facade\UserConfig;
|
||||||
use App\Helpers\DbHelper;
|
use App\Helpers\DbHelper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\VisitorHit;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
class DefaultController extends Controller
|
class DefaultController extends Controller
|
||||||
{
|
{
|
||||||
@ -17,6 +19,15 @@ class DefaultController extends Controller
|
|||||||
$albums = DbHelper::getAlbumsForCurrentUser();
|
$albums = DbHelper::getAlbumsForCurrentUser();
|
||||||
$resetStatus = $request->session()->get('status');
|
$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', [
|
return Theme::render('gallery.index', [
|
||||||
'albums' => $albums,
|
'albums' => $albums,
|
||||||
'info' => $request->session()->get('info'),
|
'info' => $request->session()->get('info'),
|
||||||
|
@ -11,6 +11,7 @@ use app\Http\Controllers\Admin\AlbumController;
|
|||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Middleware\VerifyCsrfToken;
|
use App\Http\Middleware\VerifyCsrfToken;
|
||||||
use App\Photo;
|
use App\Photo;
|
||||||
|
use App\VisitorHit;
|
||||||
use Guzzle\Http\Mimetypes;
|
use Guzzle\Http\Mimetypes;
|
||||||
use Illuminate\Support\Facades\App;
|
use Illuminate\Support\Facades\App;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
@ -58,13 +59,20 @@ class PhotoController extends Controller
|
|||||||
$this->authorizeForUser($this->getUser(), 'photo.download_original', $photo);
|
$this->authorizeForUser($this->getUser(), 'photo.download_original', $photo);
|
||||||
}
|
}
|
||||||
|
|
||||||
$photoStream = $album->getAlbumSource()->fetchPhotoContent($photo, $thumbnail);
|
// Record the visit to the photo
|
||||||
$mimeType = Mimetypes::getInstance()->fromFilename($photo->storage_file_name);
|
if (UserConfig::get('enable_visitor_hits'))
|
||||||
|
{
|
||||||
DB::transaction(function () use ($photo) {
|
DB::transaction(function () use ($album, $photo, $request, $thumbnail)
|
||||||
|
{
|
||||||
$photo->hits_download++;
|
$photo->hits_download++;
|
||||||
$photo->save();
|
$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);
|
||||||
|
|
||||||
return response()->stream(
|
return response()->stream(
|
||||||
function() use ($photoStream)
|
function() use ($photoStream)
|
||||||
@ -101,10 +109,17 @@ class PhotoController extends Controller
|
|||||||
$returnAlbumUrl = $referer;
|
$returnAlbumUrl = $referer;
|
||||||
}
|
}
|
||||||
|
|
||||||
DB::transaction(function () use ($photo) {
|
// Record the visit to the photo
|
||||||
|
if (UserConfig::get('enable_visitor_hits'))
|
||||||
|
{
|
||||||
|
DB::transaction(function () use ($album, $photo, $request)
|
||||||
|
{
|
||||||
$photo->hits++;
|
$photo->hits++;
|
||||||
$photo->save();
|
$photo->save();
|
||||||
|
|
||||||
|
VisitorHit::fromRequest($request, $album->id, $photo->id);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return Theme::render('gallery.photo', [
|
return Theme::render('gallery.photo', [
|
||||||
'album' => $album,
|
'album' => $album,
|
||||||
|
@ -3,8 +3,38 @@
|
|||||||
namespace App;
|
namespace App;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
class VisitorHit extends Model
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,10 +18,12 @@ class CreateVisitorHitsTable extends Migration
|
|||||||
$table->unsignedInteger('album_id')->nullable();
|
$table->unsignedInteger('album_id')->nullable();
|
||||||
$table->unsignedBigInteger('photo_id')->nullable();
|
$table->unsignedBigInteger('photo_id')->nullable();
|
||||||
$table->unsignedInteger('user_id')->nullable();
|
$table->unsignedInteger('user_id')->nullable();
|
||||||
$table->string('album_view')->nullable();
|
$table->string('view_style')->nullable();
|
||||||
$table->timestamp('hit_at');
|
$table->timestamp('hit_at');
|
||||||
$table->string('ip_address');
|
$table->string('ip_address');
|
||||||
$table->string('user_agent');
|
$table->string('user_agent');
|
||||||
|
$table->string('session_identifier');
|
||||||
|
$table->string('uri', 500);
|
||||||
|
|
||||||
$table->foreign('album_id')
|
$table->foreign('album_id')
|
||||||
->references('id')->on('albums')
|
->references('id')->on('albums')
|
||||||
|
@ -31,7 +31,7 @@ class AttachHitColumns extends Migration
|
|||||||
public function down()
|
public function down()
|
||||||
{
|
{
|
||||||
Schema::table('photos', function (Blueprint $table) {
|
Schema::table('photos', function (Blueprint $table) {
|
||||||
$table->bigInteger('hits_download');
|
$table->dropColumn('hits_download');
|
||||||
$table->dropColumn('hits');
|
$table->dropColumn('hits');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -123,6 +123,13 @@ return [
|
|||||||
'security_text' => 'You can assign permissions on this album to either groups (recommended) or directly to users.',
|
'security_text' => 'You can assign permissions on this album to either groups (recommended) or directly to users.',
|
||||||
'security_users_heading' => 'User Permissions',
|
'security_users_heading' => 'User Permissions',
|
||||||
'settings' => [
|
'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' => '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.'
|
'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_groups_tab' => 'Groups',
|
||||||
'user_pending' => 'Pending activation',
|
'user_pending' => 'Pending activation',
|
||||||
'users_title' => 'User accounts',
|
'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_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.'
|
'visitor_analytics_p2' => 'This code will appear at the end of your site\'s body tag. Remember to include the "script" tags.'
|
||||||
];
|
];
|
@ -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' => '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' => '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' => '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>
|
</ul>
|
||||||
|
|
||||||
{{-- Tab panes --}}
|
{{-- Tab panes --}}
|
||||||
@ -90,15 +91,6 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</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>
|
</div>
|
||||||
|
|
||||||
{{-- E-mail --}}
|
{{-- E-mail --}}
|
||||||
@ -269,6 +261,33 @@
|
|||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</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>
|
||||||
|
|
||||||
<div class="pull-right" style="margin-top: 15px;">
|
<div class="pull-right" style="margin-top: 15px;">
|
||||||
|
Loading…
Reference in New Issue
Block a user