Compare commits

...

964 Commits
2.2 ... 2.3

Author SHA1 Message Date
James Brooks
7ed480dd64 Merge pull request #4203 from fiveai/fix-api-search-with-pagination
Fix API search with pagination when specifying page
2021-03-29 11:54:58 +01:00
Seb Dangerfield
c040fc334c Ensure only allowed searchable columns are used in DB Query 2021-01-15 18:38:29 +00:00
Seb Dangerfield
48fdf79a8f Test API Pagination and searching 2021-01-15 17:10:19 +00:00
James Brooks
fe3675ff33 Apply fixes from StyleCI (#4072) 2020-08-01 09:18:12 +01:00
James Brooks
94b4fe2d39 Merge pull request #3601 from CachetHQ/l10n_2.3
New Crowdin translations
2020-08-01 09:17:48 +01:00
Cachet Bot
23cd590815 New translations pagination.php (Afrikaans) 2020-07-16 18:01:00 +01:00
Cachet Bot
748962b1c6 New translations forms.php (Swedish) 2020-04-27 09:12:19 +01:00
Cachet Bot
6f0ccb7e76 New translations forms.php (Russian) 2020-04-27 09:12:16 +01:00
Cachet Bot
0c637cc683 New translations forms.php (Vietnamese) 2020-04-27 09:11:44 +01:00
Cachet Bot
ec26e01e8d New translations validation.php (Portuguese, Brazilian) 2020-04-27 09:11:41 +01:00
Cachet Bot
9caecd3268 New translations forms.php (Danish) 2020-04-27 09:11:27 +01:00
Cachet Bot
f7ab99483c New translations forms.php (Romanian) 2020-04-27 09:11:13 +01:00
Cachet Bot
b9c9d28b59 New translations pagination.php (Afrikaans) 2020-04-27 09:11:03 +01:00
Cachet Bot
1d32adb0e6 New translations dashboard.php (Norwegian) 2020-04-27 09:10:47 +01:00
Cachet Bot
e36abd5ce4 New translations forms.php (Polish) 2020-04-27 09:10:41 +01:00
Cachet Bot
735c722918 New translations dashboard.php (Korean) 2020-04-27 09:10:15 +01:00
Cachet Bot
a588cfbd0a New translations validation.php (Czech) 2020-02-18 13:00:12 +00:00
Cachet Bot
8f0e56873e New translations setup.php (Chinese Simplified) 2020-01-13 06:50:15 +00:00
Cachet Bot
dfcf9bd392 New translations forms.php (Chinese Simplified) 2020-01-13 06:50:13 +00:00
Cachet Bot
52c93a0dfe New translations dashboard.php (Chinese Simplified) 2020-01-13 06:50:12 +00:00
Cachet Bot
28a896bf02 New translations cachet.php (Chinese Simplified) 2020-01-13 06:50:11 +00:00
Cachet Bot
06faecf3a7 New translations dashboard.php (Chinese Simplified) 2019-12-10 14:40:22 +00:00
James Brooks
5dfeaa3b6a Merge pull request #3845 from tomecho/2.3-3844-fix
add is_object check for feed result, fixes #3844
2019-11-05 21:43:26 +00:00
Tom Peck
18f5c29a16 add is_object check for feed result, fixes #3844 2019-11-05 15:43:46 -05:00
Cachet Bot
3681d277a4 New translations forms.php (Portuguese, Brazilian) 2019-11-02 10:50:13 +00:00
James Brooks
6752596ba8 Merge pull request #3712 from sigv/bugfix/2.3/gravatar-lowercase
Lowercase email for Gravatar avatars
2019-08-14 07:23:52 +01:00
Cachet Bot
d02ec7f150 New translations cachet.php (Russian) 2019-08-02 23:40:12 +01:00
Valters Jansons
300961cad4 Lowercase email for Gravatar avatars
The Gravatar docs explicitly say that e-mail addresses have
to be lowercased before hashing. In the `2.4` branch this was
already resolved in `0f4c14ac0820562a3155d6f60ea4a7770d19084b`
back in 2016 so it is safe to backport that change to the
latest stable branch for a maintenance patch release.
2019-07-16 21:58:20 +03:00
Cachet Bot
12b6888feb New translations setup.php (Japanese) 2019-07-16 10:50:30 +01:00
Cachet Bot
dde38b08d3 New translations dashboard.php (Japanese) 2019-07-16 10:50:29 +01:00
Cachet Bot
0bdf3f35aa New translations cachet.php (Japanese) 2019-07-16 10:50:27 +01:00
Cachet Bot
1a053ff5b8 New translations forms.php (Polish) 2019-07-11 13:21:54 +01:00
Cachet Bot
7f54029bad New translations forms.php (Norwegian) 2019-07-11 13:21:49 +01:00
Cachet Bot
f50a2c717e New translations forms.php (Italian) 2019-07-11 13:21:46 +01:00
Cachet Bot
a4ab01d9dc New translations forms.php (German) 2019-07-11 13:21:41 +01:00
Cachet Bot
dfa1650936 New translations forms.php (Indonesian) 2019-07-11 13:21:36 +01:00
Cachet Bot
b3f4eb261a New translations forms.php (Swedish) 2019-07-11 13:21:25 +01:00
Cachet Bot
552c029682 New translations forms.php (Zulu) 2019-07-11 13:21:21 +01:00
Cachet Bot
ce833c52bc New translations cachet.php (Zulu) 2019-07-11 13:21:19 +01:00
Cachet Bot
61acfd5dab New translations forms.php (Romanian) 2019-07-11 13:21:13 +01:00
Cachet Bot
72f6b7185d New translations forms.php (Portuguese) 2019-07-11 13:21:07 +01:00
Cachet Bot
39e670edb5 New translations validation.php (Portuguese, Brazilian) 2019-07-11 13:21:05 +01:00
Cachet Bot
0f99a14bd6 New translations forms.php (Spanish) 2019-07-11 13:21:03 +01:00
Cachet Bot
18cccd9a76 New translations forms.php (Russian) 2019-07-11 13:20:57 +01:00
Cachet Bot
f15709850d New translations forms.php (Chinese Simplified) 2019-07-11 13:20:53 +01:00
Cachet Bot
a24604b169 New translations forms.php (Chinese Traditional) 2019-07-11 13:20:49 +01:00
Cachet Bot
5cb438a30b New translations forms.php (French) 2019-07-11 13:20:30 +01:00
Cachet Bot
b43974eb48 New translations forms.php (Danish) 2019-07-11 13:20:26 +01:00
Cachet Bot
c020fd50b7 New translations validation.php (Dutch) 2019-07-11 13:20:23 +01:00
Cachet Bot
b76acbeee1 New translations forms.php (Dutch) 2019-07-11 13:20:22 +01:00
Cachet Bot
f46371bde0 New translations dashboard.php (Czech) 2019-06-25 10:20:15 +01:00
Cachet Bot
5853b43da1 New translations dashboard.php (Czech) 2019-06-25 10:10:14 +01:00
Cachet Bot
d2f3572ffc New translations forms.php (Czech) 2019-06-25 10:00:12 +01:00
Cachet Bot
8b98141c61 New translations cachet.php (Czech) 2019-06-25 10:00:10 +01:00
James Brooks
59ef9023d5 Merge pull request #3645 from anthonybocci/feature/3618-setup-assets-path
Allow Cachet setup not to be at server's root
2019-06-23 08:14:14 +01:00
Cachet Bot
1c371e9fe3 New translations setup.php (Czech) 2019-06-20 15:20:21 +01:00
Cachet Bot
cb518d0d14 New translations validation.php (Czech) 2019-06-20 15:20:20 +01:00
Cachet Bot
64dd4cbf9c New translations pagination.php (Czech) 2019-06-20 15:20:19 +01:00
Cachet Bot
c0513da918 New translations forms.php (Czech) 2019-06-20 15:20:18 +01:00
Cachet Bot
393669beae New translations dashboard.php (Czech) 2019-06-20 15:20:16 +01:00
Cachet Bot
1dfc3683ce New translations forms.php (Czech) 2019-06-20 15:10:16 +01:00
Cachet Bot
99d95a8e11 New translations dashboard.php (Czech) 2019-06-20 15:10:14 +01:00
Cachet Bot
48e8bc84f8 New translations cachet.php (Czech) 2019-06-20 15:00:16 +01:00
Cachet Bot
3e065f6c9c New translations cachet.php (Czech) 2019-06-20 14:30:26 +01:00
Cachet Bot
249de039f6 New translations cachet.php (Czech) 2019-06-20 14:00:18 +01:00
Cachet Bot
cba2eece5f New translations cachet.php (Czech) 2019-06-20 13:50:26 +01:00
Anthony Bocci
fbf141c39d Allow Cachet setup not to be at server's root
Cachet may be installed at the root of its vhost or in a subdirectory,
for example in "/" or under "/status".

The URI we found pointing to some assets were usually not prefixed with
the path, so if Cachet was installed under "/status" the asset
URI pointed to the server root like "/my-asset.js".
It is a problem because that means the behaviour is broken in this case.
The problem was present from the setup, it was not possible to fill the
setup since the path to the scripts and CSS weres wrong.

The "asset" helper is now used and resolves the URI.

See: CachetHQ#3618
2019-06-19 11:20:04 +02:00
Cachet Bot
b639d1e5ab New translations cachet.php (Czech) 2019-06-18 08:50:13 +01:00
Graham Campbell
168e36f224 Updated with the latest cloudflare ips (#3650) 2019-06-15 18:04:26 +01:00
Graham Campbell
87b5b67be4 Upgraded deps (#3616) 2019-05-22 14:24:33 +01:00
James Brooks
f79eef0e88 Merge pull request #3615 from CachetHQ/extra-spaces
Removed extra spaces
2019-05-22 13:56:30 +01:00
Graham Campbell
30978bd125 Removed extra spaces 2019-05-22 13:44:45 +01:00
James Brooks
22b6135541 Bump version for dev 2019-05-14 13:27:46 +01:00
James Brooks
cc2f4de125 Fix version 2019-05-14 13:27:19 +01:00
James Brooks
baea4e9a03 Bump version 2019-05-14 13:25:42 +01:00
James Brooks
1bc48e0c60 Fix view import 2019-05-14 13:25:32 +01:00
Cachet Bot
0d5cfb17d4 New translations setup.php (Portuguese, Brazilian) 2019-05-14 01:50:12 +01:00
Cachet Bot
429719585f New translations dashboard.php (Portuguese, Brazilian) 2019-05-14 01:50:11 +01:00
Cachet Bot
63a2d9445b New translations dashboard.php (Portuguese, Brazilian) 2019-05-14 01:40:12 +01:00
Cachet Bot
967961787c New translations cachet.php (Portuguese, Brazilian) 2019-05-14 01:40:10 +01:00
Cachet Bot
e281597260 New translations cachet.php (Portuguese, Brazilian) 2019-05-14 01:30:09 +01:00
Cachet Bot
c6b4d9ed5e New translations cachet.php (Portuguese, Brazilian) 2019-05-14 01:20:10 +01:00
Cachet Bot
31eb7086a2 New translations dashboard.php (Portuguese, Brazilian) 2019-05-14 01:10:11 +01:00
Cachet Bot
ae874c704e New translations forms.php (Portuguese, Brazilian) 2019-05-14 01:00:15 +01:00
Cachet Bot
7b2b90a78d New translations cachet.php (Portuguese, Brazilian) 2019-05-14 01:00:13 +01:00
James Brooks
1d6b117a55 Bump for dev 2019-05-13 20:33:18 +01:00
James Brooks
7a08cfd00a Release v2.3.17 2019-05-13 20:32:54 +01:00
James Brooks
52fda22acc Apply fixes from StyleCI (#3599) 2019-05-13 20:31:04 +01:00
James Brooks
9531a909d4 Prevent calling of DashboardComposer 2019-05-13 20:30:39 +01:00
James Brooks
5fcc0ce2f6 Don't need to call all() 2019-05-13 20:30:28 +01:00
James Brooks
843eabbcc3 Fixes #3598 2019-05-13 20:29:47 +01:00
Graham Campbell
16f057500b Bumped version for dev (#3588) 2019-05-13 14:31:09 +01:00
Graham Campbell
e477de77be Release v2.3.16 (#3585) 2019-05-12 23:47:56 +01:00
Graham Campbell
e7066864e2 Cachet 2.3 is known to work on PHP 7.0 and 7.1 (#3584) 2019-05-12 20:01:52 +01:00
Graham Campbell
16932219a7 Upgraded deps (#3582) 2019-05-12 19:16:31 +01:00
James Brooks
512e1a6661 Apply fixes from StyleCI (#3565) 2019-04-25 13:10:55 +01:00
James Brooks
0e5bb00f44 Merge pull request #3564 from CachetHQ/l10n_2.3
New Crowdin translations
2019-04-25 13:10:05 +01:00
Cachet Bot
6aed3531dd New translations forms.php (German) 2019-04-25 10:21:43 +01:00
James Brooks
6e79575a1c Merge pull request #3530 from CachetHQ/l10n_2.3
New Crowdin translations
2019-04-01 08:18:00 +01:00
Cachet Bot
61a371520d New translations dashboard.php (German) 2019-03-28 08:10:26 +00:00
James Brooks
1f46e06e80 Apply fixes from StyleCI (#3511) 2019-03-11 20:42:33 +00:00
James Brooks
0e82925f95 Merge pull request #3510 from CachetHQ/l10n_2.3
New Crowdin translations
2019-03-11 20:42:15 +00:00
Cachet Bot
c3cfeeb14c New translations forms.php (Swedish) 2019-03-11 09:00:13 +00:00
James Brooks
7738c73860 Apply fixes from StyleCI (#3505) 2019-03-09 08:50:34 +00:00
James Brooks
d8eb86e4d2 Merge pull request #3501 from CachetHQ/l10n_2.3
New Crowdin translations
2019-03-09 08:49:51 +00:00
Cachet Bot
48ab04c425 New translations forms.php (Romanian) 2019-03-06 20:50:11 +00:00
James Brooks
035164fae6 2.3 is not compatible with PHP7 2019-02-01 22:37:23 +00:00
James Brooks
d4bcdf0e29 Apply fixes from StyleCI (#3436) 2019-01-26 17:06:21 +00:00
James Brooks
f41aa311c5 Merge pull request #3401 from CachetHQ/l10n_2.3
New Crowdin translations
2019-01-26 17:05:46 +00:00
Cachet Bot
ef7236c16b New translations setup.php (Slovenian) 2019-01-26 11:40:20 +00:00
Cachet Bot
84915404b9 New translations forms.php (Slovenian) 2019-01-26 11:40:19 +00:00
Cachet Bot
6dfadc2f94 New translations dashboard.php (Slovenian) 2019-01-26 11:40:18 +00:00
Cachet Bot
7f6effff96 New translations validation.php (Slovenian) 2019-01-26 11:40:16 +00:00
Cachet Bot
63589167f3 New translations pagination.php (Slovenian) 2019-01-26 11:40:15 +00:00
Cachet Bot
9e96f28ddf New translations cachet.php (Slovenian) 2019-01-26 11:40:14 +00:00
Cachet Bot
6d920b2111 New translations setup.php (Mongolian) 2019-01-26 11:40:13 +00:00
Cachet Bot
760a034c0c New translations forms.php (Mongolian) 2019-01-26 11:40:12 +00:00
Cachet Bot
0a9d1b313a New translations dashboard.php (Mongolian) 2019-01-26 11:40:11 +00:00
Cachet Bot
e9020d3e08 New translations validation.php (Mongolian) 2019-01-26 11:40:10 +00:00
Cachet Bot
d61c9d190f New translations pagination.php (Mongolian) 2019-01-26 11:40:09 +00:00
Cachet Bot
520785b5ca New translations cachet.php (Mongolian) 2019-01-26 11:40:08 +00:00
Cachet Bot
dd0052a50f New translations setup.php (German) 2019-01-15 13:10:13 +00:00
Cachet Bot
cd48270cad New translations cachet.php (German) 2019-01-15 13:10:11 +00:00
Cachet Bot
79b837d65f New translations setup.php (Dutch) 2019-01-03 18:00:13 +00:00
Cachet Bot
5f639b718f New translations dashboard.php (Dutch) 2019-01-03 18:00:12 +00:00
Cachet Bot
eb18e7d982 New translations cachet.php (Dutch) 2019-01-03 18:00:11 +00:00
Cachet Bot
cd70023bbe New translations forms.php (Dutch) 2019-01-03 18:00:10 +00:00
Cachet Bot
4277ec77e4 New translations cachet.php (Dutch) 2019-01-03 17:20:11 +00:00
James Brooks
1f1cf5a242 Merge pull request #3388 from CachetHQ/l10n_2.3
New Crowdin translations
2019-01-01 10:59:41 +00:00
Cachet Bot
495f118116 New translations cachet.php (Dutch) 2018-12-31 09:30:07 +00:00
James Brooks
171588c3a5 Merge pull request #3386 from CachetHQ/l10n_2.3
New Crowdin translations
2018-12-30 17:06:44 +00:00
Cachet Bot
72def0eb60 New translations forms.php (Afrikaans) 2018-12-30 11:00:09 +00:00
Cachet Bot
79a8026191 New translations dashboard.php (Afrikaans) 2018-12-30 11:00:08 +00:00
James Brooks
11bb77b944 Merge pull request #3380 from CachetHQ/l10n_2.3
New Crowdin translations
2018-12-29 18:56:41 +00:00
Cachet Bot
3f932a2ec2 Apply fixes from StyleCI 2018-12-29 17:50:13 +00:00
Cachet Bot
9f0a11eeb4 New translations forms.php (Dutch) 2018-12-29 17:50:07 +00:00
Cachet Bot
34f5775bd8 New translations dashboard.php (German) 2018-12-29 12:40:07 +00:00
Cachet Bot
2a4a7d72a2 New translations dashboard.php (German) 2018-12-29 12:30:08 +00:00
James Brooks
2dd7fba3e1 Merge pull request #3359 from CachetHQ/l10n_2.3
New Crowdin translations
2018-12-27 22:07:36 +00:00
Cachet Bot
ac91ba5d67 New translations setup.php (Swedish) 2018-12-10 23:50:10 +00:00
Cachet Bot
2a04e8907c New translations cachet.php (Swedish) 2018-12-10 23:50:08 +00:00
Cachet Bot
c66f66a6f4 New translations cachet.php (Swedish) 2018-12-10 23:40:08 +00:00
James Brooks
589f82af84 Merge pull request #3335 from CachetHQ/l10n_2.3
New Crowdin translations
2018-11-23 11:20:01 +00:00
Cachet Bot
ef91bacc35 Apply fixes from StyleCI 2018-11-19 17:41:38 +00:00
Cachet Bot
84f1f2fe0b New translations forms.php (German) 2018-11-19 17:41:33 +00:00
Cachet Bot
525563c3c0 New translations forms.php (French) 2018-11-19 17:41:30 +00:00
Cachet Bot
4b8bc99b5e Apply fixes from StyleCI 2018-11-19 17:41:28 +00:00
Cachet Bot
66a300cade New translations forms.php (Indonesian) 2018-11-19 17:41:22 +00:00
Cachet Bot
68f80c2f95 New translations forms.php (Dutch) 2018-11-19 17:41:05 +00:00
Cachet Bot
a087b2a21a New translations forms.php (Chinese Simplified) 2018-11-19 17:41:03 +00:00
Cachet Bot
f155bfa419 New translations forms.php (Danish) 2018-11-19 17:41:01 +00:00
Cachet Bot
255922804c New translations forms.php (Chinese Traditional) 2018-11-19 17:40:56 +00:00
Cachet Bot
7191bdacf8 New translations forms.php (Swedish) 2018-11-19 17:40:49 +00:00
Cachet Bot
491b07d498 New translations forms.php (Spanish) 2018-11-19 17:40:46 +00:00
Cachet Bot
467453c29d New translations forms.php (Russian) 2018-11-19 17:40:44 +00:00
Cachet Bot
8d42f0f97b New translations forms.php (Zulu) 2018-11-19 17:40:39 +00:00
Cachet Bot
fc170bea0a New translations cachet.php (Zulu) 2018-11-19 17:40:37 +00:00
Cachet Bot
d455f56243 New translations forms.php (Italian) 2018-11-19 17:40:32 +00:00
Cachet Bot
cef1d82d8c New translations forms.php (Norwegian) 2018-11-19 17:40:29 +00:00
Cachet Bot
e7caa3ca37 Apply fixes from StyleCI 2018-11-19 17:40:26 +00:00
Cachet Bot
2a320477e3 New translations forms.php (Romanian) 2018-11-19 17:40:19 +00:00
Cachet Bot
1c593bb2f1 New translations forms.php (Portuguese, Brazilian) 2018-11-19 17:40:17 +00:00
Cachet Bot
e557e5eb9b New translations forms.php (Portuguese) 2018-11-19 17:40:14 +00:00
Cachet Bot
33ed227c97 New translations forms.php (Polish) 2018-11-19 17:40:10 +00:00
James Brooks
f4dc5d09ab Merge pull request #3278 from CachetHQ/l10n_2.3
New Crowdin translations
2018-11-13 14:24:58 +00:00
Cachet Bot
d86d2e8201 New translations cachet.php (Japanese) 2018-11-05 07:00:07 +00:00
Cachet Bot
9ac9b5898e Apply fixes from StyleCI 2018-10-18 16:50:16 +00:00
Cachet Bot
1eea552d6e New translations forms.php (Russian) 2018-10-18 17:50:07 +01:00
Cachet Bot
3fd9bfe00d New translations setup.php (Estonian) 2018-10-15 12:40:15 +01:00
Cachet Bot
282ee9802d New translations forms.php (Estonian) 2018-10-15 12:40:14 +01:00
Cachet Bot
ce7104d679 New translations dashboard.php (Estonian) 2018-10-15 12:40:13 +01:00
Cachet Bot
bcdaec1d3a New translations validation.php (Estonian) 2018-10-15 12:40:12 +01:00
Cachet Bot
53e1837368 New translations pagination.php (Estonian) 2018-10-15 12:40:11 +01:00
Cachet Bot
b8324c3e7c New translations cachet.php (Estonian) 2018-10-15 12:40:09 +01:00
James Brooks
7ea832de8e Merge pull request #3248 from CachetHQ/l10n_2.3
New Crowdin translations
2018-10-15 12:39:05 +01:00
Cachet Bot
368045b418 Apply fixes from StyleCI 2018-10-09 11:01:37 +00:00
Cachet Bot
0bfaeaa4fc New translations forms.php (French) 2018-10-09 12:01:31 +01:00
Cachet Bot
3f9ba0ee97 New translations forms.php (Dutch) 2018-10-09 12:01:24 +01:00
Cachet Bot
045bbeeba0 New translations forms.php (German) 2018-10-09 12:01:23 +01:00
Cachet Bot
5cce6d4184 New translations forms.php (Indonesian) 2018-10-09 12:01:21 +01:00
Cachet Bot
9f1dd6fedc Apply fixes from StyleCI 2018-10-09 11:01:18 +00:00
Cachet Bot
ddb2972a4a New translations forms.php (Danish) 2018-10-09 12:01:03 +01:00
Cachet Bot
ba84e3ee23 New translations forms.php (Chinese Traditional) 2018-10-09 12:00:57 +01:00
Cachet Bot
400c94d06d New translations forms.php (Chinese Simplified) 2018-10-09 12:00:54 +01:00
Cachet Bot
ebe31e2070 New translations forms.php (Swedish) 2018-10-09 12:00:50 +01:00
Cachet Bot
7b29049dd7 New translations forms.php (Russian) 2018-10-09 12:00:45 +01:00
Cachet Bot
ee73222638 New translations forms.php (Spanish) 2018-10-09 12:00:42 +01:00
Cachet Bot
6f1cba91df New translations forms.php (Zulu) 2018-10-09 12:00:40 +01:00
Cachet Bot
b313c45cd2 New translations cachet.php (Zulu) 2018-10-09 12:00:38 +01:00
Cachet Bot
3e35d29d8f New translations forms.php (Romanian) 2018-10-09 12:00:31 +01:00
Cachet Bot
8ffa6c7996 New translations forms.php (Norwegian) 2018-10-09 12:00:29 +01:00
Cachet Bot
07750e9365 New translations forms.php (Italian) 2018-10-09 12:00:21 +01:00
Cachet Bot
63a79d9d19 New translations forms.php (Portuguese, Brazilian) 2018-10-09 12:00:17 +01:00
Cachet Bot
12efe8113e New translations forms.php (Portuguese) 2018-10-09 12:00:14 +01:00
Cachet Bot
d8c6be3f9e New translations forms.php (Polish) 2018-10-09 12:00:11 +01:00
Cachet Bot
8bffaa5c9a Apply fixes from StyleCI 2018-09-28 08:40:21 +00:00
Cachet Bot
6bf9221d74 New translations forms.php (Norwegian) 2018-09-28 09:40:13 +01:00
Cachet Bot
fa5875da76 New translations cachet.php (Afrikaans) 2018-09-20 13:40:05 +01:00
Cachet Bot
34a36bc6c1 New translations cachet.php (Afrikaans) 2018-09-20 13:30:05 +01:00
James Brooks
f8a35d71b4 Merge pull request #3198 from CachetHQ/l10n_2.3
New Crowdin translations
2018-08-07 08:51:02 +01:00
James Brooks
8a8edea07a Merge pull request #3209 from CachetHQ/update-deps
Update deps
2018-08-06 18:55:38 +01:00
Cachet Bot
e3973414cd Apply fixes from StyleCI 2018-08-04 08:50:14 +00:00
Cachet Bot
9bb670cb95 New translations forms.php (Dutch) 2018-08-04 09:50:07 +01:00
James Brooks
127996f08f Update deps. Closes #3207 2018-08-03 20:58:20 +01:00
Cachet Bot
a6768da7bb Apply fixes from StyleCI
[ci skip] [skip ci]
2018-08-03 18:00:48 +00:00
Cachet Bot
123f05bd84 New translations forms.php (Spanish) 2018-08-03 19:00:08 +01:00
Cachet Bot
ecc91abcae Apply fixes from StyleCI
[ci skip] [skip ci]
2018-07-27 23:40:13 +00:00
Cachet Bot
bb9def5821 New translations setup.php (French) 2018-07-28 00:40:07 +01:00
Cachet Bot
11cbbb42fb New translations forms.php (French) 2018-07-28 00:40:06 +01:00
Cachet Bot
b361618ec0 New translations dashboard.php (French) 2018-07-28 00:30:06 +01:00
Cachet Bot
ee288e0505 New translations cachet.php (French) 2018-07-28 00:30:05 +01:00
Cachet Bot
7c5e214b1c Apply fixes from StyleCI
[ci skip] [skip ci]
2018-07-25 14:51:56 +00:00
Cachet Bot
0e1d52b3bc New translations forms.php (Chinese Simplified) 2018-07-25 15:51:07 +01:00
James Brooks
77d576fd39 Merge pull request #3189 from CachetHQ/l10n_2.3
New Crowdin translations
2018-07-21 09:12:41 +01:00
James Brooks
73fb33d03e Update VERSION 2018-07-21 09:11:04 +01:00
Cachet Bot
2746001cdb Apply fixes from StyleCI
[ci skip] [skip ci]
2018-07-17 13:00:28 +00:00
Cachet Bot
036da9248d New translations forms.php (French) 2018-07-17 14:00:19 +01:00
James Brooks
2d72914205 Merge pull request #3184 from CachetHQ/l10n_2.3
New Crowdin translations
2018-07-17 07:52:46 +01:00
Cachet Bot
237ae7dcdc Apply fixes from StyleCI
[ci skip] [skip ci]
2018-07-13 02:30:14 +00:00
Cachet Bot
8408b92d0c New translations forms.php (Russian) 2018-07-13 03:30:06 +01:00
James Brooks
2da10d1694 Apply fixes from StyleCI (#3182)
[ci skip] [skip ci]
2018-07-12 08:36:35 +01:00
James Brooks
7ac2987809 Merge pull request #3181 from CachetHQ/l10n_2.3
New Crowdin translations
2018-07-12 08:36:03 +01:00
Cachet Bot
5f1c3c92c4 New translations forms.php (French) 2018-07-11 22:52:28 +01:00
Cachet Bot
48f68994ba New translations setup.php (Finnish) 2018-07-11 22:52:27 +01:00
Cachet Bot
adfa39f336 New translations forms.php (Finnish) 2018-07-11 22:52:26 +01:00
Cachet Bot
357389908f New translations validation.php (Finnish) 2018-07-11 22:52:25 +01:00
Cachet Bot
a2252707af New translations pagination.php (Finnish) 2018-07-11 22:52:24 +01:00
Cachet Bot
5057dee219 New translations cachet.php (Finnish) 2018-07-11 22:52:23 +01:00
Cachet Bot
430a80535c New translations dashboard.php (Finnish) 2018-07-11 22:52:20 +01:00
Cachet Bot
5c815756fe New translations forms.php (Dutch) 2018-07-11 22:52:19 +01:00
Cachet Bot
b1547b9d74 New translations forms.php (German) 2018-07-11 22:52:18 +01:00
Cachet Bot
42a2825a70 New translations cachet.php (Greek) 2018-07-11 22:52:17 +01:00
Cachet Bot
3dd7d9b41d New translations forms.php (Indonesian) 2018-07-11 22:52:16 +01:00
Cachet Bot
7552177585 New translations validation.php (Indonesian) 2018-07-11 22:52:14 +01:00
Cachet Bot
6120d9627e New translations setup.php (Hungarian) 2018-07-11 22:52:13 +01:00
Cachet Bot
22a7523347 New translations forms.php (Hungarian) 2018-07-11 22:52:12 +01:00
Cachet Bot
b4c052c5ad New translations dashboard.php (Hungarian) 2018-07-11 22:52:11 +01:00
Cachet Bot
0af0e01d31 New translations validation.php (Hungarian) 2018-07-11 22:52:10 +01:00
Cachet Bot
04ca418b32 New translations pagination.php (Hungarian) 2018-07-11 22:52:09 +01:00
Cachet Bot
8ca56c0a47 New translations cachet.php (Hungarian) 2018-07-11 22:52:08 +01:00
Cachet Bot
dccca87e2e New translations forms.php (Hebrew) 2018-07-11 22:52:07 +01:00
Cachet Bot
63b15530f0 New translations dashboard.php (Hebrew) 2018-07-11 22:52:06 +01:00
Cachet Bot
008b7ce3e3 New translations validation.php (Hebrew) 2018-07-11 22:52:05 +01:00
Cachet Bot
e173c616fc New translations pagination.php (Hebrew) 2018-07-11 22:52:04 +01:00
Cachet Bot
63e629df99 New translations cachet.php (Hebrew) 2018-07-11 22:52:04 +01:00
Cachet Bot
c930ecc568 New translations setup.php (Greek) 2018-07-11 22:52:03 +01:00
Cachet Bot
c542fe762c New translations forms.php (Greek) 2018-07-11 22:52:02 +01:00
Cachet Bot
5a6dfce84e New translations dashboard.php (Greek) 2018-07-11 22:52:01 +01:00
Cachet Bot
1fc399085c New translations pagination.php (Greek) 2018-07-11 22:52:00 +01:00
Cachet Bot
dfced9e81c New translations setup.php (Hebrew) 2018-07-11 22:51:59 +01:00
Cachet Bot
e6412e9be5 New translations setup.php (Catalan) 2018-07-11 22:51:57 +01:00
Cachet Bot
6c67e01297 New translations forms.php (Catalan) 2018-07-11 22:51:57 +01:00
Cachet Bot
e4a2ef3df7 New translations dashboard.php (Catalan) 2018-07-11 22:51:56 +01:00
Cachet Bot
560be25f99 New translations pagination.php (Catalan) 2018-07-11 22:51:55 +01:00
Cachet Bot
61a71166b3 New translations cachet.php (Catalan) 2018-07-11 22:51:54 +01:00
Cachet Bot
359cd934c0 New translations setup.php (Arabic) 2018-07-11 22:51:53 +01:00
Cachet Bot
4b45eed503 New translations forms.php (Arabic) 2018-07-11 22:51:52 +01:00
Cachet Bot
73a14d5980 New translations dashboard.php (Arabic) 2018-07-11 22:51:51 +01:00
Cachet Bot
c614bd8e2a New translations validation.php (Arabic) 2018-07-11 22:51:50 +01:00
Cachet Bot
bd26724f4a New translations cachet.php (Chinese Simplified) 2018-07-11 22:51:49 +01:00
Cachet Bot
d7650d1815 New translations pagination.php (Arabic) 2018-07-11 22:51:48 +01:00
Cachet Bot
9975ecab54 New translations setup.php (Albanian) 2018-07-11 22:51:48 +01:00
Cachet Bot
a508a326ca New translations forms.php (Albanian) 2018-07-11 22:51:47 +01:00
Cachet Bot
5d836619c6 New translations dashboard.php (Albanian) 2018-07-11 22:51:46 +01:00
Cachet Bot
4ff927968b New translations pagination.php (Albanian) 2018-07-11 22:51:45 +01:00
Cachet Bot
4a9e2be6ee New translations cachet.php (Albanian) 2018-07-11 22:51:44 +01:00
Cachet Bot
3f92f85cda New translations dashboard.php (Afrikaans) 2018-07-11 22:51:42 +01:00
Cachet Bot
6138a9c4ef New translations cachet.php (Arabic) 2018-07-11 22:51:41 +01:00
Cachet Bot
210ac14e73 New translations validation.php (Dutch) 2018-07-11 22:51:40 +01:00
Cachet Bot
e5b17f1ce7 New translations dashboard.php (Chinese Simplified) 2018-07-11 22:51:39 +01:00
Cachet Bot
3a31fb01d6 New translations setup.php (Danish) 2018-07-11 22:51:38 +01:00
Cachet Bot
ff97806361 New translations forms.php (Danish) 2018-07-11 22:51:37 +01:00
Cachet Bot
b12fdb61cb New translations dashboard.php (Danish) 2018-07-11 22:51:36 +01:00
Cachet Bot
75a12767e2 New translations validation.php (Danish) 2018-07-11 22:51:35 +01:00
Cachet Bot
b4df0d7aae New translations cachet.php (Danish) 2018-07-11 22:51:34 +01:00
Cachet Bot
b4a618f362 New translations setup.php (Czech) 2018-07-11 22:51:33 +01:00
Cachet Bot
0af3fbc86c New translations forms.php (Czech) 2018-07-11 22:51:32 +01:00
Cachet Bot
8ed5ea3174 New translations dashboard.php (Czech) 2018-07-11 22:51:31 +01:00
Cachet Bot
6f98fefb85 New translations validation.php (Czech) 2018-07-11 22:51:30 +01:00
Cachet Bot
4b0a1da1b9 New translations cachet.php (Czech) 2018-07-11 22:51:29 +01:00
Cachet Bot
89779d9e3c New translations setup.php (Chinese Traditional) 2018-07-11 22:51:28 +01:00
Cachet Bot
8b4ab5f09b New translations forms.php (Chinese Traditional) 2018-07-11 22:51:27 +01:00
Cachet Bot
c077c692ed New translations dashboard.php (Chinese Traditional) 2018-07-11 22:51:26 +01:00
Cachet Bot
dea9ebbfc9 New translations validation.php (Chinese Traditional) 2018-07-11 22:51:25 +01:00
Cachet Bot
0542cda408 New translations cachet.php (Chinese Traditional) 2018-07-11 22:51:24 +01:00
Cachet Bot
6041431d12 New translations setup.php (Chinese Simplified) 2018-07-11 22:51:23 +01:00
Cachet Bot
6703854224 New translations forms.php (Chinese Simplified) 2018-07-11 22:51:22 +01:00
Cachet Bot
aa8618c163 New translations pagination.php (Czech) 2018-07-11 22:51:21 +01:00
Cachet Bot
c040a42ee7 New translations validation.php (Italian) 2018-07-11 22:51:20 +01:00
Cachet Bot
983e1a781f New translations dashboard.php (Thai) 2018-07-11 22:51:19 +01:00
Cachet Bot
b5256a9558 New translations validation.php (Thai) 2018-07-11 22:51:18 +01:00
Cachet Bot
6058cad6e0 New translations pagination.php (Thai) 2018-07-11 22:51:17 +01:00
Cachet Bot
cb42bde85c New translations cachet.php (Thai) 2018-07-11 22:51:16 +01:00
Cachet Bot
e9104d6182 New translations setup.php (Swedish) 2018-07-11 22:51:15 +01:00
Cachet Bot
1153c0da76 New translations forms.php (Swedish) 2018-07-11 22:51:14 +01:00
Cachet Bot
4e1b1fe4ef New translations dashboard.php (Swedish) 2018-07-11 22:51:13 +01:00
Cachet Bot
0078f1dd1e New translations cachet.php (Swedish) 2018-07-11 22:51:12 +01:00
Cachet Bot
6ed0d2d4c2 New translations forms.php (Thai) 2018-07-11 22:51:11 +01:00
Cachet Bot
4b9a5e8e69 New translations validation.php (Spanish) 2018-07-11 22:51:09 +01:00
Cachet Bot
375c831391 New translations forms.php (Russian) 2018-07-11 22:51:08 +01:00
Cachet Bot
126c088863 New translations validation.php (Russian) 2018-07-11 22:51:07 +01:00
Cachet Bot
9f226eea9c New translations forms.php (Spanish) 2018-07-11 22:51:05 +01:00
Cachet Bot
4ad72633ea New translations setup.php (Thai) 2018-07-11 22:51:04 +01:00
Cachet Bot
2b18410a99 New translations pagination.php (Turkish) 2018-07-11 22:51:03 +01:00
Cachet Bot
2e353fc707 New translations forms.php (Zulu) 2018-07-11 22:51:02 +01:00
Cachet Bot
cb8d4282e4 New translations cachet.php (Zulu) 2018-07-11 22:51:01 +01:00
Cachet Bot
d7fd04b183 New translations setup.php (Vietnamese) 2018-07-11 22:51:00 +01:00
Cachet Bot
3f6b825692 New translations forms.php (Vietnamese) 2018-07-11 22:50:59 +01:00
Cachet Bot
7e95648ff9 New translations dashboard.php (Vietnamese) 2018-07-11 22:50:58 +01:00
Cachet Bot
1dfd481d95 New translations validation.php (Vietnamese) 2018-07-11 22:50:57 +01:00
Cachet Bot
a8f04914fa New translations pagination.php (Vietnamese) 2018-07-11 22:50:56 +01:00
Cachet Bot
1093d2169d New translations cachet.php (Turkish) 2018-07-11 22:50:56 +01:00
Cachet Bot
4098bfe641 New translations cachet.php (Vietnamese) 2018-07-11 22:50:55 +01:00
Cachet Bot
5c51806417 New translations forms.php (Ukrainian) 2018-07-11 22:50:54 +01:00
Cachet Bot
b616842ec0 New translations dashboard.php (Ukrainian) 2018-07-11 22:50:53 +01:00
Cachet Bot
6c693ea4d5 New translations validation.php (Ukrainian) 2018-07-11 22:50:52 +01:00
Cachet Bot
c6d9b62248 New translations pagination.php (Ukrainian) 2018-07-11 22:50:51 +01:00
Cachet Bot
2770036621 New translations cachet.php (Ukrainian) 2018-07-11 22:50:50 +01:00
Cachet Bot
54943af362 New translations setup.php (Turkish) 2018-07-11 22:50:49 +01:00
Cachet Bot
00eba028e5 New translations forms.php (Turkish) 2018-07-11 22:50:48 +01:00
Cachet Bot
421d8c5d05 New translations dashboard.php (Turkish) 2018-07-11 22:50:47 +01:00
Cachet Bot
c28e86c3fa New translations validation.php (Turkish) 2018-07-11 22:50:46 +01:00
Cachet Bot
a6706b7f3f New translations setup.php (Ukrainian) 2018-07-11 22:50:46 +01:00
Cachet Bot
d2fae69bf2 New translations forms.php (Romanian) 2018-07-11 22:50:44 +01:00
Cachet Bot
9abe4962a9 New translations cachet.php (Persian) 2018-07-11 22:50:43 +01:00
Cachet Bot
e009ae4754 New translations forms.php (Norwegian) 2018-07-11 22:50:42 +01:00
Cachet Bot
4213a9a2ca New translations dashboard.php (Norwegian) 2018-07-11 22:50:41 +01:00
Cachet Bot
5da83aed92 New translations validation.php (Norwegian) 2018-07-11 22:50:40 +01:00
Cachet Bot
a159600919 New translations cachet.php (Norwegian) 2018-07-11 22:50:39 +01:00
Cachet Bot
1b0e583a8a New translations setup.php (Korean) 2018-07-11 22:50:38 +01:00
Cachet Bot
1c496338cd New translations forms.php (Korean) 2018-07-11 22:50:38 +01:00
Cachet Bot
f7353c0c64 New translations dashboard.php (Korean) 2018-07-11 22:50:37 +01:00
Cachet Bot
090f4167f2 New translations pagination.php (Persian) 2018-07-11 22:50:36 +01:00
Cachet Bot
3fbf056056 New translations validation.php (Korean) 2018-07-11 22:50:35 +01:00
Cachet Bot
3a554d25ba New translations cachet.php (Korean) 2018-07-11 22:50:34 +01:00
Cachet Bot
dbd0fd57f2 New translations setup.php (Japanese) 2018-07-11 22:50:33 +01:00
Cachet Bot
226596d47b New translations forms.php (Japanese) 2018-07-11 22:50:32 +01:00
Cachet Bot
fa8f957631 New translations dashboard.php (Japanese) 2018-07-11 22:50:31 +01:00
Cachet Bot
e465295e48 New translations validation.php (Japanese) 2018-07-11 22:50:30 +01:00
Cachet Bot
94b5ad7b09 New translations pagination.php (Japanese) 2018-07-11 22:50:29 +01:00
Cachet Bot
9512346c0c New translations cachet.php (Japanese) 2018-07-11 22:50:28 +01:00
Cachet Bot
985119e125 New translations forms.php (Italian) 2018-07-11 22:50:27 +01:00
Cachet Bot
11b5df1499 New translations pagination.php (Korean) 2018-07-11 22:50:26 +01:00
Cachet Bot
76aa95389f New translations validation.php (Persian) 2018-07-11 22:50:25 +01:00
Cachet Bot
f346449714 New translations forms.php (Persian) 2018-07-11 22:50:22 +01:00
Cachet Bot
a2da594586 New translations setup.php (Portuguese, Brazilian) 2018-07-11 22:50:21 +01:00
Cachet Bot
6b3bb85d53 New translations forms.php (Portuguese, Brazilian) 2018-07-11 22:50:20 +01:00
Cachet Bot
5d28ea4e69 New translations dashboard.php (Portuguese, Brazilian) 2018-07-11 22:50:19 +01:00
Cachet Bot
f724248b1f New translations validation.php (Portuguese, Brazilian) 2018-07-11 22:50:18 +01:00
Cachet Bot
a70ecd9e6d New translations cachet.php (Portuguese, Brazilian) 2018-07-11 22:50:17 +01:00
Cachet Bot
828ea1c2d3 New translations setup.php (Portuguese) 2018-07-11 22:50:17 +01:00
Cachet Bot
c1f65347e5 New translations forms.php (Portuguese) 2018-07-11 22:50:16 +01:00
Cachet Bot
61abbcc367 New translations dashboard.php (Persian) 2018-07-11 22:50:15 +01:00
Cachet Bot
4bf980bc1a New translations dashboard.php (Portuguese) 2018-07-11 22:50:14 +01:00
Cachet Bot
b88354d261 New translations cachet.php (Portuguese) 2018-07-11 22:50:12 +01:00
Cachet Bot
5fb88b1936 New translations forms.php (Polish) 2018-07-11 22:50:11 +01:00
Cachet Bot
e0b2368342 New translations validation.php (Polish) 2018-07-11 22:50:10 +01:00
Cachet Bot
fc87437edc New translations setup.php (Persian) 2018-07-11 22:50:08 +01:00
Cachet Bot
7786f54ad3 New translations validation.php (Portuguese) 2018-07-11 22:50:08 +01:00
Cachet Bot
ee0d56d22b New translations cachet.php (Afrikaans) 2018-07-11 22:50:06 +01:00
James Brooks
51eb5917b6 Merge pull request #3175 from CachetHQ/l10n_2.3
New Crowdin translations
2018-07-11 22:34:12 +01:00
Cachet Bot
6433c48a5f Apply fixes from StyleCI
[ci skip] [skip ci]
2018-07-11 03:10:14 +00:00
Cachet Bot
d3af0d37be New translations setup.php (Danish) 2018-07-11 04:10:06 +01:00
Cachet Bot
0430086750 New translations forms.php (Danish) 2018-07-11 04:10:05 +01:00
Cachet Bot
e43516460b New translations dashboard.php (Danish) 2018-07-11 04:00:06 +01:00
Cachet Bot
036787f3e3 New translations cachet.php (Danish) 2018-07-11 04:00:05 +01:00
Cachet Bot
b20272d14a Apply fixes from StyleCI
[ci skip] [skip ci]
2018-07-10 16:16:19 +00:00
Cachet Bot
5c11c1ff72 New translations cachet.php (Norwegian) 2018-07-10 16:50:07 +01:00
Cachet Bot
5bde0dddff New translations setup.php (Zulu) 2018-07-10 14:35:34 +01:00
Cachet Bot
beee77d2e3 New translations validation.php (German) 2018-07-10 14:35:33 +01:00
Cachet Bot
4c6106e3a6 New translations pagination.php (German) 2018-07-10 14:35:31 +01:00
Cachet Bot
c4e7010cfc New translations cachet.php (German) 2018-07-10 14:35:31 +01:00
Cachet Bot
0b505b31c6 New translations setup.php (French) 2018-07-10 14:35:30 +01:00
Cachet Bot
87b31b2b54 New translations forms.php (French) 2018-07-10 14:35:29 +01:00
Cachet Bot
c0da527878 New translations dashboard.php (French) 2018-07-10 14:35:28 +01:00
Cachet Bot
539deaaea8 New translations validation.php (French) 2018-07-10 14:35:26 +01:00
Cachet Bot
c04a845c54 New translations pagination.php (French) 2018-07-10 14:35:26 +01:00
Cachet Bot
09347fc120 New translations cachet.php (French) 2018-07-10 14:35:25 +01:00
Cachet Bot
3c2ec3dbe6 New translations setup.php (Finnish) 2018-07-10 14:35:24 +01:00
Cachet Bot
843f69b9e1 New translations dashboard.php (German) 2018-07-10 14:35:23 +01:00
Cachet Bot
5c54286fb1 New translations forms.php (Finnish) 2018-07-10 14:35:21 +01:00
Cachet Bot
32fd6535c1 New translations validation.php (Finnish) 2018-07-10 14:35:19 +01:00
Cachet Bot
622a103b7b New translations pagination.php (Finnish) 2018-07-10 14:35:18 +01:00
Cachet Bot
b8a3614649 New translations cachet.php (Finnish) 2018-07-10 14:35:17 +01:00
Cachet Bot
98ac8383c9 New translations setup.php (English) 2018-07-10 14:35:16 +01:00
Cachet Bot
747c94ebd7 New translations forms.php (English) 2018-07-10 14:35:16 +01:00
Cachet Bot
4c1a7abb7a New translations dashboard.php (English) 2018-07-10 14:35:15 +01:00
Cachet Bot
0a5691a4c2 New translations validation.php (English) 2018-07-10 14:35:14 +01:00
Cachet Bot
9aa16286a5 New translations pagination.php (English) 2018-07-10 14:35:13 +01:00
Cachet Bot
d4a693f8fb New translations cachet.php (English) 2018-07-10 14:35:12 +01:00
Cachet Bot
0ea5990af6 New translations setup.php (Dutch) 2018-07-10 14:35:11 +01:00
Cachet Bot
22cdc45074 New translations dashboard.php (Finnish) 2018-07-10 14:35:10 +01:00
Cachet Bot
61ea95a403 New translations forms.php (Dutch) 2018-07-10 14:35:09 +01:00
Cachet Bot
0dcf3f958f New translations forms.php (German) 2018-07-10 14:35:08 +01:00
Cachet Bot
b672f42635 New translations cachet.php (Greek) 2018-07-10 14:35:07 +01:00
Cachet Bot
7f6c7f7a71 New translations forms.php (Indonesian) 2018-07-10 14:35:06 +01:00
Cachet Bot
54ed6eda60 New translations dashboard.php (Indonesian) 2018-07-10 14:35:05 +01:00
Cachet Bot
877b25cfbb New translations validation.php (Indonesian) 2018-07-10 14:35:03 +01:00
Cachet Bot
8048c02286 New translations pagination.php (Indonesian) 2018-07-10 14:35:01 +01:00
Cachet Bot
082367793c New translations cachet.php (Indonesian) 2018-07-10 14:35:00 +01:00
Cachet Bot
518d28f07b New translations setup.php (Hungarian) 2018-07-10 14:34:59 +01:00
Cachet Bot
a01ccbf953 New translations forms.php (Hungarian) 2018-07-10 14:34:58 +01:00
Cachet Bot
a69c72ef40 New translations dashboard.php (Hungarian) 2018-07-10 14:34:57 +01:00
Cachet Bot
87b51835cc New translations validation.php (Hungarian) 2018-07-10 14:34:56 +01:00
Cachet Bot
edecc98cbf New translations pagination.php (Hungarian) 2018-07-10 14:34:55 +01:00
Cachet Bot
a1a78df602 New translations setup.php (German) 2018-07-10 14:34:54 +01:00
Cachet Bot
2b5127505f New translations cachet.php (Hungarian) 2018-07-10 14:34:53 +01:00
Cachet Bot
cd029e0a79 New translations forms.php (Hebrew) 2018-07-10 14:34:52 +01:00
Cachet Bot
4a0e12645c New translations dashboard.php (Hebrew) 2018-07-10 14:34:51 +01:00
Cachet Bot
18c12cf9b0 New translations validation.php (Hebrew) 2018-07-10 14:34:50 +01:00
Cachet Bot
a2b6141b55 New translations pagination.php (Hebrew) 2018-07-10 14:34:49 +01:00
Cachet Bot
3305628b16 New translations cachet.php (Hebrew) 2018-07-10 14:34:48 +01:00
Cachet Bot
81b6fd95e9 New translations setup.php (Greek) 2018-07-10 14:34:48 +01:00
Cachet Bot
cf2a9454c8 New translations forms.php (Greek) 2018-07-10 14:34:47 +01:00
Cachet Bot
d220823d8e New translations dashboard.php (Greek) 2018-07-10 14:34:45 +01:00
Cachet Bot
81d4cf89e6 New translations validation.php (Greek) 2018-07-10 14:34:44 +01:00
Cachet Bot
e0a5e4df9b New translations pagination.php (Greek) 2018-07-10 14:34:43 +01:00
Cachet Bot
090a80992a New translations setup.php (Hebrew) 2018-07-10 14:34:43 +01:00
Cachet Bot
a659db17ae New translations setup.php (Indonesian) 2018-07-10 14:34:42 +01:00
Cachet Bot
67d8a1ca35 New translations dashboard.php (Dutch) 2018-07-10 14:34:41 +01:00
Cachet Bot
220d1a1fe5 New translations pagination.php (Dutch) 2018-07-10 14:34:40 +01:00
Cachet Bot
d8bc1cd517 New translations setup.php (Catalan) 2018-07-10 14:34:39 +01:00
Cachet Bot
e7768a1cec New translations forms.php (Catalan) 2018-07-10 14:34:38 +01:00
Cachet Bot
4b1bd76ff6 New translations dashboard.php (Catalan) 2018-07-10 14:34:37 +01:00
Cachet Bot
37e778585a New translations validation.php (Catalan) 2018-07-10 14:34:36 +01:00
Cachet Bot
2646963a2e New translations pagination.php (Catalan) 2018-07-10 14:34:35 +01:00
Cachet Bot
ebe162fe71 New translations cachet.php (Catalan) 2018-07-10 14:34:34 +01:00
Cachet Bot
071159ffa1 New translations setup.php (Arabic) 2018-07-10 14:34:33 +01:00
Cachet Bot
b9549829c2 New translations forms.php (Arabic) 2018-07-10 14:34:32 +01:00
Cachet Bot
8c6be5006d New translations dashboard.php (Arabic) 2018-07-10 14:34:31 +01:00
Cachet Bot
cae3a54b50 New translations validation.php (Arabic) 2018-07-10 14:34:30 +01:00
Cachet Bot
0b3e29e8dd New translations cachet.php (Chinese Simplified) 2018-07-10 14:34:29 +01:00
Cachet Bot
a5d690abdd New translations pagination.php (Arabic) 2018-07-10 14:34:29 +01:00
Cachet Bot
31137c71d4 New translations setup.php (Albanian) 2018-07-10 14:34:28 +01:00
Cachet Bot
76963a186c New translations forms.php (Albanian) 2018-07-10 14:34:27 +01:00
Cachet Bot
3c2d85188b New translations dashboard.php (Albanian) 2018-07-10 14:34:26 +01:00
Cachet Bot
db407e81ea New translations validation.php (Albanian) 2018-07-10 14:34:25 +01:00
Cachet Bot
9dda8d5ae7 New translations pagination.php (Albanian) 2018-07-10 14:34:24 +01:00
Cachet Bot
ad637fbb81 New translations cachet.php (Albanian) 2018-07-10 14:34:23 +01:00
Cachet Bot
6805e75f63 New translations setup.php (Afrikaans) 2018-07-10 14:34:22 +01:00
Cachet Bot
bc5ae22165 New translations forms.php (Afrikaans) 2018-07-10 14:34:21 +01:00
Cachet Bot
6696465d45 New translations dashboard.php (Afrikaans) 2018-07-10 14:34:20 +01:00
Cachet Bot
58bb80efc9 New translations validation.php (Afrikaans) 2018-07-10 14:34:19 +01:00
Cachet Bot
e6b7b41f24 New translations cachet.php (Arabic) 2018-07-10 14:34:18 +01:00
Cachet Bot
682ac8ac5d New translations validation.php (Dutch) 2018-07-10 14:34:17 +01:00
Cachet Bot
9687384709 New translations pagination.php (Chinese Simplified) 2018-07-10 14:34:16 +01:00
Cachet Bot
347f443d4e New translations dashboard.php (Chinese Simplified) 2018-07-10 14:34:14 +01:00
Cachet Bot
548d9f8c3a New translations cachet.php (Dutch) 2018-07-10 14:34:13 +01:00
Cachet Bot
eeb85c1815 New translations setup.php (Danish) 2018-07-10 14:34:12 +01:00
Cachet Bot
1112c17306 New translations forms.php (Danish) 2018-07-10 14:34:10 +01:00
Cachet Bot
aa421830bb New translations dashboard.php (Danish) 2018-07-10 14:34:09 +01:00
Cachet Bot
99982566b8 New translations validation.php (Danish) 2018-07-10 14:34:08 +01:00
Cachet Bot
115b5b7013 New translations pagination.php (Danish) 2018-07-10 14:34:07 +01:00
Cachet Bot
65a263a2dd New translations cachet.php (Danish) 2018-07-10 14:34:06 +01:00
Cachet Bot
98e0a7b7b4 New translations setup.php (Czech) 2018-07-10 14:34:05 +01:00
Cachet Bot
7581d96c54 New translations forms.php (Czech) 2018-07-10 14:34:03 +01:00
Cachet Bot
8e7c0f3f0d New translations dashboard.php (Czech) 2018-07-10 14:34:02 +01:00
Cachet Bot
50c5b23f96 New translations validation.php (Chinese Simplified) 2018-07-10 14:34:01 +01:00
Cachet Bot
d77c53b5eb New translations validation.php (Czech) 2018-07-10 14:34:00 +01:00
Cachet Bot
cda30429be New translations cachet.php (Czech) 2018-07-10 14:33:59 +01:00
Cachet Bot
8cfb1282d3 New translations forms.php (Chinese Traditional) 2018-07-10 14:33:58 +01:00
Cachet Bot
9faa4b77cd New translations dashboard.php (Chinese Traditional) 2018-07-10 14:33:57 +01:00
Cachet Bot
6a5c5776a9 New translations validation.php (Chinese Traditional) 2018-07-10 14:33:56 +01:00
Cachet Bot
c63a76c86d New translations cachet.php (Chinese Traditional) 2018-07-10 14:33:54 +01:00
Cachet Bot
89718f5fbc New translations setup.php (Chinese Simplified) 2018-07-10 14:33:54 +01:00
Cachet Bot
8e84278a24 New translations forms.php (Chinese Simplified) 2018-07-10 14:33:53 +01:00
Cachet Bot
16470d548e New translations pagination.php (Czech) 2018-07-10 14:33:52 +01:00
Cachet Bot
320203262f New translations pagination.php (Afrikaans) 2018-07-10 14:33:51 +01:00
Cachet Bot
ae3b2e44b5 New translations cachet.php (Italian) 2018-07-10 14:33:50 +01:00
Cachet Bot
755b8143cb New translations validation.php (Italian) 2018-07-10 14:33:49 +01:00
Cachet Bot
4667948949 New translations dashboard.php (Thai) 2018-07-10 14:33:48 +01:00
Cachet Bot
0f7bee9c61 New translations validation.php (Thai) 2018-07-10 14:33:47 +01:00
Cachet Bot
10430ddad3 New translations pagination.php (Thai) 2018-07-10 14:33:46 +01:00
Cachet Bot
6e06e6a4dd New translations cachet.php (Thai) 2018-07-10 14:33:45 +01:00
Cachet Bot
393a1119da New translations forms.php (Swedish) 2018-07-10 14:33:44 +01:00
Cachet Bot
47fb5b2789 New translations dashboard.php (Swedish) 2018-07-10 14:33:43 +01:00
Cachet Bot
00caff7ecf New translations cachet.php (Swedish) 2018-07-10 14:33:41 +01:00
Cachet Bot
e1fccf1b26 New translations forms.php (Thai) 2018-07-10 14:33:40 +01:00
Cachet Bot
1a1e914d59 New translations setup.php (Spanish) 2018-07-10 14:33:39 +01:00
Cachet Bot
f2e995513f New translations dashboard.php (Spanish) 2018-07-10 14:33:38 +01:00
Cachet Bot
e780735987 New translations validation.php (Spanish) 2018-07-10 14:33:35 +01:00
Cachet Bot
1eaa4594af New translations pagination.php (Spanish) 2018-07-10 14:33:35 +01:00
Cachet Bot
9d51a34bd4 New translations cachet.php (Spanish) 2018-07-10 14:33:34 +01:00
Cachet Bot
d1681beae4 New translations setup.php (Russian) 2018-07-10 14:33:33 +01:00
Cachet Bot
0254d3df00 New translations forms.php (Russian) 2018-07-10 14:33:32 +01:00
Cachet Bot
2d15c27191 New translations dashboard.php (Russian) 2018-07-10 14:33:31 +01:00
Cachet Bot
17f12a0cb7 New translations validation.php (Russian) 2018-07-10 14:33:30 +01:00
Cachet Bot
e17400be21 New translations pagination.php (Russian) 2018-07-10 14:33:29 +01:00
Cachet Bot
62d7cb615d New translations cachet.php (Russian) 2018-07-10 14:33:28 +01:00
Cachet Bot
89759bb0ea New translations forms.php (Spanish) 2018-07-10 14:33:27 +01:00
Cachet Bot
7ee6cc91e7 New translations setup.php (Romanian) 2018-07-10 14:33:26 +01:00
Cachet Bot
bf2809bf50 New translations setup.php (Thai) 2018-07-10 14:33:26 +01:00
Cachet Bot
fcbd5b68b2 New translations pagination.php (Turkish) 2018-07-10 14:33:25 +01:00
Cachet Bot
1b1490f8bd New translations forms.php (Zulu) 2018-07-10 14:33:24 +01:00
Cachet Bot
019cafbbf5 New translations dashboard.php (Zulu) 2018-07-10 14:33:23 +01:00
Cachet Bot
a5a66e0de6 New translations validation.php (Zulu) 2018-07-10 14:33:22 +01:00
Cachet Bot
018aa8b0f0 New translations pagination.php (Zulu) 2018-07-10 14:33:21 +01:00
Cachet Bot
abcfdcdd0e New translations cachet.php (Zulu) 2018-07-10 14:33:20 +01:00
Cachet Bot
ceb95c30c4 New translations setup.php (Vietnamese) 2018-07-10 14:33:19 +01:00
Cachet Bot
08f9936e1d New translations forms.php (Vietnamese) 2018-07-10 14:33:19 +01:00
Cachet Bot
1647c4fc45 New translations dashboard.php (Vietnamese) 2018-07-10 14:33:18 +01:00
Cachet Bot
0eaf24febf New translations validation.php (Vietnamese) 2018-07-10 14:33:16 +01:00
Cachet Bot
544a6900bb New translations pagination.php (Vietnamese) 2018-07-10 14:33:15 +01:00
Cachet Bot
b6cbf817ab New translations cachet.php (Turkish) 2018-07-10 14:33:14 +01:00
Cachet Bot
1dab6c0f08 New translations cachet.php (Vietnamese) 2018-07-10 14:33:13 +01:00
Cachet Bot
9dfd47b1e9 New translations forms.php (Ukrainian) 2018-07-10 14:33:12 +01:00
Cachet Bot
0f26675767 New translations dashboard.php (Ukrainian) 2018-07-10 14:33:10 +01:00
Cachet Bot
24f2bb7fd4 New translations validation.php (Ukrainian) 2018-07-10 14:33:09 +01:00
Cachet Bot
4be32a6112 New translations pagination.php (Ukrainian) 2018-07-10 14:33:08 +01:00
Cachet Bot
0b23c86dd2 New translations cachet.php (Ukrainian) 2018-07-10 14:33:08 +01:00
Cachet Bot
22a6e70cfd New translations setup.php (Turkish) 2018-07-10 14:33:07 +01:00
Cachet Bot
8e6569b63d New translations forms.php (Turkish) 2018-07-10 14:33:06 +01:00
Cachet Bot
2c8c13cd82 New translations dashboard.php (Turkish) 2018-07-10 14:33:05 +01:00
Cachet Bot
3aabf285a9 New translations validation.php (Turkish) 2018-07-10 14:33:04 +01:00
Cachet Bot
d07e58d3db New translations setup.php (Ukrainian) 2018-07-10 14:33:03 +01:00
Cachet Bot
0d88d80d48 New translations pagination.php (Italian) 2018-07-10 14:33:02 +01:00
Cachet Bot
ea638ef2ae New translations forms.php (Romanian) 2018-07-10 14:33:01 +01:00
Cachet Bot
b31d30dd10 New translations validation.php (Romanian) 2018-07-10 14:33:00 +01:00
Cachet Bot
a5494b6559 New translations cachet.php (Persian) 2018-07-10 14:32:59 +01:00
Cachet Bot
909a67fe93 New translations setup.php (Norwegian) 2018-07-10 14:32:58 +01:00
Cachet Bot
2a8a4027d6 New translations forms.php (Norwegian) 2018-07-10 14:32:57 +01:00
Cachet Bot
27bc034691 New translations dashboard.php (Norwegian) 2018-07-10 14:32:56 +01:00
Cachet Bot
433093a012 New translations validation.php (Norwegian) 2018-07-10 14:32:55 +01:00
Cachet Bot
fde7ad65f6 New translations pagination.php (Norwegian) 2018-07-10 14:32:54 +01:00
Cachet Bot
172228fdb3 New translations cachet.php (Norwegian) 2018-07-10 14:32:53 +01:00
Cachet Bot
d287b10bc1 New translations setup.php (Korean) 2018-07-10 14:32:52 +01:00
Cachet Bot
db8fddf378 New translations forms.php (Korean) 2018-07-10 14:32:51 +01:00
Cachet Bot
fc45fb60ec New translations dashboard.php (Korean) 2018-07-10 14:32:50 +01:00
Cachet Bot
b11b5f2cf9 New translations pagination.php (Persian) 2018-07-10 14:32:49 +01:00
Cachet Bot
951250f1d1 New translations validation.php (Korean) 2018-07-10 14:32:48 +01:00
Cachet Bot
c9bdbf38d8 New translations cachet.php (Korean) 2018-07-10 14:32:47 +01:00
Cachet Bot
7449d44bc8 New translations setup.php (Japanese) 2018-07-10 14:32:46 +01:00
Cachet Bot
db5ce4397b New translations forms.php (Japanese) 2018-07-10 14:32:45 +01:00
Cachet Bot
3256ad8660 New translations dashboard.php (Japanese) 2018-07-10 14:32:44 +01:00
Cachet Bot
486198872a New translations validation.php (Japanese) 2018-07-10 14:32:43 +01:00
Cachet Bot
de12ccf291 New translations pagination.php (Japanese) 2018-07-10 14:32:42 +01:00
Cachet Bot
e1f5aa0639 New translations cachet.php (Japanese) 2018-07-10 14:32:40 +01:00
Cachet Bot
a70db4c031 New translations setup.php (Italian) 2018-07-10 14:32:40 +01:00
Cachet Bot
c1daf0ae0a New translations forms.php (Italian) 2018-07-10 14:32:39 +01:00
Cachet Bot
fad9e5fd92 New translations dashboard.php (Italian) 2018-07-10 14:32:38 +01:00
Cachet Bot
c224b5d05b New translations pagination.php (Korean) 2018-07-10 14:32:37 +01:00
Cachet Bot
78cc258d96 New translations dashboard.php (Romanian) 2018-07-10 14:32:36 +01:00
Cachet Bot
c87c37ad73 New translations validation.php (Persian) 2018-07-10 14:32:35 +01:00
Cachet Bot
ab02399ca6 New translations forms.php (Persian) 2018-07-10 14:32:34 +01:00
Cachet Bot
c3cf0b9e81 New translations pagination.php (Romanian) 2018-07-10 14:32:33 +01:00
Cachet Bot
2e5ead7886 New translations cachet.php (Romanian) 2018-07-10 14:32:32 +01:00
Cachet Bot
5a444d2c03 New translations forms.php (Portuguese, Brazilian) 2018-07-10 14:32:31 +01:00
Cachet Bot
34cf7428df New translations dashboard.php (Portuguese, Brazilian) 2018-07-10 14:32:30 +01:00
Cachet Bot
e3fa11d917 New translations validation.php (Portuguese, Brazilian) 2018-07-10 14:32:29 +01:00
Cachet Bot
6153d08880 New translations forms.php (Portuguese) 2018-07-10 14:32:27 +01:00
Cachet Bot
521c69b39e New translations dashboard.php (Persian) 2018-07-10 14:32:26 +01:00
Cachet Bot
9caf55d92e New translations dashboard.php (Portuguese) 2018-07-10 14:32:25 +01:00
Cachet Bot
357a1b4e86 New translations cachet.php (Portuguese) 2018-07-10 14:32:24 +01:00
Cachet Bot
c3ad824def New translations setup.php (Polish) 2018-07-10 14:32:23 +01:00
Cachet Bot
abeb6fd917 New translations forms.php (Polish) 2018-07-10 14:32:22 +01:00
Cachet Bot
be794d4ef2 New translations dashboard.php (Polish) 2018-07-10 14:32:21 +01:00
Cachet Bot
fe8ff219ef New translations validation.php (Polish) 2018-07-10 14:32:20 +01:00
Cachet Bot
e01993e5b8 New translations pagination.php (Polish) 2018-07-10 14:32:19 +01:00
Cachet Bot
6138ba99b8 New translations cachet.php (Polish) 2018-07-10 14:32:18 +01:00
Cachet Bot
6efe83c6b4 New translations setup.php (Persian) 2018-07-10 14:32:17 +01:00
Cachet Bot
1b152eb0fe New translations validation.php (Portuguese) 2018-07-10 14:32:17 +01:00
Cachet Bot
62012f4dab New translations cachet.php (Afrikaans) 2018-07-10 14:32:15 +01:00
James Brooks
5c39be5b2c Update deps 2018-07-06 08:29:21 +01:00
James Brooks
1e73861e15 Make file like 2.4 2018-07-04 21:12:30 +01:00
Cachet Bot
4099a8f4e6 Update Crowdin configuration file 2018-07-04 21:01:54 +01:00
James Brooks
163f57397d Update deps 2018-06-17 09:46:48 +01:00
James Brooks
494badb00a Merge pull request #3069 from CachetHQ/fix-component-group-status
Fix the component group status
2018-06-17 09:43:58 +01:00
James Brooks
84bea58f99 Merge branch '2.3' into fix-component-group-status 2018-06-14 21:02:26 +01:00
James Brooks
d7ffbeef0c Don't run tests on HHVM 2018-06-14 21:02:08 +01:00
James Brooks
4aff0ddec0 Fix the component group status. Closes #2731 2018-06-14 07:31:22 +01:00
James Brooks
749c83169c Merge pull request #3016 from hensur/stylesheet-fix-23
Backport stylesheet fix #3014 to 2.3
2018-04-19 08:47:32 +01:00
Henning Surmeier
58a212c2e4 Backport stylesheet fix #3014 to 2.3 2018-04-18 16:27:19 +02:00
James Brooks
0c72e5eec8 Apply fixes from StyleCI (#2962)
[ci skip] [skip ci]
2018-03-26 19:18:30 +01:00
James Brooks
83bc743d79 Merge pull request #2960 from anthonybocci/metric-points-prefix-table-2925
Use the table prefix on metric_points
2018-03-26 19:18:07 +01:00
Anthony Bocci
35dcc8c928 Use the table prefix on metric_points
In the '.env' file, a 'DB_PREFIX' sets the prefix that should be used
on every table name. When writing an SQL query the 'DB_PREFIX' value
has to be prefixed to the table name.

The repository PgSqlRepository, MySqlRepository and SqliteRepository,
located in 'app/Repositories/Metric/' did not apply this prefix on
the 'metric_points' table. The problem occured only when we set a
'DB_PREFIX' not null, the rest of the application worked correctly but
the part about 'metric_points' couldn't work, saying the table was
inexistant.

A method was added in the repository AbstractMetricRepository to get
the 'metric_points' table name with the prefix if there is one.
This method is used in the three repositories to get the right table
name.

Note: This problem was present in 2.3, but was already fixed in 2.4 so
there is no need to apply this commit on the 2.4 branch.

See: CachetHQ/Cachet/#2955
2018-03-23 20:56:41 +01:00
James Brooks
93d1f8784a Merge pull request #2864 from snowflakeOps/2.3
use a better and smaller image for open graph (e.g for slack)
2018-01-11 21:33:49 +00:00
Markus Ritzmann
0450f2f330 #2853 use a better and smaller image for og 2018-01-11 16:49:01 +01:00
James Brooks
595b152db5 Merge pull request #2671 from checkitonus/bug/invalid-template-23
Quick check to make sure the template exists
2017-09-30 11:38:19 +01:00
Graham Campbell
cc15d078bf Removed old links 2017-09-10 18:24:01 +01:00
Graham Campbell
3b568bbc07 Mail password non-required 2017-09-10 18:11:23 +01:00
Graham Campbell
ae4c414a82 Upgraded exceptions package 2017-09-10 17:54:18 +01:00
Graham Campbell
5358cf5e1e Upgraded deps 2017-09-10 17:20:07 +01:00
Andrew Judd
6dedacad57 Removing a helper method 2017-07-30 08:48:45 -04:00
Andrew Judd
29c9211935 Quick check to make sure the template exists 2017-07-29 11:13:41 -04:00
James Brooks
7d47546650 Switch to dev 2017-07-17 21:50:00 +01:00
James Brooks
f5a9941903 Update deps again 2017-07-17 21:49:42 +01:00
James Brooks
52b7bf74b9 Update version 2017-07-17 21:46:30 +01:00
James Brooks
6a59d5ac4d Update deps 2017-07-17 21:44:45 +01:00
James Brooks
19b7b0c3b2 Require predis/predis. Fixes #2611 2017-07-17 21:44:43 +01:00
Graham Campbell
d4507e0722 Back to dev 2017-06-28 23:42:10 +01:00
Graham Campbell
47bc73f9e9 Release v2.3.12 2017-06-28 23:41:31 +01:00
Graham Campbell
81fc6479d5 Revert to original travis config 2017-06-28 22:53:06 +01:00
Graham Campbell
c9ca99990c Update .travis.yml 2017-06-28 22:49:07 +01:00
Graham Campbell
e0d35d6e64 Merge branch '2.3' of https://github.com/CachetHQ/Cachet into 2.3 2017-06-28 22:39:55 +01:00
Graham Campbell
813be34f25 Upgraded dependencies 2017-06-28 22:39:41 +01:00
Graham Campbell
900723105b Update .travis.yml 2017-06-28 22:38:44 +01:00
Graham Campbell
8012a201b9 Update .travis.yml 2017-06-28 22:00:28 +01:00
Graham Campbell
706e7765e1 Update .travis.yml 2017-06-28 21:52:45 +01:00
Guido Hendriks
bcff3d0730 Improve testCreateSubscriberWithSubscriptions test case (#2487) 2017-06-28 21:45:27 +01:00
James Brooks
db5bf005bc Apply fixes from StyleCI (#2606)
[ci skip] [skip ci]
2017-06-28 20:52:41 +01:00
James Brooks
dac88efce6 Merge pull request #2601 from Daniel15/2.3-with-patches
Backport API endpoint to get system status to v2.3
2017-06-28 20:52:08 +01:00
James Brooks
38ef2630ee Add system status to /status endpoint 2017-06-20 17:18:38 +10:00
James Brooks
c215ad4111 Implement the system status api endpoint. Closes #1936 2017-06-20 17:09:03 +10:00
James Brooks
c899839a7f Back to dev 2017-04-12 23:05:32 +01:00
James Brooks
2e5e8b1545 Bump version to 2.3.11 2017-04-12 23:05:09 +01:00
James Brooks
7e556d5dba Apply fixes from StyleCI (#2486)
[ci skip] [skip ci]
2017-04-12 23:04:21 +01:00
James Brooks
331e176fbc Updated deps 2017-03-25 11:42:25 +00:00
James Brooks
bde0abe472 Fix handling of individual component subscriptions via API 2016-09-21 18:35:58 +01:00
James Brooks
f2bf2eff68 Test creating a subscriber returns subscriptions 2016-09-21 18:17:22 +01:00
James Brooks
50ab96fc4f Load subscriptions when creating a subscriber 2016-09-21 18:16:08 +01:00
James Brooks
3cbee1302e Update deps 2016-09-21 18:08:56 +01:00
Graham Campbell
8d74923e3f Back to dev 2016-08-11 12:16:50 +01:00
Graham Campbell
dbf6fe528c Release v2.3.10 2016-08-11 12:16:14 +01:00
Graham Campbell
2a9d1b4897 Backport new command tests 2016-08-11 12:09:28 +01:00
Graham Campbell
c2192d7ef7 Backport readme changes 2016-08-11 12:03:28 +01:00
Graham Campbell
1b580360ac Updated deps 2016-08-10 21:04:17 +01:00
James Brooks
15407ad9a3 Remove dump and die 2016-08-10 20:28:32 +01:00
James Brooks
14127de3ca Back to dev 2016-08-07 22:05:34 +01:00
James Brooks
57988f0009 Release v2.3.9 2016-08-07 22:05:16 +01:00
Graham Campbell
7ac7344b5e Updated dep 2016-08-07 22:01:00 +01:00
James Brooks
472dcfe85a Merge pull request #2036 from CachetHQ/analysis-8KggM3
Applied fixes from StyleCI

[ci skip] [skip ci]
2016-08-07 21:10:17 +01:00
James Brooks
77409abc5a Applied fixes from StyleCI
[ci skip] [skip ci]
2016-08-07 16:10:12 -04:00
James Brooks
7548ae7e58 Disable fixedStepSize 2016-08-07 21:09:47 +01:00
James Brooks
074d3457c6 Fix Italian translation issues. Closes #2034 2016-08-07 19:45:13 +01:00
James Brooks
205748b182 Improve metric labels 2016-08-07 19:22:19 +01:00
James Brooks
1f4bee67d6 Back to dev 2016-08-05 07:52:10 +01:00
James Brooks
2f0df5ab7b Bump version 2016-08-05 07:51:44 +01:00
James Brooks
8fe75f7112 Update deps 2016-08-05 07:51:25 +01:00
Graham Campbell
b3ee389ca5 Merge pull request #2021 from CachetHQ/require-xml
Require the ext-xml extension
2016-08-02 11:13:29 +01:00
James Brooks
a40bfd12b7 Removed blank line 2016-08-02 11:02:31 +01:00
James Brooks
8d86c5e072 Ignore SQLite databases when backing up the db 2016-08-02 11:00:39 +01:00
James Brooks
20ca9ceade Require the ext-xml extension 2016-08-02 10:55:33 +01:00
Graham Campbell
6c22c52e3a Updated the aws sdk 2016-07-29 12:51:06 -04:00
James Brooks
ecfa9b1f01 Built in production 2016-07-29 12:04:57 -04:00
James Brooks
380048dd53 Updated Chart.js and rebuilt assets 2016-07-29 11:42:08 -04:00
Graham Campbell
ac57936b62 Merge pull request #2015 from CachetHQ/metrics-y-step-size
Set the step size to the metrics places
2016-07-28 15:39:58 -04:00
James Brooks
962b008fb2 Updated deps 2016-07-28 15:19:58 -04:00
James Brooks
5b1dd8ad00 Set the step size to the metrics places. Fixes #2012 2016-07-28 15:17:20 -04:00
James Brooks
c1d8203602 Added missing setup translations. Closes #2010 2016-07-28 15:06:16 -04:00
James Brooks
dc73f62803 Fixes issues with updating using dashboard api. Closes #2014 2016-07-28 10:47:59 -04:00
Graham Campbell
fdbde63143 Back to dev 2016-07-25 22:58:23 +01:00
Graham Campbell
9a9ec833eb Released 2.3.7 2016-07-25 22:57:05 +01:00
James Brooks
136cce2d6d Merge pull request #2008 from CachetHQ/analysis-XZnLDb
Applied fixes from StyleCI

[ci skip] [skip ci]
2016-07-25 21:52:31 +01:00
Graham Campbell
880a2d9cd9 Applied fixes from StyleCI
[ci skip] [skip ci]
2016-07-25 16:52:26 -04:00
James Brooks
aea18a51c2 Sync languages 2016-07-25 21:42:49 +01:00
Graham Campbell
84bedf5c60 Merge pull request #2007 from CachetHQ/revert-1976-cli
Revert "Don't use settings caching in cli"
2016-07-25 19:32:16 +01:00
Graham Campbell
309a3f96ef Revert "Don't use settings caching in cli" 2016-07-25 19:25:05 +01:00
Graham Campbell
acd1ac496d Merge pull request #2003 from CachetHQ/analysis
Run the new static analysis checks in the tests
2016-07-24 14:58:03 +01:00
Graham Campbell
8c273b8579 Run the new static analysis checks in the tests 2016-07-24 14:48:59 +01:00
Graham Campbell
b30a774bed Merge pull request #2002 from CachetHQ/imports
Added missing imports
2016-07-24 14:48:03 +01:00
Graham Campbell
3ea1428c23 Added missing imports 2016-07-24 14:47:02 +01:00
James Brooks
d6ab5efd14 Fixes #1998 2016-07-22 11:08:49 +01:00
James Brooks
a94be2efca Update deps 2016-07-22 09:19:58 +01:00
Graham Campbell
f8505a866d Back to dev 2016-07-18 19:34:29 +01:00
Graham Campbell
27235abab2 Released 2.3.6 2016-07-18 19:34:06 +01:00
Graham Campbell
f70bc7a42f Merge pull request #1986 from CachetHQ/deps
Updated dependencies
2016-07-18 18:51:37 +01:00
Graham Campbell
6cf622ae21 Updated dependencies 2016-07-18 18:46:43 +01:00
James Brooks
dd1a14a438 Back to dev 2016-07-17 16:38:52 +01:00
James Brooks
387818dbb2 Bump version 2016-07-17 16:38:24 +01:00
James Brooks
5d70d244ce Update feed package. Fixes #1973 2016-07-17 16:37:55 +01:00
James Brooks
ddc846d959 Back to dev 2016-07-16 09:54:54 +01:00
James Brooks
6fb6641499 Bump version 2016-07-16 09:54:28 +01:00
James Brooks
d5eb087eca Merge pull request #1976 from CachetHQ/cli
Don't use settings caching in cli
2016-07-15 07:48:26 +01:00
Graham Campbell
fd25edb2f0 Don't use settings caching in cli 2016-07-14 21:31:07 -07:00
Graham Campbell
5879a2cb1a Updated the exceptions package 2016-07-14 11:11:21 -07:00
Graham Campbell
df5b9b89e6 Updated dependencies 2016-07-13 18:25:27 -07:00
James Brooks
47a5569f02 Improve how we work out system status with scheduled maintenance 2016-07-13 14:19:35 +01:00
James Brooks
ca4a72c518 Merge pull request #1960 from PeterDaveHello/bump-node-dependencies
bump nodejs package dependencies
2016-07-13 13:57:49 +01:00
Peter Dave Hello
6e45b5ae88 bump nodejs package dependencies 2016-07-13 20:57:16 +08:00
James Brooks
99dbc2cd6c Merge pull request #1959 from PeterDaveHello/fix-file-permission
remove executable permission from the files don't need it
2016-07-12 09:31:22 +01:00
Peter Dave Hello
2f2ed53b58 remove executable permission from the files don't need it 2016-07-12 16:28:28 +08:00
James Brooks
7e1ead91ed Merge pull request #1958 from PeterDaveHello/image-optimize
optimize png images using zopflipng
2016-07-12 09:23:02 +01:00
Peter Dave Hello
28578474b9 optimize png images using zopflipng 2016-07-12 16:20:14 +08:00
James Brooks
d4e332bf55 Merge pull request #1956 from PeterDaveHello/patch-1
Update README.md
2016-07-12 09:15:37 +01:00
Peter Dave Hello
13f0f67a7b Update README.md
Use svg instead of png to get localized percentage badge for better image quality.
2016-07-12 16:14:54 +08:00
James Brooks
709cac9332 Merge pull request #1953 from CachetHQ/fix-setup
fix setup env writing
2016-07-11 19:03:48 +01:00
Joseph Cohen
e17196d4c9 fix setup env writing 2016-07-11 13:00:00 -05:00
James Brooks
80be140c1f Update ISSUE_TEMPLATE 2016-07-11 09:50:33 +01:00
James Brooks
4f9af8bca0 Remove blank line 2016-07-10 17:04:08 +01:00
James Brooks
af3b7836ff Back to dev 2016-07-10 10:39:42 +01:00
James Brooks
cc4a960ea6 Release v2.3.3 2016-07-10 10:39:19 +01:00
James Brooks
467d29ca11 Use numeric validation for metric points. Fixes #1950 2016-07-10 10:37:00 +01:00
James Brooks
ac1355771c Merge pull request #1947 from CachetHQ/set-locale
Set Date locale
2016-07-08 19:43:04 +01:00
James Brooks
c41adc1019 Override date locale again. Fixes #1727 2016-07-08 19:42:20 +01:00
James Brooks
5b74b2d625 Merge pull request #1949 from CachetHQ/dashboard-api-bus
The dashboard API needs to use the Command Bus
2016-07-08 18:39:38 +01:00
James Brooks
d7835f68ed Merge pull request #1948 from CachetHQ/analysis-zO37Lk
Applied fixes from StyleCI

[ci skip] [skip ci]
2016-07-08 17:42:17 +01:00
James Brooks
a1f1a2b969 Applied fixes from StyleCI
[ci skip] [skip ci]
2016-07-08 12:42:13 -04:00
James Brooks
77394995e4 The dashboard API needs to use the Command Bus. Fixes #1927 2016-07-08 17:42:01 +01:00
James Brooks
9953557497 Back to dev 2016-07-06 21:54:50 +01:00
James Brooks
4dc175b2be Correct dev version 2016-07-06 21:53:15 +01:00
James Brooks
4a2fe00c89 Bump version 2016-07-06 21:52:32 +01:00
James Brooks
db55283b85 Merge pull request #1940 from CachetHQ/analysis-86V7RW
Applied fixes from StyleCI

[ci skip] [skip ci]
2016-07-06 19:14:04 +01:00
James Brooks
5c6440e890 Sync languages 2016-07-06 19:14:21 +01:00
James Brooks
6b299b0a90 Applied fixes from StyleCI
[ci skip] [skip ci]
2016-07-06 14:14:00 -04:00
James Brooks
9b5d4aa7c4 Merge pull request #1939 from CachetHQ/metric-repository-prefix
Metric repository now knows prefixes
2016-07-06 19:03:42 +01:00
James Brooks
1fdda03199 Metric repository now knows prefixes. Fixes #1938 2016-07-06 18:42:31 +01:00
James Brooks
7c846d06ff Updated deps 2016-07-06 18:32:04 +01:00
James Brooks
e34e4381d4 Update VERSION 2016-07-06 18:24:58 +01:00
Graham Campbell
b255f71958 Merge pull request #1934 from odannyc/patch-1
Misspelled 'email'
2016-07-02 10:59:51 +01:00
Danny Carrillo
9560b2a0dc Misspelled 'email' 2016-07-01 13:55:28 -07:00
James Brooks
f8491ceead Back to dev 2016-06-27 22:10:37 +01:00
James Brooks
823fe6e9e2 Bump version 2016-06-27 22:10:13 +01:00
James Brooks
b7e9c07a05 Merge pull request #1924 from CachetHQ/analysis-zDyveB
Applied fixes from StyleCI

[ci skip] [skip ci]
2016-06-27 21:18:57 +01:00
James Brooks
a9d83e1337 Applied fixes from StyleCI
[ci skip] [skip ci]
2016-06-27 16:18:52 -04:00
James Brooks
86cfcb501a Added /admin route redirect to /dashboard 2016-06-27 21:18:44 +01:00
James Brooks
8f68b2a347 Re-compiled assets 2016-06-27 18:39:31 +01:00
Graham Campbell
1423a9bbd0 Updated dependencies 2016-06-27 15:48:35 +01:00
James Brooks
39d302175c Merge pull request #1919 from travelton/group-dashboard-components
Component Grouping in Dashboard
2016-06-27 15:41:01 +01:00
Travis Swientek
fffb4d964c Component Grouping in Dashboard, Spelling Adjustment. 2016-06-27 09:05:34 -05:00
James Brooks
7ba12960dd Added missing events to EventServiceProvider 2016-06-27 12:22:18 +01:00
James Brooks
440f45ed4a Merge pull request #1920 from juniorb2ss/2.3
Fix language name.
2016-06-24 17:42:11 +01:00
Carlos Eduardo
549eaa3382 Fix language name.
Correct name of slugs portuguese.
2016-06-24 12:27:10 -03:00
James Brooks
5305f71c2b Updated deps 2016-06-20 13:49:55 +01:00
James Brooks
bf749c54ee Move helpers.php out of Http namespace 2016-06-17 09:16:23 +01:00
James Brooks
f1e2c1ef68 Merge pull request #1911 from CachetHQ/fix-lastpass
Help password managers
2016-06-15 08:54:50 +01:00
James Brooks
4ab9807cbe Help password managers. Fixes #1910 2016-06-15 08:54:13 +01:00
James Brooks
9f9c9a10c5 Merge pull request #1886 from CachetHQ/wizard-smtp
Wizard email configuration
2016-06-13 20:06:51 +01:00
Joseph Cohen
a5ed3c40a9 Fix write env to work with nulls and change from to address 2016-06-13 20:06:40 +01:00
James Brooks
1fe4789760 Fix spacing 2016-06-13 20:06:39 +01:00
James Brooks
9c1e94c550 Put mail log to bottom 2016-06-13 20:06:39 +01:00
Joseph Cohen
958c9eadc7 Add mail data to wizard 2016-06-13 20:06:39 +01:00
Joseph Cohen
ca3f516457 Add mail driver to the wizard 2016-06-13 20:06:28 +01:00
Graham Campbell
04215fc37a Back to dev 2016-06-11 00:47:41 +01:00
Graham Campbell
8d90357f40 Released 2.3.0 RC6 2016-06-11 00:47:07 +01:00
Graham Campbell
46add8d841 Merge branch '2.2' into 2.3
# Conflicts:
#	VERSION
#	composer.json
#	composer.lock
2016-06-11 00:46:01 +01:00
Graham Campbell
1e695d51b5 Added the aws sdk as a dependency 2016-06-11 00:45:26 +01:00
Graham Campbell
cd4a96983e Updated laravel 2016-06-11 00:21:03 +01:00
Graham Campbell
c0d3602a91 Updated dependencies 2016-06-11 00:19:19 +01:00
James Brooks
08175b89e9 Merge pull request #1905 from CachetHQ/analysis-qMPD92
Applied fixes from StyleCI

[ci skip] [skip ci]
2016-06-10 17:27:37 +01:00
James Brooks
ece696d7db Merge pull request #1904 from CachetHQ/analysis-z327Ep
Applied fixes from StyleCI

[ci skip] [skip ci]
2016-06-10 17:27:33 +01:00
James Brooks
e7052f5aff Applied fixes from StyleCI
[ci skip] [skip ci]
2016-06-10 12:27:33 -04:00
James Brooks
ff97327803 Applied fixes from StyleCI
[ci skip] [skip ci]
2016-06-10 12:27:29 -04:00
James Brooks
8dda99c499 Compiled assets 2016-06-10 17:27:26 +01:00
James Brooks
947aa27e40 Move dashboard version check into version api endpoint 2016-06-10 17:27:21 +01:00
James Brooks
1425c15ee8 Don't rely on jQuery to be ready 2016-06-10 17:13:42 +01:00
James Brooks
cdbd2db8e9 Re-compile assets 2016-06-10 13:46:28 +01:00
James Brooks
ef02d77439 Remove the login background 2016-06-10 13:42:13 +01:00
Graham Campbell
88ce241785 Updated dependencies 2016-06-10 08:53:26 +01:00
Graham Campbell
b64dd1e87e Properly fixed metric updating
// cc @jbrooksuk
2016-06-07 11:11:17 +01:00
Graham Campbell
a0b9856d61 Updated deps 2016-06-07 11:07:02 +01:00
James Brooks
d6552982a3 Order by id if order is all the same 2016-06-07 08:54:56 +01:00
James Brooks
42eac92737 Pass update order as null from the dashboard 2016-06-07 08:53:41 +01:00
Graham Campbell
a2cee97f33 Rebuilt assets 2016-06-07 00:13:41 +01:00
Graham Campbell
0541a662ff Fixed path 2016-06-07 00:12:17 +01:00
Graham Campbell
6c9b7a6fde Updated dependencies 2016-06-06 20:32:49 +01:00
James Brooks
812160839f Support a Redis passwords 2016-06-05 16:52:18 +01:00
James Brooks
27e46d77e6 Publish the cache table migration 2016-06-05 10:16:50 +01:00
James Brooks
a10d12e589 Merge pull request #1869 from CachetHQ/update-login-page
Updated login page
2016-06-04 15:55:40 +01:00
James Brooks
ac7652f3aa Remove unused divs 2016-06-04 15:55:01 +01:00
James Brooks
c63fedefe9 Updated login page 2016-06-04 14:57:16 +01:00
Graham Campbell
c17ef87651 Merge pull request #1891 from CachetHQ/deps
Updated dependencies
2016-06-03 17:23:47 +01:00
Graham Campbell
846f77b054 Updated dependencies 2016-06-03 17:20:14 +01:00
Graham Campbell
d5c29a6c4b Merge pull request #1890 from CachetHQ/fixes
Fixed the integrations
2016-06-03 17:11:00 +01:00
Graham Campbell
31861f020f Fixed typo 2016-06-03 17:10:24 +01:00
Graham Campbell
abf83361e8 Fixed the integrations 2016-06-03 17:07:36 +01:00
James Brooks
3e8801d8d4 Merge pull request #1887 from CachetHQ/analysis-XkYWW1
Applied fixes from StyleCI

[ci skip] [skip ci]
2016-06-03 14:00:33 +01:00
James Brooks
bbc9eb1f81 Applied fixes from StyleCI
[ci skip] [skip ci]
2016-06-03 09:00:29 -04:00
James Brooks
c8b602d349 Handle failing to fetch blog posts. Fixes #1878 2016-06-03 14:00:23 +01:00
James Brooks
715eb02844 Use default_view or view. Fixes #1842 2016-06-03 13:54:26 +01:00
James Brooks
c8f7e92124 Only test the seed command 2016-06-03 10:44:02 +01:00
James Brooks
eae44ee6cb Fix redirecting back to the correct settings page 2016-06-03 10:16:44 +01:00
James Brooks
3fde593a86 Standardise the error message 2016-06-03 10:15:08 +01:00
James Brooks
1527ec8ddc Test all app: commands 2016-06-02 18:40:51 +01:00
Graham Campbell
c90584bda5 Merge pull request #1879 from CachetHQ/deps
Updated dependencies
2016-06-02 10:46:20 +01:00
Graham Campbell
aea3b40c54 Updated dependencies 2016-06-02 10:43:40 +01:00
Graham Campbell
d394e108bd Fix the feed package 2016-06-02 10:37:47 +01:00
Graham Campbell
0df9f01ffe Updated dependencies 2016-06-02 10:30:38 +01:00
James Brooks
9745bb7543 Merge pull request #1876 from CachetHQ/metric-ordering-api
Set an order on metrics via the API
2016-06-02 10:16:35 +01:00
James Brooks
cab030237b Set an order on metrics via the API. Closes #1874 2016-06-02 10:16:23 +01:00
James Brooks
439ac9fe44 Updated dependencies 2016-06-02 09:21:33 +01:00
James Brooks
7eef9467aa Don't go resetting the threshold value 2016-06-02 09:09:03 +01:00
James Brooks
15387b1da8 Allow searching incidents by component_id. Closes #1873 2016-06-02 08:46:59 +01:00
James Brooks
c33d297fa4 Merge pull request #1871 from CachetHQ/analysis-8jlox9
Applied fixes from StyleCI

[ci skip]
2016-06-01 11:50:39 +01:00
James Brooks
c8af103498 Applied fixes from StyleCI
[ci skip]
2016-06-01 06:50:35 -04:00
James Brooks
0e2610eee0 Fix indentation of setting 2016-06-01 11:50:27 +01:00
James Brooks
e201a6ed06 Seed with Patreon page component 2016-06-01 11:50:27 +01:00
James Brooks
1e4d616b88 Merge pull request #1870 from CachetHQ/analysis-8wOpew
Applied fixes from StyleCI

[ci skip]
2016-06-01 11:49:11 +01:00
James Brooks
2de01671e9 Applied fixes from StyleCI
[ci skip]
2016-06-01 06:49:07 -04:00
James Brooks
dd26a3af34 Fix default settings for enable_subscribers 2016-06-01 11:48:59 +01:00
Graham Campbell
4b41395144 Tweak 2016-06-01 11:42:25 +01:00
James Brooks
2dacc71e8a Set the default show_support setting 2016-06-01 08:04:16 +01:00
James Brooks
4869c7ee21 Merge pull request #1867 from CachetHQ/analysis-8maVvE
Applied fixes from StyleCI

[ci skip]
2016-05-31 20:19:00 +01:00
James Brooks
9293dcf0df Applied fixes from StyleCI
[ci skip]
2016-05-31 15:18:56 -04:00
James Brooks
150057ef50 Sync languages 2016-05-31 20:18:39 +01:00
James Brooks
c81f18c3bc Back to dev 2016-05-31 19:31:56 +01:00
James Brooks
42aa437ac2 Released 2.3.0 RC5 2016-05-31 19:31:34 +01:00
James Brooks
6a780314fb Rebuild assets 2016-05-31 19:29:28 +01:00
James Brooks
ffae9cf3d4 Merge pull request #1866 from CachetHQ/analysis-zRP0lp
Applied fixes from StyleCI

[ci skip]
2016-05-31 19:27:14 +01:00
James Brooks
091f59c241 Applied fixes from StyleCI
[ci skip]
2016-05-31 14:27:10 -04:00
James Brooks
288fa6180b Publish the css-inliner config 2016-05-31 19:27:00 +01:00
James Brooks
7ecb546a86 Merge pull request #1865 from CachetHQ/dashboard-feed
Dashboard feed
2016-05-31 19:25:30 +01:00
James Brooks
f7c8dd6254 Merge pull request #1864 from CachetHQ/analysis-XN4p11
Applied fixes from StyleCI

[ci skip]
2016-05-31 19:12:36 +01:00
James Brooks
2adc9d032a Applied fixes from StyleCI
[ci skip]
2016-05-31 14:12:32 -04:00
James Brooks
f53075ec4f Add Patreon link and latest Cachet blog posts to dashboard 2016-05-31 19:12:23 +01:00
James Brooks
0190813012 Dashboard RSS 2016-05-31 18:02:10 +01:00
Graham Campbell
20d187d642 Back to dev 2016-05-29 19:28:42 +01:00
Graham Campbell
91bd9288f5 Released 2.3.0 RC4 2016-05-29 19:28:10 +01:00
Graham Campbell
24df32e9a9 Fixed bad caching 2016-05-29 19:20:56 +01:00
Graham Campbell
fb75ad6902 Include our user agent 2016-05-29 19:17:22 +01:00
Graham Campbell
aa87274378 Another fix 2016-05-29 18:49:40 +01:00
Graham Campbell
696a1126c7 Fixed lang file 2016-05-29 18:47:33 +01:00
Graham Campbell
7c4787a1a7 Merge pull request #1815 from CachetHQ/backers-credits-dashboard
Added credits page
2016-05-29 18:44:52 +01:00
Graham Campbell
74d24b6809 Link the images 2016-05-29 18:40:29 +01:00
Graham Campbell
22226c666f Force size 2016-05-29 18:34:08 +01:00
Graham Campbell
b3244a4639 Fixed import 2016-05-29 18:27:04 +01:00
Graham Campbell
6cf3c4c109 Merge pull request #1861 from CachetHQ/analysis-z4waDG
Applied fixes from StyleCI

[ci skip]
2016-05-29 18:24:17 +01:00
Graham Campbell
8f47bd4a4f Applied fixes from StyleCI
[ci skip]
2016-05-29 13:24:13 -04:00
Graham Campbell
c03f01ca44 Added credits 2016-05-29 18:14:40 +01:00
Graham Campbell
ab0ed775e1 Merge pull request #1860 from CachetHQ/tests
Cleanup travis test config
2016-05-29 12:09:48 +01:00
Graham Campbell
5a600c0e17 Removed old badge 2016-05-29 12:00:59 +01:00
Graham Campbell
601a863fc4 Cleanup tests 2016-05-29 12:00:02 +01:00
Graham Campbell
366eab9cae Merge pull request #1859 from CachetHQ/typo
Fixed typo
2016-05-29 11:13:14 +01:00
Graham Campbell
021c2890d2 Fixed typo 2016-05-29 10:57:45 +01:00
Graham Campbell
2eff325a23 Back to dev 2016-05-28 22:02:11 +01:00
Graham Campbell
d7e70c1870 Released 2.3.0 RC3 2016-05-28 22:01:44 +01:00
Graham Campbell
0311d59e78 Updated dependencies 2016-05-28 20:27:19 +01:00
Graham Campbell
6a6c8d866e Merge pull request #1843 from CachetHQ/improve-emails
Improve email designs, use theme colours
2016-05-28 18:36:55 +01:00
Graham Campbell
11d82a22c3 Merge pull request #1856 from CachetHQ/fix-flash-msg
Fix login flash messages #1850
2016-05-28 18:36:26 +01:00
Joseph Cohen
dcfe55e881 Fix login flash messages #1850 2016-05-28 12:34:52 -05:00
Graham Campbell
494d1a021c Merge pull request #1855 from CachetHQ/proxies
Synced the trusted proxies
2016-05-28 18:32:42 +01:00
Graham Campbell
d95557d683 Synced the trusted proxies 2016-05-28 18:31:41 +01:00
Joe Cohen
48ccc02799 Applied fixes from StyleCI
[ci skip]
2016-05-28 12:30:39 -05:00
Joseph Cohen
f3440389be Improve email content and subject, fix component notification presenter 2016-05-28 12:30:39 -05:00
James Brooks
bad9b1d550 Improve email designs, use theme colours 2016-05-28 12:30:39 -05:00
Graham Campbell
e1d07fdc99 Updated the throttle package again 2016-05-28 16:28:53 +01:00
Graham Campbell
e69395a5ad Merge pull request #1852 from CachetHQ/tests
Added more service provider tests
2016-05-28 16:27:35 +01:00
Graham Campbell
1c10cba5fc Added more service provider tests 2016-05-28 16:19:33 +01:00
Graham Campbell
3a1042e6ae Tweaked the metric repo binding 2016-05-28 16:19:17 +01:00
Graham Campbell
a2a008b108 Updated the throttle package 2016-05-28 16:18:28 +01:00
Graham Campbell
11f8ba81fd Merge pull request #1851 from CachetHQ/throttling
Fix crap login throttling
2016-05-28 15:52:25 +01:00
Graham Campbell
e8d216b671 Enabled the new displayer 2016-05-28 15:50:03 +01:00
Graham Campbell
167d076edc Fix crap login throttling 2016-05-28 15:45:38 +01:00
James Brooks
5c5634d355 We no longer need to pass the app_name in 2016-05-27 11:35:59 +01:00
Graham Campbell
1eea34e832 Updated laravel 2016-05-27 08:57:12 +01:00
James Brooks
3873fd90ba Make sure subscribers are enabled before displaying add subscriber 2016-05-26 11:51:25 +01:00
James Brooks
38a659b08c Back to dev 2016-05-26 11:44:40 +01:00
James Brooks
55b6961a4b Released 2.3.0 RC2 2016-05-26 11:43:39 +01:00
James Brooks
2b87629dca Fix issues with localizations not applying properly 2016-05-26 11:35:00 +01:00
James Brooks
48c4240c38 Removed un-needed equality param 2016-05-26 11:28:52 +01:00
James Brooks
f84793bfab Remove strong tag 2016-05-26 11:22:23 +01:00
James Brooks
0200ac848f Reduce indentation 2016-05-26 11:20:07 +01:00
James Brooks
787bb74b3b Fix trailing "email" string 2016-05-26 11:19:54 +01:00
James Brooks
8f58cdd182 Merge pull request #1831 from CachetHQ/reduce-size-settings-controller
Moved banner handling into a separate method as it's big
2016-05-26 08:43:20 +01:00
James Brooks
8f0691f3bd Merge pull request #1835 from CachetHQ/subscribers
Remove subscribers modal
2016-05-26 08:42:57 +01:00
James Brooks
a81ce21721 Merge pull request #1836 from CachetHQ/lang
Fixed English translations
2016-05-26 08:41:50 +01:00
Graham Campbell
1e0992be6c Restored the validation translations 2016-05-26 08:18:02 +01:00
Graham Campbell
00706ad744 Fixed uppercase letter 2016-05-26 08:16:49 +01:00
Joseph Cohen
31d47cfb35 Remove subscribers modal 2016-05-26 00:50:23 -05:00
James Brooks
7e29f7d363 Moved banner handling into a separate method as it's big 2016-05-25 22:16:41 +01:00
Graham Campbell
71a1ab091f Updated laravel 2016-05-25 21:55:26 +01:00
James Brooks
9e020e5d59 Merge pull request #1830 from CachetHQ/default-enable-subscibers
Enable subscribers by default
2016-05-25 21:20:45 +01:00
James Brooks
5e10f1c777 Enable subscribers by default 2016-05-25 21:20:24 +01:00
Graham Campbell
a2aa116204 Merge pull request #1829 from CachetHQ/fix-config-seeding
Fix clearing of configs when seeding
2016-05-25 20:30:30 +01:00
Graham Campbell
ac65cc56bb I prefer clear 2016-05-25 20:26:58 +01:00
James Brooks
9e3f07742b Fix clearing of configs when seeding 2016-05-25 20:00:33 +01:00
James Brooks
b120c37cbc Fix colour of p and strong tags 2016-05-25 19:23:11 +01:00
James Brooks
6211e7a1f8 Drop the "| Cachet" extra from the site title 2016-05-25 12:23:22 +01:00
Graham Campbell
5d23f83db6 Modified english translations next/previous 2016-05-25 12:21:17 +01:00
Graham Campbell
a2ea9bf10b Merge pull request #1826 from CachetHQ/controller
Avoid the deprecated controller method
2016-05-25 12:17:38 +01:00
Graham Campbell
d6495dec96 Avoid the deprecated controller method 2016-05-25 12:15:42 +01:00
Graham Campbell
5cbe3ba708 Back to dev 2016-05-25 11:39:32 +01:00
Graham Campbell
375d2330de Released 2.3.0 RC1 2016-05-25 11:39:07 +01:00
Graham Campbell
e39a3cde16 Merge pull request #1823 from CachetHQ/settings-cache
Refactored settings caching
2016-05-25 11:34:02 +01:00
Graham Campbell
13d0ff320a Another attempt 2016-05-25 11:28:03 +01:00
Graham Campbell
72577a04b7 Fixed headers 2016-05-25 11:23:48 +01:00
James Brooks
0bf2039e60 Fix some bits 2016-05-25 11:14:16 +01:00
Graham Campbell
414efb0ce7 Fixed typo 2016-05-25 10:59:11 +01:00
Graham Campbell
0500d63654 Merge pull request #1825 from CachetHQ/analysis-X017pj
Applied fixes from StyleCI

[ci skip]
2016-05-25 10:58:44 +01:00
Graham Campbell
3a86862e4f Applied fixes from StyleCI
[ci skip]
2016-05-25 05:58:40 -04:00
Graham Campbell
8df65b2dc3 Finished off the subscriber 2016-05-25 10:58:14 +01:00
Graham Campbell
c3bc8fdd2d Refactor settings caching 2016-05-25 10:55:49 +01:00
Graham Campbell
200cd62dc9 Resolve via class name 2016-05-25 10:55:33 +01:00
Graham Campbell
527e5872df Fixed typo 2016-05-25 10:55:22 +01:00
Graham Campbell
ebaf4e9395 WIP 2016-05-25 10:33:06 +01:00
Graham Campbell
d0afcbffe4 Updated dependencies (#1824) 2016-05-25 10:31:05 +01:00
Graham Campbell
2e9d56d053 Fixed typo 2016-05-25 09:55:07 +01:00
James Brooks
90419e70cf Merge pull request #1821 from CachetHQ/analysis-Xa67jZ
Applied fixes from StyleCI

[ci skip]
2016-05-25 09:52:48 +01:00
Graham Campbell
0566133c12 Cleaned up the release class and provider (#1820) 2016-05-25 09:52:44 +01:00
James Brooks
8e824eb5e0 Applied fixes from StyleCI
[ci skip]
2016-05-25 04:45:43 -04:00
James Brooks
5534cdbdde Sync languages 2016-05-25 09:45:20 +01:00
James Brooks
2db0b011e6 Rebuild assets 2016-05-25 09:28:02 +01:00
gellu
962b40f0e9 Fixed undefined component variable (#1808) 2016-05-24 20:04:47 +01:00
Graham Campbell
96450c476c Merge pull request #1811 from CachetHQ/subscribe-multiple-subscribers
Subscribe multiple subscribers at one time
2016-05-24 20:03:45 +01:00
James Brooks
ba09b3f7cd Merge pull request #1818 from CachetHQ/settings
Renamed "Config" to "Settings"
2016-05-24 18:35:23 +01:00
Graham Campbell
053e3e9477 Renamed "Config" to "Settings" 2016-05-24 17:48:13 +01:00
Graham Campbell
ff939e356e Merge pull request #1816 from CachetHQ/caching
Settings Caching
2016-05-24 17:43:15 +01:00
Graham Campbell
e4d5c53d69 Derp fix 2016-05-24 17:20:23 +01:00
Graham Campbell
4549c51959 Deal with cases when we have no settings properly 2016-05-24 17:12:08 +01:00
Graham Campbell
20e4ae5ff8 Scaled things back 2016-05-24 17:00:48 +01:00
Graham Campbell
77f455651d Work on config caching 2016-05-24 16:44:21 +01:00
Graham Campbell
7a3c231f68 Merge pull request #1812 from CachetHQ/fix-subscriber-dates
Fix subscriber dates
2016-05-24 15:13:04 +01:00
Graham Campbell
0ec77d7652 Merge pull request #1813 from CachetHQ/dashboard-component-status-bug
Fixes toggling of component status box
2016-05-24 15:12:47 +01:00
James Brooks
4f886e15ed Fixes toggling of component status box. Fixes #1792 2016-05-24 15:07:36 +01:00
James Brooks
d3454d8126 Merge pull request #1810 from CachetHQ/allow-user-level-editing
Edit the user level from edit user page
2016-05-24 14:57:42 +01:00
James Brooks
ccc0ebb7d5 Fixes #1805. Subscribers no longer have subscribed_at dates 2016-05-24 14:52:13 +01:00
James Brooks
f6bfb10500 Outdent the template 2016-05-24 14:49:09 +01:00
James Brooks
e241f38dd7 Subscribe multiple subscribers at one time 2016-05-24 14:47:34 +01:00
James Brooks
fb0dd82fe2 Edit the user level from edit user page. Closes #1809 2016-05-24 14:39:59 +01:00
James Brooks
6997e0c451 Merge pull request #1803 from CachetHQ/rename-next-prev
Use only Previous and Next links
2016-05-23 08:20:07 +01:00
James Brooks
2e73d071c9 Use only Previous and Next links. Closes #1801 2016-05-23 08:05:32 +01:00
Graham Campbell
f86f6bbc08 Merge pull request #1799 from CachetHQ/deps
Updated dependencies
2016-05-20 17:51:03 +01:00
Graham Campbell
6c872e60fc Updated dependencies 2016-05-20 17:40:31 +01:00
James Brooks
23f77a7e72 Merge pull request #1798 from CachetHQ/backup
Cleanup the backup process
2016-05-20 15:54:47 +01:00
Graham Campbell
25dd45f47c Cleanup the backup process 2016-05-20 14:49:41 +01:00
Graham Campbell
2680bafd69 Merge pull request #1797 from CachetHQ/specify-component-group-components-order
Order components within group
2016-05-20 14:38:47 +01:00
James Brooks
08c1f105c2 Order components within group. Fixes #1793 2016-05-20 14:31:08 +01:00
James Brooks
c152892610 Merge pull request #1796 from CachetHQ/jbrooksuk-patch-1
Remove Paypal button in favour of Patreon link
2016-05-20 14:03:10 +01:00
James Brooks
d54ead2868 Remove Paypal button in favour of Patreon link 2016-05-20 13:21:49 +01:00
James Brooks
81ae63b2c0 Merge pull request #1795 from vinkla/patch-2
Remove npm dependencies
2016-05-20 12:56:52 +01:00
Vincent Klaiber
9f17c34f50 Remove npm dependencies
This closes #1794
2016-05-20 13:48:39 +02:00
Graham Campbell
d0be61ad96 Updated dependencies 2016-05-13 00:27:00 +01:00
James Brooks
89f99ef663 Merge pull request #1781 from CachetHQ/drop-bower
Remove Bower dependency
2016-05-11 20:38:39 +01:00
James Brooks
9f4270f4a5 Remove Bower dependency. Closes #1780 2016-05-11 20:11:46 +01:00
James Brooks
bda3484cac Merge pull request #1777 from CachetHQ/values
Use pluck rather than lists
2016-05-09 22:04:05 +01:00
James Brooks
aec2ef0198 Use pluck rather than lists 2016-05-09 20:43:24 +01:00
Joe Cohen
651edcc7c5 Merge pull request #1754 from CachetHQ/fix-spanish-cachet-translations
Fix translations in the cachet.php file
2016-05-09 14:08:47 -05:00
James Brooks
d975cd8ca1 Fix spanish translations 2016-05-09 13:30:07 -05:00
James Brooks
c315d04d5d Merge pull request #1773 from CachetHQ/remove-setup-key-generate
Setup doesn't need to generate the key anymore
2016-05-08 17:47:08 +01:00
James Brooks
e77562d469 Setup doesn't need to generate the key anymore 2016-05-08 17:46:29 +01:00
James Brooks
088fd6631d Merge pull request #1771 from CachetHQ/subscribers-api-specify-components
Specify components to subscribe to via API
2016-05-08 16:54:45 +01:00
James Brooks
cc102847f9 Specify components to subscribe to via API. Closes #1685 2016-05-08 16:26:59 +01:00
James Brooks
b88a102629 Merge pull request #1768 from CachetHQ/default-settings
Allow us to set better default settings
2016-05-08 16:24:57 +01:00
James Brooks
452eb653a5 Allow us to set better default settings. Closes #1755 2016-05-08 16:06:11 +01:00
James Brooks
1584883f39 Merge pull request #1767 from TheoBearman/2.3
Moving 'Automatically localise your status page to your visitor's language?' to its correct home
2016-05-07 21:12:30 +01:00
Theo Bearman
595a720d8b Moving 'Automatically localise your status page to your visitor's language?' to its correct home - Fixes #1765 2016-05-07 17:24:58 +01:00
Graham Campbell
2a0decc7c6 Merge pull request #1763 from CachetHQ/composer
Updated packages
2016-05-07 09:27:10 +01:00
James Brooks
d10386821e Updated lockfile 2016-05-07 08:52:26 +01:00
Graham Campbell
8da8e83e48 Updated packages 2016-05-06 22:46:51 +01:00
Graham Campbell
80bb601813 Merge pull request #1732 from CachetHQ/database-backups
Database backups
2016-05-06 21:56:26 +01:00
James Brooks
21b60e0708 Take a backup before calling app commands. Closes #1730 2016-05-06 21:11:57 +01:00
Graham Campbell
0fd88a6ba7 Merge pull request #1761 from CachetHQ/cleanup-subscribers-component-deletions
When removing a component, clean up the subscriptions
2016-05-06 14:12:39 +01:00
Graham Campbell
8da7bde2a5 Merge pull request #1760 from CachetHQ/update-deps
Update dependencies
2016-05-06 14:11:59 +01:00
James Brooks
ceb119b226 When removing a component, clean up the subscriptions. Closes #1739 2016-05-06 13:54:00 +01:00
James Brooks
6790d85a87 Update dependencies 2016-05-06 13:46:46 +01:00
Graham Campbell
873f61fde6 Merge pull request #1759 from CachetHQ/powered-by-change
Change the powered by text
2016-05-06 13:00:54 +01:00
James Brooks
f716c7fd1d Change the powered by text. Closes #1758 2016-05-06 12:50:30 +01:00
James Brooks
50ac69b234 Merge pull request #1757 from CachetHQ/fix-pgsql-metrics
Fixes metrics repository in PGSQL
2016-05-05 18:13:59 +01:00
James Brooks
712b1078f2 Fixes metrics repository in PGSQL. Closes #1741 2016-05-05 17:59:30 +01:00
James Brooks
893e61e319 Merge pull request #1756 from CachetHQ/command-bus-db-transactions
Command bus DB transactions
2016-05-05 17:47:59 +01:00
James Brooks
bfd0ccd652 Commands now use db transactions. Fixes #1745 2016-05-05 16:47:41 +01:00
James Brooks
3feb93c074 Remove dump and die call 2016-05-05 16:46:37 +01:00
James Brooks
a5ce958b92 Merge pull request #1753 from CachetHQ/configure-automatic-localization
Allow configuring of automatic localization
2016-05-05 11:22:24 +01:00
James Brooks
47e1dff5c5 Allow configuring of automatic localization. Closes #1747 2016-05-05 10:50:14 +01:00
James Brooks
9ddf9e3e1a Merge pull request #1751 from CachetHQ/fix-component-group-api
Fix component group api
2016-05-05 10:49:44 +01:00
James Brooks
9747cb9204 Added missing docblock 2016-05-05 10:24:01 +01:00
James Brooks
bd35db8d87 Default collapsed value to 0 (always open) 2016-05-05 10:23:18 +01:00
James Brooks
23ff795809 Don't pass through default order value when updating group 2016-05-05 10:23:02 +01:00
Graham Campbell
48d2721605 Updated dependencies 2016-05-04 21:52:01 +01:00
Graham Campbell
9d78092121 Merge pull request #1750 from CachetHQ/fix-str
Fixed a bad import
2016-05-04 20:08:21 +01:00
Graham Campbell
a0b1501b2a Fixed a bad import 2016-05-04 16:38:09 +01:00
Graham Campbell
c4e724e0e6 Rebuilt assets 2016-05-01 16:24:16 +01:00
James Brooks
792a8f6a07 Bower has changed the rules in which a name must follow 2016-05-01 16:06:24 +01:00
Graham Campbell
684b480338 Merge pull request #1738 from CachetHQ/fix-subscribers
Fix subscribers
2016-05-01 16:05:41 +01:00
Joe Cohen
f1b61c7ef1 Applied fixes from StyleCI 2016-05-01 16:04:43 +01:00
Joseph Cohen
05bb91d2d9 Global subscribers and fix notifications 2016-05-01 16:04:43 +01:00
Joseph Cohen
5abd25c408 Redirect subscribers to manage 2016-05-01 16:04:43 +01:00
Graham Campbell
e1a8e2220d Merge branch '2.2' into 2.3
# Conflicts:
#	VERSION
#	public/build/dist/js/all-a62567215d.js
#	public/build/rev-manifest.json
2016-04-29 17:05:53 +01:00
Graham Campbell
df373e93ef Merge branch '2.2' into 2.3
# Conflicts:
#	composer.lock
2016-04-27 14:58:20 +01:00
Graham Campbell
28e7af7107 Merge pull request #1582 from CachetHQ/metric-point-enhancement
Refactoring metric point storage
2016-04-25 20:42:11 +01:00
James Brooks
f9bc46b460 Refactored the way we store metrics 2016-04-25 20:42:00 +01:00
James Brooks
3730ca8811 Rebuild assets 2016-04-25 16:03:48 +01:00
James Brooks
69716730ac Update dependencies 2016-04-25 16:03:40 +01:00
Graham Campbell
28bf01396c Merge branch '2.2'
# Conflicts:
#	VERSION
2016-04-23 11:04:10 +01:00
Graham Campbell
a9185b7876 Bumped version 2016-04-23 11:00:30 +01:00
622 changed files with 34049 additions and 5098 deletions

View File

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

View File

@@ -1,16 +1,8 @@
Before submitting your issue, please make sure that you've checked all of the checkboxes below.
Before submitting your issue, please make sure that you've checked the checkboxes below.
- [ ] You're running the [latest release](https://github.com/CachetHQ/Cachet/releases/latest) version of Cachet.
- [ ] Ensure that you're running at least PHP 5.5.9, you can check this by running `php -v`
- [ ] You've ran `rm -rf bootstrap/cache/*` from the root of your Cachet installation.
To help us better understand your issue, please answer the following — cheers!
### Your setup
- *What version of Cachet?*
- *What database driver? MySQL? Postgres? SQLite?*
- *What version of PHP?*
- [ ] I am running the [latest release](https://github.com/CachetHQ/Cachet/releases/latest) version of Cachet.
- [ ] I am running at least PHP 5.5.9. *You can check this by running `php -v`.*
- [ ] I have ran `rm -rf bootstrap/cache/*`.
### Expected behaviour
@@ -23,3 +15,6 @@ To help us better understand your issue, please answer the following — cheers!
### Steps to reproduce
*If your issue requires any specific steps to reproduce, please outline them here.*
1. First step
2. Second step

View File

@@ -1,21 +1,18 @@
language: php
sudo: false
dist: trusty
php:
- 5.5.9
- 5.5
- 5.6
- 7.0
- hhvm
- 7.1
sudo: false
before_install: cp .env.example .env
install:
- travis_retry composer install --no-interaction --no-scripts --prefer-source
install: travis_retry composer install --no-interaction --no-scripts --prefer-source
script:
- if [ "$TRAVIS_PHP_VERSION" != "5.6" ] || [ "$TRAVIS_PULL_REQUEST" != false ]; then vendor/bin/phpunit; fi
- if [ "$TRAVIS_PHP_VERSION" == "5.6" ] && [ "$TRAVIS_PULL_REQUEST" == false ]; then vendor/bin/phpunit --coverage-clover build/logs/clover.xml; fi
after_script:
- if [ "$TRAVIS_PHP_VERSION" == "5.6" ] && [ "$TRAVIS_PULL_REQUEST" == false ]; then wget https://scrutinizer-ci.com/ocular.phar; fi
- if [ "$TRAVIS_PHP_VERSION" == "5.6" ] && [ "$TRAVIS_PULL_REQUEST" == false ]; then php ocular.phar code-coverage:upload --format=php-clover build/logs/clover.xml; fi
script: vendor/bin/phpunit

View File

@@ -1,15 +1,14 @@
# Cachet
[![StyleCI](https://styleci.io/repos/26730195/shield)](https://styleci.io/repos/26730195/)
[![Build Status](https://img.shields.io/travis/CachetHQ/Cachet/master.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)
[![Build Status](https://img.shields.io/travis/CachetHQ/Cachet/2.3.svg?style=flat-square)](https://travis-ci.org/CachetHQ/Cachet)
[![Software License](https://img.shields.io/badge/license-BSD3-brightgreen.svg?style=flat-square)](LICENSE)
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/cachet/localized.png)](http://translate.cachethq.io/project/cachet)
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/cachet/localized.svg)](http://translate.cachethq.io/project/cachet)
[![Packagist](https://img.shields.io/packagist/v/cachethq/cachet.svg?style=flat-square)](https://packagist.org/packages/cachethq/cachet)
![Screenshot](https://cachethq.io/img/main-interface.jpg)
Cachet is a beautiful and powerful open source status page system, a free replacement to services such as StatusPage.io, Status.io and others.
Cachet is a beautiful and powerful open source status page system.
## Features
@@ -22,27 +21,23 @@ Cachet is a beautiful and powerful open source status page system, a free replac
- Metrics
- Cross-database support: MySQL, PostgreSQL and SQLite
- Subscriber notifications via Email
- Two factor authentication, with Google Authenticator
## Usage in production
The `master` branch of this repository is a development branch and **should not** be used in production. Instead, please check out the latest tag release.
- Two factor authentication using Google Authenticator
## Requirements
- PHP 5.5.9+ or newer
- PHP 5.5.9 - 7.1
- Apache or Nginx server
- [Composer](https://getcomposer.org)
## How to contribute
## I'm looking to contribute to this awesome project!
We're always looking for contributions that improve Cachet. It's easy to get started and you don't even need to know how to write a single line of code!
Sweet, we're always looking for contributions that improve Cachet! It's easy to get started and you don't even need to know how to write a single line of code!
### Contributing as a non-developer/non-designer
If you're one of the more linguistically talented people in the world who can speak and write more than just English, we're always looking for new [translations](#translations).
We're always looking for new [translations](#translations).
Of course bug reports, feature requests and [documentation](https://docs.cachethq.io) are always being sought after.
Of course bug reports, feature requests and [documentation](https://docs.cachethq.io) are always appreciated.
### Contributing as a designer
@@ -52,65 +47,60 @@ You'll need to install Node.js, Bower and Gulp.
To get started you can do the following:
1. Install Node.js, Bower and Gulp.
2. Install the assets; `bower install`
3. Modify the SCSS files in `./resources/assets/sass/`
4. Run `gulp`
1. Install Node.js and our dev dependencies.
2. Make your changes to the SCSS files in `./resources/assets/sass/`
3. Run `gulp`
If you're making a lot of changes, you'll find that running `gulp watch` will really help you out!
If you're making a lot of changes, you'll find that running `gulp watch` will make life easier for you!
### Contributing as a developer
Built using [Laravel](https://laravel.com), Cachet is very easy to jump into. Have a look around you'll find it surprisingly easy!
Built using [Laravel](https://laravel.com).
These extra dependencies are required to develop Cachet:
We use these extra dependencies to develop Cachet:
- Node.js
- Bower
- Gulp
- Git
Once cloned to your local machine, you'll need some demo data! Simply run `php artisan cachet:seed` to get the demo installation on the go.
Once cloned to your local machine, you'll need some demo data! Run `php artisan cachet:seed` to get the demo installation ready for action.
## Installation, Upgrades and Documentation
You can now find our documentation at [https://docs.cachethq.io](https://docs.cachethq.io).
Documentation is found at [https://docs.cachethq.io](https://docs.cachethq.io).
Here are some useful quick links:
- [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)
### Demo Account
To test out the demo, you may login to the [Dashboard](https://demo.cachethq.io/dashboard) with the following:
- **Username:** test or test@test.com
- **Password:** test123
- **Username:** `test` or `test@test.com`
- **Password:** `test123`
The demo is reset every half hour.
### Release Notes
All releases are listed on the [Releases page](https://github.com/CachetHQ/Cachet/releases) of the [Cachet GitHub repository](https://github.com/CachetHQ/Cachet). On the Releases page, you can also find the release notes for each release.
We list releases on the [Releases page](https://github.com/CachetHQ/Cachet/releases) of the [Cachet GitHub repository](https://github.com/CachetHQ/Cachet). On the Releases page, you can also find the release notes for each release.
## Translations
A special thank you to our [translators](https://crowdin.com/project/cachet/activity_stream), who have allowed us to share Cachet with the world. If you'd like to contribute translations, please check out our [CrowdIn project](https://crowdin.com/project/cachet).
If you'd like to contribute translations, please check out our [CrowdIn project](https://crowdin.com/project/cachet).
> Thank you to our [translators](https://crowdin.com/project/cachet/activity_stream), who have allowed us to share Cachet with the world!
## Show your support
Cachet is a BSD-3-licensed open source project.
## Professional Installation Service
We offer a professional installation service. To find out more, email us at [support@alt-three.com](mailto:support@alt-three.com?Cachet Installation)
## Security Vulnerabilities
If you discover a security vulnerability within Cachet, please send an e-mail to us at support@alt-three.com. All security vulnerabilities will be promptly addressed.
## Installations
We offer a paid installation service, which starts at $99 but is subject to change, dependant on your setup and infrastructure.
To find out more, email us at support@alt-three.com
## Donations
Cachet is open source, we don't have any licensing models and don't run ads on the [website](https://cachethq.io).
If you'd like to donate towards further development of Cachet you can do so via Paypal.
[![Donate](https://www.paypalobjects.com/en_GB/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=D4M5LVULVPPKL)
If you discover a security vulnerability within Cachet, please send an e-mail to us at support@alt-three.com. We handle all security vulnerabilities on a case-by-case basis.

View File

@@ -1 +1 @@
2.2.5-dev
2.3.19-dev

View File

@@ -69,6 +69,20 @@ final class AddMetricCommand
*/
public $default_view;
/**
* The threshold to buffer the metric points in.
*
* @var int
*/
public $threshold;
/**
* The order of which to place the metric in.
*
* @var int
*/
public $order;
/**
* The validation rules.
*
@@ -84,6 +98,8 @@ final class AddMetricCommand
'display_chart' => 'int',
'places' => 'int|between:0,4',
'default_view' => 'int|between:0,3',
'threshold' => 'numeric|between:0,10',
'order' => 'int',
];
/**
@@ -97,10 +113,12 @@ final class AddMetricCommand
* @param int $display_chart
* @param int $places
* @param int $default_view
* @param int $threshold
* @param int $order
*
* @return void
*/
public function __construct($name, $suffix, $description, $default_value, $calc_type, $display_chart, $places, $default_view)
public function __construct($name, $suffix, $description, $default_value, $calc_type, $display_chart, $places, $default_view, $threshold, $order = 0)
{
$this->name = $name;
$this->suffix = $suffix;
@@ -110,5 +128,7 @@ final class AddMetricCommand
$this->display_chart = $display_chart;
$this->places = $places;
$this->default_view = $default_view;
$this->threshold = $threshold;
$this->order = $order;
}
}

View File

@@ -42,7 +42,7 @@ final class AddMetricPointCommand
* @var string[]
*/
public $rules = [
'value' => 'int',
'value' => 'numeric',
'created_at' => 'string',
];

View File

@@ -78,6 +78,20 @@ final class UpdateMetricCommand
*/
public $default_view;
/**
* The threshold to buffer the metric points in.
*
* @var int
*/
public $threshold;
/**
* The order of which to place the metric in.
*
* @var int|null
*/
public $order;
/**
* The validation rules.
*
@@ -93,6 +107,8 @@ final class UpdateMetricCommand
'display_chart' => 'int',
'places' => 'numeric|between:0,4',
'default_view' => 'numeric|between:0,4',
'threshold' => 'numeric|between:0,10',
'order' => 'int',
];
/**
@@ -107,10 +123,12 @@ final class UpdateMetricCommand
* @param int $display_chart
* @param int $places
* @param int $default_view
* @param int $threshold
* @param int|null $order
*
* @return void
*/
public function __construct(Metric $metric, $name, $suffix, $description, $default_value, $calc_type, $display_chart, $places, $default_view)
public function __construct(Metric $metric, $name, $suffix, $description, $default_value, $calc_type, $display_chart, $places, $default_view, $threshold, $order = null)
{
$this->metric = $metric;
$this->name = $name;
@@ -121,5 +139,7 @@ final class UpdateMetricCommand
$this->display_chart = $display_chart;
$this->places = $places;
$this->default_view = $default_view;
$this->threshold = $threshold;
$this->order = $order;
}
}

View File

@@ -14,6 +14,11 @@ namespace CachetHQ\Cachet\Bus\Commands\Metric;
use CachetHQ\Cachet\Models\Metric;
use CachetHQ\Cachet\Models\MetricPoint;
/**
* This is the update metric point command.
*
* @author James Brooks <james@alt-three.com>
*/
final class UpdateMetricPointCommand
{
/**
@@ -33,7 +38,7 @@ final class UpdateMetricPointCommand
/**
* The metric point value.
*
* @var int
* @var float
*/
public $value;
@@ -50,7 +55,7 @@ final class UpdateMetricPointCommand
* @var string[]
*/
public $rules = [
'value' => 'int',
'value' => 'numeric',
'created_at' => 'string',
];
@@ -59,7 +64,7 @@ final class UpdateMetricPointCommand
*
* @param \CachetHQ\Cachet\Models\MetricPoint $point
* @param \CachetHQ\Cachet\Models\Metric $metric
* @param int $value
* @param float $value
* @param string $created_at
*
* @return void

View File

@@ -33,7 +33,7 @@ final class SubscribeSubscriberCommand
public $verified;
/**
* The subscriptions that we want to add.
* The list of subscriptions to set the subscriber up with.
*
* @var array|null
*/
@@ -53,7 +53,7 @@ final class SubscribeSubscriberCommand
*
* @param string $email
* @param bool $verified
* @param null|array $subscriptions
* @param array|null $subscriptions
*
* @return void
*/

View File

@@ -0,0 +1,50 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Bus\Commands\Subscriber;
use CachetHQ\Cachet\Models\Subscriber;
/**
* This is the subscribe subscriber command.
*
* @author Joseph Cohen <joe@alt-three.com>
*/
final class UpdateSubscriberSubscriptionCommand
{
/**
* The subscriber email.
*
* @var \CachetHQ\Cachet\Models\Subscriber
*/
public $subscriber;
/**
* The subscriptions that we want to add.
*
* @var array|null
*/
public $subscriptions;
/**
* Create a new subscribe subscriber command instance.
*
* @param \CachetHQ\Cachet\Models\Subscriber $subscriber
* @param null|array $subscriptions
*
* @return void
*/
public function __construct($subscriber, $subscriptions = null)
{
$this->subscriber = $subscriber;
$this->subscriptions = $subscriptions;
}
}

View File

@@ -1,26 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Bus\Exceptions\Subscriber;
use CachetHQ\Cachet\Bus\Exceptions\ExceptionInterface;
use Exception;
/**
* This is the already subscribed exception class.
*
* @author Graham Campbell <graham@alt-three.com>
* @author James Brooks <james@alt-three.com>
*/
class AlreadySubscribedException extends Exception implements ExceptionInterface
{
//
}

View File

@@ -70,7 +70,7 @@ class ReportIncidentCommandHandler
'visible' => $command->visible,
];
if ($command->template) {
if (IncidentTemplate::where('slug', '=', $command->template)->first()) {
$data['message'] = $this->parseIncidentTemplate($command->template, $command->template_vars);
} else {
$data['message'] = $command->message;

View File

@@ -35,6 +35,8 @@ class AddMetricCommandHandler
'display_chart' => $command->display_chart,
'places' => $command->places,
'default_view' => $command->default_view,
'threshold' => $command->threshold,
'order' => $command->order,
]);
event(new MetricWasAddedEvent($metric));

View File

@@ -15,6 +15,7 @@ use CachetHQ\Cachet\Bus\Commands\Metric\AddMetricPointCommand;
use CachetHQ\Cachet\Bus\Events\Metric\MetricPointWasAddedEvent;
use CachetHQ\Cachet\Dates\DateFactory;
use CachetHQ\Cachet\Models\MetricPoint;
use Carbon\Carbon;
class AddMetricPointCommandHandler
{
@@ -49,19 +50,35 @@ class AddMetricPointCommandHandler
$metric = $command->metric;
$createdAt = $command->created_at;
$data = [
'metric_id' => $metric->id,
'value' => $command->value,
];
// Do we have an existing point with the same value?
$point = $this->findOrCreatePoint($command);
if ($createdAt) {
$data['created_at'] = $this->dates->create('U', $createdAt)->format('Y-m-d H:i:s');
$point->increment('counter', 1);
event(new MetricPointWasAddedEvent($point));
return $point;
}
protected function findOrCreatePoint(AddMetricPointCommand $command)
{
$buffer = Carbon::now()->subMinutes($command->metric->threshold);
$point = MetricPoint::where('metric_id', $command->metric->id)->where('value', $command->value)->where('created_at', '>=', $buffer)->first();
if ($point) {
return $point;
}
$metricPoint = MetricPoint::create($data);
$data = [
'metric_id' => $command->metric->id,
'value' => $command->value,
'counter' => 0,
];
event(new MetricPointWasAddedEvent($metricPoint));
if ($command->created_at) {
$data['created_at'] = $this->dates->create('U', $command->created_at)->format('Y-m-d H:i:s');
}
return $metricPoint;
return MetricPoint::create($data);
}
}

View File

@@ -53,6 +53,8 @@ class UpdateMetricCommandHandler
'display_chart' => $command->display_chart,
'places' => $command->places,
'default_view' => $command->default_view,
'threshold' => $command->threshold,
'order' => $command->order,
];
return array_filter($params, function ($val) {

View File

@@ -51,7 +51,7 @@ class UpdateMetricPointCommandHandler
$data = [
'metric_id' => $metric->id,
'value' => $command->value,
'value' => (float) $command->value,
];
if ($createdAt) {

View File

@@ -14,8 +14,7 @@ namespace CachetHQ\Cachet\Bus\Handlers\Commands\Subscriber;
use CachetHQ\Cachet\Bus\Commands\Subscriber\SubscribeSubscriberCommand;
use CachetHQ\Cachet\Bus\Commands\Subscriber\VerifySubscriberCommand;
use CachetHQ\Cachet\Bus\Events\Subscriber\SubscriberHasSubscribedEvent;
use CachetHQ\Cachet\Bus\Events\Subscriber\SubscriberHasUpdatedSubscriptionsEvent;
use CachetHQ\Cachet\Bus\Exceptions\Subscriber\AlreadySubscribedException;
use CachetHQ\Cachet\Models\Component;
use CachetHQ\Cachet\Models\Subscriber;
use CachetHQ\Cachet\Models\Subscription;
@@ -23,6 +22,8 @@ use CachetHQ\Cachet\Models\Subscription;
* This is the subscribe subscriber command handler.
*
* @author James Brooks <james@alt-three.com>
* @author Joe Cohen <joe@alt-three.com>
* @author Graham Campbell <graham@alt-three.com>
*/
class SubscribeSubscriberCommandHandler
{
@@ -31,37 +32,38 @@ class SubscribeSubscriberCommandHandler
*
* @param \CachetHQ\Cachet\Bus\Commands\Subscriber\SubscribeSubscriberCommand $command
*
* @throws \CachetHQ\Cachet\Exceptions\AlreadySubscribedException
*
* @return \CachetHQ\Cachet\Models\Subscriber
*/
public function handle(SubscribeSubscriberCommand $command)
{
if (Subscriber::where('email', $command->email)->first() && $command->subscriptions === null) {
throw new AlreadySubscribedException("Cannot subscribe {$command->email} because they're already subscribed.");
if ($subscriber = Subscriber::where('email', $command->email)->first()) {
return $subscriber;
}
$subscriber = Subscriber::firstOrCreate(['email' => $command->email]);
// Decide what to subscribe the subscriber to.
if ($subscriptions = $command->subscriptions) {
foreach ($subscriptions as $subscription => $subscriptionValue) {
Subscription::firstOrCreate([
'subscriber_id' => $subscriber->id,
$subscription => $subscriptionValue,
]);
}
$components = Component::whereIn('id', $subscriptions)->get();
} else {
$components = Component::all();
}
if ($subscriber->is_verified === false) {
if ($command->verified) {
dispatch(new VerifySubscriberCommand($subscriber));
} else {
event(new SubscriberHasSubscribedEvent($subscriber));
}
$components->map(function ($component) use ($subscriber) {
Subscription::create([
'subscriber_id' => $subscriber->id,
'component_id' => $component->id,
]);
});
if ($command->verified) {
dispatch(new VerifySubscriberCommand($subscriber));
} else {
event(new SubscriberHasUpdatedSubscriptionsEvent($subscriber));
event(new SubscriberHasSubscribedEvent($subscriber));
}
$subscriber->load('subscriptions');
return $subscriber;
}
}

View File

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

View File

@@ -0,0 +1,64 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Bus\Handlers\Commands\Subscriber;
use CachetHQ\Cachet\Bus\Commands\Subscriber\UpdateSubscriberSubscriptionCommand;
use CachetHQ\Cachet\Bus\Events\Subscriber\SubscriberHasUpdatedSubscriptionsEvent;
use CachetHQ\Cachet\Models\Component;
use CachetHQ\Cachet\Models\Subscriber;
use CachetHQ\Cachet\Models\Subscription;
/**
* This is the subscribe subscriber command handler.
*
* @author Joseph Cohen <joe@alt-three.com>
*/
class UpdateSubscriberSubscriptionCommandHandler
{
/**
* Handle the subscribe subscriber command.
*
* @param \CachetHQ\Cachet\Bus\Commands\Subscriber\UpdateSubscriberSubscriptionCommand $command
*
* @return \CachetHQ\Cachet\Models\Subscriber
*/
public function handle(UpdateSubscriberSubscriptionCommand $command)
{
$subscriber = $command->subscriber;
$subscriptions = $command->subscriptions ?: [];
$components = Component::all();
$updateSubscriptions = $components->filter(function ($item) use ($subscriptions) {
return in_array($item->id, $subscriptions);
});
$subscriber->global = ($updateSubscriptions->count() === $components->count());
$subscriber->subscriptions()->delete();
if (!$updateSubscriptions->isEmpty()) {
foreach ($updateSubscriptions as $subscription) {
Subscription::firstOrCreate([
'subscriber_id' => $subscriber->id,
'component_id' => $subscription->id,
]);
}
}
$subscriber->save();
event(new SubscriberHasUpdatedSubscriptionsEvent($subscriber));
return $subscriber;
}
}

View File

@@ -0,0 +1,40 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Bus\Handlers\Events\Component;
use CachetHQ\Cachet\Bus\Events\Component\ComponentWasRemovedEvent;
use CachetHQ\Cachet\Models\Component;
use CachetHQ\Cachet\Models\Subscription;
/**
* This is the cleanup component subscriptions handler.
*
* @author James Brooks <james@alt-three.com>
*/
class CleanupComponentSubscriptionsHandler
{
/**
* Handle the event.
*
* @param \CachetHQ\Cachet\Bus\Events\Component\ComponentWasRemovedEvent $event
*
* @return void
*/
public function handle(ComponentWasRemovedEvent $event)
{
$component = $event->component;
$subscription = Subscription::forComponent($component->id);
// Cleanup the subscriptions.
$subscription->delete();
}
}

View File

@@ -13,7 +13,7 @@ namespace CachetHQ\Cachet\Bus\Handlers\Events\Component;
use CachetHQ\Cachet\Bus\Events\Component\ComponentWasUpdatedEvent;
use CachetHQ\Cachet\Models\Component;
use CachetHQ\Cachet\Models\Subscription;
use CachetHQ\Cachet\Models\Subscriber;
use Illuminate\Contracts\Mail\MailQueue;
use Illuminate\Mail\Message;
use McCool\LaravelAutoPresenter\Facades\AutoPresenter;
@@ -27,16 +27,25 @@ class SendComponentUpdateEmailNotificationHandler
*/
protected $mailer;
/**
* The subscriber instance.
*
* @var \CachetHQ\Cachet\Models\Subscriber
*/
protected $subscriber;
/**
* Create a new send incident email notification handler.
*
* @param \Illuminate\Contracts\Mail\Mailer $mailer
* @param \Illuminate\Contracts\Mail\Mailer $mailer
* @param \CachetHQ\Cachet\Models\Subscriber $subscriber
*
* @return void
*/
public function __construct(MailQueue $mailer)
public function __construct(MailQueue $mailer, Subscriber $subscriber)
{
$this->mailer = $mailer;
$this->subscriber = $subscriber;
}
/**
@@ -48,7 +57,42 @@ class SendComponentUpdateEmailNotificationHandler
*/
public function handle(ComponentWasUpdatedEvent $event)
{
$component = AutoPresenter::decorate($event->component);
$component = $event->component;
// First notify all global subscribers.
$globalSubscribers = $this->subscriber->isVerified()->isGlobal()->get();
foreach ($globalSubscribers as $subscriber) {
$this->notify($component, $subscriber);
}
$notified = $globalSubscribers->pluck('id')->all();
// Notify the remaining component specific subscribers.
$componentSubscribers = $this->subscriber
->isVerified()
->forComponent($component->id)
->get()
->reject(function ($subscriber) use ($notified) {
return in_array($subscriber->id, $notified);
});
foreach ($componentSubscribers as $subscriber) {
$this->notify($component, $subscriber);
}
}
/**
* Send notification to subscriber.
*
* @param \CachetHQ\Cachet\Models\Component $component
* @param \CachetHQ\Cachet\Models\Subscriber $subscriber
*
* @return \Illuminate\Database\Eloquent\Collection
*/
public function notify(Component $component, Subscriber $subscriber)
{
$component = AutoPresenter::decorate($component);
$mail = [
'subject' => trans('cachet.subscriber.email.component.subject'),
@@ -56,18 +100,14 @@ class SendComponentUpdateEmailNotificationHandler
'component_human_status' => $component->human_status,
];
foreach (Subscription::isVerifiedForComponent($component->id)->with('subscriber')->get() as $subscription) {
$subscriber = $subscription->subscriber;
$mail['email'] = $subscriber->email;
$mail['manage_link'] = route('subscribe.manage', ['code' => $subscriber->verify_code]);
$mail['unsubscribe_link'] = route('subscribe.unsubscribe', ['code' => $subscriber->verify_code, 'subscription' => $subscription->id]);
$mail['email'] = $subscriber->email;
$mail['manage_link'] = route('subscribe.manage', ['code' => $subscriber->verify_code]);
$this->mailer->queue([
'html' => 'emails.components.update-html',
'text' => 'emails.components.update-text',
], $mail, function (Message $message) use ($mail) {
$message->to($mail['email'])->subject($mail['subject']);
});
}
$this->mailer->queue([
'html' => 'emails.components.update-html',
'text' => 'emails.components.update-text',
], $mail, function (Message $message) use ($mail) {
$message->to($mail['email'])->subject($mail['subject']);
});
}
}

View File

@@ -50,7 +50,7 @@ class SendIncidentEmailNotificationHandler
/**
* Handle the event.
*
* @param \CachetHQ\Cachet\Bus\Events\Incident\IncidentHasReportedEvent $event
* @param \CachetHQ\Cachet\Bus\Events\Incident\IncidentWasReportedEvent $event
*
* @return void
*/
@@ -60,32 +60,74 @@ class SendIncidentEmailNotificationHandler
return false;
}
// Only send emails for public incidents.
if ($event->incident->visible === 0) {
return;
}
// First notify all global subscribers.
$globalSubscribers = $this->subscriber->isVerified()->isGlobal()->get();
foreach ($globalSubscribers as $subscriber) {
$this->notify($event, $subscriber);
}
if (!$event->incident->component) {
return;
}
$notified = $globalSubscribers->pluck('id')->all();
// Notify the remaining component specific subscribers.
$componentSubscribers = $this->subscriber
->isVerified()
->forComponent($event->incident->component->id)
->get()
->reject(function ($subscriber) use ($notified) {
return in_array($subscriber->id, $notified);
});
foreach ($componentSubscribers as $subscriber) {
$this->notify($event, $subscriber);
}
}
/**
* Send notification to subscriber.
*
* @param \CachetHQ\Cachet\Bus\Events\IncidentWasReportedEvent $event
* @param \CachetHQ\Cachet\Models\Subscriber $subscriber
*
* @return \Illuminate\Database\Eloquent\Collection
*/
public function notify(IncidentWasReportedEvent $event, $subscriber)
{
$incident = AutoPresenter::decorate($event->incident);
$component = AutoPresenter::decorate($event->incident->component);
// Only send emails for public incidents.
if ($event->incident->visible === 1) {
foreach ($this->subscriber->isVerified()->get() as $subscriber) {
$mail = [
'email' => $subscriber->email,
'subject' => 'New incident reported.',
'has_component' => ($event->incident->component) ? true : false,
'component_name' => $component ? $component->name : null,
'status' => $incident->human_status,
'html_content' => $incident->formattedMessage,
'text_content' => $incident->message,
'token' => $subscriber->token,
'manage_link' => route('subscribe.manage', ['code' => $subscriber->verify_code]),
'unsubscribe_link' => route('subscribe.unsubscribe', ['code' => $subscriber->verify_code]),
];
$mail = [
'email' => $subscriber->email,
'subject' => trans('cachet.subscriber.email.incident.subject', [
'status' => $incident->human_status,
'name' => $incident->name,
]),
'has_component' => ($event->incident->component) ? true : false,
'component_name' => $component ? $component->name : null,
'name' => $incident->name,
'timestamp' => $incident->created_at_formatted,
'status' => $incident->human_status,
'html_content' => $incident->formattedMessage,
'text_content' => $incident->message,
'token' => $subscriber->token,
'manage_link' => route('subscribe.manage', ['code' => $subscriber->verify_code]),
'unsubscribe_link' => route('subscribe.unsubscribe', ['code' => $subscriber->verify_code]),
];
$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']);
});
}
}
$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

@@ -50,7 +50,7 @@ class SendMaintenanceEmailNotificationHandler
/**
* Handle the event.
*
* @param \CachetHQ\Cachet\Bus\Events\MaintenanceHasScheduledEvent $event
* @param \CachetHQ\Cachet\Bus\Events\MaintenanceWasScheduledEvent $event
*
* @return void
*/
@@ -60,27 +60,73 @@ class SendMaintenanceEmailNotificationHandler
return false;
}
$data = AutoPresenter::decorate($event->incident);
// Only send emails for public incidents.
if ($event->incident->visible === 0) {
return;
}
foreach ($this->subscriber->isVerified()->get() as $subscriber) {
$mail = [
'email' => $subscriber->email,
'subject' => 'Scheduled maintenance.',
'status' => $data->human_status,
'html_content' => $data->formattedMessage,
'text_content' => $data->message,
'scheduled_at' => $data->scheduled_at_formatted,
'token' => $subscriber->token,
'manage_link' => route('subscribe.manage', ['code' => $subscriber->verify_code]),
'unsubscribe_link' => route('subscribe.unsubscribe', ['code' => $subscriber->verify_code]),
];
// First notify all global subscribers.
$globalSubscribers = $this->subscriber->isVerified()->isGlobal()->get();
$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']);
foreach ($globalSubscribers as $subscriber) {
$this->notify($event, $subscriber);
}
if (!$event->incident->component) {
return;
}
$notified = $globalSubscribers->pluck('id')->all();
// Notify the remaining component specific subscribers.
$componentSubscribers = $this->subscriber
->isVerified()
->forComponent($event->incident->component->id)
->get()
->reject(function ($subscriber) use ($notified) {
return in_array($subscriber->id, $notified);
});
foreach ($componentSubscribers as $subscriber) {
$this->notify($event, $subscriber);
}
}
/**
* Send notification to subscriber.
*
* @param \CachetHQ\Cachet\Bus\Events\MaintenanceWasScheduledEvent $event
* @param \CachetHQ\Cachet\Models\Subscriber $subscriber
*
* @return \Illuminate\Database\Eloquent\Collection
*/
public function notify(MaintenanceWasScheduledEvent $event, $subscriber)
{
$incident = AutoPresenter::decorate($event->incident);
$component = AutoPresenter::decorate($event->incident->component);
$mail = [
'email' => $subscriber->email,
'subject' => trans('cachet.subscriber.email.maintenance.subject', [
'name' => $incident->name,
]),
'has_component' => ($event->incident->component) ? true : false,
'component_name' => $component ? $component->name : null,
'name' => $incident->name,
'timestamp' => $incident->scheduled_at_formatted,
'status' => $incident->human_status,
'html_content' => $incident->formattedMessage,
'text_content' => $incident->message,
'token' => $subscriber->token,
'manage_link' => route('subscribe.manage', ['code' => $subscriber->verify_code]),
'unsubscribe_link' => route('subscribe.unsubscribe', ['code' => $subscriber->verify_code]),
];
$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

@@ -46,9 +46,9 @@ class SendSubscriberVerificationEmailHandler
public function handle(SubscriberHasSubscribedEvent $event)
{
$mail = [
'email' => $event->subscriber->email,
'subject' => 'Confirm your subscription.',
'link' => route('subscribe.verify', ['code' => $event->subscriber->verify_code]),
'email' => $event->subscriber->email,
'subject' => 'Confirm your subscription.',
'link' => route('subscribe.verify', ['code' => $event->subscriber->verify_code]),
];
$this->mailer->queue([

View File

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

View File

@@ -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\Bus\Middleware;
use Closure;
use Illuminate\Support\Facades\DB;
/**
* This is the use database transactions bus middleware class.
*
* @author James Brooks <james@alt-three.com>
*/
class UseDatabaseTransactions
{
/**
* Handle the current command in the pipeline.
*
* @param mixed $command
* @param \Closure $next
*
* @return bool
*/
public function handle($command, Closure $next)
{
return DB::transaction(function () use ($command, $next) {
return $next($command);
});
}
}

View File

@@ -41,16 +41,10 @@ class AppComposer
$view->withAppUrl(Config::get('app.url'));
$view->withAppHeader(Config::get('setting.header'));
$view->withAppFooter(Config::get('setting.footer'));
$view->withAppName($name = Config::get('setting.app_name'));
$view->withAppName(Config::get('setting.app_name'));
$view->withShowSupport($support = Config::get('setting.show_support'));
if ($support) {
$view->withSiteTitle(Config::get('setting.app_name').' | Cachet');
} else {
$view->withSiteTitle(Config::get('setting.app_name'));
}
$view->withAutomaticLocalization(Config::get('setting.automatic_localization'));
$view->withSiteTitle(Config::get('setting.app_name'));
$view->withFontSubset(Config::get('langs.'.Config::get('app.locale').'.subset', 'latin'));
}
}

View File

@@ -30,7 +30,7 @@ class DashboardComposer
{
$view->withIncidentCount(Incident::notScheduled()->count());
$view->withIncidentTemplateCount(IncidentTemplate::count());
$view->withComponentCount(Component::all()->count());
$view->withComponentCount(Component::count());
$view->withSubscriberCount(Subscriber::isVerified()->count());
}
}

View File

@@ -28,7 +28,7 @@ class MetricsComposer
{
$metrics = null;
if ($displayMetrics = Config::get('setting.display_graphs')) {
$metrics = Metric::where('display_chart', 1)->orderBy('id')->get();
$metrics = Metric::displayable()->orderBy('order')->orderBy('id')->get();
}
$view->withDisplayMetrics($displayMetrics)

View File

@@ -11,13 +11,38 @@
namespace CachetHQ\Cachet\Composers;
use CachetHQ\Cachet\Integrations\Core\System;
use CachetHQ\Cachet\Models\Component;
use CachetHQ\Cachet\Models\ComponentGroup;
use CachetHQ\Cachet\Models\Incident;
use Illuminate\Contracts\View\View;
/**
* This is the status page composer.
*
* @author James Brooks <james@alt-three.com>
*/
class StatusPageComposer
{
/**
* The system instance.
*
* @var \CachetHQ\Cachet\Integrations\Contracts\System
*/
protected $system;
/**
* Create a new status page composer instance.
*
* @param \CachetHQ\Cachet\Integrations\Contracts\System $system
*
* @return void
*/
public function __construct(System $system)
{
$this->system = $system;
}
/**
* Index page view composer.
*
@@ -27,40 +52,7 @@ class StatusPageComposer
*/
public function compose(View $view)
{
$totalComponents = Component::enabled()->count();
$majorOutages = Component::enabled()->status(4)->count();
$isMajorOutage = $totalComponents ? ($majorOutages / $totalComponents) >= 0.5 : false;
// Default data
$withData = [
'system_status' => 'info',
'system_message' => trans_choice('cachet.service.bad', $totalComponents),
'favicon' => 'favicon-high-alert',
];
if ($isMajorOutage) {
$withData = [
'system_status' => 'danger',
'system_message' => trans_choice('cachet.service.major', $totalComponents),
'favicon' => 'favicon-high-alert',
];
} elseif (Component::enabled()->notStatus(1)->count() === 0) {
// If all our components are ok, do we have any non-fixed incidents?
$incidents = Incident::notScheduled()->orderBy('created_at', 'desc')->get();
$incidentCount = $incidents->count();
if ($incidentCount === 0 || ($incidentCount >= 1 && (int) $incidents->first()->status === 4)) {
$withData = [
'system_status' => 'success',
'system_message' => trans_choice('cachet.service.good', $totalComponents),
'favicon' => 'favicon',
];
}
} else {
if (Component::enabled()->whereIn('status', [2, 3])->count() > 0) {
$withData['favicon'] = 'favicon-medium-alert';
}
}
$status = $this->system->getStatus();
// Scheduled maintenance code.
$scheduledMaintenance = Incident::scheduled()->orderBy('scheduled_at')->get();
@@ -70,7 +62,7 @@ class StatusPageComposer
$componentGroups = ComponentGroup::whereIn('id', $usedComponentGroups)->orderBy('order')->get();
$ungroupedComponents = Component::enabled()->where('group_id', 0)->orderBy('order')->orderBy('created_at')->get();
$view->with($withData)
$view->with($status)
->withComponentGroups($componentGroups)
->withUngroupedComponents($ungroupedComponents)
->withScheduledMaintenance($scheduledMaintenance);

View File

@@ -14,6 +14,7 @@ namespace CachetHQ\Cachet\Composers;
use DateTime;
use DateTimeZone;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Config;
class TimezoneLocaleComposer
@@ -32,7 +33,7 @@ class TimezoneLocaleComposer
$langs = array_map(function ($lang) use ($enabledLangs) {
$locale = basename($lang);
return [$locale => $enabledLangs[$locale]];
return [$locale => Arr::get($enabledLangs, $locale)];
}, glob(base_path('resources/lang').'/*'));
$langs = call_user_func_array('array_merge', $langs);

View File

@@ -17,9 +17,9 @@ use CachetHQ\Cachet\Models\Incident;
use CachetHQ\Cachet\Models\IncidentTemplate;
use CachetHQ\Cachet\Models\Metric;
use CachetHQ\Cachet\Models\MetricPoint;
use CachetHQ\Cachet\Models\Setting;
use CachetHQ\Cachet\Models\Subscriber;
use CachetHQ\Cachet\Models\User;
use CachetHQ\Cachet\Settings\Repository;
use DateInterval;
use DateTime;
use Illuminate\Console\Command;
@@ -49,6 +49,27 @@ class DemoSeederCommand extends Command
*/
protected $description = 'Seeds Cachet with demo data.';
/**
* The settings repository.
*
* @var \CachetHQ\Cache\Settings\Repository
*/
protected $settings;
/**
* Create a new demo seeder command instance.
*
* @param \CachetHQ\Cache\Settings\Repository $settings
*
* @return void
*/
public function __construct(Repository $settings)
{
parent::__construct();
$this->settings = $settings;
}
/**
* Execute the console command.
*
@@ -293,42 +314,45 @@ EINCIDENT;
{
$defaultSettings = [
[
'name' => 'app_name',
'key' => 'app_name',
'value' => 'Cachet Demo',
], [
'name' => 'app_domain',
'key' => 'app_domain',
'value' => 'https://demo.cachethq.io',
], [
'name' => 'show_support',
'key' => 'show_support',
'value' => '1',
], [
'name' => 'app_locale',
'key' => 'app_locale',
'value' => 'en',
], [
'name' => 'app_timezone',
'key' => 'app_timezone',
'value' => 'Europe/London',
], [
'name' => 'app_incident_days',
'key' => 'app_incident_days',
'value' => '7',
], [
'name' => 'app_analytics',
'key' => 'app_analytics',
'value' => 'UA-58442674-3',
], [
'name' => 'app_analytics_gs',
'key' => 'app_analytics_gs',
'value' => 'GSN-712462-P',
], [
'name' => 'display_graphs',
'key' => 'display_graphs',
'value' => '1',
], [
'name' => 'app_about',
'key' => 'app_about',
'value' => 'This is the demo instance of [Cachet](https://cachethq.io?ref=demo). The open source status page system, for everyone. An [Alt Three](https://alt-three.com) product.',
], [
'key' => 'enable_subscribers',
'value' => '0',
],
];
Setting::truncate();
$this->settings->clear();
foreach ($defaultSettings as $setting) {
Setting::create($setting);
$this->settings->set($setting['key'], $setting['value']);
}
}

View File

@@ -0,0 +1,88 @@
<?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\Foundation\Exceptions\Displayers;
use Exception;
use GrahamCampbell\Exceptions\Displayers\DisplayerInterface;
use Illuminate\Http\Request;
use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException;
class ThrottleDisplayer implements DisplayerInterface
{
/**
* The request instance.
*
* @var \Illuminate\Http\Request
*/
protected $request;
/**
* Create a new redirect displayer instance.
*
* @param \Illuminate\Http\Request $request
*
* @return void
*/
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()->route('auth.login')->withError(trans('forms.login.rate-limit'));
}
/**
* Get the supported content type.
*
* @return string
*/
public function contentType()
{
return 'text/html';
}
/**
* Can we display the exception?
*
* @param \Exception $original
* @param \Exception $transformed
* @param int $code
*
* @return bool
*/
public function canDisplay(Exception $original, Exception $transformed, $code)
{
return $transformed instanceof TooManyRequestsHttpException && $this->request->is('auth*');
}
/**
* Do we provide verbose information about the exception?
*
* @return bool
*/
public function isVerbose()
{
return false;
}
}

View File

@@ -12,10 +12,21 @@
namespace CachetHQ\Cachet\Foundation\Providers;
use AltThree\Bus\Dispatcher;
use CachetHQ\Cachet\Bus\Middleware\UseDatabaseTransactions;
use CachetHQ\Cachet\Dates\DateFactory;
use CachetHQ\Cachet\Integrations\Credits;
use CachetHQ\Cachet\Integrations\Feed;
use CachetHQ\Cachet\Integrations\Releases;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Str;
/**
* This is the app service provider.
*
* @author James Brooks <james@alt-three.com>
* @author Joe Cohen <joe@alt-three.com>
* @author Graham Campbell <graham@alt-three.com>
*/
class AppServiceProvider extends ServiceProvider
{
/**
@@ -29,6 +40,8 @@ class AppServiceProvider extends ServiceProvider
return Dispatcher::simpleMapping($command, 'CachetHQ\Cachet\Bus', 'CachetHQ\Cachet\Bus\Handlers');
});
$dispatcher->pipeThrough([UseDatabaseTransactions::class]);
Str::macro('canonicalize', function ($url) {
return preg_replace('/([^\/])$/', '$1/', $url);
});
@@ -42,6 +55,9 @@ class AppServiceProvider extends ServiceProvider
public function register()
{
$this->registerDateFactory();
$this->registerCredits();
$this->registerFeed();
$this->registerReleases();
}
/**
@@ -52,10 +68,53 @@ class AppServiceProvider extends ServiceProvider
protected function registerDateFactory()
{
$this->app->singleton(DateFactory::class, function ($app) {
$appTimezone = $app->config->get('app.timezone');
$cacheTimezone = $app->config->get('cachet.timezone');
$appTimezone = $app['config']->get('app.timezone');
$cacheTimezone = $app['config']->get('cachet.timezone');
return new DateFactory($appTimezone, $cacheTimezone);
});
}
/**
* Register the credits class.
*
* @return void
*/
protected function registerCredits()
{
$this->app->singleton(Credits::class, function ($app) {
$cache = $app['cache.store'];
return new Credits($cache);
});
}
/**
* Register the feed class.
*
* @return void
*/
protected function registerFeed()
{
$this->app->singleton(Feed::class, function ($app) {
$cache = $app['cache.store'];
return new Feed($cache);
});
}
/**
* Register the releases class.
*
* @return void
*/
protected function registerReleases()
{
$this->app->singleton(Releases::class, function ($app) {
$cache = $app['cache.store'];
$token = $app['config']->get('services.github.token');
return new Releases($cache, $token);
});
}
}

View File

@@ -34,7 +34,7 @@ class ComposerServiceProvider extends ServiceProvider
$factory->composer('*', CurrentUserComposer::class);
$factory->composer(['index'], MetricsComposer::class);
$factory->composer(['index', 'single-incident', 'subscribe', 'signup'], StatusPageComposer::class);
$factory->composer(['index', 'single-incident', 'subscribe.*', 'signup', 'dashboard.settings.theme'], ThemeComposer::class);
$factory->composer(['index', 'single-incident', 'subscribe.*', 'signup', 'dashboard.settings.theme', 'emails.*'], ThemeComposer::class);
$factory->composer('dashboard.*', DashboardComposer::class);
$factory->composer(['setup', 'dashboard.settings.localization'], TimezoneLocaleComposer::class);
}

View File

@@ -11,11 +11,20 @@
namespace CachetHQ\Cachet\Foundation\Providers;
use CachetHQ\Cachet\Config\Repository;
use CachetHQ\Cachet\Models\Setting as SettingModel;
use CachetHQ\Cachet\Settings\Cache;
use CachetHQ\Cachet\Settings\Repository;
use Exception;
use Illuminate\Support\ServiceProvider;
use Jenssegers\Date\Date;
/**
* This is the config service provider class.
*
* @author James Brooks <james@alt-three.com>
* @author Graham Campbell <graham@alt-three.com>
* @author Joe Cohen <joe@alt-three.com>
*/
class ConfigServiceProvider extends ServiceProvider
{
/**
@@ -25,8 +34,26 @@ class ConfigServiceProvider extends ServiceProvider
*/
public function boot()
{
$env = $this->app->environment();
$repo = $this->app->make(Repository::class);
$cache = $this->app->make(Cache::class);
$loaded = $cache->load($env);
$this->app->terminating(function () use ($repo, $cache) {
if ($repo->stale()) {
$cache->clear();
}
});
try {
$this->app->config->set('setting', $this->app->setting->all());
if ($loaded === false) {
$loaded = $repo->all();
$cache->store($env, $loaded);
}
$settings = array_merge($this->app->config->get('setting'), $loaded);
$this->app->config->set('setting', $settings);
} catch (Exception $e) {
//
}
@@ -35,9 +62,10 @@ class ConfigServiceProvider extends ServiceProvider
$this->app->config->set('app.url', $appDomain);
}
if ($appLocale = $this->app->config->get('setting.app.locale')) {
if ($appLocale = $this->app->config->get('setting.app_locale')) {
$this->app->config->set('app.locale', $appLocale);
$this->app->translator->setLocale($appLocale);
Date::setLocale($appLocale);
}
if ($appTimezone = $this->app->config->get('setting.app_timezone')) {
@@ -65,10 +93,12 @@ class ConfigServiceProvider extends ServiceProvider
*/
public function register()
{
$this->app->singleton('setting', function () {
return new Repository(new SettingModel());
$this->app->singleton(Cache::class, function ($app) {
return new Cache($app->files, $app->bootstrapPath().'/cachet');
});
$this->app->alias('setting', Repository::class);
$this->app->singleton(Repository::class, function () {
return new Repository(new SettingModel());
});
}
}

View File

@@ -11,11 +11,28 @@
namespace CachetHQ\Cachet\Foundation\Providers;
use CachetHQ\Cachet\GitHub\Release;
use CachetHQ\Cachet\Subscribers\CommandSubscriber;
use Illuminate\Support\ServiceProvider;
class GitHubServiceProvider extends ServiceProvider
/**
* This is the console service provider.
*
* @author James Brooks <james@alt-three.com>
*/
class ConsoleServiceProvider extends ServiceProvider
{
/**
* Boot the service provider.
*
* @return void
*/
public function boot()
{
$subscriber = $this->app->make(CommandSubscriber::class);
$this->app->events->subscribe($subscriber);
}
/**
* Register the service provider.
*
@@ -23,23 +40,6 @@ class GitHubServiceProvider extends ServiceProvider
*/
public function register()
{
$this->registerRelease();
}
/**
* Register the releases class.
*
* @return void
*/
protected function registerRelease()
{
$this->app->singleton('cachet.release', function ($app) {
$cache = $app['cache.store'];
$config = $app['config'];
return new Release($cache, $config);
});
$this->app->alias('cachet.release', Release::class);
//
}
}

View File

@@ -34,14 +34,20 @@ class EventServiceProvider extends ServiceProvider
//
],
'CachetHQ\Cachet\Bus\Events\Component\ComponentWasRemovedEvent' => [
//
'CachetHQ\Cachet\Bus\Handlers\Events\Component\CleanupComponentSubscriptionsHandler',
],
'CachetHQ\Cachet\Bus\Events\Component\ComponentWasUpdatedEvent' => [
'CachetHQ\Cachet\Bus\Handlers\Events\Component\SendComponentUpdateEmailNotificationHandler',
],
'CachetHQ\Cachet\Bus\Events\Incident\IncidentWasRemovedEvent' => [
//
],
'CachetHQ\Cachet\Bus\Events\Incident\IncidentWasReportedEvent' => [
'CachetHQ\Cachet\Bus\Handlers\Events\Incident\SendIncidentEmailNotificationHandler',
],
'CachetHQ\Cachet\Bus\Events\Incident\IncidentWasUpdatedEvent' => [
//
],
'CachetHQ\Cachet\Bus\Events\Incident\MaintenanceWasScheduledEvent' => [
'CachetHQ\Cachet\Bus\Handlers\Events\Incident\SendMaintenanceEmailNotificationHandler',
],

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\Foundation\Providers;
use CachetHQ\Cachet\Integrations\Contracts\System as SystemContract;
use CachetHQ\Cachet\Integrations\Core\System;
use Illuminate\Contracts\Container\Container;
use Illuminate\Support\ServiceProvider;
/**
* This is the integration service provider.
*
* @author James Brooks <james@alt-three.com>
*/
class IntegrationServiceProvider extends ServiceProvider
{
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->registerSystem();
}
/**
* Register the system class.
*
* @return void
*/
protected function registerSystem()
{
$this->app->singleton(SystemContract::class, function (Container $app) {
return new System();
});
}
}

View File

@@ -16,8 +16,15 @@ use CachetHQ\Cachet\Repositories\Metric\MetricRepository;
use CachetHQ\Cachet\Repositories\Metric\MySqlRepository as MetricMySqlRepository;
use CachetHQ\Cachet\Repositories\Metric\PgSqlRepository as MetricPgSqlRepository;
use CachetHQ\Cachet\Repositories\Metric\SqliteRepository as MetricSqliteRepository;
use Illuminate\Contracts\Config\Repository as ConfigRepository;
use Illuminate\Contracts\Container\Container;
use Illuminate\Support\ServiceProvider;
/**
* This is the repository service provider.
*
* @author James Brooks <james@alt-three.com>
*/
class RepositoryServiceProvider extends ServiceProvider
{
/**
@@ -37,22 +44,21 @@ class RepositoryServiceProvider extends ServiceProvider
*/
protected function registerMetricRepository()
{
$this->app->singleton('cachet.metricrepository', function ($app) {
$dbDriver = $app['config']->get('database.default');
$this->app->singleton(MetricRepository::class, function (Container $app) {
$config = $app->make(ConfigRepository::class);
$driver = $config->get('database.default');
if ($dbDriver == 'mysql') {
$repository = new MetricMySqlRepository();
} elseif ($dbDriver == 'pgsql') {
$repository = new MetricPgSqlRepository();
} elseif ($dbDriver == 'sqlite') {
$repository = new MetricSqliteRepository();
if ($driver == 'mysql') {
$repository = new MetricMySqlRepository($config);
} elseif ($driver == 'pgsql') {
$repository = new MetricPgSqlRepository($config);
} elseif ($driver == 'sqlite') {
$repository = new MetricSqliteRepository($config);
}
$dates = $app->make(DateFactory::class);
return new MetricRepository($repository, $dates);
});
$this->app->alias('cachet.metricrepository', MetricRepository::class);
}
}

View File

@@ -1,70 +0,0 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\GitHub;
use GuzzleHttp\Client;
use Illuminate\Contracts\Cache\Repository as CacheRepository;
use Illuminate\Contracts\Config\Repository as ConfigRepository;
class Release
{
/**
* The cache repository instance.
*
* @var \Illuminate\Contracts\Cache\Repository
*/
protected $cache;
/**
* The config repository instance.
*
* @var \Illuminate\Contracts\Config\Repository
*/
protected $config;
/**
* Creates a new release instance.
*
* @param \Illuminate\Contracts\Cache\Repository $cache
* @param \Illuminate\Contracts\Config\Repository $config
*
* @return void
*/
public function __construct(CacheRepository $cache, ConfigRepository $config)
{
$this->cache = $cache;
$this->config = $config;
}
/**
* Returns the latest GitHub release.
*
* @return string
*/
public function latest()
{
$release = $this->cache->remember('version', 720, function () {
$headers = ['Accept' => 'application/vnd.github.v3+json'];
// We can re-use the Emoji token here, if we have it.
if ($token = $this->config->get('services.github.token')) {
$headers['OAUTH-TOKEN'] = $token;
}
return json_decode((new Client())->get('https://api.github.com/repos/cachethq/cachet/releases/latest', [
'headers' => $headers,
])->getBody(), true);
});
return $release['tag_name'];
}
}

View File

@@ -88,7 +88,7 @@ class ComponentController extends AbstractApiController
$tags = preg_split('/ ?, ?/', Binput::get('tags'));
// For every tag, do we need to create it?
$componentTags = array_map(function ($taggable) use ($component) {
$componentTags = array_map(function ($taggable) {
return Tag::firstOrCreate([
'name' => $taggable,
])->id;
@@ -128,7 +128,7 @@ class ComponentController extends AbstractApiController
$tags = preg_split('/ ?, ?/', Binput::get('tags'));
// For every tag, do we need to create it?
$componentTags = array_map(function ($taggable) use ($component) {
$componentTags = array_map(function ($taggable) {
return Tag::firstOrCreate(['name' => $taggable])->id;
}, $tags);

View File

@@ -20,6 +20,13 @@ use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
/**
* This is the component group controller.
*
* @author James Brooks <james@alt-three.com>
* @author Graham Campbell <graham@alt-three.com>
* @author Joe Cohen <joe@alt-three.com>
*/
class ComponentGroupController extends AbstractApiController
{
/**
@@ -67,7 +74,7 @@ class ComponentGroupController extends AbstractApiController
$group = dispatch(new AddComponentGroupCommand(
Binput::get('name'),
Binput::get('order', 0),
Binput::get('collapsed')
Binput::get('collapsed', 0)
));
} catch (QueryException $e) {
throw new BadRequestHttpException();
@@ -89,7 +96,7 @@ class ComponentGroupController extends AbstractApiController
$group = dispatch(new UpdateComponentGroupCommand(
$group,
Binput::get('name'),
Binput::get('order', 0),
Binput::get('order'),
Binput::get('collapsed')
));
} catch (QueryException $e) {

View File

@@ -11,6 +11,14 @@
namespace CachetHQ\Cachet\Http\Controllers\Api;
use CachetHQ\Cachet\Integrations\Contracts\System;
use CachetHQ\Cachet\Integrations\Releases;
/**
* This is the general api controller.
*
* @author James Brooks <james@bluebaytravel.co.uk>
*/
class GeneralController extends AbstractApiController
{
/**
@@ -30,6 +38,26 @@ class GeneralController extends AbstractApiController
*/
public function version()
{
return $this->item(CACHET_VERSION);
$latest = app(Releases::class)->latest();
return $this->setMetaData([
'on_latest' => version_compare(CACHET_VERSION, $latest['tag_name']) === 1,
'latest' => $latest,
])->item(CACHET_VERSION);
}
/**
* Get the system status message.
*
* @return \Illuminate\Http\JsonResponse
*/
public function status()
{
$system = app()->make(System::class)->getStatus();
return $this->item([
'status' => $system['system_status'],
'message' => $system['system_message'],
]);
}
}

View File

@@ -84,7 +84,9 @@ class MetricController extends AbstractApiController
Binput::get('calc_type', 0),
Binput::get('display_chart', true),
Binput::get('places', 2),
Binput::get('view', 1)
Binput::get('default_view', Binput::get('view', 1)),
Binput::get('threshold', 5),
Binput::get('order', 0)
));
} catch (QueryException $e) {
throw new BadRequestHttpException();
@@ -112,7 +114,9 @@ class MetricController extends AbstractApiController
Binput::get('calc_type'),
Binput::get('display_chart'),
Binput::get('places'),
Binput::get('view')
Binput::get('default_view', Binput::get('view')),
Binput::get('threshold'),
Binput::get('order')
));
} catch (QueryException $e) {
throw new BadRequestHttpException();

View File

@@ -48,8 +48,8 @@ class MetricPointController extends AbstractApiController
$metricPoint = dispatch(new AddMetricPointCommand(
$metric,
Binput::get('value'),
Binput::get('timestamp'))
);
Binput::get('timestamp')
));
} catch (QueryException $e) {
throw new BadRequestHttpException();
}

View File

@@ -21,6 +21,12 @@ use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
/**
* This is the subscriber controller class.
*
* @author James Brooks <james@alt-three.com>
* @author Graham Campbell <graham@alt-three.com>
*/
class SubscriberController extends AbstractApiController
{
/**
@@ -43,7 +49,11 @@ class SubscriberController extends AbstractApiController
public function postSubscribers()
{
try {
$subscriber = dispatch(new SubscribeSubscriberCommand(Binput::get('email'), Binput::get('verify', false), null));
$subscriber = dispatch(new SubscribeSubscriberCommand(
Binput::get('email'),
Binput::get('verify', false),
Binput::get('components', null)
));
} catch (QueryException $e) {
throw new BadRequestHttpException();
}

View File

@@ -41,11 +41,11 @@ class AuthController extends Controller
*/
public function postLogin()
{
$loginData = Binput::only(['login', 'password']);
$loginData = Binput::only(['username', 'password']);
// Login with username or email.
$loginKey = Str::contains($loginData['login'], '@') ? 'email' : 'username';
$loginData[$loginKey] = array_pull($loginData, 'login');
$loginKey = Str::contains($loginData['username'], '@') ? 'email' : 'username';
$loginData[$loginKey] = array_pull($loginData, 'username');
// Validate login credentials.
if (Auth::validate($loginData)) {

View File

@@ -11,34 +11,46 @@
namespace CachetHQ\Cachet\Http\Controllers\Dashboard;
use CachetHQ\Cachet\GitHub\Release;
use CachetHQ\Cachet\Bus\Commands\Component\UpdateComponentCommand;
use CachetHQ\Cachet\Bus\Commands\ComponentGroup\UpdateComponentGroupCommand;
use CachetHQ\Cachet\Http\Controllers\Api\AbstractApiController;
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;
use Illuminate\Support\Facades\Response;
use Illuminate\Database\QueryException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
class ApiController extends Controller
class ApiController extends AbstractApiController
{
/**
* Updates a component with the entered info.
*
* @param \CachetHQ\Cachet\Models\Component $component
*
* @throws \Exception
* @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
*
* @return \CachetHQ\Cachet\Models\Component
*/
public function postUpdateComponent(Component $component)
{
if (!$component->update(Binput::except(['_token']))) {
throw new Exception(trans('dashboard.components.edit.failure'));
try {
dispatch(new UpdateComponentCommand(
$component,
$component->name,
$component->description,
Binput::get('status'),
$component->link,
$component->order,
$component->group_id,
$component->enabled
));
} catch (QueryException $e) {
throw new BadRequestHttpException();
}
return $component;
return $this->item($component);
}
/**
@@ -51,11 +63,25 @@ class ApiController extends Controller
$componentData = Binput::get('ids');
foreach ($componentData as $order => $componentId) {
// Ordering should be 1-based, data comes in 0-based
Component::find($componentId)->update(['order' => $order + 1]);
try {
$component = Component::find($componentId);
dispatch(new UpdateComponentCommand(
$component,
$component->name,
$component->description,
$component->status,
$component->link,
$order + 1,
$component->group_id,
$component->enabled
));
} catch (QueryException $e) {
throw new BadRequestHttpException();
}
}
return $componentData;
return $this->collection(Component::query()->orderBy('order')->get());
}
/**
@@ -68,10 +94,17 @@ class ApiController extends Controller
$groupData = Binput::get('ids');
foreach ($groupData as $order => $groupId) {
ComponentGroup::find($groupId)->update(['order' => $order + 1]);
$group = ComponentGroup::find($groupId);
dispatch(new UpdateComponentGroupCommand(
$group,
$group->name,
$order + 1,
$group->collapsed
));
}
return $groupData;
return $this->collection(ComponentGroup::query()->orderBy('order')->get());
}
/**
@@ -91,20 +124,4 @@ class ApiController extends Controller
throw new ModelNotFoundException("Incident template for $templateSlug could not be found.");
}
/**
* Checks if Cachet is up to date.
*
* @return \Illuminate\Http\JsonResponse
*/
public function checkVersion()
{
$latest = app(Release::class)->latest();
return Response::json([
'cachet_version' => CACHET_VERSION,
'latest_version' => $latest,
'is_latest' => version_compare(CACHET_VERSION, $latest) === 1,
]);
}
}

View File

@@ -148,7 +148,7 @@ class ComponentController extends Controller
$tags = preg_split('/ ?, ?/', $tags);
// For every tag, do we need to create it?
$componentTags = array_map(function ($taggable) use ($component) {
$componentTags = array_map(function ($taggable) {
return Tag::firstOrCreate(['name' => $taggable])->id;
}, $tags);
@@ -201,7 +201,7 @@ class ComponentController extends Controller
$tags = preg_split('/ ?, ?/', $tags);
// For every tag, do we need to create it?
$componentTags = array_map(function ($taggable) use ($component) {
$componentTags = array_map(function ($taggable) {
return Tag::firstOrCreate(['name' => $taggable])->id;
}, $tags);

View File

@@ -11,11 +11,14 @@
namespace CachetHQ\Cachet\Http\Controllers\Dashboard;
use CachetHQ\Cachet\Integrations\Feed;
use CachetHQ\Cachet\Models\Component;
use CachetHQ\Cachet\Models\ComponentGroup;
use CachetHQ\Cachet\Models\Incident;
use CachetHQ\Cachet\Models\Subscriber;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\View;
use Jenssegers\Date\Date;
@@ -36,16 +39,36 @@ class DashboardController extends Controller
protected $timeZone;
/**
* Creates a new dashboard controller.
* The feed integration.
*
* @var \CachetHQ\Cachet\Integrations\Feed
*/
protected $feed;
/**
* Creates a new dashboard controller instance.
*
* @param \CachetHQ\Cachet\Integrations\Feed $feed
*
* @return void
*/
public function __construct()
public function __construct(Feed $feed)
{
$this->feed = $feed;
$this->startDate = new Date();
$this->dateTimeZone = Config::get('cachet.timezone');
}
/**
* Redirect /admin to /dashboard.
*
* @return \Illuminate\Http\RedirectResponse
*/
public function redirectAdmin()
{
return Redirect::route('dashboard.index');
}
/**
* Shows the dashboard view.
*
@@ -56,12 +79,25 @@ class DashboardController extends Controller
$components = Component::orderBy('order')->get();
$incidents = $this->getIncidents();
$subscribers = $this->getSubscribers();
$usedComponentGroups = Component::enabled()->where('group_id', '>', 0)->groupBy('group_id')->pluck('group_id');
$componentGroups = ComponentGroup::whereIn('id', $usedComponentGroups)->orderBy('order')->get();
$ungroupedComponents = Component::enabled()->where('group_id', 0)->orderBy('order')->orderBy('created_at')->get();
$entries = null;
if ($feed = $this->feed->latest()) {
if (is_object($feed)) {
$entries = array_slice($feed->channel->item, 0, 5);
}
}
return View::make('dashboard.index')
->withPageTitle(trans('dashboard.dashboard'))
->withComponents($components)
->withIncidents($incidents)
->withSubscribers($subscribers);
->withSubscribers($subscribers)
->withEntries($entries)
->withComponentGroups($componentGroups)
->withUngroupedComponents($ungroupedComponents);
}
/**

View File

@@ -31,7 +31,7 @@ class MetricController extends Controller
*/
public function showMetrics()
{
$metrics = Metric::orderBy('created_at', 'desc')->get();
$metrics = Metric::orderBy('order')->orderBy('id')->get();
return View::make('dashboard.metrics.index')
->withPageTitle(trans('dashboard.metrics.metrics').' - '.trans('dashboard.dashboard'))
@@ -79,7 +79,8 @@ class MetricController extends Controller
$metricData['calc_type'],
$metricData['display_chart'],
$metricData['places'],
$metricData['default_view']
$metricData['default_view'],
$metricData['threshold']
));
} catch (ValidationException $e) {
return Redirect::route('dashboard.metrics.add')
@@ -151,7 +152,8 @@ class MetricController extends Controller
Binput::get('calc_type', null, false),
Binput::get('display_chart', null, false),
Binput::get('places', null, false),
Binput::get('default_view', null, false)
Binput::get('default_view', null, false),
Binput::get('threshold', null, false)
));
} catch (ValidationException $e) {
return Redirect::route('dashboard.metrics.edit', ['id' => $metric->id])

View File

@@ -11,7 +11,9 @@
namespace CachetHQ\Cachet\Http\Controllers\Dashboard;
use CachetHQ\Cachet\Integrations\Credits;
use CachetHQ\Cachet\Models\User;
use CachetHQ\Cachet\Settings\Repository;
use Exception;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Routing\Controller;
@@ -81,6 +83,12 @@ class SettingsController extends Controller
'icon' => 'ion-stats-bars',
'active' => false,
],
'credits' => [
'title' => trans('dashboard.settings.credits.credits'),
'url' => route('dashboard.settings.credits'),
'icon' => 'ion-ios-list',
'active' => false,
],
'about' => [
'title' => CACHET_VERSION,
'url' => 'javascript: void(0);',
@@ -211,6 +219,30 @@ class SettingsController extends Controller
->withSubMenu($this->subMenu);
}
/**
* Show the credits view.
*
* @return \Illuminate\View\View
*/
public function showCreditsView()
{
$this->subMenu['credits']['active'] = true;
$credits = app(Credits::class)->latest();
$backers = $credits['backers'];
$contributors = $credits['contributors'];
shuffle($backers);
shuffle($contributors);
return View::make('dashboard.settings.credits')
->withPageTitle(trans('dashboard.settings.credits.credits').' - '.trans('dashboard.dashboard'))
->withBackers($backers)
->withContributors($contributors)
->withSubMenu($this->subMenu);
}
/**
* Updates the status page settings.
*
@@ -218,9 +250,7 @@ class SettingsController extends Controller
*/
public function postSettings()
{
$redirectUrl = Session::get('redirect_to', route('dashboard.settings.setup'));
$setting = app('setting');
$setting = app(Repository::class);
if (Binput::get('remove_banner') === '1') {
$setting->set('app_banner', null);
@@ -244,30 +274,16 @@ class SettingsController extends Controller
}
}
if (isset($parameters['stylesheet'])) {
if ($stylesheet = Binput::get('stylesheet', null, false, false)) {
$setting->set('stylesheet', $stylesheet);
} else {
$setting->delete('stylesheet');
}
}
if (Binput::hasFile('app_banner')) {
$file = Binput::file('app_banner');
// Image Validation.
// Image size in bytes.
$maxSize = $file->getMaxFilesize();
if ($file->getSize() > $maxSize) {
return Redirect::to($redirectUrl)->withErrors(trans('dashboard.settings.app-setup.too-big', ['size' => $maxSize]));
}
if (!$file->isValid() || $file->getError()) {
return Redirect::to($redirectUrl)->withErrors($file->getErrorMessage());
}
if (!Str::startsWith($file->getMimeType(), 'image/')) {
return Redirect::to($redirectUrl)->withErrors(trans('dashboard.settings.app-setup.images-only'));
}
// Store the banner.
$setting->set('app_banner', base64_encode(file_get_contents($file->getRealPath())));
// Store the banner type.
$setting->set('app_banner_type', $file->getMimeType());
$this->handleUpdateBanner($setting);
}
$excludedParams = [
@@ -276,6 +292,7 @@ class SettingsController extends Controller
'remove_banner',
'header',
'footer',
'stylesheet',
];
try {
@@ -287,13 +304,47 @@ class SettingsController extends Controller
$setting->set($settingName, $settingValue);
}
} catch (Exception $e) {
return Redirect::to($redirectUrl)->withErrors(trans('dashboard.settings.edit.failure'));
return Redirect::back()->withErrors(trans('dashboard.settings.edit.failure'));
}
if (Binput::has('app_locale')) {
Lang::setLocale(Binput::get('app_locale'));
}
return Redirect::to($redirectUrl)->withSuccess(trans('dashboard.settings.edit.success'));
return Redirect::back()->withSuccess(trans('dashboard.settings.edit.success'));
}
/**
* Handle updating of the banner image.
*
* @param \CachetHQ\Cachet\Settings\Repository $setting
*
* @return void
*/
protected function handleUpdateBanner(Repository $setting)
{
$file = Binput::file('app_banner');
// Image Validation.
// Image size in bytes.
$maxSize = $file->getMaxFilesize();
if ($file->getSize() > $maxSize) {
return Redirect::to($redirectUrl)->withErrors(trans('dashboard.settings.app-setup.too-big', ['size' => $maxSize]));
}
if (!$file->isValid() || $file->getError()) {
return Redirect::to($redirectUrl)->withErrors($file->getErrorMessage());
}
if (!Str::startsWith($file->getMimeType(), 'image/')) {
return Redirect::to($redirectUrl)->withErrors(trans('dashboard.settings.app-setup.images-only'));
}
// Store the banner.
$setting->set('app_banner', base64_encode(file_get_contents($file->getRealPath())));
// Store the banner type.
$setting->set('app_banner_type', $file->getMimeType());
}
}

View File

@@ -53,7 +53,11 @@ class SubscriberController extends Controller
public function createSubscriberAction()
{
try {
dispatch(new SubscribeSubscriberCommand(Binput::get('email')));
$subscribers = preg_split("/\r\n|\n|\r/", Binput::get('email'));
foreach ($subscribers as $subscriber) {
dispatch(new SubscribeSubscriberCommand($subscriber));
}
} catch (ValidationException $e) {
return Redirect::route('dashboard.subscribers.add')
->withInput(Binput::all())

View File

@@ -12,6 +12,7 @@
namespace CachetHQ\Cachet\Http\Controllers;
use CachetHQ\Cachet\Models\User;
use CachetHQ\Cachet\Settings\Repository;
use Dotenv\Dotenv;
use Dotenv\Exception\InvalidPathException;
use GrahamCampbell\Binput\Facades\Binput;
@@ -41,6 +42,22 @@ class SetupController extends Controller
'redis' => 'Redis',
];
/**
* Array of cache drivers.
*
* @var string[]
*/
protected $mailDrivers = [
'smtp' => 'SMTP',
'mail' => 'Mail',
'sendmail' => 'Sendmail',
'mailgun' => 'Mailgun',
'mandrill' => 'Mandrill',
// 'ses' => 'Amazon SES', this will be available only if aws/aws-sdk-php is installed
'sparkpost' => 'SparkPost',
'log' => 'Log (Testing)',
];
/**
* Array of step1 rules.
*
@@ -72,6 +89,7 @@ class SetupController extends Controller
$this->rulesStep1 = [
'env.cache_driver' => 'required|in:'.implode(',', array_keys($this->cacheDrivers)),
'env.session_driver' => 'required|in:'.implode(',', array_keys($this->cacheDrivers)),
'env.mail_driver' => 'required|in:'.implode(',', array_keys($this->mailDrivers)),
];
$this->rulesStep2 = [
@@ -96,11 +114,6 @@ class SetupController extends Controller
*/
public function getIndex()
{
// If we've copied the .env.example file, then we should try and reset it.
if (strlen(Config::get('app.key')) !== 32) {
$this->keyGenerate();
}
$supportedLanguages = Request::getLanguages();
$userLanguage = Config::get('app.locale');
@@ -116,6 +129,7 @@ class SetupController extends Controller
return View::make('setup')
->withPageTitle(trans('setup.setup'))
->withCacheDrivers($this->cacheDrivers)
->withMailDrivers($this->mailDrivers)
->withUserLanguage($userLanguage)
->withAppUrl(Request::root());
}
@@ -131,6 +145,14 @@ class SetupController extends Controller
$v = Validator::make($postData, $this->rulesStep1);
$v->sometimes('env.mail_host', 'required', function ($input) {
return $input->mail_driver === 'smtp';
});
$v->sometimes(['env.mail_address', 'env.mail_username'], 'required', function ($input) {
return $input->mail_driver !== 'log';
});
if ($v->passes()) {
return Response::json(['status' => 1]);
}
@@ -180,7 +202,7 @@ class SetupController extends Controller
Auth::login($user);
$setting = app('setting');
$setting = app(Repository::class);
$settings = array_pull($postData, 'settings');
@@ -228,33 +250,16 @@ class SetupController extends Controller
try {
(new Dotenv($dir, $file))->load();
$envKey = strtoupper($key);
$envValue = env($envKey) ?: 'null';
file_put_contents($path, str_replace(
env(strtoupper($key)), $value, file_get_contents($path)
$envKey.'='.$envValue,
$envKey.'='.$value,
file_get_contents($path)
));
} catch (InvalidPathException $e) {
//
}
}
/**
* Generate the app.key value.
*
* @return void
*/
protected function keyGenerate()
{
$key = str_random(32);
$dir = app()->environmentPath();
$file = app()->environmentFile();
$path = "{$dir}/{$file}";
(new Dotenv($dir, $file))->load();
file_put_contents($path, str_replace(
Config::get('app.key'), $key, file_get_contents($path)
));
Config::set('app.key', $key);
}
}

View File

@@ -47,7 +47,7 @@ class SignupController extends Controller
return View::make('signup')
->withCode($invite->code)
->withUsername(Binput::old('username'))
->withEmail(Binput::old('emai', $invite->email));
->withEmail(Binput::old('email', $invite->email));
}
/**

View File

@@ -15,8 +15,9 @@ use AltThree\Validator\ValidationException;
use CachetHQ\Cachet\Bus\Commands\Subscriber\SubscribeSubscriberCommand;
use CachetHQ\Cachet\Bus\Commands\Subscriber\UnsubscribeSubscriberCommand;
use CachetHQ\Cachet\Bus\Commands\Subscriber\UnsubscribeSubscriptionCommand;
use CachetHQ\Cachet\Bus\Commands\Subscriber\UpdateSubscriberSubscriptionCommand;
use CachetHQ\Cachet\Bus\Commands\Subscriber\VerifySubscriberCommand;
use CachetHQ\Cachet\Bus\Exceptions\Subscriber\AlreadySubscribedException;
use CachetHQ\Cachet\Models\Component;
use CachetHQ\Cachet\Models\Subscriber;
use CachetHQ\Cachet\Models\Subscription;
use GrahamCampbell\Binput\Facades\Binput;
@@ -57,20 +58,22 @@ class SubscribeController extends Controller
$subscriptions = Binput::get('subscriptions');
try {
dispatch(new SubscribeSubscriberCommand($email, false, $subscriptions));
} catch (AlreadySubscribedException $e) {
return Redirect::route('subscribe.subscribe')
->withTitle(sprintf('<strong>%s</strong> %s', trans('dashboard.notifications.whoops'), trans('cachet.subscriber.email.failure')))
->withErrors(trans('cachet.subscriber.email.already-subscribed', ['email' => $email]));
$verified = false;
$subscription = dispatch(new SubscribeSubscriberCommand($email, $verified));
} catch (ValidationException $e) {
return Redirect::route('subscribe.subscribe')
return Redirect::route('status-page')
->withInput(Binput::all())
->withTitle(sprintf('<strong>%s</strong> %s', trans('dashboard.notifications.whoops'), trans('cachet.subscriber.email.failure')))
->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('cachet.subscriber.email.failure')))
->withErrors($e->getMessageBag());
}
return Redirect::route('status-page')
->withSuccess(sprintf('<strong>%s</strong> %s', trans('dashboard.notifications.awesome'), trans('cachet.subscriber.email.subscribed')));
$message = $subscription->is_verified ?
trans('cachet.subscriber.email.already-subscribed', ['email' => $email]) :
trans('cachet.subscriber.email.subscribed');
return Redirect::route('subscribe.manage', $subscription->verify_code)
->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), $message));
}
/**
@@ -86,16 +89,18 @@ class SubscribeController extends Controller
throw new NotFoundHttpException();
}
$subscriber = Subscriber::where('verify_code', '=', $code)->first();
$subscriber = Subscriber::where('verify_code', $code)->first();
if (!$subscriber || $subscriber->is_verified) {
if (!$subscriber) {
throw new BadRequestHttpException();
}
dispatch(new VerifySubscriberCommand($subscriber));
if (!$subscriber->is_verified) {
dispatch(new VerifySubscriberCommand($subscriber));
}
return Redirect::route('status-page')
->withSuccess(sprintf('<strong>%s</strong> %s', trans('dashboard.notifications.awesome'), trans('cachet.subscriber.email.verified')));
->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('cachet.subscriber.email.verified')));
}
/**
@@ -125,7 +130,7 @@ class SubscribeController extends Controller
}
return Redirect::route('status-page')
->withSuccess(sprintf('<strong>%s</strong> %s', trans('dashboard.notifications.awesome'), trans('cachet.subscriber.email.unsubscribed')));
->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('cachet.subscriber.email.unsubscribed')));
}
/**
@@ -143,10 +148,45 @@ class SubscribeController extends Controller
$subscriber = Subscriber::where('verify_code', '=', $code)->first();
if (!$subscriber || !$subscriber->is_verified) {
if (!$subscriber) {
throw new BadRequestHttpException();
}
return View::make('subscribe.manage')->withSubscriber($subscriber);
return View::make('subscribe.manage')
->withComponents(Component::all())
->withSubscriber($subscriber)
->withSubscriptions($subscriber->subscriptions->pluck('component_id')->all());
}
/**
* Updates the subscription manager for a subscriber.
*
* @param string|null $code
*
* @return \Illuminate\View\View
*/
public function postManage($code = null)
{
if ($code === null) {
throw new NotFoundHttpException();
}
$subscriber = Subscriber::where('verify_code', '=', $code)->first();
if (!$subscriber) {
throw new BadRequestHttpException();
}
try {
dispatch(new UpdateSubscriberSubscriptionCommand($subscriber, Binput::get('subscriptions')));
} catch (ValidationException $e) {
return Redirect::route('subscribe.manage', $subscriber->verify_code)
->withInput(Binput::all())
->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('cachet.subscriber.email.failure')))
->withErrors($e->getMessageBag());
}
return Redirect::route('subscribe.manage', $subscriber->verify_code)
->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('cachet.subscriber.email.subscribed')));
}
}

View File

@@ -59,6 +59,6 @@ class Kernel extends HttpKernel
'ready' => 'CachetHQ\Cachet\Http\Middleware\ReadyForUse',
'setup' => 'CachetHQ\Cachet\Http\Middleware\SetupAlreadyCompleted',
'subscribers' => 'CachetHQ\Cachet\Http\Middleware\SubscribersConfigured',
'throttle' => 'Illuminate\Routing\Middleware\ThrottleRequests',
'throttle' => 'AltThree\Throttle\ThrottlingMiddleware',
];
}

View File

@@ -55,6 +55,10 @@ class Localize
*/
public function handle(Request $request, Closure $next)
{
if (!(bool) $this->config->get('setting.automatic_localization')) {
return $next($request);
}
$supportedLanguages = $request->getLanguages();
$userLanguage = $this->config->get('app.locale');

View File

@@ -25,7 +25,7 @@ class Timezone
protected $config;
/**
* Creates a new release instance.
* Creates a new timezone middleware instance.
*
* @param \Illuminate\Contracts\Config\Repository $config
*

View File

@@ -33,6 +33,7 @@ class ApiRoutes
$router->group(['middleware' => ['auth.api']], function (Registrar $router) {
$router->get('ping', 'GeneralController@ping');
$router->get('version', 'GeneralController@version');
$router->get('status', 'GeneralController@status');
$router->get('components', 'ComponentController@getComponents');
$router->get('components/groups', 'ComponentGroupController@getGroups');

View File

@@ -29,206 +29,213 @@ class DashboardRoutes
*/
public function map(Registrar $router)
{
$router->group(['middleware' => ['web', 'auth'], 'prefix' => 'dashboard', 'namespace' => 'Dashboard', 'as' => 'dashboard.'], function (Registrar $router) {
$router->get('/', [
'as' => 'index',
'uses' => 'DashboardController@showDashboard',
]);
$router->group(['middleware' => ['web', 'auth'], 'namespace' => 'Dashboard'], function (Registrar $router) {
$router->get('admin', 'DashboardController@redirectAdmin');
$router->group(['as' => 'components.', 'prefix' => 'components'], function (Registrar $router) {
$router->group(['prefix' => 'dashboard', 'as' => 'dashboard.'], function (Registrar $router) {
$router->get('/', [
'as' => 'index',
'uses' => 'ComponentController@showComponents',
]);
$router->get('add', [
'as' => 'add',
'uses' => 'ComponentController@showAddComponent',
]);
$router->post('add', 'ComponentController@createComponentAction');
$router->get('groups', [
'as' => 'groups',
'uses' => 'ComponentController@showComponentGroups',
]);
$router->get('groups/add', [
'as' => 'groups.add',
'uses' => 'ComponentController@showAddComponentGroup',
]);
$router->get('groups/edit/{component_group}', [
'as' => '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->get('{component}/edit', [
'as' => 'edit',
'uses' => 'ComponentController@showEditComponent',
]);
$router->delete('{component}/delete', 'ComponentController@deleteComponentAction');
$router->post('{component}/edit', 'ComponentController@updateComponentAction');
});
$router->group(['as' => 'incidents.', 'prefix' => 'incidents'], function (Registrar $router) {
$router->get('/', [
'as' => 'index',
'uses' => 'IncidentController@showIncidents',
]);
$router->get('add', [
'as' => 'add',
'uses' => 'IncidentController@showAddIncident',
]);
$router->post('add', 'IncidentController@createIncidentAction');
$router->delete('{incident}/delete', [
'as' => 'delete',
'uses' => 'IncidentController@deleteIncidentAction',
]);
$router->get('{incident}/edit', [
'as' => 'edit',
'uses' => 'IncidentController@showEditIncidentAction',
]);
$router->post('{incident}/edit', 'IncidentController@editIncidentAction');
});
$router->group(['as' => 'schedule.', 'prefix' => 'schedule'], function (Registrar $router) {
$router->get('/', [
'as' => 'index',
'uses' => 'ScheduleController@showIndex',
]);
$router->get('add', [
'as' => 'add',
'uses' => 'ScheduleController@showAddSchedule',
]);
$router->post('add', 'ScheduleController@addScheduleAction');
$router->get('{incident}/edit', [
'as' => 'edit',
'uses' => 'ScheduleController@showEditSchedule',
]);
$router->post('{incident}/edit', 'ScheduleController@editScheduleAction');
$router->delete('{incident}/delete', [
'as' => 'delete',
'uses' => 'ScheduleController@deleteScheduleAction',
]);
});
$router->group(['as' => 'templates.', 'prefix' => 'templates'], function (Registrar $router) {
$router->get('/', [
'as' => 'index',
'uses' => 'IncidentController@showTemplates',
]);
$router->get('add', [
'as' => 'add',
'uses' => 'IncidentController@showAddIncidentTemplate',
]);
$router->post('add', 'IncidentController@createIncidentTemplateAction');
$router->get('{incident_template}/edit', [
'as' => 'edit',
'uses' => 'IncidentController@showEditTemplateAction',
]);
$router->post('{incident_template}/edit', 'IncidentController@editTemplateAction');
$router->delete('{incident_template}/delete', 'IncidentController@deleteTemplateAction');
});
$router->group(['as' => 'subscribers.', 'prefix' => 'subscribers'], function (Registrar $router) {
$router->get('/', [
'as' => 'index',
'uses' => 'SubscriberController@showSubscribers',
]);
$router->get('add', [
'as' => 'add',
'uses' => 'SubscriberController@showAddSubscriber',
]);
$router->post('add', 'SubscriberController@createSubscriberAction');
$router->delete('{subscriber}/delete', 'SubscriberController@deleteSubscriberAction');
});
$router->group(['as' => 'metrics.', 'prefix' => 'metrics'], function (Registrar $router) {
$router->get('/', [
'as' => 'index',
'uses' => 'MetricController@showMetrics',
]);
$router->get('add', [
'as' => 'add',
'uses' => 'MetricController@showAddMetric',
]);
$router->post('add', 'MetricController@createMetricAction');
$router->delete('{metric}/delete', 'MetricController@deleteMetricAction');
$router->get('{metric}/edit', [
'as' => 'edit',
'uses' => 'MetricController@showEditMetricAction',
]);
$router->post('{metric}/edit', 'MetricController@editMetricAction');
});
$router->group(['as' => 'team.', 'prefix' => 'team'], function (Registrar $router) {
$router->get('/', [
'as' => 'index',
'uses' => 'TeamController@showTeamView',
'uses' => 'DashboardController@showDashboard',
]);
$router->group(['middleware' => 'admin'], function (Registrar $router) {
$router->group(['as' => 'components.', 'prefix' => 'components'], function (Registrar $router) {
$router->get('/', [
'as' => 'index',
'uses' => 'ComponentController@showComponents',
]);
$router->get('add', [
'as' => 'add',
'uses' => 'TeamController@showAddTeamMemberView',
'uses' => 'ComponentController@showAddComponent',
]);
$router->get('invite', [
'as' => 'invite',
'uses' => 'TeamController@showInviteTeamMemberView',
$router->post('add', 'ComponentController@createComponentAction');
$router->get('groups', [
'as' => 'groups',
'uses' => 'ComponentController@showComponentGroups',
]);
$router->get('{user}', ['as' => 'edit', 'uses' => 'TeamController@showTeamMemberView']);
$router->post('add', 'TeamController@postAddUser');
$router->post('invite', 'TeamController@postInviteUser');
$router->post('{user}', 'TeamController@postUpdateUser');
$router->delete('{user}/delete', 'TeamController@deleteUser');
$router->get('groups/add', [
'as' => 'groups.add',
'uses' => 'ComponentController@showAddComponentGroup',
]);
$router->get('groups/edit/{component_group}', [
'as' => '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->get('{component}/edit', [
'as' => 'edit',
'uses' => 'ComponentController@showEditComponent',
]);
$router->delete('{component}/delete', 'ComponentController@deleteComponentAction');
$router->post('{component}/edit', 'ComponentController@updateComponentAction');
});
});
$router->group(['as' => 'settings.', 'prefix' => 'settings'], function (Registrar $router) {
$router->get('setup', [
'as' => 'setup',
'uses' => 'SettingsController@showSetupView',
]);
$router->get('analytics', [
'as' => 'analytics',
'uses' => 'SettingsController@showAnalyticsView',
]);
$router->get('localization', [
'as' => 'localization',
'uses' => 'SettingsController@showLocalizationView',
]);
$router->get('security', [
'as' => 'security',
'uses' => 'SettingsController@showSecurityView',
]);
$router->get('theme', [
'as' => 'theme',
'uses' => 'SettingsController@showThemeView',
]);
$router->get('stylesheet', [
'as' => 'stylesheet',
'uses' => 'SettingsController@showStylesheetView',
]);
$router->get('customization', [
'as' => 'customization',
'uses' => 'SettingsController@showCustomizationView',
]);
$router->post('/', 'SettingsController@postSettings');
});
$router->group(['as' => 'incidents.', 'prefix' => 'incidents'], function (Registrar $router) {
$router->get('/', [
'as' => 'index',
'uses' => 'IncidentController@showIncidents',
]);
$router->get('add', [
'as' => 'add',
'uses' => 'IncidentController@showAddIncident',
]);
$router->post('add', 'IncidentController@createIncidentAction');
$router->delete('{incident}/delete', [
'as' => 'delete',
'uses' => 'IncidentController@deleteIncidentAction',
]);
$router->get('{incident}/edit', [
'as' => 'edit',
'uses' => 'IncidentController@showEditIncidentAction',
]);
$router->post('{incident}/edit', 'IncidentController@editIncidentAction');
});
$router->group(['prefix' => 'user'], function (Registrar $router) {
$router->get('/', [
'as' => 'user',
'uses' => 'UserController@showUser',
]);
$router->post('/', 'UserController@postUser');
$router->get('{user}/api/regen', 'UserController@regenerateApiKey');
});
$router->group(['as' => 'schedule.', 'prefix' => 'schedule'], function (Registrar $router) {
$router->get('/', [
'as' => 'index',
'uses' => 'ScheduleController@showIndex',
]);
$router->get('add', [
'as' => 'add',
'uses' => 'ScheduleController@showAddSchedule',
]);
$router->post('add', 'ScheduleController@addScheduleAction');
$router->get('{incident}/edit', [
'as' => 'edit',
'uses' => 'ScheduleController@showEditSchedule',
]);
$router->post('{incident}/edit', 'ScheduleController@editScheduleAction');
$router->delete('{incident}/delete', [
'as' => 'delete',
'uses' => 'ScheduleController@deleteScheduleAction',
]);
});
$router->group(['prefix' => 'api'], function (Registrar $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');
$router->get('system/version', 'ApiController@checkVersion');
$router->group(['as' => 'templates.', 'prefix' => 'templates'], function (Registrar $router) {
$router->get('/', [
'as' => 'index',
'uses' => 'IncidentController@showTemplates',
]);
$router->get('add', [
'as' => 'add',
'uses' => 'IncidentController@showAddIncidentTemplate',
]);
$router->post('add', 'IncidentController@createIncidentTemplateAction');
$router->get('{incident_template}/edit', [
'as' => 'edit',
'uses' => 'IncidentController@showEditTemplateAction',
]);
$router->post('{incident_template}/edit', 'IncidentController@editTemplateAction');
$router->delete('{incident_template}/delete', 'IncidentController@deleteTemplateAction');
});
$router->group(['as' => 'subscribers.', 'prefix' => 'subscribers'], function (Registrar $router) {
$router->get('/', [
'as' => 'index',
'uses' => 'SubscriberController@showSubscribers',
]);
$router->get('add', [
'as' => 'add',
'uses' => 'SubscriberController@showAddSubscriber',
]);
$router->post('add', 'SubscriberController@createSubscriberAction');
$router->delete('{subscriber}/delete', 'SubscriberController@deleteSubscriberAction');
});
$router->group(['as' => 'metrics.', 'prefix' => 'metrics'], function (Registrar $router) {
$router->get('/', [
'as' => 'index',
'uses' => 'MetricController@showMetrics',
]);
$router->get('add', [
'as' => 'add',
'uses' => 'MetricController@showAddMetric',
]);
$router->post('add', 'MetricController@createMetricAction');
$router->delete('{metric}/delete', 'MetricController@deleteMetricAction');
$router->get('{metric}/edit', [
'as' => 'edit',
'uses' => 'MetricController@showEditMetricAction',
]);
$router->post('{metric}/edit', 'MetricController@editMetricAction');
});
$router->group(['as' => 'team.', 'prefix' => 'team'], function (Registrar $router) {
$router->get('/', [
'as' => 'index',
'uses' => 'TeamController@showTeamView',
]);
$router->group(['middleware' => 'admin'], function (Registrar $router) {
$router->get('add', [
'as' => 'add',
'uses' => 'TeamController@showAddTeamMemberView',
]);
$router->get('invite', [
'as' => 'invite',
'uses' => 'TeamController@showInviteTeamMemberView',
]);
$router->get('{user}', ['as' => 'edit', 'uses' => 'TeamController@showTeamMemberView']);
$router->post('add', 'TeamController@postAddUser');
$router->post('invite', 'TeamController@postInviteUser');
$router->post('{user}', 'TeamController@postUpdateUser');
$router->delete('{user}/delete', 'TeamController@deleteUser');
});
});
$router->group(['as' => 'settings.', 'prefix' => 'settings'], function (Registrar $router) {
$router->get('setup', [
'as' => 'setup',
'uses' => 'SettingsController@showSetupView',
]);
$router->get('analytics', [
'as' => 'analytics',
'uses' => 'SettingsController@showAnalyticsView',
]);
$router->get('localization', [
'as' => 'localization',
'uses' => 'SettingsController@showLocalizationView',
]);
$router->get('security', [
'as' => 'security',
'uses' => 'SettingsController@showSecurityView',
]);
$router->get('theme', [
'as' => 'theme',
'uses' => 'SettingsController@showThemeView',
]);
$router->get('stylesheet', [
'as' => 'stylesheet',
'uses' => 'SettingsController@showStylesheetView',
]);
$router->get('customization', [
'as' => 'customization',
'uses' => 'SettingsController@showCustomizationView',
]);
$router->get('credits', [
'as' => 'credits',
'uses' => 'SettingsController@showCreditsView',
]);
$router->post('/', 'SettingsController@postSettings');
});
$router->group(['prefix' => 'user'], function (Registrar $router) {
$router->get('/', [
'as' => 'user',
'uses' => 'UserController@showUser',
]);
$router->post('/', 'UserController@postUser');
$router->get('{user}/api/regen', 'UserController@regenerateApiKey');
});
$router->group(['prefix' => 'api'], function (Registrar $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

@@ -17,6 +17,7 @@ use Illuminate\Contracts\Routing\Registrar;
* This is the setup routes class.
*
* @author James Brooks <james@alt-three.com>
* @author Graham Campbell <graham@alt-three.com>
*/
class SetupRoutes
{
@@ -30,7 +31,10 @@ class SetupRoutes
public function map(Registrar $router)
{
$router->group(['middleware' => ['web', 'setup']], function (Registrar $router) {
$router->controller('setup', 'SetupController');
$router->get('setup', 'SetupController@getIndex');
$router->post('setup/step1', 'SetupController@postStep1');
$router->post('setup/step2', 'SetupController@postStep2');
$router->post('setup/step3', 'SetupController@postStep3');
});
}
}

View File

@@ -44,6 +44,11 @@ class SubscribeRoutes
'uses' => 'SubscribeController@showManage',
]);
$router->post('subscribe/manage/{code}', [
'as' => 'manage',
'uses' => 'SubscribeController@postManage',
]);
$router->get('subscribe/verify/{code}', [
'as' => 'verify',
'uses' => 'SubscribeController@getVerify',

View File

@@ -0,0 +1,27 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Integrations\Contracts;
/**
* This is the system interface.
*
* @author James Brooks <james@alt-three.com>
*/
interface System
{
/**
* Get the entire system status.
*
* @return array
*/
public function getStatus();
}

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\Integrations\Core;
use CachetHQ\Cachet\Integrations\Contracts\System as SystemContract;
use CachetHQ\Cachet\Models\Component;
use CachetHQ\Cachet\Models\Incident;
/**
* This is the core system class.
*
* @author James Brooks <james@alt-three.com>
*/
class System implements SystemContract
{
/**
* Get the entire system status.
*
* @return array
*/
public function getStatus()
{
$enabledScope = Component::enabled();
$totalComponents = Component::enabled()->count();
$majorOutages = Component::enabled()->status(4)->count();
$isMajorOutage = $totalComponents ? ($majorOutages / $totalComponents) >= 0.5 : false;
// Default data
$status = [
'system_status' => 'info',
'system_message' => trans_choice('cachet.service.bad', $totalComponents),
'favicon' => 'favicon-high-alert',
];
if ($isMajorOutage) {
$status = [
'system_status' => 'danger',
'system_message' => trans_choice('cachet.service.major', $totalComponents),
'favicon' => 'favicon-high-alert',
];
} elseif (Component::enabled()->notStatus(1)->count() === 0) {
// If all our components are ok, do we have any non-fixed incidents?
$incidents = Incident::notScheduled()->orderBy('created_at', 'desc')->get()->filter(function ($incident) {
return $incident->status > 0;
});
$incidentCount = $incidents->count();
if ($incidentCount === 0 || ($incidentCount >= 1 && (int) $incidents->first()->status === 4)) {
$status = [
'system_status' => 'success',
'system_message' => trans_choice('cachet.service.good', $totalComponents),
'favicon' => 'favicon',
];
}
} elseif (Component::enabled()->whereIn('status', [2, 3])->count() > 0) {
$status['favicon'] = 'favicon-medium-alert';
}
return $status;
}
}

View File

@@ -0,0 +1,81 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Integrations;
use Exception;
use GuzzleHttp\Client;
use Illuminate\Contracts\Cache\Repository;
class Credits
{
/**
* The default url.
*
* @var string
*/
const URL = 'https://cachethq.io/credits';
/**
* The failed status indicator.
*
* @var int
*/
const FAILED = 1;
/**
* The cache repository instance.
*
* @var \Illuminate\Contracts\Cache\Repository
*/
protected $cache;
/**
* The url to use.
*
* @var string|null
*/
protected $url;
/**
* Creates a new credits instance.
*
* @param \Illuminate\Contracts\Cache\Repository $cache
* @param string|null $url
*
* @return void
*/
public function __construct(Repository $cache, $url = null)
{
$this->cache = $cache;
$this->url = $url ?: static::URL;
}
/**
* Returns the latest credits.
*
* @return array|null
*/
public function latest()
{
$result = $this->cache->remember('credits', 2880, function () {
try {
return json_decode((new Client())->get($this->url, [
'headers' => ['Accept' => 'application/json', 'User-Agent' => defined('CACHET_VERSION') ? 'cachet/'.constant('CACHET_VERSION') : 'cachet'],
])->getBody(), true);
} catch (Exception $e) {
return self::FAILED;
}
});
return $result === self::FAILED ? null : $result;
}
}

88
app/Integrations/Feed.php Normal file
View File

@@ -0,0 +1,88 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Integrations;
use Exception;
use GuzzleHttp\Client;
use Illuminate\Contracts\Cache\Repository;
/**
* This is the feed class.
*
* @author James Brooks <james@alt-three.com>
*/
class Feed
{
/**
* The default url.
*
* @var string
*/
const URL = 'https://blog.alt-three.com/tag/cachet/rss';
/**
* The failed status indicator.
*
* @var int
*/
const FAILED = 1;
/**
* The cache repository instance.
*
* @var \Illuminate\Contracts\Cache\Repository
*/
protected $cache;
/**
* The url to use.
*
* @var string|null
*/
protected $url;
/**
* Creates a new feed instance.
*
* @param \Illuminate\Contracts\Cache\Repository $cache
* @param string|null $url
*
* @return void
*/
public function __construct(Repository $cache, $url = null)
{
$this->cache = $cache;
$this->url = $url ?: static::URL;
}
/**
* Returns the latest entries.
*
* @return array|null
*/
public function latest()
{
$result = $this->cache->remember('feeds', 720, function () {
try {
$xml = simplexml_load_string((new Client())->get($this->url, [
'headers' => ['Accept' => 'application/rss+xml', 'User-Agent' => defined('CACHET_VERSION') ? 'cachet/'.constant('CACHET_VERSION') : 'cachet'],
])->getBody()->getContents(), null, LIBXML_NOCDATA);
return json_decode(json_encode($xml));
} catch (Exception $e) {
return self::FAILED;
}
});
return $result === self::FAILED ? null : $result;
}
}

View File

@@ -0,0 +1,95 @@
<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Integrations;
use GuzzleHttp\Client;
use Illuminate\Contracts\Cache\Repository;
class Releases
{
/**
* The default url.
*
* @var string
*/
const URL = 'https://api.github.com/repos/cachethq/cachet/releases/latest';
/**
* The failed status indicator.
*
* @var int
*/
const FAILED = 1;
/**
* The cache repository instance.
*
* @var \Illuminate\Contracts\Cache\Repository
*/
protected $cache;
/**
* The github authentication token.
*
* @var string|null
*/
protected $token;
/**
* The url to use.
*
* @var string|null
*/
protected $url;
/**
* Creates a new releases instance.
*
* @param \Illuminate\Contracts\Cache\Repository $cache
* @param string|null $token
* @param string|null $url
*
* @return void
*/
public function __construct(Repository $cache, $token = null, $url = null)
{
$this->cache = $cache;
$this->token = $token;
$this->url = $url ?: static::URL;
}
/**
* Returns the latest release.
*
* @return string
*/
public function latest()
{
$release = $this->cache->remember('release.latest', 720, function () {
$headers = ['Accept' => 'application/vnd.github.v3+json', 'User-Agent' => defined('CACHET_VERSION') ? 'cachet/'.constant('CACHET_VERSION') : 'cachet'];
if ($this->token) {
$headers['OAUTH-TOKEN'] = $this->token;
}
return json_decode((new Client())->get($this->url, [
'headers' => $headers,
])->getBody(), true);
});
return [
'tag_name' => $release['tag_name'],
'prelease' => $release['prerelease'],
'draft' => $release['draft'],
];
}
}

View File

@@ -22,7 +22,10 @@ use McCool\LaravelAutoPresenter\HasPresenter;
class Component extends Model implements HasPresenter
{
use SearchableTrait, SoftDeletes, SortableTrait, ValidatingTrait;
use SearchableTrait;
use SoftDeletes;
use SortableTrait;
use ValidatingTrait;
/**
* List of attributes that have default values.

View File

@@ -20,7 +20,9 @@ use McCool\LaravelAutoPresenter\HasPresenter;
class ComponentGroup extends Model implements HasPresenter
{
use SearchableTrait, SortableTrait, ValidatingTrait;
use SearchableTrait;
use SortableTrait;
use ValidatingTrait;
/**
* The model's attributes.
@@ -119,7 +121,7 @@ class ComponentGroup extends Model implements HasPresenter
*/
public function enabled_components()
{
return $this->components()->enabled();
return $this->components()->enabled()->orderBy('order');
}
/**

View File

@@ -16,13 +16,17 @@ use CachetHQ\Cachet\Models\Traits\SearchableTrait;
use CachetHQ\Cachet\Models\Traits\SortableTrait;
use CachetHQ\Cachet\Presenters\IncidentPresenter;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use McCool\LaravelAutoPresenter\HasPresenter;
class Incident extends Model implements HasPresenter
{
use SearchableTrait, SoftDeletes, SortableTrait, ValidatingTrait;
use SearchableTrait;
use SoftDeletes;
use SortableTrait;
use ValidatingTrait;
/**
* The attributes that should be casted to native types.
@@ -71,6 +75,7 @@ class Incident extends Model implements HasPresenter
*/
protected $searchable = [
'id',
'component_id',
'name',
'status',
'visible',
@@ -96,7 +101,7 @@ class Incident extends Model implements HasPresenter
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeVisible($query)
public function scopeVisible(Builder $query)
{
return $query->where('visible', 1);
}
@@ -108,9 +113,9 @@ class Incident extends Model implements HasPresenter
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeScheduled($query)
public function scopeScheduled(Builder $query)
{
return $query->where('status', 0)->where('scheduled_at', '>=', Carbon::now());
return $query->where('status', 0)->where('scheduled_at', '>=', Carbon::now()->toDateTimeString());
}
/**
@@ -120,10 +125,12 @@ class Incident extends Model implements HasPresenter
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeNotScheduled($query)
public function scopeNotScheduled(Builder $query)
{
return $query->where(function ($query) {
return $query->whereNull('scheduled_at')->orWhere('scheduled_at', '<=', Carbon::now());
return $query->where('status', '>', 0)->orWhere(function ($query) {
$query->where('status', 0)->where(function ($query) {
$query->whereNull('scheduled_at')->orWhere('scheduled_at', '<=', Carbon::now()->toDateTimeString());
});
});
}

View File

@@ -14,12 +14,14 @@ namespace CachetHQ\Cachet\Models;
use AltThree\Validator\ValidatingTrait;
use CachetHQ\Cachet\Models\Traits\SortableTrait;
use CachetHQ\Cachet\Presenters\MetricPresenter;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use McCool\LaravelAutoPresenter\HasPresenter;
class Metric extends Model implements HasPresenter
{
use SortableTrait, ValidatingTrait;
use SortableTrait;
use ValidatingTrait;
/**
* The calculation type of sum.
@@ -47,6 +49,8 @@ class Metric extends Model implements HasPresenter
'calc_type' => 0,
'places' => 2,
'default_view' => 1,
'threshold' => 5,
'order' => 0,
];
/**
@@ -61,6 +65,8 @@ class Metric extends Model implements HasPresenter
'calc_type' => 'int',
'places' => 'int',
'default_view' => 'int',
'threshold' => 'int',
'order' => 'int',
];
/**
@@ -77,6 +83,8 @@ class Metric extends Model implements HasPresenter
'calc_type',
'places',
'default_view',
'threshold',
'order',
];
/**
@@ -91,6 +99,8 @@ class Metric extends Model implements HasPresenter
'default_value' => 'numeric',
'places' => 'numeric|between:0,4',
'default_view' => 'numeric|between:0,3',
'threshold' => 'numeric|between:0,10',
'threshold' => 'int',
];
/**
@@ -104,6 +114,7 @@ class Metric extends Model implements HasPresenter
'display_chart',
'default_value',
'calc_type',
'order',
];
/**
@@ -116,6 +127,18 @@ class Metric extends Model implements HasPresenter
return $this->hasMany(MetricPoint::class, 'metric_id', 'id');
}
/**
* Scope metrics to those of which are displayable.
*
* @param \Illuminate\Database\Eloquent\Builder $query
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeDisplayable(Builder $query)
{
return $query->where('display_chart', 1);
}
/**
* Determines whether a chart should be shown.
*

View File

@@ -20,6 +20,16 @@ class MetricPoint extends Model implements HasPresenter
{
use ValidatingTrait;
/**
* The model's attributes.
*
* @var string[]
*/
protected $attributes = [
'value' => 0,
'counter' => 1,
];
/**
* The attributes that should be casted to native types.
*
@@ -27,7 +37,8 @@ class MetricPoint extends Model implements HasPresenter
*/
protected $casts = [
'metric_id' => 'int',
'value' => 'int',
'value' => 'float',
'counter' => 'int',
];
/**
@@ -35,7 +46,12 @@ class MetricPoint extends Model implements HasPresenter
*
* @var string[]
*/
protected $fillable = ['metric_id', 'value', 'created_at'];
protected $fillable = [
'metric_id',
'value',
'counter',
'created_at',
];
/**
* The validation rules.
@@ -53,7 +69,25 @@ class MetricPoint extends Model implements HasPresenter
*/
public function metric()
{
return $this->belongsTo(Metric::class, 'id', 'metric_id');
return $this->belongsTo(Metric::class);
}
/**
* Override the value attribute.
*
* @param mixed $value
*
* @return float
*/
public function getActiveValueAttribute($value)
{
if ($this->metric->calc_type === Metric::CALC_SUM) {
return round((float) $value * $this->counter, $this->metric->places);
} elseif ($this->metric->calc_type === Metric::CALC_AVG) {
return round((float) $value * $this->counter, $this->metric->places);
}
return round((float) $value, $this->metric->places);
}
/**

View File

@@ -30,6 +30,7 @@ class Subscriber extends Model implements HasPresenter
'email' => 'string',
'verify_code' => 'string',
'verified_at' => 'date',
'global' => 'bool',
];
/**
@@ -91,6 +92,33 @@ class Subscriber extends Model implements HasPresenter
return $query->whereNotNull('verified_at');
}
/**
* Scope global subscribers.
*
* @param \Illuminate\Database\Eloquent\Builder $query
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeIsGlobal(Builder $query)
{
return $query->where('global', true);
}
/**
* Finds all verified subscriptions for a component.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param int $component_id
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeForComponent(Builder $query, $component_id)
{
return $query->select('subscribers.*')
->join('subscriptions', 'subscribers.id', '=', 'subscriptions.subscriber_id')
->where('subscriptions.component_id', $component_id);
}
/**
* Determines if the subscriber is verified.
*

View File

@@ -107,7 +107,10 @@ class Subscription extends Model
{
return $query->select('subscriptions.*')
->join('subscribers', 'subscriptions.subscriber_id', '=', 'subscribers.id')
->where('component_id', $component_id)
->where(function ($query) {
$query->where('subscriptions.component_id', $component_id)
->orWhere('subscribers.global');
})
->whereNotNull('subscribers.verified_at');
}
}

View File

@@ -34,10 +34,11 @@ trait SearchableTrait
return $query;
}
if (!array_intersect(array_keys($search), $this->searchable)) {
$allowed_search = array_intersect_key($search, array_flip($this->searchable));
if (!$allowed_search) {
return $query;
}
return $query->where($search);
return $query->where($allowed_search);
}
}

View File

@@ -22,7 +22,9 @@ use Illuminate\Support\Facades\Hash;
class User extends Model implements AuthenticatableContract, CanResetPasswordContract
{
use Authenticatable, CanResetPassword, ValidatingTrait;
use Authenticatable;
use CanResetPassword;
use ValidatingTrait;
/**
* The admin level of user.
@@ -116,7 +118,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
*/
public function getGravatarAttribute($size = 200)
{
return sprintf('https://www.gravatar.com/avatar/%s?size=%d', md5($this->email), $size);
return sprintf('https://www.gravatar.com/avatar/%s?size=%d', md5(strtolower($this->email)), $size);
}
/**

View File

@@ -53,7 +53,7 @@ class ComponentPresenter extends BasePresenter implements Arrayable
*/
public function tags()
{
return $this->wrappedObject->tags->lists('name', 'slug');
return $this->wrappedObject->tags->pluck('name', 'slug');
}
/**

View File

@@ -19,6 +19,16 @@ class MetricPointPresenter extends BasePresenter implements Arrayable
{
use TimestampsTrait;
/**
* Show the actual calculated value; as per (value * counter).
*
* @return int
*/
public function calculated_value()
{
return $this->wrappedObject->value * $this->wrappedObject->counter;
}
/**
* Convert the presenter instance to an array.
*
@@ -27,8 +37,9 @@ class MetricPointPresenter extends BasePresenter implements Arrayable
public function toArray()
{
return array_merge($this->wrappedObject->toArray(), [
'created_at' => $this->created_at(),
'updated_at' => $this->updated_at(),
'created_at' => $this->created_at(),
'updated_at' => $this->updated_at(),
'calculated_value' => $this->calculated_value(),
]);
}
}

View File

@@ -28,17 +28,7 @@ class SubscriberPresenter extends BasePresenter implements Arrayable
*/
public function verified_at()
{
return app(DateFactory::class)->make($this->wrappedObject->verified_at)->toDateTimeString();
}
/**
* Present formatted subscribed date.
*
* @return string
*/
public function subscribed_at()
{
return ucfirst(app(DateFactory::class)->make($this->wrappedObject->subscribed_at)->format(Config::get('setting.incident_date_format', 'l jS F Y H:i:s')));
return ucfirst(app(DateFactory::class)->make($this->wrappedObject->verified_at)->format(Config::get('setting.incident_date_format', 'l jS F Y H:i:s')));
}
/**

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\Repositories\Metric;
use CachetHQ\Cachet\Models\Metric;
use Illuminate\Contracts\Config\Repository;
/**
* This is the abstract metric repository class.
*
* @author Jams Brooks <james@alt-three.com>
*/
abstract class AbstractMetricRepository
{
/**
* The illuminate config repository.
*
* @var \Illuminate\Contracts\Config\Repository
*/
protected $config;
/**
* The name of the metrics table.
*
* @var string
*/
protected $tableName;
/**
* Create a new abstract metric repository instance.
*
* @param \Illuminate\Contracts\Config\Repository $config
*
* @return void
*/
public function __construct(Repository $config)
{
$this->config = $config;
}
/**
* Get the table names prefix.
*
* @return string
*/
protected function getPrefix()
{
$driver = $this->config->get('database.default');
$connection = $this->config->get('database.connections.'.$driver);
$prefix = $connection['prefix'];
return $prefix;
}
/**
* Get the metrics table name.
*
* @return string
*/
protected function getTableName()
{
$prefix = $this->getPrefix();
return $prefix.'metrics';
}
/**
* Get the metric points table name.
*
* @return string
*/
protected function getMetricPointsTableName()
{
$prefix = $this->getPrefix();
return $prefix.'metric_points';
}
}

View File

@@ -105,7 +105,7 @@ class MetricRepository
$points = [];
$pointKey = $dateTime->format('jS M');
$pointKey = $dateTime->format('D jS M');
for ($i = 0; $i <= 7; $i++) {
$points[$pointKey] = $this->repository->getPointsForDayInWeek($metric, $i);

View File

@@ -16,7 +16,12 @@ use DateInterval;
use Illuminate\Support\Facades\DB;
use Jenssegers\Date\Date;
class MySqlRepository implements MetricInterface
/**
* This is the mysql repository class.
*
* @author James Brooks <james@alt-three.com>
*/
class MySqlRepository extends AbstractMetricRepository implements MetricInterface
{
/**
* Returns metrics for the last hour.
@@ -31,15 +36,23 @@ class MySqlRepository implements MetricInterface
{
$dateTime = (new Date())->sub(new DateInterval('PT'.$hour.'H'))->sub(new DateInterval('PT'.$minute.'M'));
$timeInterval = $dateTime->format('YmdHi');
$points = $metric->points()
->whereRaw('DATE_FORMAT(created_at, "%Y%m%d%H%i") = '.$timeInterval)
->groupBy(DB::raw('HOUR(created_at), MINUTE(created_at)'));
$metricPointsTableName = $this->getMetricPointsTableName();
if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) {
$value = $points->sum('value');
$queryType = 'SUM(mp.`value` * mp.`counter`) AS `value`';
} elseif ($metric->calc_type == Metric::CALC_AVG) {
$value = $points->avg('value');
$queryType = 'AVG(mp.`value` * mp.`counter`) AS `value`';
}
$value = 0;
$points = DB::select("SELECT {$queryType} FROM {$this->getTableName()} m INNER JOIN $metricPointsTableName mp ON m.id = mp.metric_id WHERE m.id = :metricId AND DATE_FORMAT(mp.`created_at`, '%Y%m%d%H%i') = :timeInterval GROUP BY HOUR(mp.`created_at`), MINUTE(mp.`created_at`)", [
'metricId' => $metric->id,
'timeInterval' => $timeInterval,
]);
if (isset($points[0]) && !($value = $points[0]->value)) {
$value = 0;
}
if ($value === 0 && $metric->default_value != $value) {
@@ -61,15 +74,23 @@ class MySqlRepository implements MetricInterface
{
$dateTime = (new Date())->sub(new DateInterval('PT'.$hour.'H'));
$hourInterval = $dateTime->format('YmdH');
$points = $metric->points()
->whereRaw('DATE_FORMAT(created_at, "%Y%m%d%H") = '.$hourInterval)
->groupBy(DB::raw('HOUR(created_at)'));
$metricPointsTableName = $this->getMetricPointsTableName();
if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) {
$value = $points->sum('value');
$queryType = 'SUM(mp.`value` * mp.`counter`) AS `value`';
} elseif ($metric->calc_type == Metric::CALC_AVG) {
$value = $points->avg('value');
$queryType = 'AVG(mp.`value` * mp.`counter`) AS `value`';
}
$value = 0;
$points = DB::select("SELECT {$queryType} FROM {$this->getTableName()} m INNER JOIN $metricPointsTableName mp ON m.id = mp.metric_id WHERE m.id = :metricId AND DATE_FORMAT(mp.`created_at`, '%Y%m%d%H') = :hourInterval GROUP BY HOUR(mp.`created_at`)", [
'metricId' => $metric->id,
'hourInterval' => $hourInterval,
]);
if (isset($points[0]) && !($value = $points[0]->value)) {
$value = 0;
}
if ($value === 0 && $metric->default_value != $value) {
@@ -89,16 +110,23 @@ class MySqlRepository implements MetricInterface
public function getPointsForDayInWeek(Metric $metric, $day)
{
$dateTime = (new Date())->sub(new DateInterval('P'.$day.'D'));
$points = $metric->points()
->whereRaw('created_at BETWEEN DATE_SUB(created_at, INTERVAL 1 WEEK) AND NOW()')
->whereRaw('DATE_FORMAT(created_at, "%Y%m%d") = '.$dateTime->format('Ymd'))
->groupBy(DB::raw('DATE_FORMAT(created_at, "%Y%m%d")'));
$metricPointsTableName = $this->getMetricPointsTableName();
if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) {
$value = $points->sum('value');
$queryType = 'SUM(mp.`value` * mp.`counter`) AS `value`';
} elseif ($metric->calc_type == Metric::CALC_AVG) {
$value = $points->avg('value');
$queryType = 'AVG(mp.`value` * mp.`counter`) AS `value`';
}
$value = 0;
$points = DB::select("SELECT {$queryType} FROM {$this->getTableName()} m INNER JOIN $metricPointsTableName mp ON m.id = mp.metric_id WHERE m.id = :metricId AND mp.`created_at` BETWEEN DATE_SUB(mp.`created_at`, INTERVAL 1 WEEK) AND DATE_ADD(NOW(), INTERVAL 1 DAY) AND DATE_FORMAT(mp.`created_at`, '%Y%m%d') = :timeInterval GROUP BY DATE_FORMAT(mp.`created_at`, '%Y%m%d')", [
'metricId' => $metric->id,
'timeInterval' => $dateTime->format('Ymd'),
]);
if (isset($points[0]) && !($value = $points[0]->value)) {
$value = 0;
}
if ($value === 0 && $metric->default_value != $value) {

View File

@@ -16,7 +16,12 @@ use DateInterval;
use Illuminate\Support\Facades\DB;
use Jenssegers\Date\Date;
class PgSqlRepository implements MetricInterface
/**
* This is the pgsql repository class.
*
* @author James Brooks <james@alt-three.com>
*/
class PgSqlRepository extends AbstractMetricRepository implements MetricInterface
{
/**
* Returns metrics for the last hour.
@@ -29,27 +34,26 @@ class PgSqlRepository implements MetricInterface
*/
public function getPointsLastHour(Metric $metric, $hour, $minute)
{
$metricPointsTableName = $this->getMetricPointsTableName();
$dateTime = (new Date())->sub(new DateInterval('PT'.$hour.'H'))->sub(new DateInterval('PT'.$minute.'M'));
$hourInterval = $dateTime->format('YmdHi');
// Default metrics calculations.
if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) {
$queryType = 'sum(metric_points.value)';
$queryType = "sum($metricPointsTableName.value * $metricPointsTableName.counter)";
} elseif ($metric->calc_type == Metric::CALC_AVG) {
$queryType = 'avg(metric_points.value)';
$queryType = "avg($metricPointsTableName.value * $metricPointsTableName.counter)";
} else {
$queryType = 'sum(metric_points.value)';
$queryType = "sum($metricPointsTableName.value * $metricPointsTableName.counter)";
}
$query = DB::select("select {$queryType} as aggregate FROM metrics JOIN metric_points ON metric_points.metric_id = metrics.id WHERE metrics.id = :metric_id AND to_char(metric_points.created_at, 'YYYYMMDDHH24MI') = :timestamp GROUP BY to_char(metric_points.created_at, 'HHMI')", [
'metric_id' => $metric->id,
'timestamp' => $hourInterval,
$value = 0;
$query = DB::select("select {$queryType} as value FROM {$this->getTableName()} m JOIN $metricPointsTableName ON $metricPointsTableName.metric_id = m.id WHERE m.id = :metricId AND to_char($metricPointsTableName.created_at, 'YYYYMMDDHH24MI') = :timeInterval GROUP BY to_char($metricPointsTableName.created_at, 'HHMI')", [
'metricId' => $metric->id,
'timeInterval' => $dateTime->format('YmdHi'),
]);
if (isset($query[0])) {
$value = $query[0]->aggregate;
} else {
$value = 0;
$value = $query[0]->value;
}
if ($value === 0 && $metric->default_value != $value) {
@@ -70,26 +74,25 @@ class PgSqlRepository implements MetricInterface
public function getPointsByHour(Metric $metric, $hour)
{
$dateTime = (new Date())->sub(new DateInterval('PT'.$hour.'H'));
$hourInterval = $dateTime->format('YmdH');
$metricPointsTableName = $this->getMetricPointsTableName();
// Default metrics calculations.
if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) {
$queryType = 'sum(metric_points.value)';
$queryType = "sum($metricPointsTableName.value * $metricPointsTableName.counter)";
} elseif ($metric->calc_type == Metric::CALC_AVG) {
$queryType = 'avg(metric_points.value)';
$queryType = "avg($metricPointsTableName.value * $metricPointsTableName.counter)";
} else {
$queryType = 'sum(metric_points.value)';
$queryType = "sum($metricPointsTableName.value * $metricPointsTableName.counter)";
}
$query = DB::select("select {$queryType} as aggregate FROM metrics JOIN metric_points ON metric_points.metric_id = metrics.id WHERE metric_points.metric_id = :metric_id AND to_char(metric_points.created_at, 'YYYYMMDDHH24') = :timestamp GROUP BY to_char(metric_points.created_at, 'H')", [
'metric_id' => $metric->id,
'timestamp' => $hourInterval,
$value = 0;
$query = DB::select("select {$queryType} as value FROM {$this->getTableName()} m JOIN $metricPointsTableName ON $metricPointsTableName.metric_id = m.id WHERE $metricPointsTableName.metric_id = :metricId AND to_char($metricPointsTableName.created_at, 'YYYYMMDDHH24') = :timeInterval GROUP BY to_char($metricPointsTableName.created_at, 'H')", [
'metricId' => $metric->id,
'timeInterval' => $dateTime->format('YmdH'),
]);
if (isset($query[0])) {
$value = $query[0]->aggregate;
} else {
$value = 0;
$value = $query[0]->value;
}
if ($value === 0 && $metric->default_value != $value) {
@@ -109,16 +112,22 @@ class PgSqlRepository implements MetricInterface
public function getPointsForDayInWeek(Metric $metric, $day)
{
$dateTime = (new Date())->sub(new DateInterval('P'.$day.'D'));
$points = $metric->points()
->whereRaw('created_at BETWEEN (created_at - interval \'1 week\') AND now()')
->whereRaw('to_char(created_at, \'YYYYMMDD\') = \''.$dateTime->format('Ymd').'\'')
->groupBy(DB::raw('to_char(created_at, \'YYYYMMDD\')'));
$metricPointsTableName = $this->getMetricPointsTableName();
if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) {
$value = $points->sum('value');
$queryType = 'sum(mp.value * mp.counter) AS value';
} elseif ($metric->calc_type == Metric::CALC_AVG) {
$value = $points->avg('value');
$queryType = 'avg(mp.value * mp.counter) AS value';
}
$value = 0;
$points = DB::select("SELECT {$queryType} FROM {$this->getTableName()} m INNER JOIN $metricPointsTableName mp ON m.id = mp.metric_id WHERE m.id = :metricId AND mp.created_at BETWEEN (mp.created_at - interval '1 week') AND (now() + interval '1 day') AND to_char(mp.created_at, 'YYYYMMDD') = :timeInterval GROUP BY to_char(mp.created_at, 'YYYYMMDD')", [
'metricId' => $metric->id,
'timeInterval' => $dateTime->format('Ymd'),
]);
if (isset($points[0]) && !($value = $points[0]->value)) {
$value = 0;
}
if ($value === 0 && $metric->default_value != $value) {

View File

@@ -16,7 +16,7 @@ use DateInterval;
use Illuminate\Support\Facades\DB;
use Jenssegers\Date\Date;
class SqliteRepository implements MetricInterface
class SqliteRepository extends AbstractMetricRepository implements MetricInterface
{
/**
* Returns metrics for the last hour.
@@ -30,16 +30,25 @@ class SqliteRepository implements MetricInterface
public function getPointsLastHour(Metric $metric, $hour, $minute)
{
$dateTime = (new Date())->sub(new DateInterval('PT'.$hour.'H'))->sub(new DateInterval('PT'.$minute.'M'));
$hourInterval = $dateTime->format('YmdHi');
$points = $metric->points()
->whereRaw('strftime("%Y%m%d%H%M", created_at) = "'.$hourInterval.'"')
->groupBy(DB::raw('strftime("%H%M", created_at)'));
$metricPointsTableName = $this->getMetricPointsTableName();
// Default metrics calculations.
if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) {
$value = $points->sum('value');
$queryType = "sum($metricPointsTableName.value * $metricPointsTableName.counter)";
} elseif ($metric->calc_type == Metric::CALC_AVG) {
$value = $points->avg('value');
$queryType = "avg($metricPointsTableName.value * $metricPointsTableName.counter)";
} else {
$queryType = "sum($metricPointsTableName.value * $metricPointsTableName.counter)";
}
$value = 0;
$query = DB::select("select {$queryType} as value FROM {$this->getTableName()} m JOIN $metricPointsTableName ON $metricPointsTableName.metric_id = m.id WHERE m.id = :metricId AND strftime('%Y%m%d%H%M', $metricPointsTableName.created_at) = :timeInterval GROUP BY strftime('%H%M', $metricPointsTableName.created_at)", [
'metricId' => $metric->id,
'timeInterval' => $dateTime->format('YmdHi'),
]);
if (isset($query[0])) {
$value = $query[0]->value;
}
if ($value === 0 && $metric->default_value != $value) {
@@ -60,16 +69,25 @@ class SqliteRepository implements MetricInterface
public function getPointsByHour(Metric $metric, $hour)
{
$dateTime = (new Date())->sub(new DateInterval('PT'.$hour.'H'));
$hourInterval = $dateTime->format('YmdH');
$points = $metric->points()
->whereRaw('strftime("%Y%m%d%H", created_at) = "'.$hourInterval.'"')
->groupBy(DB::raw('strftime("%H", created_at)'));
$metricPointsTableName = $this->getMetricPointsTableName();
// Default metrics calculations.
if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) {
$value = $points->sum('value');
$queryType = "sum($metricPointsTableName.value * $metricPointsTableName.counter)";
} elseif ($metric->calc_type == Metric::CALC_AVG) {
$value = $points->avg('value');
$queryType = "avg($metricPointsTableName.value * $metricPointsTableName.counter)";
} else {
$queryType = "sum($metricPointsTableName.value * $metricPointsTableName.counter)";
}
$value = 0;
$query = DB::select("select {$queryType} as value FROM {$this->getTableName()} m JOIN $metricPointsTableName ON $metricPointsTableName.metric_id = m.id WHERE m.id = :metricId AND strftime('%Y%m%d%H', $metricPointsTableName.created_at) = :timeInterval GROUP BY strftime('%H', $metricPointsTableName.created_at)", [
'metricId' => $metric->id,
'timeInterval' => $dateTime->format('YmdH'),
]);
if (isset($query[0])) {
$value = $query[0]->value;
}
if ($value === 0 && $metric->default_value != $value) {
@@ -89,16 +107,25 @@ class SqliteRepository implements MetricInterface
public function getPointsForDayInWeek(Metric $metric, $day)
{
$dateTime = (new Date())->sub(new DateInterval('P'.$day.'D'));
$metricPointsTableName = $this->getMetricPointsTableName();
$points = $metric->points()
->whereRaw('created_at > date("now", "-7 day")')
->whereRaw('strftime("%Y%m%d", created_at) = "'.$dateTime->format('Ymd').'"')
->groupBy(DB::raw('strftime("%Y%m%d", created_at)'));
// Default metrics calculations.
if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) {
$value = $points->sum('value');
$queryType = "sum($metricPointsTableName.value * $metricPointsTableName.counter)";
} elseif ($metric->calc_type == Metric::CALC_AVG) {
$value = $points->avg('value');
$queryType = "avg($metricPointsTableName.value * $metricPointsTableName.counter)";
} else {
$queryType = "sum($metricPointsTableName.value * $metricPointsTableName.counter)";
}
$value = 0;
$query = DB::select("select {$queryType} as value FROM {$this->getTableName()} m JOIN $metricPointsTableName ON $metricPointsTableName.metric_id = m.id WHERE m.id = :metricId AND $metricPointsTableName.created_at > date('now', '-7 day') AND strftime('%Y%m%d', $metricPointsTableName.created_at) = :timeInterval GROUP BY strftime('%Y%m%d', $metricPointsTableName.created_at)", [
'metricId' => $metric->id,
'timeInterval' => $dateTime->format('Ymd'),
]);
if (isset($query[0])) {
$value = $query[0]->value;
}
if ($value === 0 && $metric->default_value != $value) {

103
app/Settings/Cache.php Normal file
View File

@@ -0,0 +1,103 @@
<?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\Settings;
use Exception;
use Illuminate\Filesystem\Filesystem;
/**
* This is the settings cache class.
*
* @author Graham Campbell <graham@alt-three.com>
* @author James Brooks <james@alt-three.com>
*/
class Cache
{
/**
* The filesystem instance.
*
* @var \Illuminate\Filesystem\Filesystem
*/
protected $files;
/**
* Is path to the setting cache.
*
* @var string
*/
protected $path;
/**
* Create a new settings cache instance.
*
* @param \Illuminate\Filesystem\Filesystem $files
* @param string $path
*
* @return void
*/
public function __construct(Filesystem $files, $path)
{
$this->files = $files;
$this->path = $path;
}
/**
* Store the settings in the cache.
*
* @param string $env
* @param array $data
*
* @return void
*/
public function store($env, array $data)
{
$this->files->put($this->path($env), '<?php return '.var_export($data, true).';'.PHP_EOL);
}
/**
* Load the settings from the cache.
*
* @param string $env
*
* @return array|false
*/
public function load($env)
{
try {
return $this->files->getRequire($this->path($env));
} catch (Exception $e) {
return false;
}
}
/**
* Clear the settings cache.
*
* Note that we're careful not to remove the .gitignore file.
*
* @return void
*/
public function clear()
{
$this->files->delete($this->files->allFiles($this->path));
}
/**
* Returns the settings cache path.
*
* @return string
*/
protected function path($env)
{
return "{$this->path}/{$env}.php";
}
}

View File

@@ -9,10 +9,16 @@
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Config;
namespace CachetHQ\Cachet\Settings;
use CachetHQ\Cachet\Models\Setting;
/**
* This is the settings repository class.
*
* @author Graham Campbell <graham@alt-three.com>
* @author James Brooks <james@alt-three.com>
*/
class Repository
{
/**
@@ -30,7 +36,7 @@ class Repository
protected $stale = false;
/**
* Create a new settings service instance.
* Create a new settings repository instance.
*
* @param \CachetHQ\Cachet\Models\Setting $model
*
@@ -84,6 +90,18 @@ class Repository
$this->model->where('name', $name)->delete();
}
/**
* Clear all settings.
*
* @return void
*/
public function clear()
{
$this->stale = true;
$this->model->query()->delete();
}
/**
* Is the config state stale?
*

View File

@@ -0,0 +1,110 @@
<?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\Subscribers;
use CachetHQ\Cachet\Settings\Cache;
use Carbon\Carbon;
use Exception;
use Illuminate\Console\Command;
use Illuminate\Contracts\Config\Repository;
use Illuminate\Contracts\Events\Dispatcher;
/**
* This is the command subscriber class.
*
* @author James Brooks <james@alt-three.com>
* @author Graham Campbell <graham@alt-three.com>
*/
class CommandSubscriber
{
/**
* The settings cache instance.
*
* @var \CachetHQ\Cachet\Settings\Cache
*/
protected $cache;
/**
* The config repository instance.
*
* @var \Illuminate\Contracts\Config\Repository
*/
protected $config;
/**
* Create a new command subscriber instance.
*
* @param \CachetHQ\Cachet\Settings\Cache $cache
* @param \Illuminate\Contracts\Config\Repository $config
*
* @return void
*/
public function __construct(Cache $cache, Repository $config)
{
$this->cache = $cache;
$this->config = $config;
}
/**
* Register the listeners for the subscriber.
*
* @param \Illuminate\Contracts\Events\Dispatcher $events
*
* @return void
*/
public function subscribe(Dispatcher $events)
{
$events->listen('command.installing', __CLASS__.'@fire', 5);
$events->listen('command.updating', __CLASS__.'@fire', 5);
$events->listen('command.resetting', __CLASS__.'@fire', 5);
}
/**
* Clear the settings cache, and backup the databases.
*
* @param \Illuminate\Console\Command $command
*
* @return void
*/
public function fire(Command $command)
{
$command->line('Clearing settings cache...');
$this->cache->clear();
$command->line('Settings cache cleared!');
// SQLite does not backup.
if ($this->config->get('database.default') === 'sqlite') {
$command->line('Backup skipped: SQLite is not supported.');
return;
}
$command->line('Backing up database...');
try {
$command->call('db:backup', [
'--compression' => 'gzip',
'--database' => $this->config->get('database.default'),
'--destination' => 'local',
'--destinationPath' => Carbon::now()->format('Y-m-d H.i.s'),
'--no-interaction' => true,
]);
} catch (Exception $e) {
$command->error($e->getMessage());
$command->line('Backup skipped!');
}
$command->line('Backup completed!');
}
}

View File

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

0
bootstrap/cache/.gitignore vendored Executable file → Normal file
View File

2
bootstrap/cachet/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*
!.gitignore

View File

@@ -1,23 +0,0 @@
{
"name": "Cachet",
"dependencies": {
"animate-sass": "~0.6",
"autosize": "~3.0.15",
"bootstrap-sass": "~3.3",
"chartjs": "~2.0.2",
"eonasdan-bootstrap-datetimepicker": "~3.1",
"humane-js": "~3.2",
"ionicons": "~2.0",
"jquery": "~2.2",
"jquery-minicolors": "~2.2",
"jquery-serialize-object": "~2.5",
"jquery-sparkline": "~2.1",
"livestampjs": "~1.1",
"lodash": "~4.5.1",
"messenger": "~1.4",
"moment": "~2.11.2",
"Sortable": "~1.4",
"sweetalert": "~1.1",
"github-markdown-css": "^2.2.1"
}
}

View File

@@ -20,31 +20,38 @@
],
"require": {
"php": ">=5.5.9",
"laravel/framework": "5.2.37",
"alt-three/badger": "^3.0",
"alt-three/bus": "^1.0",
"alt-three/emoji": "^3.0",
"alt-three/validator": "^1.4",
"ext-xml": "*",
"alt-three/badger": "^3.1",
"alt-three/bus": "^1.1",
"alt-three/emoji": "^3.1",
"alt-three/throttle": "^1.0",
"alt-three/validator": "^1.5",
"aws/aws-sdk-php": "^3.7",
"backup-manager/laravel": "dev-master#df53f9c9d8c6be5d7a2638f45d54b8fb7bc51e2b",
"barryvdh/laravel-cors": "^0.8",
"doctrine/dbal": "^2.5",
"fedeisas/laravel-mail-css-inliner": "^1.5",
"fideloper/proxy": "^3.1",
"graham-campbell/binput": "^3.3",
"graham-campbell/core": "^4.2",
"graham-campbell/markdown": "^6.0",
"graham-campbell/exceptions": "^8.3",
"guzzlehttp/guzzle": "^6.2",
"jenssegers/date": "^3.1",
"mccool/laravel-auto-presenter": "^4.2",
"graham-campbell/binput": "^3.4",
"graham-campbell/core": "^5.1",
"graham-campbell/exceptions": "^9.4",
"graham-campbell/markdown": "^6.1",
"guzzlehttp/guzzle": "6.3.3",
"guzzlehttp/psr7": "1.4.2",
"jenssegers/date": "^3.2",
"laravel/framework": "5.2.39",
"mccool/laravel-auto-presenter": "^4.3",
"pragmarx/google2fa": "^0.7.1",
"predis/predis": "^1.1",
"rcrowe/twigbridge": "^0.9.2",
"roumen/feed": "^2.10.3"
"roumen/feed": "^2.10.4"
},
"require-dev": {
"alt-three/testbench": "^1.1",
"filp/whoops": "^2.0",
"fzaninotto/faker": "^1.5",
"alt-three/testbench": "^1.7",
"filp/whoops": "^2.1",
"fzaninotto/faker": "^1.6",
"graham-campbell/testbench-core": "^1.1",
"mockery/mockery": "0.9.5",
"mockery/mockery": "0.9.9",
"phpunit/phpunit": "4.8.21",
"symfony/css-selector": "^3.0",
"symfony/dom-crawler": "^3.0"
@@ -54,7 +61,7 @@
"database"
],
"files": [
"app/Http/helpers.php"
"app/helpers.php"
],
"psr-4": {
"CachetHQ\\Cachet\\": "app/"
@@ -94,7 +101,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
"dev-master": "2.3-dev"
}
},
"minimum-stability": "dev",

1786
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -162,7 +162,9 @@ return [
*/
'AltThree\Badger\BadgerServiceProvider',
'AltThree\Emoji\EmojiServiceProvider',
'BackupManager\Laravel\Laravel5ServiceProvider',
'Barryvdh\Cors\ServiceProvider',
'Fedeisas\LaravelMailCssInliner\LaravelMailCssInlinerServiceProvider',
'Fideloper\Proxy\TrustedProxyServiceProvider',
'GrahamCampbell\Binput\BinputServiceProvider',
'GrahamCampbell\Exceptions\ExceptionsServiceProvider',
@@ -180,9 +182,10 @@ return [
*/
'CachetHQ\Cachet\Foundation\Providers\AppServiceProvider',
'CachetHQ\Cachet\Foundation\Providers\ComposerServiceProvider',
'CachetHQ\Cachet\Foundation\Providers\ConsoleServiceProvider',
'CachetHQ\Cachet\Foundation\Providers\ConfigServiceProvider',
'CachetHQ\Cachet\Foundation\Providers\IntegrationServiceProvider',
'CachetHQ\Cachet\Foundation\Providers\EventServiceProvider',
'CachetHQ\Cachet\Foundation\Providers\GitHubServiceProvider',
'CachetHQ\Cachet\Foundation\Providers\RepositoryServiceProvider',
'CachetHQ\Cachet\Foundation\Providers\RouteServiceProvider',
@@ -231,8 +234,8 @@ return [
'Validator' => 'Illuminate\Support\Facades\Validator',
'View' => 'Illuminate\Support\Facades\View',
'Binput' => 'GrahamCampbell\Binput\Facades\Binput',
'Str' => 'Illuminate\Support\Str',
'Binput' => 'GrahamCampbell\Binput\Facades\Binput',
'Str' => 'Illuminate\Support\Str',
],

70
config/backup-manager.php Normal file
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.
*/
return [
'local' => [
'type' => 'Local',
'root' => database_path('backups'),
],
's3' => [
'type' => 'AwsS3',
'key' => '',
'secret' => '',
'region' => 'us-east-1',
'bucket' => '',
'root' => '',
],
'gcs' => [
'type' => 'Gcs',
'key' => '',
'secret' => '',
'bucket' => '',
'root' => '',
],
'rackspace' => [
'type' => 'Rackspace',
'username' => '',
'key' => '',
'container' => '',
'zone' => '',
'endpoint' => 'https://identity.api.rackspacecloud.com/v2.0/',
'root' => '',
],
'dropbox' => [
'type' => 'Dropbox',
'token' => '',
'key' => '',
'secret' => '',
'app' => '',
'root' => '',
],
'ftp' => [
'type' => 'Ftp',
'host' => '',
'username' => '',
'password' => '',
'port' => 21,
'passive' => true,
'ssl' => true,
'timeout' => 30,
'root' => '',
],
'sftp' => [
'type' => 'Sftp',
'host' => '',
'username' => '',
'password' => '',
'port' => 21,
'timeout' => 10,
'privateKey' => '',
'root' => '',
],
];

41
config/css-inliner.php Normal file
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.
*/
return [
/*
|--------------------------------------------------------------------------
| Strip styles
|--------------------------------------------------------------------------
|
| Settings this to false prevents the inliner from removing the style
| definitions that have been inlined.
|
| Notice that media query styles are not inlined, and hence never
| stripped.
|
*/
'strip-styles' => true,
/*
|--------------------------------------------------------------------------
| Remove classes
|--------------------------------------------------------------------------
|
| Settings this to false disables the removal of class attributes from
| your html elements (do not enable this if you use media queries)
|
*/
'strip-classes' => true,
];

View File

@@ -76,25 +76,25 @@ return [
],
'pgsql' => [
'driver' => 'pgsql',
'host' => env('DB_HOST', null),
'database' => env('DB_DATABASE', null),
'username' => env('DB_USERNAME', null),
'password' => env('DB_PASSWORD', null),
'port' => env('DB_PORT', '5432'),
'charset' => 'utf8',
'prefix' => env('DB_PREFIX', null),
'schema' => env('DB_SCHEMA', 'public'),
'driver' => 'pgsql',
'host' => env('DB_HOST', null),
'database' => env('DB_DATABASE', null),
'username' => env('DB_USERNAME', null),
'password' => env('DB_PASSWORD', null),
'port' => env('DB_PORT', '5432'),
'charset' => 'utf8',
'prefix' => env('DB_PREFIX', null),
'schema' => env('DB_SCHEMA', 'public'),
],
'sqlsrv' => [
'driver' => 'sqlsrv',
'host' => env('DB_HOST', null),
'database' => env('DB_DATABASE', null),
'username' => env('DB_USERNAME', null),
'password' => env('DB_PASSWORD', null),
'port' => env('DB_PORT', null),
'prefix' => env('DB_PREFIX', null),
'driver' => 'sqlsrv',
'host' => env('DB_HOST', null),
'database' => env('DB_DATABASE', null),
'username' => env('DB_USERNAME', null),
'password' => env('DB_PASSWORD', null),
'port' => env('DB_PORT', null),
'prefix' => env('DB_PREFIX', null),
],
],
@@ -131,6 +131,7 @@ return [
'host' => env('REDIS_HOST', '127.0.0.1'),
'port' => env('REDIS_PORT', 6379),
'database' => env('REDIS_DATABASE', 0),
'password' => env('REDIS_PASSWORD', null),
],
],

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