Compare commits

...

643 Commits
0.1 ... 1.2

Author SHA1 Message Date
Graham Campbell
2311d67624 Updated dependencies 2015-09-04 15:01:16 +01:00
Graham Campbell
715d65f464 Laravel fixes 2015-09-04 14:44:48 +01:00
Graham Campbell
1ac4b7a64a Updated dependencies 2015-09-04 11:45:44 +01:00
Graham Campbell
941809037a Lock on laravel 5.1.12 2015-09-04 11:33:14 +01:00
Graham Campbell
0b8ce37e84 Merge pull request #935 from cachethq/fix-scheduled-items-timeline
Fixes #934 - Scheduled items now drop into the right days
2015-09-04 11:11:51 +01:00
James Brooks
0851427f2d Fixes #934 - Scheduled items now drop into the right days 2015-09-04 08:18:10 +01:00
Graham Campbell
860457bfae Rebuilt css 2015-08-18 16:37:47 +01:00
Graham Campbell
9112e2a58f Updated dependencies 2015-08-18 16:17:24 +01:00
James Brooks
b1600bdbee Update dependencies 2015-08-14 23:25:25 +01:00
Graham Campbell
2ef8b8411f Bumped min versions 2015-08-14 23:20:54 +01:00
James Brooks
a55bcb8c48 Update dependencies 2015-08-14 22:37:54 +01:00
James Brooks
5c8369344d Always use HTTPS for Google Fonts 2015-08-13 23:06:57 +01:00
Graham Campbell
8589089a04 Updated dependencies 2015-08-09 19:20:19 +01:00
Graham Campbell
324f8703ce Removed old docker files 2015-08-08 17:38:09 +01:00
Graham Campbell
9df14837b9 Updated phpunit 2015-08-08 17:37:25 +01:00
James Brooks
e3a3f97957 Condensed the readme further 2015-08-08 17:31:44 +01:00
James Brooks
fbfa62d087 Show y axis labels in metrics. Closes #824 2015-08-08 17:31:18 +01:00
James Brooks
1c7fb1a434 Merge pull request #887 from cachethq/api-request-sort
Added the ability to sort and order API results
2015-08-08 12:58:11 +01:00
Graham Campbell
02f069cdc1 Backport all readme changes 2015-08-07 12:14:38 +01:00
James Brooks
1779ac40c9 Added the ability to sort and order API results. Closes #756 2015-08-07 12:08:25 +01:00
Graham Campbell
e8d3c013a1 Merge pull request #883 from cachethq/removals
Remove docker/homestead/vagrant stuff
2015-08-07 12:04:48 +01:00
Graham Campbell
85efb7d114 Updated lock file 2015-08-07 11:59:42 +01:00
Graham Campbell
11d77328dc Remove docker/homestead/vagrant stuff 2015-08-07 11:59:37 +01:00
Graham Campbell
c05e9d9867 Updated phpunit 2015-08-07 11:56:15 +01:00
Graham Campbell
f9f2e5c18a Bumped version 2015-08-06 21:51:31 +01:00
Graham Campbell
2ac9d3b23e Updated dependencies 2015-08-06 20:00:53 +01:00
Graham Campbell
848fb3b607 Rebuilt css 2015-08-06 20:00:38 +01:00
Graham Campbell
7d21a7682c Updated elixir 2015-08-06 20:00:31 +01:00
Graham Campbell
e3c38c7461 Updated emoji package 2015-08-06 20:00:22 +01:00
James Brooks
8dd762184e Update CONTRIBUTING.md 2015-08-05 08:47:09 +01:00
Graham Campbell
578d4befef Fixed typo 2015-08-03 22:00:49 +01:00
Graham Campbell
549c4e1594 Fixed seeder 2015-08-03 21:49:45 +01:00
Graham Campbell
60536d5334 Fixed typos 2015-08-03 21:06:56 +01:00
Graham Campbell
ef3c32c5e9 Updated the readme 2015-08-03 18:43:55 +01:00
Graham Campbell
11cf7ef2c8 Merge pull request #865 from n0mer/patch-1
doc update - how to install Predis dependency
2015-08-03 18:42:10 +01:00
Graham Campbell
ca367ff151 Removed duplicate service provider entry 2015-08-03 18:40:46 +01:00
Nikolay Gorylenko
06ecb4b9fb Update README.md 2015-08-03 17:32:51 +02:00
Nikolay Gorylenko
122138402b doc update - how to install Predis dependency 2015-08-03 16:52:38 +02:00
Graham Campbell
14ec134ac1 Updated dependencies 2015-08-03 14:46:03 +01:00
Graham Campbell
ea0a8dfcff Updated dependencies 2015-08-03 14:28:25 +01:00
Graham Campbell
6cd10581e4 Removed incorrect php-cs-fixer config 2015-08-03 14:26:15 +01:00
Graham Campbell
90baf18724 Backport all fixes from the master to 1.1 2015-08-03 14:23:46 +01:00
Graham Campbell
5bdbc87bf2 Merge pull request #863 from cachethq/1.1-throttling
Fixed login throttling
2015-08-03 14:16:21 +01:00
Graham Campbell
60c7235d94 Merge pull request #864 from n0mer/patch-1
make 'cron' available in docker container
2015-08-03 13:53:26 +01:00
Nikolay Gorylenko
2c8cd19137 make 'cron' available in docker container 2015-08-03 14:47:06 +02:00
Graham Campbell
c1d53a7b42 Fixed login throttling 2015-08-03 13:37:16 +01:00
James Brooks
22b0e105ee Fix showing of verified subscribers when they're not. Fixes #855 2015-08-03 12:37:49 +01:00
James Brooks
c7b55401d4 Casts the subscriber 2015-08-03 12:37:49 +01:00
James Brooks
167b90265f Remove deleted_at as a date field 2015-08-03 12:37:48 +01:00
Graham Campbell
bb71d0175f Merge pull request #861 from n0mer/1.1
do not evaluate LOGGING_MODE and APP_LOCALE during build phase
2015-08-03 12:37:32 +01:00
Nikolay Gorylenko
f964c03072 ≈do not evaluate LOGGING_MODE and APP_LOCALE during build phase; fix path for contab 2015-08-03 11:32:30 +02:00
Graham Campbell
46c43a8b82 Merge pull request #854 from n0mer/1.1
cron tweaks
2015-08-02 22:02:20 +01:00
Nikolay Gorylenko
ee7a0ec5f2 proper command to add file 2015-08-02 12:58:28 +02:00
Nikolay Gorylenko
427c8d24a5 add user to crontab 2015-08-02 12:57:12 +02:00
Nikolay Gorylenko
60e6d99b95 do not daemonize cron 2015-08-02 12:49:15 +02:00
James Brooks
18db70b9cd Merge pull request #853 from n0mer/1.1
add cron config
2015-08-02 11:06:46 +01:00
Nikolay Gorylenko
3a73a9be5c add cron config 2015-08-02 12:04:10 +02:00
James Brooks
fb933720fc Merge pull request #852 from n0mer/1.1
externalize logging mode and app locale
2015-08-02 11:04:07 +01:00
Nikolay Gorylenko
a4ce37f29a add cron to supervisor 2015-08-02 11:55:44 +02:00
Nikolay Gorylenko
4f3664b3e0 externalize logging mode and app locale 2015-08-02 11:15:49 +02:00
Graham Campbell
c46c255722 Merge pull request #847 from cachethq/eager-load-metric-points
Eager load the metric points.
2015-08-01 21:01:10 +01:00
James Brooks
971a422258 Fix docblock 2015-08-01 20:41:57 +01:00
James Brooks
b6de8bf258 Eager load the metric points. 2015-08-01 20:16:58 +01:00
James Brooks
573a301957 Merge pull request #846 from cachethq/unsubscribe-fix
Fix the token sent to unsubscribe
2015-08-01 20:11:51 +01:00
Joseph Cohen
d8323f126c Fix the token sent to unsubscribe 2015-08-01 14:08:14 -05:00
James Brooks
e6db90a798 Merge pull request #844 from cachethq/tracking
Removed tracking
2015-08-01 19:16:18 +01:00
Graham Campbell
9d9bec812d Updated lock file 2015-08-01 17:14:20 +01:00
Graham Campbell
c9b3760a4d CS fix 2015-08-01 17:09:51 +01:00
Graham Campbell
fb127fb861 Removed tracking 2015-08-01 17:07:06 +01:00
Graham Campbell
2425682381 Removed other areas where the word status is appended 2015-08-01 16:45:58 +01:00
Graham Campbell
da1c999ca6 Merge pull request #840 from 5apps/do_not_append_status_to_app_name
Do not append "Status" to the site name
2015-08-01 16:44:35 +01:00
Graham Campbell
79aa78cff5 Fixed segment references 2015-08-01 16:37:27 +01:00
Graham Campbell
4438142348 Updated dependencies 2015-08-01 12:29:09 +01:00
Graham Campbell
e917e338cd Rebuilt css 2015-08-01 12:27:16 +01:00
James Brooks
da22fa208a Merge pull request #842 from n0mer/patch-1
get rid of hard-coded 'file' cache driver
2015-07-31 20:51:45 +01:00
Nikolay Gorylenko
2cb1d9e07d get rid of hard-coded 'file' cache driver 2015-07-31 12:14:25 +02:00
Greg Karékinian
68c458227f Do not append "Status" to the site name
Currently the title of the index is the site name set in the settings is
appended with "Status". This is confusing because the RSS feeds show
the site name without it (and you probably want to write "Status" in the site
name yourself anyway).
2015-07-31 10:08:37 +02:00
James Brooks
043690764d Merge pull request #831 from n0mer/master
#805 for setup UI
2015-07-29 11:05:28 +01:00
James Brooks
845d9e1e14 Remove Cachet logo from the sidebar for now. Closes #830 2015-07-28 22:19:01 +01:00
Nikolay Gorylenko
68572db6d2 do not ignore IntelliJ files 2015-07-28 22:55:08 +02:00
Nikolay Gorylenko
5d7b05d857 ignore IntelliJ files 2015-07-28 22:29:43 +02:00
Nikolay Gorylenko
9eb65eba3b add 'redis' and 'memcached' to setup step #1 2015-07-28 22:25:59 +02:00
James Brooks
17492b0dcf Merge pull request #829 from n0mer/master
cfg for #826 - typo fix
2015-07-28 19:19:52 +01:00
Nikolay Gorylenko
0f8773a547 cfg for #826 - typo fix 2015-07-28 20:01:16 +02:00
James Brooks
45f376e564 Added a way to hide the dashboard button from the footer (default) 2015-07-28 16:19:47 +01:00
James Brooks
3a44e4a809 Fixes #828 - Don't call format on a formatted string 2015-07-28 16:09:35 +01:00
James Brooks
fea555f2b0 Merge pull request #827 from n0mer/master
cfg for #826
2015-07-28 12:00:28 +01:00
Nikolay Gorylenko
9094f37156 cfg for #826 2015-07-28 12:58:22 +02:00
James Brooks
0e502ed53b Default to production 2015-07-27 22:28:52 +01:00
Graham Campbell
7f0c2a772d Don't encode the metric name either 2015-07-27 19:37:59 +01:00
James Brooks
e06688aee5 Fixes #822 - Don't encode entities in metric tooltips 2015-07-27 19:31:37 +01:00
Graham Campbell
bfe2b6ca48 Elixir fixes 2015-07-26 22:56:45 +01:00
Graham Campbell
7e663d7a76 Updated dependencies 2015-07-26 22:56:29 +01:00
Graham Campbell
65fe410a93 Fixed the default debug setting 2015-07-26 10:26:13 +01:00
James Brooks
c747f11f3c Merge pull request #818 from cachethq/elixir-three
Elixir 3
2015-07-25 19:20:03 +01:00
James Brooks
9065b7dccc Re-compile assets with Elixir 3 2015-07-25 19:17:37 +01:00
James Brooks
7727dbf33b Upgrade to Elixir 3 - closes #817 2015-07-25 19:17:30 +01:00
Graham Campbell
2868f9e052 Rebuilt css 2015-07-25 16:06:35 +01:00
Graham Campbell
aab2b1fe6e Updated dependencies 2015-07-25 16:06:30 +01:00
Graham Campbell
1e4a8c8143 Added emoji parsing support 2015-07-25 16:02:35 +01:00
Graham Campbell
e002d596b1 Updated markdown package 2015-07-25 15:56:03 +01:00
Graham Campbell
1e3e1df616 Removed overkill test 2015-07-25 15:48:10 +01:00
Graham Campbell
6e3d1af85a Updated lock file 2015-07-25 13:31:03 +01:00
Graham Campbell
e91cf591ea Updated exceptions package 2015-07-25 13:30:58 +01:00
Graham Campbell
14bbe69509 Tweaked dev dependencies 2015-07-25 13:24:05 +01:00
James Brooks
c328575417 Merge pull request #802 from cachethq/subscriber-api
Subscriber API
2015-07-24 20:44:59 +01:00
James Brooks
ecb3a4e1d9 Remove unused import 2015-07-24 14:37:06 +01:00
James Brooks
71f5de8726 Introduce the Subscriber API. Closes #787 2015-07-24 14:35:31 +01:00
James Brooks
38257c6ae6 Merge pull request #814 from andygrunwald/composer-vagrant-note
Add small note to README that a composer install needs to be executed before a vagrant up
2015-07-24 14:27:10 +01:00
Graham Campbell
6802609ce6 Removed old package 2015-07-24 14:15:35 +01:00
Graham Campbell
476adef1b0 Fixed cipher 2015-07-24 14:13:48 +01:00
Andy Grunwald
3a83110f50 Add small note to README that a composer install needs to be executed before a vagrant up 2015-07-24 14:53:36 +02:00
Graham Campbell
8c4832343d Added missing config in the tests 2015-07-24 13:53:31 +01:00
James Brooks
a0d354c3e9 Configure Redis through environment variables. Closes #805 2015-07-23 21:47:49 +01:00
James Brooks
02cb04d36f Catch generic exception to prevent Segment from breaking everything 2015-07-23 21:37:32 +01:00
Graham Campbell
07861dd245 Updated dependencies 2015-07-23 17:08:56 +01:00
Graham Campbell
14ac707d76 Rebuilt assets 2015-07-23 17:07:50 +01:00
James Brooks
0fba574f5b Update dependencies 2015-07-14 13:59:19 +01:00
James Brooks
71c30fb0bd Update email template design. 2015-07-14 13:59:15 +01:00
James Brooks
bf77fbdd33 Merge pull request #800 from cachethq/email-link
Make subscriber verify link clickable
2015-07-11 16:17:20 +01:00
James Brooks
6336bd8905 Update dependencies 2015-07-11 16:17:08 +01:00
James Brooks
dbbf4a093e Fix formatting of Blade 2015-07-11 16:15:48 +01:00
Joseph Cohen
5190578da9 Make subscriber link clickable 2015-07-10 13:08:35 -05:00
James Brooks
c5f3655d49 Merge pull request #782 from chaseconey/dashboard-sidebar-css-fix-v2
Dashboard - Active Menu Item CSS Fix v2
2015-07-09 14:59:40 +01:00
Chase Coney
721df30642 Fix sidebar formatting 2015-07-09 08:53:02 -05:00
Chase Coney
b79c8902fc Fix sidebar styling. Escape classes input 2015-07-09 08:49:52 -05:00
Chase Coney
bcc72d224f Fixes the set_active menu helper to no longer double quote class name 2015-07-09 08:07:30 -05:00
James Brooks
679005fe3f Merge pull request #776 from chaseconey/subscriber-list-759
Subscriber Administration
2015-07-09 09:18:39 +01:00
James Brooks
4990868d9a Merge pull request #779 from chaseconey/add-vagrant-homestead-support
Add support for Vagrant/Homestead
2015-07-09 07:01:29 +01:00
James Brooks
a7a4fe03e4 Merge pull request #792 from rtrauntvein/patch-1
fixing codestyle docker entrypoint.sh
2015-07-09 06:58:29 +01:00
Ryan Trauntvein
c2678ea89c fixing codestyle docker entrypoint.sh 2015-07-08 20:15:30 -07:00
Chase Coney
f1bbf0200c Use specific version for laravel/homestead 2015-07-08 17:04:49 -05:00
Chase Coney
1a5155dbc5 Add support for Vagrant/Homestead 2015-07-08 17:02:52 -05:00
Chase Coney
7e14d6d25f Fixes #759. First pass at subscriber administration 2015-07-08 16:43:41 -05:00
Graham Campbell
b003a7aa1c Updated flysystem 2015-07-08 21:59:04 +01:00
James Brooks
2c5549120b Merge pull request #788 from rtrauntvein/new-docker-env
Use the Cachet .env file inside of docker image
2015-07-07 22:11:59 +01:00
Graham Campbell
6a29b306e2 Tweak scripts 2015-07-07 11:26:21 +01:00
Graham Campbell
f01849f758 Updated lock file 2015-07-07 10:58:45 +01:00
Graham Campbell
f592aa08c9 Bumped branch alias 2015-07-07 10:57:36 +01:00
Graham Campbell
691e6fffe7 Updated scripts 2015-07-07 10:57:29 +01:00
Ryan Trauntvein
dbda00cef8 Use .env file with docker image 2015-07-06 23:59:08 -07:00
Graham Campbell
408141dd8b Fixed typos 2015-07-06 19:22:49 +01:00
Graham Campbell
9b43b42e27 Removed extra HQ 2015-07-06 18:46:27 +01:00
Graham Campbell
83955fcff5 CS fix 2015-07-06 18:26:21 +01:00
Graham Campbell
bf05197c4f Cleanup exception handling
You're going to love this @joecohens and @jbrooksuk :)
2015-07-06 18:21:23 +01:00
Graham Campbell
a72543daa2 Updated dependencies 2015-07-06 18:19:27 +01:00
Graham Campbell
cbf888d7b7 We definitely don't want the symfony level here 2015-07-06 17:47:46 +01:00
Graham Campbell
0a321bffd8 Updated copyright information 2015-07-06 17:37:01 +01:00
Graham Campbell
f74f44048d Fixes 2015-07-05 15:40:48 +01:00
Graham Campbell
78567f865a Updated trusted proxies 2015-07-05 12:54:45 +01:00
Graham Campbell
de9240d295 Updated dependencies 2015-07-05 11:52:03 +01:00
Graham Campbell
a3235f78d0 Updated scripts 2015-07-05 11:52:03 +01:00
James Brooks
3da8f3065c Added array to cache drivers 2015-07-04 22:19:24 +01:00
Graham Campbell
39091b51b5 Fix 2015-07-04 21:49:09 +01:00
James Brooks
e250d5e3fe Don't optimize any files 2015-07-04 21:46:12 +01:00
James Brooks
8ed0f17761 Remove commented out sidebar item 2015-07-03 10:33:32 +01:00
James Brooks
92caf08d1d Merge pull request #781 from chaseconey/sidebar-css-active-fix
Dashboard - Active Menu Item CSS Fix
2015-07-02 19:27:09 +01:00
James Brooks
1e6db61066 Re-compile without duplicate ionicons css? 2015-07-02 19:20:55 +01:00
Chase Coney
13e5ee548d Fixes the set_active menu helper to no longer double quote class name 2015-07-02 13:20:51 -05:00
Graham Campbell
3d328663d5 Updated dependencies 2015-07-02 17:23:32 +01:00
James Brooks
fafcc8880b Fix CS 2015-07-02 16:46:14 +01:00
James Brooks
7a283dceb7 $pageTitle needs to be snake_case too 2015-07-02 16:40:38 +01:00
James Brooks
c1a0fc10ae Use snake_case in views. Closes #778 2015-07-02 16:37:38 +01:00
James Brooks
13180cf77d Remove Piwik from settings seeder 2015-07-01 21:44:58 +01:00
James Brooks
903da245ef Fix Blade standards 2015-07-01 21:22:00 +01:00
James Brooks
939766bf7d Merge pull request #775 from chaseconey/fix-storage-engine-768
Set default database engine in migrations
2015-06-30 18:48:40 +01:00
Chase Coney
977cac091c Fix spacing issue. 2015-06-30 11:35:34 -05:00
Chase Coney
04161678b6 Fixes 768. php artisan migrate will work regardless of mysql version or default_database_engine. 2015-06-30 09:53:29 -05:00
Graham Campbell
793564e0c0 Updated dependencies 2015-06-27 15:07:31 +01:00
James Brooks
ea89254bf6 Fix transparency and algorithm for calculating severity icon 2015-06-27 14:03:24 +01:00
James Brooks
54011d7635 Update alert icons to match logo, with colours 2015-06-27 13:40:24 +01:00
James Brooks
62a71554c6 Merge pull request #752 from DivineOmega/dynamic_favicon
Dynamic favicon
2015-06-27 13:37:46 +01:00
James Brooks
e92dd0151a Update to Bootstrap 3.3.5 2015-06-27 09:58:55 +01:00
Graham Campbell
0a2f7659aa Updated dependencies 2015-06-26 00:41:16 +01:00
Graham Campbell
c0f19093e4 Updated dependencies 2015-06-25 14:51:14 +01:00
James Brooks
e858a288a6 Replace Gitter badge with CrowdIn % 2015-06-25 14:33:57 +01:00
James Brooks
d20f2cbbc8 Don't use teal for break element 2015-06-25 14:25:03 +01:00
James Brooks
902d7bd01b Fix #765 2015-06-25 08:45:01 +01:00
Graham Campbell
19d780325e Removed old config 2015-06-24 21:36:55 +01:00
Graham Campbell
b6a6acec4d Updated dependencies 2015-06-24 21:16:45 +01:00
Graham Campbell
e28a08f6bb Updated assets 2015-06-24 20:37:22 +01:00
Graham Campbell
0d8a3b4efc Updated dependencies 2015-06-24 20:37:13 +01:00
Graham Campbell
7db305edcc Cleanup tests 2015-06-24 20:16:46 +01:00
James Brooks
74ceb9885b Merge pull request #764 from cachethq/update-logo
Update logo to drop the HQ
2015-06-24 20:04:19 +01:00
James Brooks
d6617b6971 Fix logo proportions 2015-06-24 20:03:22 +01:00
James Brooks
c28ba2dfb8 Update dependencies 2015-06-24 19:58:57 +01:00
James Brooks
e794aedb3a Update logo to drop the HQ 2015-06-24 19:58:47 +01:00
James Brooks
2fa2ff9070 Fix CS on language files and add copyright header 2015-06-23 15:46:37 +01:00
Graham Campbell
0f187b323b Fixed travis file 2015-06-23 15:38:44 +01:00
James Brooks
00a480b98b Remove PHP7 tests as it's disabled in composer 2015-06-23 15:38:03 +01:00
James Brooks
69f213a4dc Merge pull request #760 from wfjsw/master
Update Chinese lang. Closes #758
2015-06-23 15:37:13 +01:00
jsw
cef5c9b1e2 Update Chinese lang. Closes #758 2015-06-23 22:00:05 +08:00
DivineOmega
0ca1668518 Initial dynamic favicon code
Syntax and logic fixes

New favicons

Contribution Guidelines

Removed trailing spaces

Style tweaks

Comma

Suggested code changes

Changed high and medium alert icons to be exclamation marks protruding through a circle

Moved favicon logic to IndexComposer

Style fixes

Removed whitespace
2015-06-23 14:41:41 +01:00
James Brooks
814a6cf30b Added PHP 7 back to test suite
Allow it to fail, instead of HHVM
2015-06-23 08:52:32 +01:00
James Brooks
b0d1eaafc2 Allow HHVM to fail, also fast finish 2015-06-23 08:50:36 +01:00
James Brooks
e68467a308 Clean the value on saving of the setting 2015-06-23 08:11:39 +01:00
James Brooks
0c940adc56 Merge pull request #751 from ldidry/fix-piwik
Fix piwik missing slash problem
2015-06-23 08:09:37 +01:00
James Brooks
96dfd5d057 Merge pull request #757 from alexxwiz/master
Russian translation
2015-06-23 07:18:20 +01:00
Alexey Vasilyev
91dfa822bc Russian translation fixes 2015-06-22 23:29:27 +03:00
Alexey Vasilyev
3c5a5b49f1 Style guide fixes. 2015-06-22 18:06:07 +03:00
Alexey Vasilyev
c12d901147 Style guide fixes 2015-06-22 18:02:56 +03:00
Alexey Vasilyev
60dac4664b Russian translation 2015-06-22 17:56:41 +03:00
James Brooks
b7dc6ab503 Merge pull request #753 from fabianlaule/login-screen-fix
Fix floating of buttons on login screen & made border radius equal
2015-06-21 20:20:45 +01:00
Fabian Laule
d207a2eeeb Fix floating of buttons on login screen & made border radius equal 2015-06-21 16:39:04 +02:00
James Brooks
986fb4c588 Fix CS 2015-06-20 11:58:47 +01:00
James Brooks
5b1c7a69dd Doh. Factories are dev only. 2015-06-20 11:57:14 +01:00
James Brooks
f7b53c06f6 Improve the MetricPointSeeder show actual metrics! 2015-06-20 11:54:42 +01:00
Luc Didry
f9d831bf8a Fix piwik missing slash problem 2015-06-19 23:34:49 +02:00
James Brooks
dc85aa79c8 Merge pull request #749 from ldidry/dont-html-escape-stylesheet
Don't HTML escape custom stylesheet
2015-06-19 22:26:26 +01:00
Luc Didry
261b38b308 Don't HTML escape custom stylesheet
If you HTML escape the custom stylesheet, you can't have quotes in it.
You need quotes if you want to add something with url('foo') (in a
background-image by exemple).
2015-06-19 23:07:37 +02:00
James Brooks
05a103c47d Merge pull request #748 from cachethq/version-one
Version one.
2015-06-19 21:17:11 +01:00
James Brooks
f51fc34f6d Update readme and dependencies. 2015-06-19 21:16:04 +01:00
James Brooks
1b8e474223 Tidy up code 2015-06-19 11:59:28 +01:00
Graham Campbell
83c671c977 Ignore the dist folder 2015-06-19 11:51:47 +01:00
Graham Campbell
e13a47aecb Update .gitignore 2015-06-19 11:51:05 +01:00
James Brooks
2579b8a48e Move bower_components into vendor. Closes #747 2015-06-19 11:47:38 +01:00
Graham Campbell
9f528584f0 Updated dependencies 2015-06-19 11:16:00 +01:00
Graham Campbell
a27fe6f8ad Merge pull request #744 from cachethq/auth
Deal with 401 exceptions in a better way
2015-06-18 22:48:10 +01:00
Graham Campbell
7578b640bd Derp fix 2015-06-18 22:45:27 +01:00
Graham Campbell
e1681a7021 Deal with 401 exceptions in a better way 2015-06-18 22:37:31 +01:00
Graham Campbell
a99aa6be1f Typo fix 2015-06-18 22:36:44 +01:00
James Brooks
60f6bec8bc Don't show components div if we have no components 2015-06-18 20:50:43 +01:00
Graham Campbell
26857597f0 Merge pull request #738 from cachethq/errors
Respond with the correct responses on error
2015-06-18 20:08:18 +01:00
James Brooks
60409c14fe Merge pull request #743 from rtrauntvein/dockercompose
Add support for docker-compose
2015-06-18 20:07:30 +01:00
Ryan Trauntvein
da2eab97aa Add support for docker-compose 2015-06-18 11:18:00 -07:00
James Brooks
8ab422143d Merge pull request #731 from amondnet/master
add Korean translation
2015-06-18 18:42:10 +01:00
Graham Campbell
14494cc74b CS fix 2015-06-18 18:18:59 +01:00
Graham Campbell
77834fb493 Added more api tests 2015-06-18 18:15:16 +01:00
Graham Campbell
62ac2780cf Removed unneeded checks 2015-06-18 18:13:37 +01:00
Graham Campbell
2b43b83455 Added middleware to the kernel 2015-06-18 18:13:15 +01:00
Graham Campbell
ddf64cc653 Make sure we only return a response from the api if the user understands it 2015-06-18 18:13:01 +01:00
Graham Campbell
c52f0ada07 Added an acceptable middleware 2015-06-18 18:12:40 +01:00
Graham Campbell
a7effcce7a Fixed unauthorized exceptions 2015-06-18 18:12:10 +01:00
James Brooks
1df2d71285 Remove resolution 2015-06-18 17:20:51 +01:00
James Brooks
9a1e6d4549 Use bootstrap-sass 3.3.5 2015-06-18 17:19:27 +01:00
Graham Campbell
fad3ed9a51 Typo fixes 2015-06-18 17:13:49 +01:00
Graham Campbell
8c4653c18c Respond with the correct responses on error 2015-06-18 17:13:48 +01:00
Graham Campbell
0acc419bab Rebuilt css and js 2015-06-18 17:12:38 +01:00
Graham Campbell
70003c6b9c Updated npm packages 2015-06-18 17:12:25 +01:00
Graham Campbell
5a9e18a592 Removed extra resolution 2015-06-18 17:12:14 +01:00
Graham Campbell
19f21f9096 Updated dependencies 2015-06-18 17:04:32 +01:00
James Brooks
2f2c4c2557 Merge pull request #742 from blaskovicz/feat/dashboard/quick-edit
feat(views/index): add quick-update buttons for incidents
2015-06-18 16:42:54 +01:00
Zach Auclair
027b0b6363 feat(views/index): add quick-update buttons for incidents
These buttons only appear if the current user is logged in
and are similar to `resources/views/dashboard/incidents/index.blade.php`.
2015-06-18 11:40:16 -04:00
James Brooks
5d7964ea53 Fixes #739 2015-06-18 16:25:34 +01:00
James Brooks
f52f5a1c80 Check for notify setting. Also close #741 (send notification via API) 2015-06-18 16:24:10 +01:00
James Brooks
44109dd9fb Cast visible to integer 2015-06-18 16:13:02 +01:00
Graham Campbell
b91e128c72 Merge pull request #735 from cachethq/api-exceptions
Make sure only "application/*" error pages are returned from the api
2015-06-17 10:00:57 +01:00
Graham Campbell
f13e0cce2c Make sure only "application/*" error pages are returned from the api 2015-06-17 09:11:17 +01:00
James Brooks
bbb7616f93 Merge pull request #727 from Jasperswaagman/master
Remove container after initializing
2015-06-17 08:42:38 +01:00
James Brooks
4284fdbb27 Merge pull request #726 from cachethq/class-syntax
Use the ::class syntax
2015-06-16 19:42:15 +01:00
amond
c4628d4f5a fix the cs. 2015-06-17 01:43:39 +09:00
amond
a4cd730665 add Korean translation 2015-06-17 01:35:19 +09:00
James Brooks
7cd7e595f2 Downgrade bootstrap-datetimepicker 2015-06-16 15:09:49 +01:00
James Brooks
ea56ca4cec Update bootstrap-datetimepicker and fix #675 2015-06-16 14:28:26 +01:00
Jasper Swaagman
915f84fc07 Remove container after initializing 2015-06-16 11:11:04 +02:00
James Brooks
fd2401a302 Re-compile assets 2015-06-16 09:47:22 +01:00
James Brooks
259ec3d3bb Use the ::class syntax 2015-06-16 09:46:29 +01:00
Graham Campbell
abd801b69e Fixed php requirement 2015-06-16 09:41:56 +01:00
James Brooks
44481c4648 Mcrypt is no longer required 2015-06-16 09:36:11 +01:00
James Brooks
99b453bbd9 Changes to the incidents 2015-06-16 09:14:24 +01:00
James Brooks
9d879b162e Fix code standards, update language files. 2015-06-16 09:07:49 +01:00
James Brooks
49411d8568 Try not to use absolute urls 2015-06-16 08:34:53 +01:00
James Brooks
9c35554a5d Clean up the seeders 2015-06-16 08:31:00 +01:00
James Brooks
26ff4dc85a Remove class annotations 2015-06-16 08:27:31 +01:00
James Brooks
2eb4bd1e69 Remove the Service model and table. 2015-06-16 08:27:23 +01:00
James Brooks
5a8f0b3145 Fix IncidentTableSeeder 2015-06-16 08:25:48 +01:00
James Brooks
90b2fe51f8 Merge pull request #724 from cachethq/design-stuff
Update elixir and some design changes
2015-06-16 07:02:07 +01:00
Joseph Cohen
28110f5c8e Update elixir and some design changes 2015-06-15 17:17:49 -05:00
James Brooks
8573b78210 Split up sections a bit more 2015-06-15 21:47:35 +01:00
James Brooks
4f25318271 Component list changes 2015-06-15 21:42:55 +01:00
James Brooks
2669d4330e Fix bad message output 2015-06-15 20:30:35 +01:00
James Brooks
f867d22b96 Pass through app_name to the preheader locale 2015-06-15 20:22:01 +01:00
James Brooks
3bc499a093 Fix timeline stem height 2015-06-15 20:10:40 +01:00
James Brooks
538e22deff Button colour should be green too 2015-06-15 20:04:27 +01:00
James Brooks
b591cf188c Cachet is primarily green based, make login green 2015-06-15 20:01:58 +01:00
James Brooks
e71c573043 Closes #723 2015-06-15 17:39:18 +01:00
James Brooks
3f53d76d07 Added home button to subscribe page 2015-06-15 16:57:04 +01:00
James Brooks
16cb1bd545 Improve scheduled maintenance design 2015-06-15 16:55:02 +01:00
James Brooks
939ec3be23 Make scheduling use panel-info 2015-06-15 16:51:11 +01:00
James Brooks
8ab3209afb Fix sticky footer? 2015-06-15 16:50:12 +01:00
James Brooks
fa3b80e3af Easily update component status when editing incident. Closes #721 2015-06-15 16:27:42 +01:00
James Brooks
d5c4561fd1 Tidy up metric code 2015-06-15 13:37:21 +01:00
James Brooks
56802476a6 Merge pull request #722 from cachethq/metric-timestamps
Closes #519 - Allow supplying of timestamps to metric points
2015-06-15 13:16:24 +01:00
James Brooks
5c6bcae02d Closes #519 - Allow supplying of timestamps to metric points. 2015-06-15 12:59:33 +01:00
James Brooks
0076c2d561 Merge pull request #720 from ldidry/add-piwik-stats
Add piwik stats
2015-06-15 12:57:53 +01:00
Luc Didry
ca1b5f0658 Add piwik stats 2015-06-15 11:28:38 +02:00
James Brooks
1650093861 Fixes #709 2015-06-15 09:30:56 +01:00
James Brooks
0862c707d9 Merge pull request #719 from ldidry/fix-atom-description
Use HTML version of incident message in atom feed
2015-06-13 16:10:57 +01:00
Luc Didry
6d851bf9f3 Correct from StyleCI recommendations 2015-06-13 17:05:04 +02:00
Luc Didry
c0980dc7a1 Use HTML version of incident message in atom feed
Atom (not RSS) feeds are able to handle html in entry content, so it
makes sense to put HTML version of incident in it.
2015-06-13 16:57:53 +02:00
James Brooks
c471105fdd Merge pull request #718 from cachethq/new-login
Added "Login" to login page title
2015-06-13 15:37:20 +01:00
James Brooks
112a104a6b Added "Login" to login page title 2015-06-13 14:39:32 +01:00
James Brooks
5fe3520137 Merge pull request #717 from cachethq/new-login
New login screen
2015-06-13 14:37:05 +01:00
James Brooks
a36ec06b2d Merge pull request #716 from ldidry/fix-rss-language
Add lang to RSS feed for W3C validity compliance
2015-06-13 14:36:50 +01:00
James Brooks
3c5c8b0096 New login screen. 2015-06-13 14:36:02 +01:00
Luc Didry
c1fadbf0d7 Add lang to RSS feed for W3C validity compliance 2015-06-13 15:21:31 +02:00
James Brooks
37b89700a6 Merge pull request #714 from ldidry/fix-712
Fix #712 Hide .bottom-menu-sidebar on small devices
2015-06-13 10:16:10 +01:00
Luc Didry
43e75ceca1 Fix #712 Hide .bottom-menu-sidebar on small devices 2015-06-13 11:12:38 +02:00
James Brooks
4f78d7c513 Fixes #708 - Upgrade roumen/feed 2015-06-13 10:09:20 +01:00
James Brooks
397679bc57 Fix usage of wrong alert type. 2015-06-13 10:05:36 +01:00
James Brooks
7bd3a57883 Closes #710 - Fix adding of scheduled maintenance. 2015-06-13 10:04:24 +01:00
Graham Campbell
2d9dcd9747 Merge pull request #713 from cachethq/exceptions
Improvements to the exception handler
2015-06-13 09:59:49 +01:00
Graham Campbell
5ceb700b4c Improvements to the exception handler 2015-06-12 23:27:30 +01:00
Graham Campbell
0cc0cdc9e3 Updated dependencies 2015-06-12 22:56:59 +01:00
Graham Campbell
f9744b04bb Fixes 2015-06-12 22:49:28 +01:00
Graham Campbell
615f9e0d75 Fixes 2015-06-12 22:49:08 +01:00
Graham Campbell
0aacc038c2 Fixes 2015-06-12 22:48:09 +01:00
Graham Campbell
8f7b538fac CS fix 2015-06-12 22:46:41 +01:00
Graham Campbell
bf53768530 Added canonicalize macro 2015-06-12 22:44:57 +01:00
Graham Campbell
33a282ca4e Removed old service provider from the config 2015-06-12 22:42:04 +01:00
Graham Campbell
2e3fa35aca Fixed the composer service provider 2015-06-12 22:41:17 +01:00
Graham Campbell
b8efd4829e Added missing import 2015-06-12 22:38:49 +01:00
Graham Campbell
78b7e4b8f0 Removed old service provider 2015-06-12 22:38:11 +01:00
Graham Campbell
50096f6a6f Deal with the command bus in the app service provider 2015-06-12 22:37:46 +01:00
Graham Campbell
c56be4c6e0 Deleted old service provider 2015-06-12 22:36:07 +01:00
Graham Campbell
22332e7969 Merge pull request #711 from ldidry/correct-feeds
Correct feeds
2015-06-12 22:34:37 +01:00
Luc Didry
0833f41189 Items' id must be different for feeds to be valid 2015-06-12 23:06:50 +02:00
Luc Didry
3cde840e2b Canonicalize URLs to be W3C compliant
The W3C feed validator (https://validator.w3.org/feed/) says that
http://cachet.example.org is not a valid value for a link, but that
http://cachet.example.org/ is.

The canonicalizeUrl method add a trailing slash if needed.
2015-06-12 23:03:42 +02:00
James Brooks
7888f5953b Don't show hidden items in RSS/Atom 2015-06-12 08:56:17 +01:00
James Brooks
884c43f160 Merge pull request #707 from ldidry/fix-706
Fix #706 Correct null ComponentGroup check for Atom and RSS feeds
2015-06-12 08:52:31 +01:00
Luc Didry
866d73e8f8 Fix #706 Correct null ComponentGroup check for Atom and RSS feeds 2015-06-12 09:41:18 +02:00
James Brooks
832db53ef2 Fixes #705 and only send emails for public incidents. 2015-06-12 08:05:07 +01:00
Joe Cohen
f1080680bf Merge pull request #651 from cachethq/incident-visibility
Incident visibility
2015-06-11 16:59:14 -05:00
James Brooks
df2ae7726d Adds incident visibility. Closes #602 2015-06-11 22:43:16 +01:00
James Brooks
e308ba3aea Don't use url helper 2015-06-11 08:25:30 +01:00
James Brooks
9257135641 Added missing localization 2015-06-10 22:15:26 +01:00
James Brooks
732ec5c827 Merge pull request #702 from cachethq/subscriber-config
Closes #700 - Subscribers can now be turned on and off
2015-06-10 22:13:04 +01:00
James Brooks
eb191a52d7 Fix alignment 2015-06-10 22:11:14 +01:00
James Brooks
9a200684c1 Improve footer layout and styling (fixed position is not fixed) 2015-06-10 22:09:28 +01:00
James Brooks
036928e53e Closes #700 - Subscribers can now be turned on and off 2015-06-10 21:29:35 +01:00
James Brooks
9877023bb4 Fix missing token from unsub link 2015-06-10 14:56:06 +01:00
James Brooks
de9745c7cf Fixes #696 2015-06-10 14:51:38 +01:00
James Brooks
8cdfd90df5 Fix unsubscribe link. Closes #697 2015-06-10 14:49:55 +01:00
James Brooks
afa8c98fbd Set environment values for MAIL_ADDRESS and MAIL_FROM 2015-06-10 14:36:31 +01:00
James Brooks
472e2316ae Don't use the absolute url 2015-06-10 14:17:59 +01:00
James Brooks
92173b65bc Merge pull request #662 from cachethq/subscribers
Subscribers
2015-06-10 14:06:15 +01:00
Graham Campbell
ff2c255d9e Updated the lock file 2015-06-10 14:03:43 +01:00
Graham Campbell
9315de8a4c Fixed up the middleware 2015-06-10 14:03:31 +01:00
Graham Campbell
7b61ad0445 Merge pull request #691 from cachethq/block-php7
Don't allow php 7 installs
2015-06-10 13:58:23 +01:00
James Brooks
980d34abbc Merge pull request #693 from cachethq/no-user-id
Closes #688 - Drop user_id column
2015-06-10 13:39:24 +01:00
James Brooks
620e7fed56 Closes #688 - Drop user_id column 2015-06-10 13:36:26 +01:00
James Brooks
d9e515c62d Make the seeded data all be operational 2015-06-10 13:34:43 +01:00
James Brooks
48c40952f2 Laravel 5.1 is released 2015-06-09 20:51:18 +01:00
Joseph Cohen
55dcf3a277 Handle subscribers 2015-06-09 14:13:27 -05:00
James Brooks
254c578ca2 Merge pull request #660 from cachethq/no-repositories
Remove repositories
2015-06-09 11:04:32 +01:00
James Brooks
106c1a034a Remove repositories from the API and switch cipher to rijndael-256 2015-06-09 10:57:45 +01:00
James Brooks
d788691006 Update dependencies 2015-06-07 09:51:35 +01:00
Joseph Cohen
fc31ce13bc Update deps 2015-06-06 20:54:50 -05:00
James Brooks
6b98832f3b Use the right cipher 2015-06-06 21:48:52 +01:00
James Brooks
cac63fe1fc Update dependencies 2015-06-05 20:45:03 +01:00
Graham Campbell
5a705f9b62 Don't allow php 7 installs 2015-06-05 09:13:06 +01:00
Graham Campbell
987f045c55 Merge pull request #690 from cachethq/security
Enable session security
2015-06-04 23:16:51 +01:00
Joseph Cohen
d85d035ab1 Revert session ecryption 2015-06-04 17:09:32 -05:00
Joseph Cohen
32e97a7fde Enable session security 2015-06-04 16:43:46 -05:00
Graham Campbell
13468239a3 Revert 2015-06-04 09:15:25 +01:00
James Brooks
ba79d2c8a3 Set session.encrypt to true 2015-06-04 09:10:58 +01:00
James Brooks
e70e228e38 Remove call to all from $usedComponentGroups 2015-06-03 22:43:05 +01:00
Graham Campbell
3a781c5e66 Removed old config 2015-06-03 22:41:45 +01:00
James Brooks
8ec29e9921 Update dependencies again 2015-06-03 22:39:11 +01:00
James Brooks
1e27882b90 Update dependencies. 2015-06-03 08:42:03 +01:00
James Brooks
fad393be1d Add testing of status code to API 2015-06-03 08:28:48 +01:00
James Brooks
dd8fc60209 Added API /ping endpoint. Closes #687 2015-06-03 08:22:08 +01:00
James Brooks
c06019a554 Remove PHP 7 nightly because Carbon is incompatible 2015-06-02 20:20:46 +01:00
James Brooks
f15f492bf3 Run tests aginst PHP 7 (nightly) 2015-06-02 20:12:56 +01:00
James Brooks
743ed28fd8 Added Metric and MetricPoint API testing 2015-06-02 20:02:43 +01:00
James Brooks
90110944ff Finish incident API tests 2015-06-02 19:48:09 +01:00
James Brooks
f94a5ec57b Rename vars 2015-06-02 19:47:20 +01:00
James Brooks
4245b95406 Finish Component API testing 2015-06-02 19:44:17 +01:00
James Brooks
9de5847004 Make license badge match the actual license 2015-06-02 14:29:17 +01:00
James Brooks
6637e49c6c Start working on metric tests 2015-06-02 14:23:55 +01:00
James Brooks
b6b5146f16 Formatting 2015-06-02 14:22:48 +01:00
James Brooks
149f043be3 Remove failing test till it can be fixed. More incident testing. 2015-06-02 14:19:24 +01:00
James Brooks
f06e9cc88f Move beUser into Abstract class 2015-06-02 13:42:39 +01:00
James Brooks
4d8b340397 Be more verbose in our testing 2015-06-02 13:41:54 +01:00
James Brooks
ee66f4c451 Now tests if a component can be created via the API 2015-06-02 09:00:33 +01:00
James Brooks
f550a7369e Auto authenticate the user if logged in 2015-06-02 08:35:30 +01:00
James Brooks
2baf17b9d5 Update dependencies 2015-06-02 08:08:53 +01:00
James Brooks
fff91417c7 Added letUserBeLoggedIn for CompoentTest (doesn't fully work) 2015-06-01 22:53:38 +01:00
James Brooks
2af917ace4 Added a User factory 2015-06-01 22:42:49 +01:00
Graham Campbell
049b9ac308 Fixed tests 2015-06-01 22:25:34 +01:00
Graham Campbell
0c065ae690 Use annotation 2015-06-01 22:03:29 +01:00
James Brooks
d3d744780d Revert change to file permission 2015-06-01 22:00:40 +01:00
Graham Campbell
a1fb287a1b Updated dependencies 2015-06-01 21:53:57 +01:00
Graham Campbell
4347a5cc0c Fixed dependencies 2015-06-01 21:48:23 +01:00
James Brooks
f970ae7100 Start working on API tests 2015-06-01 21:32:02 +01:00
James Brooks
224618b0a4 Use the View contract 2015-06-01 11:45:48 +01:00
Graham Campbell
d9414fc25c Update Repository.php 2015-05-30 09:42:29 +01:00
James Brooks
e81b29053a Merge branch 'master' of github.com:cachethq/cachet 2015-05-29 21:56:26 +01:00
James Brooks
672f475a0d Fix handling of settings not existing 2015-05-29 21:56:06 +01:00
Graham Campbell
142473c693 Deleted unused file 2015-05-29 21:14:49 +01:00
James Brooks
cb83f5c0c6 Fix bug with sorting of incident dates 2015-05-29 20:43:12 +01:00
James Brooks
3197b5d18d Fixes #682 2015-05-29 20:32:14 +01:00
Graham Campbell
4c28335ffe Merge pull request #681 from cachethq/new
Upgraded to laravel 5.1
2015-05-29 18:19:56 +01:00
Graham Campbell
e7852e06f8 Updated dependencies 2015-05-29 12:47:41 +01:00
Graham Campbell
62c2c1c7ea Typo fix 2015-05-28 21:42:05 +01:00
Graham Campbell
b85752b101 Upgraded to laravel 5.1 2015-05-28 21:37:44 +01:00
Graham Campbell
9355854289 Fixed segment cache repository 2015-05-28 20:02:15 +01:00
Graham Campbell
99e6f5a234 Merge pull request #680 from cachethq/service-providers
Cleanup service providers
2015-05-28 19:59:53 +01:00
Graham Campbell
49305a2553 Re-added needed initialisation 2015-05-28 19:54:47 +01:00
Graham Campbell
97c99d0afc Minor fixes 2015-05-28 19:49:00 +01:00
Graham Campbell
3f9ebb8abf Cleanup service providers 2015-05-28 19:46:54 +01:00
Graham Campbell
5540a50fae Deleted unused request class 2015-05-28 19:30:25 +01:00
Graham Campbell
e93fda4d53 Cleanup the segment repositories
This code should now work on guzzle 4, guzzle 5 and guzzle 6.
2015-05-28 19:17:31 +01:00
Graham Campbell
65b1038b84 Fixed spelling error 2015-05-28 19:17:31 +01:00
Graham Campbell
77e4532319 Added missing return annotation 2015-05-28 19:17:30 +01:00
Graham Campbell
4c67e04786 Removed old file 2015-05-28 19:17:29 +01:00
Graham Campbell
128fdbed19 Merge pull request #678 from cachethq/tests
Started working on a test suite.
2015-05-28 18:23:09 +01:00
James Brooks
7b3f6fee26 Started working on a test suite
Signed-off-by: Graham Campbell <graham@cachethq.io>
2015-05-28 18:21:39 +01:00
Graham Campbell
c2b69ff547 Updated composer.lock hash 2015-05-28 15:21:36 +01:00
Graham Campbell
12e940e59c Updated pre-update composer hook 2015-05-28 15:18:22 +01:00
Graham Campbell
eb9d22975d Updated .gitignore files 2015-05-28 15:16:26 +01:00
Graham Campbell
c460cd9efe Added missing entry to the language files 2015-05-28 15:13:28 +01:00
Graham Campbell
a314d8b838 Updated config 2015-05-28 15:05:35 +01:00
James Brooks
8299afaa8a Update bootstrap-datetimepicker and styles. Closes #675 2015-05-28 14:26:51 +01:00
James Brooks
40a65fe7e2 Update dependencies 2015-05-28 14:16:10 +01:00
Graham Campbell
d8811c974b Removed unused import 2015-05-28 10:41:56 +01:00
James Brooks
ea94f6dd9e Fixes issue with $pageTitle 2015-05-28 08:59:56 +01:00
James Brooks
fb8990dff2 Move pageTitle into IndexComposer 2015-05-28 08:44:04 +01:00
James Brooks
32029c0bf1 Closes #670 2015-05-28 08:42:39 +01:00
James Brooks
6b70ca7eac Somewhat improve mobile 2015-05-28 08:35:09 +01:00
James Brooks
7aba6e31ea Show components in the dashboard index, in order 2015-05-28 08:33:43 +01:00
James Brooks
c0db4d883a Remove Carbon from HomeController as it doesn't provide any use 2015-05-28 08:30:59 +01:00
James Brooks
bc01c0bb63 Remove duplicate Segment call 2015-05-28 08:25:21 +01:00
Graham Campbell
d29b872fee Fixed issues with the api controller 2015-05-27 17:02:17 +01:00
James Brooks
502ae9d2a0 Closes #669 2015-05-26 19:13:46 +01:00
Graham Campbell
e6f6946497 As cachet is a "project", we shouldn't exclude these 2015-05-26 11:56:39 +01:00
James Brooks
430f580b47 Fix metric chart heights on mobile 2015-05-26 08:16:21 +01:00
Graham Campbell
f7d9f8237c Updated composer.lock 2015-05-26 00:03:28 +01:00
Graham Campbell
1efe164d7b Merge pull request #665 from cachethq/exceptions
Upgraded to laravel exceptions 2
2015-05-25 20:29:11 +01:00
James Brooks
6c6caa7f6c Don't call Artisan facade 2015-05-25 20:28:47 +01:00
James Brooks
c85eba8f04 Compile assets 2015-05-25 20:18:42 +01:00
James Brooks
e399fe4637 Default jQuery AJAX accept headers to JSON 2015-05-25 20:18:01 +01:00
Graham Campbell
a844a711e1 Upgraded to laravel exceptions 2 2015-05-25 20:06:09 +01:00
Graham Campbell
80580eadeb Segment updates 2015-05-25 20:02:11 +01:00
Graham Campbell
2b3b6fb8d8 Merge pull request #664 from cachethq/no-html
Removed the html component
2015-05-25 19:33:37 +01:00
Graham Campbell
9bc598d234 Removed the html component 2015-05-25 19:29:29 +01:00
Graham Campbell
bc11ae6ed6 Merge branch 'master' of https://github.com/cachethq/Cachet 2015-05-25 19:19:09 +01:00
Graham Campbell
ebc842f19e Updated config 2015-05-25 19:19:03 +01:00
James Brooks
084f685387 Fix compilation of nav 2015-05-25 19:05:55 +01:00
Graham Campbell
f235780dda Revert "Updated package.json"
This reverts commit 5a9cb34332.
2015-05-25 19:03:26 +01:00
Graham Campbell
09c33a698d Fixed license years 2015-05-25 19:03:23 +01:00
Graham Campbell
fbf55eeb48 Composer updates 2015-05-25 18:53:00 +01:00
Graham Campbell
946b442ae0 Merge pull request #659 from cachethq/env-config-setup
Env config setup
2015-05-25 18:41:33 +01:00
Graham Campbell
51a4799a29 Merge pull request #663 from cachethq/package
Updated package.json
2015-05-25 18:41:01 +01:00
James Brooks
6dbd15d272 Allow changing of some env variable during setup. 2015-05-25 18:40:09 +01:00
Graham Campbell
5a9cb34332 Updated package.json 2015-05-25 18:32:30 +01:00
Graham Campbell
5709995b13 Fixed server.php 2015-05-25 18:31:51 +01:00
Graham Campbell
aa5e24e96d Updated phpunit config 2015-05-25 18:31:45 +01:00
Graham Campbell
26fbbf9f35 Updated travis config 2015-05-25 18:28:56 +01:00
Graham Campbell
634c318f3f Updated composer.lock 2015-05-25 18:02:12 +01:00
Graham Campbell
45abeea90f Fixed composer.json 2015-05-25 18:02:04 +01:00
Graham Campbell
3988753b99 Updated copyright headers 2015-05-25 17:59:08 +01:00
Graham Campbell
b06167f5e9 Updated joe's email address 2015-05-25 17:53:06 +01:00
James Brooks
a1470a01cf Delete nginx.conf 2015-05-23 17:16:38 +01:00
James Brooks
c554b40c7d Remove unused import (Input) 2015-05-23 15:54:21 +01:00
James Brooks
0e40fe4d3f Prevent Binput from trimming values when dealing with metric suffixes 2015-05-23 15:53:03 +01:00
James Brooks
1402242766 Wrap metric name value in quotes to prevent truncation 2015-05-23 15:47:59 +01:00
James Brooks
bf5941f66e Improve metric tooltips, now show name, value and suffix 2015-05-23 15:46:57 +01:00
James Brooks
6044f7d87c Don't escape the two factor auth help block 2015-05-23 15:29:27 +01:00
Graham Campbell
82cdd171c5 Updated composer.lock file 2015-05-23 14:58:56 +01:00
Graham Campbell
768f4979be Force newer jenssegers/date 2015-05-23 14:57:37 +01:00
Graham Campbell
dc1f1c4737 Updated version constraints 2015-05-23 14:51:07 +01:00
Graham Campbell
0b8ec411ae Added missing into to composer.json 2015-05-23 14:50:17 +01:00
Graham Campbell
91e4dafca9 Updated my email address 2015-05-23 14:48:33 +01:00
James Brooks
65aaa6402a Default all segment contexts to include driver info. 2015-05-23 13:30:18 +01:00
James Brooks
1af50d991e segment_track defaults parameters to an empty array 2015-05-23 13:29:01 +01:00
James Brooks
01b6bb1c2b Track Logged In and Logged Out events 2015-05-23 13:27:56 +01:00
James Brooks
83be116075 Make changes to what we send to Segment, still anonymous! 2015-05-23 13:20:05 +01:00
James Brooks
92604f2ecd Fix the segment_page function 2015-05-23 13:13:38 +01:00
James Brooks
d01ef397b3 Update laravel/framework to 5.0.32 2015-05-23 10:48:10 +01:00
James Brooks
0fb43b2ada Don't use url helper for logo in setup 2015-05-23 08:19:10 +01:00
James Brooks
e577451833 Update dependencies 2015-05-23 07:35:41 +01:00
James Brooks
6803f8e4a8 Improve handling of BasicAuth errors. 2015-05-22 18:29:09 +01:00
James Brooks
fd18b0ae07 Merge pull request #657 from cachethq/update-enUD-lang
Updates en-UD for incontext localization.
2015-05-22 17:08:39 +01:00
James Brooks
b743d56901 Fix lang src 2015-05-22 17:08:29 +01:00
James Brooks
2a94965bb6 Updates en-UD for incontext localization. 2015-05-22 17:06:18 +01:00
James Brooks
03bcf20001 Fix generation of metric point array 2015-05-22 15:35:39 +01:00
James Brooks
e4ef64d014 Fix generation of metrics, no longer sub an extra hour in calculation 2015-05-22 15:32:55 +01:00
James Brooks
d24e83e0ae Account for BasicAuth within ApiAuthenticate 2015-05-22 15:11:44 +01:00
James Brooks
2ae5fb9f22 Added GoSquared demo tracking to the seeder. 2015-05-22 14:07:09 +01:00
James Brooks
aeea02efa2 Fix conditional check for segment_write_key 2015-05-22 14:04:23 +01:00
James Brooks
b15ce2c2c7 Prefix asset urls with / for relative path 2015-05-22 08:28:03 +01:00
James Brooks
7a3a7588b1 Don't wrap the formatted message in p tags, Markdown does it 2015-05-22 08:23:40 +01:00
James Brooks
1e6cb06387 Fix displaying of scheduled time 2015-05-22 07:52:44 +01:00
James Brooks
8e2ab97dfa Fix fetching settings from env never falling to default 2015-05-22 07:34:17 +01:00
James Brooks
0be55c75c0 Merge pull request #654 from cachethq/api-auth
Authenticate api requests
2015-05-20 23:07:01 +01:00
Joseph Cohen
78b7dc92d6 Authenticate api requests 2015-05-20 17:05:37 -05:00
James Brooks
d70ca8d4e5 Fixes #653 2015-05-20 22:38:09 +01:00
James Brooks
af69c99896 Alias the Setting model 2015-05-20 20:24:54 +01:00
James Brooks
707248e436 Merge pull request #638 from cachethq/api-presenters
Make presenters work with the api
2015-05-20 20:23:33 +01:00
Joseph Cohen
088b54a5ce Abstract presenter, timestampstrait, update api responses 2015-05-20 14:19:01 -05:00
Joseph Cohen
10bcbc6169 Get default value on config repository 2015-05-20 14:19:01 -05:00
Joseph Cohen
33f6bf167c Make presenters work with the api 2015-05-20 14:19:01 -05:00
James Brooks
b6aa4b1d8b Fix bad indentation 2015-05-20 19:55:34 +01:00
James Brooks
f7bf3607ce Rebuild assets. 2015-05-20 17:50:27 +01:00
James Brooks
3e9d62f3f7 Change default formatting of date_format 2015-05-20 17:45:08 +01:00
James Brooks
cc755f5184 Improve the username regex 2015-05-20 16:16:25 +01:00
James Brooks
8840bca990 Use the env function rather than getenv 2015-05-20 10:39:31 +01:00
James Brooks
bf8b722e7b Allow all origins by default 2015-05-20 09:18:27 +01:00
James Brooks
79889edd29 Fix editing of incident.created_at under Postgres 2015-05-20 08:18:48 +01:00
James Brooks
053ed46b97 Fix docblock 2015-05-20 08:09:10 +01:00
James Brooks
a1ab59a15a Remove old Cors middleware 2015-05-20 08:08:53 +01:00
James Brooks
a119ed14b2 Default the component_groups.order value to 0 2015-05-20 08:07:08 +01:00
James Brooks
8e06f6241b Merge pull request #650 from cachethq/order-component-groups
Allows ordering of component groups
2015-05-19 22:55:44 +01:00
James Brooks
9337c1a75b Allows ordering of component groups. Closes #573. 2015-05-19 22:54:28 +01:00
James Brooks
879a8a5c69 Merge pull request #643 from cachethq/fix-api-cors
Handle CORS properly
2015-05-19 20:56:42 +01:00
James Brooks
bc376748c8 Fixes #628 - Handle Cors properly. 2015-05-19 20:54:23 +01:00
James Brooks
8984aecd85 Remove HTMLMin 2015-05-19 20:29:50 +01:00
James Brooks
1aedce0219 Merge pull request #646 from cachethq/incident-format-presenter
Fixes #644 - Incident presenter respects the date format.
2015-05-19 20:17:41 +01:00
James Brooks
d9b5c31a06 Merge pull request #647 from cachethq/change-incident-timestamps
Allow changing of incident dates. Closes #615
2015-05-19 20:17:24 +01:00
James Brooks
f2e869f610 Fixes #644 - Incident presenter respects the date format. 2015-05-19 20:04:11 +01:00
James Brooks
c097585ca0 Add missing translation strings for analytics_google, analytics_gosquared 2015-05-19 19:59:21 +01:00
James Brooks
c04ac4a5e3 Fix RedirectIfAuthenticate middleware redirecting to wrong location 2015-05-19 19:30:16 +01:00
James Brooks
166e6f8d59 Fixes #648 2015-05-19 19:14:21 +01:00
James Brooks
77d0c20015 Allow changing of incident dates. Closes #615 2015-05-19 17:40:04 +01:00
Joe Cohen
babef3f7fb Merge pull request #645 from cachethq/theme-composer
Better handling of the custom theme settings.
2015-05-19 11:12:23 -05:00
James Brooks
4d28b28bdf Better handling of the custom theme settings. 2015-05-19 17:06:39 +01:00
James Brooks
0b58160f6d Change the design and colours of the metric graphs 2015-05-19 15:27:44 +01:00
James Brooks
f714176f39 Set Chart.Line.scaleShowLabel to false 2015-05-19 15:24:04 +01:00
James Brooks
0928251673 Add Joseph Cohem and Graham Campbell to the copyright headers. 2015-05-19 10:45:38 +01:00
James Brooks
30248b00aa Add link to upgrade from L4 docs 2015-05-19 08:39:00 +01:00
James Brooks
05dfb3038b Reduce line lengths, format queries 2015-05-19 08:12:50 +01:00
James Brooks
d2048e44b3 Merge pull request #642 from cachethq/component-group-collapsing
Toggle component groups
2015-05-19 06:35:51 +01:00
James Brooks
f277d8b2bc Toggle component group visibility. Closes #572 2015-05-18 21:45:14 +01:00
James Brooks
31336478fe Fixes #606 - Bad component.group_id when adding/editing components. 2015-05-18 16:26:34 +01:00
James Brooks
159e4fc0c9 Make panels use our colour palette. Add .alert default styles 2015-05-18 09:59:07 +01:00
James Brooks
c370ed47ef Reduce letter spacing within the dashboard. 2015-05-18 09:53:30 +01:00
James Brooks
241947d069 Fixes #641 2015-05-18 09:46:19 +01:00
James Brooks
afa66814fa Make alert styles consistent 2015-05-18 09:23:09 +01:00
James Brooks
3fa0912818 Fix formatting 2015-05-16 14:52:01 +01:00
James Brooks
fe12b83c5a Merge pull request #635 from gm-ah/master
ID lang
2015-05-16 14:50:52 +01:00
gm-ah
accc828836 Update forms.php 2015-05-16 20:42:42 +07:00
gm-ah
7b00dbdf9b Update dashboard.php 2015-05-16 20:41:17 +07:00
James Brooks
05968b21e0 Merge pull request #636 from LeoColomb/patch-1
Add id in langs
2015-05-16 07:28:43 +01:00
Léo Colombaro
dcf7d62ca5 Add id in langs
Fixes crash on install
2015-05-15 13:33:53 +02:00
gm-ah
6de4a2fb59 Create validation.php 2015-05-14 19:22:53 +07:00
James Brooks
f993cfcbc3 Merge pull request #634 from gm-ah/gm-ah-port1
id/cachet.php
2015-05-14 12:54:16 +01:00
gm-ah
87baa067a6 Create setup.php 2015-05-14 16:51:46 +07:00
gm-ah
46441ca0e3 Create reminders.php 2015-05-14 16:51:14 +07:00
gm-ah
9045c52774 Create pagination.php 2015-05-14 16:50:44 +07:00
gm-ah
4a481f5736 Create forms.php 2015-05-14 16:50:15 +07:00
gm-ah
863a2f4ed3 Create errors.php 2015-05-14 16:49:44 +07:00
gm-ah
a475a857c2 Create dashboard.php 2015-05-14 16:48:54 +07:00
gm-ah
0a92d8be31 Create cachet.php 2015-05-14 16:48:11 +07:00
gm-ah
85967a9991 id/cachet.php
id lang
2015-05-14 16:43:57 +07:00
James Brooks
9b4e626447 Shorten code 2015-05-13 08:08:45 +01:00
James Brooks
fe1425a6c0 Closes #605 2015-05-10 19:51:06 +01:00
James Brooks
0569142f84 Update the Incident model attributes 2015-05-10 19:41:33 +01:00
James Brooks
43eaf2aa2d Add cookies warning to login. Closes #525. 2015-05-10 19:16:34 +01:00
James Brooks
853cd9bfbf Update dependencies 2015-05-08 11:07:17 +01:00
James Brooks
06b9bc2757 Prevent bots from indexing date ranges with no incidents. Closes #624. 2015-05-08 11:06:02 +01:00
Joe Cohen
2c0e806ad6 Merge pull request #598 from experty/L5
Use APC cache for Docker and fix bug with changing component sort order
2015-05-07 10:44:21 -05:00
Joseph Cohen
a5526c7ca7 Remove tz form formatted date helper 2015-05-07 10:37:32 -05:00
James Brooks
4eb1bee983 Merge pull request #627 from cachethq/fix-config-and-tests
Update loading config to fix failing builds
2015-05-07 16:28:06 +01:00
James Brooks
6973943e3a Merge pull request #626 from cachethq/incidents-dates
Fix incidents timezones and order
2015-05-07 16:26:46 +01:00
Joseph Cohen
bb5fd311fe Update loading config to fix failing builds 2015-05-07 09:38:58 -05:00
Joseph Cohen
5280fc8df4 Fix incidents timezones and order 2015-05-07 09:15:00 -05:00
James Brooks
2712e61ea5 Fix up the 2FA login form 2015-05-02 16:30:14 +01:00
James Brooks
65debb5014 Fixes #621 - Use zero-prefixed day formatting. 2015-05-02 14:57:48 +01:00
James Brooks
8a9456ab42 Fixes #618 - Only fetch Segment key if we want to help usage stats. 2015-05-02 09:29:00 +01:00
James Brooks
444b236f9f Fixes #619 2015-05-02 09:19:01 +01:00
James Brooks
8f9d2614e9 Fix sorting of days 2015-05-02 09:09:02 +01:00
James Brooks
b0c808f449 Remove the small HTML from the "Show Support for Cachet" string 2015-05-02 09:04:07 +01:00
James Brooks
cb049f6458 Merge pull request #613 from vinkla/patch-1
Fix typo in AbstractApiController
2015-04-28 17:23:08 +01:00
Vincent Klaiber
b26bef7251 Fix typo in AbstractApiController 2015-04-28 18:22:23 +02:00
James Brooks
61afb54121 Remove component list from editing incidents. 2015-04-28 11:21:57 +01:00
EdeMeijer
c4c55a73cb Use APC cache for Docker and fix bug with changing component sort order
By default, the file cache is used, but this breaks the throttling detection when authenticating.
The APC cache is tagged and will allow you to log in again after installation.
---
When changing the sort order, a form with hidden inputs for every component was serialized. The hidden inputs
had names in the form of `component[id]`. When you removed components, there would be holes in this ID sequence,
yielding a serialized array with empty values (since JS arrays always have every index until the highest one, even
if you don't specify a value).

This is fixed by just passing an array of component IDs in the desired sort order to the API endpoint. The API
will then update the components based on the implicit given sort order. Much simpler.
2015-04-25 12:00:53 +02:00
James Brooks
dda8917db0 Update dependencies 2015-04-23 08:12:50 +01:00
James Brooks
26642eb573 Fix missing $date variable 2015-04-23 08:12:42 +01:00
James Brooks
cbf59b9b78 Merge pull request #597 from Lavoaster/fix/homepage_excessive_queriesv2
Refactored the way incidents are pulled out of the database + Sort fix
2015-04-23 08:08:32 +01:00
James Brooks
01ea120747 Merge pull request #599 from naabster/L5
controller class names made case sensitive for router
2015-04-23 08:08:06 +01:00
naabster
968abd0dc0 controller class names made case sensitive for router 2015-04-22 23:24:37 +02:00
Adam Lavin
8b200ef35e Refactored the way incidents are pulled out of the database + Sort fix
Incidents are now pulled out via the database, grouped together via php, then missing days are added to the data.
2015-04-21 12:45:36 +01:00
James Brooks
497cc24545 Merge pull request #596 from cachethq/revert-595-fix/homepage_excessive_queries
Revert "Refactored the way incidents are pulled out of the database on t...
2015-04-21 10:13:13 +01:00
James Brooks
1543643f4c Revert "Refactored the way incidents are pulled out of the database on the homepage" 2015-04-21 10:13:08 +01:00
James Brooks
6917870c23 Merge pull request #595 from Lavoaster/fix/homepage_excessive_queries
Refactored the way incidents are pulled out of the database on the homepage
2015-04-21 07:41:43 +01:00
Adam Lavin
04438e31ed CS Fixes 2015-04-20 23:44:29 +01:00
Adam Lavin
4c4a32da3d Refactored the way incidents are pulled out of the database
Incidents are now pulled out via the database, grouped together via php, then missing days are added to the data
2015-04-20 23:28:53 +01:00
James Brooks
09dd120805 Added sensu-cachet 2015-04-20 09:45:12 +01:00
James Brooks
60af02969f Merge pull request #593 from experty/L5
Update Dockerfile for moved app config file
2015-04-20 09:18:18 +01:00
EdeMeijer
e8750e9726 Update Dockerfile for moved app config file
It seems like the app config was moved, but the Dockefile wasn't updated. This makes building work again.
2015-04-20 10:15:16 +02:00
James Brooks
70a07e6d19 Fix links to dashboard and auth/logout 2015-04-19 12:30:48 +01:00
James Brooks
d451fc4c7d Remove unused Heroku config 2015-04-19 09:19:46 +01:00
James Brooks
51ae02992e Fix copyright info 2015-04-19 09:18:16 +01:00
James Brooks
2d7be16229 Added GrahamCampbell/htmlmin 2015-04-19 09:17:31 +01:00
James Brooks
ed88aa841a Added APP_URL config 2015-04-19 09:16:59 +01:00
James Brooks
8714f4643d Import Request in trustedproxy.php 2015-04-19 09:13:20 +01:00
James Brooks
861041ff31 Fixed index.php 2015-04-19 09:11:53 +01:00
James Brooks
c3c62a6b4e Add TrustProxies to Http middleware 2015-04-19 09:04:50 +01:00
James Brooks
7cf61b9699 Update dependencies. 2015-04-19 08:59:00 +01:00
James Brooks
80e3d9167d Closes #568, adds copyright information. 2015-04-19 08:52:39 +01:00
James Brooks
dc139ef09f Remove cachet:one-click-deploy command in Travis 2015-04-18 17:11:14 +01:00
James Brooks
f9917e525c Merge pull request #591 from wfjsw/L5
Fix L10n *again*
2015-04-18 17:08:27 +01:00
jsw
af084ceec8 Fix L10n *again* 2015-04-19 00:00:29 +08:00
James Brooks
ba7f9881d6 Fix L10n style and content @wfjsw 2015-04-18 16:55:51 +01:00
James Brooks
17c31f4f2f Merge pull request #589 from EdeMeijer/L5
Add PHP pgsql driver to Dockerfile
2015-04-18 16:54:46 +01:00
EdeMeijer
31003e1d7f Add PHP pgsql driver to Dockerfile
This fixes not being able to use Cachet with Docker and Postgres (with the -e DB_DRIVER=pgsql option)
2015-04-18 17:50:54 +02:00
James Brooks
fa12463ac2 Fix styles 2015-04-18 16:39:01 +01:00
James Brooks
9c221b7b2a Fix metic point calculations. 2015-04-18 14:06:14 +01:00
James Brooks
35dc0f6f77 Remove Lato. 2015-04-18 14:06:07 +01:00
James Brooks
7c9fff983e Update L5 branch. 2015-04-18 13:59:37 +01:00
James Brooks
191e17b1a6 Closes #552 - Autosize some textareas. 2015-04-06 09:31:19 +01:00
James Brooks
d2043f41c4 Added demo account info 2015-04-05 22:55:16 +01:00
James Brooks
f462cc99c7 Update dependencies. 2015-04-03 18:06:15 +01:00
James Brooks
4f09ce1f1b Fix Atom and RSSController docblocks. 2015-04-03 18:06:08 +01:00
James Brooks
d3554ec4f4 Fixes #550 in the Laravel 5 branch. 2015-04-03 17:53:57 +01:00
James Brooks
04f957cf39 Fixed HTML encoding. 2015-04-03 17:46:33 +01:00
James Brooks
0e8899e90e Fixes #567. 2015-04-03 17:44:48 +01:00
James Brooks
f73afb87d8 Merge pull request #566 from cachethq/gosquared-tracking
GoSquared Tracking
2015-04-03 17:38:32 +01:00
James Brooks
92c1d69b16 Support GoSquared tracking codes as well. Closes #556. 2015-04-03 17:29:14 +01:00
James Brooks
cee25ba530 Fix markup. 2015-04-03 17:17:39 +01:00
James Brooks
39bf9f789c Remove small text from language string. 2015-04-03 17:17:29 +01:00
James Brooks
f7aa87c503 Remove OneClickDeployCommand from Kernel $commands 2015-04-03 17:15:31 +01:00
James Brooks
3a9bc47f09 Merge pull request #565 from cachethq/drop-heroku-support
Drop Heroku support
2015-04-03 17:11:23 +01:00
James Brooks
31f5d76bcf Removed native Heroku deployment. Closes #557. 2015-04-03 17:10:20 +01:00
James Brooks
1117f421b1 Update dependencies. 2015-04-03 17:07:06 +01:00
James Brooks
3b4fcd793f Closes #560 2015-03-31 21:38:20 +01:00
James Brooks
e61cae2ddd Fix output of HTML from support Cachet link 2015-03-31 21:29:27 +01:00
James Brooks
caeaf4c1a9 Merge pull request #559 from Duffleman/patch-1
Update .env.example
2015-03-31 21:23:16 +01:00
George Miller
6d6e8bcaf9 Update .env.example
DB_DRIVER is default set to sqlite. Anyone starting the project intending to use MySQL will have to look around to see to add that declaration here. Best add it to the example file to save them the hassle.
2015-03-31 21:21:52 +01:00
Graham Campbell
0f44fab68c More specific docblock 2015-03-30 21:48:57 +01:00
Graham Campbell
3f0b2d1375 Cleanup exception handler 2015-03-30 21:47:25 +01:00
James Brooks
64f5c23546 Use Laravel-Exceptions 2015-03-30 21:44:32 +01:00
James Brooks
f6c4f3df27 Update dependencies. 2015-03-30 21:14:15 +01:00
James Brooks
cdd91ce673 Merge pull request #555 from cachethq/issue-551
Closes #551
2015-03-30 21:12:20 +01:00
James Brooks
5251369317 Closes #551 2015-03-30 21:11:52 +01:00
James Brooks
64d1d73d70 Use env to determine the DB_DRIVER 2015-03-28 09:17:29 +00:00
Joseph Cohen
082f57569f Fix CS 2015-03-26 15:09:49 -06:00
Joseph Cohen
37e20bf2bf Update code to match master 2015-03-26 15:07:16 -06:00
Graham Campbell
eb22ac6d8a Cleaned up dependencies
Using the sexy ^ notation. :)
2015-03-23 19:44:30 +00:00
Graham Campbell
85bab1d238 Merge pull request #538 from cachethq/l5-stuffs
Loosen some version constraints
2015-03-23 19:41:32 +00:00
Graham Campbell
21355e3dd7 Update composer.json 2015-03-23 19:40:37 +00:00
Graham Campbell
ce92de2f7e Loosen some version constraints 2015-03-23 19:38:08 +00:00
Joseph Cohen
da9c32d38a Update dependencies 2015-03-21 03:05:11 -06:00
Joseph Cohen
41186b7271 CS fixes 2015-03-21 02:56:01 -06:00
Joseph Cohen
44ac45fc6b Fix loadconfix exceptions 2015-03-21 02:52:59 -06:00
Joseph Cohen
09e83ab689 Fix tests 2015-03-21 02:33:38 -06:00
Joseph Cohen
c5a93d99a7 Remove unused clases and use abstract controller 2015-03-21 02:21:20 -06:00
Joseph Cohen
d4fa4e59a0 Fix segment implementation 2015-03-21 02:16:45 -06:00
James Brooks
c1c3eb65d9 Fix unknown AbstractController import 2015-03-21 07:36:34 +00:00
Joseph Cohen
bdbd1cbd1e Added Laravel-Segment 2.0 2015-03-20 18:34:05 -06:00
Joseph Cohen
1ca9b85389 CS Fixes 2015-03-20 18:32:24 -06:00
Joseph Cohen
b4ac66d727 Cachet is now a Laravel 5 app 2015-03-20 18:30:45 -06:00
499 changed files with 17065 additions and 9269 deletions

View File

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

View File

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

26
.env.example Normal file
View File

@@ -0,0 +1,26 @@
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

View File

@@ -1,11 +0,0 @@
<?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',
];

View File

@@ -1,14 +0,0 @@
<?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,9 +1,3 @@
* text=auto
/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
*.css linguist-vendored
*.less linguist-vendored

24
.gitignore vendored
View File

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

View File

@@ -1,22 +1,15 @@
language: php
php:
- 5.4
- 5.5.9
- 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,16 +2,15 @@
## Creating issues
Issues should be made by using the [issue tracker](https://github.com/cachethq/Cachet/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).
Things to remember:
- Be descriptive
- Be respectful of others
**Always be respectful.** Organization members reserve the right to lock topics if they feel necessary.
## Languages
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.
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.
## Coding Standards
@@ -20,9 +19,9 @@ Please follow existing coding standards:
```php
<?php
namespace Foo\Bar\Controller;
namespace CachetHQ\Cachet\Controller;
use Foo\Bar\Bar;
use CachetHQ\Cachet\Bar;
class Foo extends Bar
{
@@ -50,14 +49,13 @@ 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.
- If your pull request consists of more than two commits, you **must** squash them into one.
- 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 you're still unsure, then take a look at existing code.
@@ -75,8 +73,6 @@ 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).
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)
## .editorconfig
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.

View File

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

View File

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

View File

@@ -1,85 +1,55 @@
# Cachet [![Deploy](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy)
# Cachet
[![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-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)
[![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)
![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 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.
- 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
## Requirements
- PHP 5.4 or newer
- mcrypt extension
- PHP 5.5.9+ or newer
- [Composer](https://getcomposer.org)
### Development Requirements
The following extra dependencies are required to develop Cachet.
Theses extra dependencies are required to develop Cachet:
- Node.js
+ Bower
+ Gulp
- Bower
- Gulp
## Installation & Documentation
## Installation, Upgrades and Documentation
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)
You can now find our documentation at [https://docs.cachethq.io](https://docs.cachethq.io).
## What Cachet is not
- [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)
Here is a list of things that Cachet is not or does not do:
### Demo Account
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.
To test out the demo, you may login to the [Dashboard](https://demo.cachethq.io/dashboard) with the following:
## Quickstart with Docker
- **Username:** test@test.com
- **Password:** test123
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.
## 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).
The demo is reset every half hour.
## Translations

View File

@@ -1,34 +0,0 @@
{
"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

@@ -0,0 +1,36 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
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,19 +1,26 @@
<?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\Models\Component;
use CachetHQ\Cachet\Models\Incident;
use Illuminate\View\View;
use Illuminate\Contracts\View\View;
class DashboardComposer
{
/**
* Bind data to the view.
*
* @param \Illuminate\View\View $view
*
* @return void
* @param \Illuminate\Contracts\View\View $view
*/
public function compose(View $view)
{

View File

@@ -1,19 +1,26 @@
<?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\Models\Component;
use CachetHQ\Cachet\Models\Incident;
use Illuminate\View\View;
use Illuminate\Contracts\View\View;
class IndexComposer
{
/**
* Index page view composer.
*
* @param \Illuminate\View\View $view
*
* @return void
* @param \Illuminate\Contracts\View\View $view
*/
public function compose(View $view)
{
@@ -21,6 +28,7 @@ class IndexComposer
$withData = [
'systemStatus' => 'danger',
'systemMessage' => trans('cachet.service.bad'),
'favicon' => 'favicon-high-alert',
];
if (Component::notStatus(1)->count() === 0) {
@@ -32,8 +40,13 @@ class IndexComposer
$withData = [
'systemStatus' => 'success',
'systemMessage' => trans('cachet.service.good'),
'favicon' => 'favicon',
];
}
} else {
if (Component::whereIn('status', [2, 3])->count() > 0) {
$withData['favicon'] = 'favicon-medium-alert';
}
}
$view->with($withData);

View File

@@ -0,0 +1,28 @@
<?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

@@ -0,0 +1,37 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\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,20 +1,27 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Composers;
use DateTime;
use DateTimeZone;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Facades\Config;
use Illuminate\View\View;
class TimezoneLocaleComposer
{
/**
* Timezones and Locales composer.
*
* @param \Illuminate\View\View $view
*
* @return void
* @param \Illuminate\Contracts\View\View $view
*/
public function compose(View $view)
{
@@ -24,7 +31,7 @@ class TimezoneLocaleComposer
$locale = basename($lang);
return [$locale => $enabledLangs[$locale]];
}, glob(app_path('lang').'/*'));
}, glob(base_path('resources/lang').'/*'));
$langs = call_user_func_array('array_merge', $langs);

View File

@@ -1,5 +1,14 @@
<?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\Config;
use CachetHQ\Cachet\Models\Setting;
@@ -24,8 +33,6 @@ class Repository
* Create a new settings service instance.
*
* @param \CachetHQ\Cachet\Models\Setting $model
*
* @return void
*/
public function __construct(Setting $model)
{
@@ -35,27 +42,32 @@ class Repository
/**
* Returns a setting from the database.
*
* @param string $name
* @param bool $checkEnv
* @param string $name
* @param string|null $default
* @param bool $checkEnv
*
* @return string|null
*/
public function get($name, $checkEnv = true)
public function get($name, $default = null, $checkEnv = true)
{
// if we've not loaded the settings, load them now
if (!$this->settings) {
$this->settings = $this->model->all()->lists('value', 'name');
}
// if the setting exists, return it
if (isset($this->settings[$name])) {
// if the setting exists and is not blank, return it
if (!empty($this->settings[$name])) {
return $this->settings[$name];
}
// fallback to getenv if allowed to
if ($checkEnv) {
return $this->settings[$name] = getenv(strtoupper($name));
if ($this->settings[$name] = env(strtoupper($name))) {
return $this->settings[$name];
}
}
return $default;
}
/**
@@ -63,8 +75,6 @@ class Repository
*
* @param string $name
* @param string $value
*
* @return void
*/
public function set($name, $value)
{

View File

@@ -1,5 +1,14 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Console\Commands;
use DirectoryIterator;
@@ -19,7 +28,7 @@ class FixPermissionsCommand extends Command
*
* @var string
*/
protected $description = 'Fixes file and directory permissions. Ensures SQLite database is writeable.';
protected $description = 'Fixes file and directory permissions. Ensures SQLite database is writable.';
/**
* Path to the storage directory.
@@ -56,8 +65,6 @@ class FixPermissionsCommand extends Command
* @param string $databaseDirectory
* @param string $databasePath
* @param string $databaseDefault
*
* @return void
*/
public function __construct($storageDirectory, $databaseDirectory, $databasePath, $databaseDefault)
{
@@ -71,8 +78,6 @@ class FixPermissionsCommand extends Command
/**
* Execute the console command.
*
* @return void
*/
public function fire()
{
@@ -89,8 +94,6 @@ class FixPermissionsCommand extends Command
*
* @param string $path
* @param string $mode
*
* @return void
*/
protected function recursiveChmod($path, $mode = '0755')
{

37
app/Console/Kernel.php Normal file
View File

@@ -0,0 +1,37 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\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

@@ -0,0 +1,32 @@
<?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

@@ -0,0 +1,32 @@
<?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

@@ -0,0 +1,32 @@
<?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

@@ -0,0 +1,87 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\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

@@ -0,0 +1,57 @@
<?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

@@ -0,0 +1,27 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\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

@@ -0,0 +1,41 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\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,5 +1,14 @@
<?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\Facades;
use Illuminate\Support\Facades\Facade;

View File

@@ -0,0 +1,89 @@
<?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

@@ -0,0 +1,86 @@
<?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

@@ -0,0 +1,58 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\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

@@ -0,0 +1,21 @@
<?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,15 +1,25 @@
<?php
namespace CachetHQ\Cachet\Http\Controllers;
/*
* 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\Http\Controllers\AbstractController;
use CachetHQ\Cachet\Models\Component;
use CachetHQ\Cachet\Models\ComponentGroup;
use CachetHQ\Cachet\Models\IncidentTemplate;
use Exception;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Routing\Controller;
class DashAPIController extends Controller
class ApiController extends AbstractController
{
/**
* Updates a component with the entered info.
@@ -36,17 +46,34 @@ class DashAPIController extends Controller
*/
public function postUpdateComponentOrder()
{
$componentData = Binput::all();
unset($componentData['component'][0]); // Remove random 0 index.
$componentData = Binput::get('ids');
foreach ($componentData['component'] as $componentId => $order) {
$component = Component::find($componentId);
$component->update(['order' => $order]);
foreach ($componentData as $order => $componentId) {
// Ordering should be 1-based, data comes in 0-based
Component::find($componentId)->update(['order' => $order + 1]);
}
return $componentData;
}
/**
* Updates the order of component groups.
*
* @return array
*/
public function postUpdateComponentGroupOrder()
{
$groupData = Binput::get('ids');
foreach ($groupData as $order => $groupId) {
ComponentGroup::find($groupId)->update([
'order' => $order + 1,
]);
}
return $groupData;
}
/**
* Returns a template by slug.
*

View File

@@ -1,17 +1,25 @@
<?php
namespace CachetHQ\Cachet\Http\Controllers;
/*
* 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\Http\Controllers\AbstractController;
use CachetHQ\Cachet\Models\Component;
use CachetHQ\Cachet\Models\ComponentGroup;
use CachetHQ\Cachet\Models\Tag;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\View;
class DashComponentController extends Controller
class ComponentController extends AbstractController
{
protected $subMenu = [];
@@ -32,9 +40,10 @@ class DashComponentController extends Controller
],
];
View::share('subMenu', $this->subMenu);
View::share('subTitle', trans_choice('dashboard.components.components', 2));
View::share([
'sub_menu' => $this->subMenu,
'sub_title' => trans_choice('dashboard.components.components', 2),
]);
}
/**
@@ -49,9 +58,9 @@ class DashComponentController extends Controller
$this->subMenu['components']['active'] = true;
return View::make('dashboard.components.index')->with([
'pageTitle' => trans_choice('dashboard.components.components', 2).' - '.trans('dashboard.dashboard'),
'page_title' => trans_choice('dashboard.components.components', 2).' - '.trans('dashboard.dashboard'),
'components' => $components,
'subMenu' => $this->subMenu,
'sub_menu' => $this->subMenu,
]);
}
@@ -65,9 +74,9 @@ class DashComponentController extends Controller
$this->subMenu['groups']['active'] = true;
return View::make('dashboard.components.groups.index')->with([
'pageTitle' => trans_choice('dashboard.components.groups.groups', 2).' - '.trans('dashboard.dashboard'),
'groups' => ComponentGroup::all(),
'subMenu' => $this->subMenu,
'page_title' => trans_choice('dashboard.components.groups.groups', 2).' - '.trans('dashboard.dashboard'),
'groups' => ComponentGroup::orderBy('order')->get(),
'sub_menu' => $this->subMenu,
]);
}
@@ -90,9 +99,9 @@ class DashComponentController extends Controller
);
return View::make('dashboard.components.edit')->with([
'pageTitle' => $pageTitle,
'component' => $component,
'groups' => $groups,
'page_title' => $pageTitle,
'component' => $component,
'groups' => $groups,
]);
}
@@ -106,31 +115,20 @@ class DashComponentController extends Controller
public function updateComponentAction(Component $component)
{
$_component = Binput::get('component');
$_component['user_id'] = Auth::user()->id;
$tags = array_pull($_component, 'tags');
$component->update($_component);
if (! $component->isValid()) {
segment_track('Dashboard', [
'event' => 'Edit Component',
'success' => false,
]);
if (!$component->isValid()) {
return Redirect::back()->withInput(Binput::all())
->with('title', sprintf(
'<strong>%s</strong> %s',
'%s %s',
trans('dashboard.notifications.whoops'),
trans('dashboard.components.edit.failure')
))
->with('errors', $component->getErrors());
}
segment_track('Dashboard', [
'event' => 'Edit Component',
'success' => true,
]);
// The component was added successfully, so now let's deal with the tags.
$tags = preg_split('/ ?, ?/', $tags);
@@ -144,7 +142,7 @@ class DashComponentController extends Controller
$component->tags()->sync($componentTags);
$successMsg = sprintf(
'<strong>%s</strong> %s',
'%s %s',
trans('dashboard.notifications.awesome'),
trans('dashboard.components.edit.success')
);
@@ -162,8 +160,8 @@ class DashComponentController extends Controller
$groups = ComponentGroup::all();
return View::make('dashboard.components.add')->with([
'pageTitle' => trans('dashboard.components.add.title').' - '.trans('dashboard.dashboard'),
'groups' => $groups,
'page_title' => trans('dashboard.components.add.title').' - '.trans('dashboard.dashboard'),
'groups' => $groups,
]);
}
@@ -175,32 +173,21 @@ class DashComponentController extends Controller
public function createComponentAction()
{
$_component = Binput::get('component');
$_component['user_id'] = Auth::user()->id;
// We deal with tags separately.
$tags = array_pull($_component, 'tags');
$component = Component::create($_component);
if (! $component->isValid()) {
segment_track('Dashboard', [
'event' => 'Created Component',
'success' => false,
]);
if (!$component->isValid()) {
return Redirect::back()->withInput(Binput::all())
->with('title', sprintf(
'<strong>%s</strong> %s',
'%s %s',
trans('dashboard.notifications.whoops'),
trans('dashboard.components.add.failure')
))
->with('errors', $component->getErrors());
}
segment_track('Dashboard', [
'event' => 'Created Component',
'success' => true,
]);
// The component was added successfully, so now let's deal with the tags.
$tags = preg_split('/ ?, ?/', $tags);
@@ -214,7 +201,7 @@ class DashComponentController extends Controller
$component->tags()->sync($componentTags);
$successMsg = sprintf(
'<strong>%s</strong> %s',
'%s %s',
trans('dashboard.notifications.awesome'),
trans('dashboard.components.add.success')
);
@@ -231,10 +218,6 @@ class DashComponentController extends Controller
*/
public function deleteComponentAction(Component $component)
{
segment_track('Dashboard', [
'event' => 'Deleted Component',
]);
$component->delete();
return Redirect::back();
@@ -249,9 +232,11 @@ class DashComponentController extends Controller
*/
public function deleteComponentGroupAction(ComponentGroup $group)
{
segment_track('Dashboard', [
'event' => 'Deleted Component Group',
]);
$group->components->map(function ($component) {
$component->update([
'group_id' => 0,
]);
});
$group->delete();
@@ -266,7 +251,7 @@ class DashComponentController extends Controller
public function showAddComponentGroup()
{
return View::make('dashboard.components.groups.add')->with([
'pageTitle' => trans('dashboard.components.groups.add.title').' - '.trans('dashboard.dashboard'),
'page_title' => trans('dashboard.components.groups.add.title').' - '.trans('dashboard.dashboard'),
]);
}
@@ -280,8 +265,8 @@ class DashComponentController extends Controller
public function showEditComponentGroup(ComponentGroup $group)
{
return View::make('dashboard.components.groups.edit')->with([
'pageTitle' => trans('dashboard.components.groups.edit.title').' - '.trans('dashboard.dashboard'),
'group' => $group,
'page_title' => trans('dashboard.components.groups.edit.title').' - '.trans('dashboard.dashboard'),
'group' => $group,
]);
}
@@ -294,28 +279,18 @@ class DashComponentController extends Controller
{
$group = ComponentGroup::create(Binput::get('group'));
if (! $group->isValid()) {
segment_track('Dashboard', [
'event' => 'Created Component Group',
'success' => false,
]);
if (!$group->isValid()) {
return Redirect::back()->withInput(Binput::all())
->with('title', sprintf(
'<strong>%s</strong> %s',
'%s %s',
trans('dashboard.notifications.whoops'),
trans('dashboard.components.groups.add.failure')
))
->with('errors', $group->getErrors());
}
segment_track('Dashboard', [
'event' => 'Created Component Group',
'success' => true,
]);
$successMsg = sprintf(
'<strong>%s</strong> %s',
'%s %s',
trans('dashboard.notifications.awesome'),
trans('dashboard.components.groups.add.success')
);
@@ -335,28 +310,18 @@ class DashComponentController extends Controller
$groupData = Binput::get('group');
$group->update($groupData);
if (! $group->isValid()) {
segment_track('Dashboard', [
'event' => 'Edit Component Group',
'success' => false,
]);
if (!$group->isValid()) {
return Redirect::back()->withInput(Binput::all())
->with('title', sprintf(
'<strong>%s</strong> %s',
'%s %s',
trans('dashboard.notifications.whoops'),
trans('dashboard.components.groups.edit.failure')
))
->with('errors', $group->getErrors());
}
segment_track('Dashboard', [
'event' => 'Edit Component Group',
'success' => true,
]);
$successMsg = sprintf(
'<strong>%s</strong> %s',
'%s %s',
trans('dashboard.notifications.awesome'),
trans('dashboard.components.groups.edit.success')
);

View File

@@ -1,12 +1,21 @@
<?php
namespace CachetHQ\Cachet\Http\Controllers;
/*
* 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\Http\Controllers\AbstractController;
use CachetHQ\Cachet\Models\Component;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\View;
class DashboardController extends Controller
class DashboardController extends AbstractController
{
/**
* Shows the dashboard view.
@@ -15,7 +24,7 @@ class DashboardController extends Controller
*/
public function showDashboard()
{
$components = Component::all();
$components = Component::orderBy('order')->get();
return View::make('dashboard.index')->with([
'components' => $components,
@@ -30,7 +39,7 @@ class DashboardController extends Controller
public function showNotifications()
{
return View::make('dashboard.notifications.index')->with([
'pageTitle' => trans('dashboard.notifications.notifications').' - '.trans('dashboard.dashboard'),
'page_title' => trans('dashboard.notifications.notifications').' '.trans('dashboard.dashboard'),
]);
}
}

View File

@@ -1,17 +1,30 @@
<?php
namespace CachetHQ\Cachet\Http\Controllers;
/*
* 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\IncidentHasReportedEvent;
use CachetHQ\Cachet\Facades\Setting;
use CachetHQ\Cachet\Http\Controllers\AbstractController;
use CachetHQ\Cachet\Models\Component;
use CachetHQ\Cachet\Models\ComponentGroup;
use CachetHQ\Cachet\Models\Incident;
use CachetHQ\Cachet\Models\IncidentTemplate;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\View;
use Jenssegers\Date\Date;
class DashIncidentController extends Controller
class IncidentController extends AbstractController
{
/**
* Stores the sub-sidebar tree list.
@@ -34,7 +47,7 @@ class DashIncidentController extends Controller
'icon' => 'ion-android-checkmark-circle',
'active' => true,
],
'schedule' => [
'schedule' => [
'title' => trans('dashboard.schedule.schedule'),
'url' => route('dashboard.schedule'),
'icon' => 'ion-android-calendar',
@@ -42,8 +55,8 @@ class DashIncidentController extends Controller
],
];
View::share('subMenu', $this->subMenu);
View::share('subTitle', trans('dashboard.incidents.title'));
View::share('sub_menu', $this->subMenu);
View::share('sub_title', trans('dashboard.incidents.title'));
}
/**
@@ -56,8 +69,8 @@ class DashIncidentController extends Controller
$incidents = Incident::notScheduled()->orderBy('created_at', 'desc')->get();
return View::make('dashboard.incidents.index')->with([
'pageTitle' => trans('dashboard.incidents.incidents').' - '.trans('dashboard.dashboard'),
'incidents' => $incidents,
'page_title' => trans('dashboard.incidents.incidents').' - '.trans('dashboard.dashboard'),
'incidents' => $incidents,
]);
}
@@ -68,10 +81,14 @@ class DashIncidentController extends Controller
*/
public function showAddIncident()
{
$componentsInGroups = ComponentGroup::with('components')->get();
$componentsOutGroups = Component::where('group_id', 0)->get();
return View::make('dashboard.incidents.add')->with([
'pageTitle' => trans('dashboard.incidents.add.title').' - '.trans('dashboard.dashboard'),
'components' => Component::all(),
'incidentTemplates' => IncidentTemplate::all(),
'page_title' => trans('dashboard.incidents.add.title').' - '.trans('dashboard.dashboard'),
'componentsInGroups' => $componentsInGroups,
'componentsOutGroups' => $componentsOutGroups,
'incidentTemplates' => IncidentTemplate::all(),
]);
}
@@ -83,7 +100,7 @@ class DashIncidentController extends Controller
public function showTemplates()
{
return View::make('dashboard.incidents.templates.index')->with([
'pageTitle' => trans('dashboard.incidents.templates.title').' - '.trans('dashboard.dashboard'),
'page_title' => trans('dashboard.incidents.templates.title').' - '.trans('dashboard.dashboard'),
'incidentTemplates' => IncidentTemplate::all(),
]);
}
@@ -96,20 +113,22 @@ class DashIncidentController extends Controller
public function createIncidentAction()
{
$incidentData = Binput::get('incident');
$incidentData['user_id'] = Auth::user()->id;
$componentStatus = array_pull($incidentData, 'component_status');
if (array_has($incidentData, 'created_at') && $incidentData['created_at']) {
$incidentDate = Date::createFromFormat('d/m/Y H:i', $incidentData['created_at'], Setting::get('app_timezone'))->setTimezone(Config::get('app.timezone'));
$incidentData['created_at'] = $incidentDate;
$incidentData['updated_at'] = $incidentDate;
} else {
unset($incidentData['created_at']);
}
$incident = Incident::create($incidentData);
if (! $incident->isValid()) {
segment_track('Dashboard', [
'event' => 'Created Incident',
'success' => false,
]);
if (!$incident->isValid()) {
return Redirect::back()->withInput(Binput::all())
->with('title', sprintf(
'<strong>%s</strong> %s',
'%s %s',
trans('dashboard.notifications.whoops'),
trans('dashboard.incidents.add.failure')
))
@@ -123,17 +142,21 @@ class DashIncidentController extends Controller
]);
}
segment_track('Dashboard', [
'event' => 'Created Incident',
'success' => true,
]);
$successMsg = sprintf(
'<strong>%s</strong> %s',
'%s %s',
trans('dashboard.notifications.awesome'),
trans('dashboard.incidents.add.success')
);
$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));
}
return Redirect::back()->with('success', $successMsg);
}
@@ -145,7 +168,7 @@ class DashIncidentController extends Controller
public function showAddIncidentTemplate()
{
return View::make('dashboard.incidents.templates.add')->with([
'pageTitle' => trans('dashboard.incidents.templates.add.title').' - '.trans('dashboard.dashboard'),
'page_title' => trans('dashboard.incidents.templates.add.title').' - '.trans('dashboard.dashboard'),
]);
}
@@ -159,8 +182,8 @@ class DashIncidentController extends Controller
public function showEditTemplateAction(IncidentTemplate $template)
{
return View::make('dashboard.incidents.templates.edit')->with([
'pageTitle' => trans('dashboard.incidents.templates.edit.title').' - '.trans('dashboard.dashboard'),
'template' => $template,
'page_title' => trans('dashboard.incidents.templates.edit.title').' - '.trans('dashboard.dashboard'),
'template' => $template,
]);
}
@@ -173,10 +196,6 @@ class DashIncidentController extends Controller
*/
public function deleteTemplateAction(IncidentTemplate $template)
{
segment_track('Dashboard', [
'event' => 'Deleted Incident Template',
]);
$template->delete();
return Redirect::back();
@@ -192,28 +211,18 @@ class DashIncidentController extends Controller
$_template = Binput::get('template');
$template = IncidentTemplate::create($_template);
if (! $template->isValid()) {
segment_track('Dashboard', [
'event' => 'Created Incident Template',
'success' => false,
]);
if (!$template->isValid()) {
return Redirect::back()->withInput(Binput::all())
->with('title', sprintf(
'<strong>%s</strong> %s',
trans('dashboard.notifications.awesome'),
'%s %s',
trans('dashboard.notifications.whoops'),
trans('dashboard.incidents.templates.add.failure')
))
->with('errors', $template->getErrors());
}
segment_track('Dashboard', [
'event' => 'Created Incident Template',
'success' => true,
]);
$successMsg = sprintf(
'<strong>%s</strong> %s',
'%s %s',
trans('dashboard.notifications.awesome'),
trans('dashboard.incidents.templates.add.success')
);
@@ -230,10 +239,6 @@ class DashIncidentController extends Controller
*/
public function deleteIncidentAction(Incident $incident)
{
segment_track('Dashboard', [
'event' => 'Deleted Incident',
]);
$incident->delete();
return Redirect::back();
@@ -248,10 +253,14 @@ class DashIncidentController extends Controller
*/
public function showEditIncidentAction(Incident $incident)
{
$componentsInGroups = ComponentGroup::with('components')->get();
$componentsOutGroups = Component::where('group_id', 0)->get();
return View::make('dashboard.incidents.edit')->with([
'pageTitle' => trans('dashboard.incidents.edit.title').' - '.trans('dashboard.dashboard'),
'incident' => $incident,
'components' => Component::all(),
'page_title' => trans('dashboard.incidents.edit.title').' - '.trans('dashboard.dashboard'),
'incident' => $incident,
'componentsInGroups' => $componentsInGroups,
'componentsOutGroups' => $componentsOutGroups,
]);
}
@@ -265,31 +274,36 @@ class DashIncidentController extends Controller
public function editIncidentAction(Incident $incident)
{
$incidentData = Binput::get('incident');
$incidentData['user_id'] = Auth::user()->id;
if (array_has($incidentData, 'created_at') && $incidentData['created_at']) {
$incidentDate = Date::createFromFormat('d/m/Y H:i', $incidentData['created_at'], Setting::get('app_timezone'))->setTimezone(Config::get('app.timezone'));
$incidentData['created_at'] = $incidentDate;
$incidentData['updated_at'] = $incidentDate;
} else {
unset($incidentData['created_at']);
}
$incident->update($incidentData);
if (! $incident->isValid()) {
segment_track('Dashboard', [
'event' => 'Edited Incident',
'success' => false,
]);
if (!$incident->isValid()) {
return Redirect::back()->withInput(Binput::all())
->with('title', sprintf(
'<strong>%s</strong> %s',
trans('dashboard.notifications.awesome'),
'%s %s',
trans('dashboard.notifications.whoops'),
trans('dashboard.incidents.templates.edit.failure')
))
->with('errors', $incident->getErrors());
}
segment_track('Dashboard', [
'event' => 'Edited Incident',
'success' => true,
]);
$componentStatus = array_pull($incidentData, 'component_status');
if ($incident->component) {
$incident->component->update([
'status' => $componentStatus,
]);
}
$successMsg = sprintf(
'<strong>%s</strong> %s',
'%s %s',
trans('dashboard.notifications.awesome'),
trans('dashboard.incidents.edit.success')
);
@@ -306,10 +320,6 @@ class DashIncidentController extends Controller
*/
public function editTemplateAction(IncidentTemplate $template)
{
segment_track('Dashboard', [
'event' => 'Edited Incident Template',
]);
$template->update(Binput::get('template'));
return Redirect::back()->with('updatedTemplate', $template);

View File

@@ -1,15 +1,24 @@
<?php
namespace CachetHQ\Cachet\Http\Controllers;
/*
* 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\Http\Controllers\AbstractController;
use CachetHQ\Cachet\Models\Metric;
use CachetHQ\Cachet\Models\MetricPoint;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\View;
class DashMetricController extends Controller
class MetricController extends AbstractController
{
/**
* Shows the metrics view.
@@ -21,8 +30,8 @@ class DashMetricController extends Controller
$metrics = Metric::orderBy('created_at', 'desc')->get();
return View::make('dashboard.metrics.index')->with([
'pageTitle' => trans('dashboard.metrics.metrics').' - '.trans('dashboard.dashboard'),
'metrics' => $metrics,
'page_title' => trans('dashboard.metrics.metrics').' - '.trans('dashboard.dashboard'),
'metrics' => $metrics,
]);
}
@@ -34,8 +43,8 @@ class DashMetricController extends Controller
public function showAddMetric()
{
return View::make('dashboard.metrics.add')->with([
'pageTitle' => trans('dashboard.metrics.add.title').' - '.trans('dashboard.dashboard'),
'metricMetricPoints' => MetricPoint::all(),
'page_title' => trans('dashboard.metrics.add.title').' - '.trans('dashboard.dashboard'),
'metricMetricPoints' => MetricPoint::all(),
]);
}
@@ -47,7 +56,7 @@ class DashMetricController extends Controller
public function showMetricPoints()
{
return View::make('dashboard.metrics.points.index')->with([
'pageTitle' => trans('dashboard.metrics.points.title').' - '.trans('dashboard.dashboard'),
'page_title' => trans('dashboard.metrics.points.title').' - '.trans('dashboard.dashboard'),
'metricMetricPoints' => MetricPoint::all(),
]);
}
@@ -62,28 +71,18 @@ class DashMetricController extends Controller
$metricData = Binput::get('metric');
$metric = Metric::create($metricData);
if (! $metric->isValid()) {
segment_track('Dashboard', [
'event' => 'Created Metric',
'success' => false,
]);
if (!$metric->isValid()) {
return Redirect::back()->withInput(Binput::all())
->with('title', sprintf(
'<strong>%s</strong> %s',
'%s %s',
trans('dashboard.notifications.whoops'),
trans('dashboard.metrics.add.failure')
))
->with('errors', $metric->getErrors());
}
segment_track('Dashboard', [
'event' => 'Created Metric',
'success' => true,
]);
$successMsg = sprintf(
'<strong>%s</strong> %s',
'%s %s',
trans('dashboard.notifications.awesome'),
trans('dashboard.metrics.add.success')
);
@@ -99,7 +98,7 @@ class DashMetricController extends Controller
public function showAddMetricPoint()
{
return View::make('dashboard.metrics.points.add')->with([
'pageTitle' => trans('dashboard.metrics.points.add.title').' - '.trans('dashboard.dashboard'),
'page_title' => trans('dashboard.metrics.points.add.title').' - '.trans('dashboard.dashboard'),
]);
}
@@ -110,21 +109,21 @@ class DashMetricController extends Controller
*/
public function createMetricPointAction()
{
$_point = Binput::get('point');
$_point = Binput::get('point', null, false);
$point = MetricPoint::create($_point);
if (! $point->isValid()) {
if (!$point->isValid()) {
return Redirect::back()->withInput(Binput::all())
->with('title', sprintf(
'<strong>%s</strong> %s',
trans('dashboard.notifications.awesome'),
'%s %s',
trans('dashboard.notifications.whoops'),
trans('dashboard.metrics.points.add.failure')
))
->with('errors', $point->getErrors());
}
$successMsg = sprintf(
'<strong>%s</strong> %s',
'%s %s',
trans('dashboard.notifications.awesome'),
trans('dashboard.metrics.points.add.success')
);
@@ -156,7 +155,7 @@ class DashMetricController extends Controller
public function showEditMetricAction(Metric $metric)
{
return View::make('dashboard.metrics.edit')->with([
'pageTitle' => trans('dashboard.metrics.edit.title').' - '.trans('dashboard.dashboard'),
'page_title' => trans('dashboard.metrics.edit.title').' - '.trans('dashboard.dashboard'),
'metric' => $metric,
]);
}
@@ -170,30 +169,20 @@ class DashMetricController extends Controller
*/
public function editMetricAction(Metric $metric)
{
$_metric = Binput::get('metric');
$metric->update($_metric);
if (! $metric->isValid()) {
segment_track('Dashboard', [
'event' => 'Edited Metric',
'success' => false,
]);
$metricData = Binput::get('metric', null, false);
$metric->update($metricData);
if (!$metric->isValid()) {
return Redirect::back()->withInput(Binput::all())
->with('title', sprintf(
'<strong>%s</strong>',
trans('dashboard.notifications.awesome')
trans('dashboard.notifications.whoops')
))
->with('errors', $metric->getErrors());
}
segment_track('Dashboard', [
'event' => 'Edited Metric',
'success' => true,
]);
$successMsg = sprintf(
'<strong>%s</strong> %s',
'%s %s',
trans('dashboard.notifications.awesome'),
trans('dashboard.metrics.edit.success')
);

View File

@@ -1,20 +1,29 @@
<?php
namespace CachetHQ\Cachet\Http\Controllers;
/*
* 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\MaintenanceHasScheduledEvent;
use CachetHQ\Cachet\Facades\Setting;
use CachetHQ\Cachet\Http\Controllers\AbstractController;
use CachetHQ\Cachet\Models\Incident;
use CachetHQ\Cachet\Models\IncidentTemplate;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\View;
use Illuminate\Support\MessageBag;
use Jenssegers\Date\Date;
class DashScheduleController extends Controller
class ScheduleController extends AbstractController
{
/**
* Stores the sub-sidebar tree list.
@@ -38,7 +47,7 @@ class DashScheduleController extends Controller
'icon' => 'ion-android-checkmark-circle',
'active' => false,
],
'schedule' => [
'schedule' => [
'title' => trans('dashboard.schedule.schedule'),
'url' => route('dashboard.schedule'),
'icon' => 'ion-android-calendar',
@@ -46,8 +55,8 @@ class DashScheduleController extends Controller
],
];
View::share('subMenu', $this->subMenu);
View::share('subTitle', trans('dashboard.incidents.title'));
View::share('sub_menu', $this->subMenu);
View::share('sub_title', trans('dashboard.incidents.title'));
}
/**
@@ -84,7 +93,6 @@ class DashScheduleController extends Controller
public function addScheduleAction()
{
$scheduleData = Binput::get('incident');
$scheduleData['user_id'] = Auth::user()->id;
// Parse the schedule date.
$scheduledAt = Date::createFromFormat('d/m/Y H:i', $scheduleData['scheduled_at'], Setting::get('app_timezone'))
->setTimezone(Config::get('app.timezone'));
@@ -104,32 +112,31 @@ class DashScheduleController extends Controller
$incident = Incident::create($scheduleData);
if (! $incident->isValid()) {
segment_track('Dashboard', [
'event' => 'Created Scheduled Maintenance',
'success' => false,
]);
if (!$incident->isValid()) {
return Redirect::back()->withInput(Binput::all())
->with('success', sprintf(
'<strong>%s</strong> %s',
'%s %s',
trans('dashboard.notifications.whoops'),
trans('dashboard.schedule.add.failure')
))
->with('errors', $incident->getErrors());
}
segment_track('Dashboard', [
'event' => 'Created Scheduled Maintenance',
'success' => true,
]);
$successMsg = sprintf(
'<strong>%s</strong> %s',
'%s %s',
trans('dashboard.notifications.awesome'),
trans('dashboard.schedule.add.success')
);
$isEnabled = (bool) Setting::get('enable_subscribers', false);
$mailAddress = env('MAIL_ADDRESS', false);
$mailFrom = env('MAIL_NAME', false);
$subscribersEnabled = $isEnabled && $mailAddress && $mailFrom;
if (array_get($scheduleData, 'notify') && $subscribersEnabled) {
event(new MaintenanceHasScheduledEvent($incident));
}
return Redirect::back()->with('success', $successMsg);
}
@@ -160,7 +167,6 @@ class DashScheduleController extends Controller
public function editScheduleAction(Incident $schedule)
{
$scheduleData = Binput::get('incident');
$scheduleData['user_id'] = Auth::user()->id;
// Parse the schedule date.
$scheduledAt = Date::createFromFormat('d/m/Y H:i', $scheduleData['scheduled_at'], Setting::get('app_timezone'))
->setTimezone(Config::get('app.timezone'));
@@ -180,28 +186,18 @@ class DashScheduleController extends Controller
$schedule->update($scheduleData);
if (! $schedule->isValid()) {
segment_track('Dashboard', [
'event' => 'Edited Schedule',
'success' => false,
]);
if (!$schedule->isValid()) {
return Redirect::back()->withInput(Binput::all())
->with('title', sprintf(
'<strong>%s</strong> %s',
trans('dashboard.notifications.awesome'),
'%s %s',
trans('dashboard.notifications.whoops'),
trans('dashboard.schedule.edit.failure')
))
->with('errors', $schedule->getErrors());
}
segment_track('Dashboard', [
'event' => 'Edited Schedule',
'success' => true,
]);
$successMsg = sprintf(
'<strong>%s</strong> %s',
'%s %s',
trans('dashboard.notifications.awesome'),
trans('dashboard.schedule.edit.success')
);
@@ -218,14 +214,10 @@ class DashScheduleController extends Controller
*/
public function deleteScheduleAction(Incident $schedule)
{
segment_track('Dashboard', [
'event' => 'Deleted Schedule',
]);
$schedule->delete();
return Redirect::back()->with('warning', sprintf(
'<strong>%s</strong> %s',
'%s %s',
trans('dashboard.notifications.whoops'),
trans('dashboard.schedule.delete.failure')
));

View File

@@ -1,16 +1,26 @@
<?php
namespace CachetHQ\Cachet\Http\Controllers;
/*
* 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\Http\Controllers\AbstractController;
use CachetHQ\Cachet\Models\Setting;
use CachetHQ\Cachet\Models\User;
use Exception;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Lang;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\View;
class DashSettingsController extends Controller
class SettingsController extends AbstractController
{
protected $subMenu = [];
protected $subTitle = 'Settings';
@@ -44,9 +54,9 @@ class DashSettingsController extends Controller
],
];
View::share('subTitle', $this->subTitle);
View::share('sub_title', $this->subTitle);
View::share('subMenu', $this->subMenu);
View::share('sub_menu', $this->subMenu);
}
/**
@@ -59,8 +69,8 @@ class DashSettingsController extends Controller
$this->subMenu['setup']['active'] = true;
return View::make('dashboard.settings.app-setup')->with([
'pageTitle' => 'Application Setup - Dashboard',
'subMenu' => $this->subMenu,
'page_title' => 'Application Setup - Dashboard',
'sub_menu' => $this->subMenu,
]);
}
@@ -74,8 +84,8 @@ class DashSettingsController extends Controller
$this->subMenu['theme']['active'] = true;
return View::make('dashboard.settings.theme')->with([
'pageTitle' => 'Theme - Dashboard',
'subMenu' => $this->subMenu,
'page_title' => 'Theme - Dashboard',
'sub_menu' => $this->subMenu,
]);
}
@@ -88,9 +98,12 @@ class DashSettingsController extends Controller
{
$this->subMenu['security']['active'] = true;
$unsecureUsers = User::whereNull('google_2fa_secret')->orWhere('google_2fa_secret', '')->get();
return View::make('dashboard.settings.security')->with([
'pageTitle' => 'Security - Dashboard',
'subMenu' => $this->subMenu,
'page_title' => 'Security - Dashboard',
'sub_menu' => $this->subMenu,
'unsecureUsers' => $unsecureUsers,
]);
}
@@ -104,8 +117,8 @@ class DashSettingsController extends Controller
$this->subMenu['stylesheet']['active'] = true;
return View::make('dashboard.settings.stylesheet')->with([
'pageTitle' => 'Stylesheet - Dashboard',
'subMenu' => $this->subMenu,
'page_title' => 'Stylesheet - Dashboard',
'sub_menu' => $this->subMenu,
]);
}
@@ -159,6 +172,10 @@ class DashSettingsController extends Controller
try {
foreach (Binput::except(['app_banner', 'remove_banner']) as $settingName => $settingValue) {
if ($settingName === 'app_analytics_pi_url') {
$settingValue = rtrim($settingValue, '/');
}
Setting::firstOrCreate([
'name' => $settingName,
])->update([

View File

@@ -0,0 +1,104 @@
<?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,14 +1,23 @@
<?php
namespace CachetHQ\Cachet\Http\Controllers;
/*
* 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\Http\Controllers\AbstractController;
use CachetHQ\Cachet\Models\User;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\View;
class DashTeamController extends Controller
class TeamController extends AbstractController
{
/**
* Shows the team members view.
@@ -20,7 +29,7 @@ class DashTeamController extends Controller
$team = User::all();
return View::make('dashboard.team.index')->with([
'pageTitle' => trans('dashboard.team.team').' - '.trans('dashboard.dashboard'),
'page_title' => trans('dashboard.team.team').' - '.trans('dashboard.dashboard'),
'teamMembers' => $team,
]);
}
@@ -33,8 +42,8 @@ class DashTeamController extends Controller
public function showTeamMemberView(User $user)
{
return View::make('dashboard.team.edit')->with([
'pageTitle' => trans('dashboard.team.edit.title').' - '.trans('dashboard.dashboard'),
'user' => $user,
'page_title' => trans('dashboard.team.edit.title').' - '.trans('dashboard.dashboard'),
'user' => $user,
]);
}
@@ -46,7 +55,7 @@ class DashTeamController extends Controller
public function showAddTeamMemberView()
{
return View::make('dashboard.team.add')->with([
'pageTitle' => trans('dashboard.team.add.title').' - '.trans('dashboard.dashboard'),
'page_title' => trans('dashboard.team.add.title').' - '.trans('dashboard.dashboard'),
]);
}
@@ -59,28 +68,18 @@ class DashTeamController extends Controller
{
$user = User::create(Binput::all());
if (! $user->isValid()) {
segment_track('Dashboard', [
'event' => 'Added User',
'success' => false,
]);
if (!$user->isValid()) {
return Redirect::back()->withInput(Binput::except('password'))
->with('title', sprintf(
'<strong>%s</strong> %s',
'%s %s',
trans('dashboard.notifications.whoops'),
trans('dashboard.team.add.failure')
))
->with('errors', $user->getErrors());
}
segment_track('Dashboard', [
'event' => 'Added User',
'success' => true,
]);
$successMsg = sprintf(
'<strong>%s</strong> %s',
'%s %s',
trans('dashboard.notifications.awesome'),
trans('dashboard.team.add.success')
);
@@ -107,28 +106,18 @@ class DashTeamController extends Controller
$user->update($items);
if (! $user->isValid()) {
segment_track('Dashboard', [
'event' => 'Updated User',
'success' => false,
]);
if (!$user->isValid()) {
return Redirect::back()->withInput(Binput::except('password'))
->with('title', sprintf(
'<strong>%s</strong> %s',
'%s %s',
trans('dashboard.notifications.whoops'),
trans('dashboard.team.edit.failure')
))
->with('errors', $user->getErrors());
}
segment_track('Dashboard', [
'event' => 'Updated User',
'success' => true,
]);
$successMsg = sprintf(
'<strong>%s</strong> %s',
'%s %s',
trans('dashboard.notifications.awesome'),
trans('dashboard.team.edit.success')
);

View File

@@ -1,16 +1,25 @@
<?php
namespace CachetHQ\Cachet\Http\Controllers;
/*
* 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\Http\Controllers\AbstractController;
use CachetHQ\Cachet\Models\User;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\View;
use PragmaRX\Google2FA\Vendor\Laravel\Facade as Google2FA;
class DashUserController extends Controller
class UserController extends AbstractController
{
/**
* Shows the user view.
@@ -20,7 +29,7 @@ class DashUserController extends Controller
public function showUser()
{
return View::make('dashboard.user.index')->with([
'pageTitle' => trans('dashboard.team.profile').' - '.trans('dashboard.dashboard'),
'page_title' => trans('dashboard.team.profile').' - '.trans('dashboard.dashboard'),
]);
}
@@ -37,20 +46,10 @@ class DashUserController extends Controller
$enable2FA = (bool) array_pull($items, 'google2fa');
// Let's enable/disable auth
if ($enable2FA && ! Auth::user()->hasTwoFactor) {
if ($enable2FA && !Auth::user()->hasTwoFactor) {
$items['google_2fa_secret'] = Google2FA::generateSecretKey();
segment_track('User Management', [
'event' => 'enabled_two_factor',
'value' => true,
]);
} elseif (! $enable2FA) {
} elseif (!$enable2FA) {
$items['google_2fa_secret'] = '';
segment_track('User Management', [
'event' => 'enabled_two_factor',
'value' => false,
]);
}
if (trim($passwordChange) === '') {
@@ -60,10 +59,10 @@ class DashUserController extends Controller
$user = Auth::user();
$user->update($items);
if (! $user->isValid()) {
if (!$user->isValid()) {
return Redirect::back()->withInput(Binput::except('password'))
->with('title', sprintf(
'<strong>%s</strong> %s',
'%s %s',
trans('dashboard.notifications.whoops'),
trans('dashboard.team.edit.failure')
))
@@ -71,7 +70,7 @@ class DashUserController extends Controller
}
$successMsg = sprintf(
'<strong>%s</strong> %s',
'%s %s',
trans('dashboard.notifications.awesome'),
trans('dashboard.team.edit.success')
);
@@ -86,10 +85,6 @@ class DashUserController extends Controller
*/
public function regenerateApiKey(User $user)
{
segment_track('User Management', [
'event' => 'regenrated_api_token',
]);
$user->api_key = User::generateApiKey();
$user->save();

View File

@@ -0,0 +1,204 @@
<?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

@@ -0,0 +1,132 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Controllers\Api;
use CachetHQ\Cachet\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

@@ -0,0 +1,20 @@
<?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

@@ -0,0 +1,123 @@
<?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

@@ -0,0 +1,111 @@
<?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

@@ -0,0 +1,98 @@
<?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

@@ -0,0 +1,77 @@
<?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

@@ -0,0 +1,70 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Controllers;
use CachetHQ\Cachet\Facades\Setting;
use CachetHQ\Cachet\Models\ComponentGroup;
use CachetHQ\Cachet\Models\Incident;
use GrahamCampbell\Markdown\Facades\Markdown;
use Illuminate\Support\Str;
use Roumen\Feed\Facades\Feed;
class AtomController 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->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('atom');
}
/**
* 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->toAtomString(),
Markdown::convertToHtml($incident->message)
);
}
}

View File

@@ -1,10 +1,17 @@
<?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 GrahamCampbell\Binput\Facades\Binput;
use GrahamCampbell\Throttle\Facades\Throttle;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Request;
@@ -15,7 +22,7 @@ use PragmaRX\Google2FA\Vendor\Laravel\Facade as Google2FA;
/**
* Logs users into their account.
*/
class AuthController extends Controller
class AuthController extends AbstractController
{
/**
* Shows the login view.
@@ -24,7 +31,9 @@ class AuthController extends Controller
*/
public function showLogin()
{
return View::make('auth.login');
return View::make('auth.login')->with([
'page_title' => trans('dashboard.login.login'),
]);
}
/**
@@ -47,14 +56,12 @@ class AuthController extends Controller
return Redirect::route('two-factor');
}
// We probably wan't to add support for "Remember me" here.
// We probably want to add support for "Remember me" here.
Auth::attempt(Binput::only(['email', 'password']));
return Redirect::intended('dashboard');
}
Throttle::hit(Request::instance(), 10, 10);
return Redirect::back()
->withInput(Binput::except('password'))
->with('error', trans('forms.login.invalid'));

View File

@@ -0,0 +1,118 @@
<?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

@@ -0,0 +1,70 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\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

@@ -0,0 +1,216 @@
<?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

@@ -0,0 +1,129 @@
<?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);
}
}

50
app/Http/Kernel.php Normal file
View File

@@ -0,0 +1,50 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\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

@@ -0,0 +1,36 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
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

@@ -0,0 +1,53 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Middleware;
use 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

@@ -0,0 +1,67 @@
<?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,14 +1,22 @@
<?php
namespace CachetHQ\Cachet\Http\Before;
/*
* 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\Http\Request;
use Illuminate\Routing\Route;
use Illuminate\Support\Facades\Redirect;
class IsSetupFilter
class AppIsSetup
{
/**
* Run the is setup filter.
@@ -17,19 +25,21 @@ class IsSetupFilter
* sending the user to the dashboard so they can use Cachet.
*
* @param \Illuminate\Routing\Route $route
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return \Illuminate\Http\Response|null
* @return mixed
*/
public function filter(Route $route, Request $request)
public function handle($request, Closure $next)
{
try {
$setting = Setting::where('name', 'app_name')->first();
if ($setting && $setting->value) {
return Redirect::to('/dashboard');
return Redirect::route('dashboard');
}
} catch (Exception $e) {
// do nothing
}
return $next($request);
}
}

View File

@@ -0,0 +1,53 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Middleware;
use 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

@@ -0,0 +1,62 @@
<?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

@@ -0,0 +1,53 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Middleware;
use 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

@@ -0,0 +1,35 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\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

@@ -0,0 +1,224 @@
<?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

@@ -0,0 +1,69 @@
<?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

@@ -0,0 +1,57 @@
<?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

@@ -0,0 +1,29 @@
<?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

@@ -0,0 +1,36 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
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

@@ -0,0 +1,49 @@
<?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',
]);
});
});
}
}

69
app/Http/helpers.php Normal file
View File

@@ -0,0 +1,69 @@
<?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,51 +1,36 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Models;
use CachetHQ\Cachet\Transformers\ComponentTransformer;
use Dingo\Api\Transformer\TransformableInterface;
use CachetHQ\Cachet\Presenters\ComponentPresenter;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletingTrait;
use Illuminate\Database\Eloquent\SoftDeletes;
use McCool\LaravelAutoPresenter\HasPresenter;
use Watson\Validating\ValidatingTrait;
/**
* @property int $id
* @property int $user_id
* @property string $name
* @property string $description
* @property int $status
* @property string $link
* @property int $order
* @property int $group_id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property \Carbon\Carbon $deleted_at
*/
class Component extends Model implements TransformableInterface
class Component extends Model implements HasPresenter
{
use SoftDeletingTrait, ValidatingTrait;
use SoftDeletes, ValidatingTrait;
/**
* The validation rules.
*
* @var string[]
*/
protected $rulesets = [
[
'creating' => [
'user_id' => 'integer|required',
'name' => 'required',
'status' => 'integer|required',
'link' => 'url',
],
],
[
'updating' => [
'status' => 'integer',
'link' => 'url',
],
],
protected $rules = [
'name' => 'required|string',
'status' => 'integer|required',
'link' => 'url',
];
/**
@@ -57,7 +42,6 @@ class Component extends Model implements TransformableInterface
'name',
'description',
'status',
'user_id',
'tags',
'link',
'order',
@@ -76,6 +60,13 @@ class Component extends Model implements TransformableInterface
'link' => '',
];
/**
* The attributes that should be mutated to dates.
*
* @var array
*/
protected $dates = ['deleted_at'];
/**
* Components can belong to a group.
*
@@ -83,7 +74,7 @@ class Component extends Model implements TransformableInterface
*/
public function group()
{
return $this->belongsTo('CachetHQ\Cachet\Models\ComponentGroup', 'group_id', 'id');
return $this->belongsTo(ComponentGroup::class, 'group_id', 'id');
}
/**
@@ -93,7 +84,7 @@ class Component extends Model implements TransformableInterface
*/
public function incidents()
{
return $this->hasMany('CachetHQ\Cachet\Models\Incident', 'component_id', 'id');
return $this->hasMany(Incident::class, 'component_id', 'id');
}
/**
@@ -103,7 +94,7 @@ class Component extends Model implements TransformableInterface
*/
public function tags()
{
return $this->belongsToMany('CachetHQ\Cachet\Models\Tag');
return $this->belongsToMany(Tag::class);
}
/**
@@ -157,12 +148,12 @@ class Component extends Model implements TransformableInterface
}
/**
* Get the transformer instance.
* Get the presenter class.
*
* @return \CachetHQ\Cachet\Transformers\ComponentTransformer
* @return string
*/
public function getTransformer()
public function getPresenterClass()
{
return new ComponentTransformer();
return ComponentPresenter::class;
}
}

View File

@@ -1,21 +1,22 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletingTrait;
use Watson\Validating\ValidatingTrait;
/**
* @property int $id
* @property string $name
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property \Carbon\Carbon $deleted_at
*/
class ComponentGroup extends Model
{
use SoftDeletingTrait, ValidatingTrait;
use ValidatingTrait;
/**
* The validation rules.
@@ -31,7 +32,7 @@ class ComponentGroup extends Model
*
* @var string[]
*/
protected $fillable = ['name'];
protected $fillable = ['name', 'order'];
/**
* A group can have many components.
@@ -40,6 +41,6 @@ class ComponentGroup extends Model
*/
public function components()
{
return $this->hasMany('CachetHQ\Cachet\Models\Component', 'id', 'group_id');
return $this->hasMany(Component::class, 'group_id', 'id');
}
}

View File

@@ -1,30 +1,26 @@
<?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\Transformers\IncidentTransformer;
use CachetHQ\Cachet\Presenters\IncidentPresenter;
use Carbon\Carbon;
use Dingo\Api\Transformer\TransformableInterface;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletingTrait;
use McCool\LaravelAutoPresenter\PresenterInterface;
use Illuminate\Database\Eloquent\SoftDeletes;
use McCool\LaravelAutoPresenter\HasPresenter;
use Watson\Validating\ValidatingTrait;
/**
* @property int $id
* @property int $component_id
* @property int $user_id
* @property string $name
* @property int $status
* @property string $message
* @property string $humanStatus
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property \Carbon\Carbon $deleted_at
*/
class Incident extends Model implements TransformableInterface, PresenterInterface
class Incident extends Model implements HasPresenter
{
use SoftDeletingTrait, ValidatingTrait;
use SoftDeletes, ValidatingTrait;
/**
* The validation rules.
@@ -32,10 +28,10 @@ class Incident extends Model implements TransformableInterface, PresenterInterfa
* @var string[]
*/
protected $rules = [
'user_id' => 'required|integer',
'component_id' => 'integer',
'name' => 'required',
'status' => 'required|integer',
'visible' => 'required|boolean',
'message' => 'required',
];
@@ -44,14 +40,23 @@ class Incident extends Model implements TransformableInterface, PresenterInterfa
*
* @var string[]
*/
protected $fillable = ['user_id', 'component_id', 'name', 'status', 'message', 'scheduled_at'];
protected $fillable = [
'component_id',
'name',
'status',
'visible',
'message',
'scheduled_at',
'created_at',
'updated_at',
];
/**
* The accessors to append to the model's serialized form.
*
* @var string[]
*/
protected $appends = ['humanStatus'];
protected $appends = ['human_status'];
/**
* The attributes that should be mutated to dates.
@@ -60,6 +65,27 @@ class Incident extends Model implements TransformableInterface, PresenterInterfa
*/
protected $dates = ['scheduled_at', 'deleted_at'];
/**
* The attributes that should be casted to native types.
*
* @var string[]
*/
protected $casts = [
'visible' => 'integer',
];
/**
* Finds all visible incidents.
*
* @param \Illuminate\Database\Eloquent\Builder $query
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeVisible($query)
{
return $query->where('visible', 1);
}
/**
* Finds all scheduled incidents (maintenance).
*
@@ -86,16 +112,6 @@ class Incident extends Model implements TransformableInterface, PresenterInterfa
});
}
/**
* Get presenter class.
*
* @return string
*/
public function getPresenter()
{
return 'CachetHQ\Cachet\Presenters\IncidentPresenter';
}
/**
* An incident belongs to a component.
*
@@ -103,7 +119,7 @@ class Incident extends Model implements TransformableInterface, PresenterInterfa
*/
public function component()
{
return $this->belongsTo('CachetHQ\Cachet\Models\Component', 'component_id', 'id');
return $this->belongsTo(Component::class, 'component_id', 'id');
}
/**
@@ -125,16 +141,16 @@ class Incident extends Model implements TransformableInterface, PresenterInterfa
*/
public function getIsScheduledAttribute()
{
return $this->getOriginal('scheduled_at');
return $this->getOriginal('scheduled_at') !== null;
}
/**
* Get the transformer instance.
* Get the presenter class.
*
* @return \CachetHQ\Cachet\Transformers\IncidentTransformer
* @return string
*/
public function getTransformer()
public function getPresenterClass()
{
return new IncidentTransformer();
return IncidentPresenter::class;
}
}

View File

@@ -1,19 +1,20 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use Watson\Validating\ValidatingTrait;
/**
* @property int $id
* @property string $name
* @property string $slug
* @property string $template
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
*/
class IncidentTemplate extends Model
{
use ValidatingTrait;
@@ -37,8 +38,6 @@ class IncidentTemplate extends Model
/**
* Overrides the models boot method.
*
* @return void
*/
public static function boot()
{

150
app/Models/Metric.php Normal file
View File

@@ -0,0 +1,150 @@
<?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\Facades\Setting as SettingFacade;
use CachetHQ\Cachet\Presenters\MetricPresenter;
use DateInterval;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\DB;
use Jenssegers\Date\Date;
use McCool\LaravelAutoPresenter\HasPresenter;
use Watson\Validating\ValidatingTrait;
class Metric extends Model implements HasPresenter
{
use ValidatingTrait;
const CALC_SUM = 0;
const CALC_AVG = 1;
/**
* The model's attributes.
*
* @var string[]
*/
protected $attributes = [
'name' => '',
'display_chart' => 1,
'default_value' => 0,
'calc_type' => 0,
];
/**
* The validation rules.
*
* @var string[]
*/
protected $rules = [
'name' => 'required',
'suffix' => 'required',
'display_chart' => 'boolean',
'default_value' => 'numeric',
];
/**
* The fillable properties.
*
* @var string[]
*/
protected $fillable = ['name', 'suffix', 'description', 'display_chart', 'default_value', 'calc_type'];
/**
* The relations to eager load on every query.
*
* @var string[]
*/
protected $with = ['points'];
/**
* Metrics contain many metric points.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function points()
{
return $this->hasMany(MetricPoint::class, 'metric_id', 'id');
}
/**
* Returns the sum of all values a metric has by the hour.
*
* @param int $hour
*
* @return int
*/
public function getValuesByHour($hour)
{
$dateTimeZone = SettingFacade::get('app_timezone');
$dateTime = (new Date())->setTimezone($dateTimeZone)->sub(new DateInterval('PT'.$hour.'H'));
$hourInterval = $dateTime->format('YmdH');
if (Config::get('database.default') === 'mysql') {
if (!isset($this->calc_type) || $this->calc_type == self::CALC_SUM) {
$value = (int) $this->points()
->whereRaw('DATE_FORMAT(created_at, "%Y%m%d%H") = '.$hourInterval)
->groupBy(DB::raw('HOUR(created_at)'))->sum('value');
} elseif ($this->calc_type == self::CALC_AVG) {
$value = (int) $this->points()
->whereRaw('DATE_FORMAT(created_at, "%Y%m%d%H") = '.$hourInterval)
->groupBy(DB::raw('HOUR(created_at)'))->avg('value');
}
} else {
// Default metrics calculations.
if (!isset($this->calc_type) || $this->calc_type == self::CALC_SUM) {
$queryType = 'sum(metric_points.value)';
} elseif ($this->calc_type == self::CALC_AVG) {
$queryType = 'avg(metric_points.value)';
} else {
$queryType = 'sum(metric_points.value)';
}
$query = DB::select("select {$queryType} as aggregate FROM metrics JOIN metric_points ON metric_points.metric_id = metrics.id WHERE metric_points.metric_id = {$this->id} AND to_char(metric_points.created_at, 'YYYYMMDDHH24') = :timestamp GROUP BY to_char(metric_points.created_at, 'H')", [
'timestamp' => $hourInterval,
]);
if (isset($query[0])) {
$value = $query[0]->aggregate;
} else {
$value = 0;
}
}
if ($value === 0 && $this->default_value != $value) {
return $this->default_value;
}
return $value;
}
/**
* Determines whether a chart should be shown.
*
* @return bool
*/
public function getShouldDisplayAttribute()
{
return $this->display_chart === 1;
}
/**
* Get the presenter class.
*
* @return string
*/
public function getPresenterClass()
{
return MetricPresenter::class;
}
}

View File

@@ -0,0 +1,58 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\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,16 +1,18 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Models;
use Illuminate\Database\Eloquent\Model;
/**
* @property int $id
* @property string $name
* @property string $value
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
*/
class Setting extends Model
{
/**

99
app/Models/Subscriber.php Normal file
View File

@@ -0,0 +1,99 @@
<?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,22 +1,21 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use Watson\Validating\ValidatingTrait;
/**
* @property int $id
* @property string $name
* @property string $slug
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
*/
class Tag extends Model
{
use ValidatingTrait;
/**
* The fillable properties.
*
@@ -26,8 +25,6 @@ class Tag extends Model
/**
* Overrides the models boot method.
*
* @return void
*/
public static function boot()
{
@@ -45,6 +42,6 @@ class Tag extends Model
*/
public function components()
{
return $this->belongsToMany('CachetHQ\Cachet\Models\Component');
return $this->belongsToMany(Component::class);
}
}

View File

@@ -1,32 +1,28 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Models;
use Illuminate\Auth\Reminders\RemindableInterface;
use Illuminate\Auth\Reminders\RemindableTrait;
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\UserTrait;
use Illuminate\Auth\Authenticatable;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\Hash;
use Watson\Validating\ValidatingTrait;
/**
* @property int $id
* @property string $username
* @property string $password
* @property string $remember_token
* @property string $google_2fa_secret
* @property string $email
* @property string $api_key
* @property int $active
* @property int $level
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
*/
class User extends Model implements UserInterface, RemindableInterface
class User extends Model implements AuthenticatableContract, CanResetPasswordContract
{
use RemindableTrait, UserTrait, ValidatingTrait;
use Authenticatable, CanResetPassword, ValidatingTrait;
/**
* The validation rules.
@@ -34,7 +30,7 @@ class User extends Model implements UserInterface, RemindableInterface
* @var string[]
*/
protected $rules = [
'username' => 'required|alpha_num|unique:users',
'username' => ['required', 'regex:/\A(?!.*[:;]-\))[ -~]+\z/', 'unique:users'],
'email' => 'required|email|unique:users',
'password' => 'required',
];
@@ -57,15 +53,13 @@ class User extends Model implements UserInterface, RemindableInterface
/**
* Overrides the models boot method.
*
* @return void
*/
public static function boot()
{
parent::boot();
self::creating(function ($user) {
if (! $user->api_key) {
if (!$user->api_key) {
$user->api_key = self::generateApiKey();
}
});

View File

@@ -0,0 +1,38 @@
<?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

@@ -0,0 +1,33 @@
<?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

@@ -0,0 +1,196 @@
<?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

@@ -0,0 +1,32 @@
<?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

@@ -0,0 +1,32 @@
<?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

@@ -0,0 +1,33 @@
<?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

@@ -0,0 +1,61 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\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

@@ -0,0 +1,43 @@
<?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

@@ -0,0 +1,47 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\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

@@ -0,0 +1,70 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\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,42 +1,33 @@
<?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\Console\Commands\FixPermissionsCommand;
use CachetHQ\Cachet\Console\Commands\OneClickDeployCommand;
use Illuminate\Support\ServiceProvider;
class ConsoleServiceProvider extends ServiceProvider
{
/**
* Boot the service provider.
*
* @return void
*/
public function boot()
{
$this->commands('CachetHQ\Cachet\Console\Commands\FixPermissionsCommand');
$this->commands('CachetHQ\Cachet\Console\Commands\OneClickDeployCommand');
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->app->singleton('CachetHQ\Cachet\Console\Commands\FixPermissionsCommand', function ($app) {
$storageDirectory = $app['path.storage'];
$databaseDirectory = $app['path'].'/database';
$storageDirectory = storage_path();
$databaseDirectory = base_path('database');
$databasePath = $app->config->get('database.connections.sqlite.database');
$databaseDefault = $app->config->get('database.default');
return new FixPermissionsCommand($storageDirectory, $databaseDirectory, $databasePath, $databaseDefault);
});
$this->app->singleton('CachetHQ\Cachet\Console\Commands\OneClickDeployCommand', function ($app) {
return new OneClickDeployCommand($app->environment('heroku'));
});
}
}

View File

@@ -0,0 +1,34 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\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

@@ -0,0 +1,69 @@
<?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

@@ -0,0 +1,51 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\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']),
]);
}
}

View File

@@ -1,52 +0,0 @@
// 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

@@ -1,18 +0,0 @@
.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;
}

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