Merge remote-tracking branch 'forked/2.4' into upgrade-google2fa

# Conflicts:
#	composer.lock
This commit is contained in:
Max Kovalenko
2019-07-13 10:39:25 +03:00
55 changed files with 788 additions and 991 deletions

View File

@@ -70,6 +70,4 @@ A professional **installation service** is offered by Alt Three Services Limited
## Sponsorship
Thank you to the following for [sponsoring](https://patreon.com/jbrooksuk) Cachet.
[![Exascale](/docs/images/sponsorships/exascale.jpg)](https://www.exascale.co.uk/)
You can sponsor Cachet at our [Patreon page](https://patreon.com/jbrooksuk).

View File

@@ -60,6 +60,13 @@ final class CreateScheduleCommand
*/
public $components;
/**
* Whether to notify that the incident was reported.
*
* @var bool
*/
public $notify;
/**
* The validation rules.
*
@@ -72,6 +79,7 @@ final class CreateScheduleCommand
'scheduled_at' => 'required|string',
'completed_at' => 'nullable|string',
'components' => 'nullable|array',
'notify' => 'nullable|bool',
];
/**
@@ -83,10 +91,11 @@ final class CreateScheduleCommand
* @param string $scheduled_at
* @param string $completed_at
* @param array $components
* @param bool $notify
*
* @return void
*/
public function __construct($name, $message, $status, $scheduled_at, $completed_at, array $components = [])
public function __construct($name, $message, $status, $scheduled_at, $completed_at, $components, $notify)
{
$this->name = $name;
$this->message = $message;
@@ -94,5 +103,6 @@ final class CreateScheduleCommand
$this->scheduled_at = $scheduled_at;
$this->completed_at = $completed_at;
$this->components = $components;
$this->notify = $notify;
}
}

View File

@@ -36,18 +36,27 @@ final class ScheduleWasCreatedEvent implements ActionInterface, ScheduleEventInt
*/
public $schedule;
/**
* Whether to notify that the incident was reported.
*
* @var bool
*/
public $notify;
/**
* Create a new schedule was created event instance.
*
* @param \CachetHQ\Cachet\Models\User $user
* @param \CachetHQ\Cachet\Models\Schedule $schedule
* @param bool notify
*
* @return void
*/
public function __construct(User $user, Schedule $schedule)
public function __construct(User $user, Schedule $schedule, $notify = false)
{
$this->user = $user;
$this->schedule = $schedule;
$this->notify = $notify;
}
/**

View File

@@ -66,8 +66,7 @@ class CreateScheduleCommandHandler
{
try {
$schedule = Schedule::create($this->filter($command));
event(new ScheduleWasCreatedEvent($this->auth->user(), $schedule));
event(new ScheduleWasCreatedEvent($this->auth->user(), $schedule, (bool) $command->notify));
} catch (InvalidArgumentException $e) {
throw new ValidationException(new MessageBag([$e->getMessage()]));
}
@@ -96,6 +95,7 @@ class CreateScheduleCommandHandler
'status' => $command->status,
'scheduled_at' => $scheduledAt,
'completed_at' => $completedAt,
'notify' => $command->notify,
];
$availableParams = array_filter($params, function ($val) {

View File

@@ -51,6 +51,9 @@ class SendScheduleEmailNotificationHandler
public function handle(ScheduleEventInterface $event)
{
$schedule = $event->schedule;
if (!$event->notify) {
return false;
}
// First notify all global subscribers.
$globalSubscribers = $this->subscriber->isVerified()->isGlobal()->get()->each(function ($subscriber) use ($schedule) {

View File

@@ -13,6 +13,7 @@ namespace CachetHQ\Cachet\Foundation\Providers;
use CachetHQ\Cachet\Http\Middleware\Acceptable;
use CachetHQ\Cachet\Http\Middleware\Authenticate;
use CachetHQ\Cachet\Http\Middleware\RemoteUserAuthenticate;
use CachetHQ\Cachet\Http\Middleware\Timezone;
use CachetHQ\Cachet\Http\Middleware\VerifyCsrfToken;
use CachetHQ\Cachet\Http\Routes\ApiSystemRoutes;
@@ -151,6 +152,7 @@ class RouteServiceProvider extends ServiceProvider
if ($applyAlwaysAuthenticate && !$this->isWhiteListedAuthRoute($routes)) {
$middleware[] = Authenticate::class;
$middleware[] = RemoteUserAuthenticate::class;
}
$router->group(['middleware' => $middleware], function (Router $router) use ($routes) {

View File

@@ -73,7 +73,8 @@ class ScheduleController extends AbstractApiController
Binput::get('status'),
Binput::get('scheduled_at'),
Binput::get('completed_at'),
Binput::get('components', [])
Binput::get('components', []),
Binput::get('notify', false)
));
} catch (QueryException $e) {
throw new BadRequestHttpException();

View File

@@ -45,8 +45,7 @@ class MetricController extends Controller
public function showAddMetric()
{
return View::make('dashboard.metrics.add')
->withPageTitle(trans('dashboard.metrics.add.title').' - '.trans('dashboard.dashboard'))
->withAcceptableThresholds(Metric::ACCEPTABLE_THRESHOLDS);
->withPageTitle(trans('dashboard.metrics.add.title').' - '.trans('dashboard.dashboard'));
}
/**
@@ -132,8 +131,7 @@ class MetricController extends Controller
{
return View::make('dashboard.metrics.edit')
->withPageTitle(trans('dashboard.metrics.edit.title').' - '.trans('dashboard.dashboard'))
->withMetric($metric)
->withAcceptableThresholds(Metric::ACCEPTABLE_THRESHOLDS);
->withMetric($metric);
}
/**

View File

@@ -15,6 +15,7 @@ use AltThree\Validator\ValidationException;
use CachetHQ\Cachet\Bus\Commands\Schedule\CreateScheduleCommand;
use CachetHQ\Cachet\Bus\Commands\Schedule\DeleteScheduleCommand;
use CachetHQ\Cachet\Bus\Commands\Schedule\UpdateScheduleCommand;
use CachetHQ\Cachet\Integrations\Contracts\System;
use CachetHQ\Cachet\Models\IncidentTemplate;
use CachetHQ\Cachet\Models\Schedule;
use GrahamCampbell\Binput\Facades\Binput;
@@ -35,13 +36,21 @@ class ScheduleController extends Controller
*/
protected $subMenu = [];
/**
* The system instance.
*
* @var \CachetHQ\Cachet\Integrations\Contracts\System
*/
protected $system;
/**
* Creates a new schedule controller instance.
*
* @return void
*/
public function __construct()
public function __construct(System $system)
{
$this->system = $system;
View::share('subTitle', trans('dashboard.schedule.title'));
}
@@ -70,7 +79,8 @@ class ScheduleController extends Controller
return View::make('dashboard.maintenance.add')
->withPageTitle(trans('dashboard.schedule.add.title').' - '.trans('dashboard.dashboard'))
->withIncidentTemplates($incidentTemplates);
->withIncidentTemplates($incidentTemplates)
->withNotificationsEnabled($this->system->canNotifySubscribers());
}
/**
@@ -87,7 +97,8 @@ class ScheduleController extends Controller
Binput::get('status', Schedule::UPCOMING),
Binput::get('scheduled_at'),
Binput::get('completed_at'),
Binput::get('components', [])
Binput::get('components', []),
Binput::get('notify', false)
));
} catch (ValidationException $e) {
return cachet_redirect('dashboard.schedule.create')

View File

@@ -31,7 +31,7 @@ class SubscriberController extends Controller
{
return View::make('dashboard.subscribers.index')
->withPageTitle(trans('dashboard.subscribers.subscribers').' - '.trans('dashboard.dashboard'))
->withSubscribers(Subscriber::all());
->withSubscribers(Subscriber::with('subscriptions.component')->get());
}
/**

View File

@@ -15,9 +15,11 @@ use Barryvdh\Cors\HandleCors;
use CachetHQ\Cachet\Http\Middleware\Admin;
use CachetHQ\Cachet\Http\Middleware\ApiAuthentication;
use CachetHQ\Cachet\Http\Middleware\Authenticate;
use CachetHQ\Cachet\Http\Middleware\CacheControl;
use CachetHQ\Cachet\Http\Middleware\Localize;
use CachetHQ\Cachet\Http\Middleware\ReadyForUse;
use CachetHQ\Cachet\Http\Middleware\RedirectIfAuthenticated;
use CachetHQ\Cachet\Http\Middleware\RemoteUserAuthenticate;
use CachetHQ\Cachet\Http\Middleware\SetupAlreadyCompleted;
use CachetHQ\Cachet\Http\Middleware\SubscribersConfigured;
use CachetHQ\Cachet\Http\Middleware\Throttler;
@@ -45,10 +47,12 @@ class Kernel extends HttpKernel
*/
protected $routeMiddleware = [
'admin' => Admin::class,
'auth.api' => ApiAuthentication::class,
'auth.remoteuser' => RemoteUserAuthenticate::class,
'auth' => Authenticate::class,
'cache' => CacheControl::class,
'can' => Authorize::class,
'cors' => HandleCors::class,
'auth' => Authenticate::class,
'auth.api' => ApiAuthentication::class,
'guest' => RedirectIfAuthenticated::class,
'localize' => Localize::class,
'ready' => ReadyForUse::class,

View File

@@ -0,0 +1,37 @@
<?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\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class CacheControl
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
$response = $next($request);
$maxAge = time() + 30;
$response->header('Cache-Control', 'public,max-age='.$maxAge);
return $response;
}
}

View File

@@ -0,0 +1,53 @@
<?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\Http\Middleware;
use CachetHQ\Cachet\Models\User;
use Closure;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\Request;
class RemoteUserAuthenticate
{
/**
* Create a new remote user authenticate instance.
*
* @param \Illuminate\Contracts\Auth\Guard $auth
*
* @return void
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
if ($remoteUser = $request->server('REMOTE_USER')) {
$user = User::where('email', '=', $remoteUser)->first();
if ($user instanceof User && $this->auth->guest()) {
$this->auth->login($user);
}
}
return $next($request);
}
}

View File

@@ -52,10 +52,6 @@ class SubscribersConfigured
*/
public function handle(Request $request, Closure $next)
{
if (!$this->config->get('setting.enable_subscribers')) {
return cachet_redirect('status-page');
}
return $next($request);
}
}

View File

@@ -13,6 +13,7 @@ namespace CachetHQ\Cachet\Http\Middleware;
use Fideloper\Proxy\TrustProxies as Middleware;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Config;
/**
* This is the trust proxies middleware class.
@@ -42,6 +43,8 @@ class TrustProxies extends Middleware
*/
public function __construct()
{
$this->proxies = empty(env('TRUSTED_PROXIES')) ? '*' : explode(',', trim(env('TRUSTED_PROXIES')));
$proxies = Config::get('trustedproxies.proxies');
$this->proxies = empty($proxies) ? '*' : explode(',', trim($proxies));
}
}

View File

@@ -43,7 +43,7 @@ class ApiSystemRoutes
$router->group(['middleware' => ['auth.api']], function (Registrar $router) {
$router->get('ping', 'GeneralController@ping');
$router->get('version', 'GeneralController@version');
$router->get('status', 'GeneralController@status');
$router->get('status', ['uses' => 'GeneralController@status', 'middleware' => ['cache']]);
});
});
}

View File

@@ -62,13 +62,6 @@ class Metric extends Model implements HasPresenter
*/
const VISIBLE_HIDDEN = 2;
/**
* Array of acceptable threshold minutes.
*
* @var int[]
*/
const ACCEPTABLE_THRESHOLDS = [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60];
/**
* The model's attributes.
*
@@ -134,7 +127,6 @@ class Metric extends Model implements HasPresenter
'default_value' => 'required|numeric',
'places' => 'required|numeric|between:0,4',
'default_view' => 'required|numeric|between:0,3',
'threshold' => 'required|numeric|between:0,10',
'visible' => 'required|numeric|between:0,2',
];

View File

@@ -12,21 +12,19 @@
namespace CachetHQ\Cachet\Models;
use AltThree\Validator\ValidatingTrait;
use CachetHQ\Cachet\Presenters\UserPresenter;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use McCool\LaravelAutoPresenter\HasPresenter;
/**
* This is the user model.
*
* @author James Brooks <james@alt-three.com>
*/
class User extends Authenticatable implements HasPresenter
class User extends Authenticatable
{
use Notifiable, ValidatingTrait;
@@ -211,14 +209,4 @@ class User extends Authenticatable implements HasPresenter
{
return trim($this->google_2fa_secret) !== '';
}
/**
* Get the presenter class.
*
* @return string
*/
public function getPresenterClass()
{
return UserPresenter::class;
}
}

View File

@@ -140,7 +140,7 @@ class ComponentStatusChangedNotification extends Notification
return (new SlackMessage())
->$status()
->content(trans('notifications.component.status_update.slack.subject'))
->content(trans('notifications.component.status_update.slack.title'))
->attachment(function ($attachment) use ($content, $notifiable) {
$attachment->title($content, cachet_route('status-page'))
->fields(array_filter([

View File

@@ -133,8 +133,7 @@ class NewIncidentNotification extends Notification
->fields(array_filter([
'ID' => "#{$this->incident->id}",
'Link' => $this->incident->permalink,
]))
->footer(trans('cachet.subscriber.unsubscribe', ['link' => cachet_route('subscribe.unsubscribe', $notifiable->verify_code)]));
]));
});
}
}

View File

@@ -124,8 +124,7 @@ class NewScheduleNotification extends Notification implements ShouldQueue
->fields(array_filter([
'ID' => "#{$this->schedule->id}",
'Status' => $this->schedule->human_status,
]))
->footer(trans('cachet.subscriber.unsubscribe', ['link' => cachet_route('subscribe.unsubscribe', $notifiable->verify_code)]));
]));
});
}
}

View File

@@ -1,51 +0,0 @@
<?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\Presenters;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Support\Facades\Config;
use Laravolt\Avatar\Facade as Avatar;
use McCool\LaravelAutoPresenter\BasePresenter;
/**
* This is the user presenter class.
*
* @author James Brooks <james@alt-three.com>
*/
class UserPresenter extends BasePresenter implements Arrayable
{
/**
* Returns the users avatar.
*
* @return string
*/
public function avatar()
{
if (Config::get('setting.enable_external_dependencies')) {
return sprintf('https://www.gravatar.com/avatar/%s?size=%d', md5(strtolower($this->email)), 200);
}
return Avatar::create($this->username)->toBase64();
}
/**
* Convert the presenter instance to an array.
*
* @return string[]
*/
public function toArray()
{
return array_merge($this->wrappedObject->toArray(), [
'avatar' => $this->avatar(),
]);
}
}

View File

@@ -50,7 +50,6 @@
"jenssegers/date": "^3.4",
"laravel/framework": "5.7.*",
"laravel/tinker": "^1.0",
"laravolt/avatar": "^2.1",
"mccool/laravel-auto-presenter": "^7.1",
"nexmo/client": "^1.5",
"pragmarx/google2fa": "^5.0",
@@ -65,7 +64,6 @@
"filp/whoops": "^2.3",
"fzaninotto/faker": "^1.8",
"graham-campbell/analyzer": "^2.1",
"graham-campbell/testbench-core": "^3.0",
"mockery/mockery": "^1.2",
"phpunit/phpunit": "^7.4",
"tightenco/mailthief": "^0.3.14"

883
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -185,7 +185,6 @@ return [
GrahamCampbell\Security\SecurityServiceProvider::class,
Jenssegers\Date\DateServiceProvider::class,
Laravel\Tinker\TinkerServiceProvider::class,
Laravolt\Avatar\ServiceProvider::class,
McCool\LaravelAutoPresenter\AutoPresenterServiceProvider::class,
/*

View File

@@ -24,7 +24,7 @@ return [
* of your proxy (e.g. if using ELB or similar).
*
*/
'proxies' => null, // [<ip addresses>,], '*'
'proxies' => env('TRUSTED_PROXIES'), // [<ip addresses>,], '*'
/*
* To trust one or more specific proxies that connect

View File

@@ -71,7 +71,7 @@ Cachet comes with an installation command that will:
- Run seeders (of which there are none)
```bash
php artisan app:install
php artisan cachet:install
```
> Never change the `APP_KEY` after installation on production environment.

View File

@@ -11,7 +11,7 @@
},
"devDependencies": {
"animate-sass": "^0.8.2",
"axios": "^0.18",
"axios": "^0.19",
"bootstrap-sass": "^3.4.1",
"chart.js": "^2.8.0",
"cross-env": "^5.1",
@@ -26,7 +26,7 @@
"laravel-mix": "^2.1",
"laravel-mix-purgecss": "^3.0.0",
"livestamp": "git+https://github.com/mattbradley/livestampjs.git#develop",
"lodash": "^4.17.11",
"lodash": "^4.17.13",
"messenger": "git+https://github.com/HubSpot/messenger.git",
"moment": "^2.24.0",
"promise": "^7.3.1",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,8 +1,8 @@
{
"/dist/js/vendor.js": "/dist/js/vendor.js?id=313e4cd2cf600307cb5c",
"/dist/js/app.js": "/dist/js/app.js?id=be35dd18d92eef9dee9f",
"/dist/css/dashboard/dashboard.css": "/dist/css/dashboard/dashboard.css?id=0d9dfb3411fe9391898f",
"/dist/css/dashboard/dashboard.css": "/dist/css/dashboard/dashboard.css?id=654823be1de9b1245f17",
"/dist/css/app.css": "/dist/css/app.css?id=1b9032e972af93e2c869",
"/dist/js/manifest.js": "/dist/js/manifest.js?id=40dcfff9d09d402daf38",
"/dist/js/all.js": "/dist/js/all.js?id=1350a1cbe301201dbf4b"
"/dist/js/all.js": "/dist/js/all.js?id=c77bbe3fb26a84b5347d"
}

View File

@@ -251,7 +251,8 @@ $(function () {
// Only validate going forward. If current group is invalid, do not go further
if (next > current) {
var url = '/setup/step' + current;
var currentUrl = window.location.href.replace(/step\d/, '');
var url = currentUrl + '/step' + current;
$.post(url, $form.serializeObject())
.done(function(response) {
goToStep(current, next);

View File

@@ -21,6 +21,7 @@ body.dashboard {
margin: 0;
padding: 0;
list-style: none;
padding-bottom: 64px; /* Ensure the sidebar isn't being covered by the bottom links */
.profile {
text-align: center;

View File

@@ -13,134 +13,134 @@ return [
// Setup form fields
'setup' => [
'email' => 'Email',
'username' => 'Username',
'password' => 'Password',
'site_name' => 'Site Name',
'site_domain' => 'Site Domain',
'site_timezone' => 'Select your timezone',
'site_locale' => 'Select your language',
'enable_google2fa' => 'Enable Google Two Factor Authentication',
'cache_driver' => 'Cache Driver',
'queue_driver' => 'Queue Driver',
'session_driver' => 'Session Driver',
'mail_driver' => 'Mail Driver',
'mail_host' => 'Mail Host',
'mail_address' => 'Mail From Address',
'mail_username' => 'Mail Username',
'mail_password' => 'Mail Password',
'email' => 'E-mail',
'username' => 'Uživatelské jméno',
'password' => 'Heslo',
'site_name' => 'Název webu',
'site_domain' => 'Doména webu',
'site_timezone' => 'Vyberte vaše časové pásmo',
'site_locale' => 'Vyberte svůj jazyk',
'enable_google2fa' => 'Povolit dvoufaktorové ověřování Google',
'cache_driver' => 'Ovladač cache',
'queue_driver' => 'Řadič fronty',
'session_driver' => 'Ovladač sezení',
'mail_driver' => 'Ovladač pro e-mail',
'mail_host' => 'Host pro Mail',
'mail_address' => 'Adresa Mailu',
'mail_username' => 'Uživatelské jméno pro Mail účet',
'mail_password' => 'Heslo pro Mail účet',
],
// Login form fields
'login' => [
'login' => 'Username or Email',
'email' => 'Email',
'password' => 'Password',
'2fauth' => 'Authentication Code',
'invalid' => 'Invalid username or password',
'invalid-token' => 'Invalid token',
'cookies' => 'You must enable cookies to login.',
'rate-limit' => 'Rate limit exceeded.',
'remember_me' => 'Remember me',
'login' => 'Uživatelské jméno nebo e-mail',
'email' => 'E-mail',
'password' => 'Heslo',
'2fauth' => 'Ověřovací kód',
'invalid' => 'Nesprávné uživatelské jméno nebo heslo',
'invalid-token' => 'Neplatný token',
'cookies' => 'Pro přihlášení je třeba povolit soubory cookie.',
'rate-limit' => 'Překročen limit.',
'remember_me' => 'Zůstat přihlášený',
],
// Incidents form fields
'incidents' => [
'name' => 'Name',
'status' => 'Status',
'component' => 'Component',
'component_status' => 'Component Status',
'message' => 'Message',
'message-help' => 'You may also use Markdown.',
'occurred_at' => 'When did this incident occur?',
'notify_subscribers' => 'Notify subscribers?',
'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.',
'visibility' => 'Incident Visibility',
'stick_status' => 'Stick Incident',
'stickied' => 'Stickied',
'not_stickied' => 'Not Stickied',
'public' => 'Viewable by public',
'logged_in_only' => 'Only visible to logged in users',
'name' => 'Jméno',
'status' => 'Stav',
'component' => 'Komponenta',
'component_status' => 'Stavy služeb',
'message' => 'Zpráva',
'message-help' => 'Můžete také použít Markdown.',
'occurred_at' => 'Kdy došlo k incidentu?',
'notify_subscribers' => 'Oznámit odběratelům?',
'notify_disabled' => 'Z důvodu plánované údržby budou oznámení o tomto incidentu nebo jeho součástech potlačena.',
'visibility' => 'Viditelnost incidentu',
'stick_status' => 'Připnout událost',
'stickied' => 'Připnuté',
'not_stickied' => 'Nepřipnuté',
'public' => 'Viditelné veřejnosti',
'logged_in_only' => 'Viditelné pouze pro přihlášené uživatele',
'templates' => [
'name' => 'Name',
'template' => 'Template',
'twig' => 'Incident Templates can make use of the <a href="http://twig.sensiolabs.org/" target="_blank">Twig</a> templating language.',
'name' => 'Jméno',
'template' => 'Šablona',
'twig' => 'Šablony pro incidenty mohou používat šablonovací jazyk <a href="http://twig.sensiolabs.org/" target="_blank">Twing</a>.',
],
],
'schedules' => [
'name' => 'Name',
'status' => 'Status',
'message' => 'Message',
'message-help' => 'You may also use Markdown.',
'scheduled_at' => 'When is this maintenance scheduled for?',
'completed_at' => 'When did this maintenance complete?',
'name' => 'Jméno',
'status' => 'Stav',
'message' => 'Zpráva',
'message-help' => 'Můžete také použít Markdown.',
'scheduled_at' => 'Na kdy je naplánovaná údržba?',
'completed_at' => 'Kdy bude údržba hotová?',
'templates' => [
'name' => 'Name',
'template' => 'Template',
'twig' => 'Incident Templates can make use of the <a href="http://twig.sensiolabs.org/" target="_blank">Twig</a> templating language.',
'name' => 'Jméno',
'template' => 'Šablona',
'twig' => 'Šablony pro incidenty mohou používat šablonovací jazyk <a href="http://twig.sensiolabs.org/" target="_blank">Twing</a>.',
],
],
// Components form fields
'components' => [
'name' => 'Name',
'status' => 'Status',
'group' => 'Group',
'description' => 'Description',
'link' => 'Link',
'tags' => 'Tags',
'tags-help' => 'Comma separated.',
'enabled' => 'Component enabled?',
'name' => 'Jméno',
'status' => 'Stav',
'group' => 'Skupina',
'description' => 'Popis',
'link' => 'Odkaz',
'tags' => 'Štítky',
'tags-help' => 'Oddělené čárkou.',
'enabled' => 'Je služba povolena?',
'groups' => [
'name' => 'Name',
'collapsing' => 'Expand/Collapse options',
'visible' => 'Always expanded',
'collapsed' => 'Collapse the group by default',
'collapsed_incident' => 'Collapse the group, but expand if there are issues',
'visibility' => 'Visibility',
'visibility_public' => 'Visible to public',
'visibility_authenticated' => 'Visible only to logged in users',
'name' => 'Jméno',
'collapsing' => 'Rozbalit nebo sbalit možnosti',
'visible' => 'Vždy rozbalené',
'collapsed' => 'Sbalit skupinu ve výchozím nastavení',
'collapsed_incident' => 'Sbalit skupinu, ale rozšířit, pokud existují problémy',
'visibility' => 'Viditelnost',
'visibility_public' => 'Viditelné pro veřejnost',
'visibility_authenticated' => 'Viditelné pouze pro přihlášené uživatele',
],
],
// Action form fields
'actions' => [
'name' => 'Name',
'description' => 'Description',
'start_at' => 'Schedule start time',
'timezone' => 'Timezone',
'schedule_frequency' => 'Schedule frequency (in seconds)',
'completion_latency' => 'Completion latency (in seconds)',
'group' => 'Group',
'active' => 'Active?',
'name' => 'Jméno',
'description' => 'Popis',
'start_at' => 'Naplánovat čas spuštění',
'timezone' => 'Časová zóna',
'schedule_frequency' => 'Naplánovat frekvenci (ve vteřinách)',
'completion_latency' => 'Prodleva dokončení (ve vteřinách)',
'group' => 'Skupina',
'active' => 'Aktiv?',
'groups' => [
'name' => 'Group Name',
'name' => 'Název skupiny',
],
],
// Metric form fields
'metrics' => [
'name' => 'Name',
'suffix' => 'Suffix',
'description' => 'Description',
'description-help' => 'You may also use Markdown.',
'display-chart' => 'Display chart on status page?',
'default-value' => 'Default value',
'calc_type' => 'Calculation of metrics',
'type_sum' => 'Sum',
'type_avg' => 'Average',
'places' => 'Decimal places',
'default_view' => 'Default view',
'threshold' => 'How many minutes of threshold between metric points?',
'visibility' => 'Visibility',
'visibility_authenticated' => 'Visible to authenticated users',
'visibility_public' => 'Visible to everybody',
'visibility_hidden' => 'Always hidden',
'name' => 'Jméno',
'suffix' => 'Přípona',
'description' => 'Popis',
'description-help' => 'Můžete také použít Markdown.',
'display-chart' => 'Zobrazovat graf na stavové stránce?',
'default-value' => 'Výchozí hodnota',
'calc_type' => 'Výpočet metrik',
'type_sum' => 'Celkem',
'type_avg' => 'Průměr',
'places' => 'Počet desetinných míst',
'default_view' => 'Výchozí zobrazení',
'threshold' => 'Jak často se mají snímat metrické body?',
'visibility' => 'Viditelnost',
'visibility_authenticated' => 'Viditelné přihlášeným uživatelům',
'visibility_public' => 'Viditelný všem',
'visibility_hidden' => 'Vždy skrýt',
'points' => [
'value' => 'Value',
'value' => 'Hodnota',
],
],
@@ -148,101 +148,101 @@ return [
'settings' => [
// Application setup
'app-setup' => [
'site-name' => 'Site Name',
'site-url' => 'Site URL',
'display-graphs' => 'Display graphs on status page?',
'about-this-page' => 'About this page',
'days-of-incidents' => 'How many days of incidents to show?',
'time_before_refresh' => 'Status page refresh rate (in seconds)',
'major_outage_rate' => 'Major outage threshold (in %)',
'banner' => 'Banner Image',
'banner-help' => "It's recommended that you upload files no bigger than 930px wide",
'subscribers' => 'Allow people to signup to email notifications?',
'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?',
'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)',
'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?',
'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)',
'show_timezone' => 'Show the timezone the status page is running in',
'only_disrupted_days' => 'Only show days containing incidents in the timeline?',
'site-name' => 'Název webu',
'site-url' => 'URL adresa webu',
'display-graphs' => 'Zobrazit grafy na stavové stránce?',
'about-this-page' => 'O této stránce',
'days-of-incidents' => 'Kolik dní incidentů zobrazovat?',
'time_before_refresh' => 'Obnovovací frekvence status stránky (v sekundách)',
'major_outage_rate' => 'Hlavní doba výpadků (v %)',
'banner' => 'Obrázek banneru',
'banner-help' => 'Doručuje se nenahrávat soubory větší než 930 pixelů na šířku',
'subscribers' => 'Umožnit lidem, aby se přihlašovali k odběru e-mailových upozornění?',
'suppress_notifications_in_maintenance' => 'Potlačit oznámení dojde-li k události během během času údržby?',
'skip_subscriber_verification' => 'Přestat ověřovat uživatele? (Pozor na spammery)',
'automatic_localization' => 'Automaticky lokalizovat stránku do jazyka návštěvníka?',
'enable_external_dependencies' => 'Povolit závislosti třetích stran (Google písma, Trackery, atd...)',
'show_timezone' => 'Zobrazit časové pásmo, ve které je zobrazena stavová stránka',
'only_disrupted_days' => 'Zobrazit na časové ose pouze dny, kdy došlo k incidentu?',
],
'analytics' => [
'analytics_google' => 'Google Analytics code',
'analytics_gosquared' => 'GoSquared Analytics code',
'analytics_piwik_url' => 'URL of your Piwik instance (without http(s)://)',
'analytics_piwik_siteid' => 'Piwik\'s site id',
'analytics_google' => 'Kód pro Google Analytics',
'analytics_gosquared' => 'Kód pro GoSquared Analytics',
'analytics_piwik_url' => 'URL tvojí instance Piwik (bez http(s)://)',
'analytics_piwik_siteid' => 'Id webu Piwik',
],
'localization' => [
'site-timezone' => 'Site timezone',
'site-locale' => 'Site language',
'date-format' => 'Date format',
'incident-date-format' => 'Incident timestamp format',
'site-timezone' => 'Časové pásmo webu',
'site-locale' => 'Jazyk webu',
'date-format' => 'Formát datumu',
'incident-date-format' => 'Formát času pro incident',
],
'security' => [
'allowed-domains' => 'Allowed domains',
'allowed-domains-help' => 'Comma separated. The domain set above is automatically allowed by default.',
'always-authenticate' => 'Always authenticate',
'always-authenticate-help' => 'Require login to view any Cachet page',
'allowed-domains' => 'Povolené domény',
'allowed-domains-help' => 'Oddělené čárkami. Výše uvedené domény jsou ve výchozím nastavení automaticky povoleny.',
'always-authenticate' => 'Vždy ověřovat',
'always-authenticate-help' => 'Požadovat přihlášení k zobrazení jakékoli Cachet stránky',
],
'stylesheet' => [
'custom-css' => 'Custom Stylesheet',
'custom-css' => 'Vlastní šablona stylů',
],
'theme' => [
'background-color' => 'Background color',
'background-fills' => 'Background fills (components, incidents, footer)',
'banner-background-color' => 'Banner background color',
'banner-padding' => 'Banner padding',
'fullwidth-banner' => 'Enable full width banner?',
'text-color' => 'Text color',
'dashboard-login' => 'Show dashboard button in the footer?',
'reds' => 'Red (used for errors)',
'blues' => 'Blue (used for information)',
'greens' => 'Green (used for success)',
'yellows' => 'Yellow (used for alerts)',
'oranges' => 'Orange (used for notices)',
'metrics' => 'Metrics fill',
'links' => 'Links',
'background-color' => 'Barva pozadí',
'background-fills' => 'Pozadí výplně (komponenty, incidenty, zápatí)',
'banner-background-color' => 'Barva pozadí banneru',
'banner-padding' => 'Odsazení banneru',
'fullwidth-banner' => 'Povolit banner přes celou obrazovku?',
'text-color' => 'Barva textu',
'dashboard-login' => 'Zobrazit tlačítko Řídící panel v zápatí?',
'reds' => 'Červená (používané pro chyby)',
'blues' => 'Modrá (používané pro informace)',
'greens' => 'Zelená (používá se pro vyřešení problémů)',
'yellows' => 'Žlutá (používá se pro upozornění)',
'oranges' => 'Oranžová (slouží k oznámení)',
'metrics' => 'Vyplnění metrik',
'links' => 'Odkazy',
],
],
'user' => [
'username' => 'Username',
'email' => 'Email',
'password' => 'Password',
'username' => 'Uživatelské jméno',
'email' => 'E-mail',
'password' => 'Heslo',
'api-token' => 'API Token',
'api-token-help' => 'Regenerating your API token will prevent existing applications from accessing Cachet.',
'gravatar' => 'Change your profile picture at Gravatar.',
'user_level' => 'User Level',
'api-token-help' => 'egenerování vašeho API tokenu zabrání současným aplikacím přistupovat ke Cachet.',
'gravatar' => 'Profilový obrázek si změn na Gravatar.',
'user_level' => 'Úroveň uživatele',
'levels' => [
'admin' => 'Admin',
'user' => 'User',
'admin' => 'Správce',
'user' => 'Uživatel',
],
'2fa' => [
'help' => 'Enabling two factor authentication increases security of your account. You will need to download <a href="https://support.google.com/accounts/answer/1066447?hl=en">Google Authenticator</a> or a similar app on to your mobile device. When you login you will be asked to provide a token generated by the app.',
'help' => 'Zapnutí dvoufaktorového ověřování zvýší zabezpečení vašeho účtu. Budete muset stáhnout <a href="https://support.google.com/accounts/answer/1066447?hl=en">Google Authenticator</a> nebo podobnou aplikaci pro mobilní zařízení. Po přihlášení budete vyzváni k zadání tokenu vygenerovaného aplikací.',
],
'team' => [
'description' => 'Invite your team members by entering their email addresses here.',
'email' => 'Your Team Members Email Address',
'description' => 'Pozvi uživatele do týmu zadáním emailové adresy.',
'email' => 'Email #:id',
],
],
'general' => [
'timezone' => 'Select Timezone',
'timezone' => 'Vybrat časové pásmo',
],
// Buttons
'add' => 'Add',
'save' => 'Save',
'update' => 'Update',
'create' => 'Create',
'edit' => 'Edit',
'delete' => 'Delete',
'submit' => 'Submit',
'cancel' => 'Cancel',
'remove' => 'Remove',
'invite' => 'Invite',
'signup' => 'Sign Up',
'manage_updates' => 'Manage Updates',
'add' => 'Přidat',
'save' => 'Uložit',
'update' => 'Aktualizovat',
'create' => 'Vytvořit',
'edit' => 'Upravit',
'delete' => 'Smazat',
'submit' => 'Potvrdit',
'cancel' => 'Zrušit',
'remove' => 'Smazat',
'invite' => 'Pozvat',
'signup' => 'Registrovat se',
'manage_updates' => 'Správa aktualizací',
// Other
'optional' => '* Optional',
'optional' => '* Volitelné',
];

View File

@@ -22,72 +22,72 @@ return [
|
*/
'accepted' => 'The :attribute must be accepted.',
'active_url' => 'The :attribute is not a valid URL.',
'after' => 'The :attribute must be a date after :date.',
'alpha' => 'The :attribute may only contain letters.',
'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.',
'alpha_num' => 'The :attribute may only contain letters and numbers.',
'array' => 'The :attribute must be an array.',
'before' => 'The :attribute must be a date before :date.',
'accepted' => 'Je potřeba potvrdit :attribute.',
'active_url' => ':attribute není platná adresa URL.',
'after' => ':attribute musí být datum po :date.',
'alpha' => ':attribute může obsahovat pouze písmena.',
'alpha_dash' => ':attribute může obsahovat pouze písmena, čísla a pomlčky.',
'alpha_num' => ':attribute může obsahovat pouze písmena a čísla.',
'array' => ':attribute musí být textové pole.',
'before' => ':attribute musí být datum před :date.',
'between' => [
'numeric' => 'The :attribute must be between :min and :max.',
'file' => 'The :attribute must be between :min and :max kilobytes.',
'numeric' => ':attribute musí mít hodnou mezi :min a :max.',
'file' => ':attribute musí mít velikost v rozmezí :min až :max kilobytů.',
'string' => 'The :attribute must be between :min and :max characters.',
'array' => 'The :attribute must have between :min and :max items.',
'array' => ':attribute musí mít mezi :min a :max položkami.',
],
'boolean' => 'The :attribute field must be true or false.',
'confirmed' => 'The :attribute confirmation does not match.',
'date' => 'The :attribute is not a valid date.',
'date_format' => 'The :attribute does not match the format :format.',
'boolean' => ':attribute musí mít hodnotu pravda nebo nepravda.',
'confirmed' => 'Potvrzení :attribute se neshoduje.',
'date' => ':attribute není platné datum.',
'date_format' => ':attribute se neshoduje se správným formátem :format.',
'different' => 'The :attribute and :other must be different.',
'digits' => 'The :attribute must be :digits digits.',
'digits_between' => 'The :attribute must be between :min and :max digits.',
'email' => 'The :attribute must be a valid email address.',
'exists' => 'The selected :attribute is invalid.',
'distinct' => 'The :attribute field has a duplicate value.',
'distinct' => ':attribute má duplicitní hodnotu.',
'filled' => 'The :attribute field is required.',
'image' => 'The :attribute must be an image.',
'image' => ':attribute musí být obrázek.',
'in' => 'The selected :attribute is invalid.',
'in_array' => 'The :attribute field does not exist in :other.',
'in_array' => ':attribute není v :other.',
'integer' => 'The :attribute must be an integer.',
'ip' => 'The :attribute must be a valid IP address.',
'json' => 'The :attribute must be a valid JSON string.',
'json' => ': attribute musí být ve formátu JSON.',
'max' => [
'numeric' => 'The :attribute may not be greater than :max.',
'file' => 'The :attribute may not be greater than :max kilobytes.',
'string' => 'The :attribute may not be greater than :max characters.',
'array' => 'The :attribute may not have more than :max items.',
'array' => 'Atribut nesmí mít více než :max položek.',
],
'mimes' => 'The :attribute must be a file of type: :values.',
'min' => [
'numeric' => 'The :attribute must be at least :min.',
'file' => 'The :attribute must be at least :min kilobytes.',
'file' => 'Atribut musí mít alespoň :min kB.',
'string' => 'The :attribute must be at least :min characters.',
'array' => 'The :attribute must have at least :min items.',
],
'not_in' => 'The selected :attribute is invalid.',
'numeric' => 'The :attribute must be a number.',
'present' => 'The :attribute field must be present.',
'regex' => 'The :attribute format is invalid.',
'present' => 'Pole :attribute je vyžadováno.',
'regex' => 'Formát :attribute je neplatný.',
'required' => 'The :attribute field is required.',
'required_if' => 'The :attribute field is required when :other is :value.',
'required_unless' => 'The :attribute field is required unless :other is in :values.',
'required_with' => 'The :attribute field is required when :values is present.',
'required_with_all' => 'The :attribute field is required when :values is present.',
'required_unless' => 'Pole :attribute je požadováno, pokud :other není v :value.',
'required_with' => 'Pole :attribute je požadováno, když je zadané :values.',
'required_with_all' => 'Pole :attribute je požadováno, když je zadané :values.',
'required_without' => 'The :attribute field is required when :values is not present.',
'required_without_all' => 'The :attribute field is required when none of :values are present.',
'same' => 'The :attribute and :other must match.',
'size' => [
'numeric' => 'The :attribute must be :size.',
'file' => 'The :attribute must be :size kilobytes.',
'string' => 'The :attribute must be :size characters.',
'file' => 'Atribut musí mít :size kB.',
'string' => 'Atribut musí mít :size znaků.',
'array' => 'The :attribute must contain :size items.',
],
'string' => 'The :attribute must be a string.',
'timezone' => 'The :attribute must be a valid zone.',
'unique' => 'The :attribute has already been taken.',
'url' => 'The :attribute format is invalid.',
'timezone' => ':attribute musí být platná zóna.',
'unique' => ':attribute byl už použit.',
'url' => 'Formát :attribute je neplatný.',
/*
|--------------------------------------------------------------------------
@@ -102,7 +102,7 @@ return [
'custom' => [
'attribute-name' => [
'rule-name' => 'custom-message',
'rule-name' => 'vlastní zpráva',
],
],

View File

@@ -26,16 +26,16 @@ return [
'count' => '{0}Nenhuma atualização|[1]Uma atualização|[2]Duas atualizações|[3,*]Várias atualizações',
'add' => [
'title' => 'Crie uma nova atualização de incidente',
'success' => 'Your new incident update has been created.',
'success' => 'Sua atualização de incidente foi criada.',
'failure' => 'Algo deu errado com a atualização do incidente.',
],
'edit' => [
'title' => 'Edit incident update',
'success' => 'The incident update has been updated.',
'failure' => 'Something went wrong updating the incident update',
'title' => 'Editar atualização do incidente',
'success' => 'Sua atualização de incidente foi atualizada.',
'failure' => 'Algo deu errado ao atualizar as informações do incidente',
],
],
'reported_by' => 'Reported by :user',
'reported_by' => 'Reportado por :user',
'add' => [
'title' => 'Relatar um incidente',
'success' => 'Incidente adicionado.',
@@ -56,7 +56,7 @@ return [
'title' => 'Template de incidentes',
'add' => [
'title' => 'Criar um modelo de incidente',
'message' => 'Create your first incident template.',
'message' => 'Crie seu primeiro template de incidente.',
'success' => 'Seu novo modelo de incidente foi criado.',
'failure' => 'Algo deu errado com o modelo de incidente.',
],
@@ -75,21 +75,21 @@ return [
// Incident Maintenance
'schedule' => [
'schedule' => 'Manutenção',
'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported <strong>:count</strong> schedules.',
'logged' => '{0}Ainda não ocorreu nenhuma manuteção, bom trabalho. |[1]Você agendou uma manuteção. | [2, *] Você adicionou <strong>:</strong> manutenções.',
'scheduled_at' => 'Agendada em :timestamp',
'add' => [
'title' => 'Adicionar manutenção agendada',
'success' => 'Maintenance added.',
'failure' => 'Something went wrong adding the Maintenance, please try again.',
'success' => 'Manutenção adicionada.',
'failure' => 'Algo deu errado ao adicionar a Manutenção, por favor tente novamente.',
],
'edit' => [
'title' => 'Edit Maintenance',
'success' => 'Maintenance has been updated!',
'failure' => 'Something went wrong editing the Maintenance, please try again.',
'title' => 'Editar Manutenção',
'success' => 'Manutenção atualizada!',
'failure' => 'Algo deu errado ao editar a Manutenção, por favor tente novamente.',
],
'delete' => [
'success' => 'The Maintenance has been deleted and will not show on your status page.',
'failure' => 'The Maintenance could not be deleted, please try again.',
'success' => 'A manutenção programada foi excluída e não aparecerá na sua página de status.',
'failure' => 'A Manutenção não pôde ser excluída, por favor tente novamente.',
],
],
@@ -158,12 +158,12 @@ return [
'subscribers' => [
'subscribers' => 'Assinantes',
'description' => 'Assinantes vão receber atualizações de e-mail quando incidentes criados ou componentes atualizados.',
'description_disabled' => 'To use this feature, you need allow people to signup for notifications.',
'description_disabled' => 'Para utilizar esse recurso, você precisa permitir que as pessoas se cadastrem para notificações.',
'verified' => 'Verificado',
'not_verified' => 'Não verificado',
'subscriber' => ':email, inscreveu-se em :date',
'no_subscriptions' => 'Inscrito em todas as atualizações',
'global' => 'Globally subscribed',
'global' => 'Inscrito globalmente',
'add' => [
'title' => 'Adicionar um novo assinante',
'success' => 'Inscrito adicionado.',

View File

@@ -22,7 +22,7 @@ return [
|
*/
'previous' => 'Previous',
'next' => 'Next',
'previous' => 'Anterior',
'next' => 'Próxima',
];

View File

@@ -23,7 +23,7 @@
@if($components->count() > 1)
<span class="drag-handle"><i class="ion ion-drag"></i></span>
@endif
{{ $component->name }} <small>{{ $component->human_status }}</small>
{!! $component->name !!} <small>{{ $component->human_status }}</small>
</h4>
@if($component->group)
<p><small>{{ trans('dashboard.components.listed_group', ['name' => $component->group->name]) }}</small></p>

View File

@@ -83,12 +83,12 @@
@foreach($componentsInGroups as $group)
<optgroup label="{{ $group->name }}">
@foreach($group->components as $component)
<option value="{{ $component->id }}">{{ $component->name }}</option>
<option value="{{ $component->id }}">{!! $component->name !!}</option>
@endforeach
</optgroup>
@endforeach
@foreach($componentsOutGroups as $component)
<option value="{{ $component->id }}">{{ $component->name }}</option>
<option value="{{ $component->id }}">{!! $component->name !!}</option>
@endforeach
</select>
</div>

View File

@@ -57,7 +57,15 @@
<input type="text" name="completed_at" class="form-control flatpickr-time" data-date-format="Y-m-d H:i" placeholder="{{ trans('forms.schedules.completed_at') }}">
</div>
</fieldset>
@if($notificationsEnabled)
<input type="hidden" name="notify" value="0">
<div class="checkbox">
<label>
<input type="checkbox" name="notify" value="1" checked="{{ Binput::old('notify', 'checked') }}">
{{ trans('forms.incidents.notify_subscribers') }}
</label>
</div>
@endif
<div class="form-group">
<div class="btn-group">
<button type="submit" class="btn btn-success">{{ trans('forms.add') }}</button>

View File

@@ -2,7 +2,7 @@
<form class='component-inline form-vertical' data-messenger="{{trans('dashboard.components.edit.success')}}">
<div class="row striped-list-item">
<div class="col-lg-4 col-md-3 col-sm-12">
<h5 class="{{ $component->status_color }}">{{ $component->name }}</h5>
<h5 class="{{ $component->status_color }}">{!! $component->name !!}</h5>
</div>
<div class="col-lg-8 col-md-9 col-sm-12 radio-items component-inline-update">
@foreach(trans('cachet.components.status') as $statusID => $status)

View File

@@ -2,10 +2,7 @@
<div class="sidebar-inner">
<div class="profile">
<a href="{{ cachet_route('dashboard.user') }}">
<span class="avatar"><img src="{{ $currentUser->avatar }}"></span>
</a>
<a href="{{ cachet_route('dashboard.user') }}">
<h4 class="username">{{ $currentUser->username }}</h4>
<h4 class="username"><i class='ion ion-person'></i> {{ $currentUser->username }}</h4>
</a>
</div>
<div class="clearfix"></div>

View File

@@ -8,7 +8,7 @@
<span class="uppercase">
<i class="ion ion-ios-email-outline"></i> {{ trans('dashboard.subscribers.subscribers') }}
</span>
@if($currentUser->isAdmin && $enableSubscribers)
@if($currentUser->isAdmin)
<a class="btn btn-md btn-success pull-right" href="{{ cachet_route('dashboard.subscribers.create') }}">
{{ trans('dashboard.subscribers.add.title') }}
</a>
@@ -19,11 +19,7 @@
<div class="row">
<div class="col-sm-12">
<p class="lead">
@if($enableSubscribers)
{{ trans('dashboard.subscribers.description') }}
@else
{{ trans('dashboard.subscribers.description_disabled') }}
@endif
</p>
<div class="striped-list">
@@ -51,6 +47,7 @@
@endif
</div>
<div class="col-xs-3 text-right">
<a href="{{ cachet_route('subscribe.manage', $subscriber->verify_code) }}" target="_blank" class="btn btn-success">{{ trans('forms.edit') }}</a>
<a href="{{ cachet_route('dashboard.subscribers.delete', [$subscriber->id], 'delete') }}" class="btn btn-danger confirm-action" data-method='DELETE'>{{ trans('forms.delete') }}</a>
</div>
</div>

View File

@@ -27,13 +27,12 @@
<div class="user-grid">
@foreach($teamMembers as $member)
<a href="@if($currentUser->id == $member->id) {{ cachet_route('dashboard.team.edit', $member) }} @else /dashboard/team/{{ $member->id }} @endif">
<div class="user col-sm-3 col-xs-6">
<a href="@if($currentUser->id == $member->id) {{ url('dashboard/user') }} @else /dashboard/team/{{ $member->id }} @endif">
<img src="{{ $member->avatar }}">
</a>
<div class="name">{{ $member->username }}</div>
<div class="email">{{ $member->email }}</div>
</div>
</a>
@endforeach
</div>
</div>

View File

@@ -25,7 +25,7 @@
@if($enableExternalDependencies)
{{-- <link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,700&subset={{ $fontSubset }}" rel="stylesheet" type="text/css"> --}}
@endif
<link rel="stylesheet" href="{{ mix('dist/css/dashboard/dashboard.css') }}">
<link rel="stylesheet" href="{{ asset(mix('dist/css/dashboard/dashboard.css')) }}">
@yield('css')
@include('partials.crowdin')
@@ -35,8 +35,8 @@
Global.locale = '{{ $appLocale }}';
</script>
<script src="{{ mix('dist/js/manifest.js') }}"></script>
<script src="{{ mix('dist/js/vendor.js') }}"></script>
<script src="{{ asset(mix('dist/js/manifest.js')) }}"></script>
<script src="{{ asset(mix('dist/js/vendor.js')) }}"></script>
</head>
<body class="@yield('bodyClass')">
@@ -45,5 +45,5 @@
</div>
</body>
@yield('js')
<script src="{{ mix('dist/js/all.js') }}"></script>
<script src="{{ asset(mix('dist/js/all.js')) }}"></script>
</html>

View File

@@ -31,13 +31,13 @@
@if($enableExternalDependencies)
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,700&subset={{ $fontSubset }}" rel="stylesheet" type="text/css">
@endif
<link rel="stylesheet" href="{{ mix('dist/css/dashboard/dashboard.css') }}">
<link rel="stylesheet" href="{{ asset(mix('dist/css/dashboard/dashboard.css')) }}">
@yield('css')
@include('partials.crowdin')
<script src="{{ mix('dist/js/manifest.js') }}"></script>
<script src="{{ mix('dist/js/vendor.js') }}"></script>
<script src="{{ asset(mix('dist/js/manifest.js')) }}"></script>
<script src="{{ asset(mix('dist/js/vendor.js')) }}"></script>
</head>
<body class="dashboard">
@@ -61,5 +61,5 @@
</div>
</body>
@yield('js')
<script src="{{ mix('dist/js/all.js') }}"></script>
<script src="{{ asset(mix('dist/js/all.js')) }}"></script>
</html>

View File

@@ -16,7 +16,7 @@
<meta property="og:type" content="website">
<meta property="og:title" content="@yield('title', $siteTitle)">
<meta property="og:image" content="/img/favicon.png">
<meta property="og:image" content=" {{ asset('/img/favicon.png') }}">
<meta property="og:description" content="@yield('description', trans('cachet.meta.description.overview', ['app' => $appName]))">
<!-- Mobile IE allows us to activate ClearType technology for smoothing fonts for easy reading -->
@@ -48,7 +48,7 @@
@if($enableExternalDependencies)
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,700&amp;subset={{ $fontSubset }}" rel="stylesheet" type="text/css">
@endif
<link rel="stylesheet" href="{{ mix('dist/css/app.css') }}">
<link rel="stylesheet" href="{{ asset(mix('dist/css/app.css')) }} ">
@include('partials.stylesheet')
@@ -74,8 +74,8 @@
Global.locale = '{{ $appLocale }}';
</script>
<script src="{{ mix('dist/js/manifest.js') }}"></script>
<script src="{{ mix('dist/js/vendor.js') }}"></script>
<script src="{{ asset(mix('dist/js/manifest.js')) }}"></script>
<script src="{{ asset(mix('dist/js/vendor.js')) }}"></script>
</head>
<body class="status-page @yield('bodyClass')">
@yield('outer-content')
@@ -88,5 +88,5 @@
@yield('bottom-content')
</body>
<script src="{{ mix('dist/js/all.js') }}"></script>
<script src="{{ asset(mix('dist/js/all.js')) }}"></script>
</html>

View File

@@ -1,8 +1,8 @@
<li class="list-group-item {{ $component->group_id ? "sub-component" : "component" }}">
@if($component->link)
<a href="{{ $component->link }}" target="_blank" class="links">{{ $component->name }}</a>
<a href="{{ $component->link }}" target="_blank" class="links">{!! $component->name !!}</a>
@else
{{ $component->name }}
{!! $component->name !!}
@endif
@if($component->description)

View File

@@ -8,7 +8,7 @@
@if (in_array($component->id, $subscriptions) || $subscriber->global)
checked="checked"
@endif />
{{ $component->name }}
{!! $component->name !!}
</label>
@if($component->description)
<i class="ion ion-ios-help-outline help-icon" data-toggle="tooltip" data-title="{{ $component->description }}" data-container="body"></i>

View File

@@ -33,7 +33,8 @@
@if($incident->updates->isNotEmpty())
<div class="list-group">
@foreach($incident->updates as $update)
<a class="list-group-item incident-update-item" href="{{ $update->permalink }}">
<li class="list-group-item incident-update-item">
<i class="{{ $update->icon }}" title="{{ $update->human_status }}" data-toggle="tooltip"></i>
{!! $update->formatted_message !!}
<small>
@@ -42,9 +43,9 @@
data-timeago="{{ $update->timestamp_iso }}">
</abbr>
</small>
<span class="ion-ios-arrow-right pull-right"></span>
<a href="{{ $update->permalink }}" class="pull-right"><span class="ion-ios-arrow-right"></span></a>
</a>
</li>
@endforeach
</div>
@endif

View File

@@ -11,6 +11,8 @@
namespace CachetHQ\Tests\Cachet\Api;
use CachetHQ\Cachet\Models\Component;
/**
* This is the general test class.
*
@@ -42,4 +44,36 @@ class GeneralTest extends AbstractApiTestCase
$response->assertStatus(406);
}
public function test_can_get_system_status()
{
$response = $this->json('GET', '/api/v1/status');
$response->assertStatus(200)
->assertHeader('Cache-Control')
->assertJsonFragment([
'data' => [
'status' => 'success',
'message' => 'System operational',
],
]);
}
public function test_can_get_system_status_not_success()
{
factory(Component::class)->create([
'status' => 3,
]);
$response = $this->json('GET', '/api/v1/status');
$response->assertStatus(200)
->assertHeader('Cache-Control')
->assertJsonFragment([
'data' => [
'status' => 'info',
'message' => 'The system is experiencing issues',
],
]);
}
}

View File

@@ -34,6 +34,7 @@ class CreateScheduleCommandTest extends AbstractTestCase
'scheduled_at' => date('Y-m-d H:i'),
'completed_at' => date('Y-m-d H:i'),
'components' => [],
'notify' => 1,
];
$object = new CreateScheduleCommand(
$params['name'],
@@ -41,7 +42,8 @@ class CreateScheduleCommandTest extends AbstractTestCase
$params['status'],
$params['scheduled_at'],
$params['completed_at'],
$params['components']
$params['components'],
$params['notify']
);
return compact('params', 'object');

View File

@@ -319,13 +319,13 @@ aws4@^1.8.0:
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==
axios@^0.18:
version "0.18.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.0.tgz#32d53e4851efdc0a11993b6cd000789d70c05102"
integrity sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=
axios@^0.19:
version "0.19.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.0.tgz#8e09bff3d9122e133f7b8101c8fbdd00ed3d2ab8"
integrity sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==
dependencies:
follow-redirects "^1.3.0"
is-buffer "^1.1.5"
follow-redirects "1.5.10"
is-buffer "^2.0.2"
babel-code-frame@^6.26.0:
version "6.26.0"
@@ -1861,6 +1861,13 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.6, debug@^2.6.8, debug@^2.6.
dependencies:
ms "2.0.0"
debug@=3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
dependencies:
ms "2.0.0"
debug@^3.1.0, debug@^3.2.6:
version "3.2.6"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
@@ -2549,7 +2556,14 @@ flush-write-stream@^1.0.0:
inherits "^2.0.3"
readable-stream "^2.3.6"
follow-redirects@^1.0.0, follow-redirects@^1.3.0:
follow-redirects@1.5.10:
version "1.5.10"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==
dependencies:
debug "=3.1.0"
follow-redirects@^1.0.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.7.0.tgz#489ebc198dc0e7f64167bd23b03c4c19b5784c76"
integrity sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==
@@ -2660,10 +2674,10 @@ fsevents@^1.2.7:
nan "^2.12.1"
node-pre-gyp "^0.12.0"
fstream@^1.0.0, fstream@^1.0.2:
version "1.0.11"
resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171"
integrity sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=
fstream@^1.0.0, fstream@^1.0.12:
version "1.0.12"
resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045"
integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==
dependencies:
graceful-fs "^4.1.2"
inherits "~2.0.0"
@@ -3245,6 +3259,11 @@ is-buffer@^1.1.5, is-buffer@~1.1.1:
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
is-buffer@^2.0.2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725"
integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==
is-callable@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75"
@@ -3846,10 +3865,10 @@ lodash.uniq@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.10:
version "4.17.11"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.10:
version "4.17.13"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.13.tgz#0bdc3a6adc873d2f4e0c4bac285df91b64fc7b93"
integrity sha512-vm3/XWXfWtRua0FkUyEHBZy8kCPjErNBT9fJx8Zvs+U6zjqPbTUOpkaoum3O5uiA8sm+yNMHXfYkTUHFoMxFNA==
loglevel@^1.4.1:
version "1.6.1"
@@ -6306,12 +6325,12 @@ tapable@^0.2.7:
integrity sha512-2wsvQ+4GwBvLPLWsNfLCDYGsW6xb7aeC6utq2Qh0PFwgEy7K7dsma9Jsmb2zSQj7GvYAyUGSntLtsv++GmgL1A==
tar@^2.0.0:
version "2.2.1"
resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
integrity sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=
version "2.2.2"
resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.2.tgz#0ca8848562c7299b8b446ff6a4d60cdbb23edc40"
integrity sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==
dependencies:
block-stream "*"
fstream "^1.0.2"
fstream "^1.0.12"
inherits "2"
tar@^4: