Compare commits

...

349 Commits
0.3 ... 4

Author SHA1 Message Date
github-actions 9b79699dcc Merge branch '4.7' into 4 2024-02-11 11:32:58 +00:00
Guy Sartorelli bb3eec1160
TLN Update translations (#223) 2024-02-07 16:03:34 +13:00
github-actions 5f04e466d2 Merge branch '4.7' into 4 2023-08-27 11:32:16 +00:00
Guy Sartorelli 20d61d7d87
ENH Update translations (#208) 2023-08-21 12:13:52 +12:00
Michal Kleiner b6ce505e12 Merge branch '4.7' into 4 2023-06-16 12:09:26 +12:00
Michal Kleiner 9fe83e948d
Merge pull request #201 from silverstripe/pulls/200-use-injector-for-task
MNT Use ::create to allow Injector to replace content review emails sending task
2023-06-16 12:02:44 +12:00
Michal Kleiner 2e22bd4900 MNT Use ::create to allow Injector to replace content review emails sending task 2023-06-16 11:46:30 +12:00
Michal Kleiner 32e7929f01 Merge branch '4.7' into 4 2023-06-16 11:10:50 +12:00
Michal Kleiner 27e0f8f517
Merge pull request #183 from sunnysideup/patch-1
MNT Add additional keywords to composer.json
2023-06-16 10:48:01 +12:00
Guy Sartorelli 72e4321696
Merge pull request #199 from creative-commoners/pulls/4.7/tx-1686724607
ENH Update translations
2023-06-15 10:06:32 +12:00
Steve Boyd b6e00e9528 ENH Update translations 2023-06-14 18:36:47 +12:00
Guy Sartorelli d13bebf999
Merge branch '4.7' into 4 2023-04-26 12:46:27 +12:00
Guy Sartorelli ad33d32066
Merge pull request #195 from creative-commoners/pulls/4.7/fix-broken-job-on-wrong-email
FIX Notification job marked as broken
2023-04-14 12:30:53 +12:00
Sabina Talipova c39e588306 FIX Notification job marked as broken 2023-04-14 12:22:23 +12:00
Guy Sartorelli f9dc2e537d
Merge pull request #192 from creative-commoners/pulls/4/fix-broken-job-on-wrong-email
FIX Notification job marked as broken
2023-04-14 09:40:47 +12:00
Sabina Talipova 36d3718581 ENH Add Exception with list of invilid emails 2023-04-13 10:13:08 +12:00
Sabina Talipova 24766e4e5a FIX Notification job marked as broken 2023-04-12 08:56:49 +12:00
Guy Sartorelli 77bb69f74c
MNT Revert erroneous dependency changes (#191) 2023-03-28 17:06:01 +13:00
Maxime Rainville b5e468a266
Merge pull request #190 from creative-commoners/pulls/4/dispatch-ci
MNT Use gha-dispatch-ci
2023-03-23 14:10:27 +13:00
Steve Boyd f1f6abca67 MNT Use gha-dispatch-ci 2023-03-21 12:23:51 +13:00
Nicolaas / Sunny Side Up 4324836cb7 MNT Add additional keywords to composer.json 2023-03-20 23:21:46 +13:00
Guy Sartorelli 47769763db
MNT Update development dependencies 2023-03-10 16:33:34 +13:00
Guy Sartorelli 884a846167
MNT Update release dependencies 2023-03-10 16:33:31 +13:00
Guy Sartorelli ff723b58ef
MNT Update development dependencies 2023-03-10 12:21:29 +13:00
Guy Sartorelli 18828ed094
Merge pull request #187 from creative-commoners/pulls/4/tx-1678079773
ENH Update translations
2023-03-08 10:25:08 +13:00
Steve Boyd e8a41d96e5 ENH Update translations 2023-03-06 18:16:13 +13:00
dependabot[bot] 179e9d0cf2
Merge pull request #180 from silverstripe/dependabot/npm_and_yarn/debug-2.6.9 2023-01-12 10:25:21 +00:00
dependabot[bot] 48c40a542e
Bump debug from 2.6.8 to 2.6.9
Bumps [debug](https://github.com/debug-js/debug) from 2.6.8 to 2.6.9.
- [Release notes](https://github.com/debug-js/debug/releases)
- [Changelog](https://github.com/debug-js/debug/blob/2.6.9/CHANGELOG.md)
- [Commits](https://github.com/debug-js/debug/compare/2.6.8...2.6.9)

---
updated-dependencies:
- dependency-name: debug
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-12 10:00:53 +00:00
dependabot[bot] 0b32166a1a
Merge pull request #177 from silverstripe/dependabot/npm_and_yarn/minimatch-3.0.8 2022-12-09 09:50:49 +00:00
dependabot[bot] 013a5c34e7
Bump minimatch from 3.0.4 to 3.0.8
Bumps [minimatch](https://github.com/isaacs/minimatch) from 3.0.4 to 3.0.8.
- [Release notes](https://github.com/isaacs/minimatch/releases)
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.0.4...v3.0.8)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-09 08:13:31 +00:00
dependabot[bot] fad0c2b4b4
Merge pull request #176 from silverstripe/dependabot/npm_and_yarn/qs-6.5.3 2022-12-09 08:12:59 +00:00
dependabot[bot] 63024cb902
Bump qs from 6.5.2 to 6.5.3
Bumps [qs](https://github.com/ljharb/qs) from 6.5.2 to 6.5.3.
- [Release notes](https://github.com/ljharb/qs/releases)
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ljharb/qs/compare/v6.5.2...v6.5.3)

---
updated-dependencies:
- dependency-name: qs
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-09 08:01:04 +00:00
Sabina Talipova a6c7030274
Merge pull request #174 from creative-commoners/pulls/4/stop-using-depr
API Stop using deprecated API
2022-12-05 16:34:50 +13:00
Steve Boyd 6f18e92169 API Stop using deprecated API 2022-11-24 13:04:34 +13:00
Guy Sartorelli 7eb81fd449
Merge pull request #172 from creative-commoners/pulls/4/review-behat-tests
ENH Replace ADMIN permissions with less permissions in Behat test
2022-09-16 10:46:30 +12:00
Sabina Talipova 495e7460db ENH Replace ADMIN permissions with less permissions in Behat test 2022-09-15 15:32:06 +12:00
Sabina Talipova 55d52cb7dc
Merge pull request #155 from creative-commoners/pulls/4.3/all-sections
FIX Allow users with the CMS_ACCESS_LeftAndMain permission to be added
2022-09-15 15:14:52 +12:00
Maxime Rainville dbd9099d3d
Merge pull request #170 from creative-commoners/pulls/4/fix-userdoc-deploy
MNT Fix github action for deploying userdocs
2022-08-24 11:29:09 +12:00
Guy Sartorelli 6f5edab1ad
MNT Fix github action for deploying userdocs 2022-08-23 15:24:27 +12:00
Guy Sartorelli 1123d26477
Merge pull request #169 from creative-commoners/pulls/4/userhelp-fix
DOC Correct title for userhelp
2022-08-22 11:04:27 +12:00
Maxime Rainville 566a9e7d0e DOC Correct title for userhelp 2022-08-20 20:58:19 +12:00
Steve Boyd 422647b724 Merge branch '4.5' into 4 2022-08-02 18:48:08 +12:00
Steve Boyd 774c8343c7 Merge branch '4.4' into 4.5 2022-08-02 18:48:04 +12:00
Guy Sartorelli 562e882072
Merge pull request #168 from creative-commoners/pulls/4.4/standardise-modules
MNT Standardise modules
2022-08-02 15:12:34 +12:00
Steve Boyd 9d4381554a MNT Standardise modules 2022-08-01 16:21:34 +12:00
Guy Sartorelli c5cd5c5ff3
Merge pull request #167 from creative-commoners/pulls/4/update-js
MNT Use up­date-js action
2022-07-29 17:03:59 +12:00
Steve Boyd 31c81bf093 MNT Use update-js action 2022-07-29 13:04:47 +12:00
Steve Boyd 675d094731 Merge branch '4.5' into 4 2022-07-25 11:23:19 +12:00
Steve Boyd 03ee0d0559 Merge branch '4.4' into 4.5 2022-07-25 11:23:06 +12:00
Guy Sartorelli e2bf86414e
Merge pull request #166 from creative-commoners/pulls/4.4/ci
MNT Use node 10
2022-07-20 09:39:30 +12:00
Steve Boyd 0dd255303d MNT Use node 10 2022-07-19 17:20:05 +12:00
Guy Sartorelli f93687a53d
Merge pull request #165 from creative-commoners/pulls/4.4/module-standards
MNT Use GitHub Actions CI
2022-07-15 11:31:29 +12:00
Steve Boyd 4cafa687ae MNT Use GitHub Actions CI 2022-07-08 12:00:12 +12:00
Mo Alsharaf 1cf0f01a35
NEW Allow for optional can permission method for content review (#152)
* Allow for optional can permission method for content review

* Content Review permission logic

With the new `canReviewContent()` permission checker we only need to check the permission is set for the user and `canBeReviewedBy()` will always check if the page object is due for review by its owner.

Thus removed redundant logic in `canUseReviewContent()` and accordingly renamed the class filename for additional context.

Co-authored-by: Jared Dreyer <jared.dreyer@silverstripe.com>
2022-06-22 12:25:59 +12:00
Steve Boyd c1c47583b1 Merge branch '4.5' into 4 2022-05-10 21:58:53 +12:00
Steve Boyd 3359ab477e Update translations 2022-05-04 13:29:41 +12:00
dependabot[bot] 917c63467e
Merge pull request #164 from silverstripe/dependabot/npm_and_yarn/async-2.6.4 2022-05-03 09:27:01 +00:00
dependabot[bot] 69cf355d9f
Bump async from 2.5.0 to 2.6.4
Bumps [async](https://github.com/caolan/async) from 2.5.0 to 2.6.4.
- [Release notes](https://github.com/caolan/async/releases)
- [Changelog](https://github.com/caolan/async/blob/v2.6.4/CHANGELOG.md)
- [Commits](https://github.com/caolan/async/compare/v2.5.0...v2.6.4)

---
updated-dependencies:
- dependency-name: async
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-28 21:09:32 +00:00
Guy Sartorelli 9f7b0e2169
Merge pull request #163 from creative-commoners/pulls/4/php81
ENH PHP 8.1 compatibility
2022-04-26 17:58:20 +12:00
Steve Boyd 856660192b ENH PHP 8.1 compatibility 2022-04-13 10:23:56 +12:00
Maxime Rainville 5e313dd7fc
Merge pull request #161 from creative-commoners/pulls/4/update-js-deps
MNT Add update JS deps workflow
2022-03-23 15:43:06 +13:00
Steve Boyd 3447883c3c MNT Add update JS deps workflow 2022-03-22 12:07:10 +13:00
Guy Sartorelli 141e8d0bf3
ENH: Respect sort and limit arguments (#158)
These parameters are defined in the PHPDocs for `Report` and are technically part of the method signature. They should be respected and in the case of the new default limit in silverstripe/silverstripe-reports#139 this could have performance ramifications for large datasets.
2022-03-11 09:14:06 +13:00
Maxime Rainville 46a637a6a8
Merge pull request #157 from creative-commoners/pulls/4/php74
DEP Set PHP 7.4 as the minimum version
2022-02-18 21:46:29 +13:00
Steve Boyd 7def6f8c2a DEP Set PHP 7.4 as the minimum version 2022-02-11 16:30:49 +13:00
Maxime Rainville 7fde3cf28a
Merge pull request #154 from creative-commoners/pulls/4.3/behat
MNT Update behat tests
2021-11-18 17:03:49 +13:00
Steve Boyd 3f21112947 MNT Revert workflow 2021-11-15 14:07:19 +13:00
Steve Boyd ee8c5d3f91 MNT Add CI workflow 2021-11-13 20:13:55 +13:00
Steve Boyd f816052f06 MNT Update behat tests 2021-11-12 18:24:50 +13:00
Maxime Rainville b544032a22
Merge pull request #156 from creative-commoners/pulls/4/sapphire-test-nine
API phpunit 9 support
2021-11-01 17:55:12 +13:00
Steve Boyd 89f58ec573 API phpunit 9 support 2021-11-01 14:35:22 +13:00
Steve Boyd a821edf8d7 FIX Allow users with the CMS_ACCESS_LeftAndMain permission to be added 2021-09-14 13:53:32 +12:00
dependabot[bot] b3d8f8817c
Merge pull request #119 from silverstripe/dependabot/npm_and_yarn/tar-2.2.2 2021-08-08 21:42:36 +00:00
dependabot[bot] 53209b99db
Bump tar from 2.2.1 to 2.2.2
Bumps [tar](https://github.com/npm/node-tar) from 2.2.1 to 2.2.2.
- [Release notes](https://github.com/npm/node-tar/releases)
- [Commits](https://github.com/npm/node-tar/compare/v2.2.1...v2.2.2)

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-08 15:48:24 +00:00
dependabot[bot] b3062f730b
Merge pull request #151 from silverstripe/dependabot/npm_and_yarn/ini-1.3.8 2021-08-08 15:47:39 +00:00
dependabot[bot] d47e361b29
Merge pull request #132 from silverstripe/dependabot/npm_and_yarn/node-sass-4.14.1 2021-08-08 15:47:30 +00:00
dependabot[bot] 21aebc40fe
Bump node-sass from 4.5.3 to 4.14.1
Bumps [node-sass](https://github.com/sass/node-sass) from 4.5.3 to 4.14.1.
- [Release notes](https://github.com/sass/node-sass/releases)
- [Changelog](https://github.com/sass/node-sass/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sass/node-sass/compare/v4.5.3...v4.14.1)

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-05 06:31:14 +00:00
dependabot[bot] aa019ea7ff
Bump ini from 1.3.4 to 1.3.8
Bumps [ini](https://github.com/isaacs/ini) from 1.3.4 to 1.3.8.
- [Release notes](https://github.com/isaacs/ini/releases)
- [Commits](https://github.com/isaacs/ini/compare/v1.3.4...v1.3.8)

---
updated-dependencies:
- dependency-name: ini
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-05 06:30:33 +00:00
dependabot[bot] 83d5efa50f
Merge pull request #144 from silverstripe/dependabot/npm_and_yarn/elliptic-6.5.4 2021-08-05 06:29:35 +00:00
dependabot[bot] d518cae006
Merge pull request #146 from silverstripe/dependabot/npm_and_yarn/ua-parser-js-0.7.28 2021-08-05 06:28:08 +00:00
dependabot[bot] aa93c7e661
Merge pull request #147 from silverstripe/dependabot/npm_and_yarn/hosted-git-info-2.8.9 2021-08-05 06:25:30 +00:00
dependabot[bot] b212d067f4
Merge pull request #148 from silverstripe/dependabot/npm_and_yarn/merge-1.2.1 2021-08-05 06:22:40 +00:00
Steve Boyd c15888277d Merge branch '4.2' into 4 2021-05-21 13:48:10 +12:00
Steve Boyd fa031262fb
Merge pull request #149 from dhensby/pull/135
Clear non-recurring custom date when reviewing
2021-05-17 10:30:58 +12:00
dependabot[bot] b93a050100
Merge pull request #141 from silverstripe/dependabot/npm_and_yarn/is-my-json-valid-2.20.5 2021-05-14 10:45:05 +00:00
Daniel Hensby c89a759af6
Add test 2021-05-14 11:15:09 +01:00
dependabot[bot] 63e500e083
Bump is-my-json-valid from 2.16.1 to 2.20.5
Bumps [is-my-json-valid](https://github.com/mafintosh/is-my-json-valid) from 2.16.1 to 2.20.5.
- [Release notes](https://github.com/mafintosh/is-my-json-valid/releases)
- [Commits](https://github.com/mafintosh/is-my-json-valid/compare/v2.16.1...v2.20.5)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-14 10:03:31 +00:00
Jules ebcfc483be
FIX: Clear non-recurring custom date when reviewing 2021-05-14 10:41:14 +01:00
dependabot[bot] 74945e0123
Merge pull request #145 from silverstripe/dependabot/npm_and_yarn/y18n-3.2.2 2021-05-14 09:39:54 +00:00
dependabot[bot] ce9ae1d0be
Bump merge from 1.2.0 to 1.2.1
Bumps [merge](https://github.com/yeikos/js.merge) from 1.2.0 to 1.2.1.
- [Release notes](https://github.com/yeikos/js.merge/releases)
- [Commits](https://github.com/yeikos/js.merge/compare/v1.2.0...v1.2.1)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-12 01:16:35 +00:00
dependabot[bot] 497e8eb6c5
Bump hosted-git-info from 2.5.0 to 2.8.9
Bumps [hosted-git-info](https://github.com/npm/hosted-git-info) from 2.5.0 to 2.8.9.
- [Release notes](https://github.com/npm/hosted-git-info/releases)
- [Changelog](https://github.com/npm/hosted-git-info/blob/v2.8.9/CHANGELOG.md)
- [Commits](https://github.com/npm/hosted-git-info/compare/v2.5.0...v2.8.9)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-10 15:40:44 +00:00
dependabot[bot] 9c4b5586fe
Bump ua-parser-js from 0.7.14 to 0.7.28
Bumps [ua-parser-js](https://github.com/faisalman/ua-parser-js) from 0.7.14 to 0.7.28.
- [Release notes](https://github.com/faisalman/ua-parser-js/releases)
- [Commits](https://github.com/faisalman/ua-parser-js/compare/0.7.14...0.7.28)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-07 01:56:06 +00:00
Maxime Rainville f3d7a396e3 MNT Remove obsolete branch-alias 2021-05-05 11:17:42 +12:00
dependabot[bot] 30cf99ebe2
Bump y18n from 3.2.1 to 3.2.2
Bumps [y18n](https://github.com/yargs/y18n) from 3.2.1 to 3.2.2.
- [Release notes](https://github.com/yargs/y18n/releases)
- [Changelog](https://github.com/yargs/y18n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yargs/y18n/commits)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-30 19:30:25 +00:00
dependabot[bot] 4944a14241
Bump elliptic from 6.4.0 to 6.5.4
Bumps [elliptic](https://github.com/indutny/elliptic) from 6.4.0 to 6.5.4.
- [Release notes](https://github.com/indutny/elliptic/releases)
- [Commits](https://github.com/indutny/elliptic/compare/v6.4.0...v6.5.4)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-09 09:35:32 +00:00
Steve Boyd c5f2b44895
Update build status badge 2021-01-21 16:32:51 +13:00
Garion Herman 2aa90feb32 Merge branch '4.1' into 4 2020-12-21 14:58:15 +13:00
Garion Herman d632359853
Merge pull request #138 from creative-commoners/pulls/4.1/travis-shared
MNT Travis shared config, use sminnee/phpunit
2020-12-21 14:54:46 +13:00
Steve Boyd 85e97a83ed MNT Travis shared config, use sminnee/phpunit 2020-12-15 13:54:35 +13:00
Robbie Averill b6a6b59aa8
Merge pull request #123 from creative-commoners/pulls/4/behat-fix
Fix failing behat test + update travis matrix
2020-01-29 17:18:07 +13:00
Steve Boyd ad22d6b805 Fix behat test and update travis matrix 2020-01-29 16:53:49 +13:00
Aaron Carlino 49ac8de8f0
META: Add new action to build docs 2019-12-19 13:44:37 +13:00
Robbie Averill 586fb516c6
Merge pull request #121 from silverstripe/dependabot/npm_and_yarn/jquery-3.4.0
Bump jquery from 3.2.1 to 3.4.0
2019-12-16 15:22:45 -08:00
dependabot[bot] 79f7ed77f8
Bump jquery from 3.2.1 to 3.4.0
Bumps [jquery](https://github.com/jquery/jquery) from 3.2.1 to 3.4.0.
- [Release notes](https://github.com/jquery/jquery/releases)
- [Commits](https://github.com/jquery/jquery/compare/3.2.1...3.4.0)

Signed-off-by: dependabot[bot] <support@github.com>
2019-12-14 02:48:34 +00:00
dependabot[bot] c22ef1c9e9
Merge pull request #111 from silverstripe/dependabot/npm_and_yarn/stringstream-0.0.6 2019-12-14 02:48:06 +00:00
dependabot[bot] 9180213d63
Bump stringstream from 0.0.5 to 0.0.6
Bumps [stringstream](https://github.com/mhart/StringStream) from 0.0.5 to 0.0.6.
- [Release notes](https://github.com/mhart/StringStream/releases)
- [Commits](https://github.com/mhart/StringStream/compare/v0.0.5...v0.0.6)

Signed-off-by: dependabot[bot] <support@github.com>
2019-12-14 01:59:58 +00:00
Robbie Averill 544571007b Merge branch '4.1' 2019-08-15 14:28:13 +12:00
Robbie Averill 5920058287 Update Travis to trusty and increase PHP memory limit 2019-08-15 13:53:00 +12:00
Robbie Averill c190330521 Merge branch '4.1' 2019-08-15 09:58:56 +12:00
Guy Marriott 3d00342ac2
Merge pull request #107 from creative-commoners/pulls/4.1/remove-json-methods
FIX Replace Convert JSON methods with json_* methods, deprecated from SilverStripe 4.4
2018-10-29 11:31:08 +13:00
Robbie Averill 6bc589c741 FIX Replace Convert JSON methods with json_* methods, deprecated from SilverStripe 4.4 2018-10-28 21:32:15 +00:00
Dylan Wagstaff 6bcf66c7d1
Merge pull request #106 from janzenz/patch-1
Prevent eslint rules from cascading.
2018-10-05 13:18:04 +13:00
Janzen Zarzoso 1bd0418b62
Prevent eslint rules from cascading.
This prevents eslint rules from cascading to the parent directory. This prevents the same issue on [ss-userforms](https://github.com/silverstripe/silverstripe-userforms/issues/819).
2018-10-05 12:05:28 +13:00
Robbie Averill 680d300e65 Merge branch '4.1' 2018-09-17 10:08:56 +02:00
Robbie Averill 188f77c569
Merge pull request #102 from pjayme/bugfix/ownergroups-check-before-method-call
BUGFIX: Error trying to access OwnerGroups() method on boolean value
2018-08-22 08:48:58 +12:00
pjayme d5b4fe1929 changed 'option' variable name to 'options' in places its used 2018-08-22 08:43:44 +12:00
pjayme 156a76a8e5 BUGFIX: Error trying to access OwnerGroups() method on boolean value 2018-08-22 08:20:36 +12:00
Robbie Averill cc4b6960e6
Merge pull request #101 from phalkunz/bugfix/page-check-before-method-call
BUGFIX: Error trying to OwnerGroups() method on boolean value
2018-08-21 09:50:43 +12:00
Saophalkun Ponlu 68b1616d22 BUGFIX: Error trying to OwnerGroups() method on boolean value
This issue occurs when a page has "Inherit from parent page" for content
review option and a review date, and its parent has "Disable content
review" for content review option.
2018-08-21 09:27:05 +12:00
Massey Isa'ako cf35e056b6 BUGFIX: Remove pages from content review email list, if a review log submitted after review date (#98) 2018-08-14 15:43:10 +12:00
Robbie Averill 051a945e7d Merge branch '4.1' 2018-08-14 15:19:04 +12:00
Robbie Averill 8428df1502
Merge pull request #91 from dhensby/pulls/fix-assert
FIX Use assertListEquals instead of contains and notcontains
2018-07-31 12:09:16 +12:00
Dan Hensby 6b5bc12f31
FIX Use assertListEquals 2018-07-31 00:55:50 +01:00
Robbie Averill 6ff726d0a1
Merge pull request #90 from creative-commoners/pulls/4.1/reduce-test-assertion
FIX Updating test to not assert order of results
2018-07-31 09:46:21 +12:00
Guy Marriott 8e73114051
FIX Updating test to not assert order of results 2018-07-31 09:26:49 +12:00
Robbie Averill 97a91ba20c Merge branch '4.1' 2018-06-25 14:28:12 +12:00
Robbie Averill 7f985ee5c8 Merge branch '4.0' into 4.1 2018-06-25 14:27:21 +12:00
Robbie Averill c2f0d754c2
Merge pull request #86 from creative-commoners/pulls/4.1/fix-for-ss42
BUG Update modal API for Reactstrap in SilverStripe 4.2, bump constraint
2018-06-25 14:20:43 +12:00
Guy Marriott 39a51857e9
Merge pull request #87 from creative-commoners/pulls/4.0/constrain-core
Constraint 4.0.x release line to SilverStripe 4.0 and 4.1, use contentreview 4.1 for SS 4.2+
2018-06-25 13:48:28 +12:00
Robbie Averill c56d00878b Update tested recipe versions to have a 4.2.x minimum 2018-06-25 13:22:15 +12:00
Robbie Averill 839ea9d3a5 Add various recipe versions to Travis matrix 2018-06-25 13:22:15 +12:00
Robbie Averill 6c56694bde BUG Update modal API for Reactstrap in SilverStripe 4.2, bump constraint 2018-06-25 13:22:15 +12:00
Daniel Hensby fec030f9f2
Merge branch '4.1' 2018-06-20 11:00:43 +01:00
Daniel Hensby 53ecc52af4
Merge branch '4.0' into 4.1 2018-06-20 11:00:06 +01:00
Daniel Hensby d989d4c68e
Linting fixes 2018-06-20 10:58:54 +01:00
Daniel Hensby 13aed4953f
Merge branch '3' 2018-06-20 10:55:37 +01:00
Daniel Hensby 61841ebabc
Merge branch '4.0' 2018-06-20 10:55:36 +01:00
Daniel Hensby 76e7d58ffc
Merge branch '4.0' into 4.1 2018-06-20 10:46:25 +01:00
Daniel Hensby 92770b01c6
Merge branch '3.0' into 4.0 2018-06-20 10:45:28 +01:00
Daniel Hensby c3a343d263
Merge branch '3.0' into 3 2018-06-20 10:44:20 +01:00
Robbie Averill a112834cc8
Merge pull request #54 from silbinarywolf/fix-healthcheckbug
FIX Ensure QueuedJob health check doesn't kill long running review jobs
2018-06-20 19:33:14 +12:00
Robbie Averill 5232b28551 Constraint 4.0.x release line to SilverStripe 4.0 and 4.1, use contentreview 4.1 for SS 4.2+ 2018-06-20 19:23:01 +12:00
Robbie Averill 5163c8d27e Merge branch '4.1' 2018-06-20 19:18:06 +12:00
Robbie Averill ca9faaf4bd Disable transactions in SiteTreeContentReview test 2018-06-20 18:51:00 +12:00
Damian Mooyman 06a1d3a907
Merge pull request #83 from creative-commoners/pulls/master/add-supported-module-badge
Add supported module badge to readme
2018-06-18 10:46:47 +12:00
Dylan Wagstaff d3de12fd59 Add supported module badge to readme 2018-06-15 17:33:20 +12:00
Robbie Averill bc74fc019d Update branch alias for 4.x-dev 2018-06-11 14:50:15 +12:00
Robbie Averill 86965e885d Merge branch '4.0' 2018-06-11 14:50:02 +12:00
Robbie Averill c6c7b18a5c Remove obsolete branch alias 2018-06-11 14:49:45 +12:00
Dylan a20a29b1f0 Update translations 2018-04-04 10:17:01 +12:00
Dylan Wagstaff 709bed209d
Merge pull request #82 from creative-commoners/pulls/4.0/member-profile-fix
FIX Remove automatically scaffolded GridField for Site Tree Content Review in Member fields
2018-03-26 11:21:46 +13:00
Robbie Averill dd7d1a70ec FIX Remove automatically scaffolded GridField for Site Tree Content Review in Member fields 2018-03-22 17:09:57 +13:00
Dylan Wagstaff f5052ed511
Merge pull request #80 from creative-commoners/pulls/4.0/fix-close-modal
FIX Remove unused variables import and fix the close modal button after submitting
2018-01-12 13:18:25 +13:00
Robbie Averill 19a9d55298 FIX Remove unused variables import and fix the close modal button after submitting
Also update to use the FormBuilderModal component, matching AddToCampaignForm in core.
2018-01-11 15:49:07 +13:00
Robbie Averill 5d27a124e0
Merge pull request #78 from creative-commoners/pulls/4.0/update-to-ss4
Optimise imports and update array syntax
2018-01-09 17:41:26 +13:00
Raissa North e55931f874 FIX Simplify JS requirements in SiteTreeContentReview and fix linting errors 2018-01-09 12:31:12 +13:00
Raissa North f64561e1b4 API Remove Translatable compatibility logic 2018-01-09 12:26:56 +13:00
Raissa North ad2932c418 ENHANCEMENT Optimise imports, upgrade array syntax 2018-01-09 12:26:55 +13:00
Dylan Wagstaff fe44baaa98
Merge pull request #79 from creative-commoners/pulls/4.0/update-translations
Update translations
2018-01-09 11:47:50 +13:00
Raissa North edef740ff1 Update translations and update classes to use __CLASS__ in translations 2018-01-09 11:20:50 +13:00
Raissa North f1c58fd5eb FIX Set correct Transifex resource name for javascript 2018-01-09 11:18:48 +13:00
Raissa North 1eca4b10f8 Merge branch '3' 2018-01-09 11:16:45 +13:00
Raissa North 024d48c489 Merge branch '3.0' into 3 2018-01-09 11:15:57 +13:00
Raissa North 5c9bedf161 Freeze translations for SS3 branches, commit directly to lang files 2018-01-09 11:15:35 +13:00
Robbie Averill 2c5c9ae259
Merge pull request #76 from creative-commoners/pulls/4.0/fix-composer-constraint
FIX Update constraint for serve and remove dev tags
2017-12-22 13:48:58 +13:00
Raissa North 33da1a3634 FIX Update constraint for serve and remove dev tags 2017-12-22 10:02:01 +13:00
Jake Bentvelzen 3679cb7f7d FIX Ensure QueuedJob health check doesn't kill long running review jobs 2017-11-21 09:13:42 +11:00
Robbie Averill d74066c0de
Merge pull request #71 from silverstripe-terraformers/feature/update-settings-fields-hook
v4: Add hook to updateSettingsFields so that devs can show/hide when desired
2017-11-21 09:40:42 +13:00
cpenny f490ad77cd Add a hook to updateSettingsFields so that devs can show/hide when desired. 2017-11-21 09:18:31 +13:00
Daniel Hensby 0078229057
Updating travis install steps 2017-10-12 13:25:11 +01:00
Daniel Hensby c15b550b2f Merge pull request #70 from creative-commoners/pulls/4.0/vendorise
NEW Install module to the vendor folder
2017-10-12 11:27:00 +01:00
Robbie Averill a55d5c285a Merge branch '3' 2017-10-12 13:22:24 +13:00
Robbie Averill 8241d344da Merge branch '3.0' into 3 2017-10-12 13:20:03 +13:00
Dylan Wagstaff 95d697fcba Merge pull request #69 from creative-commoners/pulls/3.0/siteconfig-defaults
FIX Ensure SiteConfig defaults are used as fallback options
2017-10-12 12:49:57 +13:00
Robbie Averill b720acb705 NEW Install module to the vendor folder 2017-10-12 09:41:01 +13:00
Robbie Averill 11a5dc7617 FIX Ensure SiteConfig defaults are used as fallback options 2017-10-06 16:39:53 +13:00
Robbie Averill 5877247972 Merge pull request #67 from creative-commoners/pulls/vendorise-ci
FIX convert CI bootstrap references to new their new locations in vendor
2017-10-05 11:06:15 +13:00
Dylan Wagstaff 46d4069f24 FIX convert CI bootstrap references to new their new locations in vendor 2017-10-05 10:07:54 +13:00
Franco Springveldt d00f37df76 Merge pull request #64 from creative-commoners/pulls/4.0/review-modal
API Add React modal popup for reviewing content in SiteTree
2017-09-19 11:00:31 +12:00
Robbie Averill 4e7792a132 FIX Use ModuleLoader for requirements, and use path resolver for thirdparty dir 2017-09-15 16:06:38 +12:00
Robbie Averill 31bcd0d439 NEW Add behat tests to cover content review configuration and review modal
* Update existing test for review button field name, remove obsolete save review test
* Move test classes to tests/php to differentiate from behat
* Add behat build to Travis configuration
2017-09-15 16:06:38 +12:00
Robbie Averill 8b8b8e3620 API Add React modal popup for reviewing content in SiteTree
* Add i18n javascript source file and Transifex configuration
* Add npm requirements, React + entwine wrapper for CMS
* Overload LeftAndMain::getSchema... methods in extension so they can be used
* Refactor CSS to only the content review button
2017-09-15 16:06:37 +12:00
Daniel Hensby 544604d0b9 Merge pull request #65 from creative-commoners/pulls/4.0/fix-datetime-casting
FIX Import DateTimeField class for GridField column casting
2017-09-13 12:27:55 +01:00
Daniel Hensby b8114f54bb Merge pull request #66 from creative-commoners/pulls/4.0/update-docs
DOCS Update readme and userguide for SS4, new screenshots, updated use examples
2017-09-13 12:27:19 +01:00
Robbie Averill 47f1983955 DOCS Update readme and userguide for SS4, new screenshots, updated use examples 2017-09-13 11:18:26 +12:00
Robbie Averill 07f24bbd63 FIX Import DateTimeField class for GridField column casting 2017-09-13 11:16:47 +12:00
Will Rossiter 05fb6fa217 Use square arrays 2017-09-11 12:56:05 +12:00
Will Rossiter 0c684045f3 Merge pull request #62 from creative-commoners/pulls/4.0/webpack-config
API Move JS and CSS to webpack, update DOM binding for SS4 CMS
2017-09-11 12:50:02 +12:00
Robbie Averill 038c41f5bf FIX Change right title to description for alignment 2017-09-07 16:20:29 +12:00
Robbie Averill a93d8046f4 API Move JS and CSS to webpack, update DOM binding for SS4 CMS 2017-09-07 16:20:29 +12:00
Franco Springveldt 521c8c9128 Merge pull request #61 from creative-commoners/pulls/4.0/ss4-compat
API Upgrade for SS4 compatibility
2017-09-07 16:20:03 +12:00
Robbie Averill cc7763afa4 FIX Import QueuedJobService namespace in job classes 2017-09-07 16:14:37 +12:00
Robbie Averill de6ca323e0 FIX Add namespace import for Member 2017-09-07 09:29:27 +12:00
Robbie Averill 1e7a2be663 Add PostgreSQL to Travis builds 2017-09-06 17:16:02 +12:00
Robbie Averill 840a0cb5e4 FIX Add legacy model class name remapping configuration 2017-09-06 17:12:31 +12:00
Robbie Averill c5f9da17d0 FIX Missing namespace imports, incorrect date formats and array keys 2017-09-06 17:12:31 +12:00
Robbie Averill 42fb360fb2 API Implement namespaces and update core API use - CLDR date formats in progress 2017-09-06 17:12:31 +12:00
Robbie Averill 0f61b1286d Update Travis configuration, add PSR-4 autoloader, update composer requirements for SS4 2017-09-06 17:12:30 +12:00
Robbie Averill 5ae95eda35 Move code to src for PSR-4 autoloading 2017-09-06 17:12:03 +12:00
Robbie Averill 4a63570bc5 Merge branch '3' 2017-09-06 17:11:15 +12:00
Robbie Averill 5b4aa0ab51 Merge branch '3.0' into 3 2017-09-06 17:11:02 +12:00
Robbie Averill c6da57f0c5 Use precise distro for Travis builds 2017-09-06 17:10:54 +12:00
Robbie Averill eae6480b59 Merge branch '3' 2017-09-06 16:58:46 +12:00
Robbie Averill ede6988cc1 Update branch alias 2017-09-06 16:58:12 +12:00
Franco Springveldt f51ec4236e Update translations 2017-08-25 16:44:46 +12:00
Robbie Averill d21e4947cc Merge branch '3.0' 2017-08-24 13:01:26 +12:00
Russell Michell 19897e0b8f FIX: Fixes #59 Minor changes wr/t typos. 2017-08-24 13:00:57 +12:00
Robbie Averill aa13834a0d Update branch alias for master 2017-08-24 13:00:23 +12:00
Robbie Averill 42718f3f86 Merge branch '3.0' 2017-08-24 12:58:51 +12:00
Robbie Averill ed7f5fc4de Merge pull request #60 from phptek/issue/59
FIX: Minor changes wr/t typos.
2017-08-23 11:32:58 +12:00
Russell Michell c05556a16b FIX: Fixes #59 Minor changes wr/t typos. 2017-08-23 11:22:56 +12:00
Damian Mooyman c403a8b231 Merge pull request #58 from dylanitorium/master
Fixing method call bug in canBeReviewedBy() (#1)
2017-07-13 18:25:20 +12:00
Dylan Sweetensen 9378483378 Fixing method call bug in canBeReviewedBy() (#1)
If getOptions returns false, then canBeReviewedBy() throws "Call to a member function OwnerGroups() on boolean".
This will return false, in the the case that options are false.
2017-07-12 09:23:30 +12:00
Daniel Hensby 4f7e57d29c Merge pull request #57 from creative-commoners/pulls/3.0/travis-php7
Add PHP7 + SS3.6 build to Travis configuration
2017-06-15 14:09:53 +01:00
Robbie Averill 12198e21e6 FIX Remove specific page edit URL from tests to ensure multi SS version compatibility 2017-06-15 14:47:25 +12:00
Robbie Averill 7bae7e2c34 Add PHP7 + SS3.6 build to Travis configuration 2017-06-15 10:14:41 +12:00
Daniel Hensby 509e798cb1 Merge pull request #56 from NightJar/patch-1
Avoid fatal errors when trying to edit in the CMS
2017-03-24 19:38:33 +13:00
NightJar ea4b6f5357 Avoid fatal errors when trying to edit in the CMS
If a page has it's `ContentReviewType` `Disabled` (either directly or on a parent via a `Inherit`) **AND ** has a `NextReviewDate` in the past, the page will cause a fatal error when attempting to load it for editing in the CMS. We can avoid this by checking if a pages Options are a boolean value (false for disabled) before trying to call methods on it. Addresses issue #55
2017-03-24 11:52:35 +13:00
Damian Mooyman 40a1ce4ee8
Fix invalid composer.json 2016-11-17 11:07:37 +13:00
Damian Mooyman 272afd4670 Remove broken string 2016-11-17 11:04:33 +13:00
Damian Mooyman 1711eb8aa6
Remove broken string 2016-11-17 11:02:06 +13:00
Damian Mooyman dd98ee92a5 Remove obsolete branch-alias 2016-11-17 10:15:57 +13:00
Damian Mooyman efb9f886bb Merge pull request #52 from silverstripe/add-helpful-robot-badge
Added Helpful Robot badge
2016-06-07 13:58:53 +12:00
Christopher Pitt 019c69b982 Added Helpful Robot badge 2016-05-21 17:33:21 +12:00
Damian Mooyman 4f8835c30e Add changelog for 3.0.2 2016-05-18 18:41:35 +12:00
Hamish Friedlander 25c0556499 Merge pull request #51 from open-sausages/pulls/fix-phantom-draft-changes
BUG Prevent non-real draft changes forcing record to appear as changed when saved
2016-05-18 17:13:26 +12:00
Damian Mooyman d75cf9e280
BUG Prevent non-real draft changes forcing record to appear as changed when saved 2016-05-17 17:57:48 +12:00
Damian Mooyman c3d26a8767 Merge pull request #50 from SilbinaryWolf/fix-useconfigforjob
FIX (ContentReviewNotificationJob): Changed to use config system for job.
2016-04-18 11:34:18 +12:00
Jake Bentvelzen 3c2c8d96aa fix(ContentReviewNotificationJob): Changed to use ->config() system so that the next_run_hour can be configured in YAML. 2016-04-11 16:44:26 +10:00
Damian Mooyman 44d01ec3c9 Changelog for 3.0.1 2016-02-04 13:10:06 +13:00
Damian Mooyman cd0702c6e8 Update translations 2016-02-04 11:03:41 +13:00
Christopher Pitt facac031e4 Merge pull request #48 from camfindlay/master
DOCS Documentation rework for better user guide.
2016-01-05 16:26:52 +13:00
Cam Findlay 361d5ac0f8 DOCS Documentation rework for better user guide. 2016-01-05 15:47:56 +13:00
Scott Hutchinson 9ce121ec88 Merge pull request #47 from helpfulrobot/update-license-year
Updated license year
2016-01-05 09:27:13 +13:00
helpfulrobot 97db427475 Updated license year 2016-01-01 06:32:22 +13:00
Ingo Schommer 34dbcfb801 Merge pull request #46 from tractorcow/pulls/fix-docs
BUG Fix documentation links
2015-11-24 16:51:20 +13:00
Damian Mooyman 40590b4527 Merge pull request #45 from helpfulrobot/add-standard-code-of-conduct
Added standard code of conduct
2015-11-24 16:20:42 +13:00
Damian Mooyman 2ed90f97cf BUG Fix documentation links 2015-11-24 09:59:22 +13:00
helpfulrobot 06f9732f4c Added standard code of conduct 2015-11-21 20:11:36 +13:00
Damian Mooyman befc75e09c Merge pull request #41 from helpfulrobot/add-standard-editor-config
Added standard editor config
2015-11-20 14:14:48 +13:00
Damian Mooyman 7e5094e030 Merge pull request #42 from helpfulrobot/add-standard-travis-config
Added standard Travis config
2015-11-20 14:14:40 +13:00
Damian Mooyman 5399b2ac8a Merge pull request #43 from helpfulrobot/add-standard-license
Added standard license
2015-11-20 14:14:33 +13:00
Damian Mooyman bb395a6b38 Merge pull request #44 from helpfulrobot/add-standard-git-attributes
Added standard git attributes
2015-11-20 14:14:21 +13:00
helpfulrobot 1fffab4def Added standard git attributes 2015-11-19 19:10:29 +13:00
helpfulrobot 7deafe24f4 Added standard license 2015-11-19 18:29:08 +13:00
Scott Hutchinson e6b6f9d4e7 Merge pull request #40 from tractorcow/pulls/release-300
Changelog for 3.0.0 release
2015-11-19 17:16:36 +13:00
Damian Mooyman bdf91536a0 Changelog for 3.0.0 release 2015-11-19 16:47:47 +13:00
helpfulrobot 0d9d9e898c Added standard Travis config 2015-11-19 14:18:10 +13:00
helpfulrobot e20becc07b Added standard editor config 2015-11-19 13:24:15 +13:00
Damian Mooyman 009c64e532 Merge pull request #37 from helpfulrobot/add-standard-scrutinizer-config
Added standard Scrutinizer config
2015-11-19 10:24:46 +13:00
Damian Mooyman 9806de9fcc Merge pull request #38 from helpfulrobot/convert-to-psr-2
Converted to PSR-2
2015-11-19 10:24:33 +13:00
Damian Mooyman 9fe28db981 Merge pull request #39 from helpfulrobot/add-standard-travis-config
Added standard Travis config
2015-11-19 10:24:10 +13:00
helpfulrobot 84ec893c45 Added standard Travis config 2015-11-18 17:20:23 +13:00
helpfulrobot 98c125360b Converted to PSR-2 2015-11-18 16:38:28 +13:00
David Craig ddf5052503 Merge pull request #35 from open-sausages/feature/custom-templates
API CMS Editable notification templates
2015-11-18 15:22:13 +13:00
helpfulrobot 64fc4d0703 Added standard Scrutinizer config 2015-11-18 14:36:12 +13:00
Damian Mooyman d9729bf7f1 API CMS Editable notification templates
PSR-2 Coding fixup
2015-11-18 13:25:54 +13:00
David Craig 6138d0b927 Merge pull request #36 from open-sausages/pulls/fix-inherited-date
BUG Show inherited date even when inheriting settings
2015-11-18 13:25:04 +13:00
Damian Mooyman affee4bb85 BUG Show inherited date even when inheriting settings 2015-11-18 11:58:57 +13:00
Damian Mooyman 97adaee9a5 Merge pull request #32 from flashbackzoo/pulls/add-user-filter
Add report filter for only the pages a user is assigned to
2015-11-18 10:30:51 +13:00
David Craig fc6caa2011 Add report filter for only the pages a user is assigned to 2015-11-18 09:44:08 +13:00
Damian Mooyman b234d4cb49 Update translations 2015-11-17 16:11:33 +13:00
Damian Mooyman 1574ae1a05 Merge pull request #34 from scott1702/master
Make 'Mark as reviewed' button look more like an action
2015-11-13 16:31:07 +13:00
scott1702 6a1047b292 Make 'Mark as reviewed' button look like an action 2015-11-13 16:22:24 +13:00
Damian Mooyman c6d9df1ae2 Merge pull request #33 from scott1702/master
Make contentreview an inline form
2015-11-13 15:12:32 +13:00
scott1702 0610b12a4a Make contentreview an inline form 2015-11-13 14:51:09 +13:00
Damian Mooyman 8980e29320 Merge pull request #29 from assertchris/fix-merge-error
Fixed merge error
2015-11-05 09:53:40 +13:00
Christopher Pitt 3973d8e7c7 Update changelog.md 2015-11-05 09:24:03 +13:00
Damian Mooyman 7ffb6afc3b Add tx config 2015-11-04 10:26:51 +13:00
Damian Mooyman b3dd69560f Update translations 2015-11-04 10:21:07 +13:00
Christopher Pitt c8a8c3b155 Merge pull request #31 from tractorcow/pulls/fix-save-form
BUG Fix form saving
2015-11-04 09:28:42 +13:00
Damian Mooyman 5056615cf2 BUG Fix form saving 2015-11-03 17:18:48 +13:00
Christopher Pitt ae7bef5449 Merge pull request #28 from scott1702/minor-tweaks
Minor UX Tweaks
2015-11-03 10:39:50 +13:00
scott1702 b7acdffff2 Change text of reviewed content button
Added description to review notes
2015-11-03 10:24:35 +13:00
Damian Mooyman c50fa30a27 Merge pull request #30 from assertchris/fix-code-style
Fixed code style
2015-11-02 13:11:05 +13:00
Christopher Pitt 61fd586533 Fixed code style 2015-11-02 12:53:31 +13:00
Christopher Pitt dc54a939bb Fixed merge error 2015-11-02 10:41:06 +13:00
Damian Mooyman c22e24567e Merge pull request #27 from assertchris/add-community-files
Added community files
2015-11-02 09:58:38 +13:00
Christopher Pitt eebba9a826 Added community files 2015-11-02 09:50:12 +13:00
Damian Mooyman f9aec74a41 Merge pull request #26 from assertchris/clean-up-tests-and-badges
Cleaned up tests and Badges
2015-11-02 09:28:24 +13:00
Christopher Pitt 119e6e59d8 Cleaned up tests and Badges 2015-10-29 13:12:27 +13:00
Igor Nadj 93a60eb455 ENH: compatability with other modules 2015-09-23 10:32:23 +12:00
Igor Nadj 7f75e994cc ENH: updating readme 2015-09-15 18:12:26 +12:00
Igor Nadj 4f1d9f15f8 ENH: play nicer with subsites module 2015-09-15 17:28:28 +12:00
Igor Nadj 2b98e7b7d9 Merge remote-tracking branch 'matt/pulls/reporting-url-fix' into cwp-support 2015-09-11 15:33:50 +12:00
madmatt 69896840cb BUGFIX: Links to CMS edit page fails when the link includes ?locale=en_NZ or similar 2015-08-03 19:30:55 +12:00
madmatt 8675212885 FEATURE: Add (optional) integration with the queuedjobs module
- Automatically creates a ContentReviewNotificationJob to run the next day if
the queuedjobs module exists

- Does nothing if the queuedjobs module does not exist, to ensure it is optional

- Update composer to suggest queuedjobs module, and updated docs to reflect both
ways of configuring the module
2015-07-31 16:07:18 +12:00
Stig Lindqvist 613ad1cb60 Adding scrutinizer badges to README.md 2014-03-07 15:22:40 +13:00
Stig Lindqvist 64af1d545d Remove double code coverage report from travis 2014-03-07 15:21:50 +13:00
Stig Lindqvist d0fec69194 configure travis to send code coverage to scrutinizer 2014-03-07 15:05:01 +13:00
Stig Lindqvist 753c2d12d5 Adding scrutinizer config 2014-03-07 14:59:40 +13:00
Stig Lindqvist 66db82e1b1 use . syntax instead of [] syntax when calling show / hide 2014-03-07 14:59:39 +13:00
Stig Lindqvist 9317dbaa8c Moved out common functionality to a static method 2014-03-07 14:58:57 +13:00
Stig Lindqvist c904ec1a15 Seems like 3.1.1 doesnt like multiple togglefields in the same tab.. 2014-02-27 13:51:13 +13:00
Stig Lindqvist 09586b4b12 Show next review date for inherited settings 2014-02-27 11:43:56 +13:00
Stig Lindqvist 4c88574799 BUG When setting up a new site, the default pages will not inherit a review date from siteconfig #20 2014-02-27 11:07:34 +13:00
Stig Lindqvist ea44b0026e Fixed the ContentReviewReportTest for real this time, wrong order in assertEquals 2014-02-25 21:21:08 +13:00
Stig Lindqvist c078bae7db Adding travis-ci image link to the README 2014-02-25 21:17:24 +13:00
Stig Lindqvist 5cae6165d2 Bad test fixture that messed up postgresql tests #16 2014-02-25 21:15:41 +13:00
Stig Lindqvist e123c1c0e7 Fixed tests for PagesDueForReviewReport 2014-02-25 20:43:46 +13:00
Stig Lindqvist ec9b58aea8 code style guidelines 2014-02-25 20:37:59 +13:00
Stig Lindqvist 3b752be238 NEW report for pages without a review schedule 2014-02-25 20:37:43 +13:00
Stig Lindqvist 8c5e91addc Simplified the Pages due for review report #12 2014-02-25 20:36:26 +13:00
Stig Lindqvist 21b6b05fb7 Showing a readonly field for where settings are derived from 2014-02-25 20:35:27 +13:00
Stig Lindqvist 3017712dfb BUG Cant get owner names from a page that is disabled 2014-02-25 20:34:42 +13:00
Stig Lindqvist 5376c3a248 Allow drafted pages to show up in the report 2014-02-25 18:23:18 +13:00
Stig Lindqvist 6b337496cf NEW Send one notification email per author #7 2014-02-25 15:54:27 +13:00
Stig Lindqvist b3c777a579 Fix travis config name and removing unused .gitconfig file 2014-02-25 14:02:55 +13:00
Stig Lindqvist e539ddc165 BUG Inherited settings doesn't trigger the mark as review button to show up 2014-02-25 12:10:39 +13:00
Stig Lindqvist d203737099 Change license date 2014-02-25 00:52:15 +13:00
Stig Lindqvist c021af834b Group tests together in the same test class #3 2014-02-25 00:51:36 +13:00
Stig Lindqvist de4fac0541 AdvanceReviewDate now can use inherited settings #3 2014-02-25 00:46:50 +13:00
Stig Lindqvist bfbc53c080 More coverage 2014-02-24 22:14:26 +13:00
Stig Lindqvist 32378bb269 Refactorings 2014-02-24 21:17:09 +13:00
Stig Lindqvist 638d2fc331 Refactorings 2014-02-24 21:10:10 +13:00
Stig Lindqvist 1057e5823a Removed unused class 2014-02-24 21:04:44 +13:00
Stig Lindqvist ee7feeb130 When changing parents content review setting update the inherited childrens settings as well 2014-02-24 20:19:44 +13:00
Stig Lindqvist d340004933 Tests and fixes for inherited settings 2014-02-24 13:38:16 +13:00
Stig Lindqvist 0ad06c49fd Inherit content review settings from siteconfig or parent page 2014-02-21 13:33:01 +13:00
Stig Lindqvist 78d84a57c6 Adding default setting to the SiteConfig, broken email and tests though. 2014-02-20 18:05:14 +13:00
Stig Lindqvist f673815eff Adding those pesky .DS_Store files to gitignore 2014-02-19 15:58:46 +13:00
Stig Lindqvist 4cc6f450a6 Adding report for pages without a content review scheduled 2014-02-19 15:58:19 +13:00
Stig Lindqvist 57f08027c7 Fix tests after moving the settings 2014-02-19 15:29:21 +13:00
Stig Lindqvist 5eba67b3ab Adding travis build configuration 2014-02-19 15:23:28 +13:00
Stig Lindqvist b9fcd76bf2 Minor change to the readme 2014-02-19 15:13:42 +13:00
Stig Lindqvist 31b23009cd Initial change of the README for this branch 2014-02-19 15:09:20 +13:00
Stig Lindqvist db48bee114 Moved content review settings to the Page.Settings tab 2014-02-19 14:31:47 +13:00
Stig Lindqvist f806987ba7 Improving the code coverage 2014-02-19 09:51:54 +13:00
Stig Lindqvist 7a843e222f Improving test coverage 2014-02-18 15:39:13 +13:00
Stig Lindqvist 11e623ab09 Moved sitetree extension to extension directory 2014-02-17 17:06:27 +13:00
Stig Lindqvist ae440666a0 Adding content reviewed actions to a sitetree 2014-02-14 14:49:43 +13:00
Stig Lindqvist 131d643a8c Allow users and/or groups to be content owners 2014-02-13 16:35:13 +13:00
Stig Lindqvist d28a0eefa0 Coding style guidelines 2014-02-13 14:10:09 +13:00
Andrew Short 90db01d259 Fix incorrect usage of data list methods. 2013-09-25 22:35:38 +10:00
Andrew Short 6a9dca2786 Mark statics as private. 2013-09-23 15:57:54 +10:00
Andrew Short e5ea96a228 Replace usae of deprecated task type. 2013-09-23 15:57:53 +10:00
Andrew Short 1b3882bcb5 Move config into YAML files. 2013-09-23 15:57:53 +10:00
Andrew Short 42eb657920 Require SS 3.1. 2013-09-23 15:57:47 +10:00
Andrew Short 730e9e94d4 Update the README to have the correct details. 2013-09-21 16:12:36 +10:00
Julian Seidenberg 72c3faca96 API renaming SiteTree->OwnerID column because it conflicts with the blog module 2013-03-18 15:20:51 +13:00
Normann Lou 26ba97a567 BUG: calling function with right argument 2013-03-06 16:48:06 +13:00
Ingo Schommer b2eb26da15 Merge branch 'master' into upstream-master
Conflicts:
	code/SiteTreeContentReview.php
2013-01-07 13:55:31 +01:00
Ingo Schommer 278f5da18f Create composer.json 2013-01-07 04:48:09 -08:00
Normann Lou 1240467033 BUGFIX: when use 'showcalendar', both 'dateformat' and 'datavalueformat' need to be set to the right format as well so that DateField save the right value into DB 2012-07-17 13:27:24 +12:00
Normann Lou 4c09ba132a BUGFIX: the page cms link updated for SS3 2012-07-16 17:50:50 +12:00
Ingo Schommer 7257fa52ce 3.0 compatibility 2012-07-12 15:51:46 +02:00
Ingo Schommer 8a5e8d9ba7 3.0 compatibility 2012-07-12 15:49:34 +02:00
Andrew O'Neil a95e90e6f0 MINOR: Fixes for unit tests 2012-07-12 16:01:43 +12:00
Ingo Schommer 84a4ee477c NEW 3.0 compatibility 2012-07-10 18:36:05 +02:00
92 changed files with 9682 additions and 546 deletions

17
.editorconfig Normal file
View File

@ -0,0 +1,17 @@
# For more information about the properties used in this file,
# please see the EditorConfig documentation:
# http://editorconfig.org
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[{*.yml,package.json,*.js,*.scss}]
indent_size = 2
# The indent size used in the package.json file cannot be changed:
# https://github.com/npm/npm/pull/3180#issuecomment-16336516

7
.eslintrc Normal file
View File

@ -0,0 +1,7 @@
{
"extends": "airbnb",
"root": true,
"rules": {
"init-declarations": 1
}
}

8
.gitattributes vendored Normal file
View File

@ -0,0 +1,8 @@
/tests export-ignore
/docs export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
/.travis.yml export-ignore
/.scrutinizer.yml export-ignore
/.phpcs.xml.dist export-ignore
/.codecov.yml export-ignore

11
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,11 @@
name: CI
on:
push:
pull_request:
workflow_dispatch:
jobs:
ci:
name: CI
uses: silverstripe/gha-ci/.github/workflows/ci.yml@v1

View File

@ -0,0 +1,15 @@
name: Deploy Userhelp Docs
on:
push:
branches:
- '5'
- '4'
paths:
- 'docs/en/userguide/**'
jobs:
deploy:
name: deploy-userhelp-docs
runs-on: ubuntu-latest
steps:
- name: Run build hook
run: curl -X POST -d {} https://api.netlify.com/build_hooks/${{ secrets.NETLIFY_BUILD_HOOK }}

16
.github/workflows/dispatch-ci.yml vendored Normal file
View File

@ -0,0 +1,16 @@
name: Dispatch CI
on:
# At 11:30 AM UTC, only on Wednesday and Thursday
schedule:
- cron: '30 11 * * 3,4'
jobs:
dispatch-ci:
name: Dispatch CI
# Only run cron on the silverstripe account
if: (github.event_name == 'schedule' && github.repository_owner == 'silverstripe') || (github.event_name != 'schedule')
runs-on: ubuntu-latest
steps:
- name: Dispatch CI
uses: silverstripe/gha-dispatch-ci@v1

17
.github/workflows/keepalive.yml vendored Normal file
View File

@ -0,0 +1,17 @@
name: Keepalive
on:
workflow_dispatch:
# The 4th of every month at 10:50am UTC
schedule:
- cron: '50 10 4 * *'
jobs:
keepalive:
name: Keepalive
# Only run cron on the silverstripe account
if: (github.event_name == 'schedule' && github.repository_owner == 'silverstripe') || (github.event_name != 'schedule')
runs-on: ubuntu-latest
steps:
- name: Keepalive
uses: silverstripe/gha-keepalive@v1

17
.github/workflows/update-js.yml vendored Normal file
View File

@ -0,0 +1,17 @@
name: Update JS
on:
workflow_dispatch:
# Run on a schedule of once per quarter
schedule:
- cron: '0 0 1 */3 *'
jobs:
update-js:
name: Update JS
# Only run cron on the silverstripe account
if: (github.event_name == 'schedule' && github.repository_owner == 'silverstripe') || (github.event_name != 'schedule')
runs-on: ubuntu-latest
steps:
- name: Update JS
uses: silverstripe/gha-update-js@v1

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.DS_Store
node_modules/

1
.nvmrc Normal file
View File

@ -0,0 +1 @@
10

97
.sass-lint.yml Normal file
View File

@ -0,0 +1,97 @@
# sass-lint config to match the AirBNB style guide
# See silverstripe-admin
files:
include: client/src/**/*.scss'
options:
formatter: stylish
merge-default-rules: false
rules:
# Warnings
# Things that require actual refactoring are marked as warnings
class-name-format:
- 1
- convention: hyphenatedbem
placeholder-name-format:
- 1
- convention: hyphenatedlowercase
nesting-depth:
- 1
- max-depth: 3
no-ids: 1
no-important: 1
no-misspelled-properties:
- 1
- extra-properties:
- "-moz-border-radius-topleft"
- "-moz-border-radius-topright"
- "-moz-border-radius-bottomleft"
- "-moz-border-radius-bottomright"
variable-name-format:
- 1
- allow-leading-underscore: true
convention: hyphenatedlowercase
no-extends: 1
# Warnings: these things are preferential rather than mandatory
no-css-comments: 1
# Errors
# Things that can be easily fixed are marked as errors
indentation:
- 2
- size: 2
final-newline:
- 2
- include: true
no-trailing-whitespace: 2
border-zero:
- 2
- convention: '0'
brace-style:
- 2
- allow-single-line: true
clean-import-paths:
- 2
- filename-extension: false
leading-underscore: false
no-debug: 2
no-empty-rulesets: 2
no-invalid-hex: 2
no-mergeable-selectors: 2
# no-qualifying-elements:
# - 1
# - allow-element-with-attribute: false
# allow-element-with-class: false
# allow-element-with-id: false
no-trailing-zero: 2
no-url-protocols: 2
quotes:
- 2
- style: double
space-after-bang:
- 2
- include: false
space-after-colon:
- 2
- include: true
space-after-comma:
- 2
- include: true
space-before-bang:
- 2
- include: true
space-before-brace:
- 2
- include: true
space-before-colon: 2
space-between-parens:
- 2
- include: false
trailing-semicolon: 2
url-quotes: 2
zero-unit: 2
single-line-per-selector: 2
one-declaration-per-line: 2
empty-line-between-blocks:
- 2
- ignore-single-line-rulesets: true

15
.tx/config Normal file
View File

@ -0,0 +1,15 @@
[main]
host = https://www.transifex.com
[o:silverstripe:p:silverstripe-contentreview:r:master]
file_filter = lang/<lang>.yml
source_file = lang/en.yml
source_lang = en
type = YML
[o:silverstripe:p:silverstripe-contentreview:r:master-js]
file_filter = client/lang/src/<lang>.json
source_file = client/lang/src/en.json
source_lang = en
type = KEYVALUEJSON

18
.upgrade.yml Normal file
View File

@ -0,0 +1,18 @@
mappings:
ContentReviewCompatability: SilverStripe\ContentReview\Compatibility\ContentReviewCompatability
ContentReviewCMSExtension: SilverStripe\ContentReview\Extensions\ContentReviewCMSExtension
ContentReviewDefaultSettings: SilverStripe\ContentReview\Extensions\ContentReviewDefaultSettings
ContentReviewOwner: SilverStripe\ContentReview\Extensions\ContentReviewOwner
SiteTreeContentReview: SilverStripe\ContentReview\Extensions\SiteTreeContentReview
ContentReviewNotificationJob: SilverStripe\ContentReview\Jobs\ContentReviewNotificationJob
ContentReviewLog: SilverStripe\ContentReview\Models\ContentReviewLog
PagesDueForReviewReport: SilverStripe\ContentReview\Reports\PagesDueForReviewReport
PagesWithoutReviewScheduleReport: SilverStripe\ContentReview\Reports\PagesWithoutReviewScheduleReport
ContentReviewEmails: SilverStripe\ContentReview\Tasks\ContentReviewEmails
ContentReviewOwnerMigrationTask: SilverStripe\ContentReview\Tasks\ContentReviewOwnerMigrationTask
ContentReviewBaseTest: SilverStripe\ContentReview\Tests\ContentReviewBaseTest
ContentReviewCMSPageEditControllerTest: SilverStripe\ContentReview\Tests\ContentReviewCMSPageEditControllerTest
ContentReviewNotificationTest: SilverStripe\ContentReview\Tests\ContentReviewNotificationTest
ContentReviewReportTest: SilverStripe\ContentReview\Tests\ContentReviewReportTest
ContentReviewSettingsTest: SilverStripe\ContentReview\Tests\ContentReviewSettingsTest
SiteTreeContentReviewTest: SilverStripe\ContentReview\Tests\SiteTreeContentReviewTest

24
LICENSE
View File

@ -1,24 +0,0 @@
* Copyright (c) 2010, SilverStripe Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY SilverStripe Ltd. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL SilverStripe Ltd. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,23 +1,59 @@
# Content Review module
## Maintainer Contact
* Tom Rix (Nickname: trix)
<tom (at) silverstripe (dot) com>
[![CI](https://github.com/silverstripe/silverstripe-contentreview/actions/workflows/ci.yml/badge.svg)](https://github.com/silverstripe/silverstripe-contentreview/actions/workflows/ci.yml)
[![Silverstripe supported module](https://img.shields.io/badge/silverstripe-supported-0071C4.svg)](https://www.silverstripe.org/software/addons/silverstripe-commercially-supported-module-list/)
This module helps keep your website content accurate and up-to-date, which keeps your users happy.
It does so by sending reviewers reminder emails to go in and check the content. For a reviewer this
often includes checking links, grammar, factual information and look and feel.
There are two types of roles with this module.
* Website owner; (typically assigned to the Administrator group) ensures that a website is accurate and up-to-date, by delegating responsibility to content reviewers.
* Content reviewer; responsible for keeping a website or part of a website accurate and up-to-date.
## Requirements
* SilverStripe 2.4 or newer
* Database: MySQL, Postgres, SQLite or MSSQL
* PHP 5.2 or newer (because of Zend_Date usage)
* module legacydatetimefields (http://svn.silverstripe.com/open/modules/legacydatetimefields/trunk)
## Installation
* Silverstripe ^4.0
**Note:** For Silverstripe 3.x, please use the [3.x release line](https://github.com/silverstripe/silverstripe-contentreview/tree/3).
Drop it into your installation folder, and refresh your database schema
through `http://<your-host>/dev/build`.
## Features
If you wish to have emails sent when a page comes up for review, you
new to have the DailyTask cron job set up. See ScheduledTask.php
* Content reviewer will receive an email notification when a page is due for review.
* Content reviewer can mark a page as 'reviewed', and provide review notes.
* Website owner can assign content reviewers to a page and set when the content should be reviewed.
* Website owner can see a report of pages and their reviewed status.
* Content reviewers can be assigned to a page, a page and all sub-pages, or globally.
* The content review schedule can be automatic, e.g. every month, and/or a specific date.
## Usage
## Wishlist features
When you open a page in the CMS, there will now be a Review tab.
* Overdue review reminder emails.
* Customisable reminder emails.
## Composer installation
```sh
$ composer require silverstripe/contentreview
```
You'll also need to run `dev/build`.
Run dev/build either via the web server by opening the URL `http://<your-host>/dev/build?flush` or
by running the dev/build via a CLI: `sake dev/build flush=1`
## Documentation
See the [docs/en](docs/en/index.md) folder.
## Versioning
This library follows [Semver](http://semver.org). According to Semver, you will be able to upgrade to any minor or patch version of this library without any breaking changes to the public API. Semver also requires that we clearly define the public API for this library.
All methods, with `public` visibility, are part of the public API. All other methods are not part of the public API. Where possible, we'll try to keep `protected` methods backwards-compatible in minor/patch versions, but if you're overriding methods then please test your work before upgrading.
## Reporting Issues
Please [create an issue](https://github.com/silverstripe/silverstripe-contentreview/issues) for any bugs you've found, or features you're missing.

View File

@ -1,10 +0,0 @@
<?php
Object::add_extension('SiteTree', 'SiteTreeContentReview');
if(class_exists('Subsite') && class_exists('SubsiteReportWrapper')){
SS_Report::register('ReportAdmin', 'SubsiteReportWrapper("PagesDueForReviewReport")',20);
} else {
SS_Report::register('ReportAdmin', 'PagesDueForReviewReport',20);
}

30
_config/config.yml Normal file
View File

@ -0,0 +1,30 @@
---
Name: contentreviewextensions
---
SilverStripe\Admin\LeftAndMain:
extensions:
- SilverStripe\ContentReview\Extensions\ContentReviewLeftAndMainExtension
SilverStripe\CMS\Controllers\CMSPageEditController:
extensions:
- SilverStripe\ContentReview\Extensions\ContentReviewCMSExtension
SilverStripe\CMS\Controllers\CMSPageSettingsController:
extensions:
- SilverStripe\ContentReview\Extensions\ContentReviewCMSExtension
SilverStripe\CMS\Model\SiteTree:
extensions:
- SilverStripe\ContentReview\Extensions\SiteTreeContentReview
SilverStripe\Security\Group:
extensions:
- SilverStripe\ContentReview\Extensions\ContentReviewOwner
SilverStripe\Security\Member:
extensions:
- SilverStripe\ContentReview\Extensions\ContentReviewOwner
SilverStripe\SiteConfig\SiteConfig:
extensions:
- SilverStripe\ContentReview\Extensions\ContentReviewDefaultSettings

6
_config/legacy.yml Normal file
View File

@ -0,0 +1,6 @@
---
Name: contentreviewlegacy
---
SilverStripe\ORM\DatabaseAdmin:
classname_value_remapping:
ContentReviewLog: SilverStripe\ContentReview\Models\ContentReviewLog

29
behat.yml Normal file
View File

@ -0,0 +1,29 @@
default:
suites:
contentreview:
paths:
- "%paths.modules.contentreview%/tests/behat/features"
contexts:
- SilverStripe\Admin\Tests\Behat\Context\AdminContext
- SilverStripe\BehatExtension\Context\BasicContext
- SilverStripe\BehatExtension\Context\EmailContext
- SilverStripe\BehatExtension\Context\LoginContext
- SilverStripe\Framework\Tests\Behaviour\CmsFormsContext
- SilverStripe\Framework\Tests\Behaviour\CmsUiContext
- SilverStripe\ContentReview\Tests\Behat\Context\FeatureContext
- SilverStripe\ContentReview\Tests\Behat\Context\FixtureContext
-
SilverStripe\ContentReview\Tests\Behat\Context\FixtureContext:
- "%paths.modules.contentreview%/tests/behat/files/"
extensions:
SilverStripe\BehatExtension\MinkExtension:
default_session: facebook_web_driver
javascript_session: facebook_web_driver
facebook_web_driver:
browser: chrome
wd_host: "http://127.0.0.1:9515"
SilverStripe\BehatExtension\Extension:
screenshot_path: "%paths.base%/artifacts/screenshots"
bootstrap_file: vendor/silverstripe/framework/tests/behat/serve-bootstrap.php

1
client/dist/js/contentreview.js vendored Normal file
View File

@ -0,0 +1 @@
!function(e){function n(o){if(t[o])return t[o].exports;var i=t[o]={i:o,l:!1,exports:{}};return e[o].call(i.exports,i,i.exports,n),i.l=!0,i.exports}var t={};n.m=e,n.c=t,n.i=function(e){return e},n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:o})},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="",n(n.s=4)}([function(e,n){e.exports=jQuery},function(e,n,t){"use strict";var o=t(8),i=t.n(o),r=t(0),s=t.n(r),c=t(6),a=t.n(c),u=t(7),d=t.n(u),l=t(5),f=(t.n(l),t.i(l.loadComponent)("FormBuilderModal"));s.a.entwine("ss",function(e){e(".cms-content-actions .content-review__button").entwine({onclick:function(n){n.preventDefault();var t=e("#content-review__dialog-wrapper");return t.length||(t=e('<div id="content-review__dialog-wrapper" />'),e("body").append(t)),t.open(),!1}}),e(".content-review-modal .content-review-modal__nav-link").entwine({onclick:function(n){n.preventDefault();var t=e(n.target);window.location=t.attr("href")}}),e("#content-review__dialog-wrapper").entwine({onunmatch:function(){this._clearModal()},open:function(){this._renderModal(!0)},close:function(){this._renderModal(!1)},_renderModal:function(n){var t=this,o=function(){return t.close()},r=function(){return t._handleSubmitModal.apply(t,arguments)},s=e("form.cms-edit-form :input[name=ID]").val(),c=window.ss.store,u=c.getState().config.sections.find(function(e){return"SilverStripe\\CMS\\Controllers\\CMSPageEditController"===e.name}),l=u.form.ReviewContentForm.schemaUrl+"/"+s,_=i.a._t("ContentReview.CONTENT_DUE_FOR_REVIEW","Content due for review");d.a.render(a.a.createElement(f,{title:_,isOpen:n,onSubmit:r,onClosed:o,schemaUrl:l,bodyClassName:"modal__dialog",className:"content-review-modal",responseClassBad:"modal__response modal__response--error",responseClassGood:"modal__response modal__response--good",identifier:"ContentReview.CONTENT_DUE_FOR_REVIEW"}),this[0])},_clearModal:function(){d.a.unmountComponentAtNode(this[0])},_handleSubmitModal:function(n,t,o){return e(".content-review__button-holder").remove(),o()}})})},function(e,n,t){"use strict";var o=t(0);t.n(o).a.entwine("ss",function(e){e(".cms-edit-form #Form_EditForm_ContentReviewType_Holder").entwine({onmatch:function(){var e=this;this.find(".optionset :input").bind("change",function(n){e.show_option(n.target.value)});var n=this.find("input[name=ContentReviewType]:checked").val();this.show_option(n),this._super()},onunmatch:function(){return this._super()},show_option:function(e){"Custom"===e?this._custom():"Inherit"===e?this._inherited():this._disabled()},_custom:function(){e(".review-settings").show(),e(".field.custom-setting").show()},_inherited:function(){e(".review-settings").show(),e(".field.custom-setting").hide()},_disabled:function(){e(".review-settings").hide()}})})},function(e,n,t){"use strict";var o=t(0);t.n(o).a.entwine("ss",function(e){function n(n){var t="ContentReviewOwnerID"+n,o=e("div.subsiteSpecificOwnerID"),i=0;for(i=0;i<o.length;i++)o[i].id===t?e(o[i]).show():e(o[i]).hide()}e("#Form_EditForm_SubsiteIDWithOwner").entwine({onmatch:function(){n(this.value)},change:function(){n(this.value)}})})},function(e,n,t){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),t(1),t(2),t(3)},function(e,n){e.exports=Injector},function(e,n){e.exports=React},function(e,n){e.exports=ReactDom},function(e,n){e.exports=i18n}]);

1
client/dist/styles/contentreview.css vendored Normal file
View File

@ -0,0 +1 @@
.content-review__button{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAoCAYAAAD+MdrbAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPlJREFUeNpi/P//PwM1AeOAGPg1h3EBiOae8j+BkFoWIi22pIoLgS5rAFIFQMwPFfoIxBNAGOjaDyQZCDTsApDSx2HXRSB2wGYoEx6X6ePxmT7U5QxEGYhLMTFqMLwMdJ0AkHpPZBwYAr19gZALDUhIdgLEeplsQBcDBUjQr4A3UoARQlbGBkYMI828TN/SBkeaFMSVjwl6GaqxEUmoEZ9hA1fAjkADL8dC6hTdxYOtTgG6DGedAnQtaXUK0DCCdQo2Q5nwuGyQ1ilA15FUpwC9PVqn0LJOAUYIWRkbGDHDpU7BkSYFceVjgl6GakSpU/AZNjRKbIAAAwDhCJTckjfR5wAAAABJRU5ErkJggg==) 50% no-repeat;background-position:0 0;display:inline-block;height:20px;margin:6px 4px 0 12px;padding:0;text-indent:-9999px;width:20px}.content-review__button:focus,.content-review__button:hover{background-position:0 -20px}

11
client/lang/en.js Normal file
View File

@ -0,0 +1,11 @@
// This file was generated by silverstripe/tx-translator from client/lang/src/en.json.
// See https://github.com/silverstripe/silverstripe-tx-translator for details
if (typeof(ss) === 'undefined' || typeof(ss.i18n) === 'undefined') {
if (typeof(console) !== 'undefined') { // eslint-disable-line no-console
console.error('Class ss.i18n not defined'); // eslint-disable-line no-console
}
} else {
ss.i18n.addDictionary('en', {
"ContentReview.CONTENT_DUE_FOR_REVIEW": "Content due for review"
});
}

11
client/lang/sk.js Normal file
View File

@ -0,0 +1,11 @@
// This file was generated by silverstripe/tx-translator from client/lang/src/sk.json.
// See https://github.com/silverstripe/silverstripe-tx-translator for details
if (typeof(ss) === 'undefined' || typeof(ss.i18n) === 'undefined') {
if (typeof(console) !== 'undefined') { // eslint-disable-line no-console
console.error('Class ss.i18n not defined'); // eslint-disable-line no-console
}
} else {
ss.i18n.addDictionary('sk', {
"ContentReview.CONTENT_DUE_FOR_REVIEW": "Obsah určený na kontrolu"
});
}

3
client/lang/src/en.json Normal file
View File

@ -0,0 +1,3 @@
{
"ContentReview.CONTENT_DUE_FOR_REVIEW": "Content due for review"
}

3
client/lang/src/sk.json Normal file
View File

@ -0,0 +1,3 @@
{
"ContentReview.CONTENT_DUE_FOR_REVIEW": "Obsah určený na kontrolu"
}

View File

@ -0,0 +1,102 @@
/* global window */
import i18n from 'i18n';
import jQuery from 'jquery';
import React from 'react';
import ReactDOM from 'react-dom';
import { loadComponent } from 'lib/Injector';
const FormBuilderModal = loadComponent('FormBuilderModal');
/**
* "Content due for review" modal popup. See AddToCampaignForm.js in
* silverstripe/admin for reference.
*/
jQuery.entwine('ss', ($) => {
/**
* Kick off a "content due for review" dialog from the CMS actions.
*/
$('.cms-content-actions .content-review__button').entwine({
onclick(event) {
event.preventDefault();
let dialog = $('#content-review__dialog-wrapper');
if (!dialog.length) {
dialog = $('<div id="content-review__dialog-wrapper" />');
$('body').append(dialog);
}
dialog.open();
return false;
},
});
// This is required because the React version of e.preventDefault() doesn't work
// this is to prevent PJAX request to occur when clicking a link the modal
$('.content-review-modal .content-review-modal__nav-link').entwine({
onclick: (e) => {
e.preventDefault();
const $link = $(e.target);
window.location = $link.attr('href');
},
});
/**
* Uses reactstrap in order to replicate the bootstrap styling and JavaScript behaviour.
*/
$('#content-review__dialog-wrapper').entwine({
onunmatch() {
// solves errors given by ReactDOM "no matched root found" error.
this._clearModal();
},
open() {
this._renderModal(true);
},
close() {
this._renderModal(false);
},
_renderModal(isOpen) {
const handleHide = () => this.close();
const handleSubmit = (...args) => this._handleSubmitModal(...args);
const id = $('form.cms-edit-form :input[name=ID]').val();
const sectionConfigKey = 'SilverStripe\\CMS\\Controllers\\CMSPageEditController';
const store = window.ss.store;
const sectionConfig = store.getState().config.sections
.find((section) => section.name === sectionConfigKey);
const modalSchemaUrl = `${sectionConfig.form.ReviewContentForm.schemaUrl}/${id}`;
const title = i18n._t('ContentReview.CONTENT_DUE_FOR_REVIEW', 'Content due for review');
ReactDOM.render(
<FormBuilderModal
title={title}
isOpen={isOpen}
onSubmit={handleSubmit}
onClosed={handleHide}
schemaUrl={modalSchemaUrl}
bodyClassName="modal__dialog"
className="content-review-modal"
responseClassBad="modal__response modal__response--error"
responseClassGood="modal__response modal__response--good"
identifier="ContentReview.CONTENT_DUE_FOR_REVIEW"
/>,
this[0]
);
},
_clearModal() {
ReactDOM.unmountComponentAtNode(this[0]);
},
_handleSubmitModal(data, action, submitFn) {
// Remove the "review content" bell button so users won't do it again
$('.content-review__button-holder').remove();
// Handle the review submission
return submitFn();
},
});
});

View File

@ -0,0 +1,52 @@
import jQuery from 'jquery';
jQuery.entwine('ss', ($) => {
/**
* Class: .cms-edit-form #Form_EditForm_ContentReviewType_Holder
*
* Toggle display of group dropdown in "access" tab,
* based on selection of radiobuttons.
*/
$('.cms-edit-form #Form_EditForm_ContentReviewType_Holder').entwine({
// Constructor: onmatch
onmatch() {
const self = this;
this.find('.optionset :input').bind('change', (e) => {
self.show_option(e.target.value);
});
// initial state
const currentVal = this.find('input[name=ContentReviewType]:checked').val();
this.show_option(currentVal);
this._super();
},
onunmatch() {
return this._super();
},
show_option(value) {
if (value === 'Custom') {
this._custom();
} else if (value === 'Inherit') {
this._inherited();
} else {
this._disabled();
}
},
_custom() {
$('.review-settings').show();
$('.field.custom-setting').show();
},
_inherited() {
$('.review-settings').show();
$('.field.custom-setting').hide();
},
_disabled() {
$('.review-settings').hide();
},
});
});

View File

@ -0,0 +1,33 @@
import jQuery from 'jquery';
/**
* @todo Re-validate this with Subsites
*/
jQuery.entwine('ss', ($) => {
// Hide all owner dropdowns except the one for the current subsite
function showCorrectSubsiteIDDropdown(value) {
const domid = `ContentReviewOwnerID${value}`;
const ownerIDDropdowns = $('div.subsiteSpecificOwnerID');
let i = 0;
for (i = 0; i < ownerIDDropdowns.length; i++) {
if (ownerIDDropdowns[i].id === domid) {
$(ownerIDDropdowns[i]).show();
} else {
$(ownerIDDropdowns[i]).hide();
}
}
}
$('#Form_EditForm_SubsiteIDWithOwner').entwine({
// Call method to show on report load
onmatch() {
showCorrectSubsiteIDDropdown(this.value);
},
// Call method to show on dropdown change
change() {
showCorrectSubsiteIDDropdown(this.value);
},
});
});

View File

@ -0,0 +1,3 @@
import 'bundles/ContentReviewForm.js';
import 'bundles/ContentReviewSettings.js';
import 'bundles/PagesDueForReview.js';

Binary file not shown.

After

Width:  |  Height:  |  Size: 364 B

View File

@ -0,0 +1,17 @@
// The bell button, shows up next to the major actions (save, publish, etc) when
// viewing a page in the CMS
.content-review__button {
background: url("images/icon-bell.png") center center no-repeat;
background-position: 0 0;
display: inline-block;
height: 20px;
margin: 6px 4px 0 12px;
padding: 0;
text-indent: -9999px;
width: 20px;
&:hover,
&:focus {
background-position: 0 -20px;
}
}

View File

@ -0,0 +1 @@
@import "ContentReviewForm";

1
code-of-conduct.md Normal file
View File

@ -0,0 +1 @@
When having discussions about this module in issues or pull request please adhere to the [SilverStripe Community Code of Conduct](https://docs.silverstripe.org/en/contributing/code_of_conduct).

View File

@ -1,52 +0,0 @@
<?php
/**
* Daily task to send emails to the owners of content items
* when the review date rolls around
*
* @package contentreview
*/
class ContentReviewEmails extends DailyTask {
function run($req) { $this->process(); }
function process() {
// Disable subsite filter (if installed)
if (ClassInfo::exists('Subsite')) {
$oldSubsiteState = Subsite::$disable_subsite_filter;
Subsite::$disable_subsite_filter = true;
}
$pages = DataObject::get('Page', "\"SiteTree\".\"NextReviewDate\" = '".(class_exists('SS_Datetime') ? SS_Datetime::now()->URLDate() : SSDatetime::now()->URLDate())."' AND \"SiteTree\".\"OwnerID\" != 0");
if ($pages && $pages->Count()) {
foreach($pages as $page) {
$owner = $page->Owner();
if ($owner) {
$sender = Security::findAnAdministrator();
$recipient = $owner;
$subject = sprintf(_t('ContentReviewEmails.SUBJECT', 'Page %s due for content review'), $page->Title);
$email = new Email();
$email->setTo($recipient->Email);
$email->setFrom(($sender->Email) ? $sender->Email : Email::getAdminEmail());
$email->setTemplate('ContentReviewEmails');
$email->setSubject($subject);
$email->populateTemplate(array(
"PageCMSLink" => "admin/show/".$page->ID,
"Recipient" => $recipient,
"Sender" => $sender,
"Page" => $page,
"StageSiteLink" => Controller::join_links($page->Link(), "?stage=Stage"),
"LiveSiteLink" => Controller::join_links($page->Link(), "?stage=Live"),
));
$email->send();
}
}
}
// Revert subsite filter (if installed)
if (ClassInfo::exists('Subsite')) {
Subsite::$disable_subsite_filter = $oldSubsiteState;
}
}
}

View File

@ -1,161 +0,0 @@
<?php
require_once 'Zend/Date.php';
/**
* Show all pages that need to be reviewed
*
* @package contentreview
*/
class PagesDueForReviewReport extends SS_Report {
function title() {
return _t('PagesDueForReviewReport.TITLE', 'Pages due for review');
}
function parameterFields() {
$params = new FieldSet();
// We need to be a bit fancier when subsites is enabled
if(class_exists('Subsite') && $subsites = DataObject::get('Subsite')) {
// javascript for subsite specific owner dropdown
Requirements::javascript('contentreview/javascript/PagesDueForReviewReport.js');
// Remember current subsite
$existingSubsite = Subsite::currentSubsiteID();
$map = array();
// Create a map of all potential owners from all applicable sites
$sites = Subsite::accessible_sites('CMS_ACCESS_CMSMain');
foreach($sites as $site) {
Subsite::changeSubsite($site);
$cmsUsers = Permission::get_members_by_permission(array("CMS_ACCESS_CMSMain", "ADMIN"));
// Key-preserving merge
foreach($cmsUsers->toDropdownMap('ID', 'Title') as $k => $v) {
$map[$k] = $v;
}
}
$map = $map + array('' => 'Any', '-1' => '(no owner)');
$params->push(new DropdownField("OwnerID", 'Page owner', $map));
// Restore current subsite
Subsite::changeSubsite($existingSubsite);
} else {
$cmsUsers = Permission::get_members_by_permission(array("CMS_ACCESS_CMSMain", "ADMIN"));
$map = $cmsUsers->map('ID', 'Title', '(no owner)');
unset($map['']);
$map = array('' => 'Any', '-1' => '(no owner)') + $map;
$params->push(new DropdownField("OwnerID", 'Page owner', $map));
}
$params->push($startDate = new CalendarDateField('ReviewDateAfter', 'Review date after or on (DD/MM/YYYY)'));
$params->push($endDate = new CalendarDateField('ReviewDateBefore', 'Review date before or on (DD/MM/YYYY)', date('d/m/Y', strtotime('midnight'))));
$endDate->mustBeAfter($startDate->Name());
$startDate->mustBeBefore($endDate->Name());
$params->push(new CheckboxField('ShowVirtualPages', 'Show Virtual Pages'));
return $params;
}
function columns() {
$fields = array(
'Title' => array(
'title' => 'Page name',
'formatting' => '<a href=\"admin/show/$ID\" title=\"Edit page\">$value</a>'
),
'NextReviewDate' => array(
'title' => 'Review Date',
'casting' => 'Date->Full'
),
'OwnerNames' => array(
'title' => 'Owner'
),
'LastEditedByName' => 'Last edited by',
'AbsoluteLink' => array(
'title' => 'URL',
'formatting' => '$value " . ($AbsoluteLiveLink ? "<a target=\"_blank\" href=\"$AbsoluteLiveLink\">(live)</a>" : "") . " <a target=\"_blank\" href=\"$value?stage=Stage\">(draft)</a>'
)
);
return $fields;
}
function sourceRecords($params, $sort, $limit) {
$wheres = array();
if(empty($params['ReviewDateBefore']) && empty($params['ReviewDateAfter'])) {
// If there's no review dates set, default to all pages due for review now
$reviewDate = new Zend_Date(SS_Datetime::now()->getValue());
$reviewDate->add(1, Zend_Date::DAY);
$wheres[] = sprintf('"NextReviewDate" < \'%s\'', $reviewDate->toString('YYYY-MM-dd'));
} else {
// Review date before
if(!empty($params['ReviewDateBefore'])) {
list($day, $month, $year) = explode('/', $params['ReviewDateBefore']);
$reviewDate = new Zend_Date("$year-$month-$day");
$reviewDate->add(1, Zend_Date::DAY);
$wheres[] = sprintf('"NextReviewDate" < \'%s\'', $reviewDate->toString('YYYY-MM-dd'));
}
// Review date after
if(!empty($params['ReviewDateAfter'])) {
list($day, $month, $year) = explode('/', $params['ReviewDateAfter']);
$reviewDate = new Zend_Date("$year-$month-$day");
$wheres[] = sprintf('"NextReviewDate" >= \'%s\'', $reviewDate->toString('YYYY-MM-dd'));
}
}
// Show virtual pages?
if(empty($params['ShowVirtualPages'])) {
$virtualPageClasses = ClassInfo::subclassesFor('VirtualPage');
$wheres[] = sprintf(
'"SiteTree"."ClassName" NOT IN (\'%s\')',
implode("','", array_values($virtualPageClasses))
);
}
// We use different dropdown depending on the subsite
$ownerIdParam = 'OwnerID';
// Owner dropdown
if(!empty($params[$ownerIdParam])) {
$ownerID = (int)$params[$ownerIdParam];
// We use -1 here to distinguish between No Owner and Any
if($ownerID == -1) $ownerID = 0;
$wheres[] = '"OwnerID" = ' . $ownerID;
}
$query = singleton("SiteTree")->extendedSQL(join(' AND ', $wheres));
// Turn a query into records
if($sort) {
$parts = explode(' ', $sort);
$field = $parts[0];
$direction = $parts[1];
if($field == 'AbsoluteLink') {
$sort = '"URLSegment" ' . $direction;
} elseif($field == 'Subsite.Title') {
$query->from[] = 'LEFT JOIN "Subsite" ON "Subsite"."ID" = "SiteTree"."SubsiteID"';
}
if($field != "LastEditedByName") {
$query->orderby = $sort;
}
}
$records = singleton('SiteTree')->buildDataObjectSet($query->execute(), 'DataObjectSet', $query);
if($records) {
if($sort && $field != "LastEditedByName") $records->sort($sort);
// Apply limit after that filtering.
if($limit) return $records->getRange($limit['start'], $limit['limit']);
else return $records;
}
}
}

View File

@ -1,82 +0,0 @@
<?php
/**
* Set dates at which content needs to be reviewed and provide
* a report and emails to alert to content needing review
*
* @package contentreview
*/
class SiteTreeContentReview extends DataObjectDecorator implements PermissionProvider {
function extraStatics() {
return array(
'db' => array(
"ReviewPeriodDays" => "Int",
"NextReviewDate" => "Date",
'ReviewNotes' => 'Text',
'LastEditedByName' => 'Varchar(255)',
'OwnerNames' => 'Varchar(255)'
),
'has_one' => array(
'Owner' => 'Member',
),
);
}
function getOwnerName() {
if($this->owner->OwnerID && $this->owner->Owner()) return $this->owner->Owner()->FirstName . ' ' . $this->owner->Owner()->Surname;
}
function getEditorName() {
if( $member = Member::currentUser() ) {
return $member->FirstName .' '. $member->Surname;
}
return NULL;
}
public function updateCMSFields(&$fields) {
if(Permission::check("EDIT_CONTENT_REVIEW_FIELDS")) {
$cmsUsers = Permission::get_members_by_permission(array("CMS_ACCESS_CMSMain", "ADMIN"));
$fields->addFieldsToTab("Root.Review", array(
new HeaderField(_t('SiteTreeCMSWorkflow.REVIEWHEADER', "Content review"), 2),
new DropdownField("OwnerID", _t("SiteTreeCMSWorkflow.PAGEOWNER",
"Page owner (will be responsible for reviews)"), $cmsUsers->map('ID', 'Title', '(no owner)')),
new CalendarDateField("NextReviewDate", _t("SiteTreeCMSWorkflow.NEXTREVIEWDATE",
"Next review date (leave blank for no review)")),
new DropdownField("ReviewPeriodDays", _t("SiteTreeCMSWorkflow.REVIEWFREQUENCY",
"Review frequency (the review date will be set to this far in the future whenever the page is published.)"), array(
0 => "No automatic review date",
1 => "1 day",
7 => "1 week",
30 => "1 month",
60 => "2 months",
91 => "3 months",
121 => "4 months",
152 => "5 months",
183 => "6 months",
365 => "12 months",
)),
new TextareaField('ReviewNotes', 'Review Notes')
));
}
}
function onBeforeWrite() {
if($this->owner->ReviewPeriodDays && !$this->owner->NextReviewDate) {
$this->owner->NextReviewDate = date('Y-m-d', strtotime('+' . $this->owner->ReviewPeriodDays . ' days'));
}
$this->owner->LastEditedByName=$this->owner->getEditorName();
$this->owner->OwnerNames = $this->owner->getOwnerName();
}
function providePermissions() {
return array(
"EDIT_CONTENT_REVIEW_FIELDS" => array(
'name' => "Set content owners and review dates",
'category' => _t('Permissions.CONTENT_CATEGORY', 'Content permissions'),
'sort' => 50
)
);
}
}

1
codecov.yml Normal file
View File

@ -0,0 +1 @@
comment: false

55
composer.json Normal file
View File

@ -0,0 +1,55 @@
{
"name": "silverstripe/contentreview",
"type": "silverstripe-vendormodule",
"description": "Flags pages for periodical author review (incl. reporting)",
"homepage": "http://silverstripe.org",
"license": "BSD-3-Clause",
"keywords": [
"silverstripe",
"cms",
"workflow",
"content review",
"review",
"permissions"
],
"authors": [
{
"name": "SilverStripe",
"homepage": "http://silverstripe.com"
},
{
"name": "The SilverStripe Community",
"homepage": "http://silverstripe.org"
}
],
"require": {
"php": "^7.4 || ^8.0",
"silverstripe/vendor-plugin": "^1",
"silverstripe/framework": "^4.10",
"silverstripe/cms": "^4.2",
"silverstripe/reports": "^4.2",
"silverstripe/siteconfig": "^4.2"
},
"require-dev": {
"silverstripe/recipe-testing": "^2",
"squizlabs/php_codesniffer": "^3",
"symbiote/silverstripe-queuedjobs": "^4.9"
},
"suggest": {
"symbiote/silverstripe-queuedjobs": "Automatically schedules content review emails to be sent, only requiring one crontask to be created"
},
"extra": {
"expose": [
"client/dist"
]
},
"autoload": {
"psr-4": {
"SilverStripe\\ContentReview\\": "src/",
"SilverStripe\\ContentReview\\Tests\\": "tests/php/",
"SilverStripe\\ContentReview\\Tests\\Behat\\Context\\": "tests/behat/src/"
}
},
"minimum-stability": "dev",
"prefer-stable": true
}

3
contributing.md Normal file
View File

@ -0,0 +1,3 @@
# Contributing
Contributions are welcome! Create an issue, explaining a bug or proposal. Submit pull requests if you feel brave. Speak to me on [Twitter](https://twitter.com/assertchris).

36
docs/en/index.md Normal file
View File

@ -0,0 +1,36 @@
# Content Review module developer documentation
## Configuration
### Global settings
The module is set up in the `Settings` section of the CMS, see the [User guide](userguide/index.md).
### Reminder emails
In order for the contentreview module to send emails, you need to *either*:
* Setup the `ContentReviewEmails` script to run daily via a system cron job.
* Install the [queuedjobs](https://github.com/symbiote/silverstripe-queuedjobs) module and follow the configuration steps to create a cron job for that module. Once installed, you can just run `dev/build` to have a job created, which will run at 9am every day by default.
## Using
See the [user guide](userguide/index.md).
## Testing
cd to the site root, and run:
```sh
$ php vendor/bin/behat @contentreview
```
or to run the unit test suite:
```sh
$ php vendor/bin/phpunit contentreview/tests
```
## Migration
If you are upgrading from an older version, you may need to run the `ContentReviewOwnerMigrationTask`

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

View File

@ -0,0 +1,29 @@
---
title: Content review
summary: Mark pages in the CMS with a date and an owner for future reviews.
---
## Content review
## Setting up
Global settings can be configured via the global settings admin in the CMS under the "Content Review" tab.
This includes global groups, users, as well as a template editor that supports a limited number of variables.
![SiteConfig settings](_images/content-review-siteconfig-settings.png)
## Schedules
To set up content review schedules you need to log in as a user with the 'Set content owners and review dates' permission. This can either
be an administrator who has all permissions, or by giving a group the specific permission.
![Content review permissions](_images/content-review-permission.png)
To set a content review schedule for a page go to `Settings > Content Review`.
![Page content review settings](_images/content-review-settings.png)
CMS users without the permission to change the content review schedule can still see the settings
and previous reviews in the same view, but cannot change anything.
![Read only view of page content review settings](_images/content-review-settings-ro.png)

View File

@ -1,31 +0,0 @@
(function($) {
// Hide all owner dropdowns except the one for the current subsite
function showCorrectSubsiteIDDropdown(value) {
var domid = 'OwnerID' + value;
var ownerIDDropdowns = $('div.subsiteSpecificOwnerID');
for(var i = 0; i < ownerIDDropdowns.length; i++) {
if(ownerIDDropdowns[i].id == domid)
$(ownerIDDropdowns[i]).show();
else
$(ownerIDDropdowns[i]).hide();
}
}
// Call method to show on report load
$('#Form_EditForm_SubsiteIDWithOwner').livequery(
function() {
showCorrectSubsiteIDDropdown(this.value);
}
);
// Call method to show on dropdown change
$('#Form_EditForm_SubsiteIDWithOwner').livequery('change',
function() {
showCorrectSubsiteIDDropdown(this.value);
}
);
})(jQuery);

0
lang/_manifest_exclude Normal file
View File

16
lang/de.yml Normal file
View File

@ -0,0 +1,16 @@
de:
SilverStripe\ContentReview\Extensions\ContentReviewDefaultSettings:
ADDGROUP: 'Gruppen hinzufügen'
ADDUSERS: 'Benutzer hinzufügen'
EMAILSUBJECT: Betreff
PAGEOWNERGROUPS: Gruppen
PAGEOWNERUSERS: Benutzer
SilverStripe\ContentReview\Extensions\SiteTreeContentReview:
ADDGROUP: 'Gruppen hinzufügen'
ADDUSERS: 'Benutzer hinzufügen'
CUSTOM: 'Benutzerdefinierte Einstellungen'
OPTIONS: Optionen
PAGEOWNERGROUPS: Gruppen
PAGEOWNERUSERS: Benutzer
SilverStripe\ContentReview\Forms\ReviewContentHandler:
Placeholder: 'Kommentare hinzufügen (optional)'

78
lang/en.yml Normal file
View File

@ -0,0 +1,78 @@
en:
SilverStripe\ContentReview\Extensions\ContentReviewCMSExtension:
ErrorItemPermissionDenied: 'It seems you don''t have the necessary permissions to review this content'
SilverStripe\ContentReview\Extensions\ContentReviewDefaultSettings:
ADDGROUP: 'Add groups'
ADDUSERS: 'Add users'
DEFAULTSETTINGSHELP: 'These settings will apply to all pages that do not have a specific Content Review schedule.'
EMAILFROM: 'From email address'
EMAILFROM_RIGHTTITLE: 'e.g: do-not-reply@site.com'
EMAILSUBJECT: 'Subject line'
EMAILTEMPLATE: 'Email template'
OWNERGROUPSDESCRIPTION: 'Page owners that are responsible for reviews'
OWNERUSERSDESCRIPTION: 'Page owners that are responsible for reviews'
PAGEOWNERGROUPS: Groups
PAGEOWNERUSERS: Users
REVIEWFREQUENCY: 'Review frequency'
REVIEWFREQUENCYDESCRIPTION: 'The review date will be set to this far in the future, whenever the page is published.'
db_ReviewBody: 'Review body'
db_ReviewFrom: 'Review from'
db_ReviewPeriodDays: 'Review period days'
db_ReviewSubject: 'Review subject'
many_many_ContentReviewGroups: 'Content review groups'
many_many_ContentReviewUsers: 'Content review users'
SilverStripe\ContentReview\Extensions\ContentReviewOwner:
many_many_SiteTreeContentReview: 'Site tree content review'
SilverStripe\ContentReview\Extensions\SiteTreeContentReview:
ADDGROUP: 'Add groups'
ADDUSERS: 'Add users'
CONTENTOWNERS: 'Content Owners'
CONTENTREVIEW: 'Content due for review'
CUSTOM: 'Custom settings'
DISABLE: 'Disable content review'
INHERIT: 'Inherit from parent page'
NEXTREVIEWDATADESCRIPTION: 'Leave blank for no review'
NEXTREVIEWDATE: 'Next review date'
OPTIONS: Options
OWNERGROUPSDESCRIPTION: 'Page owners that are responsible for reviews'
OWNERUSERSDESCRIPTION: 'Page owners that are responsible for reviews'
PAGEOWNERGROUPS: Groups
PAGEOWNERUSERS: Users
REVIEWFREQUENCY: 'Review frequency'
REVIEWFREQUENCYDESCRIPTION: 'The review date will be set to this far in the future whenever the page is published'
REVIEWHEADER: 'Content review'
SETTINGSFROM: 'Options are'
belongs_many_many_ContentReviewGroups: 'Content review groups'
belongs_many_many_ContentReviewUsers: 'Content review users'
db_ContentReviewType: 'Content review type'
db_LastEditedByName: 'Last edited by name'
db_NextReviewDate: 'Next review date'
db_OwnerNames: 'Owner names'
db_ReviewPeriodDays: 'Review period days'
has_many_ReviewLogs: 'Review logs'
SilverStripe\ContentReview\Forms\ReviewContentHandler:
ErrorReviewPermissionDenied: 'It seems you don''t have the necessary permissions to submit a content review'
MarkAsReviewedAction: 'Mark as reviewed'
NoComments: '(no comments)'
Placeholder: 'Add comments (optional)'
Success: 'Review successfully added'
SilverStripe\ContentReview\Models\ContentReviewLog:
PLURALNAME: 'Content Review Logs'
PLURALS:
one: 'A Content Review Log'
other: '{count} Content Review Logs'
SINGULARNAME: 'Content Review Log'
db_Note: Note
has_one_Reviewer: Reviewer
has_one_SiteTree: 'Site tree'
SilverStripe\ContentReview\Reports\PagesDueForReviewReport:
ONLYMYPAGES: 'Only Show pages assigned to me'
REVIEWDATEAFTER: 'Review date after or on'
REVIEWDATEBEFORE: 'Review date before or on'
SHOWVIRTUALPAGES: 'Show Virtual Pages'
TITLE: 'Pages due for review'
SilverStripe\ContentReview\Reports\PagesWithoutReviewScheduleReport:
TITLE: 'Pages without a scheduled review.'
SilverStripe\ContentReview\Tasks\ContentReviewEmails:
REVIEWPAGELINK: 'Review the page in the CMS'
VIEWPUBLISHEDLINK: 'View this page on the website'

80
lang/sk.yml Normal file
View File

@ -0,0 +1,80 @@
sk:
SilverStripe\ContentReview\Extensions\ContentReviewCMSExtension:
ErrorItemPermissionDenied: 'Zdá sa, že nemáte potrebné oprávnenia na kontrolu tohto obsahu'
SilverStripe\ContentReview\Extensions\ContentReviewDefaultSettings:
ADDGROUP: 'Pridať skupiny'
ADDUSERS: 'Pridať používateľov'
DEFAULTSETTINGSHELP: 'Tieto nastavenia sa použijú na všetky stránky, ktoré nemajú špecifický plán kontroly obsahu.'
EMAILFROM: 'Z e-mailovej adresy'
EMAILFROM_RIGHTTITLE: 'napr.: do-not-reply@site.com'
EMAILSUBJECT: Predmet
EMAILTEMPLATE: 'Šablóna e-mailu'
OWNERGROUPSDESCRIPTION: 'Vlastníci stránok, ktorí sú zodpovední za kontrolu'
OWNERUSERSDESCRIPTION: 'Vlastníci stránok, ktorí sú zodpovední za kontrolu'
PAGEOWNERGROUPS: Skupiny
PAGEOWNERUSERS: Používatelia
REVIEWFREQUENCY: 'Frekvencia kontroly'
REVIEWFREQUENCYDESCRIPTION: 'Dátum kontroly bude nastavený na tento dátum v budúcnosti, bez ohľadu na to, kedy bude stránka zverejnená.'
db_ReviewBody: 'Revízny orgán'
db_ReviewFrom: 'Kontrola od'
db_ReviewPeriodDays: 'Dni periódy kontroly'
db_ReviewSubject: 'Predmet kontroly'
many_many_ContentReviewGroups: 'Skupiny kontroly obsahu'
many_many_ContentReviewUsers: 'Používatelia kontroly obsahu'
SilverStripe\ContentReview\Extensions\ContentReviewOwner:
many_many_SiteTreeContentReview: 'Kontrola obsahu stromu stránok'
SilverStripe\ContentReview\Extensions\SiteTreeContentReview:
ADDGROUP: 'Pridať skupiny'
ADDUSERS: 'Pridať používateľov'
CONTENTOWNERS: 'Vlastníci obsahu'
CONTENTREVIEW: 'Obsah určený na kontrolu'
CUSTOM: 'Vlastné nastavenia'
DISABLE: 'Zakázať kontrolu obsahu'
INHERIT: 'Zdediť z nadradenej stránky'
NEXTREVIEWDATADESCRIPTION: 'Ak nechcete vyplniť kontrolu, ponechajte pole prázdne'
NEXTREVIEWDATE: 'Dátum ďalšej kontroly'
OPTIONS: Možnosti
OWNERGROUPSDESCRIPTION: 'Vlastníci stránok, ktorí sú zodpovední za kontrolu'
OWNERUSERSDESCRIPTION: 'Vlastníci stránok, ktorí sú zodpovední za kontrolu'
PAGEOWNERGROUPS: Skupiny
PAGEOWNERUSERS: Používatelia
REVIEWFREQUENCY: 'Frekvencia kontroly'
REVIEWFREQUENCYDESCRIPTION: 'Dátum kontroly bude nastavený na tento dátum v budúcnosti, bez ohľadu na to, kedy bude stránka zverejnená.'
REVIEWHEADER: 'Kontrola obsahu'
SETTINGSFROM: 'Možnosti sú'
belongs_many_many_ContentReviewGroups: 'Skupiny kontroly obsahu'
belongs_many_many_ContentReviewUsers: 'Používatelia kontroly obsahu'
db_ContentReviewType: 'Typ kontroly obsahu'
db_LastEditedByName: 'Naposledy upravené podľa mena'
db_NextReviewDate: 'Dátum ďalšej kontroly'
db_OwnerNames: 'Mená vlastníkov'
db_ReviewPeriodDays: 'Dni periódy kontroly'
has_many_ReviewLogs: 'Záznamy z kontroly'
SilverStripe\ContentReview\Forms\ReviewContentHandler:
ErrorReviewPermissionDenied: 'Zdá sa, že nemáte potrebné oprávnenia na odoslanie kontroly obsahu'
MarkAsReviewedAction: 'Označiť ako skontrolované'
NoComments: '(bez komentára)'
Placeholder: 'Pridať komentáre (voliteľné)'
Success: 'Kontrola bola úspešne pridaná'
SilverStripe\ContentReview\Models\ContentReviewLog:
PLURALNAME: 'Záznamy z kontroly obsahu'
PLURALS:
few: '{count} záznamy z kontroly obsahu'
many: '{count} záznamov z kontroly obsahu'
one: 'Záznam z kontroly obsahu'
other: '{count} záznamov z kontroly obsahu'
SINGULARNAME: 'Záznam z kontroly obsahu'
db_Note: Poznámka
has_one_Reviewer: Kontrolór
has_one_SiteTree: 'Strom stránok'
SilverStripe\ContentReview\Reports\PagesDueForReviewReport:
ONLYMYPAGES: 'Zobraziť iba mne priradené stránky'
REVIEWDATEAFTER: 'Dátum kontroly po'
REVIEWDATEBEFORE: 'Dátum kontroly pred'
SHOWVIRTUALPAGES: 'Zobraziť virtuálne stránky'
TITLE: 'Stránky určené na kontrolu'
SilverStripe\ContentReview\Reports\PagesWithoutReviewScheduleReport:
TITLE: 'Stránky bez naplánovanej kontroly.'
SilverStripe\ContentReview\Tasks\ContentReviewEmails:
REVIEWPAGELINK: 'Skontrolujte stránku v CMS'
VIEWPUBLISHEDLINK: 'Pozrite si túto stránku na webe'

12
license.md Normal file
View File

@ -0,0 +1,12 @@
Copyright (c) 2017, SilverStripe Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

44
package.json Normal file
View File

@ -0,0 +1,44 @@
{
"name": "silverstripe-contentreview",
"version": "4.0.0",
"description": "Flags pages for periodical author review (incl. reporting)",
"scripts": {
"build": "yarn && NODE_ENV=production webpack -p --bail --progress",
"watch": "yarn && NODE_ENV=development webpack --watch --progress",
"css": "WEBPACK_CHILD=css npm run build",
"lint": "eslint client/src; sass-lint -v"
},
"repository": {
"type": "git",
"url": "git+https://github.com/silverstripe/silverstripe-contentreview.git"
},
"keywords": [
"silverstripe",
"cms",
"workflow"
],
"author": "SilverStripe Ltd",
"license": "BSD-3-Clause",
"bugs": {
"url": "https://github.com/silverstripe/silverstripe-contentreview/issues"
},
"homepage": "https://github.com/silverstripe/silverstripe-contentreview#readme",
"dependencies": {
"jquery": "^3.4.0",
"react": "15.3.1",
"react-dom": "15.3.1",
"react-redux": "^4.4.1",
"redux": "https://registry.npmjs.org/redux/-/redux-3.0.5.tgz"
},
"devDependencies": {
"@silverstripe/webpack-config": "^0.2.5",
"babel-core": "^6.24.1",
"babel-preset-es2015": "^6.24.1",
"babel-preset-es2016": "^6.24.1",
"eslint": "^2.7.0",
"eslint-config-airbnb": "^6.2.0"
},
"engines": {
"node": "^10.x"
}
}

13
phpcs.xml.dist Normal file
View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<ruleset name="SilverStripe">
<description>CodeSniffer ruleset for SilverStripe coding conventions.</description>
<file>src</file>
<file>tests</file>
<rule ref="PSR2" >
<!-- Current exclusions -->
<exclude name="PSR1.Methods.CamelCapsMethodName" />
<exclude name="PSR1.Files.SideEffects.FoundWithSymbols" />
</rule>
</ruleset>

16
phpunit.xml.dist Normal file
View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/silverstripe/cms/tests/bootstrap.php" colors="true">
<testsuites>
<testsuite name="Default">
<directory>tests/php/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist addUncoveredFilesFromWhitelist="true">
<directory suffix=".php">src/</directory>
<exclude>
<directory suffix=".php">tests/</directory>
</exclude>
</whitelist>
</filter>
</phpunit>

View File

@ -0,0 +1,47 @@
<?php
namespace SilverStripe\ContentReview\Compatibility;
use SilverStripe\Core\ClassInfo;
use SilverStripe\Subsites\Model\Subsite;
/**
* This is a helper class which lets us do things with content review data without subsites
* messing our SQL queries up.
*
* Make sure any DataQuery instances you are building are BOTH created & executed between start()
* and done() because augmentDataQueryCreate and augmentSQL happens there.
*/
class ContentReviewCompatability
{
const SUBSITES = 0;
/**
* Returns the state of other modules before compatibility mode is started.
*
* @return array
*/
public static function start()
{
$compatibility = [
self::SUBSITES => null,
];
if (ClassInfo::exists(Subsite::class)) {
$compatibility[self::SUBSITES] = Subsite::$disable_subsite_filter;
Subsite::disable_subsite_filter(true);
}
return $compatibility;
}
/**
* @param array $compatibility
*/
public static function done(array $compatibility)
{
if (class_exists(Subsite::class)) {
Subsite::$disable_subsite_filter = $compatibility[self::SUBSITES];
}
}
}

View File

@ -0,0 +1,169 @@
<?php
namespace SilverStripe\ContentReview\Extensions;
use SilverStripe\Admin\LeftAndMain;
use SilverStripe\Admin\LeftAndMainExtension;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\ContentReview\Forms\ReviewContentHandler;
use SilverStripe\ContentReview\Traits\PermissionChecker;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Control\HTTPResponse_Exception;
use SilverStripe\Forms\Form;
use SilverStripe\ORM\ValidationResult;
use SilverStripe\Security\Security;
/**
* CMSPageEditController extension to receive the additional action button from
* SiteTreeContentReview::updateCMSActions()
*/
class ContentReviewCMSExtension extends LeftAndMainExtension
{
use PermissionChecker;
private static $allowed_actions = [
'ReviewContentForm',
'savereview',
];
/**
* URL handler for the "content due for review" form
*
* @param HTTPRequest $request
* @return Form|null
*/
public function ReviewContentForm(HTTPRequest $request)
{
// Get ID either from posted back value, or url parameter
$id = $request->param('ID') ?: $request->postVar('ID');
return $this->getReviewContentForm($id);
}
/**
* Return a handler for "content due for review" forms, according to the given object ID
*
* @param int $id
* @return Form|null
*/
public function getReviewContentForm($id)
{
$page = $this->findRecord(['ID' => $id]);
$user = Security::getCurrentUser();
if (!$this->isContentReviewable($page, $user)) {
$this->owner->httpError(403, _t(
__CLASS__.'.ErrorItemPermissionDenied',
'It seems you don\'t have the necessary permissions to review this content'
));
return null;
}
$form = $this->getReviewContentHandler()->Form($page);
$form->setValidationResponseCallback(function (ValidationResult $errors) use ($form, $id) {
$schemaId = $this->owner->join_links($this->owner->Link('schema/ReviewContentForm'), $id);
return $this->getSchemaResponse($schemaId, $form, $errors);
});
return $form;
}
/**
* Action handler for processing the submitted content review
*
* @param array $data
* @param Form $form
* @return DBHTMLText|HTTPResponse|null
*/
public function savereview($data, Form $form)
{
$page = $this->findRecord($data);
$results = $this->getReviewContentHandler()->submitReview($page, $data);
if (is_null($results)) {
return null;
}
if ($this->getSchemaRequested()) {
// Send extra "message" data with schema response
$extraData = ['message' => $results];
$schemaId = $this->owner->join_links($this->owner->Link('schema/ReviewContentForm'), $page->ID);
return $this->getSchemaResponse($schemaId, $form, null, $extraData);
}
return $results;
}
/**
* Return a handler or reviewing content
*
* @return ReviewContentHandler
*/
protected function getReviewContentHandler()
{
return ReviewContentHandler::create($this->owner);
}
/**
* Find the page this form is updating
*
* @param array $data Form data
* @return SiteTree Record
* @throws HTTPResponse_Exception
*/
protected function findRecord($data)
{
if (empty($data["ID"])) {
throw new HTTPResponse_Exception("No record ID", 404);
}
$page = null;
$id = $data["ID"];
if (is_numeric($id)) {
$page = SiteTree::get()->byID($id);
}
if (!$page || !$page->ID) {
throw new HTTPResponse_Exception("Bad record ID #{$id}", 404);
}
return $page;
}
/**
* Check if the current request has a X-Formschema-Request header set.
* Used by conditional logic that responds to validation results
*
* @todo Remove duplication. See https://github.com/silverstripe/silverstripe-admin/issues/240
*
* @return bool
*/
protected function getSchemaRequested()
{
$parts = $this->owner->getRequest()->getHeader(LeftAndMain::SCHEMA_HEADER);
return !empty($parts);
}
/**
* Generate schema for the given form based on the X-Formschema-Request header value
*
* @todo Remove duplication. See https://github.com/silverstripe/silverstripe-admin/issues/240
*
* @param string $schemaID ID for this schema. Required.
* @param Form $form Required for 'state' or 'schema' response
* @param ValidationResult $errors Required for 'error' response
* @param array $extraData Any extra data to be merged with the schema response
* @return HTTPResponse
*/
protected function getSchemaResponse($schemaID, $form = null, ValidationResult $errors = null, $extraData = [])
{
$parts = $this->owner->getRequest()->getHeader(LeftAndMain::SCHEMA_HEADER);
$data = $this->owner
->getFormSchema()
->getMultipartSchema($parts, $schemaID, $form, $errors);
if ($extraData) {
$data = array_merge($data, $extraData);
}
$response = HTTPResponse::create(json_encode($data));
$response->addHeader('Content-Type', 'application/json');
return $response;
}
}

View File

@ -0,0 +1,243 @@
<?php
namespace SilverStripe\ContentReview\Extensions;
use SilverStripe\Core\Config\Config;
use SilverStripe\Control\Email\Email;
use SilverStripe\Forms\DropdownField;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\ListboxField;
use SilverStripe\Forms\LiteralField;
use SilverStripe\Forms\TextareaField;
use SilverStripe\Forms\TextField;
use SilverStripe\ORM\DataExtension;
use SilverStripe\Security\Group;
use SilverStripe\Security\Member;
use SilverStripe\Security\Permission;
/**
* This extensions add a default schema for new pages and pages without a content
* review setting.
*
* @property int $ReviewPeriodDays
*/
class ContentReviewDefaultSettings extends DataExtension
{
/**
* @config
*
* @var array
*/
private static $db = array(
'ReviewPeriodDays' => 'Int',
'ReviewFrom' => 'Varchar(255)',
'ReviewSubject' => 'Varchar(255)',
'ReviewBody' => 'HTMLText',
);
/**
* @config
*
* @var array
*/
private static $defaults = array(
'ReviewSubject' => 'Page(s) are due for content review',
'ReviewBody' => '<h2>Page(s) due for review</h2>'
. '<p>There are $PagesCount pages that are due for review today by you.</p>',
);
/**
* @config
*
* @var array
*/
private static $many_many = [
'ContentReviewGroups' => Group::class,
'ContentReviewUsers' => Member::class,
];
/**
* Template to use for content review emails.
*
* This should contain an $EmailBody variable as a placeholder for the user-defined copy
*
* @config
*
* @var string
*/
private static $content_review_template = 'SilverStripe\\ContentReview\\ContentReviewEmail';
/**
* @return string
*/
public function getOwnerNames()
{
$names = [];
foreach ($this->OwnerGroups() as $group) {
$names[] = $group->getBreadcrumbs(' > ');
}
foreach ($this->OwnerUsers() as $group) {
$names[] = $group->getName();
}
return implode(', ', $names);
}
/**
* @return ManyManyList
*/
public function OwnerGroups()
{
return $this->owner->getManyManyComponents('ContentReviewGroups');
}
/**
* @return ManyManyList
*/
public function OwnerUsers()
{
return $this->owner->getManyManyComponents('ContentReviewUsers');
}
/**
* @param FieldList $fields
*/
public function updateCMSFields(FieldList $fields)
{
$helpText = LiteralField::create(
'ContentReviewHelp',
_t(
__CLASS__ . '.DEFAULTSETTINGSHELP',
'These settings will apply to all pages that do not have a specific Content Review schedule.'
)
);
$fields->addFieldToTab('Root.ContentReview', $helpText);
$reviewFrequency = DropdownField::create(
'ReviewPeriodDays',
_t(__CLASS__ . '.REVIEWFREQUENCY', 'Review frequency'),
SiteTreeContentReview::get_schedule()
)
->setDescription(_t(
__CLASS__ . '.REVIEWFREQUENCYDESCRIPTION',
'The review date will be set to this far in the future, whenever the page is published.'
));
$fields->addFieldToTab('Root.ContentReview', $reviewFrequency);
$users = Permission::get_members_by_permission([
'CMS_ACCESS_CMSMain',
'CMS_ACCESS_LeftAndMain',
'ADMIN',
]);
$usersMap = $users->map('ID', 'Title')->toArray();
asort($usersMap);
$userField = ListboxField::create('OwnerUsers', _t(__CLASS__ . '.PAGEOWNERUSERS', 'Users'), $usersMap)
->setAttribute('data-placeholder', _t(__CLASS__ . '.ADDUSERS', 'Add users'))
->setDescription(_t(__CLASS__ . '.OWNERUSERSDESCRIPTION', 'Page owners that are responsible for reviews'));
$fields->addFieldToTab('Root.ContentReview', $userField);
$groupsMap = [];
foreach (Group::get() as $group) {
// Listboxfield values are escaped, use ASCII char instead of &raquo;
$groupsMap[$group->ID] = $group->getBreadcrumbs(' > ');
}
asort($groupsMap);
$groupField = ListboxField::create('OwnerGroups', _t(__CLASS__ . '.PAGEOWNERGROUPS', 'Groups'), $groupsMap)
->setAttribute('data-placeholder', _t(__CLASS__ . '.ADDGROUP', 'Add groups'))
->setDescription(_t(__CLASS__ . '.OWNERGROUPSDESCRIPTION', 'Page owners that are responsible for reviews'));
$fields->addFieldToTab('Root.ContentReview', $groupField);
// Email content
$fields->addFieldsToTab(
'Root.ContentReview',
[
TextField::create('ReviewFrom', _t(__CLASS__ . '.EMAILFROM', 'From email address'))
->setDescription(_t(__CLASS__ . '.EMAILFROM_RIGHTTITLE', 'e.g: do-not-reply@site.com')),
TextField::create('ReviewSubject', _t(__CLASS__ . '.EMAILSUBJECT', 'Subject line')),
TextAreaField::create('ReviewBody', _t(__CLASS__ . '.EMAILTEMPLATE', 'Email template')),
LiteralField::create(
'TemplateHelp',
$this->owner->renderWith('SilverStripe\\ContentReview\\ContentReviewAdminHelp')
),
]
);
}
/**
* Get all Members that are default Content Owners. This includes checking group hierarchy
* and adding any direct users.
*
* @return ArrayList
*/
public function ContentReviewOwners()
{
return SiteTreeContentReview::merge_owners($this->OwnerGroups(), $this->OwnerUsers());
}
/**
* Get the review body, falling back to the default if left blank.
*
* @return string HTML text
*/
public function getReviewBody()
{
return $this->getWithDefault('ReviewBody');
}
/**
* Get the review subject line, falling back to the default if left blank.
*
* @return string plain text value
*/
public function getReviewSubject()
{
return $this->getWithDefault('ReviewSubject');
}
/**
* Get the "from" field for review emails.
*
* @return string
*/
public function getReviewFrom()
{
$from = $this->owner->getField('ReviewFrom');
if ($from) {
return $from;
}
// Fall back to admin email
return Config::inst()->get(Email::class, 'admin_email');
}
/**
* Get the value of a user-configured field, falling back to the default if left blank.
*
* @param string $field
*
* @return string
*/
protected function getWithDefault($field)
{
$value = $this->owner->getField($field);
if ($value) {
return $value;
}
// fallback to default value
$defaults = $this->owner->config()->get('defaults');
if (isset($defaults[$field])) {
return $defaults[$field];
}
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace SilverStripe\ContentReview\Extensions;
use SilverStripe\Admin\LeftAndMainExtension;
class ContentReviewLeftAndMainExtension extends LeftAndMainExtension
{
/**
* Append content review schema configuration
*
* @param array &$clientConfig
*/
public function updateClientConfig(&$clientConfig)
{
$clientConfig['form']['ReviewContentForm'] = [
'schemaUrl' => $this->owner->Link('schema/ReviewContentForm')
];
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace SilverStripe\ContentReview\Extensions;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Forms\FieldList;
use SilverStripe\ORM\DataExtension;
class ContentReviewOwner extends DataExtension
{
/**
* @var array
*/
private static $many_many = [
"SiteTreeContentReview" => SiteTree::class,
];
public function updateCMSFields(FieldList $fields)
{
// Remove automatically scaffolded GridField in Member CMS fields
$fields->removeByName('SiteTreeContentReview');
}
}

View File

@ -0,0 +1,695 @@
<?php
namespace SilverStripe\ContentReview\Extensions;
use Exception;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\ContentReview\Jobs\ContentReviewNotificationJob;
use SilverStripe\ContentReview\Models\ContentReviewLog;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Forms\CompositeField;
use SilverStripe\Forms\DateField;
use SilverStripe\Forms\DateTimeField;
use SilverStripe\Forms\DropdownField;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridFieldConfig;
use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor;
use SilverStripe\Forms\GridField\GridFieldDataColumns;
use SilverStripe\Forms\GridField\GridFieldSortableHeader;
use SilverStripe\Forms\HeaderField;
use SilverStripe\Forms\ListboxField;
use SilverStripe\Forms\LiteralField;
use SilverStripe\Forms\OptionsetField;
use SilverStripe\Forms\ReadonlyField;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\DataExtension;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DB;
use SilverStripe\ORM\FieldType\DBDate;
use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\ORM\SS_List;
use SilverStripe\Security\Group;
use SilverStripe\Security\Member;
use SilverStripe\Security\Permission;
use SilverStripe\Security\PermissionProvider;
use SilverStripe\Security\Security;
use SilverStripe\SiteConfig\SiteConfig;
use SilverStripe\View\Requirements;
use Symbiote\QueuedJobs\DataObjects\QueuedJobDescriptor;
use Symbiote\QueuedJobs\Services\QueuedJobService;
/**
* Set dates at which content needs to be reviewed and provide a report and emails to alert
* to content needing review.
*
* @property string $ContentReviewType
* @property int $ReviewPeriodDays
* @property Date $NextReviewDate
* @property string $LastEditedByName
* @property string $OwnerNames
*
* @method DataList ReviewLogs()
* @method DataList ContentReviewGroups()
* @method DataList ContentReviewUsers()
*/
class SiteTreeContentReview extends DataExtension implements PermissionProvider
{
/**
* @var array
*/
private static $db = [
"ContentReviewType" => "Enum('Inherit, Disabled, Custom', 'Inherit')",
"ReviewPeriodDays" => "Int",
"NextReviewDate" => "Date",
"LastEditedByName" => "Varchar(255)",
"OwnerNames" => "Varchar(255)",
];
/**
* @var array
*/
private static $defaults = [
"ContentReviewType" => "Inherit",
];
/**
* @var array
*/
private static $has_many = [
"ReviewLogs" => ContentReviewLog::class,
];
/**
* @var array
*/
private static $belongs_many_many = [
"ContentReviewGroups" => Group::class,
"ContentReviewUsers" => Member::class,
];
/**
* @var array
*/
private static $schedule = [
0 => "No automatic review date",
1 => "1 day",
7 => "1 week",
30 => "1 month",
60 => "2 months",
91 => "3 months",
121 => "4 months",
152 => "5 months",
183 => "6 months",
365 => "12 months",
];
/**
* @return array
*/
public static function get_schedule()
{
return Config::inst()->get(static::class, 'schedule');
}
/**
* Takes a list of groups and members and return a list of unique member.
*
* @param SS_List $groups
* @param SS_List $members
*
* @return ArrayList
*/
public static function merge_owners(SS_List $groups, SS_List $members)
{
$contentReviewOwners = new ArrayList();
if ($groups->count()) {
$groupIDs = [];
foreach ($groups as $group) {
$familyIDs = $group->collateFamilyIDs();
if (is_array($familyIDs)) {
$groupIDs = array_merge($groupIDs, array_values($familyIDs ?? []));
}
}
array_unique($groupIDs ?? []);
if (count($groupIDs ?? [])) {
$groupMembers = DataObject::get(Member::class)
->where("\"Group\".\"ID\" IN (" . implode(",", $groupIDs) . ")")
->leftJoin("Group_Members", "\"Member\".\"ID\" = \"Group_Members\".\"MemberID\"")
/** @skipUpgrade */
->leftJoin('Group', "\"Group_Members\".\"GroupID\" = \"Group\".\"ID\"");
$contentReviewOwners->merge($groupMembers);
}
}
$contentReviewOwners->merge($members);
$contentReviewOwners->removeDuplicates();
return $contentReviewOwners;
}
/**
* @param FieldList $actions
*/
public function updateCMSActions(FieldList $actions)
{
if (!$this->canBeReviewedBy(Security::getCurrentUser())) {
return;
}
Requirements::css('silverstripe/contentreview:client/dist/styles/contentreview.css');
Requirements::javascript('silverstripe/contentreview:client/dist/js/contentreview.js');
$reviewTab = LiteralField::create('ContentReviewButton', $this->owner->renderWith(__CLASS__ . '_button'));
$actions->insertAfter('MajorActions', $reviewTab);
}
/**
* Returns false if the content review have disabled.
*
* @param SiteTree $page
*
* @return bool|DBDate
*/
public function getReviewDate(SiteTree $page = null)
{
if ($page === null) {
$page = $this->owner;
}
if ($page->obj('NextReviewDate')->exists()) {
return $page->obj('NextReviewDate');
}
$options = $this->owner->getOptions();
if (!$options) {
return false;
}
if (!$options->ReviewPeriodDays) {
return false;
}
// Failover to check on ReviewPeriodDays + LastEdited
$nextReviewUnixSec = strtotime(' + ' . $options->ReviewPeriodDays . ' days', DBDatetime::now()->getTimestamp());
$date = DBDate::create('NextReviewDate');
$date->setValue($nextReviewUnixSec);
return $date;
}
/**
* Get the object that have the information about the content review settings. Either:
*
* - a SiteTreeContentReview decorated object
* - the default SiteTree config
* - false if this page have it's content review disabled
*
* Will go through parents and root pages will use the site config if their setting is Inherit.
*
* @return bool|DataObject
*
* @throws Exception
*/
public function getOptions()
{
if ($this->owner->ContentReviewType == "Custom") {
return $this->owner;
}
if ($this->owner->ContentReviewType == "Disabled") {
return false;
}
$page = $this->owner;
// $page is inheriting it's settings from it's parent, find
// the first valid parent with a valid setting
while ($parent = $page->Parent()) {
// Root page, use site config
if (!$parent->exists()) {
return SiteConfig::current_site_config();
}
if ($parent->ContentReviewType == "Custom") {
return $parent;
}
if ($parent->ContentReviewType == "Disabled") {
return false;
}
$page = $parent;
}
throw new Exception("This shouldn't really happen, as per usual developer logic.");
}
/**
* @return string
*/
public function getOwnerNames()
{
$options = $this->getOptions();
$names = [];
if (!$options) {
return "";
}
foreach ($options->OwnerGroups() as $group) {
$names[] = $group->getBreadcrumbs(" > ");
}
foreach ($options->OwnerUsers() as $group) {
$names[] = $group->getName();
}
return implode(", ", $names);
}
/**
* @return null|string
*/
public function getEditorName()
{
$member = Security::getCurrentUser();
if ($member) {
return $member->getTitle();
}
return null;
}
/**
* Get all Members that are Content Owners to this page. This includes checking group
* hierarchy and adding any direct users.
*
* @return ArrayList
*/
public function ContentReviewOwners()
{
return SiteTreeContentReview::merge_owners(
$this->OwnerGroups(),
$this->OwnerUsers()
);
}
/**
* @return ManyManyList
*/
public function OwnerGroups()
{
return $this->owner->getManyManyComponents("ContentReviewGroups");
}
/**
* @return ManyManyList
*/
public function OwnerUsers()
{
return $this->owner->getManyManyComponents("ContentReviewUsers");
}
/**
* @param FieldList $fields
*/
public function updateSettingsFields(FieldList $fields)
{
if ($this->owner->hasMethod('displayContentReview') && !$this->owner->displayContentReview()) {
return;
}
Requirements::javascript('silverstripe/contentreview:client/dist/js/contentreview.js');
// Display read-only version only
if (!Permission::check("EDIT_CONTENT_REVIEW_FIELDS")) {
$schedule = self::get_schedule();
$contentOwners = ReadonlyField::create(
"ROContentOwners",
_t(__CLASS__ . ".CONTENTOWNERS", "Content Owners"),
$this->getOwnerNames()
);
$nextReviewAt = DateField::create(
'RONextReviewDate',
_t(__CLASS__ . ".NEXTREVIEWDATE", "Next review date"),
$this->owner->NextReviewDate
);
if (!isset($schedule[$this->owner->ReviewPeriodDays])) {
$reviewFreq = ReadonlyField::create(
"ROReviewPeriodDays",
_t(__CLASS__ . ".REVIEWFREQUENCY", "Review frequency"),
$schedule[0]
);
} else {
$reviewFreq = ReadonlyField::create(
"ROReviewPeriodDays",
_t(__CLASS__ . ".REVIEWFREQUENCY", "Review frequency"),
$schedule[$this->owner->ReviewPeriodDays]
);
}
$logConfig = GridFieldConfig::create()
->addComponent(Injector::inst()->create(GridFieldSortableHeader::class))
->addComponent($logColumns = Injector::inst()->create(GridFieldDataColumns::class));
// Cast the value to the users preferred date format
$logColumns->setFieldCasting([
'Created' => DateTimeField::class . '->value',
]);
$logs = GridField::create("ROReviewNotes", "Review Notes", $this->owner->ReviewLogs(), $logConfig);
$optionsFrom = ReadonlyField::create(
"ROType",
_t(__CLASS__ . ".SETTINGSFROM", "Options are"),
$this->owner->ContentReviewType
);
$fields->addFieldsToTab("Root.ContentReview", [
$contentOwners,
$nextReviewAt->performReadonlyTransformation(),
$reviewFreq,
$optionsFrom,
$logs,
]);
return;
}
$options = [];
$options["Disabled"] = _t(__CLASS__ . ".DISABLE", "Disable content review");
$options["Inherit"] = _t(__CLASS__ . ".INHERIT", "Inherit from parent page");
$options["Custom"] = _t(__CLASS__ . ".CUSTOM", "Custom settings");
$viewersOptionsField = OptionsetField::create(
"ContentReviewType",
_t(__CLASS__ . ".OPTIONS", "Options"),
$options
);
$users = Permission::get_members_by_permission(['CMS_ACCESS_CMSMain', 'CMS_ACCESS_LeftAndMain', 'ADMIN']);
$usersMap = $users->map("ID", "Title")->toArray();
asort($usersMap);
$userField = ListboxField::create("OwnerUsers", _t(__CLASS__ . ".PAGEOWNERUSERS", "Users"), $usersMap)
->addExtraClass('custom-setting')
->setAttribute("data-placeholder", _t(__CLASS__ . ".ADDUSERS", "Add users"))
->setDescription(_t(__CLASS__ . '.OWNERUSERSDESCRIPTION', 'Page owners that are responsible for reviews'));
$groupsMap = [];
foreach (Group::get() as $group) {
$groupsMap[$group->ID] = $group->getBreadcrumbs(" > ");
}
asort($groupsMap);
$groupField = ListboxField::create("OwnerGroups", _t(__CLASS__ . ".PAGEOWNERGROUPS", "Groups"), $groupsMap)
->addExtraClass('custom-setting')
->setAttribute("data-placeholder", _t(__CLASS__ . ".ADDGROUP", "Add groups"))
->setDescription(_t(__CLASS__ . ".OWNERGROUPSDESCRIPTION", "Page owners that are responsible for reviews"));
$reviewDate = DateField::create("NextReviewDate", _t(__CLASS__ . ".NEXTREVIEWDATE", "Next review date"))
->setDescription(_t(__CLASS__ . ".NEXTREVIEWDATADESCRIPTION", "Leave blank for no review"));
$reviewFrequency = DropdownField::create(
"ReviewPeriodDays",
_t(__CLASS__ . ".REVIEWFREQUENCY", "Review frequency"),
self::get_schedule()
)
->addExtraClass('custom-setting')
->setDescription(_t(
__CLASS__ . ".REVIEWFREQUENCYDESCRIPTION",
"The review date will be set to this far in the future whenever the page is published"
));
$notesField = GridField::create(
"ReviewNotes",
"Review Notes",
$this->owner->ReviewLogs(),
GridFieldConfig_RecordEditor::create()
);
$fields->addFieldsToTab("Root.ContentReview", [
HeaderField::create('ContentReviewHeader', _t(__CLASS__ . ".REVIEWHEADER", "Content review"), 2),
$viewersOptionsField,
CompositeField::create(
$userField,
$groupField,
$reviewDate,
$reviewFrequency
)->addExtraClass("review-settings"),
ReadonlyField::create(
"ROContentOwners",
_t(__CLASS__ . ".CONTENTOWNERS", "Content Owners"),
$this->getOwnerNames()
),
$notesField,
]);
}
/**
* Creates a ContentReviewLog and connects it to this Page.
*
* @param Member $reviewer
* @param string $message
*/
public function addReviewNote(Member $reviewer, $message)
{
$reviewLog = ContentReviewLog::create();
$reviewLog->Note = $message;
$reviewLog->ReviewerID = $reviewer->ID;
$this->owner->ReviewLogs()->add($reviewLog);
}
/**
* Advance review date to the next date based on review period or set it to null
* if there is no schedule. Returns true if date was required and false is content
* review is 'off'.
*
* @return bool
*/
public function advanceReviewDate()
{
$nextDateTimestamp = false;
$options = $this->getOptions();
if ($options && $options->ReviewPeriodDays) {
$nextDateTimestamp = strtotime(
' + ' . $options->ReviewPeriodDays . ' days',
DBDatetime::now()->getTimestamp()
);
$this->owner->NextReviewDate = DBDate::create()->setValue($nextDateTimestamp)->Format(DBDate::ISO_DATE);
$this->owner->write();
}
if ($options && $options->ReviewPeriodDays == 0) {
$this->owner->NextReviewDate = null;
$this->owner->write();
}
return (bool)$nextDateTimestamp;
}
/**
* Check if a review is due by a member for this owner.
*
* @param Member $member
*
* @return bool
*/
public function canBeReviewedBy(Member $member = null)
{
if (!$this->owner->obj('NextReviewDate')->exists()) {
return false;
}
if ($this->owner->obj('NextReviewDate')->InFuture()) {
return false;
}
$options = $this->getOptions();
if (!$options) {
return false;
}
if (!$options
// Options can be a SiteConfig with different extension applied
|| (!$options->hasExtension(__CLASS__)
&& !$options->hasExtension(ContentReviewDefaultSettings::class))
) {
return false;
}
if ($options->OwnerGroups()->count() == 0 && $options->OwnerUsers()->count() == 0) {
return false;
}
if (!$member) {
return true;
}
// Check whether this user is allowed to review the content of the page.
if ($this->owner->hasMethod("canReviewContent") && !$this->owner->canReviewContent($member)) {
return false;
}
if ($member->inGroups($options->OwnerGroups())) {
return true;
}
if ($options->OwnerUsers()->find("ID", $member->ID)) {
return true;
}
return false;
}
/**
* Set the review data from the review period, if set.
*/
public function onBeforeWrite()
{
// Only update if DB fields have been changed
$changedFields = $this->owner->getChangedFields(true, 2);
if ($changedFields) {
$this->owner->LastEditedByName = $this->owner->getEditorName();
$this->owner->OwnerNames = $this->owner->getOwnerNames();
}
// If the user changed the type, we need to recalculate the review date.
if ($this->owner->isChanged("ContentReviewType", 2)) {
if ($this->owner->ContentReviewType == "Disabled") {
$this->setDefaultReviewDateForDisabled();
} elseif ($this->owner->ContentReviewType == "Custom") {
$this->setDefaultReviewDateForCustom();
} else {
$this->setDefaultReviewDateForInherited();
}
}
// Ensure that a inherited page always have a next review date
if ($this->owner->ContentReviewType == "Inherit" && !$this->owner->NextReviewDate) {
$this->setDefaultReviewDateForInherited();
}
// We need to update all the child pages that inherit this setting. We can only
// change children after this record has been created, otherwise the stageChildren
// method will grab all pages in the DB (this messes up unit testing)
if (!$this->owner->exists()) {
return;
}
// parent page change its review period
// && !$this->owner->isChanged('ContentReviewType', 2)
if ($this->owner->isChanged('ReviewPeriodDays', 2)) {
$nextReviewUnixSec = strtotime(
' + ' . $this->owner->ReviewPeriodDays . ' days',
DBDatetime::now()->getTimestamp()
);
$this->owner->NextReviewDate = DBDate::create()->setValue($nextReviewUnixSec)->Format('y-MM-dd');
}
}
private function setDefaultReviewDateForDisabled()
{
$this->owner->NextReviewDate = null;
}
protected function setDefaultReviewDateForCustom()
{
// Don't overwrite existing value
if ($this->owner->NextReviewDate) {
return;
}
$this->owner->NextReviewDate = null;
$nextDate = $this->getReviewDate();
if (is_object($nextDate)) {
$this->owner->NextReviewDate = $nextDate->getValue();
} else {
$this->owner->NextReviewDate = $nextDate;
}
}
protected function setDefaultReviewDateForInherited()
{
// Don't overwrite existing value
if ($this->owner->NextReviewDate) {
return;
}
$options = $this->getOptions();
$nextDate = null;
if ($options instanceof SiteTree) {
$nextDate = $this->getReviewDate($options);
} elseif ($options instanceof SiteConfig) {
$nextDate = $this->getReviewDate();
}
if (is_object($nextDate)) {
$this->owner->NextReviewDate = $nextDate->getValue();
} else {
$this->owner->NextReviewDate = $nextDate;
}
}
/**
* Provide permissions to the CMS.
*
* @return array
*/
public function providePermissions()
{
return [
"EDIT_CONTENT_REVIEW_FIELDS" => [
"name" => "Set content owners and review dates",
"category" => _t("SilverStripe\\Security\\Permission.CONTENT_CATEGORY", "Content permissions"),
"sort" => 50,
],
];
}
/**
* If the queued jobs module is installed, queue up the first job for 9am tomorrow morning
* (by default).
*/
public function requireDefaultRecords()
{
if (class_exists(ContentReviewNotificationJob::class)) {
// Ensure there is not already a job queued
if (QueuedJobDescriptor::get()->filter("Implementation", ContentReviewNotificationJob::class)->first()) {
return;
}
$nextRun = Injector::inst()->create(ContentReviewNotificationJob::class);
$runHour = Config::inst()->get(ContentReviewNotificationJob::class, "first_run_hour");
$firstRunTime = date(
"Y-m-d H:i:s",
mktime($runHour ?? 0, 0, 0, date("m"), date("d") + 1, date("y"))
);
singleton(QueuedJobService::class)->queueJob(
$nextRun,
$firstRunTime
);
DB::alteration_message(sprintf("Added ContentReviewNotificationJob to run at %s", $firstRunTime));
}
}
}

View File

@ -0,0 +1,132 @@
<?php
namespace SilverStripe\ContentReview\Forms;
use SilverStripe\ContentReview\Extensions\SiteTreeContentReview;
use SilverStripe\ContentReview\Traits\PermissionChecker;
use SilverStripe\Control\Controller;
use SilverStripe\Control\Director;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Core\Injector\Injectable;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\Form;
use SilverStripe\Forms\FormAction;
use SilverStripe\Forms\HiddenField;
use SilverStripe\Forms\TextareaField;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\ValidationException;
use SilverStripe\Security\Security;
class ReviewContentHandler
{
use Injectable;
use PermissionChecker;
/**
* Parent controller for this form
*
* @var Controller
*/
protected $controller;
/**
* Form name to use
*
* @var string
*/
protected $name;
/**
* @param Controller $controller
* @param string $name
*/
public function __construct($controller = null, $name = 'ReviewContentForm')
{
$this->controller = $controller;
$this->name = $name;
}
/**
* Bootstrap the form fields for the content review modal
*
* @param DataObject $object
* @return Form
*/
public function Form($object)
{
$placeholder = _t(__CLASS__ . '.Placeholder', 'Add comments (optional)');
$title = _t(__CLASS__ . '.MarkAsReviewedAction', 'Mark as reviewed');
$fields = FieldList::create([
HiddenField::create('ID', null, $object->ID),
HiddenField::create('ClassName', null, $object->baseClass()),
TextareaField::create('Review', '')
->setAttribute('placeholder', $placeholder)
->setSchemaData(['attributes' => ['placeholder' => $placeholder]])
]);
$action = FormAction::create('savereview', $title)
->setTitle($title)
->setUseButtonTag(false)
->addExtraClass('review-content__action btn btn-primary');
$actions = FieldList::create([$action]);
$form = Form::create($this->controller, $this->name, $fields, $actions)
->setHTMLID('Form_EditForm_ReviewContent')
->addExtraClass('form--no-dividers review-content__form');
return $form;
}
/**
* Validate, and save the submitted form's review
*
* @param DataObject $record
* @param array $data
* @return HTTPResponse|string
* @throws ValidationException If the user cannot submit the review
*/
public function submitReview($record, $data)
{
/** @var DataObject|SiteTreeContentReview $record */
if (!$this->canSubmitReview($record)) {
throw new ValidationException(_t(
__CLASS__ . '.ErrorReviewPermissionDenied',
'It seems you don\'t have the necessary permissions to submit a content review'
));
}
$notes = (!empty($data['Review']) ? $data['Review'] : _t(__CLASS__ . '.NoComments', '(no comments)'));
$record->addReviewNote(Security::getCurrentUser(), $notes);
$record->advanceReviewDate();
$request = $this->controller->getRequest();
$message = _t(__CLASS__ . '.Success', 'Review successfully added');
if ($request->getHeader('X-Formschema-Request')) {
return $message;
} elseif (Director::is_ajax()) {
$response = HTTPResponse::create($message, 200);
$response->addHeader('Content-Type', 'text/html; charset=utf-8');
return $response;
}
return $this->controller->redirectBack();
}
/**
* Determine whether the user can submit a review
*
* @param DataObject $record
* @return bool
*/
public function canSubmitReview($record)
{
// Ensure the parameter of correct data type
if (!$record instanceof DataObject) {
return false;
}
return $this->isContentReviewable($record, Security::getCurrentUser());
}
}

View File

@ -0,0 +1,124 @@
<?php
namespace SilverStripe\ContentReview\Jobs;
use SilverStripe\ContentReview\Tasks\ContentReviewEmails;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Core\Config\Config;
use Symbiote\QueuedJobs\Services\AbstractQueuedJob;
use Symbiote\QueuedJobs\Services\QueuedJob;
use Symbiote\QueuedJobs\Services\QueuedJobService;
if (!class_exists(AbstractQueuedJob::class)) {
return;
}
/**
* Allows the content review module to use the optional queued jobs module to automatically
* process content review emails. If the module isn't installed, nothing is done - SilverStripe
* will never include this class declaration.
*
* If the module is installed, it will create a new job to be processed once every day by default.
*
* @see https://github.com/silverstripe-australia/silverstripe-queuedjobs
*/
class ContentReviewNotificationJob extends AbstractQueuedJob implements QueuedJob
{
/**
* The hour that the first job will be created at (for the next day). All other jobs should
* be triggered around this time too, as the next generation is queued when this job is run.
*
* @var int
*
* @config
*/
private static $first_run_hour = 9;
/**
* The hour at which to run these jobs.
*
* @var int
*
* @config
*/
private static $next_run_hour = 9;
/**
* The minutes past the hour (see above) at which to run these jobs.
*
* @var int
*
* @config
*/
private static $next_run_minute = 0;
/**
* The number of days to skip between job runs (1 means run this job every day,
* 2 means run it every second day etc).
*
* @var int
*
* @config
*/
private static $next_run_in_days = 1;
/**
* @return string
*/
public function getTitle()
{
return "Content Review Notification Job";
}
/**
* @return string
*/
public function getJobType()
{
$this->totalSteps = 1;
return QueuedJob::QUEUED;
}
public function setUp()
{
parent::setup();
// Recommended for long running jobs that don't increment 'currentStep'
// https://github.com/silverstripe-australia/silverstripe-queuedjobs
$this->currentStep = -1;
}
public function process()
{
$this->queueNextRun();
$task = ContentReviewEmails::create();
$task->run(new HTTPRequest("GET", "/dev/tasks/ContentReviewEmails"));
$this->currentStep = 1;
$this->isComplete = true;
}
/**
* Queue up the next job to run.
*/
protected function queueNextRun()
{
$nextRun = new ContentReviewNotificationJob();
$nextRunTime = mktime(
Config::inst()->get(__CLASS__, 'next_run_hour') ?? 0,
Config::inst()->get(__CLASS__, 'next_run_minute'),
0,
date("m"),
date("d") + Config::inst()->get(__CLASS__, 'next_run_in_days'),
date("Y")
);
singleton(QueuedJobService::class)->queueJob(
$nextRun,
date("Y-m-d H:i:s", $nextRunTime)
);
}
}

View File

@ -0,0 +1,52 @@
<?php
namespace SilverStripe\ContentReview\Models;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\ORM\DataObject;
use SilverStripe\Security\Member;
use SilverStripe\Security\Security;
class ContentReviewLog extends DataObject
{
/**
* @var array
*/
private static $db = [
"Note" => "Text",
];
/**
* @var array
*/
private static $has_one = [
"Reviewer" => Member::class,
"SiteTree" => SiteTree::class,
];
/**
* @var array
*/
private static $summary_fields = [
"Note" => ["title" => "Note"],
"Created" => ["title" => "Reviewed at"],
"Reviewer.Title" => ["title" => "Reviewed by"]
];
/**
* @var string
*/
private static $default_sort = "Created DESC";
private static $table_name = 'ContentReviewLog';
/**
* @param mixed $member
*
* @return bool
*/
public function canView($member = null)
{
return (bool) Security::getCurrentUser();
}
}

View File

@ -0,0 +1,246 @@
<?php
namespace SilverStripe\ContentReview\Reports;
use SilverStripe\CMS\Controllers\CMSPageEditController;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\CMS\Model\VirtualPage;
use SilverStripe\ContentReview\Compatibility\ContentReviewCompatability;
use SilverStripe\ContentReview\Extensions\ContentReviewOwner;
use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Convert;
use SilverStripe\Forms\CheckboxField;
use SilverStripe\Forms\DateField;
use SilverStripe\Forms\FieldList;
use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\ORM\SS_List;
use SilverStripe\Reports\Report;
use SilverStripe\Security\Security;
use SilverStripe\SiteConfig\SiteConfig;
use SilverStripe\Versioned\Versioned;
/**
* Show all pages that need to be reviewed.
*/
class PagesDueForReviewReport extends Report
{
/**
* @return string
*/
public function title()
{
return _t(__CLASS__ . ".TITLE", "Pages due for review");
}
/**
* @return FieldList
*/
public function parameterFields()
{
$filtersList = FieldList::create();
$filtersList->push(
DateField::create(
"ReviewDateAfter",
_t(__CLASS__ . ".REVIEWDATEAFTER", "Review date after or on")
)
);
$filtersList->push(
DateField::create(
"ReviewDateBefore",
_t(__CLASS__ . ".REVIEWDATEBEFORE", "Review date before or on"),
date("d/m/Y", strtotime("midnight"))
)
);
$filtersList->push(
CheckboxField::create(
"ShowVirtualPages",
_t(__CLASS__ . ".SHOWVIRTUALPAGES", "Show Virtual Pages")
)
);
$filtersList->push(
CheckboxField::create(
"OnlyMyPages",
_t(__CLASS__ . ".ONLYMYPAGES", "Only Show pages assigned to me")
)
);
return $filtersList;
}
/**
* @return array
*/
public function columns()
{
$linkBase = singleton(CMSPageEditController::class)->Link("show");
$linkPath = parse_url($linkBase ?? '', PHP_URL_PATH);
$linkQuery = parse_url($linkBase ?? '', PHP_URL_QUERY);
$fields = [
"Title" => [
"title" => "Page name",
"formatting" => "<a href='{$linkPath}/\$ID?{$linkQuery}' title='Edit page'>\$value</a>"
],
"NextReviewDate" => [
"title" => "Review Date",
"casting" => "Date->Full",
"formatting" => function ($value, $item) {
if ($item->ContentReviewType == "Disabled") {
return "disabled";
}
if ($item->ContentReviewType == "Inherit") {
$setting = $item->getOptions();
if (!$setting) {
return "disabled";
}
return $item->obj("NextReviewDate")->Full();
}
return $value;
}
],
"OwnerNames" => [
"title" => "Owner"
],
"LastEditedByName" => "Last edited by",
"AbsoluteLink" => [
"title" => "URL",
"formatting" => function ($value, $item) {
$liveLink = $item->AbsoluteLiveLink;
$stageLink = $item->AbsoluteLink();
return sprintf(
"%s <a href='%s'>%s</a>",
$stageLink,
$liveLink ? $liveLink : $stageLink . "?stage=Stage",
$liveLink ? "(live)" : "(draft)"
);
}
],
"ContentReviewType" => [
"title" => "Settings are",
"formatting" => function ($value, $item) use ($linkPath, $linkQuery) {
if ($item->ContentReviewType == "Inherit") {
$options = $item->getOptions();
if ($options && $options instanceof SiteConfig) {
return "Inherited from <a href='admin/settings'>Settings</a>";
} elseif ($options) {
return sprintf(
"Inherited from <a href='%s/%d?%s'>%s</a>",
$linkPath,
$options->ID,
$linkQuery,
$options->Title
);
}
}
return $value;
}
],
];
return $fields;
}
/**
* @param array $params
* @param array|string|null $sort
* @param int|null $limit
*
* @return SS_List
*/
public function sourceRecords($params = [], $sort = null, $limit = null)
{
Versioned::set_stage(Versioned::DRAFT);
$records = SiteTree::get();
$compatibility = ContentReviewCompatability::start();
// Apply sort and limit if appropriate.
if ($sort !== null) {
$records = $records->sort($sort);
}
if ($limit !== null) {
$records = $records->limit($limit);
}
if (empty($params['ReviewDateBefore']) && empty($params['ReviewDateAfter'])) {
// If there's no review dates set, default to all pages due for review now
$records = $records->where(
sprintf(
'"NextReviewDate" < \'%s\'',
DBDatetime::now()->Format('y-MM-dd')
)
);
} else {
// Review date before
if (!empty($params['ReviewDateBefore'])) {
// TODO Get value from DateField->dataValue() once we have access to form elements here
$nextReviewUnixSec = strtotime(
' + 1 day',
strtotime($params['ReviewDateBefore'] ?? '')
);
$records = $records->where(
sprintf(
"\"NextReviewDate\" < '%s'",
DBDatetime::create()->setValue($nextReviewUnixSec)->Format('y-MM-dd')
)
);
}
// Review date after
if (!empty($params['ReviewDateAfter'])) {
// TODO Get value from DateField->dataValue() once we have access to form elements here
$records = $records->where(
sprintf(
"\"NextReviewDate\" >= '%s'",
DBDatetime::create()->setValue(strtotime($params['ReviewDateAfter']))->Format('y-MM-dd')
)
);
}
}
// Show virtual pages?
if (empty($params["ShowVirtualPages"])) {
$virtualPageClasses = ClassInfo::subclassesFor(VirtualPage::class);
$records = $records->where(sprintf(
"\"SiteTree\".\"ClassName\" NOT IN ('%s')",
implode("','", array_values($virtualPageClasses ?? []))
));
}
// Owner dropdown
if (!empty($params[ContentReviewOwner::class])) {
$ownerNames = Convert::raw2sql($params[ContentReviewOwner::class]);
$records = $records->filter("OwnerNames:PartialMatch", $ownerNames);
}
// Only show pages assigned to the current user?
// This come last because it transforms $records to an ArrayList.
if (!empty($params["OnlyMyPages"])) {
$currentUser = Security::getCurrentUser();
$records = $records->filterByCallback(function ($page) use ($currentUser) {
$options = $page->getOptions();
if ($options) {
foreach ($options->ContentReviewOwners() as $owner) {
if ($currentUser->ID == $owner->ID) {
return true;
}
}
}
return false;
});
}
ContentReviewCompatability::done($compatibility);
return $records;
}
}

View File

@ -0,0 +1,167 @@
<?php
namespace SilverStripe\ContentReview\Reports;
use SilverStripe\CMS\Controllers\CMSPageEditController;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\CMS\Model\VirtualPage;
use SilverStripe\ContentReview\Compatibility\ContentReviewCompatability;
use SilverStripe\Core\ClassInfo;
use SilverStripe\Forms\CheckboxField;
use SilverStripe\Forms\FieldList;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\SS_List;
use SilverStripe\Reports\Report;
use SilverStripe\SiteConfig\SiteConfig;
use SilverStripe\Versioned\Versioned;
/**
* Show all pages that need to be reviewed.
*/
class PagesWithoutReviewScheduleReport extends Report
{
/**
* @return string
*/
public function title()
{
return _t(__CLASS__ . ".TITLE", "Pages without a scheduled review.");
}
/**
* @return FieldList
*/
public function parameterFields()
{
$params = FieldList::create();
$params->push(CheckboxField::create("ShowVirtualPages", "Show Virtual Pages"));
return $params;
}
/**
* @return array
*/
public function columns()
{
$linkBase = singleton(CMSPageEditController::class)->Link("show");
$linkPath = parse_url($linkBase ?? '', PHP_URL_PATH);
$linkQuery = parse_url($linkBase ?? '', PHP_URL_QUERY);
$fields = [
"Title" => [
"title" => "Page name",
"formatting" => "<a href='{$linkPath}/\$ID?{$linkQuery}' title='Edit page'>\$value</a>",
],
"NextReviewDate" => [
"title" => "Review Date",
"casting" => "Date->Full",
],
"OwnerNames" => [
"title" => "Owner",
],
"LastEditedByName" => "Last edited by",
"AbsoluteLink" => [
"title" => "URL",
"formatting" => function ($value, $item) {
$liveLink = $item->AbsoluteLiveLink;
$stageLink = $item->AbsoluteLink();
return sprintf(
"%s <a href='%s'>%s</a>",
$stageLink,
$liveLink ? $liveLink : $stageLink . "?stage=Stage",
$liveLink ? "(live)" : "(draft)"
);
},
],
"ContentReviewType" => [
"title" => "Settings are",
"formatting" => function ($value, $item) use ($linkPath, $linkQuery) {
if ($item->ContentReviewType == "Inherit") {
$options = $item->getOptions();
if ($options && $options instanceof SiteConfig) {
return "Inherited from <a href='admin/settings'>Settings</a>";
} elseif ($options) {
return sprintf(
"Inherited from <a href='%s/%d?%s'>%s</a>",
$linkPath,
$options->ID,
$linkQuery,
$options->Title
);
}
}
return $value;
},
],
];
return $fields;
}
/**
* @param array $params
* @param array|string|null $sort
* @param int|null $limit
*
* @return SS_List
*/
public function sourceRecords($params = [], $sort = null, $limit = null)
{
Versioned::set_stage(Versioned::DRAFT);
$records = SiteTree::get();
$compatibility = ContentReviewCompatability::start();
// If there's no review dates set, default to all pages due for review now.
// Show virtual pages?
if (empty($params["ShowVirtualPages"])) {
$virtualPageClasses = ClassInfo::subclassesFor(VirtualPage::class);
$records = $records->where(sprintf(
"\"SiteTree\".\"ClassName\" NOT IN ('%s')",
implode("','", array_values($virtualPageClasses ?? []))
));
}
// Apply sort and limit if appropriate.
if ($sort !== null) {
$records = $records->sort($sort);
}
if ($limit !== null) {
$records = $records->limit($limit);
}
// Trim out calculated values
$list = $records->filterByCallback(function ($record) {
return !$this->hasReviewSchedule($record);
});
ContentReviewCompatability::done($compatibility);
return $list;
}
/**
* @param DataObject $record
*
* @return bool
*/
protected function hasReviewSchedule(DataObject $record)
{
if (!$record->obj("NextReviewDate")->exists()) {
return false;
}
$options = $record->getOptions();
if ($options && $options->OwnerGroups()->count() == 0 && $options->OwnerUsers()->count() == 0) {
return false;
}
return true;
}
}

View File

@ -0,0 +1,199 @@
<?php
namespace SilverStripe\ContentReview\Tasks;
use Page;
use RuntimeException;
use SilverStripe\ContentReview\Compatibility\ContentReviewCompatability;
use SilverStripe\Control\Email\Email;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Dev\BuildTask;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\SS_List;
use SilverStripe\Security\Member;
use SilverStripe\SiteConfig\SiteConfig;
use SilverStripe\View\ArrayData;
use SilverStripe\View\SSViewer;
/**
* Daily task to send emails to the owners of content items when the review date rolls around.
*/
class ContentReviewEmails extends BuildTask
{
private array $invalid_emails = [];
/**
* @param HTTPRequest $request
* @throws RuntimeException
*/
public function run($request)
{
if (!$this->isValidEmail($senderEmail = SiteConfig::current_site_config()->ReviewFrom)) {
throw new RuntimeException(
sprintf(
'Provided sender email address is invalid: "%s".',
$senderEmail
)
);
}
$compatibility = ContentReviewCompatability::start();
// First grab all the pages with a custom setting
$pages = Page::get()
->filter('NextReviewDate:LessThanOrEqual', DBDatetime::now()->URLDate());
$overduePages = $this->getOverduePagesForOwners($pages);
// Lets send one email to one owner with all the pages in there instead of no of pages
// of emails.
foreach ($overduePages as $memberID => $pages) {
$this->notifyOwner($memberID, $pages);
}
ContentReviewCompatability::done($compatibility);
if (is_array($this->invalid_emails) && count($this->invalid_emails) > 0) {
$plural = count($this->invalid_emails) > 1 ? 's are' : ' is';
throw new RuntimeException(
sprintf(
'Provided email' . $plural . ' invalid: "%s".',
implode(', ', $this->invalid_emails)
)
);
}
}
/**
* @param SS_List $pages
*
* @return array
*/
protected function getOverduePagesForOwners(SS_List $pages)
{
$overduePages = [];
foreach ($pages as $page) {
if (!$page->canBeReviewedBy()) {
continue;
}
// get most recent review log of current [age]
$contentReviewLog = $page->ReviewLogs()->sort('Created DESC')->first();
// check log date vs NextReviewDate. If someone has left a content review
// after the review date, then we don't need to notify anybody
if ($contentReviewLog && $contentReviewLog->Created >= $page->NextReviewDate) {
$page->advanceReviewDate();
continue;
}
$options = $page->getOptions();
if ($options) {
foreach ($options->ContentReviewOwners() as $owner) {
if (!isset($overduePages[$owner->ID])) {
$overduePages[$owner->ID] = ArrayList::create();
}
$overduePages[$owner->ID]->push($page);
}
}
}
return $overduePages;
}
/**
* @param int $ownerID
* @param array|SS_List $pages
*/
protected function notifyOwner($ownerID, SS_List $pages)
{
// Prepare variables
$siteConfig = SiteConfig::current_site_config();
$owner = Member::get()->byID($ownerID);
if (!$this->isValidEmail($owner->Email)) {
$this->invalid_emails[] = $owner->Name . ': ' . $owner->Email;
return;
}
$templateVariables = $this->getTemplateVariables($owner, $siteConfig, $pages);
// Build email
$email = Email::create();
$email->setTo($owner->Email);
$email->setFrom($siteConfig->ReviewFrom);
$email->setSubject($siteConfig->ReviewSubject);
// Get user-editable body
$body = $this->getEmailBody($siteConfig, $templateVariables);
// Populate mail body with fixed template
$email->setHTMLTemplate($siteConfig->config()->get('content_review_template'));
$email->setData(
array_merge(
$templateVariables,
[
'EmailBody' => $body,
'Recipient' => $owner,
'Pages' => $pages,
]
)
);
$email->send();
}
/**
* Get string value of HTML body with all variable evaluated.
*
* @param SiteConfig $config
* @param array List of safe template variables to expose to this template
*
* @return HTMLText
*/
protected function getEmailBody($config, $variables)
{
$template = SSViewer::fromString($config->ReviewBody);
$value = $template->process(ArrayData::create($variables));
// Cast to HTML
return DBField::create_field('HTMLText', (string) $value);
}
/**
* Gets list of safe template variables and their values which can be used
* in both the static and editable templates.
*
* {@see ContentReviewAdminHelp.ss}
*
* @param Member $recipient
* @param SiteConfig $config
* @param SS_List $pages
*
* @return array
*/
protected function getTemplateVariables($recipient, $config, $pages)
{
return [
'Subject' => $config->ReviewSubject,
'PagesCount' => $pages->count(),
'FromEmail' => $config->ReviewFrom,
'ToFirstName' => $recipient->FirstName,
'ToSurname' => $recipient->Surname,
'ToEmail' => $recipient->Email,
];
}
/**
* Check validity of email
*/
protected function isValidEmail(?string $email): bool
{
return (bool) filter_var($email, FILTER_VALIDATE_EMAIL);
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace SilverStripe\ContentReview\Tasks;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Dev\BuildTask;
use SilverStripe\ORM\DB;
/**
* Task which migrates the ContentReview Module's SiteTree->OwnerID column to a new column name.
*/
class ContentReviewOwnerMigrationTask extends BuildTask
{
/**
* @param HTTPRequest $request
*/
public function run($request)
{
$results = DB::query("SHOW columns from \"SiteTree\" WHERE \"field\" = 'OwnerID'");
if ($results->numRecords() == 0) {
echo "<h1>No need to run task. SiteTree->OwnerID doesn't exist</h1>";
} else {
DB::query("UPDATE \"SiteTree\" SET \"ContentReviewOwnerID\" = \"OwnerID\"");
DB::query("UPDATE \"SiteTree_Live\" SET \"ContentReviewOwnerID\" = \"OwnerID\"");
DB::query("UPDATE \"SiteTree_versions\" SET \"ContentReviewOwnerID\" = \"OwnerID\"");
DB::query("ALTER TABLE \"SiteTree\" DROP COLUMN \"OwnerID\"");
DB::query("ALTER TABLE \"SiteTree_Live\" DROP COLUMN \"OwnerID\"");
DB::query("ALTER TABLE \"SiteTree_Versions\" DROP COLUMN \"OwnerID\"");
echo "<h1>Migrated 3 tables. Dropped obsolete OwnerID column</h1>";
}
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace SilverStripe\ContentReview\Traits;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\ORM\DataObject;
use SilverStripe\Security\Member;
use SilverStripe\Security\Security;
trait PermissionChecker
{
/**
* Checks the user has been granted special permission to review the content of the page
* if not fallback to canEdit() permission.
*/
protected function isContentReviewable(DataObject $record, ?Member $user = null): bool
{
return $record->hasMethod('canReviewContent')
? $record->canReviewContent($user)
: $record->canEdit();
}
}

View File

@ -1,24 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
</head>
<body>
<table id="Content" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td scope="row" colspan="2" class="typography">
<h2><% _t('ContentReviewEmails.EMAIL_HEADING','Page due for review') %></h2>
<p>The page $Page.Title is due for review today by you</p>
<h2>Actions</h2>
<ul>
<li><a href="$PageCMSLink"><% _t('ContentReviewEmails.REVIEWPAGELINK','Review the page in the CMS') %></a></li>
<li><a href="$LiveSiteLink"><% _t('ContentReviewEmails.VIEWPUBLISHEDLINK','View this page on the website') %></a></li>
</ul>
</td>
</tr>
</tbody>
</table>
</body>
</html>

View File

@ -0,0 +1,10 @@
<p>This is a list of dynamic variables that you can use in the email templates.</p>
<ul>
<li>&#36;Subject - Email subject line</li>
<li>&#36;PagesCount - Number of pages pending review</li>
<li>&#36;FromEmail - Sender email address</li>
<li>&#36;ToFirstName - The email receivers first name</li>
<li>&#36;ToSurname - The email receivers surname</li>
<li>&#36;ToEmail - The email receivers email</li>
</ul>

View File

@ -0,0 +1,23 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head></head>
<body>
<table id="Content" cellspacing="1" cellpadding="10">
<tbody>
<tr>
<td scope="row" colspan="2" class="typography">
$EmailBody
</td>
</tr>
<% loop $Pages %>
<tr>
<td valign="top">$Title</td>
<td><a href="{$BaseURL}admin/pages/edit/show/$ID"><%t SilverStripe\\ContentReview\\Tasks\\ContentReviewEmails.REVIEWPAGELINK 'Review the page in the CMS' %></a><br />
<a href="$AbsoluteLink"><%t SilverStripe\\ContentReview\\Tasks\\ContentReviewEmails.VIEWPUBLISHEDLINK 'View this page on the website' %></a>
</td>
</tr>
<% end_loop %>
</tbody>
</table>
</body>
</html>

View File

@ -0,0 +1,3 @@
<div class="content-review__button-holder">
<a href="#" class="content-review__button"><%t SilverStripe\\ContentReview\\Extensions\\SiteTreeContentReview.CONTENTREVIEW 'Content due for review' %></a>
</div>

View File

@ -1,100 +0,0 @@
<?php
class ContentReviewTest extends FunctionalTest {
static $fixture_file = 'contentreview/tests/ContentReviewTest.yml';
function testPermissions() {
$editor = $this->objFromFixture('Member', 'editor');
$author = $this->objFromFixture('Member', 'author');
// Assert the permission code exists
$perms = singleton('SiteTreeContentReview')->providePermissions();
$this->assertTrue(isset($perms['EDIT_CONTENT_REVIEW_FIELDS']));
// Check a user with permission can edit fields
$this->logInAs($editor);
$page = new Page();
$fields = $page->getCMSFields();
$this->assertNotNull($fields->fieldByName('Root.Review'));
// Check a user without permission can see tab
$this->logInAs($author);
$page = new Page();
$fields = $page->getCMSFields();
$this->assertNull($fields->fieldByName('Root.Review'));
}
function testContentReviewEmails() {
SS_Datetime::set_mock_now('2010-02-14 12:00:00');
$task = new ContentReviewEmails();
$task->run(new SS_HTTPRequest('GET', '/dev/tasks/ContentReviewEmails'));
$this->assertEmailSent('author@example.com', null, sprintf(_t('ContentReviewEmails.SUBJECT', 'Page %s due for content review'), 'Staff'));
SS_Datetime::clear_mock_now();
}
function testAutomaticallySettingReviewDate() {
$editor = $this->objFromFixture('Member', 'editor');
$this->logInAs($editor);
$page = new Page();
$page->ReviewPeriodDays = 10;
$page->write();
$this->assertTrue($page->doPublish());
$this->assertEquals(date('Y-m-d', strtotime('now + 10 days')), $page->NextReviewDate);
}
function testReportContent() {
$editor = $this->objFromFixture('Member', 'editor');
$this->logInAs($editor);
$report = new PagesDueForReviewReport();
$report->parameterFields();
$report->columns();
$report->title();
$results = $report->sourceRecords(array(
'ReviewDateAfter' => '01/01/2010',
'ReviewDateBefore' => '12/12/2010'
), 'NextReviewDate ASC', false);
$this->assertEquals($results->column('Title'), array(
'Home',
'About Us',
'Staff',
'Contact Us'
));
SS_Datetime::set_mock_now('2010-02-13 00:00:00');
$results = $report->sourceRecords(array(
), 'NextReviewDate ASC', false);
$this->assertEquals($results->column('Title'), array(
'Home',
'About Us'
));
SS_Datetime::clear_mock_now();
}
function testOwnerName() {
$editor = $this->objFromFixture('Member', 'editor');
$this->logInAs($editor);
$page = new Page();
$page->ReviewPeriodDays = 10;
$page->OwnerID = $editor->ID;
$page->write();
$this->assertTrue($page->doPublish());
$this->assertEquals($page->OwnerName, "Test Editor");
$page = $this->objFromFixture('Page', 'about');
$page->OwnerID = 0;
$page->write();
$this->assertTrue($page->doPublish());
$this->assertNull($page->OwnerName);
}
}

View File

@ -1,48 +0,0 @@
Permission:
cmsmain1:
Code: CMS_ACCESS_CMSMain
cmsmain2:
Code: CMS_ACCESS_CMSMain
setreviewdates:
Code: EDIT_CONTENT_REVIEW_FIELDS
workflowadmin1:
Code: IS_WORKFLOW_ADMIN
workflowadmin2:
Code: IS_WORKFLOW_ADMIN
Group:
editorgroup:
Title: Edit existing pages
Code: editorgroup
Permissions: =>Permission.cmsmain1,=>Permission.workflowadmin1,=>Permission.setreviewdates
authorgroup:
Title: Author existing pages
Code: authorgroup
Permissions: =>Permission.cmsmain2,=>Permission.workflowadmin2
Member:
author:
FirstName: Test
Surname: Author
Email: author@example.com
Groups: =>Group.authorgroup
editor:
FirstName: Test
Surname: Editor
Groups: =>Group.editorgroup
Page:
home:
Title: Home
NextReviewDate: 2010-02-01
about:
Title: About Us
NextReviewDate: 2010-02-07
staff:
Title: Staff
NextReviewDate: 2010-02-14
Owner: =>Member.author
contact:
Title: Contact Us
NextReviewDate: 2010-02-21

View File

View File

@ -0,0 +1,58 @@
Feature: Set up reviews
As a CMS user
I can set up content reviews for my content
In order to ensure my content gets reviewed regularly
Background:
# Note: the review date is deliberately in the past
Given a "page" "My page" with "Content"="<p>Welcome</p>", "NextReviewDate"="01/01/2017", "ReviewPeriodDays"="1"
And the "group" "ADMIN group" has permissions "Full administrative rights"
And the "group" "EDITOR" has permissions "CMS_ACCESS_CMSMain" and "EDIT_CONTENT_REVIEW_FIELDS"
And the "group" "AUTHOR" has permissions and "CMS_ACCESS_LeftAndMain"
And the "group" "FILEONLY" has permissions "FILE_EDIT_ALL"
And the "group" "CMS_MAIN" has permissions "CMS_ACCESS_CMSMain"
And a "member" "Ed" belonging to "AUTHOR" with "Email"="ed@example.com"
And a "member" "Phil" belonging to "FILEONLY" with "Email"="phil@example.com"
And a "member" "Anna" belonging to "CMS_MAIN" with "Email"="anna@example.com"
And I am logged in as a member of "EDITOR" group
And I go to "admin/pages"
And I wait for 1 second
And I click on "My page" in the tree
And I click the "Settings" CMS tab
And I click the "Content review" CMS tab
Scenario: I can set content reviewers to users and groups who can edit pages
When I select "Custom settings" from "Options" input group
And I wait for 1 second
# Test adding individual member based on them having access to the Pages section fo the CMS
Then the "#Form_EditForm_OwnerUsers" select element should have an option with an "Ed" label
And the "#Form_EditForm_OwnerUsers" select element should have an option with an "Anna" label
And the "#Form_EditForm_OwnerUsers" select element should not have an option with a "Phil" label
# Test adding groups
Then the "#Form_EditForm_OwnerGroups" select element should have an option with an "EDITOR" label
# Required to avoid "unsaved changed" browser dialog
Then I press the "Save" button
Scenario: There is an alert icon when a content review is overdue
When I select "Custom settings" from "Options" input group
And I wait for 1 second
Then I should not see the ".content-review__button" element
When I press the "Save" button
And I select "EDITOR" from "Groups"
And I press the "Save" button
Then I should see the ".content-review__button" element
When I click on the ".content-review__button" element
Then I should see the ".modal" element
And I should see "Mark as reviewed"
# Fill in a review
When I fill in "Form_EditForm_ReviewContent_Review" with "My review"
And I press "Mark as reviewed"
And I wait for 1 second
Then I should see "Review successfully added"
When I click on the ".close" element
And I press the "Save" button
Then I should see "My review"

View File

@ -0,0 +1,42 @@
Feature: Set up reviews
As a CMS user
I can set up content reviews for my content
In order to ensure my content gets reviewed regularly
Background:
# Note: the review date is deliberately in the past
Given a "page" "Home" with "Content"="<p>Welcome</p>", "NextReviewDate"="01/01/2017", "ReviewPeriodDays"="1"
And the "group" "EDITOR" has permissions "CMS_ACCESS_CMSMain" and "EDIT_CONTENT_REVIEW_FIELDS"
And I am logged in as a member of "EDITOR" group
And I go to "admin/pages"
@javascript
Scenario: I can set content review options
When I click on "Home" in the tree
And I click the "Settings" CMS tab
Then I should see a "Content review" CMS tab
When I click the "Content review" CMS tab
And I select "Custom settings" from "Options" input group
And I wait for 1 second
And I select "EDITOR" from "Groups"
And I press "Save"
Then I should see a "Content due for review" button
@javascript
Scenario: I can enter a review in the modal
When I click on "Home" in the tree
And I click the "Settings" CMS tab
And I click the "Content review" CMS tab
And I select "Custom settings" from "Options" input group
And I wait for 1 seconds
And I select "EDITOR" from "Groups"
And I press "Save"
And I follow "Content due for review"
And I wait for 3 seconds
Then I should see a "Mark as reviewed" button
When I fill in "Review" with "LGTM"
And I press "Mark as reviewed"
And I wait for 3 seconds
Then I should see "Review successfully added"

View File

View File

@ -0,0 +1,29 @@
<?php
namespace SilverStripe\ContentReview\Tests\Behat\Context;
use SilverStripe\BehatExtension\Context\SilverStripeContext;
class FeatureContext extends SilverStripeContext
{
/**
* @Given /^the "([^"]*)" select element should(| not) have an option with (a|an) "([^"]*)" label$/
* @param string $id
* @param string $should
* @param string $label
*/
public function theSelectElementShouldHaveAnOptionWithALabel($id, $should, $label)
{
$n = $should === '' ? 1 : 0;
$js = <<<JS
;let hasLabel = 0;
document.querySelectorAll('#{$id} > option').forEach(function(option) {
if (option.innerHTML == '$label') {
hasLabel = 1;
}
});
return hasLabel;
JS;
return $this->getSession()->evaluateScript($js) == $n;
}
}

View File

@ -0,0 +1,9 @@
<?php
namespace SilverStripe\ContentReview\Tests\Behat\Context;
use SilverStripe\BehatExtension\Context\FixtureContext as BaseFixtureContext;
class FixtureContext extends BaseFixtureContext
{
}

View File

@ -0,0 +1,52 @@
<?php
namespace SilverStripe\ContentReview\Tests;
use SilverStripe\Dev\FunctionalTest;
use SilverStripe\CMS\Model\SiteTree;
// @todo add translatable namespace
use Translatable;
/**
* Extend this class when writing unit tests which are compatible with other modules.
* All compatibility code goes here.
*/
abstract class ContentReviewBaseTest extends FunctionalTest
{
/**
* @var bool
*/
protected $translatableEnabledBefore;
protected function setUp(): void
{
parent::setUp();
/*
* We set the locale for pages explicitly, because if we don't, then we get into a situation
* where the page takes on the tester's (your) locale, and any calls to simulate subsequent requests
* (e.g. $this->post()) do not seem to get passed the tester's locale,
* but instead fallback to the default locale.
*
* So we set the pages locale to be the default locale, which will then match any subsequent requests.
*
* If creating pages in your unit tests (rather than reading from the fixtures file), you must explicitly call
* self::compat() on the page, for the same reasons as above.
*/
if (class_exists(Translatable::class)) {
$this->translatableEnabledBefore = SiteTree::has_extension(Translatable::class);
SiteTree::remove_extension(Translatable::class);
}
}
protected function tearDown(): void
{
if (class_exists(Translatable::class)) {
if ($this->translatableEnabledBefore) {
SiteTree::add_extension(Translatable::class);
}
}
parent::tearDown();
}
}

View File

@ -0,0 +1,104 @@
<?php
namespace SilverStripe\ContentReview\Tests;
use Page;
use SilverStripe\CMS\Controllers\CMSPageEditController;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\ContentReview\Extensions\SiteTreeContentReview;
use SilverStripe\ContentReview\Extensions\ContentReviewOwner;
use SilverStripe\ContentReview\Extensions\ContentReviewCMSExtension;
use SilverStripe\ContentReview\Extensions\ContentReviewDefaultSettings;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse_Exception;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\Form;
use SilverStripe\Security\Group;
use SilverStripe\Security\Member;
use SilverStripe\SiteConfig\SiteConfig;
class ContentReviewCMSPageEditControllerTest extends ContentReviewBaseTest
{
/**
* @var string
*/
protected static $fixture_file = 'ContentReviewTest.yml';
/**
* @var array
*/
protected static $required_extensions = [
SiteTree::class => [SiteTreeContentReview::class],
Group::class => [ContentReviewOwner::class],
Member::class => [ContentReviewOwner::class],
CMSPageEditController::class => [ContentReviewCMSExtension::class],
SiteConfig::class => [ContentReviewDefaultSettings::class],
];
public function testReviewedThrowsExceptionWithNoRecordID()
{
$this->expectException(HTTPResponse_Exception::class);
/** @var CMSPageEditController|ContentReviewCMSExtension $controller */
$controller = new CMSPageEditController();
$dummyForm = new Form($controller, "EditForm", new FieldList(), new FieldList());
$controller->savereview(array(
"ID" => null,
"Message" => null,
), $dummyForm);
}
public function testReviewedThrowsExceptionWithWrongRecordID()
{
$this->expectException(HTTPResponse_Exception::class);
/** @var CMSPageEditController|ContentReviewCMSExtension $controller */
$controller = new CMSPageEditController();
$dummyForm = new Form($controller, "EditForm", new FieldList(), new FieldList());
$controller->savereview(array(
"ID" => "FAIL",
"Message" => null,
), $dummyForm);
}
public function testReviewedWithAuthor()
{
/** @var Member $author */
$author = $this->objFromFixture(Member::class, "author");
$this->logInAs($author);
/** @var Page|SiteTreeContentReview $page */
$page = $this->objFromFixture(Page::class, "home");
$data = array(
"action_savereview" => 1,
"ID" => $page->ID,
);
$this->get('admin/pages/edit/show/' . $page->ID);
$response = $this->post($this->getFormAction($page), $data);
$this->assertEquals("OK", $response->getStatusDescription());
$this->assertEquals(200, $response->getStatusCode());
}
/**
* Return a CMS page edit form action via using a dummy request and session
*
* @param Page $page
* @return string
*/
protected function getFormAction(Page $page)
{
$controller = singleton(CMSPageEditController::class);
$controller->setRequest(new HTTPRequest('GET', '/'));
$controller->getRequest()->setSession($this->session());
return $controller->getEditForm($page->ID)->FormAction();
}
}

View File

@ -0,0 +1,169 @@
<?php
namespace SilverStripe\ContentReview\Tests;
use Page;
use ReflectionClass;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\CMS\Controllers\CMSPageEditController;
use SilverStripe\ContentReview\Extensions\ContentReviewCMSExtension;
use SilverStripe\ContentReview\Extensions\ContentReviewDefaultSettings;
use SilverStripe\ContentReview\Extensions\ContentReviewOwner;
use SilverStripe\ContentReview\Extensions\SiteTreeContentReview;
use SilverStripe\ContentReview\Tasks\ContentReviewEmails;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\Security\Group;
use SilverStripe\Security\Member;
use SilverStripe\SiteConfig\SiteConfig;
use SilverStripe\ContentReview\Models\ContentReviewLog;
class ContentReviewNotificationTest extends SapphireTest
{
/**
* @var string
*/
protected static $fixture_file = 'ContentReviewTest.yml';
protected function setUp(): void
{
parent::setUp();
// Hack to ensure only desired siteconfig is scaffolded
$desiredID = $this->idFromFixture(SiteConfig::class, 'mysiteconfig');
foreach (SiteConfig::get()->exclude('ID', $desiredID) as $config) {
$config->delete();
}
}
/**
* @var array
*/
protected static $required_extensions = [
SiteTree::class => [SiteTreeContentReview::class],
Group::class => [ContentReviewOwner::class],
Member::class => [ContentReviewOwner::class],
CMSPageEditController::class => [ContentReviewCMSExtension::class],
SiteConfig::class => [ContentReviewDefaultSettings::class],
];
public function testContentReviewEmails()
{
DBDatetime::set_mock_now('2010-02-24 12:00:00');
/** @var Page|SiteTreeContentReview $childParentPage */
$childParentPage = $this->objFromFixture(Page::class, 'contact');
$childParentPage->NextReviewDate = '2010-02-23';
$childParentPage->write();
$task = new ContentReviewEmails();
$task->run(new HTTPRequest('GET', '/dev/tasks/ContentReviewEmails'));
// Set template variables (as per variable case)
$ToEmail = 'author@example.com';
$Subject = 'Please log in to review some content!';
$PagesCount = 3;
$ToFirstName = 'Test';
$email = $this->findEmail($ToEmail, null, $Subject);
$this->assertNotNull($email, "Email haven't been sent.");
$this->assertStringContainsString(
"<h1>$Subject</h1>".
"<p>There are $PagesCount pages that are due for review today by you, $ToFirstName.</p>".
"<p>This email was sent to $ToEmail</p>",
$email['HtmlContent']
);
$this->assertStringContainsString('Staff', $email['HtmlContent']);
$this->assertStringContainsString('Contact Us', $email['HtmlContent']);
$this->assertStringContainsString('Contact Us Child', $email['HtmlContent']);
DBDatetime::clear_mock_now();
}
/**
* When a content review is left after a review date, we want to ensure that
* overdue notifications aren't sent.
*/
public function testContentReviewNeeded()
{
DBDatetime::set_mock_now('2018-08-10 12:00:00');
/** @var Page|SiteTreeContentReview $childParentPage */
$childParentPage = $this->objFromFixture(Page::class, 'no-review');
$childParentPage->NextReviewDate = '2018-08-10';
$childParentPage->write();
// we need to ensure only our test page is being ran. If we don't do this
// then it may notify for other pages which fails our test
$this->deleteAllPagesExcept([$childParentPage->ID]);
// Grabbing the 'author' from member class
$member = $this->objFromFixture(Member::class, 'author');
// Assigning member as contentreviewer to page
$childParentPage->ContentReviewUsers()->add($member);
// Assert that only one reviewer is assigned to page
$this->assertCount(1, $childParentPage->ContentReviewUsers());
// Create new log
$log = new ContentReviewLog();
// Assign log reviewer as current member
$log->ReviewerID = $member->ID;
// Assign log ID to page ID
$log->SiteTreeID = $childParentPage->ID;
// Write to DB
$log->write();
// assert that log was created day of review
$this->assertEquals('2018-08-10 12:00:00', $log->Created);
$this->assertCount(1, $childParentPage->ReviewLogs());
$task = new ContentReviewEmails();
$task->run(new HTTPRequest('GET', '/dev/tasks/ContentReviewEmails'));
// Expecting to not send the email as content review for page is done
$email = $this->findEmail($member->Email);
$this->assertNull($email);
DBDatetime::clear_mock_now();
}
/**
* Test that provided email is valid
*/
public function testIsValidEmail()
{
$class = new ReflectionClass(ContentReviewEmails::class);
$method = $class->getMethod('isValidEmail');
$method->setAccessible(true);
$member = $this->objFromFixture(Member::class, 'author');
$task = new ContentReviewEmails();
$this->assertTrue($method->invokeArgs($task, [$member->Email]));
$this->assertTrue($method->invokeArgs($task, ['correct.email@example.com']));
$this->assertFalse($method->invokeArgs($task, [null]));
$this->assertFalse($method->invokeArgs($task, ['broken.email']));
$this->assertFalse($method->invokeArgs($task, ['broken@email']));
}
/**
* Deletes all pages except those passes in to the $ids parameter
*
* @param array $ids Page IDs which will NOT be deleted
*/
private function deleteAllPagesExcept(array $ids)
{
$pages = SiteTree::get()->exclude('ID', $ids);
foreach ($pages as $page) {
$page->delete();
}
}
}

View File

@ -0,0 +1,97 @@
<?php
namespace SilverStripe\ContentReview\Tests;
use SilverStripe\CMS\Controllers\CMSPageEditController;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\ContentReview\Extensions\ContentReviewCMSExtension;
use SilverStripe\ContentReview\Extensions\ContentReviewDefaultSettings;
use SilverStripe\ContentReview\Extensions\ContentReviewOwner;
use SilverStripe\ContentReview\Extensions\SiteTreeContentReview;
use SilverStripe\ContentReview\Reports\PagesDueForReviewReport;
use SilverStripe\ContentReview\Reports\PagesWithoutReviewScheduleReport;
use SilverStripe\Dev\FunctionalTest;
use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\Security\Group;
use SilverStripe\Security\Member;
use SilverStripe\SiteConfig\SiteConfig;
class ContentReviewReportTest extends FunctionalTest
{
/**
* @var string
*/
protected static $fixture_file = 'ContentReviewTest.yml';
/**
* @var array
*/
protected static $required_extensions = [
SiteTree::class => [SiteTreeContentReview::class],
Group::class => [ContentReviewOwner::class],
Member::class => [ContentReviewOwner::class],
CMSPageEditController::class => [ContentReviewCMSExtension::class],
SiteConfig::class => [ContentReviewDefaultSettings::class],
];
public function testPagesDueForReviewReport()
{
/** @var Member $editor */
$editor = $this->objFromFixture(Member::class, "editor");
$this->logInAs($editor);
$report = new PagesDueForReviewReport();
$report->parameterFields();
$report->columns();
$report->title();
$results = $report->sourceRecords([
"ReviewDateAfter" => "2010-01-01",
"ReviewDateBefore" => "2010-12-12",
]);
$this->assertListEquals([
['Title' => 'Contact Us Child'],
['Title' => 'Home'],
['Title' => 'About Us'],
['Title' => 'Staff'],
['Title' => 'Contact Us'],
], $results);
DBDatetime::set_mock_now("2010-02-13 00:00:00");
$results = $report->sourceRecords([]);
$this->assertEquals([
"Home",
"About Us",
], $results->column("Title"));
DBDatetime::clear_mock_now();
}
public function testPagesWithoutReviewScheduleReport()
{
/** @var Member $editor */
$editor = $this->objFromFixture(Member::class, "editor");
$this->logInAs($editor);
$report = new PagesWithoutReviewScheduleReport();
$report->parameterFields();
$report->columns();
$report->title();
$results = $report->sourceRecords();
$this->assertListEquals([
['Title' => 'Home'],
['Title' => 'About Us'],
['Title' => 'Page without review date'],
['Title' => 'Page owned by group'],
], $results);
}
}

View File

@ -0,0 +1,321 @@
<?php
namespace SilverStripe\ContentReview\Tests;
use function date;
use Page;
use SilverStripe\CMS\Controllers\CMSPageEditController;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\ContentReview\Extensions\ContentReviewCMSExtension;
use SilverStripe\ContentReview\Extensions\ContentReviewDefaultSettings;
use SilverStripe\ContentReview\Extensions\ContentReviewOwner;
use SilverStripe\ContentReview\Extensions\SiteTreeContentReview;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\FieldType\DBDate;
use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\Security\Group;
use SilverStripe\Security\Member;
use SilverStripe\SiteConfig\SiteConfig;
/**
* This class tests that settings are inherited correctly based on the inherited,
* custom or disabled settings.
*/
class ContentReviewSettingsTest extends SapphireTest
{
/**
* @var string
*/
protected static $fixture_file = 'ContentReviewSettingsTest.yml';
/**
* @var array
*/
protected static $required_extensions = [
SiteTree::class => [SiteTreeContentReview::class],
Group::class => [ContentReviewOwner::class],
Member::class => [ContentReviewOwner::class],
CMSPageEditController::class => [ContentReviewCMSExtension::class],
SiteConfig::class => [ContentReviewDefaultSettings::class],
];
public function testAdvanceReviewDate10Days()
{
/** @var Page|SiteTreeContentReview $page */
$page = new Page();
$page->ContentReviewType = "Custom";
$page->ReviewPeriodDays = 10;
$this->assertTrue($page->advanceReviewDate());
$page->write();
$this->assertEquals(date('Y-m-d', strtotime("now + 10 days")), $page->NextReviewDate);
}
public function testAdvanceReviewDateNull()
{
/** @var Page|SiteTreeContentReview $page */
$page = new Page();
$page->ContentReviewType = "Custom";
$page->ReviewPeriodDays = 0;
$this->assertFalse($page->advanceReviewDate());
$page->write();
$this->assertEquals(null, $page->NextReviewDate);
}
public function testAdvanceReviewFromCustomSettings()
{
/** @var Page|SiteTreeContentReview $page */
$page = $this->objFromFixture(Page::class, "custom");
$this->assertTrue($page->advanceReviewDate());
$page->write();
$this->assertEquals(
date('Y-m-d', strtotime("now + " . $page->ReviewPeriodDays . " days")),
$page->NextReviewDate
);
}
public function testAdvanceReviewFromInheritedSettings()
{
// When a parent page is advanced, the next review date of the child is not automatically advanced
$parentPage = $this->objFromFixture(Page::class, "page-1");
$this->assertTrue($parentPage->advanceReviewDate());
$parentPage->write();
$page = $this->objFromFixture(Page::class, "page-1-1");
$this->assertEquals(date('Y-m-d', strtotime("now + 5 days")), $parentPage->NextReviewDate);
$this->assertEquals('2011-04-12', $page->NextReviewDate);
// When a sub page is advanced, the next review date is advanced by the number of days in the parent
$this->assertTrue($page->advanceReviewDate());
$page->write();
$this->assertEquals(date('Y-m-d', strtotime("now + 5 days")), $page->NextReviewDate);
}
public function testAdvanceReviewFromInheritedSiteConfigSettings()
{
/** @var Page|SiteTreeContentReview $page */
$page = $this->objFromFixture(Page::class, "inherit");
/** @var SiteConfig|ContentReviewDefaultSettings $siteConfig */
$siteConfig = $this->objFromFixture(SiteConfig::class, "default");
$this->assertTrue($page->advanceReviewDate());
$page->write();
$this->assertEquals(
date(
'Y-m-d',
strtotime("now + " . $siteConfig->ReviewPeriodDays . " days")
),
$page->NextReviewDate
);
}
public function testGetSettingsObjectFromCustom()
{
/** @var Page|SiteTreeContentReview $page */
$page = $this->objFromFixture(Page::class, "custom");
$this->assertEquals("Custom", $page->ContentReviewType);
$this->assertEquals($page, $page->getOptions());
}
public function testGetSettingsObjectFromDisabled()
{
/** @var Page|SiteTreeContentReview $page */
$page = $this->objFromFixture(Page::class, "disabled");
$this->assertEquals("Disabled", $page->ContentReviewType);
$this->assertFalse($page->getOptions());
}
public function testGetOptionObjectFromInheritedDisabled()
{
/** @var Page|SiteTreeContentReview $page */
$page = $this->objFromFixture(Page::class, "page-2-1-1");
$this->assertEquals("Inherit", $page->ContentReviewType);
$this->assertFalse($page->getOptions());
}
public function testGetOptionObjectFromDeeplyInheritedPage()
{
/** @var Page|SiteTreeContentReview $page */
$page = $this->objFromFixture(Page::class, "page-3-1-1-1");
$this->assertEquals("Inherit", $page->ContentReviewType);
$this->assertInstanceOf(SiteConfig::class, $page->getOptions());
}
public function testGetSettingsObjectFromInheritPage()
{
/** @var Page|SiteTreeContentReview $page */
$page = $this->objFromFixture(Page::class, "page-1-1");
/** @var Page|SiteTreeContentReview $parentPage */
$parentPage = $this->objFromFixture(Page::class, "page-1");
$this->assertEquals("Inherit", $page->ContentReviewType);
$this->assertEquals(get_class($parentPage), get_class($page->getOptions()));
$this->assertEquals($parentPage->ID, $page->getOptions()->ID);
}
public function testGetSettingsObjectFromInheritedRootPage()
{
/** @var Page|SiteTreeContentReview $page */
$page = $this->objFromFixture(Page::class, "inherit");
$this->assertEquals("Inherit", $page->ContentReviewType);
$this->assertEquals(
$this->objFromFixture(
SiteConfig::class,
"default"
)->ID,
$page->getOptions()->ID
);
}
public function testGetNextReviewDateFromCustomSettings()
{
/** @var Page|SiteTreeContentReview $page */
$page = $this->objFromFixture(Page::class, 'custom');
$date = $page->getReviewDate();
$this->assertEquals('2010-02-01', $date->format('Y-MM-dd'));
}
public function testGetNextReviewDateFromSiteConfigInheritedSetting()
{
/** @var Page|SiteTreeContentReview $page */
$page = $this->objFromFixture(Page::class, "inherit");
$nextReviewDate = $page->getReviewDate();
$this->assertInstanceOf(DBDate::class, $nextReviewDate);
/** @var SiteConfig|ContentReviewDefaultSettings $siteConfig */
$siteConfig = $this->objFromFixture(SiteConfig::class, "default");
$expected = $this->addDaysToDate(DBDatetime::now(), $siteConfig->ReviewPeriodDays);
$this->assertEquals($expected, $nextReviewDate->format('Y-MM-dd'));
}
public function testGetNextReviewDateFromPageInheritedSetting()
{
// Although page-1-1 inherits from page-1, it has an independent review date
$page = $this->objFromFixture(Page::class, "page-1-1");
$nextReviewDate = $page->getReviewDate();
$this->assertInstanceOf(DBDate::class, $nextReviewDate);
$this->assertEquals('2011-04-12', $nextReviewDate->format('Y-MM-dd'));
}
public function testUpdateNextReviewDateFromCustomToDisabled()
{
/** @var Page|SiteTreeContentReview $page */
$page = $this->objFromFixture(Page::class, "custom");
// before write()
$this->assertEquals("2010-02-01", $page->NextReviewDate);
$page->ContentReviewType = "Disabled";
$page->write();
DataObject::flush_and_destroy_cache();
unset($page);
/** @var Page|SiteTreeContentReview $page */
$page = $this->objFromFixture(Page::class, "custom");
$this->assertNull($page->NextReviewDate);
}
public function testUpdateNextReviewDateFromDisabledToCustom()
{
/** @var Page|SiteTreeContentReview $page */
$page = $this->objFromFixture(Page::class, "disabled");
$this->assertNull($page->NextReviewDate);
$page->ContentReviewType = "Custom";
$page->ReviewPeriodDays = "7";
$page->write();
DataObject::flush_and_destroy_cache();
unset($page);
/** @var Page|SiteTreeContentReview $page */
$page = $this->objFromFixture(Page::class, "disabled");
$expected = date('Y-m-d', strtotime("+ " . $page->ReviewPeriodDays . " days"));
$this->assertEquals($expected, $page->NextReviewDate);
}
public function testParentChangedOptionsAndChildShouldToo()
{
/** @var Page|SiteTreeContentReview $parentPage */
$parentPage = $this->objFromFixture(Page::class, "page-1");
/** @var Page|SiteTreeContentReview $childPage */
$childPage = $this->objFromFixture(Page::class, "page-1-1");
// Parent and child pages have different review dates
$this->assertNotEquals($parentPage->NextReviewDate, $childPage->NextReviewDate);
// But if we change the parent page ReviewPeriodDays to 10, the childs stays the same
$parentPage->ReviewPeriodDays = 10;
$parentPage->write();
// Flush all the caches!
DataObject::flush_and_destroy_cache();
/** @var Page|SiteTreeContentReview $page */
$parentPage = $this->objFromFixture(Page::class, "page-1");
/** @var Page|SiteTreeContentReview $page */
$childPage = $this->objFromFixture(Page::class, "page-1-1");
// The parent page's date advances, but not the child's
$this->assertEquals('2011-04-12', $childPage->NextReviewDate);
$this->assertEquals($this->addDaysToDate(date('Y-m-d'), 10), $parentPage->NextReviewDate);
// Reviewing the child page should, however, advance its review by 10 days
$childPage->advanceReviewDate();
$childPage->write();
$this->assertEquals($this->addDaysToDate(date('Y-m-d'), 10), $childPage->NextReviewDate);
}
/**
* Note: all input dates should be DBDatetime or strings in CLDR date format. See {@link DBDate} for information
*
* @param string|DBDatetime $date
* @param int $days
* @param string $format
*
* @return bool|string
*/
private function addDaysToDate($date, $days, $format = 'Y-MM-dd')
{
if (is_object($date)) {
$sec = strtotime("+ " . $days . " days", $date->getTimestamp());
} else {
$sec = strtotime("+ " . $days . " days", DBDate::create()->setValue($date)->getTimestamp());
}
return DBDate::create()->setValue($sec)->format($format);
}
}

View File

@ -0,0 +1,106 @@
SilverStripe\Security\Permission:
cmsmain1:
Code: CMS_ACCESS_CMSMain
cmsmain2:
Code: CMS_ACCESS_CMSMain
setreviewdates:
Code: EDIT_CONTENT_REVIEW_FIELDS
workflowadmin1:
Code: IS_WORKFLOW_ADMIN
workflowadmin2:
Code: IS_WORKFLOW_ADMIN
SilverStripe\Security\Group:
webmastergroup:
Title: Edit existing pages
Code: editorgroup
Permissions:
- =>SilverStripe\Security\Permission.cmsmain1
- =>SilverStripe\Security\Permission.workflowadmin1
- =>SilverStripe\Security\Permission.setreviewdates
editorgroup:
Title: Edit existing pages
Code: editorgroup
Permissions:
- =>SilverStripe\Security\Permission.cmsmain1
- =>SilverStripe\Security\Permission.workflowadmin1
- =>SilverStripe\Security\Permission.setreviewdates
authorgroup:
Title: Author existing pages
Code: authorgroup
Permissions:
- =>SilverStripe\Security\Permission.cmsmain2
- =>SilverStripe\Security\Permission.workflowadmin2
SilverStripe\Security\Member:
webmaster:
FirstName: Web
Surname: Master
Email: webmaster@example.com
Groups: =>SilverStripe\Security\Group.webmastergroup
author:
FirstName: Test
Surname: Author
Email: author@example.com
Groups: =>SilverStripe\Security\Group.authorgroup
editor:
FirstName: Test
Surname: Editor
Groups: =>SilverStripe\Security\Group.editorgroup
SilverStripe\SiteConfig\SiteConfig:
default:
ContentReviewUsers: =>SilverStripe\Security\Member.webmaster
ContentReviewGroups: =>SilverStripe\Security\Group.webmastergroup
ReviewPeriodDays: 30
Page:
custom:
Title: custom
ContentReviewType: Custom
NextReviewDate: 2010-02-01
ContentReviewUsers: =>SilverStripe\Security\Member.editor
ReviewPeriodDays: 10
disabled:
Title: disabled
ContentReviewType: Disabled
inherit:
Title: inherit
ContentReviewType: Inherit
page-1:
Title: page 1
ContentReviewType: Custom
ReviewPeriodDays: 5
NextReviewDate: 2010-02-01
page-1-1:
Title: page 1 1
ContentReviewType: Inherit
ReviewPeriodDays: 1
NextReviewDate: 2011-04-12
ParentID: =>Page.page-1
page-2:
Title: page 2
ContentReviewType: Inherit
page-2-1:
Title: page 2 1
ContentReviewType: Disabled
ParentID: =>Page.page-2
page-2-1-1:
Title: page 2 1 1
ContentReviewType: Inherit
ParentID: =>Page.page-2-1
page-3:
Title: page 3
ContentReviewType: Inherit
page-3-1:
Title: page 3 1
ContentReviewType: Inherit
ParentID: =>Page.page-3
page-3-1-1:
Title: page 3 1 1
ContentReviewType: Inherit
ParentID: =>Page.page-3-1
page-3-1-1-1:
Title: page 3 1 1 1
ContentReviewType: Inherit
ParentID: =>Page.page-3-1-1

View File

@ -0,0 +1,87 @@
SilverStripe\SiteConfig\SiteConfig:
mysiteconfig:
ReviewFrom: sender@silverstripe.com
ReviewSubject: 'Please log in to review some content!'
ReviewBody: '<h1>$Subject</h1><p>There are $PagesCount pages that are due for review today by you, $ToFirstName.</p><p>This email was sent to $ToEmail</p>'
SilverStripe\Security\Permission:
cmsmain1:
Code: CMS_ACCESS_CMSMain
cmsmain2:
Code: CMS_ACCESS_CMSMain
setreviewdates:
Code: EDIT_CONTENT_REVIEW_FIELDS
workflowadmin1:
Code: IS_WORKFLOW_ADMIN
workflowadmin2:
Code: IS_WORKFLOW_ADMIN
SilverStripe\Security\Group:
editorgroup:
Title: Edit existing pages
Code: editorgroup
Permissions:
- =>SilverStripe\Security\Permission.cmsmain1
- =>SilverStripe\Security\Permission.workflowadmin1
- =>SilverStripe\Security\Permission.setreviewdates
authorgroup:
Title: Author existing pages
Code: authorgroup
Permissions:
- =>SilverStripe\Security\Permission.cmsmain2
- =>SilverStripe\Security\Permission.workflowadmin2
SilverStripe\Security\Member:
author:
FirstName: Test
Surname: Author
Email: author@example.com
Groups: =>SilverStripe\Security\Group.authorgroup
editor:
FirstName: Test
Surname: Editor
Groups: =>SilverStripe\Security\Group.editorgroup
visitor:
FirstName: Kari
Surname: Visitor
Email: visitor@example.com
Page:
# Cant be reviewed, no owners
home:
Title: Home
ContentReviewType: Custom
NextReviewDate: 2010-02-01
ReviewPeriodDays: 10
# Cant be reviewed, no owners
about:
Title: About Us
ContentReviewType: Custom
NextReviewDate: 2010-02-07
ReviewPeriodDays: 10
staff:
Title: Staff
ContentReviewType: Custom
NextReviewDate: 2010-02-14
ReviewPeriodDays: 10
ContentReviewUsers: =>SilverStripe\Security\Member.author
contact:
Title: Contact Us
ContentReviewType: Custom
ReviewPeriodDays: 10
NextReviewDate: 2010-02-21
ContentReviewGroups: =>SilverStripe\Security\Group.authorgroup
contact-child:
Title: Contact Us Child
ContentReviewType: Inherit
ParentID: =>Page.contact
# Cant be reviewed, no NextReviewDate
no-review:
Title: Page without review date
ContentReviewType: Custom
ContentReviewUsers: =>SilverStripe\Security\Member.author
# Cant be reviewed, no NextReviewDate
group-owned:
Title: Page owned by group
ContentReviewType: Custom
ContentReviewGroups: =>SilverStripe\Security\Group.authorgroup

View File

@ -0,0 +1,91 @@
<?php
namespace SilverStripe\ContentReview\Tests\Extensions;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\ContentReview\Extensions\ContentReviewCMSExtension;
use SilverStripe\ContentReview\Forms\ReviewContentHandler;
use SilverStripe\Control\Controller;
use SilverStripe\Control\HTTPResponse_Exception;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\Forms\Form;
use SilverStripe\Security\Member;
class ContentReviewCMSExtensionTest extends SapphireTest
{
/**
* Test that ReviewContentForm finds an ID parameter then returns the result of getReviewContentForm
* with the passed ID
*/
public function testReviewContentForm()
{
$mock = $this->getMockBuilder(ContentReviewCMSExtension::class)
->setMethods(['getReviewContentForm'])
->getMock();
$mock->expects($this->once())->method('getReviewContentForm')->with(123)->willReturn(true);
$request = new HTTPRequest('GET', '/', [], ['ID' => 123]);
$result = $mock->ReviewContentForm($request);
$this->assertTrue($result);
}
public function testGetReviewContentFormThrowsExceptionWhenPageNotFound()
{
$this->expectException(HTTPResponse_Exception::class);
$this->expectExceptionMessage('Bad record ID #1234');
(new ContentReviewCMSExtension)->getReviewContentForm(1234);
}
public function testGetReviewContentFormThrowsExceptionWhenObjectCannotBeReviewed()
{
$this->expectException(HTTPResponse_Exception::class);
$this->expectExceptionMessage('It seems you don\'t have the necessary permissions to review this content');
$this->logOut();
$mock = $this->getMockBuilder(ContentReviewCMSExtension::class)
->setMethods(['findRecord'])
->getMock();
$mock->setOwner(new Controller);
// Return a DataObject without the content review extension applied
$mock->expects($this->once())->method('findRecord')->with(['ID' => 123])->willReturn(new SiteTree);
$mock->getReviewContentForm(123);
}
/**
* Ensure that savereview() calls the ReviewContentHandler and passes the data to it
*/
public function testSaveReviewCallsHandler()
{
$mock = $this->getMockBuilder(ContentReviewCMSExtension::class)
->setMethods(['findRecord', 'getReviewContentHandler'])
->getMock();
$mock->setOwner(new Controller);
$mockPage = (object) ['ID' => 123];
$mock->expects($this->once())->method('findRecord')->willReturn($mockPage);
$mockHandler = $this->getMockBuilder(ReviewContentHandler::class)
->setMethods(['submitReview'])
->getMock();
$mockHandler->expects($this->once())
->method('submitReview')
->with($mockPage, ['foo'])
->willReturn('Success');
$mock->expects($this->once())->method('getReviewContentHandler')->willReturn($mockHandler);
$form = $this->getMockBuilder(Form::class)
->disableOriginalConstructor()
->getMock();
$result = $mock->savereview(['foo'], $form);
$this->assertSame('Success', $result);
}
}

View File

@ -0,0 +1,90 @@
<?php
namespace SilverStripe\ContentReview\Tests\Forms;
use Page;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Control\Controller;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\ContentReview\Forms\ReviewContentHandler;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\Forms\Form;
use SilverStripe\Forms\HiddenField;
use SilverStripe\Forms\TextareaField;
use SilverStripe\Security\Member;
use SilverStripe\ORM\ValidationException;
class ReviewContentHandlerTest extends SapphireTest
{
public function testForm()
{
$page = Page::create();
$page->Title = 'Test';
$page->write();
$form = ReviewContentHandler::create()->Form($page);
$this->assertInstanceOf(Form::class, $form);
$this->assertSame('ReviewContentForm', $form->getName());
$this->assertInstanceOf(HiddenField::class, $form->Fields()->fieldByName('ID'));
$this->assertInstanceOf(HiddenField::class, $form->Fields()->fieldByName('ClassName'));
$this->assertInstanceOf(TextareaField::class, $form->Fields()->fieldByName('Review'));
$saveAction = $form->Actions()->first();
$this->assertNotNull($saveAction);
$this->assertTrue($saveAction->hasClass('review-content__action'));
}
public function testExceptionThrownWhenSubmittingReviewForInvalidObject()
{
$this->expectException(ValidationException::class);
$this->expectExceptionMessage('It seems you don\'t have the necessary permissions to submit a content review');
ReviewContentHandler::create()->submitReview(new Member, ['foo' => 'bar']);
}
public function testExceptionThrownWhenSubmittingReviewForInvalidDataObject()
{
$this->expectException(ValidationException::class);
$this->expectExceptionMessage('It seems you don\'t have the necessary permissions to submit a content review');
ReviewContentHandler::create()->submitReview(new Controller, ['foo' => 'bar']);
}
public function testAddReviewNoteCalledWhenSubmittingReview()
{
$this->logInWithPermission('ADMIN');
$controller = new Controller;
$request = new HTTPRequest('GET', '/');
$controller->setRequest($request);
Injector::inst()->registerservice($request);
$mock = $this->getMockBuilder(ReviewContentHandler::class)
->setConstructorArgs([$controller])
->setMethods(['canSubmitReview'])
->getMock();
$mock->expects($this->exactly(3))->method('canSubmitReview')->willReturn(true);
// Via CMS
$request->addHeader('X-Formschema-Request', true);
$result = $mock->submitReview(new SiteTree, ['Review' => 'testing']);
$this->assertSame('Review successfully added', $result);
$request->removeHeader('X-Formschema-Request');
// Via AJAX
$request->addHeader('X-Requested-With', 'XMLHttpRequest');
$result = $mock->submitReview(new SiteTree, ['Review' => 'testing']);
$this->assertInstanceOf(HTTPResponse::class, $result);
$this->assertSame(200, $result->getStatusCode());
$this->assertSame('Review successfully added', $result->getBody());
$request->removeHeader('X-Requested-With');
// Default
$result = $mock->submitReview(new SiteTree, ['Review' => 'testing']);
$this->assertInstanceOf(HTTPResponse::class, $result);
$this->assertSame(302, $result->getStatusCode());
}
}

View File

@ -0,0 +1,404 @@
<?php
namespace SilverStripe\ContentReview\Tests;
use Page;
use SilverStripe\CMS\Controllers\CMSPageEditController;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\ContentReview\Extensions\ContentReviewCMSExtension;
use SilverStripe\ContentReview\Extensions\ContentReviewDefaultSettings;
use SilverStripe\ContentReview\Extensions\ContentReviewOwner;
use SilverStripe\ContentReview\Extensions\SiteTreeContentReview;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Forms\LiteralField;
use SilverStripe\ORM\FieldType\DBDate;
use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\Security\Group;
use SilverStripe\Security\Member;
use SilverStripe\SiteConfig\SiteConfig;
use SilverStripe\Versioned\Versioned;
use SilverStripe\ORM\ArrayList;
class SiteTreeContentReviewTest extends ContentReviewBaseTest
{
protected $usesTransactions = false;
/**
* @var string
*/
protected static $fixture_file = 'ContentReviewTest.yml';
/**
* @var array
*/
protected static $required_extensions = [
SiteTree::class => [SiteTreeContentReview::class],
Group::class => [ContentReviewOwner::class],
Member::class => [ContentReviewOwner::class],
CMSPageEditController::class => [ContentReviewCMSExtension::class],
SiteConfig::class => [ContentReviewDefaultSettings::class],
];
public function testOwnerNames()
{
/** @var Member $editor */
$editor = $this->objFromFixture(Member::class, "editor");
$this->logInAs($editor);
/** @var Page|SiteTreeContentReview $page */
$page = new Page();
$page->ReviewPeriodDays = 10;
$page->ContentReviewType = "Custom";
$page->ContentReviewUsers()->push($editor);
$page->write();
$this->assertTrue($page->canPublish());
$this->assertTrue($page->publishRecursive());
$this->assertEquals($page->OwnerNames, "Test Editor", "Test Editor should be the owner");
/** @var Page|SiteTreeContentReview $page */
$page = $this->objFromFixture(Page::class, "about");
$page->OwnerUsers()->removeAll();
$page->write();
$this->assertTrue($page->canPublish());
$this->assertTrue($page->publishRecursive());
$this->assertEquals("", $page->OwnerNames);
}
public function testPermissionsExists()
{
$perms = singleton(SiteTreeContentReview::class)->providePermissions();
$this->assertTrue(isset($perms["EDIT_CONTENT_REVIEW_FIELDS"]));
}
public function testUserWithPermissionCanEdit()
{
/** @var Member $editor */
$editor = $this->objFromFixture(Member::class, "editor");
$this->logInAs($editor);
/** @var Page|SiteTreeContentReview $page */
$page = new Page();
$fields = $page->getSettingsFields();
$this->assertNotNull($fields->dataFieldByName("NextReviewDate"));
}
public function testUserWithoutPermissionCannotEdit()
{
/** @var Member $author */
$author = $this->objFromFixture(Member::class, "author");
$this->logInAs($author);
/** @var Page|SiteTreeContentReview $page */
$page = new Page();
$fields = $page->getSettingsFields();
$this->assertNull($fields->dataFieldByName("NextReviewDate"));
}
public function testAutomaticallyToNotSetReviewDate()
{
/** @var Member $editor */
$editor = $this->objFromFixture(Member::class, "editor");
$this->logInAs($editor);
/** @var Page|SiteTreeContentReview $page */
$page = new Page();
$page->ReviewPeriodDays = 10;
$page->write();
$this->assertTrue($page->publishRecursive());
$this->assertEquals(null, $page->NextReviewDate);
}
public function testAdvanceReviewDate()
{
$page = new Page();
$page->Title = 'Test page';
$page->ReviewPeriodDays = 0;
// Set timestamp to a time in the past
$timestamp = DBDatetime::now()->getTimestamp() - 100000;
$page->NextReviewDate = DBDate::create()->setValue($timestamp)->Format(DBDate::ISO_DATE);
$page->write();
$page->advanceReviewDate();
$this->assertNull(Page::get()->find('Title', 'Test page')->NextReviewDate);
}
public function testAddReviewNote()
{
/** @var Member $author */
$author = $this->objFromFixture(Member::class, "author");
/** @var Page|SiteTreeContentReview $page */
$page = $this->objFromFixture(Page::class, "home");
$page->addReviewNote($author, "This is a message");
/** @var Page|SiteTreeContentReview $page */
$homepage = $this->objFromFixture(Page::class, "home");
$this->assertEquals(1, $homepage->ReviewLogs()->count());
$this->assertEquals("This is a message", $homepage->ReviewLogs()->first()->Note);
}
public function testGetContentReviewOwners()
{
/** @var Page|SiteTreeContentReview $page */
$page = $this->objFromFixture(Page::class, "group-owned");
$owners = $page->ContentReviewOwners();
$this->assertEquals(1, $owners->count());
$this->assertEquals("author@example.com", $owners->first()->Email);
}
public function testCanNotBeReviewBecauseNoReviewDate()
{
DBDatetime::set_mock_now("2010-01-01 12:00:00");
/** @var Member $author */
$author = $this->objFromFixture(Member::class, "author");
/** @var Page|SiteTreeContentReview $page */
$page = $this->objFromFixture(Page::class, "no-review");
$this->assertFalse($page->canBeReviewedBy($author));
DBDatetime::clear_mock_now();
}
public function testCanNotBeReviewedBecauseInFuture()
{
DBDatetime::set_mock_now("2010-01-01 12:00:00");
/** @var Member $author */
$author = $this->objFromFixture(Member::class, "author");
/** @var Page|SiteTreeContentReview $page */
$page = $this->objFromFixture(Page::class, "staff");
$this->assertFalse($page->canBeReviewedBy($author));
DBDatetime::clear_mock_now();
}
public function testCanNotBeReviewedByUser()
{
DBDatetime::set_mock_now("2010-03-01 12:00:00");
/** @var Member $author */
$author = $this->objFromFixture(Member::class, "author");
/** @var Page|SiteTreeContentReview $page */
$page = $this->objFromFixture(Page::class, "home");
$this->assertFalse($page->canBeReviewedBy($author));
DBDatetime::clear_mock_now();
}
public function testCanBeReviewedByUser()
{
DBDatetime::set_mock_now("2010-03-01 12:00:00");
/** @var Member $author */
$author = $this->objFromFixture(Member::class, "author");
/** @var Page|SiteTreeContentReview $page */
$page = $this->objFromFixture(Page::class, "staff");
$this->assertTrue($page->canBeReviewedBy($author));
DBDatetime::clear_mock_now();
}
public function testCanNotBeReviewedByGroup()
{
DBDatetime::set_mock_now("2010-03-01 12:00:00");
/** @var Member $author */
$author = $this->objFromFixture(Member::class, "editor");
/** @var Page|SiteTreeContentReview $page */
$page = $this->objFromFixture(Page::class, "contact");
$this->assertFalse($page->canBeReviewedBy($author));
DBDatetime::clear_mock_now();
}
public function testCanBeReviewedByGroup()
{
DBDatetime::set_mock_now("2010-03-01 12:00:00");
/** @var Member $author */
$author = $this->objFromFixture(Member::class, "author");
/** @var Page|SiteTreeContentReview $page */
$page = $this->objFromFixture(Page::class, "contact");
$this->assertTrue($page->canBeReviewedBy($author));
DBDatetime::clear_mock_now();
}
public function testCanBeReviewedFromInheritedSetting()
{
DBDatetime::set_mock_now("2013-03-01 12:00:00");
/** @var Member $author */
$author = $this->objFromFixture(Member::class, "author");
/** @var Page|SiteTreeContentReview $parentPage */
$parentPage = $this->objFromFixture(Page::class, "contact");
$parentPage->NextReviewDate = "2013-01-01";
$parentPage->write();
/** @var Page|SiteTreeContentReview $page */
$page = $this->objFromFixture(Page::class, "contact-child");
$this->assertTrue($page->canBeReviewedBy($author));
DBDatetime::clear_mock_now();
}
public function testUnModifiedPagesDontChangeEditor()
{
DBDatetime::set_mock_now("2013-03-01 12:00:00");
/** @var Member $author */
$author = $this->objFromFixture(Member::class, "author");
$this->logInAs($author);
// Page which is un-modified doesn't advance version of have an editor assigned
$contactPage = $this->objFromFixture(Page::class, "contact");
$contactPageVersion = $contactPage->Version;
$contactPage->write();
$this->assertEmpty($contactPage->LastEditedByName);
$this->assertEquals(
$contactPageVersion,
Versioned::get_versionnumber_by_stage(SiteTree::class, 'Stage', $contactPage->ID, false)
);
// Page with modifications gets marked
$homePage = $this->objFromFixture(Page::class, "home");
$homePageVersion = $homePage->Version;
$homePage->Content = '<p>Welcome!</p>';
$homePage->write();
$this->assertNotEmpty($homePage->LastEditedByName);
$this->assertEquals($author->getTitle(), $homePage->LastEditedByName);
$this->assertGreaterThan(
$homePageVersion,
Versioned::get_versionnumber_by_stage(SiteTree::class, 'Stage', $homePage->ID, false)
);
DBDatetime::clear_mock_now();
}
public function testReviewActionVisibleForAuthor()
{
DBDatetime::set_mock_now('2020-03-01 12:00:00');
/** @var Page|SiteTreeContentReview $page */
$page = $this->objFromFixture(Page::class, 'contact');
/** @var Member $author */
$author = $this->objFromFixture(Member::class, 'author');
$this->logInAs($author);
$fields = $page->getCMSActions();
$this->assertInstanceOf(LiteralField::class, $fields->fieldByName('ContentReviewButton'));
DBDatetime::clear_mock_now();
}
public function testReviewActionNotVisibleForEditor()
{
DBDatetime::set_mock_now("2020-03-01 12:00:00");
/** @var Page|SiteTreeContentReview $page */
$page = $this->objFromFixture(Page::class, "contact");
/** @var Member $author */
$author = $this->objFromFixture(Member::class, "editor");
$this->logInAs($author);
$fields = $page->getCMSActions();
$this->assertNull($fields->fieldByName("ActionMenus.ReviewContent"));
DBDatetime::clear_mock_now();
}
public function testSiteConfigSettingsAreUsedAsDefaults()
{
DBDatetime::set_mock_now("2020-03-01 12:00:00");
/** @var Member $author */
$author = $this->objFromFixture(Member::class, 'editor');
/** @var SiteConfig $siteConfig */
$siteConfig = SiteConfig::current_site_config();
// Set the author to a default user for reviewing
$siteConfig->OwnerUsers()->add($author);
$emptyPage = new Page;
$emptyPage->NextReviewDate = '2020-02-20 12:00:00';
$this->assertTrue($emptyPage->canBeReviewedBy($author));
DBDatetime::clear_mock_now();
}
public function testPermissionCheckByOnDataObject()
{
$reviewer = $this->objFromFixture(Member::class, 'editor');
// Mock Page class with canReviewContent method to return true on first call and false on second call
$mock = $this->getMockBuilder(Page::class)
->setMethods(['canReviewContent', 'NextReviewDate', 'OwnerUsers'])
->getMock();
$mock->expects($this->exactly(2))->method('canReviewContent')->willReturnOnConsecutiveCalls(false, true);
$mock->method('NextReviewDate')->willReturn('2020-02-20 12:00:00');
$mock->method('OwnerUsers')->willReturn(ArrayList::create([$reviewer]));
$mock->ContentReviewType = 'Custom';
/** @var SiteTreeContentReview $extension */
$extension = Injector::inst()->get(SiteTreeContentReview::class);
$extension->setOwner($mock);
// Assert that the user is not allowed to review content
$author = $this->objFromFixture(Member::class, 'author');
$this->assertFalse($extension->canBeReviewedBy($author));
DBDatetime::set_mock_now("2020-03-01 12:00:00");
// Assert that the user is allowed to review content
$this->assertTrue($extension->canBeReviewedBy($reviewer));
// Assert tht canBeReviewedBy return true if no user logged in
// This is for CLI execution for ContentReviewEmails task
$this->logOut();
$this->assertTrue($extension->canBeReviewedBy());
DBDatetime::clear_mock_now();
}
}

54
webpack.config.js Normal file
View File

@ -0,0 +1,54 @@
const Path = require('path');
// Import the core config
const webpackConfig = require('@silverstripe/webpack-config');
const {
resolveJS,
externalJS,
moduleJS,
pluginJS,
moduleCSS,
pluginCSS,
} = webpackConfig;
const ENV = process.env.NODE_ENV;
const PATHS = {
MODULES: 'node_modules',
FILES_PATH: '../',
ROOT: Path.resolve(),
SRC: Path.resolve('client/src'),
DIST: Path.resolve('client/dist'),
THIRDPARTY: Path.resolve('thirdparty'),
};
const config = [
{
name: 'js',
entry: {
contentreview: `${PATHS.SRC}/bundles/bundle.js`,
},
output: {
path: PATHS.DIST,
filename: 'js/[name].js',
},
devtool: (ENV !== 'production') ? 'source-map' : '',
resolve: resolveJS(ENV, PATHS),
externals: externalJS(ENV, PATHS),
module: moduleJS(ENV, PATHS),
plugins: pluginJS(ENV, PATHS),
},
{
name: 'css',
entry: {
contentreview: `${PATHS.SRC}/styles/bundle.scss`,
},
output: {
path: PATHS.DIST,
filename: 'styles/[name].css'
},
devtool: (ENV !== 'production') ? 'source-map' : '',
module: moduleCSS(ENV, PATHS),
plugins: pluginCSS(ENV, PATHS),
},
];
module.exports = config;

4783
yarn.lock Normal file
View File

@ -0,0 +1,4783 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@silverstripe/webpack-config@^0.2.5":
version "0.2.9"
resolved "https://registry.yarnpkg.com/@silverstripe/webpack-config/-/webpack-config-0.2.9.tgz#45d10f576f01718023b9ee480391c67652f65ac0"
dependencies:
autoprefixer "^6.4.0"
babel-core "^6.24.1"
babel-loader "^7.0.0"
babel-plugin-transform-es2015-modules-umd "^6.6.5"
babel-plugin-transform-object-rest-spread "^6.8.0"
babel-preset-es2015 "^6.24.1"
babel-preset-es2016 "^6.24.1"
babel-preset-react "^6.24.1"
css-loader "^0.28.1"
eslint "^2.5.3"
eslint-config-airbnb "^6.2.0"
eslint-loader "^1.7.1"
eslint-plugin-react "^4.2.3"
expose-loader "^0.7.3"
extract-text-webpack-plugin "^2.1.0"
file-loader "^0.11.1"
imports-loader "^0.6.5"
json-loader "^0.5.4"
modernizr "^3.5.0"
modernizr-loader "^1.0.1"
node-sass "^4.5.3"
postcss-load-config "^1.2.0"
postcss-loader "^2.0.5"
resolve-url-loader "^2.0.2"
sass-lint "^1.9.1"
sass-loader "^6.0.5"
script-loader "^0.7.0"
url-loader "^0.5.8"
webpack "^2.6.1"
abbrev@1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
acorn-dynamic-import@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz#c752bd210bef679501b6c6cb7fc84f8f47158cc4"
dependencies:
acorn "^4.0.3"
acorn-jsx@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b"
dependencies:
acorn "^3.0.4"
acorn@^3.0.4:
version "3.3.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
acorn@^4.0.3:
version "4.0.13"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787"
acorn@^5.0.0, acorn@^5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.2.tgz#911cb53e036807cf0fa778dc5d370fbd864246d7"
adjust-sourcemap-loader@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/adjust-sourcemap-loader/-/adjust-sourcemap-loader-1.1.0.tgz#412d92404eb61e4113635012cba53a33d008e0e2"
dependencies:
assert "^1.3.0"
camelcase "^1.2.1"
loader-utils "^1.0.2"
lodash.assign "^4.0.1"
lodash.defaults "^3.1.2"
object-path "^0.9.2"
regex-parser "^2.2.1"
ajv-keywords@^1.0.0, ajv-keywords@^1.1.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
ajv@^4.7.0:
version "4.11.8"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536"
dependencies:
co "^4.6.0"
json-stable-stringify "^1.0.1"
ajv@^5.0.0:
version "5.2.2"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.2.2.tgz#47c68d69e86f5d953103b0074a9430dc63da5e39"
dependencies:
co "^4.6.0"
fast-deep-equal "^1.0.0"
json-schema-traverse "^0.3.0"
json-stable-stringify "^1.0.1"
ajv@^6.12.3:
version "6.12.6"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
dependencies:
fast-deep-equal "^3.1.1"
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
align-text@^0.1.1, align-text@^0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
dependencies:
kind-of "^3.0.2"
longest "^1.0.1"
repeat-string "^1.5.2"
alphanum-sort@^1.0.1, alphanum-sort@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"
amdefine@>=0.0.4:
version "1.0.1"
resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
ansi-escapes@^1.1.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
ansi-regex@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
ansi-regex@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
ansi-regex@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
ansi-styles@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
ansi-styles@^3.1.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88"
dependencies:
color-convert "^1.9.0"
ansi-styles@^3.2.0:
version "3.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
dependencies:
color-convert "^1.9.0"
anymatch@^1.3.0:
version "1.3.2"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a"
dependencies:
micromatch "^2.1.5"
normalize-path "^2.0.0"
aproba@^1.0.3:
version "1.2.0"
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
are-we-there-yet@~1.1.2:
version "1.1.5"
resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21"
dependencies:
delegates "^1.0.0"
readable-stream "^2.0.6"
argparse@^1.0.7:
version "1.0.9"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86"
dependencies:
sprintf-js "~1.0.2"
argparse@~0.1.15:
version "0.1.16"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-0.1.16.tgz#cfd01e0fbba3d6caed049fbd758d40f65196f57c"
dependencies:
underscore "~1.7.0"
underscore.string "~2.4.0"
arr-diff@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
dependencies:
arr-flatten "^1.0.1"
arr-flatten@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1"
array-find-index@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
array-union@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
dependencies:
array-uniq "^1.0.1"
array-uniq@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
array-unique@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
arrify@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
asap@~2.0.3:
version "2.0.6"
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
asn1.js@^4.0.0:
version "4.9.1"
resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.1.tgz#48ba240b45a9280e94748990ba597d216617fd40"
dependencies:
bn.js "^4.0.0"
inherits "^2.0.1"
minimalistic-assert "^1.0.0"
asn1@~0.2.3:
version "0.2.4"
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
dependencies:
safer-buffer "~2.1.0"
assert-plus@1.0.0, assert-plus@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
assert@^1.1.1, assert@^1.3.0:
version "1.4.1"
resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91"
dependencies:
util "0.10.3"
async-each@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
async-foreach@^0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542"
async@^2.1.2, async@^2.1.5:
version "2.6.4"
resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221"
dependencies:
lodash "^4.17.14"
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
atob@~1.1.0:
version "1.1.3"
resolved "https://registry.yarnpkg.com/atob/-/atob-1.1.3.tgz#95f13629b12c3a51a5d215abdce2aa9f32f80773"
autolinker@~0.15.0:
version "0.15.3"
resolved "https://registry.yarnpkg.com/autolinker/-/autolinker-0.15.3.tgz#342417d8f2f3461b14cf09088d5edf8791dc9832"
autoprefixer@^6.3.1, autoprefixer@^6.4.0:
version "6.7.7"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014"
dependencies:
browserslist "^1.7.6"
caniuse-db "^1.0.30000634"
normalize-range "^0.1.2"
num2fraction "^1.2.2"
postcss "^5.2.16"
postcss-value-parser "^3.2.3"
aws-sign2@~0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
aws4@^1.8.0:
version "1.11.0"
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
babel-code-frame@^6.11.0, babel-code-frame@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
dependencies:
chalk "^1.1.3"
esutils "^2.0.2"
js-tokens "^3.0.2"
babel-core@^6.24.1, babel-core@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.0.tgz#af32f78b31a6fcef119c87b0fd8d9753f03a0bb8"
dependencies:
babel-code-frame "^6.26.0"
babel-generator "^6.26.0"
babel-helpers "^6.24.1"
babel-messages "^6.23.0"
babel-register "^6.26.0"
babel-runtime "^6.26.0"
babel-template "^6.26.0"
babel-traverse "^6.26.0"
babel-types "^6.26.0"
babylon "^6.18.0"
convert-source-map "^1.5.0"
debug "^2.6.8"
json5 "^0.5.1"
lodash "^4.17.4"
minimatch "^3.0.4"
path-is-absolute "^1.0.1"
private "^0.1.7"
slash "^1.0.0"
source-map "^0.5.6"
babel-generator@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.0.tgz#ac1ae20070b79f6e3ca1d3269613053774f20dc5"
dependencies:
babel-messages "^6.23.0"
babel-runtime "^6.26.0"
babel-types "^6.26.0"
detect-indent "^4.0.0"
jsesc "^1.3.0"
lodash "^4.17.4"
source-map "^0.5.6"
trim-right "^1.0.1"
babel-helper-builder-binary-assignment-operator-visitor@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664"
dependencies:
babel-helper-explode-assignable-expression "^6.24.1"
babel-runtime "^6.22.0"
babel-types "^6.24.1"
babel-helper-builder-react-jsx@^6.24.1:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz#39ff8313b75c8b65dceff1f31d383e0ff2a408a0"
dependencies:
babel-runtime "^6.26.0"
babel-types "^6.26.0"
esutils "^2.0.2"
babel-helper-call-delegate@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d"
dependencies:
babel-helper-hoist-variables "^6.24.1"
babel-runtime "^6.22.0"
babel-traverse "^6.24.1"
babel-types "^6.24.1"
babel-helper-define-map@^6.24.1:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f"
dependencies:
babel-helper-function-name "^6.24.1"
babel-runtime "^6.26.0"
babel-types "^6.26.0"
lodash "^4.17.4"
babel-helper-explode-assignable-expression@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa"
dependencies:
babel-runtime "^6.22.0"
babel-traverse "^6.24.1"
babel-types "^6.24.1"
babel-helper-function-name@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9"
dependencies:
babel-helper-get-function-arity "^6.24.1"
babel-runtime "^6.22.0"
babel-template "^6.24.1"
babel-traverse "^6.24.1"
babel-types "^6.24.1"
babel-helper-get-function-arity@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d"
dependencies:
babel-runtime "^6.22.0"
babel-types "^6.24.1"
babel-helper-hoist-variables@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76"
dependencies:
babel-runtime "^6.22.0"
babel-types "^6.24.1"
babel-helper-optimise-call-expression@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257"
dependencies:
babel-runtime "^6.22.0"
babel-types "^6.24.1"
babel-helper-regex@^6.24.1:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72"
dependencies:
babel-runtime "^6.26.0"
babel-types "^6.26.0"
lodash "^4.17.4"
babel-helper-replace-supers@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a"
dependencies:
babel-helper-optimise-call-expression "^6.24.1"
babel-messages "^6.23.0"
babel-runtime "^6.22.0"
babel-template "^6.24.1"
babel-traverse "^6.24.1"
babel-types "^6.24.1"
babel-helpers@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2"
dependencies:
babel-runtime "^6.22.0"
babel-template "^6.24.1"
babel-loader@^7.0.0:
version "7.1.2"
resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-7.1.2.tgz#f6cbe122710f1aa2af4d881c6d5b54358ca24126"
dependencies:
find-cache-dir "^1.0.0"
loader-utils "^1.0.2"
mkdirp "^0.5.1"
babel-messages@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e"
dependencies:
babel-runtime "^6.22.0"
babel-plugin-check-es2015-constants@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a"
dependencies:
babel-runtime "^6.22.0"
babel-plugin-syntax-exponentiation-operator@^6.8.0:
version "6.13.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de"
babel-plugin-syntax-flow@^6.18.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d"
babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946"
babel-plugin-syntax-object-rest-spread@^6.8.0:
version "6.13.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5"
babel-plugin-transform-es2015-arrow-functions@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221"
dependencies:
babel-runtime "^6.22.0"
babel-plugin-transform-es2015-block-scoped-functions@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141"
dependencies:
babel-runtime "^6.22.0"
babel-plugin-transform-es2015-block-scoping@^6.24.1:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f"
dependencies:
babel-runtime "^6.26.0"
babel-template "^6.26.0"
babel-traverse "^6.26.0"
babel-types "^6.26.0"
lodash "^4.17.4"
babel-plugin-transform-es2015-classes@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db"
dependencies:
babel-helper-define-map "^6.24.1"
babel-helper-function-name "^6.24.1"
babel-helper-optimise-call-expression "^6.24.1"
babel-helper-replace-supers "^6.24.1"
babel-messages "^6.23.0"
babel-runtime "^6.22.0"
babel-template "^6.24.1"
babel-traverse "^6.24.1"
babel-types "^6.24.1"
babel-plugin-transform-es2015-computed-properties@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3"
dependencies:
babel-runtime "^6.22.0"
babel-template "^6.24.1"
babel-plugin-transform-es2015-destructuring@^6.22.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d"
dependencies:
babel-runtime "^6.22.0"
babel-plugin-transform-es2015-duplicate-keys@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e"
dependencies:
babel-runtime "^6.22.0"
babel-types "^6.24.1"
babel-plugin-transform-es2015-for-of@^6.22.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691"
dependencies:
babel-runtime "^6.22.0"
babel-plugin-transform-es2015-function-name@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b"
dependencies:
babel-helper-function-name "^6.24.1"
babel-runtime "^6.22.0"
babel-types "^6.24.1"
babel-plugin-transform-es2015-literals@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e"
dependencies:
babel-runtime "^6.22.0"
babel-plugin-transform-es2015-modules-amd@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154"
dependencies:
babel-plugin-transform-es2015-modules-commonjs "^6.24.1"
babel-runtime "^6.22.0"
babel-template "^6.24.1"
babel-plugin-transform-es2015-modules-commonjs@^6.24.1:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz#0d8394029b7dc6abe1a97ef181e00758dd2e5d8a"
dependencies:
babel-plugin-transform-strict-mode "^6.24.1"
babel-runtime "^6.26.0"
babel-template "^6.26.0"
babel-types "^6.26.0"
babel-plugin-transform-es2015-modules-systemjs@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23"
dependencies:
babel-helper-hoist-variables "^6.24.1"
babel-runtime "^6.22.0"
babel-template "^6.24.1"
babel-plugin-transform-es2015-modules-umd@^6.24.1, babel-plugin-transform-es2015-modules-umd@^6.6.5:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468"
dependencies:
babel-plugin-transform-es2015-modules-amd "^6.24.1"
babel-runtime "^6.22.0"
babel-template "^6.24.1"
babel-plugin-transform-es2015-object-super@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d"
dependencies:
babel-helper-replace-supers "^6.24.1"
babel-runtime "^6.22.0"
babel-plugin-transform-es2015-parameters@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b"
dependencies:
babel-helper-call-delegate "^6.24.1"
babel-helper-get-function-arity "^6.24.1"
babel-runtime "^6.22.0"
babel-template "^6.24.1"
babel-traverse "^6.24.1"
babel-types "^6.24.1"
babel-plugin-transform-es2015-shorthand-properties@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0"
dependencies:
babel-runtime "^6.22.0"
babel-types "^6.24.1"
babel-plugin-transform-es2015-spread@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1"
dependencies:
babel-runtime "^6.22.0"
babel-plugin-transform-es2015-sticky-regex@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc"
dependencies:
babel-helper-regex "^6.24.1"
babel-runtime "^6.22.0"
babel-types "^6.24.1"
babel-plugin-transform-es2015-template-literals@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d"
dependencies:
babel-runtime "^6.22.0"
babel-plugin-transform-es2015-typeof-symbol@^6.22.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372"
dependencies:
babel-runtime "^6.22.0"
babel-plugin-transform-es2015-unicode-regex@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9"
dependencies:
babel-helper-regex "^6.24.1"
babel-runtime "^6.22.0"
regexpu-core "^2.0.0"
babel-plugin-transform-exponentiation-operator@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e"
dependencies:
babel-helper-builder-binary-assignment-operator-visitor "^6.24.1"
babel-plugin-syntax-exponentiation-operator "^6.8.0"
babel-runtime "^6.22.0"
babel-plugin-transform-flow-strip-types@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz#84cb672935d43714fdc32bce84568d87441cf7cf"
dependencies:
babel-plugin-syntax-flow "^6.18.0"
babel-runtime "^6.22.0"
babel-plugin-transform-object-rest-spread@^6.8.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06"
dependencies:
babel-plugin-syntax-object-rest-spread "^6.8.0"
babel-runtime "^6.26.0"
babel-plugin-transform-react-display-name@^6.23.0:
version "6.25.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.25.0.tgz#67e2bf1f1e9c93ab08db96792e05392bf2cc28d1"
dependencies:
babel-runtime "^6.22.0"
babel-plugin-transform-react-jsx-self@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz#df6d80a9da2612a121e6ddd7558bcbecf06e636e"
dependencies:
babel-plugin-syntax-jsx "^6.8.0"
babel-runtime "^6.22.0"
babel-plugin-transform-react-jsx-source@^6.22.0:
version "6.22.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz#66ac12153f5cd2d17b3c19268f4bf0197f44ecd6"
dependencies:
babel-plugin-syntax-jsx "^6.8.0"
babel-runtime "^6.22.0"
babel-plugin-transform-react-jsx@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz#840a028e7df460dfc3a2d29f0c0d91f6376e66a3"
dependencies:
babel-helper-builder-react-jsx "^6.24.1"
babel-plugin-syntax-jsx "^6.8.0"
babel-runtime "^6.22.0"
babel-plugin-transform-regenerator@^6.24.1:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f"
dependencies:
regenerator-transform "^0.10.0"
babel-plugin-transform-strict-mode@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758"
dependencies:
babel-runtime "^6.22.0"
babel-types "^6.24.1"
babel-preset-es2015@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz#d44050d6bc2c9feea702aaf38d727a0210538939"
dependencies:
babel-plugin-check-es2015-constants "^6.22.0"
babel-plugin-transform-es2015-arrow-functions "^6.22.0"
babel-plugin-transform-es2015-block-scoped-functions "^6.22.0"
babel-plugin-transform-es2015-block-scoping "^6.24.1"
babel-plugin-transform-es2015-classes "^6.24.1"
babel-plugin-transform-es2015-computed-properties "^6.24.1"
babel-plugin-transform-es2015-destructuring "^6.22.0"
babel-plugin-transform-es2015-duplicate-keys "^6.24.1"
babel-plugin-transform-es2015-for-of "^6.22.0"
babel-plugin-transform-es2015-function-name "^6.24.1"
babel-plugin-transform-es2015-literals "^6.22.0"
babel-plugin-transform-es2015-modules-amd "^6.24.1"
babel-plugin-transform-es2015-modules-commonjs "^6.24.1"
babel-plugin-transform-es2015-modules-systemjs "^6.24.1"
babel-plugin-transform-es2015-modules-umd "^6.24.1"
babel-plugin-transform-es2015-object-super "^6.24.1"
babel-plugin-transform-es2015-parameters "^6.24.1"
babel-plugin-transform-es2015-shorthand-properties "^6.24.1"
babel-plugin-transform-es2015-spread "^6.22.0"
babel-plugin-transform-es2015-sticky-regex "^6.24.1"
babel-plugin-transform-es2015-template-literals "^6.22.0"
babel-plugin-transform-es2015-typeof-symbol "^6.22.0"
babel-plugin-transform-es2015-unicode-regex "^6.24.1"
babel-plugin-transform-regenerator "^6.24.1"
babel-preset-es2016@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-preset-es2016/-/babel-preset-es2016-6.24.1.tgz#f900bf93e2ebc0d276df9b8ab59724ebfd959f8b"
dependencies:
babel-plugin-transform-exponentiation-operator "^6.24.1"
babel-preset-flow@^6.23.0:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz#e71218887085ae9a24b5be4169affb599816c49d"
dependencies:
babel-plugin-transform-flow-strip-types "^6.22.0"
babel-preset-react@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-preset-react/-/babel-preset-react-6.24.1.tgz#ba69dfaea45fc3ec639b6a4ecea6e17702c91380"
dependencies:
babel-plugin-syntax-jsx "^6.3.13"
babel-plugin-transform-react-display-name "^6.23.0"
babel-plugin-transform-react-jsx "^6.24.1"
babel-plugin-transform-react-jsx-self "^6.22.0"
babel-plugin-transform-react-jsx-source "^6.22.0"
babel-preset-flow "^6.23.0"
babel-register@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071"
dependencies:
babel-core "^6.26.0"
babel-runtime "^6.26.0"
core-js "^2.5.0"
home-or-tmp "^2.0.0"
lodash "^4.17.4"
mkdirp "^0.5.1"
source-map-support "^0.4.15"
babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
dependencies:
core-js "^2.4.0"
regenerator-runtime "^0.11.0"
babel-template@^6.24.1, babel-template@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02"
dependencies:
babel-runtime "^6.26.0"
babel-traverse "^6.26.0"
babel-types "^6.26.0"
babylon "^6.18.0"
lodash "^4.17.4"
babel-traverse@^6.24.1, babel-traverse@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee"
dependencies:
babel-code-frame "^6.26.0"
babel-messages "^6.23.0"
babel-runtime "^6.26.0"
babel-types "^6.26.0"
babylon "^6.18.0"
debug "^2.6.8"
globals "^9.18.0"
invariant "^2.2.2"
lodash "^4.17.4"
babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497"
dependencies:
babel-runtime "^6.26.0"
esutils "^2.0.2"
lodash "^4.17.4"
to-fast-properties "^1.0.3"
babylon@^6.18.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3"
balanced-match@^0.4.2:
version "0.4.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
balanced-match@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
base64-js@^1.0.2:
version "1.2.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886"
bcrypt-pbkdf@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
dependencies:
tweetnacl "^0.14.3"
big.js@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978"
binary-extensions@^1.0.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.10.0.tgz#9aeb9a6c5e88638aad171e167f5900abe24835d0"
block-stream@*:
version "0.0.9"
resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
dependencies:
inherits "~2.0.0"
bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.11.9:
version "4.12.0"
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88"
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
dependencies:
balanced-match "^1.0.0"
concat-map "0.0.1"
braces@^1.8.2:
version "1.8.5"
resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
dependencies:
expand-range "^1.8.1"
preserve "^0.2.0"
repeat-element "^1.1.2"
brorand@^1.0.1, brorand@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
browserify-aes@^1.0.0, browserify-aes@^1.0.4:
version "1.0.8"
resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.0.8.tgz#c8fa3b1b7585bb7ba77c5560b60996ddec6d5309"
dependencies:
buffer-xor "^1.0.3"
cipher-base "^1.0.0"
create-hash "^1.1.0"
evp_bytestokey "^1.0.3"
inherits "^2.0.1"
safe-buffer "^5.0.1"
browserify-cipher@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.0.tgz#9988244874bf5ed4e28da95666dcd66ac8fc363a"
dependencies:
browserify-aes "^1.0.4"
browserify-des "^1.0.0"
evp_bytestokey "^1.0.0"
browserify-des@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.0.tgz#daa277717470922ed2fe18594118a175439721dd"
dependencies:
cipher-base "^1.0.1"
des.js "^1.0.0"
inherits "^2.0.1"
browserify-rsa@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524"
dependencies:
bn.js "^4.1.0"
randombytes "^2.0.1"
browserify-sign@^4.0.0:
version "4.0.4"
resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298"
dependencies:
bn.js "^4.1.1"
browserify-rsa "^4.0.0"
create-hash "^1.1.0"
create-hmac "^1.1.2"
elliptic "^6.0.0"
inherits "^2.0.1"
parse-asn1 "^5.0.0"
browserify-zlib@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d"
dependencies:
pako "~0.2.0"
browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6:
version "1.7.7"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9"
dependencies:
caniuse-db "^1.0.30000639"
electron-to-chromium "^1.2.7"
buffer-xor@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9"
buffer@^4.3.0:
version "4.9.1"
resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298"
dependencies:
base64-js "^1.0.2"
ieee754 "^1.1.4"
isarray "^1.0.0"
builtin-status-codes@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
caller-path@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f"
dependencies:
callsites "^0.2.0"
callsites@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca"
camelcase-keys@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7"
dependencies:
camelcase "^2.0.0"
map-obj "^1.0.0"
camelcase@^1.0.2, camelcase@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
camelcase@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
camelcase@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
camelcase@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
camelcase@^5.0.0:
version "5.3.1"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
caniuse-api@^1.5.2:
version "1.6.1"
resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.6.1.tgz#b534e7c734c4f81ec5fbe8aca2ad24354b962c6c"
dependencies:
browserslist "^1.3.6"
caniuse-db "^1.0.30000529"
lodash.memoize "^4.1.2"
lodash.uniq "^4.5.0"
caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
version "1.0.30000726"
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000726.tgz#9bb742f8d026a62df873bc03c06843d2255b60d7"
caseless@~0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
center-align@^0.1.1:
version "0.1.3"
resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad"
dependencies:
align-text "^0.1.3"
lazy-cache "^1.0.3"
chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
dependencies:
ansi-styles "^2.2.1"
escape-string-regexp "^1.0.2"
has-ansi "^2.0.0"
strip-ansi "^3.0.0"
supports-color "^2.0.0"
chalk@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.1.0.tgz#ac5becf14fa21b99c6c92ca7a7d7cfd5b17e743e"
dependencies:
ansi-styles "^3.1.0"
escape-string-regexp "^1.0.5"
supports-color "^4.0.0"
chokidar@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
dependencies:
anymatch "^1.3.0"
async-each "^1.0.0"
glob-parent "^2.0.0"
inherits "^2.0.1"
is-binary-path "^1.0.0"
is-glob "^2.0.0"
path-is-absolute "^1.0.0"
readdirp "^2.0.0"
optionalDependencies:
fsevents "^1.0.0"
cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de"
dependencies:
inherits "^2.0.1"
safe-buffer "^5.0.1"
circular-json@^0.3.1:
version "0.3.3"
resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66"
clap@^1.0.9:
version "1.2.0"
resolved "https://registry.yarnpkg.com/clap/-/clap-1.2.0.tgz#59c90fe3e137104746ff19469a27a634ff68c857"
dependencies:
chalk "^1.1.3"
cli-cursor@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987"
dependencies:
restore-cursor "^1.0.1"
cli-width@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639"
cliui@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
dependencies:
center-align "^0.1.1"
right-align "^0.1.1"
wordwrap "0.0.2"
cliui@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
dependencies:
string-width "^1.0.1"
strip-ansi "^3.0.1"
wrap-ansi "^2.0.0"
cliui@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5"
dependencies:
string-width "^3.1.0"
strip-ansi "^5.2.0"
wrap-ansi "^5.1.0"
clone-deep@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-0.3.0.tgz#348c61ae9cdbe0edfe053d91ff4cc521d790ede8"
dependencies:
for-own "^1.0.0"
is-plain-object "^2.0.1"
kind-of "^3.2.2"
shallow-clone "^0.1.2"
clone@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149"
co@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
coa@~1.0.1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/coa/-/coa-1.0.4.tgz#a9ef153660d6a86a8bdec0289a5c684d217432fd"
dependencies:
q "^1.1.2"
code-point-at@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
color-convert@^1.3.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a"
dependencies:
color-name "^1.1.1"
color-convert@^1.9.0:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
dependencies:
color-name "1.1.3"
color-name@1.1.3, color-name@^1.0.0, color-name@^1.1.1:
version "1.1.3"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
color-string@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/color-string/-/color-string-0.3.0.tgz#27d46fb67025c5c2fa25993bfbf579e47841b991"
dependencies:
color-name "^1.0.0"
color@^0.11.0:
version "0.11.4"
resolved "https://registry.yarnpkg.com/color/-/color-0.11.4.tgz#6d7b5c74fb65e841cd48792ad1ed5e07b904d764"
dependencies:
clone "^1.0.2"
color-convert "^1.3.0"
color-string "^0.3.0"
colormin@^1.0.5:
version "1.1.2"
resolved "https://registry.yarnpkg.com/colormin/-/colormin-1.1.2.tgz#ea2f7420a72b96881a38aae59ec124a6f7298133"
dependencies:
color "^0.11.0"
css-color-names "0.0.4"
has "^1.0.1"
colors@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63"
combined-stream@^1.0.6, combined-stream@~1.0.6:
version "1.0.8"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
dependencies:
delayed-stream "~1.0.0"
commander@^2.8.1:
version "2.11.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563"
commondir@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
concat-stream@^1.4.6:
version "1.6.0"
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7"
dependencies:
inherits "^2.0.3"
readable-stream "^2.2.2"
typedarray "^0.0.6"
console-browserify@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10"
dependencies:
date-now "^0.1.4"
console-control-strings@^1.0.0, console-control-strings@~1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
constants-browserify@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
convert-source-map@^0.3.3:
version "0.3.5"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-0.3.5.tgz#f1d802950af7dd2631a1febe0596550c86ab3190"
convert-source-map@^1.1.1, convert-source-map@^1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5"
core-js@^1.0.0:
version "1.2.7"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
core-js@^2.4.0, core-js@^2.5.0:
version "2.5.1"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.1.tgz#ae6874dc66937789b80754ff5428df66819ca50b"
core-util-is@1.0.2, core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
cosmiconfig@^2.1.0, cosmiconfig@^2.1.1:
version "2.2.2"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-2.2.2.tgz#6173cebd56fac042c1f4390edf7af6c07c7cb892"
dependencies:
is-directory "^0.3.1"
js-yaml "^3.4.3"
minimist "^1.2.0"
object-assign "^4.1.0"
os-homedir "^1.0.1"
parse-json "^2.2.0"
require-from-string "^1.1.0"
create-ecdh@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d"
dependencies:
bn.js "^4.1.0"
elliptic "^6.0.0"
create-hash@^1.1.0, create-hash@^1.1.2:
version "1.1.3"
resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd"
dependencies:
cipher-base "^1.0.1"
inherits "^2.0.1"
ripemd160 "^2.0.0"
sha.js "^2.4.0"
create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
version "1.1.6"
resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.6.tgz#acb9e221a4e17bdb076e90657c42b93e3726cf06"
dependencies:
cipher-base "^1.0.3"
create-hash "^1.1.0"
inherits "^2.0.1"
ripemd160 "^2.0.0"
safe-buffer "^5.0.1"
sha.js "^2.4.8"
create-react-class@^15.5.1:
version "15.6.0"
resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.6.0.tgz#ab448497c26566e1e29413e883207d57cfe7bed4"
dependencies:
fbjs "^0.8.9"
loose-envify "^1.3.1"
object-assign "^4.1.1"
cross-spawn@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982"
dependencies:
lru-cache "^4.0.1"
which "^1.2.9"
crypto-browserify@^3.11.0:
version "3.11.1"
resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.1.tgz#948945efc6757a400d6e5e5af47194d10064279f"
dependencies:
browserify-cipher "^1.0.0"
browserify-sign "^4.0.0"
create-ecdh "^4.0.0"
create-hash "^1.1.0"
create-hmac "^1.1.0"
diffie-hellman "^5.0.0"
inherits "^2.0.1"
pbkdf2 "^3.0.3"
public-encrypt "^4.0.0"
randombytes "^2.0.0"
css-color-names@0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
css-loader@^0.28.1:
version "0.28.7"
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.28.7.tgz#5f2ee989dd32edd907717f953317656160999c1b"
dependencies:
babel-code-frame "^6.11.0"
css-selector-tokenizer "^0.7.0"
cssnano ">=2.6.1 <4"
icss-utils "^2.1.0"
loader-utils "^1.0.2"
lodash.camelcase "^4.3.0"
object-assign "^4.0.1"
postcss "^5.0.6"
postcss-modules-extract-imports "^1.0.0"
postcss-modules-local-by-default "^1.0.1"
postcss-modules-scope "^1.0.0"
postcss-modules-values "^1.1.0"
postcss-value-parser "^3.3.0"
source-list-map "^2.0.0"
css-selector-tokenizer@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz#e6988474ae8c953477bf5e7efecfceccd9cf4c86"
dependencies:
cssesc "^0.1.0"
fastparse "^1.1.1"
regexpu-core "^1.0.0"
css@^2.0.0:
version "2.2.1"
resolved "https://registry.yarnpkg.com/css/-/css-2.2.1.tgz#73a4c81de85db664d4ee674f7d47085e3b2d55dc"
dependencies:
inherits "^2.0.1"
source-map "^0.1.38"
source-map-resolve "^0.3.0"
urix "^0.1.0"
cssesc@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4"
"cssnano@>=2.6.1 <4":
version "3.10.0"
resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-3.10.0.tgz#4f38f6cea2b9b17fa01490f23f1dc68ea65c1c38"
dependencies:
autoprefixer "^6.3.1"
decamelize "^1.1.2"
defined "^1.0.0"
has "^1.0.1"
object-assign "^4.0.1"
postcss "^5.0.14"
postcss-calc "^5.2.0"
postcss-colormin "^2.1.8"
postcss-convert-values "^2.3.4"
postcss-discard-comments "^2.0.4"
postcss-discard-duplicates "^2.0.1"
postcss-discard-empty "^2.0.1"
postcss-discard-overridden "^0.1.1"
postcss-discard-unused "^2.2.1"
postcss-filter-plugins "^2.0.0"
postcss-merge-idents "^2.1.5"
postcss-merge-longhand "^2.0.1"
postcss-merge-rules "^2.0.3"
postcss-minify-font-values "^1.0.2"
postcss-minify-gradients "^1.0.1"
postcss-minify-params "^1.0.4"
postcss-minify-selectors "^2.0.4"
postcss-normalize-charset "^1.1.0"
postcss-normalize-url "^3.0.7"
postcss-ordered-values "^2.1.0"
postcss-reduce-idents "^2.2.2"
postcss-reduce-initial "^1.0.0"
postcss-reduce-transforms "^1.0.3"
postcss-svgo "^2.1.1"
postcss-unique-selectors "^2.0.2"
postcss-value-parser "^3.2.3"
postcss-zindex "^2.0.1"
csso@~2.3.1:
version "2.3.2"
resolved "https://registry.yarnpkg.com/csso/-/csso-2.3.2.tgz#ddd52c587033f49e94b71fc55569f252e8ff5f85"
dependencies:
clap "^1.0.9"
source-map "^0.5.3"
currently-unhandled@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
dependencies:
array-find-index "^1.0.1"
d@1:
version "1.0.0"
resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f"
dependencies:
es5-ext "^0.10.9"
dashdash@^1.12.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
dependencies:
assert-plus "^1.0.0"
date-now@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
debug@^2.1.1, debug@^2.2.0, debug@^2.6.8:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
dependencies:
ms "2.0.0"
decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
deep-extend@~0.4.0:
version "0.4.2"
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f"
deep-is@~0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
defined@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
del@^2.0.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8"
dependencies:
globby "^5.0.0"
is-path-cwd "^1.0.0"
is-path-in-cwd "^1.0.0"
object-assign "^4.0.1"
pify "^2.0.0"
pinkie-promise "^2.0.0"
rimraf "^2.2.8"
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
delegates@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
des.js@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc"
dependencies:
inherits "^2.0.1"
minimalistic-assert "^1.0.0"
detect-indent@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208"
dependencies:
repeating "^2.0.0"
diffie-hellman@^5.0.0:
version "5.0.2"
resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e"
dependencies:
bn.js "^4.1.0"
miller-rabin "^4.0.0"
randombytes "^2.0.0"
doctrine@1.2.3:
version "1.2.3"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.2.3.tgz#6aec6bbd62cf89dd498cae70c0ed9f49da873a6a"
dependencies:
esutils "^2.0.2"
isarray "^1.0.0"
doctrine@^1.2.2:
version "1.5.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa"
dependencies:
esutils "^2.0.2"
isarray "^1.0.0"
domain-browser@^1.1.1:
version "1.1.7"
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc"
ecc-jsbn@~0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
dependencies:
jsbn "~0.1.0"
safer-buffer "^2.1.0"
electron-to-chromium@^1.2.7:
version "1.3.20"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.20.tgz#2eedd5ccbae7ddc557f68ad1fce9c172e915e4e5"
elliptic@^6.0.0:
version "6.5.4"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb"
dependencies:
bn.js "^4.11.9"
brorand "^1.1.0"
hash.js "^1.0.0"
hmac-drbg "^1.0.1"
inherits "^2.0.4"
minimalistic-assert "^1.0.1"
minimalistic-crypto-utils "^1.0.1"
emoji-regex@^7.0.1:
version "7.0.3"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
emojis-list@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
encoding@^0.1.11:
version "0.1.12"
resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
dependencies:
iconv-lite "~0.4.13"
enhanced-resolve@^3.3.0:
version "3.4.1"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz#0421e339fd71419b3da13d129b3979040230476e"
dependencies:
graceful-fs "^4.1.2"
memory-fs "^0.4.0"
object-assign "^4.0.1"
tapable "^0.2.7"
errno@^0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d"
dependencies:
prr "~0.0.0"
error-ex@^1.2.0:
version "1.3.2"
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
dependencies:
is-arrayish "^0.2.1"
es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14:
version "0.10.30"
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.30.tgz#7141a16836697dbabfaaaeee41495ce29f52c939"
dependencies:
es6-iterator "2"
es6-symbol "~3.1"
es6-iterator@2, es6-iterator@^2.0.1, es6-iterator@~2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.1.tgz#8e319c9f0453bf575d374940a655920e59ca5512"
dependencies:
d "1"
es5-ext "^0.10.14"
es6-symbol "^3.1"
es6-map@^0.1.3:
version "0.1.5"
resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0"
dependencies:
d "1"
es5-ext "~0.10.14"
es6-iterator "~2.0.1"
es6-set "~0.1.5"
es6-symbol "~3.1.1"
event-emitter "~0.3.5"
es6-set@~0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1"
dependencies:
d "1"
es5-ext "~0.10.14"
es6-iterator "~2.0.1"
es6-symbol "3.1.1"
event-emitter "~0.3.5"
es6-symbol@3.1.1, es6-symbol@^3.1, es6-symbol@^3.1.1, es6-symbol@~3.1, es6-symbol@~3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77"
dependencies:
d "1"
es5-ext "~0.10.14"
es6-weak-map@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f"
dependencies:
d "1"
es5-ext "^0.10.14"
es6-iterator "^2.0.1"
es6-symbol "^3.1.1"
escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
escope@^3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3"
dependencies:
es6-map "^0.1.3"
es6-weak-map "^2.0.1"
esrecurse "^4.1.0"
estraverse "^4.1.1"
eslint-config-airbnb@^6.2.0:
version "6.2.0"
resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-6.2.0.tgz#4a28196aa4617de01b8c914e992a82e5d0886a6e"
eslint-loader@^1.7.1:
version "1.9.0"
resolved "https://registry.yarnpkg.com/eslint-loader/-/eslint-loader-1.9.0.tgz#7e1be9feddca328d3dcfaef1ad49d5beffe83a13"
dependencies:
loader-fs-cache "^1.0.0"
loader-utils "^1.0.2"
object-assign "^4.0.1"
object-hash "^1.1.4"
rimraf "^2.6.1"
eslint-plugin-react@^4.2.3:
version "4.3.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-4.3.0.tgz#c79aac8069d62de27887c13b8298d592088de378"
eslint@^2.5.3, eslint@^2.7.0:
version "2.13.1"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-2.13.1.tgz#e4cc8fa0f009fb829aaae23855a29360be1f6c11"
dependencies:
chalk "^1.1.3"
concat-stream "^1.4.6"
debug "^2.1.1"
doctrine "^1.2.2"
es6-map "^0.1.3"
escope "^3.6.0"
espree "^3.1.6"
estraverse "^4.2.0"
esutils "^2.0.2"
file-entry-cache "^1.1.1"
glob "^7.0.3"
globals "^9.2.0"
ignore "^3.1.2"
imurmurhash "^0.1.4"
inquirer "^0.12.0"
is-my-json-valid "^2.10.0"
is-resolvable "^1.0.0"
js-yaml "^3.5.1"
json-stable-stringify "^1.0.0"
levn "^0.3.0"
lodash "^4.0.0"
mkdirp "^0.5.0"
optionator "^0.8.1"
path-is-absolute "^1.0.0"
path-is-inside "^1.0.1"
pluralize "^1.2.1"
progress "^1.1.8"
require-uncached "^1.0.2"
shelljs "^0.6.0"
strip-json-comments "~1.0.1"
table "^3.7.8"
text-table "~0.2.0"
user-home "^2.0.0"
espree@^3.1.6:
version "3.5.0"
resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.0.tgz#98358625bdd055861ea27e2867ea729faf463d8d"
dependencies:
acorn "^5.1.1"
acorn-jsx "^3.0.0"
esprima@^2.6.0:
version "2.7.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
esprima@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804"
esrecurse@^4.1.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163"
dependencies:
estraverse "^4.1.0"
object-assign "^4.0.1"
estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13"
esutils@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
event-emitter@~0.3.5:
version "0.3.5"
resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39"
dependencies:
d "1"
es5-ext "~0.10.14"
events@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02"
dependencies:
md5.js "^1.3.4"
safe-buffer "^5.1.1"
exit-hook@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8"
expand-brackets@^0.1.4:
version "0.1.5"
resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
dependencies:
is-posix-bracket "^0.1.0"
expand-range@^1.8.1:
version "1.8.2"
resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337"
dependencies:
fill-range "^2.1.0"
expose-loader@^0.7.3:
version "0.7.3"
resolved "https://registry.yarnpkg.com/expose-loader/-/expose-loader-0.7.3.tgz#35fbd3659789e4faa81f59de8b7e9fc39e466d51"
extend@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
extglob@^0.3.1:
version "0.3.2"
resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
dependencies:
is-extglob "^1.0.0"
extract-text-webpack-plugin@^2.1.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/extract-text-webpack-plugin/-/extract-text-webpack-plugin-2.1.2.tgz#756ef4efa8155c3681833fbc34da53b941746d6c"
dependencies:
async "^2.1.2"
loader-utils "^1.0.2"
schema-utils "^0.3.0"
webpack-sources "^1.0.1"
extsprintf@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
extsprintf@^1.2.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
fast-deep-equal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff"
fast-deep-equal@^3.1.1:
version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
fast-json-stable-stringify@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
fast-levenshtein@~2.0.4:
version "2.0.6"
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
fastparse@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8"
fbjs@^0.8.4, fbjs@^0.8.9:
version "0.8.15"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.15.tgz#4f0695fdfcc16c37c0b07facec8cb4c4091685b9"
dependencies:
core-js "^1.0.0"
isomorphic-fetch "^2.1.1"
loose-envify "^1.0.0"
object-assign "^4.1.0"
promise "^7.1.1"
setimmediate "^1.0.5"
ua-parser-js "^0.7.9"
figures@^1.3.5:
version "1.7.0"
resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e"
dependencies:
escape-string-regexp "^1.0.5"
object-assign "^4.1.0"
file-entry-cache@^1.1.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-1.3.1.tgz#44c61ea607ae4be9c1402f41f44270cbfe334ff8"
dependencies:
flat-cache "^1.2.1"
object-assign "^4.0.1"
file-loader@^0.11.1:
version "0.11.2"
resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-0.11.2.tgz#4ff1df28af38719a6098093b88c82c71d1794a34"
dependencies:
loader-utils "^1.0.2"
file@0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/file/-/file-0.2.2.tgz#c3dfd8f8cf3535ae455c2b423c2e52635d76b4d3"
filename-regex@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
fill-range@^2.1.0:
version "2.2.3"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723"
dependencies:
is-number "^2.1.0"
isobject "^2.0.0"
randomatic "^1.1.3"
repeat-element "^1.1.2"
repeat-string "^1.5.2"
find-cache-dir@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-0.1.1.tgz#c8defae57c8a52a8a784f9e31c57c742e993a0b9"
dependencies:
commondir "^1.0.1"
mkdirp "^0.5.1"
pkg-dir "^1.0.0"
find-cache-dir@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f"
dependencies:
commondir "^1.0.1"
make-dir "^1.0.0"
pkg-dir "^2.0.0"
find-parent-dir@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/find-parent-dir/-/find-parent-dir-0.3.0.tgz#33c44b429ab2b2f0646299c5f9f718f376ff8d54"
find-up@^1.0.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
dependencies:
path-exists "^2.0.0"
pinkie-promise "^2.0.0"
find-up@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
dependencies:
locate-path "^2.0.0"
find-up@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
dependencies:
locate-path "^3.0.0"
flat-cache@^1.2.1:
version "1.2.2"
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96"
dependencies:
circular-json "^0.3.1"
del "^2.0.2"
graceful-fs "^4.1.2"
write "^0.2.1"
flatten@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
for-in@^0.1.3:
version "0.1.8"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1"
for-in@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
for-own@^0.1.4:
version "0.1.5"
resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce"
dependencies:
for-in "^1.0.1"
for-own@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b"
dependencies:
for-in "^1.0.1"
forever-agent@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
form-data@~2.3.2:
version "2.3.3"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.6"
mime-types "^2.1.12"
front-matter@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/front-matter/-/front-matter-2.1.2.tgz#f75983b9f2f413be658c93dfd7bd8ce4078f5cdb"
dependencies:
js-yaml "^3.4.6"
fs-extra@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-3.0.1.tgz#3794f378c58b342ea7dbbb23095109c4b3b62291"
dependencies:
graceful-fs "^4.1.2"
jsonfile "^3.0.0"
universalify "^0.1.0"
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
fsevents@^1.0.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.2.tgz#3282b713fb3ad80ede0e9fcf4611b5aa6fc033f4"
dependencies:
nan "^2.3.0"
node-pre-gyp "^0.6.36"
fstream-ignore@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105"
dependencies:
fstream "^1.0.0"
inherits "2"
minimatch "^3.0.0"
fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.12:
version "1.0.12"
resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045"
dependencies:
graceful-fs "^4.1.2"
inherits "~2.0.0"
mkdirp ">=0.5 0"
rimraf "2"
function-bind@^1.0.2, function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
gauge@~2.7.3:
version "2.7.4"
resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
dependencies:
aproba "^1.0.3"
console-control-strings "^1.0.0"
has-unicode "^2.0.0"
object-assign "^4.1.0"
signal-exit "^3.0.0"
string-width "^1.0.1"
strip-ansi "^3.0.1"
wide-align "^1.1.0"
gaze@^1.0.0:
version "1.1.3"
resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a"
dependencies:
globule "^1.0.0"
generate-function@^2.0.0:
version "2.3.1"
resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f"
dependencies:
is-property "^1.0.2"
generate-object-property@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0"
dependencies:
is-property "^1.0.0"
get-caller-file@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
get-caller-file@^2.0.1:
version "2.0.5"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
get-stdin@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
getpass@^0.1.1:
version "0.1.7"
resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
dependencies:
assert-plus "^1.0.0"
glob-base@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
dependencies:
glob-parent "^2.0.0"
is-glob "^2.0.0"
glob-parent@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28"
dependencies:
is-glob "^2.0.0"
glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.2, glob@^7.1.3, glob@~7.1.1:
version "7.1.7"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90"
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
globals@^9.18.0, globals@^9.2.0:
version "9.18.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a"
globby@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d"
dependencies:
array-union "^1.0.1"
arrify "^1.0.0"
glob "^7.0.3"
object-assign "^4.0.1"
pify "^2.0.0"
pinkie-promise "^2.0.0"
globule@^1.0.0:
version "1.3.2"
resolved "https://registry.yarnpkg.com/globule/-/globule-1.3.2.tgz#d8bdd9e9e4eef8f96e245999a5dee7eb5d8529c4"
dependencies:
glob "~7.1.1"
lodash "~4.17.10"
minimatch "~3.0.2"
gonzales-pe@^4.1.1:
version "4.2.2"
resolved "https://registry.yarnpkg.com/gonzales-pe/-/gonzales-pe-4.2.2.tgz#f50a8c17842f13a9007909b7cb32188266e4d74c"
dependencies:
minimist "1.1.x"
graceful-fs@^4.1.2:
version "4.2.8"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a"
graceful-fs@^4.1.6:
version "4.1.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
har-schema@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
har-validator@~5.1.3:
version "5.1.5"
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd"
dependencies:
ajv "^6.12.3"
har-schema "^2.0.0"
has-ansi@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
dependencies:
ansi-regex "^2.0.0"
has-flag@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
has-flag@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51"
has-unicode@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
has@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28"
dependencies:
function-bind "^1.0.2"
has@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
dependencies:
function-bind "^1.1.1"
hash-base@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1"
dependencies:
inherits "^2.0.1"
hash-base@^3.0.0:
version "3.0.4"
resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918"
dependencies:
inherits "^2.0.1"
safe-buffer "^5.0.1"
hash.js@^1.0.0, hash.js@^1.0.3:
version "1.1.7"
resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42"
dependencies:
inherits "^2.0.3"
minimalistic-assert "^1.0.1"
hmac-drbg@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
dependencies:
hash.js "^1.0.3"
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.1"
hoist-non-react-statics@^1.0.3:
version "1.2.0"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb"
home-or-tmp@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8"
dependencies:
os-homedir "^1.0.0"
os-tmpdir "^1.0.1"
hosted-git-info@^2.1.4:
version "2.8.9"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
html-comment-regex@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e"
http-signature@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
dependencies:
assert-plus "^1.0.0"
jsprim "^1.2.2"
sshpk "^1.7.0"
https-browserify@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82"
iconv-lite@~0.4.13:
version "0.4.19"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b"
icss-replace-symbols@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded"
icss-utils@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-2.1.0.tgz#83f0a0ec378bf3246178b6c2ad9136f135b1c962"
dependencies:
postcss "^6.0.1"
ieee754@^1.1.4:
version "1.1.8"
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4"
ignore@^3.1.2:
version "3.3.5"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.5.tgz#c4e715455f6073a8d7e5dae72d2fc9d71663dba6"
imports-loader@^0.6.5:
version "0.6.5"
resolved "https://registry.yarnpkg.com/imports-loader/-/imports-loader-0.6.5.tgz#ae74653031d59e37b3c2fb2544ac61aeae3530a6"
dependencies:
loader-utils "0.2.x"
source-map "0.1.x"
imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
in-publish@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.1.tgz#948b1a535c8030561cea522f73f78f4be357e00c"
indent-string@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80"
dependencies:
repeating "^2.0.0"
indexes-of@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607"
indexof@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
dependencies:
once "^1.3.0"
wrappy "1"
inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
inherits@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
ini@~1.3.0:
version "1.3.8"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
inquirer@^0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e"
dependencies:
ansi-escapes "^1.1.0"
ansi-regex "^2.0.0"
chalk "^1.0.0"
cli-cursor "^1.0.1"
cli-width "^2.0.0"
figures "^1.3.5"
lodash "^4.3.0"
readline2 "^1.0.1"
run-async "^0.1.0"
rx-lite "^3.1.2"
string-width "^1.0.1"
strip-ansi "^3.0.0"
through "^2.3.6"
interpret@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.3.tgz#cbc35c62eeee73f19ab7b10a801511401afc0f90"
invariant@^2.0.0, invariant@^2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360"
dependencies:
loose-envify "^1.0.0"
invert-kv@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
is-absolute-url@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6"
is-arrayish@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
is-binary-path@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
dependencies:
binary-extensions "^1.0.0"
is-buffer@^1.0.2, is-buffer@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc"
is-core-module@^2.2.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.5.0.tgz#f754843617c70bfd29b7bd87327400cda5c18491"
dependencies:
has "^1.0.3"
is-directory@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1"
is-dotfile@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1"
is-equal-shallow@^0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534"
dependencies:
is-primitive "^2.0.0"
is-extendable@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
is-extglob@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
is-finite@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3"
is-fullwidth-code-point@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
dependencies:
number-is-nan "^1.0.0"
is-fullwidth-code-point@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
is-glob@^2.0.0, is-glob@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
dependencies:
is-extglob "^1.0.0"
is-my-ip-valid@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz#7b351b8e8edd4d3995d4d066680e664d94696824"
is-my-json-valid@^2.10.0:
version "2.20.5"
resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.20.5.tgz#5eca6a8232a687f68869b7361be1612e7512e5df"
dependencies:
generate-function "^2.0.0"
generate-object-property "^1.1.0"
is-my-ip-valid "^1.0.0"
jsonpointer "^4.0.0"
xtend "^4.0.0"
is-number@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
dependencies:
kind-of "^3.0.2"
is-number@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
dependencies:
kind-of "^3.0.2"
is-path-cwd@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d"
is-path-in-cwd@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc"
dependencies:
is-path-inside "^1.0.0"
is-path-inside@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f"
dependencies:
path-is-inside "^1.0.1"
is-plain-obj@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
is-plain-object@^2.0.1:
version "2.0.4"
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
dependencies:
isobject "^3.0.1"
is-posix-bracket@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
is-primitive@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
is-property@^1.0.0, is-property@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84"
is-resolvable@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62"
dependencies:
tryit "^1.0.1"
is-stream@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
is-svg@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-2.1.0.tgz#cf61090da0d9efbcab8722deba6f032208dbb0e9"
dependencies:
html-comment-regex "^1.1.0"
is-typedarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
is-utf8@^0.2.0:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
isexe@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
isobject@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
dependencies:
isarray "1.0.0"
isobject@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
isomorphic-fetch@^2.1.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
dependencies:
node-fetch "^1.0.1"
whatwg-fetch ">=0.10.0"
isstream@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
jquery@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.4.0.tgz#8de513fa0fa4b2c7d2e48a530e26f0596936efdf"
js-base64@^2.1.8:
version "2.6.4"
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.6.4.tgz#f4e686c5de1ea1f867dbcad3d46d969428df98c4"
js-base64@^2.1.9:
version "2.1.9"
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.1.9.tgz#f0e80ae039a4bd654b5f281fc93f04a914a7fcce"
js-tokens@^3.0.0, js-tokens@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
js-yaml@^3.4.3, js-yaml@^3.4.6, js-yaml@^3.5.1, js-yaml@^3.5.4:
version "3.9.1"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.9.1.tgz#08775cebdfdd359209f0d2acd383c8f86a6904a0"
dependencies:
argparse "^1.0.7"
esprima "^4.0.0"
js-yaml@~3.7.0:
version "3.7.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80"
dependencies:
argparse "^1.0.7"
esprima "^2.6.0"
jsbn@~0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
jsesc@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b"
jsesc@~0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
json-loader@^0.5.4:
version "0.5.7"
resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.7.tgz#dca14a70235ff82f0ac9a3abeb60d337a365185d"
json-schema-traverse@^0.3.0:
version "0.3.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340"
json-schema-traverse@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
json-schema@0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
dependencies:
jsonify "~0.0.0"
json-stringify-safe@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
json5@^0.5.0, json5@^0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
jsonfile@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-3.0.1.tgz#a5ecc6f65f53f662c4415c7675a0331d0992ec66"
optionalDependencies:
graceful-fs "^4.1.6"
jsonify@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
jsonpointer@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.1.0.tgz#501fb89986a2389765ba09e6053299ceb4f2c2cc"
jsprim@^1.2.2:
version "1.4.1"
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
dependencies:
assert-plus "1.0.0"
extsprintf "1.3.0"
json-schema "0.2.3"
verror "1.10.0"
kind-of@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-2.0.1.tgz#018ec7a4ce7e3a86cb9141be519d24c8faa981b5"
dependencies:
is-buffer "^1.0.2"
kind-of@^3.0.2, kind-of@^3.2.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
dependencies:
is-buffer "^1.1.5"
kind-of@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57"
dependencies:
is-buffer "^1.1.5"
known-css-properties@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.3.0.tgz#a3d135bbfc60ee8c6eacf2f7e7e6f2d4755e49a4"
lazy-cache@^0.2.3:
version "0.2.7"
resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-0.2.7.tgz#7feddf2dcb6edb77d11ef1d117ab5ffdf0ab1b65"
lazy-cache@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
lcid@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
dependencies:
invert-kv "^1.0.0"
levn@^0.3.0, levn@~0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
dependencies:
prelude-ls "~1.1.2"
type-check "~0.3.2"
load-json-file@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
dependencies:
graceful-fs "^4.1.2"
parse-json "^2.2.0"
pify "^2.0.0"
pinkie-promise "^2.0.0"
strip-bom "^2.0.0"
loader-fs-cache@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/loader-fs-cache/-/loader-fs-cache-1.0.1.tgz#56e0bf08bd9708b26a765b68509840c8dec9fdbc"
dependencies:
find-cache-dir "^0.1.1"
mkdirp "0.5.1"
loader-runner@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2"
loader-utils@0.2.x, loader-utils@^0.2.16:
version "0.2.17"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348"
dependencies:
big.js "^3.1.3"
emojis-list "^2.0.0"
json5 "^0.5.0"
object-assign "^4.0.1"
loader-utils@^1.0.0, loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd"
dependencies:
big.js "^3.1.3"
emojis-list "^2.0.0"
json5 "^0.5.0"
locate-path@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
dependencies:
p-locate "^2.0.0"
path-exists "^3.0.0"
locate-path@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
dependencies:
p-locate "^3.0.0"
path-exists "^3.0.0"
lodash._baseassign@^3.0.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e"
dependencies:
lodash._basecopy "^3.0.0"
lodash.keys "^3.0.0"
lodash._basecopy@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36"
lodash._bindcallback@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e"
lodash._createassigner@^3.0.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11"
dependencies:
lodash._bindcallback "^3.0.0"
lodash._isiterateecall "^3.0.0"
lodash.restparam "^3.0.0"
lodash._getnative@^3.0.0:
version "3.9.1"
resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
lodash._isiterateecall@^3.0.0:
version "3.0.9"
resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c"
lodash.assign@^3.0.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa"
dependencies:
lodash._baseassign "^3.0.0"
lodash._createassigner "^3.0.0"
lodash.keys "^3.0.0"
lodash.assign@^4.0.1:
version "4.2.0"
resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7"
lodash.camelcase@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
lodash.capitalize@^4.1.0:
version "4.2.1"
resolved "https://registry.yarnpkg.com/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz#f826c9b4e2a8511d84e3aca29db05e1a4f3b72a9"
lodash.defaults@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-3.1.2.tgz#c7308b18dbf8bc9372d701a73493c61192bd2e2c"
dependencies:
lodash.assign "^3.0.0"
lodash.restparam "^3.0.0"
lodash.defaults@^4.0.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
lodash.isarguments@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a"
lodash.isarray@^3.0.0:
version "3.0.4"
resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55"
lodash.kebabcase@^4.0.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36"
lodash.keys@^3.0.0:
version "3.1.2"
resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a"
dependencies:
lodash._getnative "^3.0.0"
lodash.isarguments "^3.0.0"
lodash.isarray "^3.0.0"
lodash.memoize@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
lodash.restparam@^3.0.0:
version "3.6.1"
resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"
lodash.tail@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664"
lodash.uniq@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
lodash@4.17.4:
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
lodash@^4.0.0, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@~4.17.10:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
longest@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
dependencies:
js-tokens "^3.0.0"
loud-rejection@^1.0.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
dependencies:
currently-unhandled "^0.4.1"
signal-exit "^3.0.0"
lru-cache@^4.0.1:
version "4.1.5"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
dependencies:
pseudomap "^1.0.2"
yallist "^2.1.2"
macaddress@^0.2.8:
version "0.2.8"
resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12"
make-dir@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.0.0.tgz#97a011751e91dd87cfadef58832ebb04936de978"
dependencies:
pify "^2.3.0"
map-obj@^1.0.0, map-obj@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
math-expression-evaluator@^1.2.14:
version "1.2.17"
resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz#de819fdbcd84dccd8fae59c6aeb79615b9d266ac"
md5.js@^1.3.4:
version "1.3.4"
resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d"
dependencies:
hash-base "^3.0.0"
inherits "^2.0.1"
memory-fs@^0.4.0, memory-fs@~0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
dependencies:
errno "^0.1.3"
readable-stream "^2.0.1"
meow@^3.7.0:
version "3.7.0"
resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb"
dependencies:
camelcase-keys "^2.0.0"
decamelize "^1.1.2"
loud-rejection "^1.0.0"
map-obj "^1.0.1"
minimist "^1.1.3"
normalize-package-data "^2.3.4"
object-assign "^4.0.1"
read-pkg-up "^1.0.1"
redent "^1.0.0"
trim-newlines "^1.0.0"
merge@^1.2.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145"
micromatch@^2.1.5:
version "2.3.11"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
dependencies:
arr-diff "^2.0.0"
array-unique "^0.2.1"
braces "^1.8.2"
expand-brackets "^0.1.4"
extglob "^0.3.1"
filename-regex "^2.0.0"
is-extglob "^1.0.0"
is-glob "^2.0.1"
kind-of "^3.0.2"
normalize-path "^2.0.1"
object.omit "^2.0.0"
parse-glob "^3.0.4"
regex-cache "^0.4.2"
miller-rabin@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.0.tgz#4a62fb1d42933c05583982f4c716f6fb9e6c6d3d"
dependencies:
bn.js "^4.0.0"
brorand "^1.0.1"
mime-db@1.49.0:
version "1.49.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.49.0.tgz#f3dfde60c99e9cf3bc9701d687778f537001cbed"
mime-types@^2.1.12, mime-types@~2.1.19:
version "2.1.32"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.32.tgz#1d00e89e7de7fe02008db61001d9e02852670fd5"
dependencies:
mime-db "1.49.0"
mime@1.3.x:
version "1.3.6"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.6.tgz#591d84d3653a6b0b4a3b9df8de5aa8108e72e5e0"
minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
minimalistic-crypto-utils@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.2:
version "3.0.8"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.8.tgz#5e6a59bd11e2ab0de1cfb843eb2d82e546c321c1"
dependencies:
brace-expansion "^1.1.7"
minimist@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
minimist@1.1.x:
version "1.1.3"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.1.3.tgz#3bedfd91a92d39016fcfaa1c681e8faa1a1efda8"
minimist@^1.1.3, minimist@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
minimist@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
mixin-object@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/mixin-object/-/mixin-object-2.0.1.tgz#4fb949441dab182540f1fe035ba60e1947a5e57e"
dependencies:
for-in "^0.1.3"
is-extendable "^0.1.1"
mkdirp@0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
dependencies:
minimist "0.0.8"
"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1:
version "0.5.5"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
dependencies:
minimist "^1.2.5"
modernizr-loader@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/modernizr-loader/-/modernizr-loader-1.0.1.tgz#e52a6f9a12578b944abbd6cbd65c863ea4a83f49"
modernizr@^3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/modernizr/-/modernizr-3.5.0.tgz#396a02231bdc54628bbde2c0813a8e884c7e8060"
dependencies:
doctrine "1.2.3"
file "0.2.2"
find-parent-dir "0.3.0"
lodash "4.17.4"
mkdirp "0.5.1"
remarkable "^1.6.2"
requirejs "2.1.22"
yargs "7.0.2"
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
mute-stream@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0"
nan@^2.13.2, nan@^2.3.0:
version "2.15.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee"
node-fetch@^1.0.1:
version "1.7.3"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef"
dependencies:
encoding "^0.1.11"
is-stream "^1.0.1"
node-gyp@^3.8.0:
version "3.8.0"
resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c"
dependencies:
fstream "^1.0.0"
glob "^7.0.3"
graceful-fs "^4.1.2"
mkdirp "^0.5.0"
nopt "2 || 3"
npmlog "0 || 1 || 2 || 3 || 4"
osenv "0"
request "^2.87.0"
rimraf "2"
semver "~5.3.0"
tar "^2.0.0"
which "1"
node-libs-browser@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.0.0.tgz#a3a59ec97024985b46e958379646f96c4b616646"
dependencies:
assert "^1.1.1"
browserify-zlib "^0.1.4"
buffer "^4.3.0"
console-browserify "^1.1.0"
constants-browserify "^1.0.0"
crypto-browserify "^3.11.0"
domain-browser "^1.1.1"
events "^1.0.0"
https-browserify "0.0.1"
os-browserify "^0.2.0"
path-browserify "0.0.0"
process "^0.11.0"
punycode "^1.2.4"
querystring-es3 "^0.2.0"
readable-stream "^2.0.5"
stream-browserify "^2.0.1"
stream-http "^2.3.1"
string_decoder "^0.10.25"
timers-browserify "^2.0.2"
tty-browserify "0.0.0"
url "^0.11.0"
util "^0.10.3"
vm-browserify "0.0.4"
node-pre-gyp@^0.6.36:
version "0.6.36"
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz#db604112cb74e0d477554e9b505b17abddfab786"
dependencies:
mkdirp "^0.5.1"
nopt "^4.0.1"
npmlog "^4.0.2"
rc "^1.1.7"
request "^2.81.0"
rimraf "^2.6.1"
semver "^5.3.0"
tar "^2.2.1"
tar-pack "^3.4.0"
node-sass@^4.5.3:
version "4.14.1"
resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.14.1.tgz#99c87ec2efb7047ed638fb4c9db7f3a42e2217b5"
dependencies:
async-foreach "^0.1.3"
chalk "^1.1.1"
cross-spawn "^3.0.0"
gaze "^1.0.0"
get-stdin "^4.0.1"
glob "^7.0.3"
in-publish "^2.0.0"
lodash "^4.17.15"
meow "^3.7.0"
mkdirp "^0.5.1"
nan "^2.13.2"
node-gyp "^3.8.0"
npmlog "^4.0.0"
request "^2.88.0"
sass-graph "2.2.5"
stdout-stream "^1.4.0"
"true-case-path" "^1.0.2"
"nopt@2 || 3":
version "3.0.6"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
dependencies:
abbrev "1"
nopt@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
dependencies:
abbrev "1"
osenv "^0.1.4"
normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
version "2.5.0"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
dependencies:
hosted-git-info "^2.1.4"
resolve "^1.10.0"
semver "2 || 3 || 4 || 5"
validate-npm-package-license "^3.0.1"
normalize-path@^2.0.0, normalize-path@^2.0.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
dependencies:
remove-trailing-separator "^1.0.1"
normalize-range@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
normalize-url@^1.4.0:
version "1.9.1"
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.1.tgz#2cc0d66b31ea23036458436e3620d85954c66c3c"
dependencies:
object-assign "^4.0.1"
prepend-http "^1.0.0"
query-string "^4.1.0"
sort-keys "^1.0.0"
"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
dependencies:
are-we-there-yet "~1.1.2"
console-control-strings "~1.1.0"
gauge "~2.7.3"
set-blocking "~2.0.0"
num2fraction@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede"
number-is-nan@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
oauth-sign@~0.9.0:
version "0.9.0"
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
object-hash@^1.1.4:
version "1.1.8"
resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.1.8.tgz#28a659cf987d96a4dabe7860289f3b5326c4a03c"
object-path@^0.9.2:
version "0.9.2"
resolved "https://registry.yarnpkg.com/object-path/-/object-path-0.9.2.tgz#0fd9a74fc5fad1ae3968b586bda5c632bd6c05a5"
object.omit@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
dependencies:
for-own "^0.1.4"
is-extendable "^0.1.1"
once@^1.3.0, once@^1.3.3:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
dependencies:
wrappy "1"
onetime@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789"
optionator@^0.8.1:
version "0.8.2"
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64"
dependencies:
deep-is "~0.1.3"
fast-levenshtein "~2.0.4"
levn "~0.3.0"
prelude-ls "~1.1.2"
type-check "~0.3.2"
wordwrap "~1.0.0"
os-browserify@^0.2.0:
version "0.2.1"
resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.2.1.tgz#63fc4ccee5d2d7763d26bbf8601078e6c2e0044f"
os-homedir@^1.0.0, os-homedir@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
os-locale@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9"
dependencies:
lcid "^1.0.0"
os-tmpdir@^1.0.0, os-tmpdir@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
osenv@0:
version "0.1.5"
resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
dependencies:
os-homedir "^1.0.0"
os-tmpdir "^1.0.0"
osenv@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644"
dependencies:
os-homedir "^1.0.0"
os-tmpdir "^1.0.0"
p-limit@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc"
p-limit@^2.0.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
dependencies:
p-try "^2.0.0"
p-locate@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
dependencies:
p-limit "^1.1.0"
p-locate@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
dependencies:
p-limit "^2.0.0"
p-try@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
pako@~0.2.0:
version "0.2.9"
resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
parse-asn1@^5.0.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712"
dependencies:
asn1.js "^4.0.0"
browserify-aes "^1.0.0"
create-hash "^1.1.0"
evp_bytestokey "^1.0.0"
pbkdf2 "^3.0.3"
parse-glob@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
dependencies:
glob-base "^0.3.0"
is-dotfile "^1.0.0"
is-extglob "^1.0.0"
is-glob "^2.0.0"
parse-json@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
dependencies:
error-ex "^1.2.0"
path-browserify@0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a"
path-exists@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
dependencies:
pinkie-promise "^2.0.0"
path-exists@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
path-is-absolute@^1.0.0, path-is-absolute@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
path-is-inside@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
path-parse@^1.0.6:
version "1.0.7"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
path-type@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
dependencies:
graceful-fs "^4.1.2"
pify "^2.0.0"
pinkie-promise "^2.0.0"
pbkdf2@^3.0.3:
version "3.0.13"
resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.13.tgz#c37d295531e786b1da3e3eadc840426accb0ae25"
dependencies:
create-hash "^1.1.2"
create-hmac "^1.1.4"
ripemd160 "^2.0.1"
safe-buffer "^5.0.1"
sha.js "^2.4.8"
performance-now@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
pify@^2.0.0, pify@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
pify@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
pinkie-promise@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
dependencies:
pinkie "^2.0.0"
pinkie@^2.0.0:
version "2.0.4"
resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
pkg-dir@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4"
dependencies:
find-up "^1.0.0"
pkg-dir@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b"
dependencies:
find-up "^2.1.0"
pluralize@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45"
postcss-calc@^5.2.0:
version "5.3.1"
resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-5.3.1.tgz#77bae7ca928ad85716e2fda42f261bf7c1d65b5e"
dependencies:
postcss "^5.0.2"
postcss-message-helpers "^2.0.0"
reduce-css-calc "^1.2.6"
postcss-colormin@^2.1.8:
version "2.2.2"
resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-2.2.2.tgz#6631417d5f0e909a3d7ec26b24c8a8d1e4f96e4b"
dependencies:
colormin "^1.0.5"
postcss "^5.0.13"
postcss-value-parser "^3.2.3"
postcss-convert-values@^2.3.4:
version "2.6.1"
resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz#bbd8593c5c1fd2e3d1c322bb925dcae8dae4d62d"
dependencies:
postcss "^5.0.11"
postcss-value-parser "^3.1.2"
postcss-discard-comments@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz#befe89fafd5b3dace5ccce51b76b81514be00e3d"
dependencies:
postcss "^5.0.14"
postcss-discard-duplicates@^2.0.1:
version "2.1.0"
resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz#b9abf27b88ac188158a5eb12abcae20263b91932"
dependencies:
postcss "^5.0.4"
postcss-discard-empty@^2.0.1:
version "2.1.0"
resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz#d2b4bd9d5ced5ebd8dcade7640c7d7cd7f4f92b5"
dependencies:
postcss "^5.0.14"
postcss-discard-overridden@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz#8b1eaf554f686fb288cd874c55667b0aa3668d58"
dependencies:
postcss "^5.0.16"
postcss-discard-unused@^2.2.1:
version "2.2.3"
resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz#bce30b2cc591ffc634322b5fb3464b6d934f4433"
dependencies:
postcss "^5.0.14"
uniqs "^2.0.0"
postcss-filter-plugins@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/postcss-filter-plugins/-/postcss-filter-plugins-2.0.2.tgz#6d85862534d735ac420e4a85806e1f5d4286d84c"
dependencies:
postcss "^5.0.4"
uniqid "^4.0.0"
postcss-load-config@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-1.2.0.tgz#539e9afc9ddc8620121ebf9d8c3673e0ce50d28a"
dependencies:
cosmiconfig "^2.1.0"
object-assign "^4.1.0"
postcss-load-options "^1.2.0"
postcss-load-plugins "^2.3.0"
postcss-load-options@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/postcss-load-options/-/postcss-load-options-1.2.0.tgz#b098b1559ddac2df04bc0bb375f99a5cfe2b6d8c"
dependencies:
cosmiconfig "^2.1.0"
object-assign "^4.1.0"
postcss-load-plugins@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/postcss-load-plugins/-/postcss-load-plugins-2.3.0.tgz#745768116599aca2f009fad426b00175049d8d92"
dependencies:
cosmiconfig "^2.1.1"
object-assign "^4.1.0"
postcss-loader@^2.0.5:
version "2.0.6"
resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-2.0.6.tgz#8c7e0055a3df1889abc6bad52dd45b2f41bbc6fc"
dependencies:
loader-utils "^1.1.0"
postcss "^6.0.2"
postcss-load-config "^1.2.0"
schema-utils "^0.3.0"
postcss-merge-idents@^2.1.5:
version "2.1.7"
resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz#4c5530313c08e1d5b3bbf3d2bbc747e278eea270"
dependencies:
has "^1.0.1"
postcss "^5.0.10"
postcss-value-parser "^3.1.1"
postcss-merge-longhand@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz#23d90cd127b0a77994915332739034a1a4f3d658"
dependencies:
postcss "^5.0.4"
postcss-merge-rules@^2.0.3:
version "2.1.2"
resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz#d1df5dfaa7b1acc3be553f0e9e10e87c61b5f721"
dependencies:
browserslist "^1.5.2"
caniuse-api "^1.5.2"
postcss "^5.0.4"
postcss-selector-parser "^2.2.2"
vendors "^1.0.0"
postcss-message-helpers@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz#a4f2f4fab6e4fe002f0aed000478cdf52f9ba60e"
postcss-minify-font-values@^1.0.2:
version "1.0.5"
resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz#4b58edb56641eba7c8474ab3526cafd7bbdecb69"
dependencies:
object-assign "^4.0.1"
postcss "^5.0.4"
postcss-value-parser "^3.0.2"
postcss-minify-gradients@^1.0.1:
version "1.0.5"
resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz#5dbda11373703f83cfb4a3ea3881d8d75ff5e6e1"
dependencies:
postcss "^5.0.12"
postcss-value-parser "^3.3.0"
postcss-minify-params@^1.0.4:
version "1.2.2"
resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz#ad2ce071373b943b3d930a3fa59a358c28d6f1f3"
dependencies:
alphanum-sort "^1.0.1"
postcss "^5.0.2"
postcss-value-parser "^3.0.2"
uniqs "^2.0.0"
postcss-minify-selectors@^2.0.4:
version "2.1.1"
resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz#b2c6a98c0072cf91b932d1a496508114311735bf"
dependencies:
alphanum-sort "^1.0.2"
has "^1.0.1"
postcss "^5.0.14"
postcss-selector-parser "^2.0.0"
postcss-modules-extract-imports@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.0.tgz#66140ecece38ef06bf0d3e355d69bf59d141ea85"
dependencies:
postcss "^6.0.1"
postcss-modules-local-by-default@^1.0.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz#f7d80c398c5a393fa7964466bd19500a7d61c069"
dependencies:
css-selector-tokenizer "^0.7.0"
postcss "^6.0.1"
postcss-modules-scope@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz#d6ea64994c79f97b62a72b426fbe6056a194bb90"
dependencies:
css-selector-tokenizer "^0.7.0"
postcss "^6.0.1"
postcss-modules-values@^1.1.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz#ecffa9d7e192518389f42ad0e83f72aec456ea20"
dependencies:
icss-replace-symbols "^1.1.0"
postcss "^6.0.1"
postcss-normalize-charset@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz#ef9ee71212d7fe759c78ed162f61ed62b5cb93f1"
dependencies:
postcss "^5.0.5"
postcss-normalize-url@^3.0.7:
version "3.0.8"
resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz#108f74b3f2fcdaf891a2ffa3ea4592279fc78222"
dependencies:
is-absolute-url "^2.0.0"
normalize-url "^1.4.0"
postcss "^5.0.14"
postcss-value-parser "^3.2.3"
postcss-ordered-values@^2.1.0:
version "2.2.3"
resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz#eec6c2a67b6c412a8db2042e77fe8da43f95c11d"
dependencies:
postcss "^5.0.4"
postcss-value-parser "^3.0.1"
postcss-reduce-idents@^2.2.2:
version "2.4.0"
resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz#c2c6d20cc958284f6abfbe63f7609bf409059ad3"
dependencies:
postcss "^5.0.4"
postcss-value-parser "^3.0.2"
postcss-reduce-initial@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz#68f80695f045d08263a879ad240df8dd64f644ea"
dependencies:
postcss "^5.0.4"
postcss-reduce-transforms@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz#ff76f4d8212437b31c298a42d2e1444025771ae1"
dependencies:
has "^1.0.1"
postcss "^5.0.8"
postcss-value-parser "^3.0.1"
postcss-selector-parser@^2.0.0, postcss-selector-parser@^2.2.2:
version "2.2.3"
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz#f9437788606c3c9acee16ffe8d8b16297f27bb90"
dependencies:
flatten "^1.0.2"
indexes-of "^1.0.1"
uniq "^1.0.1"
postcss-svgo@^2.1.1:
version "2.1.6"
resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-2.1.6.tgz#b6df18aa613b666e133f08adb5219c2684ac108d"
dependencies:
is-svg "^2.0.0"
postcss "^5.0.14"
postcss-value-parser "^3.2.3"
svgo "^0.7.0"
postcss-unique-selectors@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz#981d57d29ddcb33e7b1dfe1fd43b8649f933ca1d"
dependencies:
alphanum-sort "^1.0.1"
postcss "^5.0.4"
uniqs "^2.0.0"
postcss-value-parser@^3.0.1, postcss-value-parser@^3.0.2, postcss-value-parser@^3.1.1, postcss-value-parser@^3.1.2, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15"
postcss-zindex@^2.0.1:
version "2.2.0"
resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-2.2.0.tgz#d2109ddc055b91af67fc4cb3b025946639d2af22"
dependencies:
has "^1.0.1"
postcss "^5.0.4"
uniqs "^2.0.0"
postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.2.16:
version "5.2.17"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.17.tgz#cf4f597b864d65c8a492b2eabe9d706c879c388b"
dependencies:
chalk "^1.1.3"
js-base64 "^2.1.9"
source-map "^0.5.6"
supports-color "^3.2.3"
postcss@^6.0.1, postcss@^6.0.2:
version "6.0.11"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.11.tgz#f48db210b1d37a7f7ab6499b7a54982997ab6f72"
dependencies:
chalk "^2.1.0"
source-map "^0.5.7"
supports-color "^4.4.0"
prelude-ls@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
prepend-http@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
preserve@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
private@^0.1.6, private@^0.1.7:
version "0.1.7"
resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1"
process-nextick-args@~1.0.6:
version "1.0.7"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
process-nextick-args@~2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
process@^0.11.0:
version "0.11.10"
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
progress@^1.1.8:
version "1.1.8"
resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be"
promise@^7.1.1:
version "7.3.1"
resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
dependencies:
asap "~2.0.3"
prop-types@^15.5.4:
version "15.5.10"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154"
dependencies:
fbjs "^0.8.9"
loose-envify "^1.3.1"
prr@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a"
pseudomap@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
psl@^1.1.28:
version "1.8.0"
resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24"
public-encrypt@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6"
dependencies:
bn.js "^4.1.0"
browserify-rsa "^4.0.0"
create-hash "^1.1.0"
parse-asn1 "^5.0.0"
randombytes "^2.0.1"
punycode@1.3.2:
version "1.3.2"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
punycode@^1.2.4:
version "1.4.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
punycode@^2.1.0, punycode@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
q@^1.1.2:
version "1.5.0"
resolved "https://registry.yarnpkg.com/q/-/q-1.5.0.tgz#dd01bac9d06d30e6f219aecb8253ee9ebdc308f1"
qs@~6.5.2:
version "6.5.3"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad"
query-string@^4.1.0:
version "4.3.4"
resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb"
dependencies:
object-assign "^4.1.0"
strict-uri-encode "^1.0.0"
querystring-es3@^0.2.0:
version "0.2.1"
resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
querystring@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
randomatic@^1.1.3:
version "1.1.7"
resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c"
dependencies:
is-number "^3.0.0"
kind-of "^4.0.0"
randombytes@^2.0.0, randombytes@^2.0.1:
version "2.0.5"
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.5.tgz#dc009a246b8d09a177b4b7a0ae77bc570f4b1b79"
dependencies:
safe-buffer "^5.1.0"
raw-loader@~0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-0.5.1.tgz#0c3d0beaed8a01c966d9787bf778281252a979aa"
rc@^1.1.7:
version "1.2.1"
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95"
dependencies:
deep-extend "~0.4.0"
ini "~1.3.0"
minimist "^1.2.0"
strip-json-comments "~2.0.1"
react-dom@15.3.1:
version "15.3.1"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.3.1.tgz#6d42cd2b64c8c5e0b693f3ffaec301e6e627e24e"
react-redux@^4.4.1:
version "4.4.8"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-4.4.8.tgz#e7bc1dd100e8b64e96ac8212db113239b9e2e08f"
dependencies:
create-react-class "^15.5.1"
hoist-non-react-statics "^1.0.3"
invariant "^2.0.0"
lodash "^4.2.0"
loose-envify "^1.1.0"
prop-types "^15.5.4"
react@15.3.1:
version "15.3.1"
resolved "https://registry.yarnpkg.com/react/-/react-15.3.1.tgz#f78501ed8c2ec6e6e31c3223652e97f1369d2bd6"
dependencies:
fbjs "^0.8.4"
loose-envify "^1.1.0"
object-assign "^4.1.0"
read-pkg-up@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
dependencies:
find-up "^1.0.0"
read-pkg "^1.0.0"
read-pkg@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
dependencies:
load-json-file "^1.0.0"
normalize-package-data "^2.3.2"
path-type "^1.0.0"
readable-stream@^2.0.1, readable-stream@^2.0.6:
version "2.3.7"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.3"
isarray "~1.0.0"
process-nextick-args "~2.0.0"
safe-buffer "~5.1.1"
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.4, readable-stream@^2.2.2, readable-stream@^2.2.6:
version "2.3.3"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c"
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.3"
isarray "~1.0.0"
process-nextick-args "~1.0.6"
safe-buffer "~5.1.1"
string_decoder "~1.0.3"
util-deprecate "~1.0.1"
readdirp@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"
dependencies:
graceful-fs "^4.1.2"
minimatch "^3.0.2"
readable-stream "^2.0.2"
set-immediate-shim "^1.0.1"
readline2@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35"
dependencies:
code-point-at "^1.0.0"
is-fullwidth-code-point "^1.0.0"
mute-stream "0.0.5"
redent@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"
dependencies:
indent-string "^2.1.0"
strip-indent "^1.0.1"
reduce-css-calc@^1.2.6:
version "1.3.0"
resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716"
dependencies:
balanced-match "^0.4.2"
math-expression-evaluator "^1.2.14"
reduce-function-call "^1.0.1"
reduce-function-call@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/reduce-function-call/-/reduce-function-call-1.0.2.tgz#5a200bf92e0e37751752fe45b0ab330fd4b6be99"
dependencies:
balanced-match "^0.4.2"
"redux@https://registry.npmjs.org/redux/-/redux-3.0.5.tgz":
version "3.0.5"
resolved "https://registry.npmjs.org/redux/-/redux-3.0.5.tgz#f3f23f780b98c8dd7f84b9187ab5f86fe90199b8"
regenerate@^1.2.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260"
regenerator-runtime@^0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz#7e54fe5b5ccd5d6624ea6255c3473be090b802e1"
regenerator-transform@^0.10.0:
version "0.10.1"
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd"
dependencies:
babel-runtime "^6.18.0"
babel-types "^6.19.0"
private "^0.1.6"
regex-cache@^0.4.2:
version "0.4.4"
resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd"
dependencies:
is-equal-shallow "^0.1.3"
regex-parser@^2.2.1:
version "2.2.7"
resolved "https://registry.yarnpkg.com/regex-parser/-/regex-parser-2.2.7.tgz#bd090e09181849acc45457e765f7be2a63f50ef1"
regexpu-core@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b"
dependencies:
regenerate "^1.2.1"
regjsgen "^0.2.0"
regjsparser "^0.1.4"
regexpu-core@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240"
dependencies:
regenerate "^1.2.1"
regjsgen "^0.2.0"
regjsparser "^0.1.4"
regjsgen@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7"
regjsparser@^0.1.4:
version "0.1.5"
resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c"
dependencies:
jsesc "~0.5.0"
remarkable@^1.6.2:
version "1.7.1"
resolved "https://registry.yarnpkg.com/remarkable/-/remarkable-1.7.1.tgz#aaca4972100b66a642a63a1021ca4bac1be3bff6"
dependencies:
argparse "~0.1.15"
autolinker "~0.15.0"
remove-trailing-separator@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
repeat-element@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a"
repeat-string@^1.5.2:
version "1.6.1"
resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
repeating@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
dependencies:
is-finite "^1.0.0"
request@^2.81.0, request@^2.87.0, request@^2.88.0:
version "2.88.2"
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
dependencies:
aws-sign2 "~0.7.0"
aws4 "^1.8.0"
caseless "~0.12.0"
combined-stream "~1.0.6"
extend "~3.0.2"
forever-agent "~0.6.1"
form-data "~2.3.2"
har-validator "~5.1.3"
http-signature "~1.2.0"
is-typedarray "~1.0.0"
isstream "~0.1.2"
json-stringify-safe "~5.0.1"
mime-types "~2.1.19"
oauth-sign "~0.9.0"
performance-now "^2.1.0"
qs "~6.5.2"
safe-buffer "^5.1.2"
tough-cookie "~2.5.0"
tunnel-agent "^0.6.0"
uuid "^3.3.2"
require-directory@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
require-from-string@^1.1.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-1.2.1.tgz#529c9ccef27380adfec9a2f965b649bbee636418"
require-main-filename@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
require-main-filename@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
require-uncached@^1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3"
dependencies:
caller-path "^0.1.0"
resolve-from "^1.0.0"
requirejs@2.1.22:
version "2.1.22"
resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.1.22.tgz#dd78fd2d34180c0d62c724b5b8aebc0664e0366f"
resolve-from@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226"
resolve-url-loader@^2.0.2:
version "2.1.0"
resolved "https://registry.yarnpkg.com/resolve-url-loader/-/resolve-url-loader-2.1.0.tgz#27c95cc16a4353923fdbdc2dbaf5eef22232c477"
dependencies:
adjust-sourcemap-loader "^1.1.0"
camelcase "^4.0.0"
convert-source-map "^1.1.1"
loader-utils "^1.0.0"
lodash.defaults "^4.0.0"
rework "^1.0.1"
rework-visit "^1.0.0"
source-map "^0.5.6"
urix "^0.1.0"
resolve-url@~0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
resolve@^1.10.0:
version "1.20.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
dependencies:
is-core-module "^2.2.0"
path-parse "^1.0.6"
restore-cursor@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541"
dependencies:
exit-hook "^1.0.0"
onetime "^1.0.0"
rework-visit@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/rework-visit/-/rework-visit-1.0.0.tgz#9945b2803f219e2f7aca00adb8bc9f640f842c9a"
rework@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/rework/-/rework-1.0.1.tgz#30806a841342b54510aa4110850cd48534144aa7"
dependencies:
convert-source-map "^0.3.3"
css "^2.0.0"
right-align@^0.1.1:
version "0.1.3"
resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
dependencies:
align-text "^0.1.1"
rimraf@2:
version "2.7.1"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
dependencies:
glob "^7.1.3"
rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d"
dependencies:
glob "^7.0.5"
ripemd160@^2.0.0, ripemd160@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7"
dependencies:
hash-base "^2.0.0"
inherits "^2.0.1"
run-async@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389"
dependencies:
once "^1.3.0"
rx-lite@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102"
safe-buffer@^5.0.1, safe-buffer@^5.1.2:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
safe-buffer@^5.1.0, safe-buffer@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
sass-graph@2.2.5:
version "2.2.5"
resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.5.tgz#a981c87446b8319d96dce0671e487879bd24c2e8"
dependencies:
glob "^7.0.0"
lodash "^4.0.0"
scss-tokenizer "^0.2.3"
yargs "^13.3.2"
sass-lint@^1.9.1:
version "1.11.1"
resolved "https://registry.yarnpkg.com/sass-lint/-/sass-lint-1.11.1.tgz#1ccea9be01e60fd0ca7ddf379a0096311b218240"
dependencies:
commander "^2.8.1"
eslint "^2.7.0"
front-matter "2.1.2"
fs-extra "^3.0.1"
glob "^7.0.0"
globule "^1.0.0"
gonzales-pe "^4.1.1"
js-yaml "^3.5.4"
known-css-properties "^0.3.0"
lodash.capitalize "^4.1.0"
lodash.kebabcase "^4.0.0"
merge "^1.2.0"
path-is-absolute "^1.0.0"
util "^0.10.3"
sass-loader@^6.0.5:
version "6.0.6"
resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-6.0.6.tgz#e9d5e6c1f155faa32a4b26d7a9b7107c225e40f9"
dependencies:
async "^2.1.5"
clone-deep "^0.3.0"
loader-utils "^1.0.1"
lodash.tail "^4.1.1"
pify "^3.0.0"
sax@~1.2.1:
version "1.2.4"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
schema-utils@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.3.0.tgz#f5877222ce3e931edae039f17eb3716e7137f8cf"
dependencies:
ajv "^5.0.0"
script-loader@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/script-loader/-/script-loader-0.7.0.tgz#685dc7e7069e0dee7a92674f0ebc5b0f55baa5ec"
dependencies:
raw-loader "~0.5.1"
scss-tokenizer@^0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1"
dependencies:
js-base64 "^2.1.8"
source-map "^0.4.2"
"semver@2 || 3 || 4 || 5":
version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
semver@^5.3.0:
version "5.4.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e"
semver@~5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
set-blocking@^2.0.0, set-blocking@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
set-immediate-shim@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
setimmediate@^1.0.4, setimmediate@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
sha.js@^2.4.0, sha.js@^2.4.8:
version "2.4.8"
resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.8.tgz#37068c2c476b6baf402d14a49c67f597921f634f"
dependencies:
inherits "^2.0.1"
shallow-clone@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-0.1.2.tgz#5909e874ba77106d73ac414cfec1ffca87d97060"
dependencies:
is-extendable "^0.1.1"
kind-of "^2.0.1"
lazy-cache "^0.2.3"
mixin-object "^2.0.1"
shelljs@^0.6.0:
version "0.6.1"
resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.6.1.tgz#ec6211bed1920442088fe0f70b2837232ed2c8a8"
signal-exit@^3.0.0:
version "3.0.3"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
slash@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
slice-ansi@0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"
sort-keys@^1.0.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad"
dependencies:
is-plain-obj "^1.0.0"
source-list-map@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085"
source-map-resolve@^0.3.0:
version "0.3.1"
resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.3.1.tgz#610f6122a445b8dd51535a2a71b783dfc1248761"
dependencies:
atob "~1.1.0"
resolve-url "~0.2.1"
source-map-url "~0.3.0"
urix "~0.1.0"
source-map-support@^0.4.15:
version "0.4.17"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.17.tgz#6f2150553e6375375d0ccb3180502b78c18ba430"
dependencies:
source-map "^0.5.6"
source-map-url@~0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9"
source-map@0.1.x, source-map@^0.1.38:
version "0.1.43"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346"
dependencies:
amdefine ">=0.0.4"
source-map@^0.4.2:
version "0.4.4"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
dependencies:
amdefine ">=0.0.4"
source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1, source-map@~0.5.3:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
spdx-correct@^3.0.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9"
dependencies:
spdx-expression-parse "^3.0.0"
spdx-license-ids "^3.0.0"
spdx-exceptions@^2.1.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d"
spdx-expression-parse@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679"
dependencies:
spdx-exceptions "^2.1.0"
spdx-license-ids "^3.0.0"
spdx-license-ids@^3.0.0:
version "3.0.9"
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz#8a595135def9592bda69709474f1cbeea7c2467f"
sprintf-js@~1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
sshpk@^1.7.0:
version "1.16.1"
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
dependencies:
asn1 "~0.2.3"
assert-plus "^1.0.0"
bcrypt-pbkdf "^1.0.0"
dashdash "^1.12.0"
ecc-jsbn "~0.1.1"
getpass "^0.1.1"
jsbn "~0.1.0"
safer-buffer "^2.0.2"
tweetnacl "~0.14.0"
stdout-stream@^1.4.0:
version "1.4.1"
resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.1.tgz#5ac174cdd5cd726104aa0c0b2bd83815d8d535de"
dependencies:
readable-stream "^2.0.1"
stream-browserify@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db"
dependencies:
inherits "~2.0.1"
readable-stream "^2.0.2"
stream-http@^2.3.1:
version "2.7.2"
resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.2.tgz#40a050ec8dc3b53b33d9909415c02c0bf1abfbad"
dependencies:
builtin-status-codes "^3.0.0"
inherits "^2.0.1"
readable-stream "^2.2.6"
to-arraybuffer "^1.0.0"
xtend "^4.0.0"
strict-uri-encode@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
string-width@^1.0.1, string-width@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
dependencies:
code-point-at "^1.0.0"
is-fullwidth-code-point "^1.0.0"
strip-ansi "^3.0.0"
"string-width@^1.0.2 || 2", string-width@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
dependencies:
is-fullwidth-code-point "^2.0.0"
strip-ansi "^4.0.0"
string-width@^3.0.0, string-width@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
dependencies:
emoji-regex "^7.0.1"
is-fullwidth-code-point "^2.0.0"
strip-ansi "^5.1.0"
string_decoder@^0.10.25:
version "0.10.31"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
string_decoder@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab"
dependencies:
safe-buffer "~5.1.0"
string_decoder@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
dependencies:
safe-buffer "~5.1.0"
strip-ansi@^3.0.0, strip-ansi@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
dependencies:
ansi-regex "^2.0.0"
strip-ansi@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
dependencies:
ansi-regex "^3.0.0"
strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
dependencies:
ansi-regex "^4.1.0"
strip-bom@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
dependencies:
is-utf8 "^0.2.0"
strip-indent@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2"
dependencies:
get-stdin "^4.0.1"
strip-json-comments@~1.0.1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91"
strip-json-comments@~2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
supports-color@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
supports-color@^3.1.0, supports-color@^3.2.3:
version "3.2.3"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
dependencies:
has-flag "^1.0.0"
supports-color@^4.0.0, supports-color@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e"
dependencies:
has-flag "^2.0.0"
svgo@^0.7.0:
version "0.7.2"
resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5"
dependencies:
coa "~1.0.1"
colors "~1.1.2"
csso "~2.3.1"
js-yaml "~3.7.0"
mkdirp "~0.5.1"
sax "~1.2.1"
whet.extend "~0.9.9"
table@^3.7.8:
version "3.8.3"
resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f"
dependencies:
ajv "^4.7.0"
ajv-keywords "^1.0.0"
chalk "^1.1.1"
lodash "^4.0.0"
slice-ansi "0.0.4"
string-width "^2.0.0"
tapable@^0.2.7, tapable@~0.2.5:
version "0.2.8"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.8.tgz#99372a5c999bf2df160afc0d74bed4f47948cd22"
tar-pack@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.0.tgz#23be2d7f671a8339376cbdb0b8fe3fdebf317984"
dependencies:
debug "^2.2.0"
fstream "^1.0.10"
fstream-ignore "^1.0.5"
once "^1.3.3"
readable-stream "^2.1.4"
rimraf "^2.5.1"
tar "^2.2.1"
uid-number "^0.0.6"
tar@^2.0.0, tar@^2.2.1:
version "2.2.2"
resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.2.tgz#0ca8848562c7299b8b446ff6a4d60cdbb23edc40"
dependencies:
block-stream "*"
fstream "^1.0.12"
inherits "2"
text-table@~0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
through@^2.3.6:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
timers-browserify@^2.0.2:
version "2.0.4"
resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.4.tgz#96ca53f4b794a5e7c0e1bd7cc88a372298fa01e6"
dependencies:
setimmediate "^1.0.4"
to-arraybuffer@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
to-fast-properties@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
tough-cookie@~2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
dependencies:
psl "^1.1.28"
punycode "^2.1.1"
trim-newlines@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
trim-right@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
"true-case-path@^1.0.2":
version "1.0.3"
resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.3.tgz#f813b5a8c86b40da59606722b144e3225799f47d"
dependencies:
glob "^7.1.2"
tryit@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb"
tty-browserify@0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
tunnel-agent@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
dependencies:
safe-buffer "^5.0.1"
tweetnacl@^0.14.3, tweetnacl@~0.14.0:
version "0.14.5"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
type-check@~0.3.2:
version "0.3.2"
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
dependencies:
prelude-ls "~1.1.2"
typedarray@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
ua-parser-js@^0.7.9:
version "0.7.28"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.28.tgz#8ba04e653f35ce210239c64661685bf9121dec31"
uglify-js@^2.8.27:
version "2.8.29"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd"
dependencies:
source-map "~0.5.1"
yargs "~3.10.0"
optionalDependencies:
uglify-to-browserify "~1.0.0"
uglify-to-browserify@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
uid-number@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
underscore.string@~2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.4.0.tgz#8cdd8fbac4e2d2ea1e7e2e8097c42f442280f85b"
underscore@~1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.7.0.tgz#6bbaf0877500d36be34ecaa584e0db9fef035209"
uniq@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
uniqid@^4.0.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/uniqid/-/uniqid-4.1.1.tgz#89220ddf6b751ae52b5f72484863528596bb84c1"
dependencies:
macaddress "^0.2.8"
uniqs@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02"
universalify@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7"
uri-js@^4.2.2:
version "4.4.1"
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
dependencies:
punycode "^2.1.0"
urix@^0.1.0, urix@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
url-loader@^0.5.8:
version "0.5.9"
resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-0.5.9.tgz#cc8fea82c7b906e7777019250869e569e995c295"
dependencies:
loader-utils "^1.0.2"
mime "1.3.x"
url@^0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
dependencies:
punycode "1.3.2"
querystring "0.2.0"
user-home@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f"
dependencies:
os-homedir "^1.0.0"
util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
util@0.10.3, util@^0.10.3:
version "0.10.3"
resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
dependencies:
inherits "2.0.1"
uuid@^3.3.2:
version "3.4.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
validate-npm-package-license@^3.0.1:
version "3.0.4"
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
dependencies:
spdx-correct "^3.0.0"
spdx-expression-parse "^3.0.0"
vendors@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.1.tgz#37ad73c8ee417fb3d580e785312307d274847f22"
verror@1.10.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
dependencies:
assert-plus "^1.0.0"
core-util-is "1.0.2"
extsprintf "^1.2.0"
vm-browserify@0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73"
dependencies:
indexof "0.0.1"
watchpack@^1.3.1:
version "1.4.0"
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.4.0.tgz#4a1472bcbb952bd0a9bb4036801f954dfb39faac"
dependencies:
async "^2.1.2"
chokidar "^1.7.0"
graceful-fs "^4.1.2"
webpack-sources@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.0.1.tgz#c7356436a4d13123be2e2426a05d1dad9cbe65cf"
dependencies:
source-list-map "^2.0.0"
source-map "~0.5.3"
webpack@^2.6.1:
version "2.7.0"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-2.7.0.tgz#b2a1226804373ffd3d03ea9c6bd525067034f6b1"
dependencies:
acorn "^5.0.0"
acorn-dynamic-import "^2.0.0"
ajv "^4.7.0"
ajv-keywords "^1.1.1"
async "^2.1.2"
enhanced-resolve "^3.3.0"
interpret "^1.0.0"
json-loader "^0.5.4"
json5 "^0.5.1"
loader-runner "^2.3.0"
loader-utils "^0.2.16"
memory-fs "~0.4.1"
mkdirp "~0.5.0"
node-libs-browser "^2.0.0"
source-map "^0.5.3"
supports-color "^3.1.0"
tapable "~0.2.5"
uglify-js "^2.8.27"
watchpack "^1.3.1"
webpack-sources "^1.0.1"
yargs "^6.0.0"
whatwg-fetch@>=0.10.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
whet.extend@~0.9.9:
version "0.9.9"
resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1"
which-module@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
which-module@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
which@1, which@^1.2.9:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
dependencies:
isexe "^2.0.0"
wide-align@^1.1.0:
version "1.1.3"
resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
dependencies:
string-width "^1.0.2 || 2"
window-size@0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
wordwrap@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
wordwrap@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
wrap-ansi@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
dependencies:
string-width "^1.0.1"
strip-ansi "^3.0.1"
wrap-ansi@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09"
dependencies:
ansi-styles "^3.2.0"
string-width "^3.0.0"
strip-ansi "^5.0.0"
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
write@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757"
dependencies:
mkdirp "^0.5.1"
xtend@^4.0.0:
version "4.0.2"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
y18n@^3.2.1:
version "3.2.2"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.2.tgz#85c901bd6470ce71fc4bb723ad209b70f7f28696"
y18n@^4.0.0:
version "4.0.3"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf"
yallist@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
yargs-parser@^13.1.2:
version "13.1.2"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38"
dependencies:
camelcase "^5.0.0"
decamelize "^1.2.0"
yargs-parser@^4.2.0:
version "4.2.1"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c"
dependencies:
camelcase "^3.0.0"
yargs-parser@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a"
dependencies:
camelcase "^3.0.0"
yargs@7.0.2:
version "7.0.2"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.0.2.tgz#115b97df1321823e8b8648e8968c782521221f67"
dependencies:
camelcase "^3.0.0"
cliui "^3.2.0"
decamelize "^1.1.1"
get-caller-file "^1.0.1"
os-locale "^1.4.0"
read-pkg-up "^1.0.1"
require-directory "^2.1.1"
require-main-filename "^1.0.1"
set-blocking "^2.0.0"
string-width "^1.0.2"
which-module "^1.0.0"
y18n "^3.2.1"
yargs-parser "^5.0.0"
yargs@^13.3.2:
version "13.3.2"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd"
dependencies:
cliui "^5.0.0"
find-up "^3.0.0"
get-caller-file "^2.0.1"
require-directory "^2.1.1"
require-main-filename "^2.0.0"
set-blocking "^2.0.0"
string-width "^3.0.0"
which-module "^2.0.0"
y18n "^4.0.0"
yargs-parser "^13.1.2"
yargs@^6.0.0:
version "6.6.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208"
dependencies:
camelcase "^3.0.0"
cliui "^3.2.0"
decamelize "^1.1.1"
get-caller-file "^1.0.1"
os-locale "^1.4.0"
read-pkg-up "^1.0.1"
require-directory "^2.1.1"
require-main-filename "^1.0.1"
set-blocking "^2.0.0"
string-width "^1.0.2"
which-module "^1.0.0"
y18n "^3.2.1"
yargs-parser "^4.2.0"
yargs@~3.10.0:
version "3.10.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"
dependencies:
camelcase "^1.0.2"
cliui "^2.1.0"
decamelize "^1.0.0"
window-size "0.1.0"