Compare commits

..

117 Commits

Author SHA1 Message Date
James Brooks
d5d92f5a3d Update original incident with new update status 2016-08-04 20:28:06 +01:00
Graham Campbell
247c1565a4 Merge branch 'master' into develop 2016-07-29 13:26:02 -04:00
Graham Campbell
8f5afff4a2 Merge branch '2.4' 2016-07-29 13:14:33 -04:00
Graham Campbell
b045028c7b Merge pull request #2004 from CachetHQ/existence
Improved the bus test coverage
2016-07-29 13:12:29 -04:00
Graham Campbell
16189da222 Finished off tests 2016-07-29 13:05:30 -04:00
Graham Campbell
7596966e6c Added missing listener definitions 2016-07-29 13:05:18 -04:00
James Brooks
dcea947973 Fix metric point tests 2016-07-29 12:54:20 -04:00
James Brooks
d8ea3c59e3 Added update subscriber subscription command test 2016-07-29 12:54:20 -04:00
James Brooks
a2f8f4540e Added missing event tests 2016-07-29 12:54:20 -04:00
Graham Campbell
4031c42958 Added test existence tests 2016-07-29 12:54:20 -04:00
Graham Campbell
8348f48692 Merge branch '2.3' into 2.4 2016-07-29 12:51:23 -04:00
James Brooks
faf91470aa Remove elixir config 2016-07-29 12:05:50 -04:00
James Brooks
58039634bd Merge branch '2.3' into 2.4 2016-07-29 12:05:19 -04:00
James Brooks
915ea0d0bd Merge branch '2.3' into 2.4 2016-07-29 11:45:45 -04:00
Graham Campbell
a019d82010 Merge branch '2.4' 2016-07-25 23:03:58 +01:00
Graham Campbell
0f029702d4 Merge branch '2.3' into 2.4 2016-07-25 23:02:12 +01:00
James Brooks
71b5d446ba Merge branch '2.3' into 2.4 2016-07-25 21:44:07 +01:00
James Brooks
6246f20506 Set debug to true in tests 2016-07-25 08:09:53 +01:00
Graham Campbell
9dcc5d6896 Merge branch '2.3' into 2.4 2016-07-24 15:06:52 +01:00
James Brooks
235e3281b0 Merge branch '2.3' into 2.4 2016-07-22 09:20:58 +01:00
James Brooks
04b96e7dec Merge pull request #1995 from CachetHQ/standardise-team-member-commands
Standardise the team member commands
2016-07-22 09:15:48 +01:00
James Brooks
e15af44449 Standardise the team member commands. Closes #1881 2016-07-21 11:49:05 +01:00
Joe Cohen
ef9f7d23a0 Merge pull request #1993 from CachetHQ/skip-subscriber-verification
Added option to skip subscriber verification
2016-07-20 14:50:29 -05:00
Graham Campbell
ef694b027a Removed old variable 2016-07-20 19:58:58 +01:00
Graham Campbell
f53e466500 Applied fixes from StyleCI
[ci skip] [skip ci]
2016-07-20 14:56:55 -04:00
Graham Campbell
1e24138d7a Removed extra brackets 2016-07-20 19:54:48 +01:00
Graham Campbell
9120dba237 Fixed verification skipping 2016-07-20 19:52:23 +01:00
James Brooks
7f261a218a Added option to skip subscriber verification. Closes #1990 2016-07-20 16:00:27 +01:00
Graham Campbell
5b5db06ce3 Updated composer.lock hashes 2016-07-18 19:44:19 +01:00
Graham Campbell
b6635d30ee Merge branch '2.4' 2016-07-18 19:39:25 +01:00
Graham Campbell
5ae23b64d2 Bumped version 2016-07-18 19:39:18 +01:00
Graham Campbell
0d90f0459b Merge branch '2.3' into 2.4 2016-07-18 19:38:10 +01:00
James Brooks
bcbbee22d9 Merge pull request #1983 from peelman/improve-manage-subscriptions
group components on manage subscriptions page
2016-07-18 15:00:21 +01:00
Nick Peelman
9750191bff proper indents for @includes 2016-07-18 09:51:23 -04:00
Nick Peelman
52c4901a78 left align @include tags 2016-07-18 09:39:09 -04:00
Nick Peelman
587555c2d4 Adding a newline... 2016-07-18 09:12:42 -04:00
Nick Peelman
b4c7fb2ab0 adding a period... 2016-07-18 09:12:00 -04:00
Nick Peelman
e61d24f685 Fixing indentation problems... 2016-07-18 09:08:48 -04:00
Nick Peelman
88e85d2dfb group components on manage subscriptions page 2016-07-18 08:49:38 -04:00
James Brooks
5b72f2febc Merge '2.3' 2016-07-17 16:42:27 +01:00
Graham Campbell
7583fedaec Updated laravel 2016-07-14 11:25:50 -07:00
Graham Campbell
eecd78496c Merge branch 'master' into develop 2016-07-14 11:25:16 -07:00
Graham Campbell
4703aeadb2 Merge branch '2.3' 2016-07-14 11:23:45 -07:00
Graham Campbell
48dc39122f Merge branch 'master' into develop 2016-07-13 19:07:01 -07:00
Graham Campbell
3aacfb7849 Fixed the route service provider 2016-07-13 19:06:49 -07:00
Graham Campbell
ef304950bb Updated the tests 2016-07-13 19:04:58 -07:00
Graham Campbell
2101b829bb Merge branch 'master' into develop 2016-07-13 18:41:58 -07:00
Graham Campbell
ad8f098ec1 Merge branch '2.3' 2016-07-13 18:28:48 -07:00
James Brooks
2551a1a038 Updated deps 2016-07-13 19:24:57 +01:00
James Brooks
3874b533be Fix Feed import 2016-07-13 14:41:59 +01:00
James Brooks
85c0e94408 Fix import 2016-07-13 14:39:39 +01:00
James Brooks
1793f5588a Added missing import 2016-07-13 14:39:13 +01:00
James Brooks
46ff13c7fb Merge pull request #1972 from CachetHQ/analysis-qyrNE2
Applied fixes from StyleCI

[ci skip] [skip ci]
2016-07-13 14:38:51 +01:00
James Brooks
da8c8fae74 Applied fixes from StyleCI
[ci skip] [skip ci]
2016-07-13 09:38:47 -04:00
James Brooks
ff9eb123c6 Don't use the Config facade in any composers 2016-07-13 14:38:36 +01:00
James Brooks
895d1ea1b6 Don't use the Config facade in the TimezoneLocaleComposer 2016-07-13 14:35:49 +01:00
James Brooks
503252c3a2 Tidy up integrations, use contracts 2016-07-13 14:33:20 +01:00
James Brooks
ec0f0768f0 Added missing typehints 2016-07-13 14:24:02 +01:00
James Brooks
68cc6eb93c Merge pull request #1968 from CachetHQ/system-status-api
Implement the system status api endpoint
2016-07-13 14:22:29 +01:00
James Brooks
fdfebc18fb Implement the system status api endpoint. Closes #1936 2016-07-13 14:21:57 +01:00
James Brooks
0cd3ea0e92 Merge branch '2.3' 2016-07-13 14:21:00 +01:00
James Brooks
0f10522e9c Merge pull request #1957 from CachetHQ/apple-system-font
Update the font-stack to be -apple-system font
2016-07-12 22:41:07 +01:00
James Brooks
3913ab65ac Merge pull request #1962 from CachetHQ/user-management-api
Added Team Member API
2016-07-12 18:00:48 +01:00
James Brooks
2048e0899c Added Team Member API. Closes #1822 2016-07-12 17:59:50 +01:00
James Brooks
83e1013771 Merge branch '2.3' 2016-07-12 09:37:11 +01:00
James Brooks
7d4bab478f Merge branch '2.3' 2016-07-12 09:29:47 +01:00
James Brooks
18d7af2b35 Update the font-stack to be apple-system-font 2016-07-12 09:18:07 +01:00
James Brooks
e3cfb47d66 Merge branch '2.3' 2016-07-12 09:16:07 +01:00
James Brooks
716d357738 Resize the footer elements 2016-07-12 09:14:27 +01:00
James Brooks
cee336fd7c Merge pull request #1955 from CachetHQ/system-timezones
System Timezones
2016-07-12 09:10:23 +01:00
James Brooks
b3497820f9 Merge pull request #1954 from CachetHQ/analysis-8jlaNr
Applied fixes from StyleCI

[ci skip] [skip ci]
2016-07-11 21:44:19 +01:00
James Brooks
67152806d7 Applied fixes from StyleCI
[ci skip] [skip ci]
2016-07-11 16:44:15 -04:00
James Brooks
5298ad241a Show the timezone in the footer. 2016-07-11 21:43:59 +01:00
James Brooks
e2da8ee1fa Merge pull request #1952 from CachetHQ/disable-external-dependencies
Option to disable external dependencies
2016-07-11 10:12:27 +01:00
James Brooks
b6c22c1029 Option to disable external dependencies. Closes #1929 2016-07-11 10:11:44 +01:00
James Brooks
5c54830b0f Merged 2.3 2016-07-11 09:56:11 +01:00
James Brooks
1a6c22a8a9 Write the readme gooder 2016-06-30 08:48:30 +01:00
Graham Campbell
690290449e Merge branch 'master' into develop 2016-06-27 15:52:51 +01:00
Graham Campbell
cb5badefcc Merge branch '2.3' 2016-06-27 15:50:43 +01:00
Graham Campbell
e326381604 Merge branch 'master' into develop
# Conflicts:
#	composer.json
#	composer.lock
2016-06-11 00:55:48 +01:00
Graham Campbell
c25437871a Merge branch '2.3'
# Conflicts:
#	composer.lock
2016-06-11 00:49:49 +01:00
Graham Campbell
662fff9edf Merge branch 'master' into develop
# Conflicts:
#	VERSION
#	composer.json
#	composer.lock
2016-06-10 09:02:30 +01:00
Graham Campbell
e96088fc0f Updated lock file 2016-06-10 08:56:40 +01:00
Graham Campbell
7472657812 Merge branch '2.3' 2016-06-10 08:56:18 +01:00
Graham Campbell
6becaf2acd Bumped version to 2.4 2016-06-10 08:40:57 +01:00
Graham Campbell
c5c21cd8db Merge branch '2.3'
# Conflicts:
#	composer.lock
2016-06-07 11:21:25 +01:00
Graham Campbell
b960146512 Merge branch '2.3'
# Conflicts:
#	composer.json
#	composer.lock
2016-06-06 20:42:12 +01:00
Graham Campbell
3b6fb9f64e Use the new exception handler 2016-06-03 17:30:13 +01:00
Graham Campbell
acfb32bf1d Merge branch '2.3'
# Conflicts:
#	composer.json
#	composer.lock
2016-06-03 17:29:40 +01:00
James Brooks
f9946928c1 Merge pull request #1712 from CachetHQ/tags-api
Tags API
2016-06-02 11:25:14 +01:00
James Brooks
5176fca8f0 Implement the component tag API 2016-06-02 11:19:28 +01:00
James Brooks
4852f5558a Create a Tag api 2016-06-02 11:19:28 +01:00
Graham Campbell
b0c75a2319 Merge pull request #1863 from CachetHQ/analysis-8jl73Z
Applied fixes from StyleCI

[ci skip]
2016-05-30 12:15:20 +01:00
Graham Campbell
73d7303b6e Applied fixes from StyleCI
[ci skip]
2016-05-30 07:15:16 -04:00
Graham Campbell
2d8f2cbd63 Fixed typo 2016-05-30 12:14:56 +01:00
Graham Campbell
cb2ce8f67f Synced with laravel 5.3 2016-05-30 12:12:43 +01:00
Graham Campbell
d6d103cf15 Merge branch '2.3' 2016-05-29 19:38:59 +01:00
Graham Campbell
7f36783582 Merge branch '2.3' 2016-05-29 12:10:20 +01:00
Graham Campbell
ed851c232a Merge branch '2.3'
# Conflicts:
#	composer.lock
2016-05-28 22:07:52 +01:00
Graham Campbell
920a3ef6a9 Updated dependencies 2016-05-28 16:40:26 +01:00
Graham Campbell
15816c56bb Merge branch '2.3'
# Conflicts:
#	composer.json
#	composer.lock
2016-05-28 16:36:06 +01:00
Graham Campbell
e5e4b04151 Fix merge 2016-05-25 22:03:36 +01:00
Graham Campbell
283d343dd6 Merge branch '2.3'
# Conflicts:
#	composer.json
#	composer.lock
2016-05-25 22:03:20 +01:00
Graham Campbell
aa85c8708e Merge pull request #1742 from CachetHQ/next
Upgraded to Laravel 5.3
2016-05-25 19:54:46 +01:00
Graham Campbell
f93506fed9 Updated to the latest laravel version 2016-05-25 16:06:11 +01:00
Graham Campbell
b92f9d30fc Use the new bindings substitution middleware 2016-05-25 15:56:28 +01:00
Graham Campbell
3673e57c6f Upgraded to laravel 5.3 2016-05-25 12:38:16 +01:00
Graham Campbell
9fb6ae4fc0 Merge branch '2.3' 2016-05-25 12:28:46 +01:00
Graham Campbell
583601644c Merge branch '2.3'
# Conflicts:
#	composer.json
#	composer.lock
2016-05-25 12:04:37 +01:00
Graham Campbell
5ea816ce2b Merge pull request #1595 from CachetHQ/incident-updates
Incident updates
2016-05-14 08:47:03 +01:00
Joseph Cohen
541d410e41 Implement Incident Updates 2016-05-14 02:38:07 -05:00
Graham Campbell
03348b8ff2 Merge branch '2.3'
# Conflicts:
#	composer.lock
2016-05-13 00:38:09 +01:00
Graham Campbell
2e8743eb6b Merge branch '2.3' 2016-05-01 16:25:09 +01:00
Graham Campbell
66ff1cca65 Updated dependencies 2016-04-27 15:04:32 +01:00
Graham Campbell
64ff9b7d40 Updated phpunit and mockery 2016-04-27 15:01:48 +01:00
Graham Campbell
446aed6b9a Bumped min php version
# Conflicts:
#	composer.json
2016-04-27 15:01:30 +01:00
Graham Campbell
0281c44933 Bumped version 2016-04-27 15:00:45 +01:00
220 changed files with 5579 additions and 1267 deletions

View File

@@ -1,7 +1,7 @@
Before submitting your issue, please make sure that you've checked the checkboxes below.
- [ ] I am running the [latest release](https://github.com/CachetHQ/Cachet/releases/latest) version of Cachet.
- [ ] I am running at least PHP 5.5.9. *You can check this by running `php -v`.*
- [ ] I am running at least PHP 5.6.4. *You can check this by running `php -v`.*
- [ ] I have ran `rm -rf bootstrap/cache/*`.
### Expected behaviour

View File

@@ -1,18 +1,11 @@
language: php
sudo: false
dist: trusty
php:
- 5.5.9
- 5.5
- 5.6
- 7.0
- 7.1
- hhvm
before_install: cp .env.example .env
sudo: false
install: travis_retry composer install --no-interaction --no-scripts --prefer-source

View File

@@ -1,14 +1,18 @@
# Cachet
[![StyleCI](https://styleci.io/repos/26730195/shield)](https://styleci.io/repos/26730195/)
[![Build Status](https://img.shields.io/travis/CachetHQ/Cachet/2.3.svg?style=flat-square)](https://travis-ci.org/CachetHQ/Cachet)
[![Build Status](https://img.shields.io/travis/CachetHQ/Cachet/master.svg?style=flat-square)](https://travis-ci.org/CachetHQ/Cachet)
[![Software License](https://img.shields.io/badge/license-BSD3-brightgreen.svg?style=flat-square)](LICENSE)
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/cachet/localized.svg)](http://translate.cachethq.io/project/cachet)
[![Packagist](https://img.shields.io/packagist/v/cachethq/cachet.svg?style=flat-square)](https://packagist.org/packages/cachethq/cachet)
![Screenshot](https://cachethq.io/img/main-interface.jpg)
Cachet is a beautiful and powerful open source status page system.
Cachet is a beautiful and powerful open source status page system, a free replacement to services such as StatusPage.io, Status.io and others.
## Show your support
Cachet is a BSD-3-licensed open source project. If you'd like to support future development, check out the [Patreon campaign](https://patreon.com/jbrooksuk).
## Features
@@ -21,17 +25,21 @@ Cachet is a beautiful and powerful open source status page system.
- Metrics
- Cross-database support: MySQL, PostgreSQL and SQLite
- Subscriber notifications via Email
- Two factor authentication using Google Authenticator
- Two factor authentication, with Google Authenticator
## Usage in production
Use of `master` in a production environment is not recommended as it may change at any time.
## Requirements
- PHP 5.5.9+ or newer
- PHP 5.6.4+ or newer
- Apache or Nginx server
- [Composer](https://getcomposer.org)
## I'm looking to contribute to this awesome project!
## How to contribute
Sweet, we're always looking for contributions that improve Cachet! It's easy to get started and you don't even need to know how to write a single line of code!
We're always looking for contributions that improve Cachet. It's easy to get started and you don't even need to know how to write a single line of code!
### Contributing as a non-developer/non-designer
@@ -63,13 +71,11 @@ We use these extra dependencies to develop Cachet:
- Gulp
- Git
Once cloned to your local machine, you'll need some demo data! Run `php artisan cachet:seed` to get the demo installation ready for action.
Once cloned to your local machine, you'll need some demo data! Run `php artisan cachet:seed` to get the demo installation on the go.
## Installation, Upgrades and Documentation
Documentation is found at [https://docs.cachethq.io](https://docs.cachethq.io).
Here are some useful quick links:
You can now find our documentation at [https://docs.cachethq.io](https://docs.cachethq.io).
- [Installing Cachet](https://docs.cachethq.io/docs/installing-cachet)
- [Getting started with Docker](https://docs.cachethq.io/docs/get-started-with-docker)
@@ -78,8 +84,8 @@ Here are some useful quick links:
To test out the demo, you may login to the [Dashboard](https://demo.cachethq.io/dashboard) with the following:
- **Username:** `test` or `test@test.com`
- **Password:** `test123`
- **Username:** test or test@test.com
- **Password:** test123
The demo is reset every half hour.
@@ -89,18 +95,14 @@ We list releases on the [Releases page](https://github.com/CachetHQ/Cachet/relea
## Translations
If you'd like to contribute translations, please check out our [CrowdIn project](https://crowdin.com/project/cachet).
> Thank you to our [translators](https://crowdin.com/project/cachet/activity_stream), who have allowed us to share Cachet with the world!
## Show your support
Cachet is a BSD-3-licensed open source project. If you'd like to support future development, check out the [Patreon campaign](https://patreon.com/jbrooksuk).
## Professional Installation Service
We offer a professional installation service. To find out more, email us at [support@alt-three.com](mailto:support@alt-three.com?Cachet Installation)
A special thank you to our [translators](https://crowdin.com/project/cachet/activity_stream), who have allowed us to share Cachet with the world. If you'd like to contribute translations, please check out our [CrowdIn project](https://crowdin.com/project/cachet).
## Security Vulnerabilities
If you discover a security vulnerability within Cachet, please send an e-mail to us at support@alt-three.com. We handle all security vulnerabilities on a case-by-case basis.
## Installations
We offer a paid installation service, which starts at $99 but is subject to change, dependant on your setup and infrastructure.
To find out more, email us at support@alt-three.com

View File

@@ -1 +1 @@
2.3.12
3.0.0-dev

View File

@@ -0,0 +1,61 @@
<?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\Commands\ComponentTag;
use CachetHQ\Cachet\Models\Component;
use CachetHQ\Cachet\Models\Tag;
/**
* This is the add component tag command.
*
* @author James Brooks <james@alt-three.com>
*/
final class AddComponentTagCommand
{
/**
* The component to add the tag to.
*
* @var \CachetHQ\Cachet\Models\Component
*/
public $component;
/**
* The tag to add to the component.
*
* @var \CachetHQ\Cachet\Models\Tag
*/
public $tag;
/**
* The validation rules.
*
* @var string[]
*/
public $rules = [
'component' => 'required',
'tag' => 'required',
];
/**
* Create a add component tag command instance.
*
* @param \CachetHQ\Cachet\Models\Component $component
* @param \CachetHQ\Cachet\Models\Tag $tag
*
* @return void
*/
public function __construct(Component $component, Tag $tag)
{
$this->component = $component;
$this->tag = $tag;
}
}

View File

@@ -0,0 +1,61 @@
<?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\Commands\ComponentTag;
use CachetHQ\Cachet\Models\Component;
use CachetHQ\Cachet\Models\Tag;
/**
* This is the delete component tag command.
*
* @author James Brooks <james@alt-three.com>
*/
final class DeleteComponentTagCommand
{
/**
* The component to delete the tag from.
*
* @var \CachetHQ\Cachet\Models\Component
*/
public $component;
/**
* The tag to delete.
*
* @var \CachetHQ\Cachet\Models\Tag
*/
public $tag;
/**
* The validation rules.
*
* @var string[]
*/
public $rules = [
'component' => 'required',
'tag' => 'required',
];
/**
* Create a delete component tag command instance.
*
* @param \CachetHQ\Cachet\Models\Component $component
* @param \CachetHQ\Cachet\Models\Tag $tag
*
* @return void
*/
public function __construct(Component $component, Tag $tag)
{
$this->component = $component;
$this->tag = $tag;
}
}

View File

@@ -0,0 +1,41 @@
<?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\Commands\IncidentUpdate;
use CachetHQ\Cachet\Models\IncidentUpdate;
/**
* This is the remove incident update command.
*
* @author James Brooks <james@alt-three.com>
*/
final class RemoveIncidentUpdateCommand
{
/**
* The incident update to remove.
*
* @var \CachetHQ\Cachet\Models\IncidentUpdate
*/
public $incidentUpdate;
/**
* Create a new remove incident update command instance.
*
* @param \CachetHQ\Cachet\Models\IncidentUpdate $incidentUpdate
*
* @return void
*/
public function __construct(IncidentUpdate $incidentUpdate)
{
$this->incidentUpdate = $incidentUpdate;
}
}

View File

@@ -0,0 +1,81 @@
<?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\Commands\IncidentUpdate;
use CachetHQ\Cachet\Models\Incident;
use CachetHQ\Cachet\Models\User;
/**
* This is the report incident update command.
*
* @author James Brooks <james@alt-three.com>
*/
final class ReportIncidentUpdateCommand
{
/**
* The incident.
*
* @var \CachetHQ\Cachet\Models\Incident
*/
public $incident;
/**
* The incident status.
*
* @var int
*/
public $status;
/**
* The incident message.
*
* @var string
*/
public $message;
/**
* The user.
*
* @var \CachetHQ\Cachet\Models\User
*/
public $user;
/**
* The validation rules.
*
* @var string[]
*/
public $rules = [
'incident' => 'required',
'status' => 'required|int|min:1|max:4',
'message' => 'required|string',
'user' => 'required',
];
/**
* Create a new report incident update command instance.
*
* @param \CachetHQ\Cachet\Models\Incident $incident
* @param string $status
* @param string $message
* @param \CachetHQ\Cachet\Models\User $user
*
* @return void
*/
public function __construct(Incident $incident, $status, $message, User $user)
{
$this->incident = $incident;
$this->status = $status;
$this->message = $message;
$this->user = $user;
}
}

View File

@@ -0,0 +1,81 @@
<?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\Commands\IncidentUpdate;
use CachetHQ\Cachet\Models\IncidentUpdate;
use CachetHQ\Cachet\Models\User;
/**
* This is the update incident update command.
*
* @author James Brooks <james@alt-three.com>
*/
final class UpdateIncidentUpdateCommand
{
/**
* The incident update.
*
* @var \CachetHQ\Cachet\Models\IncidentUpdate
*/
public $update;
/**
* The incident status.
*
* @var int
*/
public $status;
/**
* The incident message.
*
* @var string
*/
public $message;
/**
* The user.
*
* @var \CachetHQ\Cachet\Models\User
*/
public $user;
/**
* The validation rules.
*
* @var string[]
*/
public $rules = [
'update' => 'required',
'status' => 'int|min:1|max:4',
'message' => 'string',
'user' => 'required',
];
/**
* Create a new update incident update command instance.
*
* @param \CachetHQ\Cachet\Models\IncidentUpdate $update
* @param string $status
* @param string $message
* @param \CachetHQ\Cachet\Models\User $user
*
* @return void
*/
public function __construct(IncidentUpdate $update, $status, $message, User $user)
{
$this->update = $update;
$this->status = $status;
$this->message = $message;
$this->user = $user;
}
}

View File

@@ -0,0 +1,58 @@
<?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\Commands\Tag;
/**
* This is the create tag command.
*
* @author James Brooks <james@alt-three.com>
*/
final class CreateTagCommand
{
/**
* The name.
*
* @var string
*/
public $name;
/**
* The slug.
*
* @var string
*/
public $slug;
/**
* The validation rules.
*
* @var array
*/
public $rules = [
'name' => 'required|string',
'slug' => 'sometimes|string',
];
/**
* Create a new create tag command instance.
*
* @param string $name
* @param string $slug
*
* @return void
*/
public function __construct($name, $slug)
{
$this->name = $name;
$this->slug = $slug;
}
}

View File

@@ -0,0 +1,50 @@
<?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\Commands\Tag;
use CachetHQ\Cachet\Models\Tag;
/**
* This is the delete tag command.
*
* @author James Brooks <james@alt-three.com>
*/
final class DeleteTagCommand
{
/**
* The tag.
*
* @var \CachetHQ\Cachet\Models\Tag
*/
public $tag;
/**
* The validation rules.
*
* @var array
*/
public $rules = [
'tag' => 'required',
];
/**
* Create a new delete tag command instance.
*
* @param \CachetHQ\Cachet\Models\Tag $tag
*
* @return void
*/
public function __construct(Tag $tag)
{
$this->tag = $tag;
}
}

View File

@@ -0,0 +1,70 @@
<?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\Commands\Tag;
use CachetHQ\Cachet\Models\Tag;
/**
* This is the update tag command.
*
* @author James Brooks <james@alt-three.com>
*/
final class UpdateTagCommand
{
/**
* The tag.
*
* @var \CachetHQ\Cachet\Models\Tag
*/
public $tag;
/**
* The name.
*
* @var string
*/
public $name;
/**
* The slug.
*
* @var string
*/
public $slug;
/**
* The validation rules.
*
* @var array
*/
public $rules = [
'tag' => 'required',
'name' => 'sometimes|string',
'slug' => 'sometimes|string',
];
/**
* Create a new update tag command instance.
*
* @param \CachetHQ\Cachet\Models\Tag $tag
* @param string $name
* @param string $slug
*
* @return void
*/
public function __construct(Tag $tag, $name, $slug)
{
$this->tag = $tag;
$this->name = $name;
$this->slug = $slug;
}
}

View File

@@ -11,7 +11,12 @@
namespace CachetHQ\Cachet\Bus\Commands\User;
final class AddTeamMemberCommand
/**
* This is the add user command.
*
* @author James Brooks <james@alt-three.com>
*/
final class AddUserCommand
{
/**
* The user username.
@@ -48,8 +53,9 @@ final class AddTeamMemberCommand
*/
public $rules = [
'name' => 'required|string',
'password' => 'string',
'level' => 'int',
'email' => 'required|email',
'password' => 'required|string',
'level' => 'int|min:1|max:2',
];
/**

View File

@@ -11,7 +11,12 @@
namespace CachetHQ\Cachet\Bus\Commands\User;
final class InviteTeamMemberCommand
/**
* This is the invite user command.
*
* @author James Brooks <james@alt-three.com>
*/
final class InviteUserCommand
{
/**
* The invite emails.
@@ -30,7 +35,7 @@ final class InviteTeamMemberCommand
];
/**
* Create a new invite team member command instance.
* Create a new invite user command instance.
*
* @param string[] $emails
*

View File

@@ -0,0 +1,90 @@
<?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\Commands\User;
use CachetHQ\Cachet\Models\User;
/**
* This is the update team member command.
*
* @author James Brooks <james@alt-three.com>
*/
final class UpdateTeamMemberCommand
{
/**
* The user to update.
*
* @var \CachetHQ\Cachet\Models\User
*/
public $user;
/**
* The user username.
*
* @var string
*/
public $username;
/**
* The user password.
*
* @var string
*/
public $password;
/**
* The user email.
*
* @var string
*/
public $email;
/**
* The user level.
*
* @var int
*/
public $level;
/**
* The validation rules.
*
* @var string[]
*/
public $rules = [
'user' => 'required',
'name' => 'required|string',
'email' => 'required|email',
'password' => 'required|string',
'level' => 'int|min:1|max:2',
];
/**
* Create a new add team member command instance.
*
* @param \CachetHQ\Cachet\Models\User $user
* @param string $username
* @param string $password
* @param string $email
* @param int $level
*
* @return void
*/
public function __construct(User $user, $username, $password, $email, $level)
{
$this->user = $user;
$this->username = $username;
$this->password = $password;
$this->email = $email;
$this->level = $level;
}
}

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\Events\IncidentUpdate;
use CachetHQ\Cachet\Bus\Events\EventInterface;
/**
* This is the incident update event interface.
*
* @author James Brooks <james@alt-three.com>
*/
interface IncidentUpdateEventInterface extends EventInterface
{
//
}

View File

@@ -0,0 +1,41 @@
<?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\Events\IncidentUpdate;
use CachetHQ\Cachet\Models\IncidentUpdate;
/**
* This is the incident update was removed event.
*
* @author James Brooks <james@alt-three.com>
*/
final class IncidentUpdateWasRemovedEvent implements IncidentUpdateEventInterface
{
/**
* The incident update that has been removed.
*
* @var \CachetHQ\Cachet\Models\IncidentUpdate
*/
public $update;
/**
* Create a new incident update was removed event instance.
*
* @param \CachetHQ\Cachet\Models\IncidentUpdate $update
*
* @return void
*/
public function __construct(IncidentUpdate $update)
{
$this->update = $update;
}
}

View File

@@ -0,0 +1,41 @@
<?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\Events\IncidentUpdate;
use CachetHQ\Cachet\Models\IncidentUpdate;
/**
* This is the incident update was reported event.
*
* @author James Brooks <james@alt-three.com>
*/
final class IncidentUpdateWasReportedEvent implements IncidentUpdateEventInterface
{
/**
* The incident update that has been reported.
*
* @var \CachetHQ\Cachet\Models\IncidentUpdate
*/
public $update;
/**
* Create a new incident update was reported event instance.
*
* @param \CachetHQ\Cachet\Models\IncidentUpdate $update
*
* @return void
*/
public function __construct(IncidentUpdate $update)
{
$this->update = $update;
}
}

View File

@@ -0,0 +1,41 @@
<?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\Events\IncidentUpdate;
use CachetHQ\Cachet\Models\IncidentUpdate;
/**
* This is the incident update was updated event.
*
* @author James Brooks <james@alt-three.com>
*/
final class IncidentUpdateWasUpdatedEvent implements IncidentUpdateEventInterface
{
/**
* The incident update that has been updated.
*
* @var \CachetHQ\Cachet\Models\IncidentUpdate
*/
public $update;
/**
* Create a new incident update was updated event instance.
*
* @param \CachetHQ\Cachet\Models\IncidentUpdate $update
*
* @return void
*/
public function __construct(IncidentUpdate $update)
{
$this->update = $update;
}
}

View File

@@ -0,0 +1,41 @@
<?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\Events\User;
use CachetHQ\Cachet\Models\User;
/**
* This is the user was updated event.
*
* @author James Brooks <james@alt-three.com>
*/
final class UserWasUpdatedEvent implements UserEventInterface
{
/**
* The user that has been updated.
*
* @var \CachetHQ\Cachet\Models\User
*/
public $user;
/**
* Create a new user was updated event instance.
*
* @param \CachetHQ\Cachet\Models\User $user
*
* @return void
*/
public function __construct(User $user)
{
$this->user = $user;
}
}

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\Exceptions\Tag;
use Exception;
/**
* This is the tag does not exist on component exception class.
*
* @author James Brooks <james@alt-three.com>
*/
class TagDoesNotExistOnComponentException extends Exception implements TagExceptionInterface
{
//
}

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\Exceptions\Tag;
use CachetHQ\Cachet\Bus\Exceptions\ExceptionInterface;
/**
* This is the tag exception interface.
*
* @author James Brooks <james@alt-three.com>
*/
interface TagExceptionInterface extends ExceptionInterface
{
//
}

View File

@@ -0,0 +1,40 @@
<?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\Commands\ComponentTag;
use CachetHQ\Cachet\Bus\Commands\ComponentTag\AddComponentTagCommand;
use CachetHQ\Cachet\Models\ComponentTag;
/**
* This is the add component tag command handler.
*
* @author James Brooks <james@alt-three.com>
*/
class AddComponentTagCommandHandler
{
/**
* Handle the add component tag command.
*
* @param \CachetHQ\Cachet\Bus\Commands\ComponentTag\AddComponentTagCommand $command
*
* @return \CachetHQ\Cachet\Models\ComponentTag
*/
public function handle(AddComponentTagCommand $command)
{
$tag = ComponentTag::create([
'component_id' => $command->component->id,
'tag_id' => $command->tag->id,
]);
return $tag;
}
}

View File

@@ -0,0 +1,41 @@
<?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\Commands\ComponentTag;
use CachetHQ\Cachet\Bus\Commands\ComponentTag\DeleteComponentTagCommand;
use CachetHQ\Cachet\Bus\Exceptions\Tag\TagDoesNotExistOnComponentException;
use CachetHQ\Cachet\Models\ComponentTag;
/**
* This is the delete component tag command handler.
*
* @author James Brooks <james@alt-three.com>
*/
class DeleteComponentTagCommandHandler
{
/**
* Handle the add component tag command.
*
* @param \CachetHQ\Cachet\Bus\Commands\ComponentTag\DeleteComponentTagCommand $command
*
* @return void
*/
public function handle(DeleteComponentTagCommand $command)
{
// If the tag does not exist on the component, throw an exception.
if (!($componentTag = ComponentTag::tagForComponent($command->tag->id, $command->component->id))) {
throw new TagDoesNotExistOnComponentException('The given tag <'.$command->tag->id.'> does not exist on this component <'.$command->componnet->id.'>');
}
$componentTag->delete();
}
}

View File

@@ -0,0 +1,39 @@
<?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\Commands\IncidentUpdate;
use CachetHQ\Cachet\Bus\Commands\IncidentUpdate\RemoveIncidentUpdateCommand;
use CachetHQ\Cachet\Bus\Events\IncidentUpdate\IncidentUpdateWasRemovedEvent;
/**
* This is the remove incident update command handler.
*
* @author James Brooks <james@alt-three.com>
*/
class RemoveIncidentUpdateCommandHandler
{
/**
* Handle the remove incident update command.
*
* @param \CachetHQ\Cachet\Bus\Commands\IncidentUpdate\RemoveIncidentUpdateCommand $command
*
* @return void
*/
public function handle(RemoveIncidentUpdateCommand $command)
{
$update = $command->incidentUpdate;
event(new IncidentUpdateWasRemovedEvent($update));
$update->delete();
}
}

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\Commands\IncidentUpdate;
use CachetHQ\Cachet\Bus\Commands\IncidentUpdate\ReportIncidentUpdateCommand;
use CachetHQ\Cachet\Bus\Commands\Incident\UpdateIncidentCommand;
use CachetHQ\Cachet\Bus\Events\IncidentUpdate\IncidentUpdateWasReportedEvent;
use CachetHQ\Cachet\Models\IncidentUpdate;
/**
* This is the report incident update command handler.
*
* @author James Brooks <james@alt-three.com>
*/
class ReportIncidentUpdateCommandHandler
{
/**
* Handle the report incident command.
*
* @param \CachetHQ\Cachet\Bus\Commands\IncidentUpdate\ReportIncidentUpdateCommand $command
*
* @return \CachetHQ\Cachet\Models\IncidentUpdate
*/
public function handle(ReportIncidentUpdateCommand $command)
{
$data = [
'incident_id' => $command->incident->id,
'status' => $command->status,
'message' => $command->message,
'user_id' => $command->user->id,
];
// Create the incident update.
$update = IncidentUpdate::create($data);
// Update the original incident with the new status.
dispatch(new UpdateIncidentCommand(
$incident,
null,
$command->status,
null,
null,
null,
null,
null,
null,
null,
null
));
event(new IncidentUpdateWasReportedEvent($update));
return $update;
}
}

View File

@@ -0,0 +1,59 @@
<?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\Commands\IncidentUpdate;
use CachetHQ\Cachet\Bus\Commands\IncidentUpdate\UpdateIncidentUpdateCommand;
use CachetHQ\Cachet\Bus\Events\IncidentUpdate\IncidentUpdateWasUpdatedEvent;
/**
* This is the update incident update command handler.
*
* @author James Brooks <james@alt-three.com>
*/
class UpdateIncidentUpdateCommandHandler
{
/**
* Handle the update incident update command.
*
* @param \CachetHQ\Cachet\Bus\Commands\IncidentUpdate\UpdateIncidentUpdateCommand $command
*
* @return \CachetHQ\Cachet\Models\IncidentUpdate
*/
public function handle(UpdateIncidentUpdateCommand $command)
{
$command->update->update($this->filter($command));
event(new IncidentUpdateWasUpdatedEvent($command->update));
return $command->update;
}
/**
* Filter the command data.
*
* @param \CachetHQ\Cachet\Bus\Commands\IncidentUpdate\UpdateIncidentUpdateCommand $command
*
* @return array
*/
protected function filter(UpdateIncidentUpdateCommand $command)
{
$params = [
'status' => $command->status,
'message' => $command->message,
'user_id' => $command->user->id,
];
return array_filter($params, function ($val) {
return $val !== null;
});
}
}

View File

@@ -44,17 +44,17 @@ class SubscribeSubscriberCommandHandler
// Decide what to subscribe the subscriber to.
if ($subscriptions = $command->subscriptions) {
$components = Component::whereIn('id', $subscriptions)->get();
$subscriptions = Component::whereIn('id', $subscriptions);
} else {
$components = Component::all();
$subscriptions = Component::all();
}
$components->map(function ($component) use ($subscriber) {
foreach ($subscriptions as $component) {
Subscription::create([
'subscriber_id' => $subscriber->id,
'component_id' => $component->id,
]);
});
}
if ($command->verified) {
dispatch(new VerifySubscriberCommand($subscriber));
@@ -62,8 +62,6 @@ class SubscribeSubscriberCommandHandler
event(new SubscriberHasSubscribedEvent($subscriber));
}
$subscriber->load('subscriptions');
return $subscriber;
}
}

View File

@@ -13,6 +13,7 @@ namespace CachetHQ\Cachet\Bus\Handlers\Commands\Subscriber;
use CachetHQ\Cachet\Bus\Commands\Subscriber\UnsubscribeSubscriberCommand;
use CachetHQ\Cachet\Bus\Events\Subscriber\SubscriberHasUnsubscribedEvent;
use CachetHQ\Cachet\Models\Subscriber;
class UnsubscribeSubscriberCommandHandler
{

View File

@@ -0,0 +1,35 @@
<?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\Commands\Tag;
use CachetHQ\Cachet\Bus\Commands\Tag\CreateTagCommand;
use CachetHQ\Cachet\Models\Tag;
class CreateTagCommandHandler
{
/**
* Handle the create tag command.
*
* @param \CachetHQ\Cachet\Bus\Commands\Tag\CreateTagCommand $command
*
* @return \CachetHQ\Cachet\Models\Tag
*/
public function handle(CreateTagCommand $command)
{
$tag = Tag::create([
'name' => $command->name,
'slug' => $command->slug,
]);
return $tag;
}
}

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\Cachet\Bus\Handlers\Commands\Tag;
use CachetHQ\Cachet\Bus\Commands\Tag\DeleteTagCommand;
use CachetHQ\Cachet\Models\Tag;
class DeleteTagCommandHandler
{
/**
* Handle the delete tag command.
*
* @param \CachetHQ\Cachet\Bus\Commands\Tag\DeleteTagCommand $command
*
* @return void
*/
public function handle(DeleteTagCommand $command)
{
$command->tag->delete();
}
}

View File

@@ -0,0 +1,51 @@
<?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\Commands\Tag;
use CachetHQ\Cachet\Bus\Commands\Tag\UpdateTagCommand;
use CachetHQ\Cachet\Models\Tag;
class UpdateTagCommandHandler
{
/**
* Handle the update tag command.
*
* @param \CachetHQ\Cachet\Bus\Commands\Tag\UpdateTagCommand $command
*
* @return \CachetHQ\Cachet\Models\Tag
*/
public function handle(UpdateTagCommand $command)
{
$command->tag->update($this->filter($command));
return $command->tag;
}
/**
* Filter the command data.
*
* @param \CachetHQ\Cachet\Bus\Commands\Tag\UpdateTagCommand $command
*
* @return array
*/
protected function filter(UpdateTagCommand $command)
{
$params = [
'name' => $command->name,
'slug' => $command->slug,
];
return array_filter($params, function ($val) {
return $val !== null;
});
}
}

View File

@@ -11,20 +11,25 @@
namespace CachetHQ\Cachet\Bus\Handlers\Commands\User;
use CachetHQ\Cachet\Bus\Commands\User\AddTeamMemberCommand;
use CachetHQ\Cachet\Bus\Commands\User\AddUserCommand;
use CachetHQ\Cachet\Bus\Events\User\UserWasAddedEvent;
use CachetHQ\Cachet\Models\User;
class AddTeamMemberCommandHandler
/**
* This is the add user command handler.
*
* @author James Brooks <james@alt-three.com>
*/
class AddUserCommandHandler
{
/**
* Handle the add team member command.
* Handle the add user command.
*
* @param \CachetHQ\Cachet\Bus\Commands\User\AddTeamMemberCommand $command
* @param \CachetHQ\Cachet\Bus\Commands\User\AddUserCommand $command
*
* @return \CachetHQ\Cachet\Models\User
*/
public function handle(AddTeamMemberCommand $command)
public function handle(AddUserCommand $command)
{
$user = User::create([
'username' => $command->username,

View File

@@ -11,20 +11,25 @@
namespace CachetHQ\Cachet\Bus\Handlers\Commands\User;
use CachetHQ\Cachet\Bus\Commands\User\InviteTeamMemberCommand;
use CachetHQ\Cachet\Bus\Commands\User\InviteUserCommand;
use CachetHQ\Cachet\Bus\Events\User\UserWasInvitedEvent;
use CachetHQ\Cachet\Models\Invite;
class InviteTeamMemberCommandHandler
/**
* This is the invite user command handler.
*
* @author James Brooks <james@alt-three.com>
*/
class InviteUserCommandHandler
{
/**
* Handle the invite team member command.
*
* @param \CachetHQ\Cachet\Bus\Commands\User\InviteTeamMemberCommand $command
* @param \CachetHQ\Cachet\Bus\Commands\User\InviteUserCommand $command
*
* @return void
*/
public function handle(InviteTeamMemberCommand $command)
public function handle(InviteUserCommand $command)
{
foreach ($command->emails as $email) {
$invite = Invite::create([

View File

@@ -0,0 +1,63 @@
<?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\Commands\User;
use CachetHQ\Cachet\Bus\Commands\User\UpdateTeamMemberCommand;
use CachetHQ\Cachet\Bus\Events\User\UserWasUpdatedEvent;
use CachetHQ\Cachet\Models\User;
/**
* This is the update team member command handler.
*
* @author James Brooks <james@alt-three.com>
*/
class UpdateTeamMemberCommandHandler
{
/**
* Handle the add team member command.
*
* @param \CachetHQ\Cachet\Bus\Commands\User\UpdateTeamMemberCommand $command
*
* @return \CachetHQ\Cachet\Models\User
*/
public function handle(UpdateTeamMemberCommand $command)
{
$user = $command->user;
$user->update($this->filter($command));
event(new UserWasUpdatedEvent($user));
return $user;
}
/**
* Filter the command data.
*
* @param \CachetHQ\Cachet\Bus\Commands\User\UpdateTeamMemberCommand $command
*
* @return array
*/
protected function filter(UpdateTeamMemberCommand $command)
{
$params = [
'username' => $command->username,
'password' => $command->password,
'email' => $command->email,
'level' => $command->level,
];
return array_filter($params, function ($val) {
return $val !== null;
});
}
}

View File

@@ -106,8 +106,8 @@ class SendIncidentEmailNotificationHandler
$component = AutoPresenter::decorate($event->incident->component);
$mail = [
'email' => $subscriber->email,
'subject' => trans('cachet.subscriber.email.incident.subject', [
'email' => $subscriber->email,
'subject' => trans('cachet.subscriber.email.incident.subject', [
'status' => $incident->human_status,
'name' => $incident->name,
]),

View File

@@ -106,9 +106,9 @@ class SendMaintenanceEmailNotificationHandler
$component = AutoPresenter::decorate($event->incident->component);
$mail = [
'email' => $subscriber->email,
'subject' => trans('cachet.subscriber.email.maintenance.subject', [
'name' => $incident->name,
'email' => $subscriber->email,
'subject' => trans('cachet.subscriber.email.maintenance.subject', [
'name' => $incident->name,
]),
'has_component' => ($event->incident->component) ? true : false,
'component_name' => $component ? $component->name : null,

View File

@@ -46,9 +46,9 @@ class SendInviteUserEmailHandler
public function handle(UserWasInvitedEvent $event)
{
$mail = [
'email' => $event->invite->email,
'subject' => 'You have been invited.',
'link' => route('signup.invite', ['code' => $event->invite->code]),
'email' => $event->invite->email,
'subject' => 'You have been invited.',
'link' => route('signup.invite', ['code' => $event->invite->code]),
];
$this->mailer->queue([

View File

@@ -11,12 +11,41 @@
namespace CachetHQ\Cachet\Composers;
use CachetHQ\Cachet\Dates\DateFactory;
use GrahamCampbell\Markdown\Facades\Markdown;
use Illuminate\Contracts\Config\Repository;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Facades\Config;
class AppComposer
{
/**
* The date factory instance.
*
* @var \CachetHQ\Cachet\Dates\DateFactory
*/
protected $dates;
/**
* The illuminate config instance.
*
* @var \Illuminate\Contracts\Config\Repository
*/
protected $config;
/**
* Create a new app composer instance.
*
* @param \CachetHQ\Cachet\Dates\DateFactory $dates
* @param \Illuminate\Contracts\Config\Repository $config
*
* @return void
*/
public function __construct(DateFactory $dates, Repository $config)
{
$this->dates = $dates;
$this->config = $config;
}
/**
* Index page view composer.
*
@@ -26,25 +55,28 @@ class AppComposer
*/
public function compose(View $view)
{
$view->withAboutApp(Markdown::convertToHtml(Config::get('setting.app_about')));
$view->withAppAnalytics(Config::get('setting.app_analytics'));
$view->withAppAnalyticsGoSquared(Config::get('setting.app_analytics_gs'));
$view->withAppAnalyticsPiwikUrl(Config::get('setting.app_analytics_piwik_url'));
$view->withAppAnalyticsPiwikSiteId(Config::get('setting.app_analytics_piwik_site_id'));
$view->withAppBanner(Config::get('setting.app_banner'));
$view->withAppBannerStyleFullWidth(Config::get('setting.style_fullwidth_header'));
$view->withAppBannerType(Config::get('setting.app_banner_type'));
$view->withAppDomain(Config::get('setting.app_domain'));
$view->withAppGraphs(Config::get('setting.display_graphs'));
$view->withAppLocale(Config::get('setting.app_locale'));
$view->withAppStylesheet(Config::get('setting.stylesheet'));
$view->withAppUrl(Config::get('app.url'));
$view->withAppHeader(Config::get('setting.header'));
$view->withAppFooter(Config::get('setting.footer'));
$view->withAppName(Config::get('setting.app_name'));
$view->withShowSupport($support = Config::get('setting.show_support'));
$view->withAutomaticLocalization(Config::get('setting.automatic_localization'));
$view->withSiteTitle(Config::get('setting.app_name'));
$view->withFontSubset(Config::get('langs.'.Config::get('app.locale').'.subset', 'latin'));
$view->withAboutApp(Markdown::convertToHtml($this->config->get('setting.app_about')));
$view->withAppAnalytics($this->config->get('setting.app_analytics'));
$view->withAppAnalyticsGoSquared($this->config->get('setting.app_analytics_gs'));
$view->withAppAnalyticsPiwikUrl($this->config->get('setting.app_analytics_piwik_url'));
$view->withAppAnalyticsPiwikSiteId($this->config->get('setting.app_analytics_piwik_site_id'));
$view->withAppBanner($this->config->get('setting.app_banner'));
$view->withAppBannerStyleFullWidth($this->config->get('setting.style_fullwidth_header'));
$view->withAppBannerType($this->config->get('setting.app_banner_type'));
$view->withAppDomain($this->config->get('setting.app_domain'));
$view->withAppGraphs($this->config->get('setting.display_graphs'));
$view->withAppLocale($this->config->get('setting.app_locale'));
$view->withAppStylesheet($this->config->get('setting.stylesheet'));
$view->withAppUrl($this->config->get('app.url'));
$view->withAppHeader($this->config->get('setting.header'));
$view->withAppFooter($this->config->get('setting.footer'));
$view->withAppName($this->config->get('setting.app_name'));
$view->withShowSupport($this->config->get('setting.show_support'));
$view->withAutomaticLocalization($this->config->get('setting.automatic_localization'));
$view->withEnableExternalDependencies($this->config->get('setting.enable_external_dependencies'));
$view->withShowTimezone($this->config->get('setting.show_timezone'));
$view->withTimezone($this->dates->getTimezone());
$view->withSiteTitle($this->config->get('setting.app_name'));
$view->withFontSubset($this->config->get('langs.'.$this->config->get('app.locale').'.subset', 'latin'));
}
}

View File

@@ -12,11 +12,30 @@
namespace CachetHQ\Cachet\Composers;
use CachetHQ\Cachet\Models\Metric;
use Illuminate\Contracts\Config\Repository;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Facades\Config;
class MetricsComposer
{
/**
* The illuminate config instance.
*
* @var \Illuminate\Contracts\Config\Repository
*/
protected $config;
/**
* Create a new metrics composer.
*
* @param \Illuminate\Contracts\Config\Repository $config
*
* @return void
*/
public function __construct(Repository $config)
{
$this->config = $config;
}
/**
* Metrics view composer.
*
@@ -27,7 +46,7 @@ class MetricsComposer
public function compose(View $view)
{
$metrics = null;
if ($displayMetrics = Config::get('setting.display_graphs')) {
if ($displayMetrics = $this->config->get('setting.display_graphs')) {
$metrics = Metric::displayable()->orderBy('order')->orderBy('id')->get();
}

View File

@@ -11,11 +11,30 @@
namespace CachetHQ\Cachet\Composers;
use Illuminate\Contracts\Config\Repository;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Facades\Config;
class ThemeComposer
{
/**
* The illuminate config instance.
*
* @var \Illuminate\Contracts\Config\Repository
*/
protected $config;
/**
* Create a new theme composer.
*
* @param \Illuminate\Contracts\Config\Repository $config
*
* @return void
*/
public function __construct(Repository $config)
{
$this->config = $config;
}
/**
* Bind data to the view.
*
@@ -26,17 +45,17 @@ class ThemeComposer
public function compose(View $view)
{
// Theme colors.
$view->withThemeBackgroundColor(Config::get('setting.style_background_color', '#F0F3F4'));
$view->withThemeBackgroundFills(Config::get('setting.style_background_fills', '#FFFFFF'));
$view->withThemeBannerBackgroundColor(Config::get('setting.style_banner_background_color', ''));
$view->withThemeBannerPadding(Config::get('setting.style_banner_padding', '40px 0'));
$view->withThemeTextColor(Config::get('setting.style_text_color', '#333333'));
$view->withThemeReds(Config::get('setting.style_reds', '#ff6f6f'));
$view->withThemeBlues(Config::get('setting.style_blues', '#3498db'));
$view->withThemeGreens(Config::get('setting.style_greens', '#7ED321'));
$view->withThemeYellows(Config::get('setting.style_yellows', '#F7CA18'));
$view->withThemeOranges(Config::get('setting.style_oranges', '#FF8800'));
$view->withThemeMetrics(Config::get('setting.style_metrics', '#0dccc0'));
$view->withThemeLinks(Config::get('setting.style_links', '#7ED321'));
$view->withThemeBackgroundColor($this->config->get('setting.style_background_color', '#F0F3F4'));
$view->withThemeBackgroundFills($this->config->get('setting.style_background_fills', '#FFFFFF'));
$view->withThemeBannerBackgroundColor($this->config->get('setting.style_banner_background_color', ''));
$view->withThemeBannerPadding($this->config->get('setting.style_banner_padding', '40px 0'));
$view->withThemeTextColor($this->config->get('setting.style_text_color', '#333333'));
$view->withThemeReds($this->config->get('setting.style_reds', '#ff6f6f'));
$view->withThemeBlues($this->config->get('setting.style_blues', '#3498db'));
$view->withThemeGreens($this->config->get('setting.style_greens', '#7ED321'));
$view->withThemeYellows($this->config->get('setting.style_yellows', '#F7CA18'));
$view->withThemeOranges($this->config->get('setting.style_oranges', '#FF8800'));
$view->withThemeMetrics($this->config->get('setting.style_metrics', '#0dccc0'));
$view->withThemeLinks($this->config->get('setting.style_links', '#7ED321'));
}
}

View File

@@ -13,11 +13,30 @@ namespace CachetHQ\Cachet\Composers;
use DateTime;
use DateTimeZone;
use Illuminate\Contracts\Config\Repository;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Facades\Config;
class TimezoneLocaleComposer
{
/**
* The illuminate config instance.
*
* @var \Illuminate\Contracts\Config\Repository
*/
protected $config;
/**
* Create a new timezone locale composer.
*
* @param \Illuminate\Contracts\Config\Repository $config
*
* @return void
*/
public function __construct(Repository $config)
{
$this->config = $config;
}
/**
* Timezones and Locales composer.
*
@@ -27,7 +46,7 @@ class TimezoneLocaleComposer
*/
public function compose(View $view)
{
$enabledLangs = Config::get('langs');
$enabledLangs = $this->config->get('langs');
$langs = array_map(function ($lang) use ($enabledLangs) {
$locale = basename($lang);

View File

@@ -15,6 +15,7 @@ use CachetHQ\Cachet\Models\Component;
use CachetHQ\Cachet\Models\ComponentGroup;
use CachetHQ\Cachet\Models\Incident;
use CachetHQ\Cachet\Models\IncidentTemplate;
use CachetHQ\Cachet\Models\IncidentUpdate;
use CachetHQ\Cachet\Models\Metric;
use CachetHQ\Cachet\Models\MetricPoint;
use CachetHQ\Cachet\Models\Subscriber;
@@ -187,71 +188,31 @@ class DemoSeederCommand extends Command
*/
protected function seedIncidents()
{
$incidentMessage = <<<'EINCIDENT'
# Of course it does!
What kind of web application doesn't these days?
## Headers are fun aren't they
It's _exactly_ why we need Markdown. For **emphasis** and such.
EINCIDENT;
$defaultIncidents = [
[
'name' => 'Cachet supports Markdown!',
'message' => $incidentMessage,
'status' => 4,
'name' => 'Our monkeys aren\'t performing',
'message' => 'We\'re investigating an issue with our monkeys not performing as they should be.',
'status' => Incident::INVESTIGATING,
'component_id' => 0,
'scheduled_at' => null,
'visible' => 1,
],
[
'name' => 'Awesome',
'message' => ':+1: We totally nailed the fix.',
'status' => 4,
], [
'name' => 'This is an unresolved incident',
'message' => 'Unresolved incidents are left without a **Fixed** update.',
'status' => Incident::INVESTIGATING,
'component_id' => 0,
'scheduled_at' => null,
'visible' => 1,
],
[
'name' => 'Monitoring the fix',
'message' => ":ship: We've deployed a fix.",
'status' => 3,
'component_id' => 0,
'scheduled_at' => null,
'visible' => 1,
],
[
'name' => 'Update',
'message' => "We've identified the problem. Our engineers are currently looking at it.",
'status' => 2,
'component_id' => 0,
'scheduled_at' => null,
'visible' => 1,
],
[
'name' => 'Test Incident',
'message' => 'Something went wrong, with something or another.',
'status' => 1,
'component_id' => 0,
'scheduled_at' => null,
'visible' => 1,
],
[
'name' => 'Investigating the API',
'message' => ':zap: We\'ve seen high response times from our API. It looks to be fixing itself as time goes on.',
'status' => 1,
'component_id' => 1,
'scheduled_at' => null,
'visible' => 1,
],
];
Incident::truncate();
IncidentUpdate::truncate();
foreach ($defaultIncidents as $incident) {
Incident::create($incident);
foreach ($defaultIncidents as $defaultIncident) {
$incident = Incident::create($defaultIncident);
$this->seedIncidentUpdates($incident);
}
}
@@ -265,6 +226,47 @@ EINCIDENT;
IncidentTemplate::truncate();
}
/**
* Seed the incident updates table for a given incident.
*
* @return void
*/
protected function seedIncidentUpdates($incident)
{
$defaultUpdates = [
1 => [
[
'status' => Incident::FIXED,
'message' => 'The monkeys are back and rested!',
'user_id' => 1,
], [
'status' => Incident::WATCHED,
'message' => 'Our monkeys need a break from performing. They\'ll be back after a good rest.',
'user_id' => 1,
], [
'status' => Incident::IDENTIFIED,
'message' => 'We have identified the issue with our lovely performing monkeys.',
'user_id' => 1,
],
],
2 => [
[
'status' => Incident::WATCHED,
'message' => 'We\'re actively watching this issue, so it remains unresolved.',
'user_id' => 1,
],
],
];
$updates = $defaultUpdates[$incident->id];
foreach ($updates as $updateId => $update) {
$update['incident_id'] = $incident->id;
IncidentUpdate::create($update);
}
}
/**
* Seed the metric points table.
*

View File

@@ -11,6 +11,7 @@
namespace CachetHQ\Cachet\Dates;
use DateTimeZone;
use Jenssegers\Date\Date;
class DateFactory
@@ -88,4 +89,17 @@ class DateFactory
{
return (new Date($time))->setTimezone($this->cachetTimezone);
}
/**
* Return the abbreviated timezone.
*
* @return string
*/
public function getTimezone()
{
$dateTime = new Date();
$dateTime->setTimeZone(new DateTimeZone($this->cachetTimezone));
return $dateTime->format('T');
}
}

View File

@@ -14,9 +14,6 @@ namespace CachetHQ\Cachet\Foundation\Providers;
use AltThree\Bus\Dispatcher;
use CachetHQ\Cachet\Bus\Middleware\UseDatabaseTransactions;
use CachetHQ\Cachet\Dates\DateFactory;
use CachetHQ\Cachet\Integrations\Credits;
use CachetHQ\Cachet\Integrations\Feed;
use CachetHQ\Cachet\Integrations\Releases;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Str;
@@ -55,9 +52,6 @@ class AppServiceProvider extends ServiceProvider
public function register()
{
$this->registerDateFactory();
$this->registerCredits();
$this->registerFeed();
$this->registerReleases();
}
/**
@@ -74,47 +68,4 @@ class AppServiceProvider extends ServiceProvider
return new DateFactory($appTimezone, $cacheTimezone);
});
}
/**
* Register the credits class.
*
* @return void
*/
protected function registerCredits()
{
$this->app->singleton(Credits::class, function ($app) {
$cache = $app['cache.store'];
return new Credits($cache);
});
}
/**
* Register the feed class.
*
* @return void
*/
protected function registerFeed()
{
$this->app->singleton(Feed::class, function ($app) {
$cache = $app['cache.store'];
return new Feed($cache);
});
}
/**
* Register the releases class.
*
* @return void
*/
protected function registerReleases()
{
$this->app->singleton(Releases::class, function ($app) {
$cache = $app['cache.store'];
$token = $app['config']->get('services.github.token');
return new Releases($cache, $token);
});
}
}

View File

@@ -48,6 +48,9 @@ class EventServiceProvider extends ServiceProvider
'CachetHQ\Cachet\Bus\Events\Incident\IncidentWasUpdatedEvent' => [
//
],
'CachetHQ\Cachet\Bus\Events\Incident\IncidentWasRemovedEvent' => [
//
],
'CachetHQ\Cachet\Bus\Events\Incident\MaintenanceWasScheduledEvent' => [
'CachetHQ\Cachet\Bus\Handlers\Events\Incident\SendMaintenanceEmailNotificationHandler',
],
@@ -90,5 +93,11 @@ class EventServiceProvider extends ServiceProvider
'CachetHQ\Cachet\Bus\Events\User\UserWasInvitedEvent' => [
'CachetHQ\Cachet\Bus\Handlers\Events\User\SendInviteUserEmailHandler',
],
'CachetHQ\Cachet\Bus\Events\User\UserWasUpdatedEvent' => [
//
],
'CachetHQ\Cachet\Bus\Events\User\UserWasRemovedEvent' => [
//
],
];
}

View File

@@ -11,8 +11,14 @@
namespace CachetHQ\Cachet\Foundation\Providers;
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\Credits;
use CachetHQ\Cachet\Integrations\Core\Feed;
use CachetHQ\Cachet\Integrations\Core\System;
use CachetHQ\Cachet\Integrations\GitHub\Releases;
use Illuminate\Contracts\Container\Container;
use Illuminate\Support\ServiceProvider;
@@ -30,7 +36,39 @@ class IntegrationServiceProvider extends ServiceProvider
*/
public function register()
{
$this->registerCredits();
$this->registerFeed();
$this->registerSystem();
$this->registerReleases();
}
/**
* Register the credits class.
*
* @return void
*/
protected function registerCredits()
{
$this->app->singleton(CreditsContract::class, function ($app) {
$cache = $app['cache.store'];
return new Credits($cache);
});
}
/**
* Register the feed class.
*
* @return void
*/
protected function registerFeed()
{
$this->app->singleton(FeedContract::class, function ($app) {
$cache = $app['cache.store'];
return new Feed($cache);
});
}
/**
@@ -44,4 +82,19 @@ class IntegrationServiceProvider extends ServiceProvider
return new System();
});
}
/**
* Register the releases class.
*
* @return void
*/
protected function registerReleases()
{
$this->app->singleton(ReleasesContract::class, function ($app) {
$cache = $app['cache.store'];
$token = $app['config']->get('services.github.token');
return new Releases($cache, $token);
});
}
}

View File

@@ -28,34 +28,36 @@ class RouteServiceProvider extends ServiceProvider
/**
* Define the route model bindings, pattern filters, etc.
*
* @return void
*/
public function boot()
{
parent::boot();
$this->app->call([$this, 'bind']);
}
/**
* Define the bindings for the application.
*
* @param \Illuminate\Routing\Router $router
*
* @return void
*/
public function boot(Router $router)
public function bind(Router $router)
{
parent::boot($router);
$this->registerBindings();
}
/**
* Register model bindings.
*
* @return void
*/
protected function registerBindings()
{
$this->app->router->model('component', 'CachetHQ\Cachet\Models\Component');
$this->app->router->model('component_group', 'CachetHQ\Cachet\Models\ComponentGroup');
$this->app->router->model('incident', 'CachetHQ\Cachet\Models\Incident');
$this->app->router->model('incident_template', 'CachetHQ\Cachet\Models\IncidentTemplate');
$this->app->router->model('metric', 'CachetHQ\Cachet\Models\Metric');
$this->app->router->model('metric_point', 'CachetHQ\Cachet\Models\MetricPoint');
$this->app->router->model('setting', 'CachetHQ\Cachet\Models\Setting');
$this->app->router->model('subscriber', 'CachetHQ\Cachet\Models\Subscriber');
$this->app->router->model('subscription', 'CachetHQ\Cachet\Models\Subscription');
$this->app->router->model('user', 'CachetHQ\Cachet\Models\User');
$router->model('component', 'CachetHQ\Cachet\Models\Component');
$router->model('component_group', 'CachetHQ\Cachet\Models\ComponentGroup');
$router->model('component_tag', 'CachetHQ\Cachet\Models\ComponentTag');
$router->model('incident', 'CachetHQ\Cachet\Models\Incident');
$router->model('incident_template', 'CachetHQ\Cachet\Models\IncidentTemplate');
$router->model('metric', 'CachetHQ\Cachet\Models\Metric');
$router->model('metric_point', 'CachetHQ\Cachet\Models\MetricPoint');
$router->model('setting', 'CachetHQ\Cachet\Models\Setting');
$router->model('subscriber', 'CachetHQ\Cachet\Models\Subscriber');
$router->model('subscription', 'CachetHQ\Cachet\Models\Subscription');
$router->model('tag', 'CachetHQ\Cachet\Models\Tag');
$router->model('user', 'CachetHQ\Cachet\Models\User');
}
/**

View File

@@ -0,0 +1,117 @@
<?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\Controllers\Api;
use CachetHQ\Cachet\Bus\Commands\ComponentTag\AddComponentTagCommand;
use CachetHQ\Cachet\Bus\Commands\ComponentTag\DeleteComponentTagCommand;
use CachetHQ\Cachet\Bus\Exceptions\Tag\TagDoesNotExistOnComponentException;
use CachetHQ\Cachet\Models\Component;
use CachetHQ\Cachet\Models\ComponentTag;
use CachetHQ\Cachet\Models\Tag;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
/**
* This is the component tag controller class.
*
* @author James Brooks <james@alt-three.com>
*/
class ComponentTagController extends AbstractApiController
{
/**
* Get all tags.
*
* @return \Illuminate\Http\JsonResponse
*/
public function getTags()
{
$tags = Tag::query();
$tags->search(Binput::except(['sort', 'order', 'per_page']));
if ($sortBy = Binput::get('sort')) {
$direction = Binput::has('order') && Binput::get('order') == 'desc';
$tags->sort($sortBy, $direction);
}
$tags = $tags->paginate(Binput::get('per_page', 20));
return $this->paginator($tags, Request::instance());
}
/**
* Get a single component tag.
*
* @param \CachetHQ\Cachet\Models\ComponentTag $componentTag
*
* @return \Illuminate\Http\JsonResponse
*/
public function getTag(ComponentTag $componentTag)
{
return $this->item($componentTag);
}
/**
* Create a new component tag.
*
* @return \Illuminate\Http\JsonResponse
*/
public function postTags()
{
$component = Component::find(Binput::get('component_id'));
$tag = Tag::find(Binput::get('tag_id'));
if (!($component && $tag)) {
throw new BadRequestHttpException();
}
try {
$tag = dispatch(new AddComponentTagCommand(
$component,
$tag
));
} catch (QueryException $e) {
throw new BadRequestHttpException();
}
return $this->item($tag);
}
/**
* Delete an existing tag.
*
* @return \Illuminate\Http\JsonResponse
*/
public function deleteTag()
{
$component = Component::find(Binput::get('component_id'));
$tag = Tag::find(Binput::get('tag_id'));
if (!($component && $tag)) {
throw new BadRequestHttpException();
}
try {
dispatch(new DeleteComponentTagCommand(
$component,
$tag
));
} catch (TagDoesNotExistOnComponentException $e) {
throw new BadRequestHttpException();
}
return $this->noContent();
}
}

View File

@@ -11,8 +11,8 @@
namespace CachetHQ\Cachet\Http\Controllers\Api;
use CachetHQ\Cachet\Integrations\Contracts\Releases;
use CachetHQ\Cachet\Integrations\Contracts\System;
use CachetHQ\Cachet\Integrations\Releases;
/**
* This is the general api controller.
@@ -38,7 +38,7 @@ class GeneralController extends AbstractApiController
*/
public function version()
{
$latest = app(Releases::class)->latest();
$latest = app()->make(Releases::class)->latest();
return $this->setMetaData([
'on_latest' => version_compare(CACHET_VERSION, $latest['tag_name']) === 1,
@@ -55,9 +55,6 @@ class GeneralController extends AbstractApiController
{
$system = app()->make(System::class)->getStatus();
return $this->item([
'status' => $system['system_status'],
'message' => $system['system_message'],
]);
return $this->item($system['system_message']);
}
}

View File

@@ -0,0 +1,132 @@
<?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\Controllers\Api;
use CachetHQ\Cachet\Bus\Commands\IncidentUpdate\RemoveIncidentUpdateCommand;
use CachetHQ\Cachet\Bus\Commands\IncidentUpdate\ReportIncidentUpdateCommand;
use CachetHQ\Cachet\Bus\Commands\IncidentUpdate\UpdateIncidentUpdateCommand;
use CachetHQ\Cachet\Models\Incident;
use CachetHQ\Cachet\Models\IncidentUpdate;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
/**
* This is the incident update controller.
*
* @author James Brooks <james@alt-three.com>
*/
class IncidentUpdateController extends AbstractApiController
{
/**
* Return all updates on the incident.
*
* @param \CachetHQ\Cachet\Models\Incident $incident
*
* @return \Illuminate\Http\JsonResponse
*/
public function getIncidentUpdates(Incident $incident)
{
$updates = IncidentUpdate::orderBy('created_at', 'desc');
if ($sortBy = Binput::get('sort')) {
$direction = Binput::has('order') && Binput::get('order') == 'desc';
$updates->sort($sortBy, $direction);
}
$updates = $updates->paginate(Binput::get('per_page', 20));
return $this->paginator($updates, Request::instance());
}
/**
* Return a single incident update.
*
* @param \CachetHQ\Cachet\Models\Incident $incident
* @param \CachetHQ\Cachet\Models\IncidentUpdate $update
*
* @return \Illuminate\Http\JsonResponse
*/
public function getIncidentUpdate(Incident $incident, IncidentUpdate $update)
{
return $this->item($update);
}
/**
* Create a new incident update.
*
* @param \CachetHQ\Cachet\Models\Incident $incident
*
* @return \Illuminate\Http\JsonResponse
*/
public function postIncidentUpdate(Incident $incident)
{
try {
$update = dispatch(new ReportIncidentUpdateCommand(
$incident,
Binput::get('status'),
Binput::get('message'),
Auth::user()
));
} catch (QueryException $e) {
throw new BadRequestHttpException();
}
return $this->item($update);
}
/**
* Update an incident update.
*
* @param \CachetHQ\Cachet\Models\Incident $incident
* @param \CachetHQ\Cachet\Models\IncidentUpdate $update
*
* @return \Illuminate\Http\JsonResponse
*/
public function putIncidentUpdate(Incident $incident, IncidentUpdate $update)
{
try {
$update = dispatch(new UpdateIncidentUpdateCommand(
$update,
Binput::get('status'),
Binput::get('message'),
Auth::user()
));
} catch (QueryException $e) {
throw new BadRequestHttpException();
}
return $this->item($update);
}
/**
* Create a new incident update.
*
* @param \CachetHQ\Cachet\Models\Incident $incident
* @param \CachetHQ\Cachet\Models\IncidentUpdate $update
*
* @return \Illuminate\Http\JsonResponse
*/
public function deleteIncidentUpdate(Incident $incident, IncidentUpdate $update)
{
try {
dispatch(new RemoveIncidentUpdateCommand($update));
} catch (QueryException $e) {
throw new BadRequestHttpException();
}
return $this->noContent();
}
}

View File

@@ -17,6 +17,7 @@ use CachetHQ\Cachet\Bus\Commands\Subscriber\UnsubscribeSubscriptionCommand;
use CachetHQ\Cachet\Models\Subscriber;
use CachetHQ\Cachet\Models\Subscription;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Contracts\Config\Repository;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
@@ -48,12 +49,10 @@ class SubscriberController extends AbstractApiController
*/
public function postSubscribers()
{
$verified = Binput::get('verify', app(Repository::class)->get('setting.skip_subscriber_verification'));
try {
$subscriber = dispatch(new SubscribeSubscriberCommand(
Binput::get('email'),
Binput::get('verify', false),
Binput::get('components', null)
));
$subscriber = dispatch(new SubscribeSubscriberCommand(Binput::get('email'), $verified, Binput::get('components')));
} catch (QueryException $e) {
throw new BadRequestHttpException();
}

View File

@@ -0,0 +1,113 @@
<?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\Controllers\Api;
use CachetHQ\Cachet\Bus\Commands\Tag\CreateTagCommand;
use CachetHQ\Cachet\Bus\Commands\Tag\DeleteTagCommand;
use CachetHQ\Cachet\Bus\Commands\Tag\UpdateTagCommand;
use CachetHQ\Cachet\Models\Tag;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
class TagController extends AbstractApiController
{
/**
* Get all tags.
*
* @return \Illuminate\Http\JsonResponse
*/
public function getTags()
{
$tags = Tag::query();
$tags->search(Binput::except(['sort', 'order', 'per_page']));
if ($sortBy = Binput::get('sort')) {
$direction = Binput::has('order') && Binput::get('order') == 'desc';
$tags->sort($sortBy, $direction);
}
$tags = $tags->paginate(Binput::get('per_page', 20));
return $this->paginator($tags, Request::instance());
}
/**
* Get a single tag.
*
* @param \CachetHQ\Cachet\Models\Tag $tag
*
* @return \Illuminate\Http\JsonResponse
*/
public function getTag(Tag $tag)
{
return $this->item($tag);
}
/**
* Create a new tag.
*
* @return \Illuminate\Http\JsonResponse
*/
public function postTags()
{
try {
$tag = dispatch(new CreateTagCommand(
Binput::get('name'),
Binput::get('slug')
));
} catch (QueryException $e) {
throw new BadRequestHttpException();
}
return $this->item($tag);
}
/**
* Update an existing tag.
*
* @param \CachetHQ\Cachet\Models\Tag $tag
*
* @return \Illuminate\Http\JsonResponse
*/
public function putTag(Tag $tag)
{
try {
$tag = dispatch(new UpdateTagCommand(
$tag,
Binput::get('name'),
Binput::get('slug')
));
} catch (QueryException $e) {
throw new BadRequestHttpException();
}
return $this->item($tag);
}
/**
* Delete an existing tag.
*
* @param \CachetHQ\Cachet\Models\Tag $tag
*
* @return \Illuminate\Http\JsonResponse
*/
public function deleteTag(Tag $tag)
{
dispatch(new DeleteTagCommand($tag));
return $this->noContent();
}
}

View File

@@ -0,0 +1,87 @@
<?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\Controllers\Api;
use CachetHQ\Cachet\Bus\Commands\User\AddTeamMemberCommand;
use CachetHQ\Cachet\Bus\Commands\User\RemoveUserCommand;
use CachetHQ\Cachet\Bus\Commands\User\UpdateTeamMemberCommand;
use CachetHQ\Cachet\Models\User;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Database\QueryException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
/**
* This is the user controller class.
*
* @author James Brooks <james@alt-three.com>
*/
class UserController extends AbstractApiController
{
/**
* Create a new user.
*
* @return \Illuminate\Http\JsonResponse
*/
public function postUsers()
{
try {
$user = dispatch(new AddTeamMemberCommand(
Binput::get('username'),
Binput::get('password'),
Binput::get('email'),
Binput::get('level', User::LEVEL_USER)
));
} catch (QueryException $e) {
throw new BadRequestHttpException();
}
return $this->item($user);
}
/**
* Update an existing user.
*
* @param \CachetHQ\Cachet\Models\User $user
*
* @return \Illuminate\Http\JsonResponse
*/
public function putUser(User $user)
{
try {
dispatch(new UpdateTeamMemberCommand(
$user,
Binput::get('username'),
Binput::get('password'),
Binput::get('email'),
Binput::get('level')
));
} catch (QueryException $e) {
throw new BadRequestHttpException();
}
return $this->item($user);
}
/**
* Delete a user from the system.
*
* @param \CachetHQ\Cachet\Models\User $user
*
* @return \Illuminate\Http\JsonResponse
*/
public function deleteUser(User $user)
{
dispatch(new RemoveUserCommand($user));
return $this->noContent();
}
}

View File

@@ -11,7 +11,7 @@
namespace CachetHQ\Cachet\Http\Controllers\Dashboard;
use CachetHQ\Cachet\Integrations\Feed;
use CachetHQ\Cachet\Integrations\Contracts\Feed;
use CachetHQ\Cachet\Models\Component;
use CachetHQ\Cachet\Models\ComponentGroup;
use CachetHQ\Cachet\Models\Incident;

View File

@@ -15,15 +15,22 @@ use AltThree\Validator\ValidationException;
use CachetHQ\Cachet\Bus\Commands\Incident\RemoveIncidentCommand;
use CachetHQ\Cachet\Bus\Commands\Incident\ReportIncidentCommand;
use CachetHQ\Cachet\Bus\Commands\Incident\UpdateIncidentCommand;
use CachetHQ\Cachet\Bus\Commands\IncidentUpdate\ReportIncidentUpdateCommand;
use CachetHQ\Cachet\Models\Component;
use CachetHQ\Cachet\Models\ComponentGroup;
use CachetHQ\Cachet\Models\Incident;
use CachetHQ\Cachet\Models\IncidentTemplate;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\View;
/**
* This is the incident controller.
*
* @author James Brooks <james@alt-three.com>
*/
class IncidentController extends Controller
{
/**
@@ -33,13 +40,24 @@ class IncidentController extends Controller
*/
protected $subMenu = [];
/**
* The guard instance.
*
* @var \Illuminate\Contracts\Auth\Guard
*/
protected $auth;
/**
* Creates a new incident controller instance.
*
* @param \Illuminate\Contracts\Auth\Guard $auth
*
* @return void
*/
public function __construct()
public function __construct(Guard $auth)
{
$this->auth = $auth;
$this->subMenu = [
'incidents' => [
'title' => trans('dashboard.incidents.incidents'),
@@ -279,4 +297,43 @@ class IncidentController extends Controller
return Redirect::route('dashboard.templates.edit', ['id' => $template->id])
->withUpdatedTemplate($template);
}
/**
* Shows the incident update form.
*
* @param \CachetHQ\Cachet\Models\Incident $incident
*
* @return \Illuminate\View\View
*/
public function showIncidentUpdateAction(Incident $incident)
{
return View::make('dashboard.incidents.update')->withIncident($incident);
}
/**
* Creates a new incident update.
*
* @param \CachetHQ\Cachet\Models\Incident $incident
*
* @return \Illuminate\Http\RedirectResponse
*/
public function createIncidentUpdateAction(Incident $incident)
{
try {
$incident = dispatch(new ReportIncidentUpdateCommand(
$incident,
Binput::get('status'),
Binput::get('message'),
$this->auth->user()
));
} catch (ValidationException $e) {
return Redirect::route('dashboard.incidents.update', ['id' => $incident->id])
->withInput(Binput::all())
->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('dashboard.incidents.templates.edit.failure')))
->withErrors($e->getMessageBag());
}
return Redirect::route('dashboard.incidents.index')
->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.incidents.delete.success')));
}
}

View File

@@ -11,7 +11,7 @@
namespace CachetHQ\Cachet\Http\Controllers\Dashboard;
use CachetHQ\Cachet\Integrations\Credits;
use CachetHQ\Cachet\Integrations\Contracts\Credits;
use CachetHQ\Cachet\Models\User;
use CachetHQ\Cachet\Settings\Repository;
use Exception;

View File

@@ -16,6 +16,7 @@ use CachetHQ\Cachet\Bus\Commands\Subscriber\SubscribeSubscriberCommand;
use CachetHQ\Cachet\Bus\Commands\Subscriber\UnsubscribeSubscriberCommand;
use CachetHQ\Cachet\Models\Subscriber;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Contracts\Config\Repository;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\View;
@@ -52,11 +53,13 @@ class SubscriberController extends Controller
*/
public function createSubscriberAction()
{
$verified = app(Repository::class)->get('setting.skip_subscriber_verification');
try {
$subscribers = preg_split("/\r\n|\n|\r/", Binput::get('email'));
foreach ($subscribers as $subscriber) {
dispatch(new SubscribeSubscriberCommand($subscriber));
dispatch(new SubscribeSubscriberCommand($subscriber, $verified));
}
} catch (ValidationException $e) {
return Redirect::route('dashboard.subscribers.add')

View File

@@ -12,8 +12,8 @@
namespace CachetHQ\Cachet\Http\Controllers\Dashboard;
use AltThree\Validator\ValidationException;
use CachetHQ\Cachet\Bus\Commands\User\AddTeamMemberCommand;
use CachetHQ\Cachet\Bus\Commands\User\InviteTeamMemberCommand;
use CachetHQ\Cachet\Bus\Commands\User\AddUserCommand;
use CachetHQ\Cachet\Bus\Commands\User\InviteUserCommand;
use CachetHQ\Cachet\Bus\Commands\User\RemoveUserCommand;
use CachetHQ\Cachet\Models\User;
use GrahamCampbell\Binput\Facades\Binput;
@@ -81,7 +81,7 @@ class TeamController extends Controller
public function postAddUser()
{
try {
dispatch(new AddTeamMemberCommand(
dispatch(new AddUserCommand(
Binput::get('username'),
Binput::get('password'),
Binput::get('email'),
@@ -130,7 +130,7 @@ class TeamController extends Controller
public function postInviteUser()
{
try {
dispatch(new InviteTeamMemberCommand(
dispatch(new InviteUserCommand(
array_unique(array_filter((array) Binput::get('emails')))
));
} catch (ValidationException $e) {

View File

@@ -48,11 +48,11 @@ class SetupController extends Controller
* @var string[]
*/
protected $mailDrivers = [
'smtp' => 'SMTP',
'mail' => 'Mail',
'sendmail' => 'Sendmail',
'mailgun' => 'Mailgun',
'mandrill' => 'Mandrill',
'smtp' => 'SMTP',
'mail' => 'Mail',
'sendmail' => 'Sendmail',
'mailgun' => 'Mailgun',
'mandrill' => 'Mandrill',
// 'ses' => 'Amazon SES', this will be available only if aws/aws-sdk-php is installed
'sparkpost' => 'SparkPost',
'log' => 'Log (Testing)',

View File

@@ -85,7 +85,7 @@ class StatusPageController extends AbstractApiController
$allIncidents = Incident::notScheduled()->where('visible', '>=', $incidentVisibility)->whereBetween('created_at', [
$startDate->copy()->subDays($daysToShow)->format('Y-m-d').' 00:00:00',
$startDate->format('Y-m-d').' 23:59:59',
])->orderBy('scheduled_at', 'desc')->orderBy('created_at', 'desc')->get()->groupBy(function (Incident $incident) {
])->orderBy('scheduled_at', 'desc')->orderBy('created_at', 'desc')->get()->load('updates')->groupBy(function (Incident $incident) {
return app(DateFactory::class)->make($incident->is_scheduled ? $incident->scheduled_at : $incident->created_at)->toDateString();
});

View File

@@ -18,10 +18,12 @@ use CachetHQ\Cachet\Bus\Commands\Subscriber\UnsubscribeSubscriptionCommand;
use CachetHQ\Cachet\Bus\Commands\Subscriber\UpdateSubscriberSubscriptionCommand;
use CachetHQ\Cachet\Bus\Commands\Subscriber\VerifySubscriberCommand;
use CachetHQ\Cachet\Models\Component;
use CachetHQ\Cachet\Models\ComponentGroup;
use CachetHQ\Cachet\Models\Subscriber;
use CachetHQ\Cachet\Models\Subscription;
use GrahamCampbell\Binput\Facades\Binput;
use GrahamCampbell\Markdown\Facades\Markdown;
use Illuminate\Contracts\Config\Repository;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Redirect;
@@ -56,10 +58,9 @@ class SubscribeController extends Controller
{
$email = Binput::get('email');
$subscriptions = Binput::get('subscriptions');
$verified = app(Repository::class)->get('setting.skip_subscriber_verification');
try {
$verified = false;
$subscription = dispatch(new SubscribeSubscriberCommand($email, $verified));
} catch (ValidationException $e) {
return Redirect::route('status-page')
@@ -147,15 +148,19 @@ class SubscribeController extends Controller
}
$subscriber = Subscriber::where('verify_code', '=', $code)->first();
$usedComponentGroups = Component::enabled()->where('group_id', '>', 0)->groupBy('group_id')->pluck('group_id');
$componentGroups = ComponentGroup::whereIn('id', $usedComponentGroups)->orderBy('order')->get();
$ungroupedComponents = Component::enabled()->where('group_id', 0)->orderBy('order')->orderBy('created_at')->get();
if (!$subscriber) {
throw new BadRequestHttpException();
}
return View::make('subscribe.manage')
->withComponents(Component::all())
->withUngroupedComponents($ungroupedComponents)
->withSubscriber($subscriber)
->withSubscriptions($subscriber->subscriptions->pluck('component_id')->all());
->withSubscriptions($subscriber->subscriptions->pluck('component_id')->all())
->withComponentGroups($componentGroups);
}
/**
@@ -180,6 +185,8 @@ class SubscribeController extends Controller
try {
dispatch(new UpdateSubscriberSubscriptionCommand($subscriber, Binput::get('subscriptions')));
} catch (ValidationException $e) {
dd($e->getMessageBag());
return Redirect::route('subscribe.manage', $subscriber->verify_code)
->withInput(Binput::all())
->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('cachet.subscriber.email.failure')))

View File

@@ -37,11 +37,13 @@ class Kernel extends HttpKernel
'Illuminate\Session\Middleware\StartSession',
'Illuminate\View\Middleware\ShareErrorsFromSession',
'Illuminate\Foundation\Http\Middleware\VerifyCsrfToken',
'Illuminate\Routing\Middleware\SubstituteBindings',
],
'api' => [
'Barryvdh\Cors\HandleCors',
'CachetHQ\Cachet\Http\Middleware\Acceptable',
'CachetHQ\Cachet\Http\Middleware\Timezone',
'Illuminate\Routing\Middleware\SubstituteBindings',
],
];

View File

@@ -38,14 +38,22 @@ class ApiRoutes
$router->get('components', 'ComponentController@getComponents');
$router->get('components/groups', 'ComponentGroupController@getGroups');
$router->get('components/groups/{component_group}', 'ComponentGroupController@getGroup');
$router->get('components/tags', 'ComponentTagController@getTags');
$router->get('components/tags/{component_tag}', 'ComponentTagController@getTag');
$router->get('components/{component}', 'ComponentController@getComponent');
$router->get('incidents', 'IncidentController@getIncidents');
$router->get('incidents/{incident}', 'IncidentController@getIncident');
$router->get('incidents/{incident}/updates', 'IncidentUpdateController@getIncidentUpdates');
$router->get('incidents/{incident}/updates/{update}', 'IncidentUpdateController@getIncidentUpdate');
$router->get('metrics', 'MetricController@getMetrics');
$router->get('metrics/{metric}', 'MetricController@getMetric');
$router->get('metrics/{metric}/points', 'MetricController@getMetricPoints');
$router->get('tags', 'TagController@getTags');
$router->get('tags/{tag}', 'TagController@getTag');
});
$router->group(['middleware' => ['auth.api:true']], function (Registrar $router) {
@@ -53,24 +61,35 @@ class ApiRoutes
$router->post('components', 'ComponentController@postComponents');
$router->post('components/groups', 'ComponentGroupController@postGroups');
$router->post('components/tags', 'ComponentTagController@postTags');
$router->post('incidents', 'IncidentController@postIncidents');
$router->post('incidents/{incident}/updates', 'IncidentUpdateController@postIncidentUpdate');
$router->post('metrics', 'MetricController@postMetrics');
$router->post('metrics/{metric}/points', 'MetricPointController@postMetricPoints');
$router->post('subscribers', 'SubscriberController@postSubscribers');
$router->post('tags', 'TagController@postTags');
$router->post('users', 'UserController@postUsers');
$router->put('components/groups/{component_group}', 'ComponentGroupController@putGroup');
$router->put('components/{component}', 'ComponentController@putComponent');
$router->put('incidents/{incident}', 'IncidentController@putIncident');
$router->put('incidents/{incident}/updates/{update}', 'IncidentUpdateController@putIncidentUpdate');
$router->put('metrics/{metric}', 'MetricController@putMetric');
$router->put('metrics/{metric}/points/{metric_point}', 'MetricPointController@putMetricPoint');
$router->put('tags/{tag}', 'TagController@putTag');
$router->put('users/{user}', 'UserController@putUser');
$router->delete('components/groups/{component_group}', 'ComponentGroupController@deleteGroup');
$router->delete('components/tags', 'ComponentTagController@deleteTag');
$router->delete('components/{component}', 'ComponentController@deleteComponent');
$router->delete('incidents/{incident}', 'IncidentController@deleteIncident');
$router->delete('incidents/{incident}/updates/{update}', 'IncidentUpdateController@deleteIncidentUpdate');
$router->delete('metrics/{metric}', 'MetricController@deleteMetric');
$router->delete('metrics/{metric}/points/{metric_point}', 'MetricPointController@deleteMetricPoint');
$router->delete('subscribers/{subscriber}', 'SubscriberController@deleteSubscriber');
$router->delete('subscriptions/{subscription}', 'SubscriberController@deleteSubscription');
$router->delete('tags/{tag}', 'TagController@deleteTag');
$router->delete('users/{user}', 'UserController@deleteUser');
});
});
}

View File

@@ -89,7 +89,12 @@ class DashboardRoutes
'as' => 'edit',
'uses' => 'IncidentController@showEditIncidentAction',
]);
$router->get('{incident}/update', [
'as' => 'update',
'uses' => 'IncidentController@showIncidentUpdateAction',
]);
$router->post('{incident}/edit', 'IncidentController@editIncidentAction');
$router->post('{incident}/update', 'IncidentController@createIncidentUpdateAction');
});
$router->group(['as' => 'schedule.', 'prefix' => 'schedule'], function (Registrar $router) {
@@ -131,7 +136,7 @@ class DashboardRoutes
$router->delete('{incident_template}/delete', 'IncidentController@deleteTemplateAction');
});
$router->group(['as' => 'subscribers.', 'prefix' => 'subscribers'], function (Registrar $router) {
$router->group(['as' => 'subscribers.', 'prefix' => 'subscribers'], function (Registrar $router) {
$router->get('/', [
'as' => 'index',
'uses' => 'SubscriberController@showSubscribers',
@@ -144,7 +149,7 @@ class DashboardRoutes
$router->delete('{subscriber}/delete', 'SubscriberController@deleteSubscriberAction');
});
$router->group(['as' => 'metrics.', 'prefix' => 'metrics'], function (Registrar $router) {
$router->group(['as' => 'metrics.', 'prefix' => 'metrics'], function (Registrar $router) {
$router->get('/', [
'as' => 'index',
'uses' => 'MetricController@showMetrics',

View File

@@ -0,0 +1,27 @@
<?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 credits interface.
*
* @author James Brooks <james@alt-three.com>
*/
interface Credits
{
/**
* Returns the latest credits.
*
* @return array|null
*/
public function latest();
}

View File

@@ -0,0 +1,27 @@
<?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 feed interface.
*
* @author James Brooks <james@alt-three.com>
*/
interface Feed
{
/**
* Returns the latest entries.
*
* @return array|null
*/
public function latest();
}

View File

@@ -0,0 +1,27 @@
<?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 releases interface.
*
* @author James Brooks <james@alt-three.com>
*/
interface Releases
{
/**
* Returns the latest release.
*
* @return string
*/
public function latest();
}

View File

@@ -9,13 +9,14 @@
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Integrations;
namespace CachetHQ\Cachet\Integrations\Core;
use CachetHQ\Cachet\Integrations\Contracts\Credits as CreditsContract;
use Exception;
use GuzzleHttp\Client;
use Illuminate\Contracts\Cache\Repository;
class Credits
class Credits implements CreditsContract
{
/**
* The default url.

View File

@@ -9,8 +9,9 @@
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Integrations;
namespace CachetHQ\Cachet\Integrations\Core;
use CachetHQ\Cachet\Integrations\Contracts\Feed as FeedContract;
use Exception;
use GuzzleHttp\Client;
use Illuminate\Contracts\Cache\Repository;
@@ -20,7 +21,7 @@ use Illuminate\Contracts\Cache\Repository;
*
* @author James Brooks <james@alt-three.com>
*/
class Feed
class Feed implements FeedContract
{
/**
* The default url.

View File

@@ -53,8 +53,11 @@ class System implements SystemContract
return $incident->status > 0;
});
$incidentCount = $incidents->count();
$unresolvedCount = $incidents->filter(function ($incident) {
return !$incident->is_resolved;
})->count();
if ($incidentCount === 0 || ($incidentCount >= 1 && (int) $incidents->first()->status === 4)) {
if ($incidentCount === 0 || ($incidentCount >= 1 && $unresolvedCount === 0)) {
$status = [
'system_status' => 'success',
'system_message' => trans_choice('cachet.service.good', $totalComponents),

View File

@@ -9,12 +9,13 @@
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Integrations;
namespace CachetHQ\Cachet\Integrations\GitHub;
use CachetHQ\Cachet\Integrations\Contracts\Releases as ReleasesContract;
use GuzzleHttp\Client;
use Illuminate\Contracts\Cache\Repository;
class Releases
class Releases implements ReleasesContract
{
/**
* The default url.

View File

@@ -129,11 +129,11 @@ class Component extends Model implements HasPresenter
/**
* Components can have many tags.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
* @return \Illuminate\Database\Eloquent\Relations\HasManyThrough
*/
public function tags()
{
return $this->belongsToMany(Tag::class);
return $this->hasManyThrough(Tag::class, ComponentTag::class, 'tag_id', 'id');
}
/**

View File

@@ -0,0 +1,74 @@
<?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\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
/**
* This is the component tag class.
*
* @author James Brooks <james@alt-three.com>
*/
class ComponentTag extends Model
{
/**
* The attributes that should be casted to native types.
*
* @var string[]
*/
protected $casts = [
'component_id' => 'int',
'tag_id' => 'int',
];
/**
* The fillable properties.
*
* @var string[]
*/
protected $fillable = ['component_id', 'tag_id'];
/**
* Get the component relation.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function component()
{
return $this->belongsTo(Component::class, 'component_id', 'id');
}
/**
* Get the tag relation.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function tag()
{
return $this->belongsTo(Tag::class, 'tag_id', 'id');
}
/**
* Find a given tag for a component.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param int $tagId
* @param int $componentId
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeTagForComponent(Builder $query, $tagId, $componentId)
{
return $query->where('component_id', $componentId)->where('tag_id', $tagId);
}
}

View File

@@ -25,6 +25,43 @@ class Incident extends Model implements HasPresenter
{
use SearchableTrait, SoftDeletes, SortableTrait, ValidatingTrait;
/**
* Status for incident being investigated.
*
* @var int
*/
const INVESTIGATING = 1;
/**
* Status for incident having been identified.
*
* @var int
*/
const IDENTIFIED = 2;
/**
* Status for incident being watched.
*
* @var int
*/
const WATCHED = 3;
/**
* Status for incident now being fixed.
*
* @var int
*/
const FIXED = 4;
/**
* The accessors to append to the model's array form.
*
* @var string[]
*/
protected $appends = [
'is_resolved',
];
/**
* The attributes that should be casted to native types.
*
@@ -91,6 +128,13 @@ class Incident extends Model implements HasPresenter
'message',
];
/**
* The relations to eager load on every query.
*
* @var string[]
*/
protected $with = ['updates'];
/**
* Finds all visible incidents.
*
@@ -131,6 +175,16 @@ class Incident extends Model implements HasPresenter
});
}
/**
* Get the updates relation.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function updates()
{
return $this->hasMany(IncidentUpdate::class)->orderBy('created_at', 'desc');
}
/**
* An incident belongs to a component.
*
@@ -141,6 +195,20 @@ class Incident extends Model implements HasPresenter
return $this->belongsTo(Component::class, 'component_id', 'id');
}
/**
* Is the incident resolved?
*
* @return bool
*/
public function getIsResolvedAttribute()
{
if ($updates = $this->updates->first()) {
return $updates->status === self::FIXED;
}
return $this->status === self::FIXED;
}
/**
* Returns whether the "incident" is scheduled or not.
*

View File

@@ -12,6 +12,7 @@
namespace CachetHQ\Cachet\Models;
use AltThree\Validator\ValidatingTrait;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
@@ -66,7 +67,7 @@ class IncidentTemplate extends Model
*
* @return \Illuminate\Database\Query\Builder
*/
public function scopeForSlug($query, $slug)
public function scopeForSlug(Builder $query, $slug)
{
return $query->where('slug', $slug);
}

View File

@@ -0,0 +1,90 @@
<?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\Models;
use AltThree\Validator\ValidatingTrait;
use CachetHQ\Cachet\Models\Traits\SortableTrait;
use CachetHQ\Cachet\Presenters\IncidentUpdatePresenter;
use Illuminate\Database\Eloquent\Model;
use McCool\LaravelAutoPresenter\HasPresenter;
class IncidentUpdate extends Model implements HasPresenter
{
use SortableTrait, ValidatingTrait;
/**
* The attributes that should be casted to native types.
*
* @var string[]
*/
protected $casts = [
'incident_id' => 'int',
'status' => 'int',
'message' => 'string',
'user_id' => 'int',
];
/**
* The fillable properties.
*
* @var string[]
*/
protected $fillable = [
'incident_id',
'status',
'message',
'user_id',
];
/**
* The validation rules.
*
* @var string[]
*/
public $rules = [
'incident_id' => 'int',
'status' => 'required|int',
'message' => 'required|string',
'user_id' => 'required|int',
];
/**
* The sortable fields.
*
* @var string[]
*/
protected $sortable = [
'id',
'status',
'user_id',
];
/**
* Get the incident relation.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function incident()
{
return $this->belongsTo(Incident::class);
}
/**
* Get the presenter class.
*
* @return string
*/
public function getPresenterClass()
{
return IncidentUpdatePresenter::class;
}
}

View File

@@ -11,11 +11,15 @@
namespace CachetHQ\Cachet\Models;
use CachetHQ\Cachet\Models\Traits\SearchableTrait;
use CachetHQ\Cachet\Models\Traits\SortableTrait;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
class Tag extends Model
{
use SearchableTrait, SortableTrait;
/**
* The attributes that should be casted to native types.
*
@@ -32,6 +36,28 @@ class Tag extends Model
*/
protected $fillable = ['name'];
/**
* The searchable fields.
*
* @var string[]
*/
protected $searchable = [
'id',
'name',
'slug',
];
/**
* The sortable fields.
*
* @var string[]
*/
protected $sortable = [
'id',
'name',
'slug',
];
/**
* Overrides the models boot method.
*/

View File

@@ -97,4 +97,27 @@ class ComponentGroupPresenter extends BasePresenter implements Arrayable
'lowest_human_status' => $this->lowest_human_status(),
]);
}
/**
* Determine if any of the contained components have active subscriptions.
*
* @return bool
*/
public function has_subscriber($subscriptions)
{
$enabled_components = $this->wrappedObject->enabled_components()->orderBy('order')->pluck('id')->toArray();
$intersected = array_intersect($enabled_components, $subscriptions);
return count($intersected) != 0;
}
/**
* Determine the class for collapsed/uncollapsed groups on the subscription form.
*
* @return string
*/
public function collapse_class_with_subscriptions($subscriptions)
{
return $this->has_subscriber($subscriptions) ? 'ion-ios-minus-outline' : 'ion-ios-plus-outline';
}
}

View File

@@ -22,6 +22,19 @@ class IncidentPresenter extends BasePresenter implements Arrayable
{
use TimestampsTrait;
/**
* Inciden icon lookup.
*
* @var array
*/
protected $icons = [
0 => 'icon ion-android-calendar', // Scheduled
1 => 'icon ion-flag oranges', // Investigating
2 => 'icon ion-alert yellows', // Identified
3 => 'icon ion-eye blues', // Watching
4 => 'icon ion-checkmark greens', // Fixed
];
/**
* Renders the message from Markdown into HTML.
*
@@ -32,6 +45,16 @@ class IncidentPresenter extends BasePresenter implements Arrayable
return Markdown::convertToHtml($this->wrappedObject->message);
}
/**
* Return the raw text of the message, even without Markdown.
*
* @return string
*/
public function raw_message()
{
return strip_tags($this->formattedMessage());
}
/**
* Present diff for humans date time.
*
@@ -157,19 +180,8 @@ class IncidentPresenter extends BasePresenter implements Arrayable
*/
public function icon()
{
switch ($this->wrappedObject->status) {
case 0: // Scheduled
return 'icon ion-android-calendar';
case 1: // Investigating
return 'icon ion-flag oranges';
case 2: // Identified
return 'icon ion-alert yellows';
case 3: // Watching
return 'icon ion-eye blues';
case 4: // Fixed
return 'icon ion-checkmark greens';
default: // Something actually broke, this shouldn't happen.
return '';
if (isset($this->icons[$this->wrappedObject->status])) {
return $this->icons[$this->wrappedObject->status];
}
}
@@ -183,6 +195,72 @@ class IncidentPresenter extends BasePresenter implements Arrayable
return trans('cachet.incidents.status.'.$this->wrappedObject->status);
}
/**
* Returns the latest update.
*
* @return int|null
*/
public function latest_status()
{
if ($update = $this->latest()) {
return $update->status;
}
return $this->wrappedObject->status;
}
/**
* Returns the latest update.
*
* @return string|null
*/
public function latest_human_status()
{
if ($update = $this->latest()) {
return trans('cachet.incidents.status.'.$update->status);
}
return $this->human_status();
}
/**
* Present the latest icon.
*
* @return string
*/
public function latest_icon()
{
if ($update = $this->latest()) {
if (isset($this->icons[$update->status])) {
return $this->icons[$update->status];
}
}
return $this->icon();
}
/**
* Fetch the latest incident update.
*
* @return \CachetHQ\Cachet\Models\IncidentUpdate|null
*/
public function latest()
{
if ($update = $this->wrappedObject->updates()->orderBy('created_at', 'desc')->first()) {
return $update;
}
}
/**
* Get the incident permalink.
*
* @return string
*/
public function permalink()
{
return route('incident', $this->wrappedObject->id);
}
/**
* Convert the presenter instance to an array.
*
@@ -191,10 +269,15 @@ class IncidentPresenter extends BasePresenter implements Arrayable
public function toArray()
{
return array_merge($this->wrappedObject->toArray(), [
'human_status' => $this->human_status(),
'scheduled_at' => $this->scheduled_at(),
'created_at' => $this->created_at(),
'updated_at' => $this->updated_at(),
'human_status' => $this->human_status(),
'latest_update_id' => $this->latest() ? $this->latest()->id : null,
'latest_status' => $this->latest_status(),
'latest_human_status' => $this->latest_human_status(),
'latest_icon' => $this->latest_icon(),
'permalink' => $this->permalink(),
'scheduled_at' => $this->scheduled_at(),
'created_at' => $this->created_at(),
'updated_at' => $this->updated_at(),
]);
}
}

View File

@@ -0,0 +1,162 @@
<?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 CachetHQ\Cachet\Dates\DateFactory;
use CachetHQ\Cachet\Presenters\Traits\TimestampsTrait;
use GrahamCampbell\Markdown\Facades\Markdown;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Support\Facades\Config;
use McCool\LaravelAutoPresenter\BasePresenter;
/**
* This is the incident update presenter.
*
* @author James Brooks <james@alt-three.com>
*/
class IncidentUpdatePresenter extends BasePresenter implements Arrayable
{
use TimestampsTrait;
/**
* Renders the message from Markdown into HTML.
*
* @return string
*/
public function formattedMessage()
{
return Markdown::convertToHtml($this->wrappedObject->message);
}
/**
* Return the raw text of the message, even without Markdown.
*
* @return string
*/
public function raw_message()
{
return strip_tags($this->formattedMessage());
}
/**
* Present diff for humans date time.
*
* @return string
*/
public function created_at_diff()
{
return app(DateFactory::class)->make($this->wrappedObject->created_at)->diffForHumans();
}
/**
* Present formatted date time.
*
* @return string
*/
public function created_at_formatted()
{
return ucfirst(app(DateFactory::class)->make($this->wrappedObject->created_at)->format(Config::get('setting.incident_date_format', 'l jS F Y H:i:s')));
}
/**
* Formats the created_at time ready to be used by bootstrap-datetimepicker.
*
* @return string
*/
public function created_at_datetimepicker()
{
return app(DateFactory::class)->make($this->wrappedObject->created_at)->format('d/m/Y H:i');
}
/**
* Present formatted date time.
*
* @return string
*/
public function created_at_iso()
{
return app(DateFactory::class)->make($this->wrappedObject->created_at)->toISO8601String();
}
/**
* Returns a formatted timestamp for use within the timeline.
*
* @return string
*/
public function timestamp_formatted()
{
if ($this->wrappedObject->is_scheduled) {
return $this->scheduled_at_formatted;
}
return $this->created_at_formatted;
}
/**
* Return the iso timestamp for use within the timeline.
*
* @return string
*/
public function timestamp_iso()
{
if ($this->wrappedObject->is_scheduled) {
return $this->scheduled_at_iso;
}
return $this->created_at_iso;
}
/**
* Present the status with an icon.
*
* @return string
*/
public function icon()
{
switch ($this->wrappedObject->status) {
case 1: // Investigating
return 'icon ion-flag oranges';
case 2: // Identified
return 'icon ion-alert yellows';
case 3: // Watching
return 'icon ion-eye blues';
case 4: // Fixed
return 'icon ion-checkmark greens';
default: // Something actually broke, this shouldn't happen.
return '';
}
}
/**
* Returns a human readable version of the status.
*
* @return string
*/
public function human_status()
{
return trans('cachet.incidents.status.'.$this->wrappedObject->status);
}
/**
* Convert the presenter instance to an array.
*
* @return string[]
*/
public function toArray()
{
return array_merge($this->wrappedObject->toArray(), [
'human_status' => $this->human_status(),
'created_at' => $this->created_at(),
'updated_at' => $this->updated_at(),
]);
}
}

View File

@@ -83,13 +83,6 @@ class CommandSubscriber
$command->line('Settings cache cleared!');
// SQLite does not backup.
if ($this->config->get('database.default') === 'sqlite') {
$command->line('Backup skipped: SQLite is not supported.');
return;
}
$command->line('Backing up database...');
try {

View File

@@ -14,6 +14,7 @@ use Illuminate\Support\Facades\Request;
use Jenssegers\Date\Date;
if (!function_exists('set_active')) {
/**
* Set active class if request is in path.
*

View File

@@ -26,7 +26,7 @@ $app->singleton('Illuminate\Contracts\Http\Kernel', 'CachetHQ\Cachet\Http\Kernel
$app->singleton('Illuminate\Contracts\Console\Kernel', 'CachetHQ\Cachet\Console\Kernel');
$app->singleton('Illuminate\Contracts\Debug\ExceptionHandler', 'GrahamCampbell\Exceptions\ExceptionHandler');
$app->singleton('Illuminate\Contracts\Debug\ExceptionHandler', 'GrahamCampbell\Exceptions\NewExceptionHandler');
/*
|--------------------------------------------------------------------------

View File

@@ -19,17 +19,16 @@
}
],
"require": {
"php": ">=5.5.9",
"ext-xml": "*",
"laravel/framework": "5.2.39",
"php": ">=5.6.4",
"laravel/framework": "~5.3.0",
"alt-three/badger": "^3.1",
"alt-three/bus": "^1.1",
"alt-three/emoji": "^3.1",
"alt-three/throttle": "^1.0",
"alt-three/validator": "^1.5",
"aws/aws-sdk-php": "^3.7",
"backup-manager/laravel": "dev-master#df53f9c9d8c6be5d7a2638f45d54b8fb7bc51e2b",
"barryvdh/laravel-cors": "^0.8",
"backup-manager/laravel": "^1.1",
"barryvdh/laravel-cors": "^0.8.1",
"doctrine/dbal": "^2.5",
"fedeisas/laravel-mail-css-inliner": "^1.5",
"fideloper/proxy": "^3.1",
@@ -41,7 +40,7 @@
"jenssegers/date": "^3.2",
"mccool/laravel-auto-presenter": "^4.3",
"pragmarx/google2fa": "^0.7.1",
"rcrowe/twigbridge": "^0.9.2",
"rcrowe/twigbridge": "^0.10",
"roumen/feed": "^2.10.4"
},
"require-dev": {
@@ -49,10 +48,10 @@
"filp/whoops": "^2.1",
"fzaninotto/faker": "^1.6",
"graham-campbell/testbench-core": "^1.1",
"mockery/mockery": "0.9.9",
"phpunit/phpunit": "4.8.21",
"symfony/css-selector": "^3.0",
"symfony/dom-crawler": "^3.0"
"mockery/mockery": "0.9.5",
"phpunit/phpunit": "^5.2",
"symfony/css-selector": "^3.1",
"symfony/dom-crawler": "^3.1"
},
"autoload": {
"classmap": [
@@ -93,13 +92,13 @@
},
"config": {
"platform": {
"php": "5.5.9"
"php": "5.6.4"
},
"preferred-install": "dist"
},
"extra": {
"branch-alias": {
"dev-master": "2.3-dev"
"dev-develop": "3.0-dev"
}
},
"minimum-stability": "dev",

1299
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -208,6 +208,7 @@ return [
'Artisan' => 'Illuminate\Support\Facades\Artisan',
'Auth' => 'Illuminate\Support\Facades\Auth',
'Blade' => 'Illuminate\Support\Facades\Blade',
'Broadcast' => 'Illuminate\Support\Facades\Broadcast',
'Cache' => 'Illuminate\Support\Facades\Cache',
'Config' => 'Illuminate\Support\Facades\Config',
'Cookie' => 'Illuminate\Support\Facades\Cookie',
@@ -234,8 +235,8 @@ return [
'Validator' => 'Illuminate\Support\Facades\Validator',
'View' => 'Illuminate\Support\Facades\View',
'Binput' => 'GrahamCampbell\Binput\Facades\Binput',
'Str' => 'Illuminate\Support\Str',
'Binput' => 'GrahamCampbell\Binput\Facades\Binput',
'Str' => 'Illuminate\Support\Str',
],

View File

@@ -57,7 +57,15 @@ return [
],
'memcached' => [
'driver' => 'memcached',
'driver' => 'memcached',
'persistent_id' => env('MEMCACHED_PERSISTENT_ID'),
'sasl' => [
env('MEMCACHED_USERNAME'),
env('MEMCACHED_PASSWORD'),
],
'options' => [
// Memcached::OPT_CONNECT_TIMEOUT => 2000,
],
'servers' => [
[
'host' => '127.0.0.1',

View File

@@ -71,30 +71,31 @@ return [
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => env('DB_PREFIX', null),
'strict' => false,
'strict' => true,
'engine' => null,
],
'pgsql' => [
'driver' => 'pgsql',
'host' => env('DB_HOST', null),
'database' => env('DB_DATABASE', null),
'username' => env('DB_USERNAME', null),
'password' => env('DB_PASSWORD', null),
'port' => env('DB_PORT', '5432'),
'charset' => 'utf8',
'prefix' => env('DB_PREFIX', null),
'schema' => env('DB_SCHEMA', 'public'),
'driver' => 'pgsql',
'host' => env('DB_HOST', null),
'database' => env('DB_DATABASE', null),
'username' => env('DB_USERNAME', null),
'password' => env('DB_PASSWORD', null),
'port' => env('DB_PORT', '5432'),
'charset' => 'utf8',
'prefix' => env('DB_PREFIX', null),
'schema' => env('DB_SCHEMA', 'public'),
'sslmode' => 'prefer',
],
'sqlsrv' => [
'driver' => 'sqlsrv',
'host' => env('DB_HOST', null),
'database' => env('DB_DATABASE', null),
'username' => env('DB_USERNAME', null),
'password' => env('DB_PASSWORD', null),
'port' => env('DB_PORT', null),
'prefix' => env('DB_PREFIX', null),
'driver' => 'sqlsrv',
'host' => env('DB_HOST', null),
'database' => env('DB_DATABASE', null),
'username' => env('DB_USERNAME', null),
'password' => env('DB_PASSWORD', null),
'port' => env('DB_PORT', null),
'prefix' => env('DB_PREFIX', null),
],
],

View File

@@ -11,35 +11,35 @@
return [
// Enabled langs
'af' => [
'af' => [
'name' => 'Afrikaans',
'subset' => 'latin',
],
'ar' => [
'ar' => [
'name' => 'Arabic',
'subset' => 'latin',
],
'ca' => [
'ca' => [
'name' => 'Catalan',
'subset' => 'latin',
],
'cs' => [
'cs' => [
'name' => 'Czech',
'subset' => 'latin,latin-ext',
],
'da' => [
'da' => [
'name' => 'Danish',
'subset' => 'latin,latin-ext',
],
'de' => [
'de' => [
'name' => 'Deutsch',
'subset' => 'latin,latin-ext',
],
'el' => [
'el' => [
'name' => 'Greek',
'subset' => 'greek,greek-ext',
],
'en' => [
'en' => [
'name' => 'English',
'subset' => 'latin',
],
@@ -47,55 +47,55 @@ return [
'name' => 'CrowdIn - InContext Localization',
'subset' => 'latin',
],
'es' => [
'es' => [
'name' => 'Español',
'subset' => 'latin,latin-ext',
],
'fa' => [
'fa' => [
'name' => 'Persian',
'subset' => 'latin',
],
'fi' => [
'fi' => [
'name' => 'Finnish',
'subset' => 'latin,latin-ext',
],
'fr' => [
'fr' => [
'name' => 'Français',
'subset' => 'latin,latin-ext',
],
'he' => [
'he' => [
'name' => 'Hebrew',
'subset' => 'latin',
],
'hu' => [
'hu' => [
'name' => 'Hungarian',
'subset' => 'latin,latin-ext',
],
'id' => [
'id' => [
'name' => 'Indonesian',
'subset' => 'latin',
],
'it' => [
'it' => [
'name' => 'Italiano',
'subset' => 'latin,latin-ext',
],
'ja' => [
'ja' => [
'name' => 'Japanese',
'subset' => 'latin',
],
'ko' => [
'ko' => [
'name' => '한글',
'subset' => 'latin',
],
'nl' => [
'nl' => [
'name' => 'Nederlands',
'subset' => 'latin,latin-ext',
],
'no' => [
'no' => [
'name' => 'Norwegian',
'subset' => 'latin,latin-ext',
],
'pl' => [
'pl' => [
'name' => 'Polski',
'subset' => 'latin,latin-ext',
],
@@ -107,19 +107,19 @@ return [
'name' => 'Portuguese, Portugal',
'subset' => 'latin,latin-ext',
],
'ro' => [
'ro' => [
'name' => 'Romanian',
'subset' => 'latin,latin-ext',
],
'ru' => [
'ru' => [
'name' => 'Русский',
'subset' => 'latin,cyrillic',
],
'sq' => [
'sq' => [
'name' => 'Albanian',
'subset' => 'latin,latin-ext',
],
'sr' => [
'sr' => [
'name' => 'Sebrian (Cyrillic)',
'subset' => 'latin,cyrillic,cyrillic-ext',
],
@@ -127,15 +127,15 @@ return [
'name' => 'Swedish',
'subset' => 'latin,latin-ext',
],
'tr' => [
'tr' => [
'name' => 'Turkish',
'subset' => 'latin,latin-ext',
],
'uk' => [
'uk' => [
'name' => 'Ukranian',
'subset' => 'latin,cyrillic-ext',
],
'vi' => [
'vi' => [
'name' => 'Vietnamese',
'subset' => 'latin,vietnamese',
],

View File

@@ -94,6 +94,19 @@ return [
'table' => 'sessions',
/*
|--------------------------------------------------------------------------
| Session Cache Store
|--------------------------------------------------------------------------
|
| When using the "apc" or "memcached" session drivers, you may specify a
| cache store that should be used for these sessions. This value must
| correspond with one of the application's configured cache stores.
|
*/
'store' => null,
/*
|--------------------------------------------------------------------------
| Session Sweeping Lottery

View File

@@ -56,4 +56,36 @@ return [
'show_support' => true,
/*
|--------------------------------------------------------------------------
| Enable External Dependencies
|--------------------------------------------------------------------------
|
| Whether to disable third-party dependencies.
|
*/
'enable_external_dependencies' => true,
/*
|--------------------------------------------------------------------------
| Show the timezone
|--------------------------------------------------------------------------
|
| Whether to show the status page timezone in the footer.
|
*/
'show_timezone' => false,
/*
|--------------------------------------------------------------------------
| Skip subscriber verifications
|--------------------------------------------------------------------------
|
| Whether to allow skipping of subscriber verifications.
|
*/
'skip_subscriber_verification' => false,
];

View File

@@ -11,14 +11,18 @@
use CachetHQ\Cachet\Models\Component;
use CachetHQ\Cachet\Models\ComponentGroup;
use CachetHQ\Cachet\Models\ComponentTag;
use CachetHQ\Cachet\Models\Incident;
use CachetHQ\Cachet\Models\IncidentTemplate;
use CachetHQ\Cachet\Models\IncidentUpdate;
use CachetHQ\Cachet\Models\Metric;
use CachetHQ\Cachet\Models\MetricPoint;
use CachetHQ\Cachet\Models\Subscriber;
use CachetHQ\Cachet\Models\Subscription;
use CachetHQ\Cachet\Models\Tag;
use CachetHQ\Cachet\Models\User;
use Carbon\Carbon;
use Illuminate\Support\Str;
$factory->define(Component::class, function ($faker) {
return [
@@ -38,6 +42,13 @@ $factory->define(ComponentGroup::class, function ($faker) {
];
});
$factory->define(ComponentTag::class, function ($faker) {
return [
'component_id' => factory(Component::class)->create()->id,
'tag_id' => factory(Tag::class)->create()->id,
];
});
$factory->define(Incident::class, function ($faker) {
return [
'name' => $faker->sentence(),
@@ -55,6 +66,15 @@ $factory->define(IncidentTemplate::class, function ($faker) {
];
});
$factory->define(IncidentUpdate::class, function ($faker) {
return [
'incident_id' => factory(Incident::class)->create()->id,
'message' => $faker->paragraph(),
'status' => random_int(1, 4),
'user_id' => factory(User::class)->create()->id,
];
});
$factory->define(Metric::class, function ($faker) {
return [
'name' => $faker->sentence(),
@@ -91,6 +111,15 @@ $factory->define(Subscription::class, function ($faker) {
];
});
$factory->define(Tag::class, function ($faker) {
$name = $faker->sentence();
return [
'name' => $name,
'slug' => Str::slug($name),
];
});
$factory->define(User::class, function ($faker) {
return [
'username' => $faker->userName,

View File

@@ -0,0 +1,46 @@
<?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.
*/
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateIncidentUpdatesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('incident_updates', function (Blueprint $table) {
$table->increments('id');
$table->integer('incident_id')->unsigned();
$table->integer('status');
$table->longText('message');
$table->integer('user_id')->unsigned();
$table->timestamps();
$table->index('incident_id');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('incident_updates');
}
}

View File

@@ -0,0 +1,36 @@
<?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.
*/
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\Schema;
class RenameComponentTagTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::rename('component_tag', 'component_tags');
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::rename('component_tags', 'component_tag');
}
}

View File

@@ -0,0 +1,41 @@
<?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.
*/
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AlterTableComponentTagsAddTimestamps extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('component_tags', function (Blueprint $table) {
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('component_tags', function (Blueprint $table) {
$table->dropTimestamps();
});
}
}

View File

@@ -1,8 +1,5 @@
var elixir = require('laravel-elixir');
elixir.config.production = true;
elixir.config.sourcemaps = false;
elixir(function (mix) {
mix
.sass('app.scss', 'public/dist/css/app.css')

View File

@@ -27,6 +27,7 @@
</filter>
<php>
<env name="APP_ENV" value="testing"/>
<env name="APP_DEBUG" value="true"/>
<env name="APP_URL" value="http://localhost"/>
<env name="APP_KEY" value="GCvcgDKMRIN498g52zfVEd9CxDs6PR7q"/>
<env name="DB_DRIVER" value="sqlite"/>

View File

@@ -277,6 +277,24 @@ $(function() {
$this.next('.group-items').toggleClass('hide');
});
$('.select-group').on('click', function () {
var $parentGroup = $(this).closest('ul.list-group');
$parentGroup.find('input[type=checkbox]').prop('checked', true);
$parentGroup.find('.group-items').removeClass('hide')
$parentGroup.find('.group-toggle').addClass('ion-ios-minus-outline').removeClass('ion-ios-plus-outline');
event.stopPropagation();
return false;
});
$('.deselect-group').on('click', function () {
var $parentGroup = $(this).closest('ul.list-group');
$parentGroup.find('input[type=checkbox]').prop('checked', false);
$parentGroup.find('.group-items').addClass('hide');
$parentGroup.find('.group-toggle').removeClass('ion-ios-minus-outline').addClass('ion-ios-plus-outline');
event.stopPropagation();
return false;
});
// Setup wizard
$('.wizard-next').on('click', function () {
var $form = $('#setup-form'),

View File

@@ -276,6 +276,14 @@ body.status-page {
line-height: 1.3em;
}
i.icon {
font-size: 21px;
line-height: 24px;
text-align: center;
display: inline-block;
min-width: 20px;
}
&.group-name {
background-color: $cachet_gray_light;
padding: {

Some files were not shown because too many files have changed in this diff Show More