Compare commits

..

63 Commits
1.2 ... 0.1

Author SHA1 Message Date
James Brooks
7c57ed65fa Don't use url helper 2015-04-18 16:51:18 +01:00
James Brooks
e0fd2db5ea Fixes #583, use 24H in PgSQL 2015-04-15 18:57:32 +01:00
James Brooks
7e1d0ebc75 Fixes #584, change the metrics display to include current hour values. 2015-04-15 18:56:29 +01:00
James Brooks
7f0a77ffa1 Fixes #585 - Multiple metrics under PgSql/SQLite would fail 2015-04-15 18:53:20 +01:00
James Brooks
a3f696e5b3 Fix CS 2015-04-15 09:10:42 +01:00
James Brooks
fe0cc779b9 Merge pull request #581 from silverxp/master
Added Dutch translation
2015-04-15 08:41:21 +01:00
Thom
02a240a172 Fixed indentation 2015-04-15 09:17:10 +02:00
Thom Spooren
47d0d4e007 Added Dutch translation 2015-04-12 22:29:21 +02:00
James Brooks
3e6a9fc77f Fix CS error 2015-04-11 19:15:41 +01:00
James Brooks
94d92aa6dc Do not use Lato anymore. Closes #578. 2015-04-11 19:14:02 +01:00
James Brooks
a35ea250da Fix poor metrics calculations. Closes #577 2015-04-11 19:10:42 +01:00
James Brooks
a1346deda9 Fix CS issues caused by new fixer settings. 2015-04-11 18:52:22 +01:00
James Brooks
07db5defb7 Merge pull request #580 from ApfelUser/patch-1
Fix typo
2015-04-11 18:49:31 +01:00
ApfelUser
f26d4c41c5 Fix typo
https://crowdin.com/translate/cachet/9/en-de#435
2015-04-10 13:57:01 +02:00
James Brooks
a88eadf79f Merge pull request #575 from bimlendu/sensu-handler
adding sensu handler info in README
2015-04-07 20:47:47 +01:00
Bimlendu Mishra
78eb149fc6 adding sensu handler info in README 2015-04-07 22:31:51 +05:30
James Brooks
dfa602f1f5 Merge pull request #570 from applelam/master
zh-Hant and zh-Hans Translation
2015-04-05 20:33:33 +01:00
James Brooks
352090d90f Closes #571 2015-04-05 20:31:40 +01:00
Apple Lam
bffb244506 zh-Hant and zh-Hans Translation
Translation for Chinese (Traditional) and Chinese (Simplified)
2015-04-06 02:48:26 +08:00
James Brooks
108a1fa0dd Make the RSS feed more valid. Still #547 2015-04-03 18:00:57 +01:00
James Brooks
647fb5a4d5 Update dependencies. 2015-04-03 17:53:15 +01:00
James Brooks
8dec726bc4 Closes #550 - Component Group feeds now work. 2015-04-03 17:52:18 +01:00
James Brooks
9f920634db Merge pull request #558 from urtho/master
Polish (PL-pl) translation
2015-03-31 16:07:33 +01:00
Paweł Pierścionek
2934f9be67 PL Translation 2015-03-31 15:01:34 +00:00
James Brooks
6756c037c9 Fix #544 2015-03-31 08:48:49 +01:00
James Brooks
83e979cc25 Order Atom & RSS feed by reversed creation date 2015-03-26 12:21:16 +00:00
James Brooks
438964c1dd Merge pull request #549 from cachethq/component-groups-feed
Feeds can now accept a component group id to filter. Closes #548
2015-03-26 09:00:38 +00:00
James Brooks
9a8e9a47c4 Merge pull request #545 from anarcat/fr
add maintenance translations
2015-03-26 09:00:22 +00:00
James Brooks
5e05b859ae Feeds can now accept a component group id to filter. Closes #548 2015-03-26 08:58:18 +00:00
James Brooks
4becca76f3 Make the Atom feed a little better. Part of #547 2015-03-26 08:46:17 +00:00
James Brooks
46578f9407 Update the RSS feed to be compliant. Part of #547 2015-03-26 08:44:04 +00:00
Antoine Beaupré
0a30a07c43 add maintenance translations 2015-03-25 16:26:06 -04:00
James Brooks
3e9b560640 Added property annotation 2015-03-25 12:10:22 +00:00
James Brooks
ca263d8b50 Don't display the template itself. Closes #541 2015-03-25 12:07:08 +00:00
James Brooks
6986ee95d3 List components within groups. Closes #542 2015-03-25 12:06:33 +00:00
James Brooks
fd429a6ea7 Merge pull request #539 from anarcat/patch-2
'composante' is feminine in french, also adjust other fr trans
2015-03-24 14:18:56 +00:00
Antoine Beaupré
59f69f6d99 'composante' is feminine in french, also adjust other fr trans
'Il s'est passé quelquechose...' doesn't actually mean anything...
2015-03-24 10:17:01 -04:00
James Brooks
f5756ff4bf Commit changes to ComponentGroup for no longer soft deleting 2015-03-24 13:10:13 +00:00
James Brooks
5e907ba04f Component groups are now properly removed. Closes #535 2015-03-24 08:52:28 +00:00
James Brooks
d12748a49d Merge pull request #537 from anarcat/patch-2
add more fr translation
2015-03-23 23:03:22 +00:00
anarcat
eeaa4cbc91 add more fr translation
this especially gets rid of the english word "Cool" but also translates a few more items
2015-03-23 16:38:25 -04:00
James Brooks
2f8db16161 Merge pull request #536 from anarcat/patch-1
more precise french translation for "watching"
2015-03-23 20:26:29 +00:00
anarcat
96d90aff65 more precise french translation for "watching"
`Analyse en cours` means `Under analysis`, which is basically the same as status `1` (`Investigating`), so a little misleading. I chose `Sous surveillance` (litterally `Under surveillance`) because it is more explicit. `Surveillé` (litterally `surveilled`) seemed a bit weird.
2015-03-23 13:57:17 -04:00
James Brooks
1b60d00bba Merge pull request #531 from matejkramny/feature/readme-addons
Add Addons section
2015-03-22 14:43:08 +00:00
Matej Kramny
b0049611af Add Addons section 2015-03-22 12:46:55 +00:00
James Brooks
95bbb955aa Fix #528 - Status value for scheduled statuses. 2015-03-21 11:19:19 +00:00
James Brooks
ad414a11e0 Fallback for $queryTypes 2015-03-21 07:28:15 +00:00
James Brooks
f76e9bab06 Better condition for showing the break item 2015-03-20 22:42:29 +00:00
James Brooks
9aa5972040 Only display the break item if we have ungrouped-components 2015-03-20 22:41:43 +00:00
James Brooks
11b1125cf8 Show components within groups on the status page. Closes #393. 2015-03-20 12:03:18 +00:00
James Brooks
2467d24702 Metric descriptions are no longer required, so make the form know that. 2015-03-20 11:39:50 +00:00
James Brooks
a62860fda3 Use the more appropriate collection method 2015-03-20 11:35:54 +00:00
James Brooks
c91344f79c CS changes 2015-03-20 11:23:17 +00:00
James Brooks
a4819099eb Track setups (pass and fails) 2015-03-20 11:20:55 +00:00
James Brooks
99d599e1c7 Split the new list up a little 2015-03-20 11:03:31 +00:00
James Brooks
77d1a45538 List users who have not enabled two-factor authentication. 2015-03-20 11:03:12 +00:00
James Brooks
b5ca990ae5 Fix responsive positioning of action buttons. 2015-03-20 10:53:16 +00:00
James Brooks
9d6ef75597 Reset the group_id for components if a group is deleted. 2015-03-20 10:49:58 +00:00
James Brooks
5299d9ea16 Show the number of components a group has in it. 2015-03-20 10:48:42 +00:00
James Brooks
d6a55a6540 Fix relationship of ComponentGroup and Components. 2015-03-20 10:48:03 +00:00
James Brooks
38a4fb710f Show the group a component is in, on the dashboard component index. 2015-03-20 10:45:44 +00:00
James Brooks
6496f8c928 Make sure we have a segment write key before we try tracking 2015-03-20 10:34:53 +00:00
James Brooks
c20f1ac785 Don't throw errors if we have no connection. 2015-03-20 10:32:07 +00:00
497 changed files with 9318 additions and 14654 deletions

View File

@@ -1,4 +1,4 @@
{
"directory": "vendor/bower_components",
"directory": "app/assets/bower_components",
"interactive": false
}

1
.dockerignore Normal file
View File

@@ -0,0 +1 @@
.git

View File

@@ -1,26 +0,0 @@
APP_ENV=production
APP_DEBUG=false
APP_URL=http://localhost
APP_KEY=SomeRandomString
DB_DRIVER=mysql
DB_HOST=localhost
DB_DATABASE=cachet
DB_USERNAME=homestead
DB_PASSWORD=secret
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=database
MAIL_DRIVER=smtp
MAIL_HOST=mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ADDRESS=null
MAIL_NAME=null
REDIS_HOST=null
REDIS_DATABASE=null
REDIS_PORT=null

11
.env.example.php Normal file
View File

@@ -0,0 +1,11 @@
<?php
return [
'APP_DEBUG' => getenv('APP_DEBUG') ?: false,
'DB_DRIVER' => 'mysql',
'DB_HOST' => 'localhost',
'DB_DATABASE' => 'cachet',
'DB_USERNAME' => 'homestead',
'DB_PASSWORD' => 'secret',
'CACHE_DRIVER' => 'apc',
];

14
.env.heroku.php Normal file
View File

@@ -0,0 +1,14 @@
<?php
$dbURL = parse_url(getenv('DATABASE_URL'));
$dbName = substr($dbURL["path"], 1);
return [
'APP_DEBUG' => getenv('APP_DEBUG') ?: false,
'DB_HOST' => $dbURL['host'],
'DB_DATABASE' => $dbName,
'DB_USERNAME' => $dbURL['user'],
'DB_PASSWORD' => $dbURL['pass'],
'DB_DRIVER' => 'pgsql',
'CACHE_DRIVER' => 'apc',
];

10
.gitattributes vendored
View File

@@ -1,3 +1,9 @@
* text=auto
*.css linguist-vendored
*.less linguist-vendored
/tests export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
/phpunit.xml export-ignore
/CONTRIBUTING.md export-ignore
/INSTALL.md export-ignore
/README.md export-ignore

26
.gitignore vendored
View File

@@ -1,4 +1,24 @@
.env
node_modules
phpunit.xml
# Laravel
bootstrap/compiled.php
vendor
# Configuration
.env.*.php
.env.php
config.codekit
!.env.heroku.php
!.env.example.php
# Assets
app/assets/bower_components
node_modules
public/dist
public/css
public/js
# Packages
npm-debug.log
.vagrant
# PHPUnit
phpunit.xml

View File

@@ -1,15 +1,22 @@
language: php
php:
- 5.5.9
- 5.4
- 5.5
- 5.6
- nightly
- hhvm
matrix:
allow_failures:
- php: nightly
sudo: false
install: travis_retry composer install --no-interaction --ignore-platform-reqs --no-scripts --prefer-source
before_script: php artisan cachet:one-click-deploy
script:
- bash -c 'if [ "$TRAVIS_PHP_VERSION" == "hhvm" ]; then vendor/bin/phpunit; fi;'
- bash -c 'if [ "$TRAVIS_PHP_VERSION" != "hhvm" ]; then vendor/bin/phpunit --coverage-clover build/logs/clover.xml; fi;'

View File

@@ -2,15 +2,16 @@
## Creating issues
Feature requests and bug reports should be made by using the [issue tracker](https://github.com/cachethq/Cachet/issues). Support questions should be directed to our support email; [support@alt-three.com](mailto:support@alt-three.com?subject=Cachet Support).
Issues should be made by using the [issue tracker](https://github.com/cachethq/Cachet/issues).
**Always be respectful.** Organization members reserve the right to lock topics if they feel necessary.
Things to remember:
- Be descriptive
- Be respectful of others
## Languages
When needing to add labels, placeholders or general text, you **must not** write directly into the source file, rather make use of the `./resources/lang/` directory.
Always provide the English translation and copy your English string to all other languages - making sure that the indentation and alignment of the arrays are updated.
When needing to add labels, placeholders or general text, you **must not** write directly into the source file, rather make use of the `./app/lang/` directory. Always provide the English translation and copy your English string to all other languages - making sure that the indentation and alignment of the arrays are updated.
## Coding Standards
@@ -19,9 +20,9 @@ Please follow existing coding standards:
```php
<?php
namespace CachetHQ\Cachet\Controller;
namespace Foo\Bar\Controller;
use CachetHQ\Cachet\Bar;
use Foo\Bar\Bar;
class Foo extends Bar
{
@@ -49,13 +50,14 @@ class Foo extends Bar
}
```
- Braces on a new line following: `namespace`, `use`, `function` and `class`.
- Line lengths have a soft 80 limit and hard 120 length.
- PHP constants should be in lowercase; `true`, `false` and `null`.
- Defined constants should always be in uppercase.
- Never leave trailing spaces at the end of a line.
- Files should end with one blank line.
- Do not use `# Bash` style comments.
- Always add or update Docblocs to functions.
- We use [StyleCI](https://styleci.io) to automatically check code standards in Pull Requests. If your PR fails the CI check, then apply the supplied patch and re-push.
- If your pull request consists of more than two commits, you **must** squash them into one.
If you're still unsure, then take a look at existing code.
@@ -73,6 +75,8 @@ If you're not particularly fond of the command line, you can get one of GitHub's
If you're feeling adventurous, you can become a Git & GitHub master with the [Git Path on Code School](https://www.codeschool.com/paths/git).
## .editorconfig
There is always the Cachet Gitter chat to ask any questions you may have:
[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/cachethq/Cachet?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
You should also make use of the [.editorconfig](/.editorconfig) file found within the root of the repository. It'll make sure that your editor is setup with the same file settings.

42
Dockerfile Normal file
View File

@@ -0,0 +1,42 @@
FROM debian:jessie
ENV DB_DRIVER=mysql \
ENV=production \
DB_DATABASE=cachet \
DB_HOST= \
DB_USERNAME= \
DB_PASSWORD= \
DEBIAN_FRONTEND=noninteractive
COPY . /var/www/html/
WORKDIR /var/www/html/
# Using nodesource and debian jessie packages instead of compiling from scratch
RUN echo "APT::Install-Recommends \"0\";" >> /etc/apt/apt.conf.d/02recommends && \
echo "APT::Install-Suggests \"0\";" >> /etc/apt/apt.conf.d/02recommends && \
apt-get -qq update && \
apt-get -qq install \
ca-certificates nginx php5-fpm=5.* php5-curl php5-readline php5-mcrypt php5-mysql php5-apcu php5-cli \
git sqlite libsqlite3-dev curl supervisor && \
apt-get clean && apt-get autoremove -qq && \
rm -rf /var/lib/apt/lists/* /usr/share/doc /usr/share/man /tmp/* && \
chown -R www-data /var/www/html
# Hardcode the Illuminate key in app/config/app.php. If you want security, feel free
# to override the key in your own container with a 'php artisan key:generate' :)
RUN sed -i "s/'key' => '\w.*/'key' => 'f20d3e5ae02125a94bd60203a4edfbde',/" app/config/app.php && \
grep key app/config/app.php
# copy the various nginx and supervisor conf (to handle both fpm and nginx)
RUN sed -i -e "s/;daemonize\s*=\s*yes/daemonize = no/g" /etc/php5/fpm/php-fpm.conf ;\
echo "daemon off;" >> /etc/nginx/nginx.conf ;\
mv /var/www/html/docker/php-fpm-pool.conf /etc/php5/fpm/pool.d/www.conf ;\
rm -f /etc/nginx/sites-enabled/* && rm -f /etc/nginx/conf.d/* && mv /var/www/html/docker/nginx-site.conf /etc/nginx/conf.d/default.conf
RUN curl -sS https://getcomposer.org/installer | php && php composer.phar install --no-dev -o
COPY docker/supervisord.conf /etc/supervisor/supervisord.conf
EXPOSE 8000
CMD ["/usr/bin/supervisord"]

View File

@@ -1,4 +1,4 @@
Copyright (c) 2015 Alt Three Services Limited.
Copyright (c) 2015 James Brooks and individual contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

1
Procfile Normal file
View File

@@ -0,0 +1 @@
web: vendor/bin/heroku-php-nginx -C nginx.conf public

View File

@@ -1,46 +1,44 @@
# Cachet
# Cachet [![Deploy](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy)
[![StyleCI](https://styleci.io/repos/26730195/shield)](https://styleci.io/repos/26730195/)
[![Build Status](https://img.shields.io/travis/cachethq/Cachet.svg?style=flat-square)](https://travis-ci.org/cachethq/Cachet)
[![Quality Score](https://img.shields.io/scrutinizer/g/cachethq/Cachet.svg?style=flat-square)](https://scrutinizer-ci.com/g/cachethq/Cachet)
[![Software License](https://img.shields.io/badge/license-BSD3-brightgreen.svg?style=flat-square)](LICENSE)
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/cachet/localized.png)](http://translate.cachethq.io/project/cachet)
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE)
[![Gitter](https://img.shields.io/badge/gitter-join%20chat-brightgreen.svg?style=flat-square)](https://gitter.im/cachethq/Cachet?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
![Screenshot](https://cachethq.io/img/main-interface.jpg)
**Currently in development. Things may change or break until a solid release has been announced.**
## Features
- List your services components
- Log incidents
- Apply custom CSS to the status page
- Markdown support for incident messages
- JSON API
- Translated into eleven languages
- Metrics
- Cross-database support: MySQL, PostgreSQL and SQLite
- Subscriber notifications via Email
- Two factor authentication, with Google Authenticator
- List your services components.
- Log incidents.
- Apply a custom stylesheet to the status page.
- Markdown support for incident messages.
- RESTful API.
- Translated into several languages.
- Easy Heroku deployment.
- Metrics.
- Cross-database support: MySQL, PostgreSQL and SQLite.
## Requirements
- PHP 5.5.9+ or newer
- PHP 5.4 or newer
- mcrypt extension
- [Composer](https://getcomposer.org)
### Development Requirements
Theses extra dependencies are required to develop Cachet:
The following extra dependencies are required to develop Cachet.
- Node.js
- Bower
- Gulp
+ Bower
+ Gulp
## Installation, Upgrades and Documentation
## Installation & Documentation
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)
- [Getting started with Vagrant](https://docs.cachethq.io/docs/get-started-with-vagrant)
You can now find our documentation at [https://docs.cachethq.io](https://docs.cachethq.io) or, directly at [http://cachet.readme.io](http://cachet.readme.io) if the first link fails to load. [Cachet Demo](https://demo.cachethq.io)
### Demo Account
@@ -49,7 +47,53 @@ To test out the demo, you may login to the [Dashboard](https://demo.cachethq.io/
- **Username:** test@test.com
- **Password:** test123
The demo is reset every half hour.
The demo is reset every half past the hour.
## What Cachet is not
Here is a list of things that Cachet is not or does not do:
1. It does not monitor your services. It works only as a way to display the status of your services. *However, Cachet is able to receive updates from third-party services via its API.*
2. It does not work on a plugin system. There are no monitoring services to extend.
3. It's not a Twitter clone.
## Quickstart with Docker
Run a DB container (you can either pass in environment variables for the DB, or mount a config with `-v /my/database.php:/var/www/html/app/config/database.php`):
```bash
$ export DB_USERNAME=cachet
$ export DB_PASSWORD=cachet
$ export DB_ROOT_PASSWORD=cachet
$ export DB_DATABASE=cachet
$ docker run --name mysql -e MYSQL_USER=$DB_USERNAME -e MYSQL_PASSWORD=$DB_PASSWORD -e MYSQL_ROOT_PASSWORD=$DB_ROOT_PASSWORD -e MYSQL_DATABASE=$DB_DATABASE -d mysql
```
Initialize the DB if you haven't yet:
```bash
$ docker run --link mysql:mysql -e DB_HOST=mysql -e DB_DATABASE=$DB_DATABASE -e DB_USERNAME=$DB_USERNAME -e DB_PASSWORD=$DB_PASSWORD cachethq/cachet:latest php artisan migrate --force
```
Run Cachet:
```bash
$ docker run -d --name cachet --link mysql:mysql -p 80:8000 -e DB_HOST=mysql -e DB_DATABASE=$DB_DATABASE -e DB_USERNAME=$DB_USERNAME -e DB_PASSWORD=$DB_PASSWORD cachethq/cachet:latest
```
Now go to `http://<ipdockerisboundto>/setup` and have fun!
Note: When running in production you should ensure that you enable SSL.
This is commonly achieved by running Nginx with your certificates on your Docker host, service or load balancers in-front of the running container, or by adding your custom SSL certificates and configuration to the supplied Nginx configuration.
## Addons
- [cachet-monitor](https://github.com/castawaylabs/cachet-monitor) - For url monitoring. Automatic incident updates
- [sensu-cachet](https://github.com/bimlendu/sensu-cachethq) - Sensu handler for updating CachetHQ.
## Read more about Cachet
For more information on why I started developing Cachet, check out my [Cachet articles on my blog](https://james-brooks.uk/tag/cachet/?utm_source=github&utm_medium=readme&utm_campaign=github-cachet).
## Translations

34
app.json Normal file
View File

@@ -0,0 +1,34 @@
{
"name": "Cachet",
"description": "An open source status page system.",
"keywords": [
"cachet",
"laravel",
"status",
"page"
],
"website": "https://cachethq.io",
"logo": "https://raw.githubusercontent.com/cachethq/assets/79336a33c24b28c470a89742671e0e291813d004/images/icon/Cachet-Icon.png",
"success_url": "/setup",
"repository": "https://github.com/cachethq/Cachet",
"addons": [
"heroku-postgresql"
],
"env": {
"ENV": {
"value": "heroku",
"description": "Warning: Do not modify this value on Heroku deployments."
},
"BUILDPACK_URL": {
"value": "https://github.com/heroku/heroku-buildpack-php",
"description": "Warning: Do not modify this value on Heroku deployments."
},
"CACHE_DRIVER": {
"value": "apc",
"description": "Warning: Do not modify this value on Heroku deployments."
}
},
"scripts": {
"postdeploy": "php artisan migrate --env=heroku; php artisan key:generate;"
}
}

View File

@@ -1,36 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Composers;
use CachetHQ\Cachet\Facades\Setting;
use Illuminate\Contracts\View\View;
class AppComposer
{
/**
* Index page view composer.
*
* @param \Illuminate\Contracts\View\View $view
*/
public function compose(View $view)
{
$isEnabled = (bool) Setting::get('enable_subscribers', false);
$mailAddress = env('MAIL_ADDRESS', false);
$mailFrom = env('MAIL_NAME', false);
$withData = [
'subscribersEnabled' => $isEnabled && $mailAddress && $mailFrom,
];
$view->with($withData);
}
}

View File

@@ -1,28 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Composers;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Facades\Auth;
class LoggedUserComposer
{
/**
* Bind data to the view.
*
* @param \Illuminate\Contracts\View\View $view
*/
public function compose(View $view)
{
$view->with('loggedUser', Auth::user());
}
}

View File

@@ -1,37 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Composers;
use CachetHQ\Cachet\Facades\Setting;
use Illuminate\Contracts\View\View;
class ThemeComposer
{
/**
* Bind data to the view.
*
* @param \Illuminate\Contracts\View\View $view
*/
public function compose(View $view)
{
$view->with('themeBackgroundColor', Setting::get('style_background_color'));
$view->with('themeTextColor', Setting::get('style_text_color'));
$viewData = $view->getData();
$themeView = array_only($viewData, preg_grep('/^theme/', array_keys($viewData)));
$hasThemeSettings = array_filter($themeView, function ($data) {
return $data != null;
});
$view->with('themeSetup', !empty($hasThemeSettings));
}
}

View File

@@ -1,37 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
'CachetHQ\Cachet\Console\Commands\FixPermissionsCommand',
];
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
*/
protected function schedule(Schedule $schedule)
{
$schedule->command('queue:work --sleep=3 --tries=3')->everyMinute();
}
}

View File

@@ -1,32 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Events;
use CachetHQ\Cachet\Models\Subscriber;
class CustomerHasSubscribedEvent
{
/**
* The customer who has subscribed.
*
* @var \CachetHQ\Cachet\Models\Subscriber
*/
public $subscriber;
/**
* Create a new customer has subscribed event instance.
*/
public function __construct(Subscriber $subscriber)
{
$this->subscriber = $subscriber;
}
}

View File

@@ -1,32 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Events;
use CachetHQ\Cachet\Models\Incident;
class IncidentHasReportedEvent
{
/**
* The incident that has been reported.
*
* @var \CachetHQ\Cachet\Models\Incident
*/
public $incident;
/**
* Create a new incident has reported event instance.
*/
public function __construct(Incident $incident)
{
$this->incident = $incident;
}
}

View File

@@ -1,32 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Events;
use CachetHQ\Cachet\Models\Incident;
class MaintenanceHasScheduledEvent
{
/**
* The incident that has been reported.
*
* @var \CachetHQ\Cachet\Models\Incident
*/
public $incident;
/**
* Create a new maintenance has scheduled event instance.
*/
public function __construct(Incident $incident)
{
$this->incident = $incident;
}
}

View File

@@ -1,87 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Exceptions\Displayers;
use Exception;
use GrahamCampbell\Exceptions\Displayers\DisplayerInterface;
use Illuminate\Http\Request;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
class RedirectDisplayer implements DisplayerInterface
{
/**
* The request instance.
*
* @var \Illuminate\Http\Request
*/
protected $request;
/**
* Create a new redirect displayer instance.
*
* @param \Illuminate\Http\Request $request
*/
public function __construct(Request $request)
{
$this->request = $request;
}
/**
* Get the error response associated with the given exception.
*
* @param \Exception $exception
* @param string $id
* @param int $code
* @param string[] $headers
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function display(Exception $exception, $id, $code, array $headers)
{
return redirect()->guest('auth/login');
}
/**
* Get the supported content type.
*
* @return string
*/
public function contentType()
{
return 'text/html';
}
/**
* Can we display the exception?
*
* @param \Exception $original
* @param \Exception $transformed
*
* @return bool
*/
public function canDisplay(Exception $original, Exception $transformed)
{
$redirect = $transformed instanceof HttpExceptionInterface && $transformed->getStatusCode() === 401;
return $redirect && !$this->request->is('api*');
}
/**
* Do we provide verbose information about the exception?
*
* @return bool
*/
public function isVerbose()
{
return false;
}
}

View File

@@ -1,57 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Exceptions\Filters;
use Exception;
use Illuminate\Http\Request;
class ApiFilter
{
/**
* The request instance.
*
* @var \Illuminate\Http\Request
*/
protected $request;
/**
* Create a new api filter instance.
*
* @param \Illuminate\Http\Request $request
*/
public function __construct(Request $request)
{
$this->request = $request;
}
/**
* Filter and return the displayers.
*
* @param \GrahamCampbell\Exceptions\Displayers\DisplayerInterface[] $displayers
* @param \Exception $original
* @param \Exception $transformed
*
* @return \GrahamCampbell\Exceptions\Displayers\DisplayerInterface[]
*/
public function filter(array $displayers, Exception $original, Exception $transformed)
{
if ($this->request->is('api*')) {
foreach ($displayers as $index => $displayer) {
if (!str_contains($displayer->contentType(), 'application/')) {
unset($displayers[$index]);
}
}
}
return array_values($displayers);
}
}

View File

@@ -1,27 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Exceptions;
use GrahamCampbell\Exceptions\ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that should not be reported.
*
* @var string[]
*/
protected $dontReport = [
NotFoundHttpException::class,
];
}

View File

@@ -1,41 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Exceptions\Transformers;
use Exception;
use GrahamCampbell\Exceptions\Transformers\TransformerInterface;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* This is the model not found transformer class.
*
* @author Graham Campbell <graham@alt-three.com>
*/
class ModelNotFoundTransformer implements TransformerInterface
{
/**
* Transform the provided exception.
*
* @param \Exception $exception
*
* @return \Exception
*/
public function transform(Exception $exception)
{
if ($exception instanceof ModelNotFoundException) {
$exception = new NotFoundHttpException('Resource not found');
}
return $exception;
}
}

View File

@@ -1,89 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Handlers\Events;
use CachetHQ\Cachet\Events\IncidentHasReportedEvent;
use CachetHQ\Cachet\Models\Subscriber;
use Illuminate\Contracts\Mail\MailQueue;
use Illuminate\Mail\Message;
use McCool\LaravelAutoPresenter\PresenterDecorator;
class SendIncidentEmailNotificationHandler
{
/**
* The mailer instance.
*
* @var \Illuminate\Contracts\Mail\Mailer
*/
protected $mailer;
/**
* The subscriber instance.
*
* @var \CachetHQ\Cachet\Models\Subscriber
*/
protected $subscriber;
/**
* The presenter instance.
*
* @var \McCool\LaravelAutoPresenter\PresenterDecorator
*/
protected $presenter;
/**
* Create a new send incident email notification handler.
*
* @param \Illuminate\Contracts\Mail\Mailer $mailer
* @param \CachetHQ\Cachet\Models\Subscriber $subscriber
* @param \McCool\LaravelAutoPresenter\PresenterDecorator $presenter
*/
public function __construct(MailQueue $mailer, Subscriber $subscriber, PresenterDecorator $presenter)
{
$this->mailer = $mailer;
$this->subscriber = $subscriber;
$this->presenter = $presenter;
}
/**
* Handle the event.
*
* @param \CachetHQ\Cachet\Events\IncidentHasReportedEvent $event
*/
public function handle(IncidentHasReportedEvent $event)
{
$data = $this->presenter->decorate($event->incident);
// Only send emails for public incidents.
if ($event->incident->visible === 1) {
foreach ($this->subscriber->all() as $subscriber) {
$mail = [
'email' => $subscriber->email,
'subject' => 'New incident reported.',
'status' => $data->humanStatus,
'htmlContent' => $data->formattedMessage,
'textContent' => $data->message,
'token' => $subscriber->token,
'unsubscribeLink' => route('unsubscribe', ['code' => $subscriber->verify_code]),
'appUrl' => env('APP_URL'),
];
$this->mailer->queue([
'html' => 'emails.incidents.new-html',
'text' => 'emails.incidents.new-text',
], $mail, function (Message $message) use ($mail) {
$message->to($mail['email'])->subject($mail['subject']);
});
}
}
}
}

View File

@@ -1,86 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Handlers\Events;
use CachetHQ\Cachet\Events\MaintenanceHasScheduledEvent;
use CachetHQ\Cachet\Models\Subscriber;
use Illuminate\Contracts\Mail\MailQueue;
use Illuminate\Mail\Message;
use McCool\LaravelAutoPresenter\PresenterDecorator;
class SendMaintenanceEmailNotificationHandler
{
/**
* The mailer instance.
*
* @var \Illuminate\Contracts\Mail\MailQueue
*/
protected $mailer;
/**
* The subscriber instance.
*
* @var \CachetHQ\Cachet\Models\Subscriber
*/
protected $subscriber;
/**
* The presenter instance.
*
* @var \McCool\LaravelAutoPresenter\PresenterDecorator
*/
protected $presenter;
/**
* Create a new send maintenance email notification handler.
*
* @param \Illuminate\Contracts\Mail\Mailer $mailer
* @param \CachetHQ\Cachet\Models\Subscriber $subscriber
* @param \McCool\LaravelAutoPresenter\PresenterDecorator $presenter
*/
public function __construct(MailQueue $mailer, Subscriber $subscriber, PresenterDecorator $presenter)
{
$this->mailer = $mailer;
$this->subscriber = $subscriber;
$this->presenter = $presenter;
}
/**
* Handle the event.
*
* @param \CachetHQ\Cachet\Events\MaintenanceHasScheduledEvent $event
*/
public function handle(MaintenanceHasScheduledEvent $event)
{
$data = $this->presenter->decorate($event->incident);
foreach ($this->subscriber->all() as $subscriber) {
$mail = [
'email' => $subscriber->email,
'subject' => 'Scheduled maintenance.',
'status' => $data->humanStatus,
'htmlContent' => $data->formattedMessage,
'textContent' => $data->message,
'token' => $subscriber->token,
'unsubscribeLink' => route('unsubscribe', ['code' => $subscriber->verify_code]),
'appUrl' => env('APP_URL'),
];
$this->mailer->queue([
'html' => 'emails.incidents.maintenance-html',
'text' => 'emails.incidents.maintenance-text',
], $mail, function (Message $message) use ($mail) {
$message->to($mail['email'])->subject($mail['subject']);
});
}
}
}

View File

@@ -1,58 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Handlers\Events;
use CachetHQ\Cachet\Events\CustomerHasSubscribedEvent;
use Illuminate\Contracts\Mail\MailQueue;
use Illuminate\Mail\Message;
class SendSubscriberVerificationEmailHandler
{
/**
* The mailer instance.
*
* @var \Illuminate\Contracts\Mail\MailQueue
*/
protected $mailer;
/**
* Create a new send subscriber verification email handler.
*
* @param \Illuminate\Contracts\Mail\Mailer $mailer
*/
public function __construct(MailQueue $mailer)
{
$this->mailer = $mailer;
}
/**
* Handle the event.
*
* @param \CachetHQ\Cachet\Events\CustomerHasSubscribedEvent $event
*/
public function handle(CustomerHasSubscribedEvent $event)
{
$mail = [
'email' => $event->subscriber->email,
'subject' => 'Confirm your subscription.',
'link' => route('subscribe-verify', ['code' => $event->subscriber->verify_code]),
'appUrl' => env('APP_URL'),
];
$this->mailer->queue([
'html' => 'emails.subscribers.verify-html',
'text' => 'emails.subscribers.verify-text',
], $mail, function (Message $message) use ($mail) {
$message->to($mail['email'])->subject($mail['subject']);
});
}
}

View File

@@ -1,21 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
abstract class AbstractController extends BaseController
{
use DispatchesJobs, ValidatesRequests;
}

View File

@@ -1,104 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Controllers\Admin;
use CachetHQ\Cachet\Events\CustomerHasSubscribedEvent;
use CachetHQ\Cachet\Http\Controllers\AbstractController;
use CachetHQ\Cachet\Models\Subscriber;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\View;
class SubscriberController extends AbstractController
{
/**
* Shows the subscribers view.
*
* @return \Illuminate\View\View
*/
public function showSubscribers()
{
$subscribers = Subscriber::all();
return View::make('dashboard.subscribers.index')
->with([
'page_title' => trans('dashboard.subscribers.subscribers').' - '.trans('dashboard.dashboard'),
'subscribers' => $subscribers,
]);
}
/**
* Shows the add subscriber view.
*
* @return \Illuminate\View\View
*/
public function showAddSubscriber()
{
return View::make('dashboard.subscribers.add')
->with([
'page_title' => trans('dashboard.subscribers.add.title').' - '.trans('dashboard.dashboard'),
'incidentTemplates' => Subscriber::all(),
]);
}
/**
* Creates a new subscriber.
*
* @return \Illuminate\Http\RedirectResponse
*/
public function createSubscriberAction()
{
$email = Binput::get('email');
$subscriber = Subscriber::create([
'email' => $email,
]);
if (!$subscriber->isValid()) {
return Redirect::back()
->withInput(Binput::all())
->with('title', sprintf(
'%s %s',
trans('dashboard.notifications.whoops'),
trans('dashboard.subscribers.add.failure')
))
->with('errors', $subscriber->getErrors());
}
$successMsg = sprintf(
'%s %s',
trans('dashboard.notifications.awesome'),
trans('dashboard.subscribers.add.success')
);
event(new CustomerHasSubscribedEvent($subscriber));
return Redirect::back()
->with('success', $successMsg);
}
/**
* Deletes a subscriber.
*
* @param \CachetHQ\Cachet\Models\Subscriber $subscriber
*
* @throws \Exception
*
* @return \Illuminate\Http\RedirectResponse
*/
public function deleteSubscriberAction(Subscriber $subscriber)
{
$subscriber->delete();
return Redirect::back();
}
}

View File

@@ -1,204 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Controllers\Api;
use CachetHQ\Cachet\Http\Controllers\AbstractController as BaseController;
use Illuminate\Contracts\Pagination\Paginator;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Response;
use McCool\LaravelAutoPresenter\Facades\AutoPresenter;
abstract class AbstractApiController extends BaseController
{
/**
* The HTTP response headers.
*
* @var array
*/
protected $headers = [];
/**
* The HTTP response meta data.
*
* @var array
*/
protected $meta = [];
/**
* The HTTP response data.
*
* @var mixed
*/
protected $data = null;
/**
* The HTTP response status code.
*
* @var int
*/
protected $statusCode = 200;
/**
* Set the response headers.
*
* @param array $headers
*
* @return $this
*/
protected function setHeaders(array $headers)
{
$this->headers = $headers;
return $this;
}
/**
* Set the response meta data.
*
* @param array $meta
*
* @return $this
*/
protected function setMetaData(array $meta)
{
$this->meta = $meta;
return $this;
}
/**
* Set the response meta data.
*
* @param array $data
*
* @return $this
*/
protected function setData($data)
{
$this->data = $data;
return $this;
}
/**
* Set the response status code.
*
* @param int $statusCode
*
* @return $this
*/
protected function setStatusCode($statusCode)
{
$this->statusCode = $statusCode;
return $this;
}
/**
* Respond with an item response.
*
* @param mixed
*
* @return \Illuminate\Http\JsonResponse
*/
public function item($item)
{
return $this->setData(AutoPresenter::decorate($item))->respond();
}
/**
* Respond with a collection response.
*
* @param \Illuminate\Support\Collection $collection
*
* @return \Illuminate\Http\JsonResponse
*/
public function collection(Collection $collection)
{
return $this->setData(AutoPresenter::decorate($collection))->respond();
}
/**
* Respond with a pagination response.
*
* @param \Illuminate\Pagination\Paginator $paginator
* @param \Illuminate\Http\Request $request
*
* @return \Illuminate\Http\JsonResponse
*/
protected function paginator(Paginator $paginator, Request $request)
{
foreach ($request->query as $key => $value) {
if ($key != 'page') {
$paginator->addQuery($key, $value);
}
}
$pagination = [
'pagination' => [
'total' => $paginator->total(),
'count' => count($paginator->items()),
'per_page' => $paginator->perPage(),
'current_page' => $paginator->currentPage(),
'total_pages' => $paginator->lastPage(),
'links' => [
'next_page' => $paginator->nextPageUrl(),
'previous_page' => $paginator->previousPageUrl(),
],
],
];
$items = $paginator->getCollection();
if ($sortBy = $request->get('sort')) {
$direction = $request->has('order') && $request->get('order') == 'desc';
$items = $items->sortBy($sortBy, SORT_REGULAR, $direction);
}
return $this->setMetaData($pagination)->setData(AutoPresenter::decorate($items->values()->all()))->respond();
}
/**
* Respond with a no content response.
*
* @param string $message
*
* @return \Illuminate\Http\JsonResponse
*/
protected function noContent()
{
return $this->setStatusCode(204)->respond();
}
/**
* Build the response.
*
* @return \Illuminate\Http\Response
*/
protected function respond()
{
if (!empty($this->meta)) {
$response['meta'] = $this->meta;
}
$response['data'] = $this->data;
if ($this->data instanceof Arrayable) {
$response['data'] = $this->data->toArray();
}
return Response::json($response, $this->statusCode, $this->headers);
}
}

View File

@@ -1,132 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Controllers\Api;
use CachetHQ\Cachet\Models\Component;
use CachetHQ\Cachet\Models\Tag;
use Exception;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
class ComponentController extends AbstractApiController
{
/**
* Get all components.
*
* @param \Symfony\Component\HttpFoundation\Request $request
*
* @return \Illuminate\Database\Eloquent\Collection
*/
public function getComponents(Request $request)
{
$components = Component::paginate(Binput::get('per_page', 20));
return $this->paginator($components, $request);
}
/**
* Get a single component.
*
* @param \CachetHQ\Cachet\Models\Component $component
*
* @return \CachetHQ\Cachet\Models\Component
*/
public function getComponent(Component $component)
{
return $this->item($component);
}
/**
* Create a new component.
*
* @param \Illuminate\Contracts\Auth\Guard $auth
*
* @return \CachetHQ\Cachet\Models\Component
*/
public function postComponents(Guard $auth)
{
$componentData = Binput::except('tags');
try {
$component = Component::create($componentData);
} catch (Exception $e) {
throw new BadRequestHttpException();
}
if (!$component->isValid()) {
throw new BadRequestHttpException();
}
if (Binput::has('tags')) {
// The component was added successfully, so now let's deal with the tags.
$tags = preg_split('/ ?, ?/', Binput::get('tags'));
// For every tag, do we need to create it?
$componentTags = array_map(function ($taggable) use ($component) {
return Tag::firstOrCreate([
'name' => $taggable,
])->id;
}, $tags);
$component->tags()->sync($componentTags);
}
return $this->item($component);
}
/**
* Update an existing component.
*
* @param \CachetHQ\Cachet\Models\Componet $component
*
* @return \CachetHQ\Cachet\Models\Component
*/
public function putComponent(Component $component)
{
$component->update(Binput::except('tags'));
if (!$component->isValid('updating')) {
throw new BadRequestHttpException();
}
if (Binput::has('tags')) {
$tags = preg_split('/ ?, ?/', Binput::get('tags'));
// For every tag, do we need to create it?
$componentTags = array_map(function ($taggable) use ($component) {
return Tag::firstOrCreate([
'name' => $taggable,
])->id;
}, $tags);
$component->tags()->sync($componentTags);
}
return $this->item($component);
}
/**
* Delete an existing component.
*
* @param \CachetHQ\Cachet\Models\Component $component
*
* @return \Illuminate\Http\JsonResponse
*/
public function deleteComponent(Component $component)
{
$component->delete();
return $this->noContent();
}
}

View File

@@ -1,20 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Controllers\Api;
class GeneralController extends AbstractApiController
{
public function ping()
{
return $this->item('Pong!');
}
}

View File

@@ -1,123 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Controllers\Api;
use CachetHQ\Cachet\Events\IncidentHasReportedEvent;
use CachetHQ\Cachet\Facades\Setting;
use CachetHQ\Cachet\Models\Incident;
use Exception;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
class IncidentController extends AbstractApiController
{
/**
* Get all incidents.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* @param \Illuminate\Contracts\Auth\Guard $auth
*
* @return \Illuminate\Database\Eloquent\Collection
*/
public function getIncidents(Request $request, Guard $auth)
{
$incidentVisiblity = $auth->check() ? 0 : 1;
$incidents = Incident::where('visible', '>=', $incidentVisiblity)
->paginate(Binput::get('per_page', 20));
return $this->paginator($incidents, $request);
}
/**
* Get a single incident.
*
* @param \CachetHQ\Cachet\Models\Incident $incident
*
* @return \CachetHQ\Cachet\Models\Incident
*/
public function getIncident(Incident $incident)
{
return $this->item($incident);
}
/**
* Create a new incident.
*
* @param \Illuminate\Contracts\Auth\Guard $auth
*
* @return \CachetHQ\Cachet\Models\Incident
*/
public function postIncidents(Guard $auth)
{
$incidentData = Binput::all();
if (!array_has($incidentData, 'visible')) {
$incidentData['visible'] = 1;
}
try {
$incident = Incident::create($incidentData);
} catch (Exception $e) {
throw new BadRequestHttpException();
}
$isEnabled = (bool) Setting::get('enable_subscribers', false);
$mailAddress = env('MAIL_ADDRESS', false);
$mailFrom = env('MAIL_NAME', false);
$subscribersEnabled = $isEnabled && $mailAddress && $mailFrom;
if (array_get($incidentData, 'notify') && $subscribersEnabled) {
event(new IncidentHasReportedEvent($incident));
}
if ($incident->isValid()) {
return $this->item($incident);
}
throw new BadRequestHttpException();
}
/**
* Update an existing incident.
*
* @param \CachetHQ\Cachet\Models\Inicdent $incident
*
* @return \CachetHQ\Cachet\Models\Incident
*/
public function putIncident(Incident $incident)
{
$incident->update(Binput::all());
if ($incident->isValid('updating')) {
return $this->item($incident);
}
throw new BadRequestHttpException();
}
/**
* Delete an existing incident.
*
* @param \CachetHQ\Cachet\Models\Inicdent $incident
*
* @return \Illuminate\Http\JsonResponse
*/
public function deleteIncident(Incident $incident)
{
$incident->delete();
return $this->noContent();
}
}

View File

@@ -1,111 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Controllers\Api;
use CachetHQ\Cachet\Models\Metric;
use Exception;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Http\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
class MetricController extends AbstractApiController
{
/**
* Get all metrics.
*
* @param \Symfony\Component\HttpFoundation\Request $request
*
* @return \Illuminate\Database\Eloquent\Collection
*/
public function getMetrics(Request $request)
{
$metrics = Metric::paginate(Binput::get('per_page', 20));
return $this->paginator($metrics, $request);
}
/**
* Get a single metric.
*
* @param \CachetHQ\Cachet\Models\Metric $metric
*
* @return \CachetHQ\Cachet\Models\Metric
*/
public function getMetric(Metric $metric)
{
return $this->item($metric);
}
/**
* Get all metric points.
*
* @param \CachetHQ\Cachet\Models\Metric $metric
*
* @return \Illuminate\Database\Eloquent\Collection
*/
public function getMetricPoints(Metric $metric)
{
return $this->collection($metric->points);
}
/**
* Create a new metric.
*
* @return \CachetHQ\Cachet\Models\Metric
*/
public function postMetrics()
{
try {
$metric = Metric::create(Binput::all());
} catch (Exception $e) {
throw new BadRequestHttpException();
}
if ($metric->isValid()) {
return $this->item($metric);
}
throw new BadRequestHttpException();
}
/**
* Update an existing metric.
*
* @param \CachetHQ\Cachet\Models\Metric $metric
*
* @return \CachetHQ\Cachet\Models\Metric
*/
public function putMetric(Metric $metric)
{
$metric->update(Binput::all());
if ($metric->isValid('updating')) {
return $this->item($metric);
}
throw new BadRequestHttpException();
}
/**
* Delete an existing metric.
*
* @param \CachetHQ\Cachet\Models\Metric $metric
*
* @return \Illuminate\Http\JsonResponse
*/
public function deleteMetric(Metric $metric)
{
$metric->delete();
return $this->noContent();
}
}

View File

@@ -1,98 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Controllers\Api;
use CachetHQ\Cachet\Models\Metric;
use CachetHQ\Cachet\Models\MetricPoint;
use Carbon\Carbon;
use Exception;
use GrahamCampbell\Binput\Facades\Binput;
class MetricPointController extends AbstractApiController
{
/**
* Get a single metric point.
*
* @param \CachetHQ\Cachet\Models\Metric $metric
* @param \CachetHQ\Cachet\Models\MetricPoint $metricPoint
*
* @return \CachetHQ\Cachet\Models\MetricPoint
*/
public function getMetricPoints(Metric $metric, MetricPoint $metricPoint)
{
return $this->item($metricPoint);
}
/**
* Create a new metric point.
*
* @param \CachetHQ\Cachet\Models\Metric $metric
*
* @return \CachetHQ\Cachet\Models\MetricPoint
*/
public function postMetricPoints(Metric $metric)
{
$metricPointData = Binput::all();
$metricPointData['metric_id'] = $metric->id;
if ($timestamp = array_pull($metricPointData, 'timestamp')) {
$pointTimestamp = Carbon::createFromFormat('U', $timestamp);
$metricPointData['created_at'] = $pointTimestamp->format('Y-m-d H:i:s');
}
try {
$metricPoint = MetricPoint::create($metricPointData);
} catch (Exception $e) {
throw new BadRequestHttpException();
}
return $this->item($metricPoint);
}
/**
* Updates a metric point.
*
* @param \CachetHQ\Cachet\Models\Metric $metric
* @param \CachetHQ\Cachet\Models\MetircPoint $metricPoint
*
* @return \CachetHQ\Cachet\Models\MetricPoint
*/
public function putMetricPoint(Metric $metric, MetricPoint $metricPoint)
{
$metricPointData = Binput::all();
$metricPointData['metric_id'] = $metric->id;
if ($timestamp = array_pull($metricPointData, 'timestamp')) {
$pointTimestamp = Carbon::createFromFormat('U', $timestamp);
$metricPointData['created_at'] = $pointTimestamp->format('Y-m-d H:i:s');
}
$metricPoint->update($metricPointData);
return $this->item($metricPoint);
}
/**
* Destroys a metric point.
*
* @param \CachetHQ\Cachet\Models\Metric $metric
* @param \CachetHQ\Cachet\Models\MetricPoint $metricPoint
*
* @return \Dingo\Api\Http\Response
*/
public function deleteMetricPoint(Metric $metric, MetricPoint $metricPoint)
{
$metricPoint->delete();
return $this->noContent();
}
}

View File

@@ -1,77 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Controllers\Api;
use CachetHQ\Cachet\Events\CustomerHasSubscribedEvent;
use CachetHQ\Cachet\Models\Subscriber;
use Exception;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Http\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
class SubscriberController extends AbstractApiController
{
/**
* Get all subscribers.
*
* @param \Symfony\Component\HttpFoundation\Request $request
*
* @return \Illuminate\Database\Eloquent\Collection
*/
public function getSubscribers(Request $request)
{
$subscribers = Subscriber::paginate(Binput::get('per_page', 20));
return $this->paginator($subscribers, $request);
}
/**
* Create a new subscriber.
*
* @return \CachetHQ\Cachet\Models\Subscriber
*/
public function postSubscribers()
{
$subscriberData = Binput::except('verify');
try {
$subscriber = Subscriber::create($subscriberData);
} catch (Exception $e) {
throw new BadRequestHttpException();
}
if ($subscriber->isValid()) {
// If we're auto-verifying the subscriber, don't bother with this event.
if (!(Binput::get('verify'))) {
event(new CustomerHasSubscribedEvent($subscriber));
}
return $this->item($subscriber);
}
throw new BadRequestHttpException();
}
/**
* Delete a subscriber.
*
* @param \CachetHQ\Cachet\Models\Subscriber $subscriber
*
* @return \Illuminate\Http\JsonResponse
*/
public function deleteSubscriber(Subscriber $subscriber)
{
$subscriber->delete();
return $this->noContent();
}
}

View File

@@ -1,118 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Controllers;
use CachetHQ\Cachet\Facades\Setting;
use CachetHQ\Cachet\Models\Component;
use CachetHQ\Cachet\Models\ComponentGroup;
use CachetHQ\Cachet\Models\Incident;
use CachetHQ\Cachet\Models\Metric;
use Exception;
use GrahamCampbell\Binput\Facades\Binput;
use GrahamCampbell\Markdown\Facades\Markdown;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\View;
use Jenssegers\Date\Date;
class HomeController extends AbstractController
{
/**
* Returns the rendered Blade templates.
*
* @return \Illuminate\View\View
*/
public function showIndex()
{
$today = Date::now();
$startDate = Date::now();
// Check if we have another starting date
if (Binput::has('start_date')) {
try {
// If date provided is valid
$oldDate = Date::createFromFormat('Y-m-d', Binput::get('start_date'));
// If trying to get a future date fallback to today
if ($today->gt($oldDate)) {
$startDate = $oldDate;
}
} catch (Exception $e) {
// Fallback to today
}
}
$metrics = null;
if ($displayMetrics = Setting::get('display_graphs')) {
$metrics = Metric::where('display_chart', 1)->get();
}
$daysToShow = Setting::get('app_incident_days') ?: 7;
$incidentDays = range(0, $daysToShow - 1);
$dateTimeZone = Setting::get('app_timezone');
$incidentVisiblity = Auth::check() ? 0 : 1;
$allIncidents = Incident::notScheduled()->where('visible', '>=', $incidentVisiblity)->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) use ($dateTimeZone) {
// If it's scheduled, get the scheduled at date.
if ($incident->is_scheduled) {
return (new Date($incident->scheduled_at))
->setTimezone($dateTimeZone)->toDateString();
}
return (new Date($incident->created_at))
->setTimezone($dateTimeZone)->toDateString();
});
// Add in days that have no incidents
foreach ($incidentDays as $i) {
$date = (new Date($startDate))->setTimezone($dateTimeZone)->subDays($i);
if (!isset($allIncidents[$date->toDateString()])) {
$allIncidents[$date->toDateString()] = [];
}
}
// Sort the array so it takes into account the added days
$allIncidents = $allIncidents->sortBy(function ($value, $key) {
return strtotime($key);
}, SORT_REGULAR, true)->all();
// Scheduled maintenance code.
$scheduledMaintenance = Incident::scheduled()->orderBy('scheduled_at')->get();
// Component & Component Group lists.
$usedComponentGroups = Component::where('group_id', '>', 0)->groupBy('group_id')->lists('group_id');
$componentGroups = ComponentGroup::whereIn('id', $usedComponentGroups)->orderBy('order')->get();
$ungroupedComponents = Component::where('group_id', 0)->orderBy('order')->orderBy('created_at')->get();
$canPageBackward = Incident::notScheduled()->where('created_at', '<', $startDate->format('Y-m-d'))->count() != 0;
return View::make('index', [
'componentGroups' => $componentGroups,
'ungroupedComponents' => $ungroupedComponents,
'displayMetrics' => $displayMetrics,
'metrics' => $metrics,
'allIncidents' => $allIncidents,
'scheduledMaintenance' => $scheduledMaintenance,
'aboutApp' => Markdown::convertToHtml(Setting::get('app_about')),
'canPageForward' => (bool) $today->gt($startDate),
'canPageBackward' => $canPageBackward,
'previousDate' => $startDate->copy()->subDays($daysToShow)->toDateString(),
'nextDate' => $startDate->copy()->addDays($daysToShow)->toDateString(),
'page_title' => Setting::get('app_name'),
]);
}
}

View File

@@ -1,70 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Controllers;
use CachetHQ\Cachet\Facades\Setting;
use CachetHQ\Cachet\Models\ComponentGroup;
use CachetHQ\Cachet\Models\Incident;
use Illuminate\Support\Str;
use Roumen\Feed\Facades\Feed;
class RssController extends AbstractController
{
/**
* Generates an Atom feed of all incidents.
*
* @param \CachetHQ\Cachet\Models\ComponentGroup|null $group
*
* @return \Illuminate\Http\Response
*/
public function feedAction(ComponentGroup $group = null)
{
$feed = Feed::make();
$feed->title = Setting::get('app_name');
$feed->lang = Setting::get('app_locale');
$feed->description = trans('cachet.feed');
$feed->link = Str::canonicalize(Setting::get('app_domain'));
$feed->setDateFormat('datetime');
if ($group->exists) {
$group->components->map(function ($component) use ($feed) {
$component->incidents()->visible()->orderBy('created_at', 'desc')->get()->map(function ($incident) use ($feed) {
$this->feedAddItem($feed, $incident);
});
});
} else {
Incident::visible()->orderBy('created_at', 'desc')->get()->map(function ($incident) use ($feed) {
$this->feedAddItem($feed, $incident);
});
}
return $feed->render('rss');
}
/**
* Adds an item to the feed.
*
* @param \Roumen\Feed\Facades\Feed $feed
* @param \CachetHQ\Cachet\Models\Incident $incident
*/
private function feedAddItem(&$feed, $incident)
{
$feed->add(
$incident->name,
Setting::get('app_name'),
Str::canonicalize(Setting::get('app_domain')).'#'.$incident->id,
$incident->created_at->toRssString(),
$incident->message
);
}
}

View File

@@ -1,216 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Controllers;
use CachetHQ\Cachet\Models\Setting;
use CachetHQ\Cachet\Models\User;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\View;
class SetupController extends AbstractController
{
/**
* Array of cache drivers.
*
* @var string[]
*/
protected $cacheDrivers = [
'apc' => 'APC(u)',
'array' => 'Array',
'file' => 'File',
'database' => 'Database',
'memcached' => 'Memcached',
'redis' => 'Redis',
];
/**
* Create a new setup controller instance.
*/
public function __construct()
{
$this->beforeFilter('csrf', ['only' => ['postCachet']]);
}
/**
* Returns the setup page.
*
* @return \Illuminate\View\View
*/
public function getIndex()
{
// If we've copied the .env.example file, then we should try and reset it.
if (getenv('APP_KEY') === 'SomeRandomString') {
$this->keyGenerate();
}
return View::make('setup')->with([
'page_title' => trans('setup.setup'),
'cacheDrivers' => $this->cacheDrivers,
'appUrl' => Request::root(),
]);
}
/**
* Handles validation on step one of the setup form.
*
* @return \Illuminate\Http\Response
*/
public function postStep1()
{
$postData = Binput::all();
$v = Validator::make($postData, [
'env.cache_driver' => 'required|in:'.implode(',', array_keys($this->cacheDrivers)),
'env.session_driver' => 'required|in:'.implode(',', array_keys($this->cacheDrivers)),
]);
if ($v->passes()) {
return Response::json(['status' => 1]);
} else {
return Response::json(['errors' => $v->messages()], 400);
}
}
/**
* Handles validation on step two of the setup form.
*
* @return \Illuminate\Http\Response
*/
public function postStep2()
{
$postData = Binput::all();
$v = Validator::make($postData, [
'env.cache_driver' => 'required|in:'.implode(',', array_keys($this->cacheDrivers)),
'env.session_driver' => 'required|in:'.implode(',', array_keys($this->cacheDrivers)),
'settings.app_name' => 'required',
'settings.app_domain' => 'required',
'settings.app_timezone' => 'required',
'settings.app_locale' => 'required',
'settings.show_support' => 'boolean',
]);
if ($v->passes()) {
return Response::json(['status' => 1]);
} else {
return Response::json(['errors' => $v->messages()], 400);
}
}
/**
* Handles the actual app setup, including user, settings and env.
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response
*/
public function postStep3()
{
$postData = Binput::all();
$v = Validator::make($postData, [
'env.cache_driver' => 'required|in:'.implode(',', array_keys($this->cacheDrivers)),
'env.session_driver' => 'required|in:'.implode(',', array_keys($this->cacheDrivers)),
'settings.app_name' => 'required',
'settings.app_domain' => 'required',
'settings.app_timezone' => 'required',
'settings.app_locale' => 'required',
'settings.show_support' => 'boolean',
'user.username' => ['required', 'regex:/\A(?!.*[:;]-\))[ -~]+\z/'],
'user.email' => 'email|required',
'user.password' => 'required',
]);
if ($v->passes()) {
// Pull the user details out.
$userDetails = array_pull($postData, 'user');
$user = User::create([
'username' => $userDetails['username'],
'email' => $userDetails['email'],
'password' => $userDetails['password'],
'level' => 1,
]);
Auth::login($user);
$settings = array_pull($postData, 'settings');
foreach ($settings as $settingName => $settingValue) {
Setting::create([
'name' => $settingName,
'value' => $settingValue,
]);
}
$envData = array_pull($postData, 'env');
// Write the env to the .env file.
foreach ($envData as $envKey => $envValue) {
$this->writeEnv($envKey, $envValue);
}
Session::flash('setup.done', true);
if (Request::ajax()) {
return Response::json(['status' => 1]);
}
return Redirect::to('dashboard');
} else {
if (Request::ajax()) {
return Response::json(['errors' => $v->messages()], 400);
}
return Redirect::back()->withInput()->with('errors', $v->messages());
}
}
/**
* Writes to the .env file with given parameters.
*
* @param string $key
* @param mixed $value
*/
protected function writeEnv($key, $value)
{
static $path = null;
if ($path === null || ($path !== null && file_exists($path))) {
$path = base_path('.env');
file_put_contents($path, str_replace(
getenv(strtoupper($key)), $value, file_get_contents($path)
));
}
}
/**
* Generate the app.key value.
*/
protected function keyGenerate()
{
$key = str_random(42);
$path = base_path('.env');
file_put_contents($path, str_replace(
Config::get('app.key'), $key, file_get_contents($path)
));
Config::set('app.key', $key);
}
}

View File

@@ -1,129 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Controllers;
use CachetHQ\Cachet\Events\CustomerHasSubscribedEvent;
use CachetHQ\Cachet\Facades\Setting;
use CachetHQ\Cachet\Models\Subscriber;
use Carbon\Carbon;
use GrahamCampbell\Binput\Facades\Binput;
use GrahamCampbell\Markdown\Facades\Markdown;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\View;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class SubscribeController extends AbstractController
{
/**
* Show the subscribe by email page.
*
* @return \Illuminate\View\View
*/
public function showSubscribe()
{
return View::make('subscribe', [
'page_title' => Setting::get('app_name'),
'aboutApp' => Markdown::convertToHtml(Setting::get('app_about')),
]);
}
/**
* Handle the subscribe user.
*
* @return \Illuminate\View\View
*/
public function postSubscribe()
{
$subscriber = Subscriber::create(['email' => Binput::get('email')]);
if (!$subscriber->isValid()) {
return Redirect::back()->withInput(Binput::all())
->with('title', sprintf(
'<strong>%s</strong> %s',
trans('dashboard.notifications.whoops'),
trans('cachet.subscriber.email.failure')
))
->with('errors', $subscriber->getErrors());
}
$successMsg = sprintf(
'<strong>%s</strong> %s',
trans('dashboard.notifications.awesome'),
trans('cachet.subscriber.email.subscribed')
);
event(new CustomerHasSubscribedEvent($subscriber));
return Redirect::route('status-page')->with('success', $successMsg);
}
/**
* Handle the verify subscriber email.
*
* @param string $code
*
* @return \Illuminate\View\View
*/
public function getVerify($code = null)
{
if (is_null($code)) {
throw new NotFoundHttpException();
}
$subscriber = Subscriber::where('verify_code', '=', $code)->first();
if (!$subscriber || $subscriber->verified()) {
return Redirect::route('status-page');
}
$subscriber->verified_at = Carbon::now();
$subscriber->save();
$successMsg = sprintf(
'<strong>%s</strong> %s',
trans('dashboard.notifications.awesome'),
trans('cachet.subscriber.email.verified')
);
return Redirect::route('status-page')->with('success', $successMsg);
}
/**
* Handle the unsubscribe.
*
* @param string $code
*
* @return \Illuminate\View\View
*/
public function getUnsubscribe($code = null)
{
if (is_null($code)) {
throw new NotFoundHttpException();
}
$subscriber = Subscriber::where('verify_code', '=', $code)->first();
if (!$subscriber || !$subscriber->verified()) {
return Redirect::route('status-page');
}
$subscriber->delete();
$successMsg = sprintf(
'<strong>%s</strong> %s',
trans('dashboard.notifications.awesome'),
trans('cachet.subscriber.email.unsuscribed')
);
return Redirect::route('status-page')->with('success', $successMsg);
}
}

View File

@@ -1,50 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* @var array
*/
protected $middleware = [
'Fideloper\Proxy\TrustProxies',
'Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode',
'Illuminate\Cookie\Middleware\EncryptCookies',
'Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse',
'Illuminate\Session\Middleware\StartSession',
'Illuminate\View\Middleware\ShareErrorsFromSession',
];
/**
* The application's route middleware.
*
* @var array
*/
protected $routeMiddleware = [
'auth' => 'CachetHQ\Cachet\Http\Middleware\Authenticate',
'auth.api' => 'CachetHQ\Cachet\Http\Middleware\ApiAuthenticate',
'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth',
'guest' => 'CachetHQ\Cachet\Http\Middleware\RedirectIfAuthenticated',
'csrf' => 'Illuminate\Foundation\Http\Middleware\VerifyCsrfToken',
'admin' => 'CachetHQ\Cachet\Http\Middleware\Admin',
'throttling' => 'GrahamCampbell\Throttle\Http\Middleware\ThrottleMiddleware',
'app.isSetup' => 'CachetHQ\Cachet\Http\Middleware\AppIsSetup',
'app.hasSetting' => 'CachetHQ\Cachet\Http\Middleware\HasSetting',
'app.subscribers' => 'CachetHQ\Cachet\Http\Middleware\SubscribersConfigured',
'accept' => 'CachetHQ\Cachet\Http\Middleware\Acceptable',
];
}

View File

@@ -1,36 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Middleware;
use Closure;
use Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException;
class Acceptable
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string $type
*
* @return mixed
*/
public function handle($request, Closure $next, $type)
{
if (!$request->accepts($type)) {
throw new NotAcceptableHttpException();
}
return $next($request);
}
}

View File

@@ -1,53 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
use Symfony\Component\HttpKernel\Exception\HttpException;
class Admin
{
/**
* The authentication guard instance.
*
* @var \Illuminate\Contracts\Auth\Guard
*/
protected $auth;
/**
* Create a new admin middleware instance.
*
* @param \Illuminate\Contracts\Auth\Guard $auth
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* We're verifying that the current user is logged in to Cachet and is an admin level.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle($request, Closure $next)
{
if (!$this->auth->check() || ($this->auth->check() && !$this->auth->user()->isAdmin)) {
throw new HttpException(401);
}
return $next($request);
}
}

View File

@@ -1,67 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Middleware;
use CachetHQ\Cachet\Models\User;
use Closure;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Symfony\Component\HttpKernel\Exception\HttpException;
class ApiAuthenticate
{
/**
* The authentication guard instance.
*
* @var \Illuminate\Contracts\Auth\Guard
*/
protected $auth;
/**
* Create a new api authenticate middleware instance.
*
* @param \Illuminate\Contracts\Auth\Guard $auth
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->guest()) {
if ($apiToken = $request->header('X-Cachet-Token')) {
try {
$this->auth->onceUsingId(User::findByApiToken($apiToken)->id);
} catch (ModelNotFoundException $e) {
throw new HttpException(401);
}
} elseif ($request->getUser()) {
if ($this->auth->onceBasic() !== null) {
throw new HttpException(401);
}
} else {
throw new HttpException(401);
}
}
return $next($request);
}
}

View File

@@ -1,53 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
use Symfony\Component\HttpKernel\Exception\HttpException;
class Authenticate
{
/**
* The authentication guard instance.
*
* @var \Illuminate\Contracts\Auth\Guard
*/
protected $auth;
/**
* Create a new authenticate middleware instance.
*
* @param \Illuminate\Contracts\Auth\Guard $auth
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->guest()) {
throw new HttpException(401);
}
return $next($request);
}
}

View File

@@ -1,62 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Middleware;
use CachetHQ\Cachet\Models\Setting;
use Closure;
use Exception;
use Illuminate\Support\Facades\Redirect;
class HasSetting
{
/**
* Run the has setting middleware.
*
* We're verifying that the given setting exists in our database. If it
* doesn't, then we're sending the user to the setup page so that they can
* complete the installation of Cachet on their server.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle($request, Closure $next)
{
$settingName = $this->getSettingName($request);
try {
$setting = Setting::where('name', $settingName)->first();
if (!$setting || !$setting->value) {
return Redirect::to('setup');
}
} catch (Exception $e) {
return Redirect::to('setup');
}
return $next($request);
}
/**
* Get the setting from the request.
*
* @param \Illuminate\Http\Request $request
*
* @return array
*/
private function getSettingName($request)
{
$actions = $request->route()->getAction();
return $actions['setting'];
}
}

View File

@@ -1,53 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\RedirectResponse;
class RedirectIfAuthenticated
{
/**
* The authentication guard instance.
*
* @var \Illuminate\Contracts\Auth\Guard
*/
protected $auth;
/**
* Create a new redirect if authenticated middleware instance.
*
* @param \Illuminate\Contracts\Auth\Guard $auth
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->check()) {
return new RedirectResponse(route('dashboard'));
}
return $next($request);
}
}

View File

@@ -1,35 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Redirect;
class SubscribersConfigured
{
/**
* We're verifying that subscribers is both enabled and configured.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle($request, Closure $next)
{
if (!subscribers_enabled()) {
return Redirect::route('status-page');
}
return $next($request);
}
}

View File

@@ -1,224 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Routes;
use Illuminate\Contracts\Routing\Registrar;
class AdminRoutes
{
/**
* Define the dashboard routes.
*
* @param \Illuminate\Contracts\Routing\Registrar $router
*/
public function map(Registrar $router)
{
$router->group([
'middleware' => 'auth',
'prefix' => 'dashboard',
'namespace' => 'Admin',
], function ($router) {
// Dashboard
$router->get('/', [
'as' => 'dashboard',
'uses' => 'DashboardController@showDashboard',
]);
// Components
$router->group(['prefix' => 'components'], function ($router) {
$router->get('/', [
'as' => 'dashboard.components',
'uses' => 'ComponentController@showComponents',
]);
$router->get('add', [
'as' => 'dashboard.components.add',
'uses' => 'ComponentController@showAddComponent',
]);
$router->post('add', 'ComponentController@createComponentAction');
$router->get('groups', [
'as' => 'dashboard.components.groups',
'uses' => 'ComponentController@showComponentGroups',
]);
$router->get('groups/add', [
'as' => 'dashboard.components.groups.add',
'uses' => 'ComponentController@showAddComponentGroup',
]);
$router->get('groups/edit/{component_group}', [
'as' => 'dashboard.components.groups.edit',
'uses' => 'ComponentController@showEditComponentGroup',
]);
$router->post('groups/edit/{component_group}', 'ComponentController@updateComponentGroupAction');
$router->delete('groups/{component_group}/delete', 'ComponentController@deleteComponentGroupAction');
$router->post('groups/add', 'ComponentController@postAddComponentGroup');
$router->delete('{component}/delete', 'ComponentController@deleteComponentAction');
$router->get('{component}/edit', 'ComponentController@showEditComponent');
$router->post('{component}/edit', 'ComponentController@updateComponentAction');
});
// Incidents
$router->group(['prefix' => 'incidents'], function ($router) {
$router->get('/', [
'as' => 'dashboard.incidents',
'uses' => 'IncidentController@showIncidents',
]);
$router->get('add', [
'as' => 'dashboard.incidents.add',
'uses' => 'IncidentController@showAddIncident',
]);
$router->post('add', 'IncidentController@createIncidentAction');
$router->delete('{incident}/delete', 'IncidentController@deleteIncidentAction');
$router->get('{incident}/edit', 'IncidentController@showEditIncidentAction');
$router->post('{incident}/edit', 'IncidentController@editIncidentAction');
});
// Scheduled Maintenance
$router->group(['prefix' => 'schedule'], function ($router) {
$router->get('/', ['as' => 'dashboard.schedule', 'uses' => 'ScheduleController@showIndex']);
$router->get('add', [
'as' => 'dashboard.schedule.add',
'uses' => 'ScheduleController@showAddSchedule',
]);
$router->post('add', 'ScheduleController@addScheduleAction');
$router->get('{incident}/edit', [
'as' => 'dashboard.schedule.edit',
'uses' => 'ScheduleController@showEditSchedule',
]);
$router->post('{incident}/edit', 'ScheduleController@editScheduleAction');
$router->delete('{incident}/delete', [
'as' => 'dashboard.schedule.delete',
'uses' => 'ScheduleController@deleteScheduleAction',
]);
});
// Incident Templates
$router->group(['prefix' => 'templates'], function ($router) {
$router->get('/', [
'as' => 'dashboard.templates',
'uses' => 'IncidentController@showTemplates',
]);
$router->get('add', [
'as' => 'dashboard.templates.add',
'uses' => 'IncidentController@showAddIncidentTemplate',
]);
$router->post('add', 'IncidentController@createIncidentTemplateAction');
$router->get('{incident_template}/edit', 'IncidentController@showEditTemplateAction');
$router->post('{incident_template}/edit', 'IncidentController@editTemplateAction');
$router->delete('{incident_template}/delete', 'IncidentController@deleteTemplateAction');
});
// Subscribers
$router->group(['prefix' => 'subscribers'], function ($router) {
$router->get('/', [
'as' => 'dashboard.subscribers',
'uses' => 'SubscriberController@showSubscribers',
]);
$router->get('add', [
'as' => 'dashboard.subscribers.add',
'uses' => 'SubscriberController@showAddSubscriber',
]);
$router->post('add', 'SubscriberController@createSubscriberAction');
$router->delete('{subscriber}/delete', 'SubscriberController@deleteSubscriberAction');
});
// Metrics
$router->group(['prefix' => 'metrics'], function ($router) {
$router->get('/', [
'as' => 'dashboard.metrics',
'uses' => 'MetricController@showMetrics',
]);
$router->get('add', [
'as' => 'dashboard.metrics.add',
'uses' => 'MetricController@showAddMetric',
]);
$router->post('add', 'MetricController@createMetricAction');
$router->delete('{metric}/delete', 'MetricController@deleteMetricAction');
$router->get('{metric}/edit', 'MetricController@showEditMetricAction');
$router->post('{metric}/edit', 'MetricController@editMetricAction');
});
// Notifications
$router->group(['prefix' => 'notifications'], function ($router) {
$router->get('/', [
'as' => 'dashboard.notifications',
'uses' => 'DashboardController@showNotifications',
]);
});
// Team Members
$router->group(['prefix' => 'team'], function ($router) {
$router->get('/', [
'as' => 'dashboard.team',
'uses' => 'TeamController@showTeamView',
]);
$router->group(['middleware' => 'admin'], function ($router) {
$router->get('add', [
'as' => 'dashboard.team.add',
'uses' => 'TeamController@showAddTeamMemberView',
]);
$router->get('{user}', 'TeamController@showTeamMemberView');
$router->post('add', 'TeamController@postAddUser');
$router->post('{user}', 'TeamController@postUpdateUser');
});
});
// Settings
$router->group(['prefix' => 'settings'], function ($router) {
$router->get('setup', [
'as' => 'dashboard.settings.setup',
'uses' => 'SettingsController@showSetupView',
]);
$router->get('security', [
'as' => 'dashboard.settings.security',
'uses' => 'SettingsController@showSecurityView',
]);
$router->get('theme', [
'as' => 'dashboard.settings.theme',
'uses' => 'SettingsController@showThemeView',
]);
$router->get('stylesheet', [
'as' => 'dashboard.settings.stylesheet',
'uses' => 'SettingsController@showStylesheetView',
]);
$router->post('/', 'SettingsController@postSettings');
});
// User Settings
$router->group(['prefix' => 'user'], function ($router) {
$router->get('/', [
'as' => 'dashboard.user',
'uses' => 'UserController@showUser',
]);
$router->post('/', 'UserController@postUser');
$router->get('{user}/api/regen', 'UserController@regenerateApiKey');
});
// Internal API.
// This should only be used for making requests within the dashboard.
$router->group(['prefix' => 'api'], function ($router) {
$router->get('incidents/templates', 'ApiController@getIncidentTemplate');
$router->post('components/groups/order', 'ApiController@postUpdateComponentGroupOrder');
$router->post('components/order', 'ApiController@postUpdateComponentOrder');
$router->post('components/{component}', 'ApiController@postUpdateComponent');
});
});
}
}

View File

@@ -1,69 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Routes;
use Illuminate\Contracts\Routing\Registrar;
class ApiRoutes
{
/**
* Define the api routes.
*
* @param \Illuminate\Contracts\Routing\Registrar $router
*/
public function map(Registrar $router)
{
$router->group([
'namespace' => 'Api',
'prefix' => 'api/v1',
'middleware' => 'accept:application/json',
], function ($router) {
// General
$router->get('ping', 'GeneralController@ping');
// Components
$router->get('components', 'ComponentController@getComponents');
$router->get('components/{component}', 'ComponentController@getComponent');
// Incidents
$router->get('incidents', 'IncidentController@getIncidents');
$router->get('incidents/{incident}', 'IncidentController@getIncident');
// Metrics
$router->get('metrics', 'MetricController@getMetrics');
$router->get('metrics/{metric}', 'MetricController@getMetric');
$router->get('metrics/{metric}/points', 'MetricController@getMetricPoints');
// Api protected
$router->group(['middleware' => 'auth.api'], function ($router) {
$router->get('subscribers', 'SubscriberController@getSubscribers');
$router->post('components', 'ComponentController@postComponents');
$router->post('incidents', 'IncidentController@postIncidents');
$router->post('metrics', 'MetricController@postMetrics');
$router->post('metrics/{metric}/points', 'MetricPointController@postMetricPoints');
$router->post('subscribers', 'SubscriberController@postSubscribers');
$router->put('components/{component}', 'ComponentController@putComponent');
$router->put('incidents/{incident}', 'IncidentController@putIncident');
$router->put('metrics/{metric}', 'MetricController@putMetric');
$router->put('metrics/{metric}/points/{metric_point}', 'MetricPointController@putMetricPoint');
$router->delete('components/{component}', 'ComponentController@deleteComponent');
$router->delete('incidents/{incident}', 'IncidentController@deleteIncident');
$router->delete('metrics/{metric}', 'MetricController@deleteMetric');
$router->delete('metrics/{metric}/points/{metric_point}', 'MetricPointController@deleteMetricPoint');
$router->delete('subscribers/{subscriber}', 'SubscriberController@deleteSubscriber');
});
});
}
}

View File

@@ -1,57 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Routes;
use Illuminate\Contracts\Routing\Registrar;
class AuthRoutes
{
/**
* Define the auth routes.
*
* @param \Illuminate\Contracts\Routing\Registrar $router
*/
public function map(Registrar $router)
{
$router->group(['prefix' => 'auth'], function ($router) {
$router->group(['middleware' => 'app.hasSetting', 'setting' => 'app_name'], function ($router) {
// Login routes
$router->get('login', [
'middleware' => 'guest',
'as' => 'login',
'uses' => 'AuthController@showLogin',
]);
$router->post('login', [
'middleware' => ['guest', 'csrf', 'throttling:10,10'],
'as' => 'login',
'uses' => 'AuthController@postLogin',
]);
// Two factor authorization
$router->get('2fa', [
'as' => 'two-factor',
'uses' => 'AuthController@showTwoFactorAuth',
]);
$router->post('2fa', 'AuthController@postTwoFactor');
});
$router->group(['middleware' => 'auth'], function ($router) {
$router->get('logout', [
'as' => 'logout',
'uses' => 'AuthController@logoutAction',
]);
});
});
}
}

View File

@@ -1,29 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Routes;
use Illuminate\Contracts\Routing\Registrar;
class SetupRoutes
{
/**
* Define the setup routes.
*
* @param \Illuminate\Contracts\Routing\Registrar $router
*/
public function map(Registrar $router)
{
$router->group(['middleware' => 'app.isSetup'], function ($router) {
$router->controller('setup', 'SetupController');
});
}
}

View File

@@ -1,36 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Routes;
use Illuminate\Contracts\Routing\Registrar;
class StatusPageRoutes
{
/**
* Define the status page routes.
*
* @param \Illuminate\Contracts\Routing\Registrar $router
*/
public function map(Registrar $router)
{
// Prevent access until the app is setup.
$router->group(['middleware' => 'app.hasSetting', 'setting' => 'app_name'], function ($router) {
$router->get('/', [
'as' => 'status-page',
'uses' => 'HomeController@showIndex',
]);
$router->get('/atom/{component_group?}', 'AtomController@feedAction');
$router->get('/rss/{component_group?}', 'RssController@feedAction');
});
}
}

View File

@@ -1,49 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Routes;
use Illuminate\Contracts\Routing\Registrar;
class SubscribeRoutes
{
/**
* Define the subscribe routes.
*
* @param \Illuminate\Contracts\Routing\Registrar $router
*/
public function map(Registrar $router)
{
$router->group(['middleware' => 'app.hasSetting', 'setting' => 'app_name'], function ($router) {
$router->group(['middleware' => 'app.subscribers'], function ($router) {
$router->get('subscribe', [
'as' => 'subscribe-page',
'uses' => 'SubscribeController@showSubscribe',
]);
$router->post('subscribe', [
'as' => 'subscribe',
'uses' => 'SubscribeController@postSubscribe',
]);
$router->get('subscribe/verify/{code}', [
'as' => 'subscribe-verify',
'uses' => 'SubscribeController@getVerify',
]);
$router->get('unsubscribe/{code}', [
'as' => 'unsubscribe',
'uses' => 'SubscribeController@getUnsubscribe',
]);
});
});
}
}

View File

@@ -1,69 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use CachetHQ\Cachet\Facades\Setting;
use Illuminate\Support\Facades\Request;
use Jenssegers\Date\Date;
if (!function_exists('set_active')) {
/**
* Set active class if request is in path.
*
* @param string $path
* @param array $classes
* @param string $active
*
* @return string
*/
function set_active($path, array $classes = [], $active = 'active')
{
if (Request::is($path)) {
$classes[] = $active;
}
$class = e(implode(' ', $classes));
return empty($classes) ? '' : "class=\"{$class}\"";
}
}
if (!function_exists('formatted_date')) {
/**
* Formats a date with the user timezone and the selected format.
*
* @param string $date
*
* @return \Jenssegers\Date\Date
*/
function formatted_date($date)
{
$dateFormat = Setting::get('date_format', 'jS F Y');
return (new Date($date))->format($dateFormat);
}
}
if (!function_exists('subscribers_enabled')) {
/**
* Is the subscriber functionality enabled and configured.
*
* @return bool
*/
function subscribers_enabled()
{
$isEnabled = Setting::get('enable_subscribers', false);
$mailAddress = env('MAIL_ADDRESS', false);
$mailFrom = env('MAIL_NAME', false);
return $isEnabled && $mailAddress && $mailFrom;
}
}

View File

@@ -1,58 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Models;
use CachetHQ\Cachet\Presenters\MetricPointPresenter;
use Illuminate\Database\Eloquent\Model;
use McCool\LaravelAutoPresenter\HasPresenter;
use Watson\Validating\ValidatingTrait;
class MetricPoint extends Model implements HasPresenter
{
use ValidatingTrait;
/**
* The attributes that are mass assignable.
*
* @var string[]
*/
protected $fillable = ['metric_id', 'value', 'created_at'];
/**
* The validation rules.
*
* @var string[]
*/
protected $rules = [
'value' => 'numeric|required',
];
/**
* A metric point belongs to a metric unit.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function metric()
{
return $this->belongsTo(Metric::class, 'id', 'metric_id');
}
/**
* Get the presenter class.
*
* @return string
*/
public function getPresenterClass()
{
return MetricPointPresenter::class;
}
}

View File

@@ -1,99 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Models;
use CachetHQ\Cachet\Presenters\SubscriberPresenter;
use Illuminate\Database\Eloquent\Model;
use McCool\LaravelAutoPresenter\HasPresenter;
use Watson\Validating\ValidatingTrait;
class Subscriber extends Model implements HasPresenter
{
use ValidatingTrait;
/**
* The validation rules.
*
* @var string[]
*/
protected $rules = [
'email' => 'required|email|unique:subscribers',
];
/**
* The fillable properties.
*
* @var string[]
*/
protected $fillable = ['email'];
/**
* The attributes that should be mutated to dates.
*
* @var array
*/
protected $dates = ['verified_at'];
/**
* The attributes that should be casted to native types.
*
* @var string[]
*/
protected $casts = [
'email' => 'string',
'verify_code' => 'string',
];
/**
* Overrides the models boot method.
*/
public static function boot()
{
parent::boot();
self::creating(function ($user) {
if (!$user->verify_code) {
$user->verify_code = self::generateVerifyCode();
}
});
}
/**
* Determines if the subscriber is verified.
*
* @return bool
*/
public function verified()
{
return !is_null($this->verified_at);
}
/**
* Returns an new verify code.
*
* @return string
*/
public static function generateVerifyCode()
{
return str_random(42);
}
/**
* Get the presenter class.
*
* @return string
*/
public function getPresenterClass()
{
return SubscriberPresenter::class;
}
}

View File

@@ -1,38 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Presenters;
use CachetHQ\Cachet\Facades\Setting;
use Illuminate\Contracts\Support\Arrayable;
use McCool\LaravelAutoPresenter\BasePresenter as BaseLaravelAutoPresenter;
abstract class AbstractPresenter extends BaseLaravelAutoPresenter implements Arrayable
{
/**
* The setting repository.
*
* @var \CachetHQ\Cachet\Config\Repository
*/
protected $setting;
/**
* Create a incident presenter instance.
*
* @param object $resource
*/
public function __construct($resource)
{
parent::__construct($resource);
$this->setting = app('setting');
}
}

View File

@@ -1,33 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Presenters;
use CachetHQ\Cachet\Presenters\Traits\TimestampsTrait;
class ComponentPresenter extends AbstractPresenter
{
use TimestampsTrait;
/**
* Convert the presenter instance to an array.
*
* @return string[]
*/
public function toArray()
{
return array_merge($this->wrappedObject->toArray(), [
'created_at' => $this->created_at(),
'updated_at' => $this->updated_at(),
'status_name' => $this->wrappedObject->humanStatus,
]);
}
}

View File

@@ -1,196 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Presenters;
use CachetHQ\Cachet\Facades\Setting;
use CachetHQ\Cachet\Presenters\Traits\TimestampsTrait;
use GrahamCampbell\Markdown\Facades\Markdown;
use Jenssegers\Date\Date;
class IncidentPresenter extends AbstractPresenter
{
use TimestampsTrait;
/**
* Renders the message from Markdown into HTML.
*
* @return string
*/
public function formattedMessage()
{
return Markdown::convertToHtml($this->wrappedObject->message);
}
/**
* Present diff for humans date time.
*
* @return string
*/
public function created_at_diff()
{
return (new Date($this->wrappedObject->created_at))
->setTimezone($this->setting->get('app_timezone'))
->diffForHumans();
}
/**
* Present formatted date time.
*
* @return string
*/
public function created_at_formatted()
{
return ucfirst((new Date($this->wrappedObject->created_at))
->setTimezone($this->setting->get('app_timezone'))
->format($this->setting->get('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 $this->wrappedObject->created_at->setTimezone($this->setting->get('app_timezone'))->format('d/m/Y H:i');
}
/**
* Present formatted date time.
*
* @return string
*/
public function created_at_iso()
{
return $this->wrappedObject->created_at->setTimezone($this->setting->get('app_timezone'))->toISO8601String();
}
/**
* Present formatted date time.
*
* @return string
*/
public function scheduled_at()
{
return (new Date($this->wrappedObject->scheduled_at))
->setTimezone($this->setting->get('app_timezone'))->toDateTimeString();
}
/**
* Present diff for humans date time.
*
* @return string
*/
public function scheduled_at_diff()
{
return (new Date($this->wrappedObject->scheduled_at))
->setTimezone($this->setting->get('app_timezone'))
->diffForHumans();
}
/**
* Present formated date time.
*
* @return string
*/
public function scheduled_at_formatted()
{
return ucfirst((new Date($this->wrappedObject->scheduled_at))
->setTimezone($this->setting->get('app_timezone'))
->format($this->setting->get('incident_date_format', 'l jS F Y H:i:s')));
}
/**
* Present formatted date time.
*
* @return string
*/
public function scheduled_at_iso()
{
return $this->wrappedObject->scheduled_at->setTimezone($this->setting->get('app_timezone'))->toISO8601String();
}
/**
* Formats the scheduled_at time ready to be used by bootstrap-datetimepicker.
*
* @return string
*/
public function scheduled_at_datetimepicker()
{
return $this->wrappedObject->scheduled_at->setTimezone($this->setting->get('app_timezone'))->format('d/m/Y H:i');
}
/**
* 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;
} else {
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;
} else {
return $this->created_at_iso;
}
}
/**
* Present the status with an icon.
*
* @return string
*/
public function icon()
{
switch ($this->wrappedObject->status) {
case 0: // Scheduled
return 'icon ion-android-calendar';
case 1: // Investigating
return 'icon ion-flag';
case 2: // Identified
return 'icon ion-alert';
case 3: // Watching
return 'icon ion-eye';
case 4: // Fixed
return 'icon ion-checkmark';
default: // Something actually broke, this shouldn't happen.
return '';
}
}
/**
* Convert the presenter instance to an array.
*
* @return string[]
*/
public function toArray()
{
return array_merge($this->wrappedObject->toArray(), [
'scheduled_at' => $this->created_at(),
'created_at' => $this->created_at(),
'updated_at' => $this->updated_at(),
]);
}
}

View File

@@ -1,32 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Presenters;
use CachetHQ\Cachet\Presenters\Traits\TimestampsTrait;
class MetricPointPresenter extends AbstractPresenter
{
use TimestampsTrait;
/**
* Convert the presenter instance to an array.
*
* @return string[]
*/
public function toArray()
{
return array_merge($this->wrappedObject->toArray(), [
'created_at' => $this->created_at(),
'updated_at' => $this->updated_at(),
]);
}
}

View File

@@ -1,32 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Presenters;
use CachetHQ\Cachet\Presenters\Traits\TimestampsTrait;
class MetricPresenter extends AbstractPresenter
{
use TimestampsTrait;
/**
* Convert the presenter instance to an array.
*
* @return string[]
*/
public function toArray()
{
return array_merge($this->wrappedObject->toArray(), [
'created_at' => $this->created_at(),
'updated_at' => $this->updated_at(),
]);
}
}

View File

@@ -1,33 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Presenters;
use CachetHQ\Cachet\Presenters\Traits\TimestampsTrait;
class SubscriberPresenter extends AbstractPresenter
{
use TimestampsTrait;
/**
* Convert the presenter instance to an array.
*
* @return string[]
*/
public function toArray()
{
return array_merge($this->wrappedObject->toArray(), [
'created_at' => $this->created_at(),
'updated_at' => $this->updated_at(),
'verified_at' => $this->verified_at(),
]);
}
}

View File

@@ -1,61 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Presenters\Traits;
use Jenssegers\Date\Date;
trait TimestampsTrait
{
/**
* Present formatted date time.
*
* @return string
*/
public function created_at()
{
return (new Date($this->wrappedObject->created_at))
->setTimezone($this->setting->get('app_timezone'))->toDateTimeString();
}
/**
* Present formatted date time.
*
* @return string
*/
public function updated_at()
{
return (new Date($this->wrappedObject->updated_at))
->setTimezone($this->setting->get('app_timezone'))->toDateTimeString();
}
/**
* Present formatted date time.
*
* @return string
*/
public function deleted_at()
{
return (new Date($this->wrappedObject->deleted_at))
->setTimezone($this->setting->get('app_timezone'))->toDateTimeString();
}
/**
* Present formatted date time.
*
* @return string
*/
public function verified_at()
{
return (new Date($this->wrappedObject->verified_at))
->setTimezone($this->setting->get('app_timezone'))->toDateTimeString();
}
}

View File

@@ -1,43 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Providers;
use Illuminate\Bus\Dispatcher;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Str;
class AppServiceProvider extends ServiceProvider
{
/**
* Boot the service provider.
*
* @param \Illuminate\Bus\Dispatcher $dispatcher
*/
public function boot(Dispatcher $dispatcher)
{
$dispatcher->mapUsing(function ($command) {
return Dispatcher::simpleMapping($command, 'CachetHQ\Cachet\Commands', 'CachetHQ\Cachet\Handlers\Commands');
});
Str::macro('canonicalize', function ($url) {
return preg_replace('/([^\/])$/', '$1/', $url);
});
}
/**
* Register the service provider.
*/
public function register()
{
$this->app->bind('Illuminate\Contracts\Auth\Registrar', 'CachetHQ\Cachet\Services\Registrar');
}
}

View File

@@ -1,47 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Providers;
use CachetHQ\Cachet\Composers\AppComposer;
use CachetHQ\Cachet\Composers\DashboardComposer;
use CachetHQ\Cachet\Composers\IndexComposer;
use CachetHQ\Cachet\Composers\LoggedUserComposer;
use CachetHQ\Cachet\Composers\ThemeComposer;
use CachetHQ\Cachet\Composers\TimezoneLocaleComposer;
use Illuminate\Contracts\View\Factory;
use Illuminate\Support\ServiceProvider;
class ComposerServiceProvider extends ServiceProvider
{
/**
* Boot the service provider.
*
* @param \Illuminate\Contracts\View\Factory $factory
*/
public function boot(Factory $factory)
{
$factory->composer('*', AppComposer::class);
$factory->composer('*', LoggedUserComposer::class);
$factory->composer(['index', 'subscribe'], IndexComposer::class);
$factory->composer(['index', 'subscribe'], ThemeComposer::class);
$factory->composer('dashboard.*', DashboardComposer::class);
$factory->composer(['setup', 'dashboard.settings.app-setup'], TimezoneLocaleComposer::class);
}
/**
* Register the service provider.
*/
public function register()
{
//
}
}

View File

@@ -1,70 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Providers;
use CachetHQ\Cachet\Config\Repository;
use CachetHQ\Cachet\Facades\Setting;
use CachetHQ\Cachet\Models\Setting as SettingModel;
use Exception;
use Illuminate\Support\ServiceProvider;
class ConfigServiceProvider extends ServiceProvider
{
/**
* Boot the service provider.
*/
public function boot()
{
$appDomain = $appLocale = null;
try {
// Get app custom configuration.
$appDomain = Setting::get('app_domain');
$appLocale = Setting::get('app_locale');
// Setup Cors.
$allowedOrigins = $this->app->config->get('cors.defaults.allowedOrigins');
$allowedOrigins[] = Setting::get('app_domain');
// Add our allowed domains too.
if ($allowedDomains = Setting::get('allowed_domains')) {
$domains = explode(',', $allowedDomains);
foreach ($domains as $domain) {
$allowedOrigins[] = $domain;
}
} else {
$allowedOrigins[] = env('APP_URL');
}
$this->app->config->set('cors.paths.api/v1/*.allowedOrigins', $allowedOrigins);
} catch (Exception $e) {
// Don't throw any errors, we may not be setup yet.
}
// Override default app values.
$this->app->config->set('app.url', $appDomain ?: $this->app->config->get('app.url'));
$this->app->config->set('app.locale', $appLocale ?: $this->app->config->get('app.locale'));
// Set custom lang.
$this->app->translator->setLocale($appLocale);
}
/**
* Register the service provider.
*/
public function register()
{
$this->app->bindShared('setting', function () {
return new Repository(new SettingModel());
});
}
}

View File

@@ -1,34 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Providers;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* The event handler mappings for the application.
*
* @var array
*/
protected $listen = [
'CachetHQ\Cachet\Events\CustomerHasSubscribedEvent' => [
'CachetHQ\Cachet\Handlers\Events\SendSubscriberVerificationEmailHandler',
],
'CachetHQ\Cachet\Events\IncidentHasReportedEvent' => [
'CachetHQ\Cachet\Handlers\Events\SendIncidentEmailNotificationHandler',
],
'CachetHQ\Cachet\Events\MaintenanceHasScheduledEvent' => [
'CachetHQ\Cachet\Handlers\Events\SendMaintenanceEmailNotificationHandler',
],
];
}

View File

@@ -1,69 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Providers;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Routing\Router;
class RouteServiceProvider extends ServiceProvider
{
/**
* This namespace is applied to the controller routes in your routes file.
*
* In addition, it is set as the URL generator's root namespace.
*
* @var string
*/
protected $namespace = 'CachetHQ\Cachet\Http\Controllers';
/**
* Define the route model bindings, pattern filters, etc.
*
* @param \Illuminate\Routing\Router $router
*/
public function boot(Router $router)
{
parent::boot($router);
$this->registerBindings();
}
/**
* Register model bindings.
*/
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('user', 'CachetHQ\Cachet\Models\User');
}
/**
* Define the routes for the application.
*
* @param \Illuminate\Routing\Router $router
*/
public function map(Router $router)
{
$router->group(['namespace' => $this->namespace], function (Router $router) {
foreach (glob(app_path('Http//Routes').'/*.php') as $file) {
$this->app->make('CachetHQ\\Cachet\\Http\\Routes\\'.basename($file, '.php'))->map($router);
}
});
}
}

View File

@@ -1,51 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Services;
use CachetHQ\Cachet\User;
use Illuminate\Contracts\Auth\Registrar as RegistrarContract;
use Validator;
class Registrar implements RegistrarContract
{
/**
* Get a validator for an incoming registration request.
*
* @param array $data
*
* @return \Illuminate\Contracts\Validation\Validator
*/
public function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'password' => 'required|confirmed|min:6',
]);
}
/**
* Create a new user instance after a valid registration.
*
* @param array $data
*
* @return User
*/
public function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
}
}

78
resources/assets/js/app.js → app/assets/js/app.js Executable file → Normal file
View File

@@ -5,18 +5,12 @@ $(function() {
if (! options.crossDomain) {
token = $('meta[name="token"]').attr('content');
if (token) {
jqXHR.setRequestHeader('X-CSRF-Token', token);
return jqXHR.setRequestHeader('X-CSRF-Token', token);
}
}
return jqXHR;
});
$.ajaxSetup({
beforeSend: function (xhr) {
xhr.setRequestHeader('Accept', 'application/json');
// xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
},
statusCode: {
401: function () {
window.location.href = '/';
@@ -132,21 +126,6 @@ $(function() {
}
});
$('input[rel=datepicker-any]').datetimepicker({
format: "DD/MM/YYYY HH:mm",
sideBySide: true,
icons: {
time: 'ion-clock',
date: 'ion-android-calendar',
up: 'ion-ios-arrow-up',
down: 'ion-ios-arrow-down',
previous: 'ion-ios-arrow-left',
next: 'ion-ios-arrow-right',
today: 'ion-android-home',
clear: 'ion-trash-a',
}
});
// Sortable components.
var componentList = document.getElementById("component-list");
if (componentList) {
@@ -154,51 +133,21 @@ $(function() {
group: "omega",
handle: ".drag-handle",
onUpdate: function() {
var orderedComponentIds = $.map($('#component-list .striped-list-item'), function(elem) {
return $(elem).data('component-id');
// Loop each component, setting the order input to the new order.
var $components = $('#component-list .striped-list-item');
$.each($components, function(id) {
// Order should start from 1 now.
$(this).find('input[rel=order]').val(id + 1);
});
// Now POST the form to the internal API.
$.ajax({
async: true,
url: '/dashboard/api/components/order',
type: 'POST',
data: {
ids: orderedComponentIds
},
data: $('form[name=componentList]').serializeObject(),
success: function() {
(new CachetHQ.Notifier()).notify('Component orders updated.', 'success');
},
error: function() {
(new CachetHQ.Notifier()).notify('Component orders not updated.', 'error');
}
});
}
});
}
// Sortable Component Groups
var componentGroupList = document.getElementById("component-group-list");
if (componentGroupList) {
new Sortable(componentGroupList, {
group: "omega",
handle: ".drag-handle",
onUpdate: function() {
var orderedComponentGroupsIds = $.map(
$('#component-group-list .striped-list-item'),
function(elem) {
return $(elem).data('group-id');
}
);
$.ajax({
async: true,
url: '/dashboard/api/components/groups/order',
type: 'POST',
data: {ids: orderedComponentGroupsIds},
success: function() {
(new CachetHQ.Notifier()).notify('Component groups order has been updated.', 'success');
},
error: function() {
(new CachetHQ.Notifier()).notify('Component groups order could not be updated.', 'error');
(new CachetHQ.Notifier()).notify('Components updated.', 'success');
}
});
}
@@ -233,6 +182,7 @@ $(function() {
if (slug) {
$.ajax({
async: true,
dataType: 'json',
data: {
slug: slug
},
@@ -255,14 +205,6 @@ $(function() {
$('input[name=remove_banner]').val('1');
});
$('.group-name').on('click', function () {
var $this = $(this);
$this.find('.group-toggle').toggleClass('ion-ios-minus-outline').toggleClass('ion-ios-plus-outline');
$this.next('.group-items').toggleClass('hide');
});
// Setup wizard
$('.wizard-next').on('click', function () {
var $form = $('#setup-form'),

View File

View File

View File

View File

@@ -1,5 +1,4 @@
body.status-page {
padding-top: 40px;
font-family: $base-font-family;
background-color: #F0F3F4;
color: #333333;
@@ -45,6 +44,8 @@ body.status-page {
.container {
max-width: 960px;
margin-bottom: 40px;
margin-top: 20px;
}
.page-header {
@@ -64,8 +65,25 @@ body.status-page {
}
.alert {
border-radius: 0;
font-size: 1.2em;
font-weight: 600;
&.alert-success {
background-color: $cachet_green;
border-color: $cachet_dark-green;
color: white;
}
&.alert-info {
background: $cachet_blue;
border-color: $cachet_dark-blue;
color: #FFF;
}
&.alert-danger {
background: $cachet_red;
border-color: $cachet_dark-red;
color: #FFF;
}
}
.timeline {
@@ -121,8 +139,8 @@ body.status-page {
position: relative;
&.first {
&:before {
// height: 130%;
top: -5px;
height: 130%;
top: -20px;
}
&:after {
content: '';
@@ -139,7 +157,7 @@ body.status-page {
content: '';
position: absolute;
left: 26px;
top: -5px;
top: 5px;
width: 2px;
height: 100%;
background: #7266BA;
@@ -216,30 +234,12 @@ body.status-page {
}
}
.panel-heading {
strong {
font-size: 1.1em;
}
}
.panel-body {
border-top: 1px solid #eee;
p {
&:not(:last-child) {
margin-bottom: 10px;
}
font-size: 1.1em;
}
}
img {
box-sizing: border-box;
&.emoji {
height: 20px;
width: 20px;
vertical-align: middle;
max-width: none;
margin: 0;
font-size: 1em;
// font-weight: normal;
}
}
}
@@ -252,9 +252,9 @@ body.status-page {
}
.list-group {
// margin-bottom: 20px;
margin-bottom: 20px;
padding-left: 0;
// border-radius: 0;
border-radius: 0;
.list-group-item {
border-radius: 0;
@@ -285,87 +285,39 @@ body.status-page {
top: 0.6em;
bottom: 0.6em;
}
cursor: pointer;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
&.sub-component {
&:before {
@extend .ion;
content: $ionicon-var-ios-plus-outline;
margin-right: 10px;
}
}
&.break {
padding: 1px;
background-color: $cachet-base-medium;
background-color: $cachet_gray_light;
}
}
&.components {
@extend .panel;
border-color: $cachet_gray_light;
margin-bottom: 30px;
p {
margin-bottom: 10px;
}
.badge {
color: transparent;
}
a {
color: $cachet-base-dark !important;
}
}
}
footer {
position: absolute;
width: 100%;
bottom: 0;
height: 60px;
padding: 40px 0 60px 0;
footer.footer {
padding-top: 40px;
padding-bottom: 40px;
color: #777;
text-align: center;
border-top: 1px solid $cachet_gray_light;
background-color: lighten($cachet_gray_light, 5%);
color: $cachet-gray-darker;
line-height: 30px;
text-align: center;
.icons {
a.icon-link {
display: inline-block;
min-width: 30px;
height: 30px;
border-radius: 3px;
background-color: $cachet-gray-darker;
text-align: center;
color: $cachet_gray_light;
transition: all 0.15s;
padding: 0 10px 0 10px;
&.rss {
background-color: $cachet-orange;
}
&:hover {
text-decoration: none;
background-color: darken($cachet-gray-darker, 10%);
}
}
}
@media (min-width: 768px) {
text-align: left;
.icons {
margin-top: 0;
text-align: right;
}
}
}
// Individual section styling.
.section-timeline, .section-components, .section-metrics, .section-scheduled {
margin-top: 40px;
}
}

View File

@@ -1,19 +1,12 @@
@import "palette";
$ionicons-font-path: "../../../fonts" !default;
@import "./vendor/bower_components/ionicons/scss/ionicons";
@import "../bower_components/ionicons/scss/ionicons";
@import "modules/bootstrap";
html {
position: relative;
min-height: 100%;
-webkit-font-smoothing: antialiased;
}
body {
margin-bottom: 60px;
padding-bottom: 60px;
html, body {
height: 100%;
}
@import "helpers";
@@ -22,9 +15,6 @@ body {
@import "modules/tabs";
@import "modules/forms";
@import "modules/well";
@import "modules/alerts";
@import "modules/panels";
@import "modules/btns";
// Styles for partials
@import "partials/base";

View File

@@ -0,0 +1,52 @@
// Bootstrap variable overrides and custom variables
@import "variables";
// Core variables and mixins
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/variables";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/mixins";
// Reset and dependencies
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/normalize";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/print";
// Core CSS
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/scaffolding";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/type";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/code";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/grid";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/tables";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/forms";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/buttons";
// Components
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/component-animations";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/dropdowns";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/button-groups";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/input-groups";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/navs";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/navbar";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/breadcrumbs";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/pagination";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/pager";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/labels";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/badges";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/jumbotron";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/thumbnails";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/alerts";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/progress-bars";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/media";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/list-group";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/panels";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/responsive-embed";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/wells";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/close";
// Components w/ JavaScript
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/modals";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/tooltip";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/popovers";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/carousel";
// Utility classes
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/utilities";
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/responsive-utilities";

View File

@@ -15,7 +15,7 @@ $tooltip-bg: #333 !default;
$tooltip-opacity: .9 !default;
$base-background-color: #f1f1f1;
$base-font-family: "Helvetica Neue", "Helvetica", "Arial", sans-serif;
$base-font-family: "Open Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif;
$base-font-weight: 400;
$base-letter-spacing: 0.08em;
$base-font-size: 15px;

View File

@@ -0,0 +1,18 @@
.login {
padding-top: 90px;
}
.login .logo {
display: block;
margin: 0 auto 30px;
}
.login legend {
border: 0;
padding: 0;
width: 100%;
font-size: 24px;
font-weight: 500;
text-align: center;
margin: 0 0 30px 0;
}

View File

@@ -10,7 +10,7 @@
border-radius: 2px 2px 0 0;
margin-bottom: 20px;
.step {
@extend .col-xs-3;
@extend .col-xs-4;
padding: 20px 0;
text-align: center;
position: relative;

View File

@@ -2,7 +2,7 @@ body.dashboard {
font-family: $base-font-family;
font-weight: $base-font-weight;
font-size: $base-font-size;
// letter-spacing: $base-letter-spacing;
letter-spacing: $base-letter-spacing;
display: table;
width: 100%;
height: 100%;

View File

@@ -30,7 +30,7 @@ body.dashboard {
letter-spacing: 0.04em;
font-weight: 600;
text-transform: uppercase;
@media (min-width: $screen-sm-max) {
@media #{$screen-sm-max} {
span {
padding-right: 10px;
&:before {

View File

@@ -39,23 +39,16 @@ body.dashboard {
width: 50px;
}
}
.username-wrapper {
@extend .hidden-sm;
}
&.username {
word-break: break-all;
color: $sidebar-text-color;
.profile {
&.username {
word-break: break-all;
color: $sidebar-text-color;
}
}
}
.quick-add-incident {
@extend .text-center;
padding: 10px;
i {
@extend .visible-sm;
}
span {
@extend .hidden-sm;
}
}
ul {
clear: both;
@@ -111,14 +104,8 @@ body.dashboard {
}
}
}
& > ul > li > a {
& > span {
@extend .hidden-sm;
}
}
}
.bottom-menu-sidebar {
@extend .hidden-sm;
position: fixed;
bottom: 0;
width: 230px;
@@ -161,21 +148,34 @@ body.dashboard {
.profile .avatar img {
width: 40px;
}
.profile .username-wrapper {
@extend .hidden-sm;
}
.quick-add-incident {
.btn {
padding: 3px 6px;
}
i {
@extend .visible-sm;
font-size: 20px;
}
span {
@extend .hidden-sm;
}
}
& > ul > li > a {
text-align: center;
& > i {
font-size: 25px;
}
& > span {
@extend .hidden-sm;
}
}
}
.bottom-menu-sidebar {
@extend .hidden-sm;
}
}
}

View File

@@ -1,4 +1,4 @@
@import "./vendor/bower_components/animate-sass/animate";
@import "../../bower_components/animate-sass/animate";
body {
-webkit-backface-visibility: hidden; // Addresses a small issue in webkit: http://bit.ly/NEdoDq

View File

@@ -0,0 +1,301 @@
// Import boostrap variables including default color palette and fonts
@import "../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/_variables";
.bootstrap-datetimepicker-widget {
top: 0;
left: 0;
width: 250px;
padding: 4px;
margin-top: 1px;
z-index: 99999 !important;
border-radius: $border-radius-base;
&.timepicker-sbs {
width: 600px;
}
&.bottom {
&:before {
content: '';
display: inline-block;
border-left: 7px solid transparent;
border-right: 7px solid transparent;
border-bottom: 7px solid #ccc;
border-bottom-color: rgba(0,0,0,.2);
position: absolute;
top: -7px;
left: 7px;
}
&:after {
content: '';
display: inline-block;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 6px solid white;
position: absolute;
top: -6px;
left: 8px;
}
}
&.top {
&:before {
content: '';
display: inline-block;
border-left: 7px solid transparent;
border-right: 7px solid transparent;
border-top: 7px solid #ccc;
border-top-color: rgba(0,0,0,.2);
position: absolute;
bottom: -7px;
left: 6px;
}
&:after {
content: '';
display: inline-block;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-top: 6px solid white;
position: absolute;
bottom: -6px;
left: 7px;
}
}
& .dow {
width: 14.2857%;
}
&.pull-right {
&:before {
left: auto;
right: 6px;
}
&:after {
left: auto;
right: 7px;
}
}
>ul {
list-style-type: none;
margin: 0;
}
a[data-action] {
padding: 6px 0;
}
a[data-action]:active {
box-shadow: none;
}
.timepicker-hour, .timepicker-minute, .timepicker-second {
width: 54px;
font-weight: bold;
font-size: 1.2em;
margin: 0;
}
button[data-action] {
padding: 6px;
}
table[data-hour-format="12"] .separator {
width: 4px;
padding: 0;
margin: 0;
}
.datepicker > div {
display: none;
}
.picker-switch {
text-align: center;
}
table {
width: 100%;
margin: 0;
}
td,
th {
text-align: center;
border-radius: $border-radius-base;
}
td {
height: 54px;
line-height: 54px;
width: 54px;
&.cw {
font-size: 10px;
height: 20px;
line-height: 20px;
color: $gray-light;
}
&.day {
height: 20px;
line-height: 20px;
width: 20px;
}
&.day:hover,
&.hour:hover,
&.minute:hover,
&.second:hover {
background: $gray-lighter;
cursor: pointer;
}
&.old,
&.new {
color: $gray-light;
}
&.today {
position: relative;
&:before {
content: '';
display: inline-block;
border-left: 7px solid transparent;
border-bottom: 7px solid $btn-primary-bg;
border-top-color: rgba(0, 0, 0, 0.2);
position: absolute;
bottom: 4px;
right: 4px;
}
}
&.active,
&.active:hover {
background-color: $btn-primary-bg;
color: $btn-primary-color;
text-shadow: 0 -1px 0 rgba(0,0,0,.25);
}
&.active.today:before {
border-bottom-color: #fff;
}
&.disabled,
&.disabled:hover {
background: none;
color: $gray-light;
cursor: not-allowed;
}
span {
display: inline-block;
width: 54px;
height: 54px;
line-height: 54px;
margin: 2px 1.5px;
cursor: pointer;
border-radius: $border-radius-base;
&:hover {
background: $gray-lighter;
}
&.active {
background-color: $btn-primary-bg;
color: $btn-primary-color;
text-shadow: 0 -1px 0 rgba(0,0,0,.25);
}
&.old {
color: $gray-light;
}
&.disabled,
&.disabled:hover {
background: none;
color: $gray-light;
cursor: not-allowed;
}
}
}
th {
height: 20px;
line-height: 20px;
width: 20px;
&.picker-switch {
width: 145px;
}
&.next,
&.prev {
font-size: $font-size-base * 1.5;
}
&.disabled,
&.disabled:hover {
background: none;
color: $gray-light;
cursor: not-allowed;
}
}
thead tr:first-child th {
cursor: pointer;
&:hover {
background: $gray-lighter;
}
}
}
.input-group {
&.date {
.input-group-addon span {
display: block;
cursor: pointer;
width: 16px;
height: 16px;
}
}
}
.bootstrap-datetimepicker-widget.left-oriented {
&:before {
left: auto;
right: 6px;
}
&:after {
left: auto;
right: 7px;
}
}
.bootstrap-datetimepicker-widget ul.list-unstyled li div.timepicker div.timepicker-picker table.table-condensed tbody > tr > td {
padding: 0px !important;
}
@media screen and (max-width: 767px) {
.bootstrap-datetimepicker-widget.timepicker-sbs {
width: 283px;
}
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip: rect(0,0,0,0);
border: 0;
}

View File

@@ -1,14 +1,5 @@
<?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.
*/
return [
/*
@@ -22,7 +13,7 @@ return [
|
*/
'debug' => env('APP_DEBUG', false),
'debug' => getenv('APP_DEBUG') ?: false,
/*
|--------------------------------------------------------------------------
@@ -35,7 +26,7 @@ return [
|
*/
'url' => env('APP_URL', 'http://localhost'),
'url' => 'http://localhost',
/*
|--------------------------------------------------------------------------
@@ -61,7 +52,7 @@ return [
|
*/
'locale' => env('APP_LOCALE', 'en'),
'locale' => 'en',
/*
|--------------------------------------------------------------------------
@@ -87,24 +78,9 @@ return [
|
*/
'key' => env('APP_KEY', 'SomeRandomString'),
'key' => 'kCifbUiHYswooAvSZBQjWZVY1S6aBdnD',
'cipher' => 'AES-256-CBC',
/*
|--------------------------------------------------------------------------
| Logging Configuration
|--------------------------------------------------------------------------
|
| Here you may configure the log settings for your application. Out of
| the box, Laravel uses the Monolog PHP logging library. This gives
| you a variety of powerful log handlers / formatters to utilize.
|
| Available Settings: "single", "daily", "syslog", "errorlog"
|
*/
'log' => env('LOGGING_MODE', 'daily'),
'cipher' => MCRYPT_RIJNDAEL_128,
/*
|--------------------------------------------------------------------------
@@ -124,23 +100,24 @@ return [
*/
'Illuminate\Foundation\Providers\ArtisanServiceProvider',
'Illuminate\Auth\AuthServiceProvider',
'Illuminate\Broadcasting\BroadcastServiceProvider',
'Illuminate\Bus\BusServiceProvider',
'Illuminate\Cache\CacheServiceProvider',
'Illuminate\Session\CommandsServiceProvider',
'Illuminate\Foundation\Providers\ConsoleSupportServiceProvider',
'Illuminate\Routing\ControllerServiceProvider',
'Illuminate\Cookie\CookieServiceProvider',
'Illuminate\Database\DatabaseServiceProvider',
'Illuminate\Encryption\EncryptionServiceProvider',
'Illuminate\Filesystem\FilesystemServiceProvider',
'Illuminate\Foundation\Providers\FoundationServiceProvider',
'Illuminate\Hashing\HashServiceProvider',
'Illuminate\Html\HtmlServiceProvider',
'Illuminate\Log\LogServiceProvider',
'Illuminate\Mail\MailServiceProvider',
'Illuminate\Database\MigrationServiceProvider',
'Illuminate\Pagination\PaginationServiceProvider',
'Illuminate\Pipeline\PipelineServiceProvider',
'Illuminate\Queue\QueueServiceProvider',
'Illuminate\Redis\RedisServiceProvider',
'Illuminate\Auth\Passwords\PasswordResetServiceProvider',
'Illuminate\Auth\Reminders\ReminderServiceProvider',
'Illuminate\Database\SeedServiceProvider',
'Illuminate\Session\SessionServiceProvider',
'Illuminate\Translation\TranslationServiceProvider',
'Illuminate\Validation\ValidationServiceProvider',
@@ -149,11 +126,9 @@ return [
/*
* Packages Service Providers...
*/
'AltThree\Emoji\EmojiServiceProvider',
'Barryvdh\Cors\CorsServiceProvider',
'Fideloper\Proxy\TrustedProxyServiceProvider',
'Dingo\Api\Provider\ApiServiceProvider',
'Fideloper\Proxy\ProxyServiceProvider',
'GrahamCampbell\Binput\BinputServiceProvider',
'GrahamCampbell\Exceptions\ExceptionsServiceProvider',
'GrahamCampbell\Markdown\MarkdownServiceProvider',
'GrahamCampbell\Security\SecurityServiceProvider',
'GrahamCampbell\Throttle\ThrottleServiceProvider',
@@ -161,19 +136,36 @@ return [
'McCool\LaravelAutoPresenter\LaravelAutoPresenterServiceProvider',
'PragmaRX\Google2FA\Vendor\Laravel\ServiceProvider',
'Roumen\Feed\FeedServiceProvider',
'Thujohn\Rss\RssServiceProvider',
/*
* Application Service Providers...
*/
'CachetHQ\Cachet\Providers\AppServiceProvider',
'CachetHQ\Cachet\Providers\ComposerServiceProvider',
'CachetHQ\Cachet\Providers\ConfigServiceProvider',
'CachetHQ\Cachet\Providers\AuthServiceProvider',
'CachetHQ\Cachet\Providers\ConsoleServiceProvider',
'CachetHQ\Cachet\Providers\EventServiceProvider',
'CachetHQ\Cachet\Providers\RouteServiceProvider',
'CachetHQ\Cachet\Providers\RepositoryServiceProvider',
'CachetHQ\Cachet\Providers\RoutingServiceProvider',
'CachetHQ\Cachet\Providers\ViewComposerServiceProvider',
'CachetHQ\Cachet\Providers\LoadConfigServiceProvider',
'CachetHQ\Cachet\Providers\SettingsServiceProvider',
'CachetHQ\Cachet\Providers\SegmentApiServiceProvider',
'CachetHQ\Segment\SegmentServiceProvider',
],
/*
|--------------------------------------------------------------------------
| Service Provider Manifest
|--------------------------------------------------------------------------
|
| The service provider manifest is used by Laravel to lazy load service
| providers which are not needed for each request, as well to keep a
| list of all of the services. Here, you may set its storage spot.
|
*/
'manifest' => storage_path().'/meta',
/*
|--------------------------------------------------------------------------
| Class Aliases
@@ -187,41 +179,17 @@ return [
'aliases' => [
'App' => 'Illuminate\Support\Facades\App',
'Artisan' => 'Illuminate\Support\Facades\Artisan',
'Auth' => 'Illuminate\Support\Facades\Auth',
'Blade' => 'Illuminate\Support\Facades\Blade',
'Bus' => 'Illuminate\Support\Facades\Bus',
'Cache' => 'Illuminate\Support\Facades\Cache',
'Config' => 'Illuminate\Support\Facades\Config',
'Cookie' => 'Illuminate\Support\Facades\Cookie',
'Crypt' => 'Illuminate\Support\Facades\Crypt',
'DB' => 'Illuminate\Support\Facades\DB',
'Eloquent' => 'Illuminate\Database\Eloquent\Model',
'Event' => 'Illuminate\Support\Facades\Event',
'File' => 'Illuminate\Support\Facades\File',
'Hash' => 'Illuminate\Support\Facades\Hash',
'Input' => 'Illuminate\Support\Facades\Input',
'Inspiring' => 'Illuminate\Foundation\Inspiring',
'Lang' => 'Illuminate\Support\Facades\Lang',
'Log' => 'Illuminate\Support\Facades\Log',
'Mail' => 'Illuminate\Support\Facades\Mail',
'Password' => 'Illuminate\Support\Facades\Password',
'Queue' => 'Illuminate\Support\Facades\Queue',
'Redirect' => 'Illuminate\Support\Facades\Redirect',
'Redis' => 'Illuminate\Support\Facades\Redis',
'Request' => 'Illuminate\Support\Facades\Request',
'Response' => 'Illuminate\Support\Facades\Response',
'Route' => 'Illuminate\Support\Facades\Route',
'Schema' => 'Illuminate\Support\Facades\Schema',
'Session' => 'Illuminate\Support\Facades\Session',
'Storage' => 'Illuminate\Support\Facades\Storage',
'URL' => 'Illuminate\Support\Facades\URL',
'Validator' => 'Illuminate\Support\Facades\Validator',
'View' => 'Illuminate\Support\Facades\View',
'Setting' => 'CachetHQ\Cachet\Facades\Setting',
'Str' => 'Illuminate\Support\Str',
'App' => 'Illuminate\Support\Facades\App',
'Auth' => 'Illuminate\Support\Facades\Auth',
'Form' => 'Illuminate\Support\Facades\Form',
'Input' => 'Illuminate\Support\Facades\Input',
'Redirect' => 'Illuminate\Support\Facades\Redirect',
'Request' => 'Illuminate\Support\Facades\Request',
'Response' => 'Illuminate\Support\Facades\Response',
'Route' => 'Illuminate\Support\Facades\Route',
'Session' => 'Illuminate\Support\Facades\Session',
'Setting' => 'CachetHQ\Cachet\Facades\Setting',
'Str' => 'Illuminate\Support\Str',
],

View File

@@ -1,14 +1,5 @@
<?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.
*/
return [
/*
@@ -54,23 +45,27 @@ return [
/*
|--------------------------------------------------------------------------
| Password Reset Settings
| Password Reminder Settings
|--------------------------------------------------------------------------
|
| Here you may set the options for resetting passwords including the view
| that is your password reset e-mail. You can also set the name of the
| table that maintains all of the reset tokens for your application.
| Here you may set the settings for password reminders, including a view
| that should be used as your password reminder e-mail. You will also
| be able to set the name of the table that holds the reset tokens.
|
| The expire time is the number of minutes that the reset token should be
| The "expire" time is the number of minutes that the reminder should be
| considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed.
|
*/
'password' => [
'email' => 'emails.password',
'table' => 'password_resets',
'reminder' => [
'email' => 'emails.auth.reminder',
'table' => 'password_reminders',
'expire' => 60,
],
];

89
app/config/cache.php Normal file
View File

@@ -0,0 +1,89 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Cache Driver
|--------------------------------------------------------------------------
|
| This option controls the default cache "driver" that will be used when
| using the Caching library. Of course, you may use other drivers any
| time you wish. This is the default when another is not specified.
|
| Supported: "file", "database", "apc", "memcached", "redis", "array"
|
*/
'driver' => getenv('CACHE_DRIVER') ?: 'apc',
/*
|--------------------------------------------------------------------------
| File Cache Location
|--------------------------------------------------------------------------
|
| When using the "file" cache driver, we need a location where the cache
| files may be stored. A sensible default has been specified, but you
| are free to change it to any other place on disk that you desire.
|
*/
'path' => storage_path().'/cache',
/*
|--------------------------------------------------------------------------
| Database Cache Connection
|--------------------------------------------------------------------------
|
| When using the "database" cache driver you may specify the connection
| that should be used to store the cached items. When this option is
| null the default database connection will be utilized for cache.
|
*/
'connection' => null,
/*
|--------------------------------------------------------------------------
| Database Cache Table
|--------------------------------------------------------------------------
|
| When using the "database" cache driver we need to know the table that
| should be used to store the cached items. A default table name has
| been provided but you're free to change it however you deem fit.
|
*/
'table' => 'cache',
/*
|--------------------------------------------------------------------------
| Memcached Servers
|--------------------------------------------------------------------------
|
| Now you may specify an array of your Memcached servers that should be
| used when utilizing the Memcached cache driver. All of the servers
| should contain a value for "host", "port", and "weight" options.
|
*/
'memcached' => [
['host' => '127.0.0.1', 'port' => 11211, 'weight' => 100],
],
/*
|--------------------------------------------------------------------------
| Cache Key Prefix
|--------------------------------------------------------------------------
|
| When utilizing a RAM based store such as APC or Memcached, there might
| be other applications utilizing the same cache. So, we'll specify a
| value to get prefixed to all our keys so we can avoid collisions.
|
*/
'prefix' => 'laravel',
];

16
app/config/compile.php Normal file
View File

@@ -0,0 +1,16 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Additional Compiled Classes
|--------------------------------------------------------------------------
|
| Here you may specify additional classes to include in the compiled file
| generated by the `artisan optimize` command. These should be classes
| that are included on basically every request into the application.
|
*/
];

View File

@@ -1,14 +1,5 @@
<?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.
*/
return [
/*
@@ -35,7 +26,7 @@ return [
|
*/
'default' => env('DB_DRIVER', 'sqlite'),
'default' => getenv('DB_DRIVER') ?: 'sqlite',
/*
|--------------------------------------------------------------------------
@@ -57,40 +48,39 @@ return [
'sqlite' => [
'driver' => 'sqlite',
'database' => env('DB_HOST', storage_path().'/database.sqlite'),
'database' => app_path('database').'/'.getenv('DB_DATABASE') ?: null,
'prefix' => '',
],
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', null),
'database' => env('DB_DATABASE', null),
'username' => env('DB_USERNAME', null),
'password' => env('DB_PASSWORD', null),
'host' => getenv('DB_HOST') ?: null,
'database' => getenv('DB_DATABASE') ?: null,
'username' => getenv('DB_USERNAME') ?: null,
'password' => getenv('DB_PASSWORD') ?: null,
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
],
'pgsql' => [
'driver' => 'pgsql',
'host' => env('DB_HOST', null),
'database' => env('DB_DATABASE', null),
'username' => env('DB_USERNAME', null),
'password' => env('DB_PASSWORD', null),
'charset' => 'utf8',
'prefix' => '',
'schema' => 'public',
'driver' => 'pgsql',
'host' => getenv('DB_HOST') ?: null,
'database' => getenv('DB_DATABASE') ?: null,
'username' => getenv('DB_USERNAME') ?: null,
'password' => getenv('DB_PASSWORD') ?: null,
'charset' => 'utf8',
'prefix' => '',
'schema' => 'public',
],
'sqlsrv' => [
'driver' => 'sqlsrv',
'host' => env('DB_HOST', null),
'database' => env('DB_DATABASE', null),
'username' => env('DB_USERNAME', null),
'password' => env('DB_PASSWORD', null),
'prefix' => '',
'driver' => 'sqlsrv',
'host' => getenv('DB_HOST') ?: null,
'database' => getenv('DB_DATABASE') ?: null,
'username' => getenv('DB_USERNAME') ?: null,
'password' => getenv('DB_PASSWORD') ?: null,
'prefix' => '',
],
],
@@ -124,9 +114,9 @@ return [
'cluster' => false,
'default' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'port' => env('REDIS_PORT', 6379),
'database' => env('REDIS_DATABASE', 0),
'host' => '127.0.0.1',
'port' => 6379,
'database' => 0,
],
],

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