From 5c391cc88846b128dfeed62d648835a2885cf4cd Mon Sep 17 00:00:00 2001 From: James Brooks Date: Fri, 23 Jan 2015 17:24:34 +0000 Subject: [PATCH] Anonymous Segment.com tracking. Closes #91. --- app/config/app.php | 12 +- .../packages/cachethq/segment/config.php | 9 ++ app/lang/de/setup.php | 1 + app/lang/en/setup.php | 1 + app/lang/fr/setup.php | 1 + app/start/global.php | 11 ++ .../dashboard/settings/app-setup.blade.php | 9 ++ app/views/setup.blade.php | 6 + composer.json | 1 + composer.lock | 106 +++++++++++++++++- .../Commands/OneClickDeployCommand.php | 8 +- .../Controllers/DashComponentController.php | 38 +++++++ .../Controllers/DashIncidentController.php | 42 +++++++ src/Http/Controllers/DashTeamController.php | 20 ++++ src/Http/Controllers/DashUserController.php | 14 +++ src/Http/Controllers/HomeController.php | 19 ++++ src/Http/Controllers/SetupController.php | 8 ++ src/Providers/LoadConfigServiceProvider.php | 4 + src/Providers/SegmentApiServiceProvider.php | 37 ++++++ src/Segment/CacheRepository.php | 55 +++++++++ src/Segment/HttpRepository.php | 40 +++++++ src/Segment/RepositoryInterface.php | 13 +++ src/helpers.php | 76 +++++++++++++ 23 files changed, 523 insertions(+), 8 deletions(-) create mode 100644 app/config/packages/cachethq/segment/config.php create mode 100644 src/Providers/SegmentApiServiceProvider.php create mode 100644 src/Segment/CacheRepository.php create mode 100644 src/Segment/HttpRepository.php create mode 100644 src/Segment/RepositoryInterface.php diff --git a/app/config/app.php b/app/config/app.php index 671dc42e..3ad3649c 100644 --- a/app/config/app.php +++ b/app/config/app.php @@ -127,16 +127,16 @@ return [ * Packages Service Providers... */ 'Dingo\Api\Provider\ApiServiceProvider', - 'GrahamCampbell\Security\SecurityServiceProvider', + 'Fideloper\Proxy\ProxyServiceProvider', 'GrahamCampbell\Binput\BinputServiceProvider', - 'GrahamCampbell\Throttle\ThrottleServiceProvider', 'GrahamCampbell\Markdown\MarkdownServiceProvider', - 'Roumen\Feed\FeedServiceProvider', - 'Thujohn\Rss\RssServiceProvider', + 'GrahamCampbell\Security\SecurityServiceProvider', + 'GrahamCampbell\Throttle\ThrottleServiceProvider', 'Jenssegers\Date\DateServiceProvider', 'McCool\LaravelAutoPresenter\LaravelAutoPresenterServiceProvider', 'PragmaRX\Google2FA\Vendor\Laravel\ServiceProvider', - 'Fideloper\Proxy\ProxyServiceProvider', + 'Roumen\Feed\FeedServiceProvider', + 'Thujohn\Rss\RssServiceProvider', /* * Application Service Providers... @@ -148,6 +148,8 @@ return [ 'CachetHQ\Cachet\Providers\ViewComposerServiceProvider', 'CachetHQ\Cachet\Providers\LoadConfigServiceProvider', 'CachetHQ\Cachet\Providers\SettingsServiceProvider', + 'CachetHQ\Cachet\Providers\SegmentApiServiceProvider', + 'CachetHQ\Segment\SegmentServiceProvider', ], diff --git a/app/config/packages/cachethq/segment/config.php b/app/config/packages/cachethq/segment/config.php new file mode 100644 index 00000000..cf789553 --- /dev/null +++ b/app/config/packages/cachethq/segment/config.php @@ -0,0 +1,9 @@ + '', + 'consumer' => 'socket', + 'debug' => false, + 'ssl' => true, + 'error_handler' => null, +]; diff --git a/app/lang/de/setup.php b/app/lang/de/setup.php index 9b60680e..88301da6 100644 --- a/app/lang/de/setup.php +++ b/app/lang/de/setup.php @@ -10,4 +10,5 @@ return [ 'complete_setup' => 'Setup abschließen', 'completed' => 'Cachet wurde erfolgreich eingerichtet!', 'finish_setup' => 'Zum Dashboard', + 'allow_tracking' => 'Allow anonymous usage tracking?', ]; diff --git a/app/lang/en/setup.php b/app/lang/en/setup.php index af0d654b..6a317615 100644 --- a/app/lang/en/setup.php +++ b/app/lang/en/setup.php @@ -10,4 +10,5 @@ return [ 'complete_setup' => 'Complete Setup', 'completed' => 'Cachet has been configured successfully!', 'finish_setup' => 'Go to dashboard', + 'allow_tracking' => 'Allow anonymous usage tracking?', ]; diff --git a/app/lang/fr/setup.php b/app/lang/fr/setup.php index ae8e0d68..3fb5cbbf 100644 --- a/app/lang/fr/setup.php +++ b/app/lang/fr/setup.php @@ -10,4 +10,5 @@ return [ 'complete_setup' => 'Terminer l\'installation', 'completed' => 'Cachet a été configuré avec succès !', 'finish_setup' => 'Aller au tableau de bord', + 'allow_tracking' => 'Allow anonymous usage tracking?', ]; diff --git a/app/start/global.php b/app/start/global.php index 4853e52d..29a16879 100644 --- a/app/start/global.php +++ b/app/start/global.php @@ -61,3 +61,14 @@ App::missing(function ($exception) { App::down(function () { return Response::make("Be right back!", 503); }); + +/* +|-------------------------------------------------------------------------- +| Analytics +|-------------------------------------------------------------------------- +| +| We handle all Segment.com tracking here. The function call will only do +| something if tracking is enabled. +| +*/ +segment_identify(); diff --git a/app/views/dashboard/settings/app-setup.blade.php b/app/views/dashboard/settings/app-setup.blade.php index b99bbc93..11d4440b 100644 --- a/app/views/dashboard/settings/app-setup.blade.php +++ b/app/views/dashboard/settings/app-setup.blade.php @@ -108,6 +108,15 @@ +
+
+
+ + + +
+
+
diff --git a/app/views/setup.blade.php b/app/views/setup.blade.php index 4b1c81b8..111fbcce 100644 --- a/app/views/setup.blade.php +++ b/app/views/setup.blade.php @@ -78,6 +78,12 @@ {{ trans("setup.show_support") }}
+
+ +

diff --git a/composer.json b/composer.json index 3d888eb1..e56e9bbb 100644 --- a/composer.json +++ b/composer.json @@ -14,6 +14,7 @@ "ext-mcrypt": "*", "ext-openssl": "*", "laravel/framework": "4.2.*", + "cachethq/segment": "1.0.*@dev", "dingo/api": "0.8.*", "doctrine/dbal": "2.5.*", "graham-campbell/binput": "2.1.*", diff --git a/composer.lock b/composer.lock index 9ec0536d..69b65cab 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,63 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "3752fec41d40201f38e46974caa27d62", + "hash": "b32031bb1053f393308be4f68d1d0c94", "packages": [ + { + "name": "cachethq/segment", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/cachethq/Laravel-Segment.git", + "reference": "39121d7953cb91197f0474b9cf43ae198fca1e26" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cachethq/Laravel-Segment/zipball/39121d7953cb91197f0474b9cf43ae198fca1e26", + "reference": "39121d7953cb91197f0474b9cf43ae198fca1e26", + "shasum": "" + }, + "require": { + "illuminate/config": "~4.1", + "illuminate/support": "~4.1", + "php": ">=5.4.7", + "segmentio/analytics-php": "~1.1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "CachetHQ\\Segment\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "James Brooks", + "email": "james@cachethq.io" + } + ], + "description": "Segment.com wrapper written for Laravel 4", + "keywords": [ + "CachetHQ", + "Laravel Segment", + "api", + "cachet", + "framework", + "laravel", + "segment", + "segment.com", + "segment.io" + ], + "time": "2015-01-23 22:49:00" + }, { "name": "classpreloader/classpreloader", "version": "1.0.2", @@ -2108,6 +2163,51 @@ ], "time": "2014-12-09 14:53:34" }, + { + "name": "segmentio/analytics-php", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/segmentio/analytics-php.git", + "reference": "db24fa9a2e1110570c338fea7a6f46bbb7ef105c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/segmentio/analytics-php/zipball/db24fa9a2e1110570c338fea7a6f46bbb7ef105c", + "reference": "db24fa9a2e1110570c338fea7a6f46bbb7ef105c", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*" + }, + "type": "library", + "autoload": { + "files": [ + "lib/Segment.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Segment.io ", + "homepage": "https://segment.io/" + } + ], + "description": "Segmentio Analytics PHP Library", + "homepage": "https://segment.io/libraries/php", + "keywords": [ + "analytics", + "analytics.js", + "segmentio" + ], + "time": "2015-01-07 07:11:38" + }, { "name": "stack/builder", "version": "v1.0.3", @@ -3997,7 +4097,9 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "cachethq/segment": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { diff --git a/src/Console/Commands/OneClickDeployCommand.php b/src/Console/Commands/OneClickDeployCommand.php index fbd0d7ca..9ec52b93 100644 --- a/src/Console/Commands/OneClickDeployCommand.php +++ b/src/Console/Commands/OneClickDeployCommand.php @@ -50,7 +50,13 @@ class OneClickDeployCommand extends Command public function fire() { if ($this->migrate) { - return $this->runMigrations(); + $migrations = $this->runMigrations(); + + segment_track('Installation', [ + 'event' => 'Heroku Deployment', + ]); + + return $migrations; } $this->info('Please run "php artisan migrate" to finish the installation.'); diff --git a/src/Http/Controllers/DashComponentController.php b/src/Http/Controllers/DashComponentController.php index e73998c5..33f6a866 100644 --- a/src/Http/Controllers/DashComponentController.php +++ b/src/Http/Controllers/DashComponentController.php @@ -109,6 +109,11 @@ class DashComponentController extends Controller $component->update($_component); if (! $component->isValid()) { + segment_track('Dashboard', [ + 'event' => 'Edit Component', + 'success' => false, + ]); + return Redirect::back()->withInput(Binput::all()) ->with('title', sprintf( '%s %s', @@ -118,6 +123,11 @@ class DashComponentController extends Controller ->with('errors', $component->getErrors()); } + segment_track('Dashboard', [ + 'event' => 'Edit Component', + 'success' => true, + ]); + // The component was added successfully, so now let's deal with the tags. $tags = preg_split('/ ?, ?/', $tags); @@ -168,6 +178,11 @@ class DashComponentController extends Controller $component = Component::create($_component); if (! $component->isValid()) { + segment_track('Dashboard', [ + 'event' => 'Created Component', + 'success' => false, + ]); + return Redirect::back()->withInput(Binput::all()) ->with('title', sprintf( '%s %s', @@ -177,6 +192,11 @@ class DashComponentController extends Controller ->with('errors', $component->getErrors()); } + segment_track('Dashboard', [ + 'event' => 'Created Component', + 'success' => true, + ]); + // The component was added successfully, so now let's deal with the tags. $tags = preg_split('/ ?, ?/', $tags); @@ -207,6 +227,10 @@ class DashComponentController extends Controller */ public function deleteComponentAction(Component $component) { + segment_track('Dashboard', [ + 'event' => 'Deleted Component', + ]); + $component->delete(); return Redirect::back(); @@ -221,6 +245,10 @@ class DashComponentController extends Controller */ public function deleteComponentGroupAction(ComponentGroup $group) { + segment_track('Dashboard', [ + 'event' => 'Deleted Component Group', + ]); + $group->delete(); return Redirect::back(); @@ -248,6 +276,11 @@ class DashComponentController extends Controller $group = ComponentGroup::create(Binput::get('group')); if (! $group->isValid()) { + segment_track('Dashboard', [ + 'event' => 'Created Component Group', + 'success' => false, + ]); + return Redirect::back()->withInput(Binput::all()) ->with('title', sprintf( '%s %s', @@ -257,6 +290,11 @@ class DashComponentController extends Controller ->with('errors', $group->getErrors()); } + segment_track('Dashboard', [ + 'event' => 'Created Component Group', + 'success' => true, + ]); + $successMsg = sprintf( '%s %s', trans('dashboard.notifications.awesome'), diff --git a/src/Http/Controllers/DashIncidentController.php b/src/Http/Controllers/DashIncidentController.php index ac16851d..77228ba6 100644 --- a/src/Http/Controllers/DashIncidentController.php +++ b/src/Http/Controllers/DashIncidentController.php @@ -66,6 +66,11 @@ class DashIncidentController extends Controller $incident = Incident::create($incidentData); if (! $incident->isValid()) { + segment_track('Dashboard', [ + 'event' => 'Created Incident', + 'success' => false, + ]); + return Redirect::back()->withInput(Binput::all()) ->with('title', sprintf( '%s %s', @@ -82,6 +87,11 @@ class DashIncidentController extends Controller ]); } + segment_track('Dashboard', [ + 'event' => 'Created Incident', + 'success' => true, + ]); + $successMsg = sprintf( '%s %s', trans('dashboard.notifications.awesome'), @@ -127,6 +137,10 @@ class DashIncidentController extends Controller */ public function deleteTemplateAction(IncidentTemplate $template) { + segment_track('Dashboard', [ + 'event' => 'Deleted Incident Template', + ]); + $template->delete(); return Redirect::back(); @@ -143,6 +157,11 @@ class DashIncidentController extends Controller $template = IncidentTemplate::create($_template); if (! $template->isValid()) { + segment_track('Dashboard', [ + 'event' => 'Created Incident Template', + 'success' => false, + ]); + return Redirect::back()->withInput(Binput::all()) ->with('title', sprintf( '%s %s', @@ -152,6 +171,11 @@ class DashIncidentController extends Controller ->with('errors', $template->getErrors()); } + segment_track('Dashboard', [ + 'event' => 'Created Incident Template', + 'success' => true, + ]); + $successMsg = sprintf( '%s %s', trans('dashboard.notifications.awesome'), @@ -170,6 +194,10 @@ class DashIncidentController extends Controller */ public function deleteIncidentAction(Incident $incident) { + segment_track('Dashboard', [ + 'event' => 'Deleted Incident', + ]); + $incident->delete(); return Redirect::back(); @@ -204,6 +232,11 @@ class DashIncidentController extends Controller $incident->update($_incident); if (! $incident->isValid()) { + segment_track('Dashboard', [ + 'event' => 'Edited Incident', + 'success' => false, + ]); + return Redirect::back()->withInput(Binput::all()) ->with('title', sprintf( '%s %s', @@ -213,6 +246,11 @@ class DashIncidentController extends Controller ->with('errors', $incident->getErrors()); } + segment_track('Dashboard', [ + 'event' => 'Edited Incident', + 'success' => true, + ]); + $successMsg = sprintf( '%s %s', trans('dashboard.notifications.awesome'), @@ -231,6 +269,10 @@ class DashIncidentController extends Controller */ public function editTemplateAction(IncidentTemplate $template) { + segment_track('Dashboard', [ + 'event' => 'Edited Incident Template', + ]); + $template->update(Binput::get('template')); return Redirect::back()->with('updatedTemplate', $template); diff --git a/src/Http/Controllers/DashTeamController.php b/src/Http/Controllers/DashTeamController.php index b3533a4f..7f504113 100644 --- a/src/Http/Controllers/DashTeamController.php +++ b/src/Http/Controllers/DashTeamController.php @@ -60,6 +60,11 @@ class DashTeamController extends Controller $user = User::create(Binput::all()); if (! $user->isValid()) { + segment_track('Dashboard', [ + 'event' => 'Added User', + 'success' => false, + ]); + return Redirect::back()->withInput(Binput::except('password')) ->with('title', sprintf( '%s %s', @@ -69,6 +74,11 @@ class DashTeamController extends Controller ->with('errors', $user->getErrors()); } + segment_track('Dashboard', [ + 'event' => 'Added User', + 'success' => true, + ]); + $successMsg = sprintf( '%s %s', trans('dashboard.notifications.awesome'), @@ -98,6 +108,11 @@ class DashTeamController extends Controller $user->update($items); if (! $user->isValid()) { + segment_track('Dashboard', [ + 'event' => 'Updated User', + 'success' => false, + ]); + return Redirect::back()->withInput(Binput::except('password')) ->with('title', sprintf( '%s %s', @@ -107,6 +122,11 @@ class DashTeamController extends Controller ->with('errors', $user->getErrors()); } + segment_track('Dashboard', [ + 'event' => 'Updated User', + 'success' => true, + ]); + $successMsg = sprintf( '%s %s', trans('dashboard.notifications.awesome'), diff --git a/src/Http/Controllers/DashUserController.php b/src/Http/Controllers/DashUserController.php index bf95039b..a5a2c250 100644 --- a/src/Http/Controllers/DashUserController.php +++ b/src/Http/Controllers/DashUserController.php @@ -39,8 +39,18 @@ class DashUserController extends Controller // Let's enable/disable auth if ($enable2FA && ! Auth::user()->hasTwoFactor) { $items['google_2fa_secret'] = Google2FA::generateSecretKey(); + + segment_track('User Management', [ + 'event' => 'enabled_two_factor', + 'value' => true, + ]); } elseif (! $enable2FA) { $items['google_2fa_secret'] = ''; + + segment_track('User Management', [ + 'event' => 'enabled_two_factor', + 'value' => false, + ]); } if (trim($passwordChange) === '') { @@ -76,6 +86,10 @@ class DashUserController extends Controller */ public function regenerateApiKey(User $user) { + segment_track('User Management', [ + 'event' => 'regenrated_api_token' + ]); + $user->api_key = User::generateApiKey(); $user->save(); diff --git a/src/Http/Controllers/HomeController.php b/src/Http/Controllers/HomeController.php index 09e7cd25..f186d493 100644 --- a/src/Http/Controllers/HomeController.php +++ b/src/Http/Controllers/HomeController.php @@ -22,6 +22,10 @@ class HomeController extends Controller */ public function showIndex() { + segment_track('Status Page', [ + 'event' => 'Landed', + ]); + $components = Component::orderBy('order')->orderBy('created_at')->get(); $allIncidents = []; @@ -38,6 +42,21 @@ class HomeController extends Controller try { // If date provided is valid $oldDate = Date::createFromFormat('Y-m-d', Binput::get('start_date')); + + segment_track('Status Page', [ + 'start_date' => $oldDate->format('Y-m-d'), + ]); + + if (Setting::get('app_tracking')) { + Segment::track([ + 'userId' => Config::get('app.key'), + 'event' => 'Home Page', + 'properties' => [ + 'start_date' => $oldDate, + ], + ]); + } + // If trying to get a future date fallback to today if ($today->gt($oldDate)) { $startDate = $oldDate; diff --git a/src/Http/Controllers/SetupController.php b/src/Http/Controllers/SetupController.php index f2094375..b1aae56c 100644 --- a/src/Http/Controllers/SetupController.php +++ b/src/Http/Controllers/SetupController.php @@ -47,6 +47,10 @@ class SetupController extends Controller { $postData = Binput::all(); + segment_track('Setup', [ + 'step' => '1', + ]); + $v = Validator::make($postData, [ 'settings.app_name' => 'required', 'settings.app_domain' => 'required', @@ -72,6 +76,10 @@ class SetupController extends Controller { $postData = Binput::all(); + segment_track('Setup', [ + 'step' => '2', + ]); + $v = Validator::make($postData, [ 'settings.app_name' => 'required', 'settings.app_domain' => 'required', diff --git a/src/Providers/LoadConfigServiceProvider.php b/src/Providers/LoadConfigServiceProvider.php index 63b29887..0e0ac0ad 100644 --- a/src/Providers/LoadConfigServiceProvider.php +++ b/src/Providers/LoadConfigServiceProvider.php @@ -25,6 +25,10 @@ class LoadConfigServiceProvider extends ServiceProvider // Don't throw any errors, we may not be setup yet. } + // Set the Segment.com settings. + $segmentRepository = $this->app->make('CachetHQ\Cachet\Segment\RepositoryInterface'); + $this->app->config->set('cachethq/segment::write_key', $segmentRepository->fetch()); + // Override default app values. $this->app->config->set('app.url', $appDomain ?: $this->app->config->get('app.url')); $this->app->config->set('app.locale', $appLocale ?: $this->app->config->get('app.locale')); diff --git a/src/Providers/SegmentApiServiceProvider.php b/src/Providers/SegmentApiServiceProvider.php new file mode 100644 index 00000000..33c639b0 --- /dev/null +++ b/src/Providers/SegmentApiServiceProvider.php @@ -0,0 +1,37 @@ +app->singleton('CachetHQ\Cachet\Segment\RepositoryInterface', function () { + $url = 'https://gist.githubusercontent.com/jbrooksuk/5de24bc1cf90fb1a3d57/raw/cachet.json'; + $guzzleClient = new Client(); + $client = new HttpRepository($guzzleClient, $url); + + return new CacheRepository($client); + }); + } +} diff --git a/src/Segment/CacheRepository.php b/src/Segment/CacheRepository.php new file mode 100644 index 00000000..5908daef --- /dev/null +++ b/src/Segment/CacheRepository.php @@ -0,0 +1,55 @@ +repository = $repository; + } + + /** + * Determines whether to use the segment_write_key setting or to fetch a new. + * + * @return string + */ + public function fetch() + { + // Firstly, does the setting exist? + if (false === ($writeKey = Setting::get('segment_write_key'))) { + // No, let's go fetch it. + $writeKey = $this->repository->fetch(); + Setting::set('segment_write_key', $writeKey); + } else { + // It does, but how old is it? + $setting = SettingModel::where('name', 'segment_write_key')->first(); + + // It's older than an hour, let's refresh + if ($setting->updated_at->lt(Carbon::now()->subHour())) { + $writeKey = $this->repository->fetch(); + + // Update the setting. This is done manual to make sure updated_at is overwritten. + $setting->value = $writeKey; + $setting->updated_at = Carbon::now(); + $setting->save(); + } + } + + return $writeKey; + } +} diff --git a/src/Segment/HttpRepository.php b/src/Segment/HttpRepository.php new file mode 100644 index 00000000..85309505 --- /dev/null +++ b/src/Segment/HttpRepository.php @@ -0,0 +1,40 @@ +client = $client; + $this->url = $url; + } + + /** + * Fetches the segment_write_key from the given url. + * + * @return string + */ + public function fetch() + { + return $this->client->get($this->url)->json()['segment_write_key']; + } +} diff --git a/src/Segment/RepositoryInterface.php b/src/Segment/RepositoryInterface.php new file mode 100644 index 00000000..f02abc1e --- /dev/null +++ b/src/Segment/RepositoryInterface.php @@ -0,0 +1,13 @@ + Config::get('app.key'), + 'context' => [ + 'locale' => Config::get('app.locale'), + 'timezone' => Setting::get('app_timezone'), + ], + ]); + } else { + return false; + } + } +} + +if (!function_exists('segment_track')) { + /** + * Tracks events in Segment.com. + * + * @param string $event + * @param array $properties + * + * @return bool + */ + function segment_track($event, array $properties) + { + if (Setting::get('app_track')) { + return Segment::track([ + 'anonymousId' => Config::get('app.key'), + 'event' => $event, + 'properties' => $properties, + 'context' => [ + 'locale' => Config::get('app.locale'), + 'timezone' => Setting::get('app_timezone'), + ], + ]); + } else { + return false; + } + } +} + +if (!function_exists('segment_page')) { + /** + * Tracks pages in Segment.com. + * + * @param string $name + * + * @return bool + */ + function segment_page($page) + { + if (Setting::get('app_track')) { + return Segment::page([ + 'anonymousId' => Config::get('app.key'), + 'page' => $page, + 'context' => [ + 'locale' => Config::get('app.locale'), + 'timezone' => Setting::get('app_timezone'), + ], + ]); + } else { + return false; + } + } +}