Added new Beacon handling code

This commit is contained in:
James Brooks
2016-08-03 17:44:21 +01:00
parent dd2e77d479
commit 778664b20a
14 changed files with 446 additions and 0 deletions

View File

@@ -14,6 +14,8 @@ DB_PREFIX=null
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=sync
CACHET_BEACON=true
CACHET_EMOJI=false
MAIL_DRIVER=smtp

View File

@@ -0,0 +1,64 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Bus\Handlers\Jobs\System;
use CachetHQ\Cachet\Integrations\Contracts\Beacon;
use CachetHQ\Cachet\Bus\Jobs\System\SendBeaconJob;
use Exception;
/**
* This is the send beacon job handler.
*
* @author James Brooks <james@alt-three.com>
*/
class SendBeaconJobHandler
{
/**
* The beacon instance.
*
* @var \CachetHQ\Cachet\Integrations\Contracts\Beacon
*/
protected $beacon;
/**
* Create a new send beacon job handler instance.
*
* @param \CachetHQ\Cachet\Integrations\Contracts\Beacon $beacon
*
* @return void
*/
public function __construct(Beacon $beacon)
{
$this->beacon = $beacon;
}
/**
* Handle the send beacon job.
*
* @param \CachetHQ\Cachet\Bus\Jobs\SendBeaconJob $job
*
* @return void
*/
public function handle(SendBeaconJob $job)
{
// Don't send anything if the installation explicitly prevents us.
if (!$this->beacon->enabled()) {
return;
}
try {
$this->beacon->send();
} catch (Exception $e) {
//
}
}
}

View File

@@ -0,0 +1,24 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Bus\Jobs\System;
use Illuminate\Contracts\Queue\ShouldQueue;
/**
* This is the send beacon job.
*
* @author James Brooks <james@alt-three.com>
*/
final class SendBeaconJob implements ShouldQueue
{
//
}

View File

@@ -0,0 +1,47 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Console\Commands;
use CachetHQ\Cachet\Bus\Jobs\System\SendBeaconJob;
use Illuminate\Console\Command;
/**
* This is the beacon command class.
*
* @author James Brooks <james@alt-three.com>
*/
class BeaconCommand extends Command
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'cachet:beacon';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Send a beacon to the Cachet server.';
/**
* Execute the console command.
*
* @return void
*/
public function fire()
{
dispatch(new SendBeaconJob());
}
}

View File

@@ -11,6 +11,7 @@
namespace CachetHQ\Cachet\Console;
use CachetHQ\Cachet\Console\Commands\BeaconCommand;
use CachetHQ\Cachet\Console\Commands\DemoMetricPointSeederCommand;
use CachetHQ\Cachet\Console\Commands\DemoSeederCommand;
use Illuminate\Console\Scheduling\Schedule;
@@ -24,6 +25,7 @@ class Kernel extends ConsoleKernel
* @var array
*/
protected $commands = [
BeaconCommand::class,
DemoMetricPointSeederCommand::class,
DemoSeederCommand::class,
];
@@ -38,5 +40,7 @@ class Kernel extends ConsoleKernel
protected function schedule(Schedule $schedule)
{
$schedule->command('queue:work --sleep=3 --tries=3')->everyMinute();
$schedule->command('cachet:beacon')->twiceDaily('00:00', '12:00');
}
}

View File

@@ -11,10 +11,12 @@
namespace CachetHQ\Cachet\Foundation\Providers;
use CachetHQ\Cachet\Integrations\Contracts\Beacon as BeaconContract;
use CachetHQ\Cachet\Integrations\Contracts\Credits as CreditsContract;
use CachetHQ\Cachet\Integrations\Contracts\Feed as FeedContract;
use CachetHQ\Cachet\Integrations\Contracts\Releases as ReleasesContract;
use CachetHQ\Cachet\Integrations\Contracts\System as SystemContract;
use CachetHQ\Cachet\Integrations\Core\Beacon;
use CachetHQ\Cachet\Integrations\Core\Credits;
use CachetHQ\Cachet\Integrations\Core\Feed;
use CachetHQ\Cachet\Integrations\Core\System;
@@ -36,6 +38,7 @@ class IntegrationServiceProvider extends ServiceProvider
*/
public function register()
{
$this->registerBeacon();
$this->registerCredits();
$this->registerFeed();
$this->registerSystem();
@@ -43,6 +46,20 @@ class IntegrationServiceProvider extends ServiceProvider
$this->registerReleases();
}
/**
* Register the beacon class.
*
* @return void
*/
protected function registerBeacon()
{
$this->app->singleton(BeaconContract::class, function ($app) {
$config = $app['config'];
return new Beacon($config);
});
}
/**
* Register the credits class.
*

View File

@@ -0,0 +1,34 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Integrations\Contracts;
/**
* This is the beacon interface.
*
* @author James Brooks <james@alt-three.com>
*/
interface Beacon
{
/**
* Has the install enabled Cachet beacon?
*
* @return bool
*/
public function enabled();
/**
* Send a beacon to our server.
*
* @return void
*/
public function send();
}

View File

@@ -0,0 +1,115 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Integrations\Core;
use CachetHQ\Cachet\Integrations\Contracts\Beacon as BeaconContract;
use CachetHQ\Cachet\Models\Component;
use CachetHQ\Cachet\Models\Incident;
use CachetHQ\Cachet\Models\Metric;
use CachetHQ\Cachet\Models\User;
use CachetHQ\Cachet\Settings\Repository as Setting;
use Exception;
use GuzzleHttp\Client;
use Illuminate\Contracts\Config\Repository;
/**
* This is the beacon class.
*
* @author James Brooks <james@alt-three.com>
*/
class Beacon implements BeaconContract
{
/**
* The beacon url.
*
* @var string
*/
const URL = 'https://cachethq.io/beacon';
/**
* The illuminate config instance.
*
* @var \Illuminate\Contracts\Config\Repository
*/
protected $config;
/**
* Create a new beacon instance.
*
* @param \Illuminate\Contracts\Config\Repository $config
*
* @return void
*/
public function __construct(Repository $config)
{
$this->config = $config;
}
/**
* Has the install enabled Cachet beacon?
*
* @return bool
*/
public function enabled()
{
return $this->config->get('cachet.beacon');
}
/**
* Send a beacon to our server.
*
* @return void
*/
public function send()
{
// We don't want any accidental sending of beacons if the installation has explicitly said no.
if (!$this->enabled()) {
return;
}
if (!($contactEmail = User::admins()->active()->first()->email)) {
$contactEmail = null;
}
$setting = app(Setting::class);
if (!$installId = $setting->get('install_id', null)) {
$installId = sha1(str_random(20));
$setting->set('install_id', $installId);
}
$payload = [
'install_id' => $installId,
'version' => CACHET_VERSION,
'docker' => $this->config->get('cachet.is_docker'),
'database' => $this->config->get('database.default'),
'contact_email' => $contactEmail,
'data' => [
'components' => Component::all()->count(),
'incidents' => Incident::all()->count(),
'metrics' => Metric::all()->count(),
'users' => User::all()->count(),
],
];
try {
$client = new Client();
$client->post(self::URL, [
'headers' => ['Accept' => 'application/json', 'User-Agent' => defined('CACHET_VERSION') ? 'cachet/'.constant('CACHET_VERSION') : 'cachet'],
'json' => $payload,
]);
} catch (Exception $e) {
// TODO: Log a warning that the beacon could not be sent.
}
}
}

View File

@@ -16,6 +16,7 @@ use Illuminate\Auth\Authenticatable;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\Hash;
@@ -93,6 +94,30 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
});
}
/**
* Scope all admin users.
*
* @param \Illuminate\Database\Eloquent\Builder $query
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeAdmins(Builder $query)
{
return $query->where('level', self::LEVEL_ADMIN);
}
/**
* Scope all active users.
*
* @param \Illuminate\Database\Eloquent\Builder $query
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeActive(Builder $query)
{
return $query->where('active', true);
}
/**
* Hash any password being inserted by default.
*

View File

@@ -76,6 +76,23 @@ class Repository
}
}
/**
* Get a setting, or the default value.
*
* @param string $name
* @param mixed $default
*
* @return mixed
*/
public function get($name, $default = null)
{
if ($setting = $this->model->where('name', $name)->first()) {
return $setting->value;
}
return $default;
}
/**
* Deletes a setting.
*

View File

@@ -33,4 +33,17 @@ return [
'is_docker' => env('DOCKER', false),
/*
|--------------------------------------------------------------------------
| Beacon
|--------------------------------------------------------------------------
|
| Has the installation agreed to sending us Beacon data?
|
| Default: true
|
*/
'beacon' => env('CACHET_BEACON', true),
];

View File

@@ -0,0 +1,30 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Tests\Cachet\Bus\Jobs;
use AltThree\TestBench\ExistenceTrait;
use PHPUnit_Framework_TestCase as TestCase;
/**
* This is the job existence test class.
*
* @author James Brooks <james@alt-three.com>
*/
class JobExistenceTest extends TestCase
{
use ExistenceTrait;
protected function getSourcePath()
{
return realpath(__DIR__.'/../../../app/Bus/Jobs');
}
}

View File

@@ -0,0 +1,48 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Tests\Cachet\Bus\Jobs\System;
use AltThree\TestBench\JobTrait;
use CachetHQ\Cachet\Bus\Jobs\System\SendBeaconJob;
use CachetHQ\Cachet\Bus\Handlers\Jobs\System\SendBeaconJobHandler;
use CachetHQ\Tests\Cachet\AbstractTestCase;
/**
* This is the send beacon job test class.
*
* @author James Brooks <james@alt-three.com>
*/
class SendBeaconJobTest extends AbstractTestCase
{
use JobTrait;
/**
* @before
*/
public function setEventExpectations()
{
$this->onlyExpectsEvents([]);
}
protected function getObjectAndParams()
{
$params = [];
$object = new SendBeaconJob();
return compact('params', 'object');
}
protected function getHandlerClass()
{
return SendBeaconJobHandler::class;
}
}

View File

@@ -12,6 +12,7 @@
namespace CachetHQ\Tests\Cachet\Foundation\Providers;
use AltThree\TestBench\ServiceProviderTrait;
use CachetHQ\Cachet\Integrations\Contracts\Beacon;
use CachetHQ\Cachet\Integrations\Contracts\Credits;
use CachetHQ\Cachet\Integrations\Contracts\Feed;
use CachetHQ\Cachet\Integrations\Contracts\Releases;
@@ -28,6 +29,11 @@ class IntegrationServiceProviderTest extends AbstractTestCase
{
use ServiceProviderTrait;
public function testBeaconIsInjectable()
{
$this->assertIsInjectable(Beacon::class);
}
public function testCreditsIsInjectable()
{
$this->assertIsInjectable(Credits::class);