Compare commits
66 Commits
Author | SHA1 | Date |
---|---|---|
github-actions | 9b79699dcc | |
Guy Sartorelli | bb3eec1160 | |
github-actions | 5f04e466d2 | |
Guy Sartorelli | 20d61d7d87 | |
Michal Kleiner | b6ce505e12 | |
Michal Kleiner | 9fe83e948d | |
Michal Kleiner | 2e22bd4900 | |
Michal Kleiner | 32e7929f01 | |
Michal Kleiner | 27e0f8f517 | |
Guy Sartorelli | 72e4321696 | |
Steve Boyd | b6e00e9528 | |
Guy Sartorelli | d13bebf999 | |
Guy Sartorelli | ad33d32066 | |
Sabina Talipova | c39e588306 | |
Guy Sartorelli | f9dc2e537d | |
Sabina Talipova | 36d3718581 | |
Sabina Talipova | 24766e4e5a | |
Guy Sartorelli | 77bb69f74c | |
Maxime Rainville | b5e468a266 | |
Steve Boyd | f1f6abca67 | |
Nicolaas / Sunny Side Up | 4324836cb7 | |
Guy Sartorelli | 47769763db | |
Guy Sartorelli | 884a846167 | |
Guy Sartorelli | ff723b58ef | |
Guy Sartorelli | 18828ed094 | |
Steve Boyd | e8a41d96e5 | |
dependabot[bot] | 179e9d0cf2 | |
dependabot[bot] | 48c40a542e | |
dependabot[bot] | 0b32166a1a | |
dependabot[bot] | 013a5c34e7 | |
dependabot[bot] | fad0c2b4b4 | |
dependabot[bot] | 63024cb902 | |
Sabina Talipova | a6c7030274 | |
Steve Boyd | 6f18e92169 | |
Guy Sartorelli | 7eb81fd449 | |
Sabina Talipova | 495e7460db | |
Sabina Talipova | 55d52cb7dc | |
Maxime Rainville | dbd9099d3d | |
Guy Sartorelli | 6f5edab1ad | |
Guy Sartorelli | 1123d26477 | |
Maxime Rainville | 566a9e7d0e | |
Steve Boyd | 422647b724 | |
Steve Boyd | 774c8343c7 | |
Guy Sartorelli | 562e882072 | |
Steve Boyd | 9d4381554a | |
Guy Sartorelli | c5cd5c5ff3 | |
Steve Boyd | 31c81bf093 | |
Steve Boyd | 675d094731 | |
Steve Boyd | 03ee0d0559 | |
Guy Sartorelli | e2bf86414e | |
Steve Boyd | 0dd255303d | |
Guy Sartorelli | f93687a53d | |
Steve Boyd | 4cafa687ae | |
Mo Alsharaf | 1cf0f01a35 | |
Steve Boyd | c1c47583b1 | |
Steve Boyd | 3359ab477e | |
dependabot[bot] | 917c63467e | |
dependabot[bot] | 69cf355d9f | |
Guy Sartorelli | 9f7b0e2169 | |
Steve Boyd | 856660192b | |
Maxime Rainville | 5e313dd7fc | |
Steve Boyd | 3447883c3c | |
Guy Sartorelli | 141e8d0bf3 | |
Maxime Rainville | 46a637a6a8 | |
Steve Boyd | 7def6f8c2a | |
Steve Boyd | a821edf8d7 |
|
@ -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
|
|
@ -1,13 +1,14 @@
|
|||
name: Build Docs
|
||||
name: Deploy Userhelp Docs
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- '5'
|
||||
- '4'
|
||||
paths:
|
||||
- 'docs/en/userguide/**'
|
||||
jobs:
|
||||
build:
|
||||
name: build-docs
|
||||
deploy:
|
||||
name: deploy-userhelp-docs
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Run build hook
|
|
@ -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
|
|
@ -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
|
|
@ -1,11 +0,0 @@
|
|||
name: Module CI
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
uses: silverstripe/github-actions-ci-cd/.github/workflows/ci.yml@0.1.11
|
||||
with:
|
||||
run_endtoend: true
|
|
@ -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
|
|
@ -1,10 +1,7 @@
|
|||
# sass-lint config to match the AirBNB style guide
|
||||
# See silverstripe-admin
|
||||
files:
|
||||
include: '**/client/src/**/*.scss'
|
||||
ignore:
|
||||
- 'client/src/styles/legacy/*'
|
||||
- 'src/**/*'
|
||||
include: client/src/**/*.scss'
|
||||
options:
|
||||
formatter: stylish
|
||||
merge-default-rules: false
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
inherit: true
|
||||
|
||||
checks:
|
||||
php:
|
||||
code_rating: true
|
||||
duplication: true
|
||||
|
||||
filter:
|
||||
paths: [src/*, tests/*]
|
|
@ -1,9 +0,0 @@
|
|||
version: ~> 1.0
|
||||
|
||||
import:
|
||||
- silverstripe/silverstripe-travis-shared:config/provision/standard-jobs-range-behat.yml
|
||||
|
||||
env:
|
||||
global:
|
||||
- BEHAT_SUITE="contentreview"
|
||||
- REQUIRE_EXTRA="symbiote/silverstripe-queuedjobs:^4"
|
|
@ -1,14 +1,15 @@
|
|||
[main]
|
||||
host = https://www.transifex.com
|
||||
|
||||
[silverstripe-contentreview.master]
|
||||
[o:silverstripe:p:silverstripe-contentreview:r:master]
|
||||
file_filter = lang/<lang>.yml
|
||||
source_file = lang/en.yml
|
||||
source_lang = en
|
||||
type = YML
|
||||
type = YML
|
||||
|
||||
[silverstripe-contentreview.master-js]
|
||||
[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
|
||||
type = KEYVALUEJSON
|
||||
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
# Content Review module
|
||||
|
||||
[![Build Status](https://api.travis-ci.com/silverstripe/silverstripe-contentreview.svg?branch=4)](https://travis-ci.com/silverstripe/silverstripe-contentreview)
|
||||
[![SilverStripe supported module](https://img.shields.io/badge/silverstripe-supported-0071C4.svg)](https://www.silverstripe.org/software/addons/silverstripe-commercially-supported-module-list/)
|
||||
[![Code quality](https://scrutinizer-ci.com/g/silverstripe/silverstripe-contentreview/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/silverstripe/silverstripe-contentreview/?branch=master)
|
||||
[![Code coverage](https://codecov.io/gh/silverstripe/silverstripe-contentreview/branch/master/graph/badge.svg)](https://codecov.io/gh/silverstripe/silverstripe-contentreview)
|
||||
[![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.
|
||||
|
||||
|
@ -17,9 +15,9 @@ There are two types of roles with this module.
|
|||
|
||||
## Requirements
|
||||
|
||||
* SilverStripe ^4.0
|
||||
* Silverstripe ^4.0
|
||||
|
||||
**Note:** For SilverStripe 3.x, please use the [3.x release line](https://github.com/silverstripe/silverstripe-contentreview/tree/3).
|
||||
**Note:** For Silverstripe 3.x, please use the [3.x release line](https://github.com/silverstripe/silverstripe-contentreview/tree/3).
|
||||
|
||||
## Features
|
||||
|
|
@ -1 +0,0 @@
|
|||
{"version":3,"sources":["webpack:///./client/src/styles/ContentReviewForm.scss?a3bd","webpack:///./bundle.scss?6663"],"names":[],"mappings":"AAEA,wBACE,uDACA,wBACA,qBACA,YACA,sBACA,UACA,oBACA,WCDD,4DDKG,4BCAH","file":"styles/contentreview.css","sourcesContent":["// The bell button, shows up next to the major actions (save, publish, etc) when\n// viewing a page in the CMS\n.content-review__button {\n background: url(\"images/icon-bell.png\") center center no-repeat;\n background-position: 0 0;\n display: inline-block;\n height: 20px;\n margin: 6px 4px 0 12px;\n padding: 0;\n text-indent: -9999px;\n width: 20px;\n\n &:hover,\n &:focus {\n background-position: 0 -20px;\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./client/src/styles/ContentReviewForm.scss",".content-review__button {\n background: url(\"../images/icon-bell.png\") center center no-repeat;\n background-position: 0 0;\n display: inline-block;\n height: 20px;\n margin: 6px 4px 0 12px;\n padding: 0;\n text-indent: -9999px;\n width: 20px;\n}\n\n.content-review__button:hover,\n.content-review__button:focus {\n background-position: 0 -20px;\n}\n\n\n\n\n// WEBPACK FOOTER //\n// ./bundle.scss"],"sourceRoot":""}
|
|
@ -1,5 +1,5 @@
|
|||
// This file was generated by silverstripe/cow from client/lang/src/en.json.
|
||||
// See https://github.com/tractorcow/cow for details
|
||||
// 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
|
||||
|
|
|
@ -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"
|
||||
});
|
||||
}
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"ContentReview.CONTENT_DUE_FOR_REVIEW": "Content due for review"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"ContentReview.CONTENT_DUE_FOR_REVIEW": "Obsah určený na kontrolu"
|
||||
}
|
|
@ -7,7 +7,10 @@
|
|||
"keywords": [
|
||||
"silverstripe",
|
||||
"cms",
|
||||
"workflow"
|
||||
"workflow",
|
||||
"content review",
|
||||
"review",
|
||||
"permissions"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
|
@ -20,7 +23,7 @@
|
|||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^7.3 || ^8.0",
|
||||
"php": "^7.4 || ^8.0",
|
||||
"silverstripe/vendor-plugin": "^1",
|
||||
"silverstripe/framework": "^4.10",
|
||||
"silverstripe/cms": "^4.2",
|
||||
|
@ -29,7 +32,8 @@
|
|||
},
|
||||
"require-dev": {
|
||||
"silverstripe/recipe-testing": "^2",
|
||||
"squizlabs/php_codesniffer": "^3"
|
||||
"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"
|
||||
|
@ -48,4 +52,4 @@
|
|||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
}
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
---
|
||||
title: Content review
|
||||
summary: Mark pages in the CMS with a date and an owner for future reviews.
|
||||
---
|
||||
|
||||
## Content review
|
||||
|
||||
|
|
19
lang/en.yml
19
lang/en.yml
|
@ -15,6 +15,14 @@ en:
|
|||
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'
|
||||
|
@ -34,6 +42,14 @@ en:
|
|||
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'
|
||||
|
@ -46,6 +62,9 @@ en:
|
|||
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'
|
||||
|
|
|
@ -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'
|
|
@ -39,6 +39,6 @@
|
|||
"eslint-config-airbnb": "^6.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^6.x"
|
||||
"node": "^10.x"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit bootstrap="vendor/silverstripe/cms/tests/bootstrap.php" colors="true">
|
||||
<testsuites>
|
||||
<testsuite name="Default">
|
||||
|
|
|
@ -6,10 +6,10 @@ 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\Core\Convert;
|
||||
use SilverStripe\Forms\Form;
|
||||
use SilverStripe\ORM\ValidationResult;
|
||||
use SilverStripe\Security\Security;
|
||||
|
@ -20,6 +20,8 @@ use SilverStripe\Security\Security;
|
|||
*/
|
||||
class ContentReviewCMSExtension extends LeftAndMainExtension
|
||||
{
|
||||
use PermissionChecker;
|
||||
|
||||
private static $allowed_actions = [
|
||||
'ReviewContentForm',
|
||||
'savereview',
|
||||
|
@ -48,7 +50,7 @@ class ContentReviewCMSExtension extends LeftAndMainExtension
|
|||
{
|
||||
$page = $this->findRecord(['ID' => $id]);
|
||||
$user = Security::getCurrentUser();
|
||||
if (!$page->canEdit() || ($page->hasMethod('canBeReviewedBy') && !$page->canBeReviewedBy($user))) {
|
||||
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'
|
||||
|
|
|
@ -130,6 +130,7 @@ class ContentReviewDefaultSettings extends DataExtension
|
|||
|
||||
$users = Permission::get_members_by_permission([
|
||||
'CMS_ACCESS_CMSMain',
|
||||
'CMS_ACCESS_LeftAndMain',
|
||||
'ADMIN',
|
||||
]);
|
||||
|
||||
|
|
|
@ -132,13 +132,13 @@ class SiteTreeContentReview extends DataExtension implements PermissionProvider
|
|||
$familyIDs = $group->collateFamilyIDs();
|
||||
|
||||
if (is_array($familyIDs)) {
|
||||
$groupIDs = array_merge($groupIDs, array_values($familyIDs));
|
||||
$groupIDs = array_merge($groupIDs, array_values($familyIDs ?? []));
|
||||
}
|
||||
}
|
||||
|
||||
array_unique($groupIDs);
|
||||
array_unique($groupIDs ?? []);
|
||||
|
||||
if (count($groupIDs)) {
|
||||
if (count($groupIDs ?? [])) {
|
||||
$groupMembers = DataObject::get(Member::class)
|
||||
->where("\"Group\".\"ID\" IN (" . implode(",", $groupIDs) . ")")
|
||||
->leftJoin("Group_Members", "\"Member\".\"ID\" = \"Group_Members\".\"MemberID\"")
|
||||
|
@ -397,7 +397,7 @@ class SiteTreeContentReview extends DataExtension implements PermissionProvider
|
|||
$options
|
||||
);
|
||||
|
||||
$users = Permission::get_members_by_permission(["CMS_ACCESS_CMSMain", "ADMIN"]);
|
||||
$users = Permission::get_members_by_permission(['CMS_ACCESS_CMSMain', 'CMS_ACCESS_LeftAndMain', 'ADMIN']);
|
||||
|
||||
$usersMap = $users->map("ID", "Title")->toArray();
|
||||
|
||||
|
@ -512,11 +512,11 @@ class SiteTreeContentReview extends DataExtension implements PermissionProvider
|
|||
*/
|
||||
public function canBeReviewedBy(Member $member = null)
|
||||
{
|
||||
if (!$this->owner->obj("NextReviewDate")->exists()) {
|
||||
if (!$this->owner->obj('NextReviewDate')->exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->owner->obj("NextReviewDate")->InFuture()) {
|
||||
if ($this->owner->obj('NextReviewDate')->InFuture()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -542,6 +542,11 @@ class SiteTreeContentReview extends DataExtension implements PermissionProvider
|
|||
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;
|
||||
}
|
||||
|
@ -676,7 +681,7 @@ class SiteTreeContentReview extends DataExtension implements PermissionProvider
|
|||
$runHour = Config::inst()->get(ContentReviewNotificationJob::class, "first_run_hour");
|
||||
$firstRunTime = date(
|
||||
"Y-m-d H:i:s",
|
||||
mktime($runHour, 0, 0, date("m"), date("d") + 1, date("y"))
|
||||
mktime($runHour ?? 0, 0, 0, date("m"), date("d") + 1, date("y"))
|
||||
);
|
||||
|
||||
singleton(QueuedJobService::class)->queueJob(
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
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;
|
||||
|
@ -19,6 +20,7 @@ use SilverStripe\Security\Security;
|
|||
class ReviewContentHandler
|
||||
{
|
||||
use Injectable;
|
||||
use PermissionChecker;
|
||||
|
||||
/**
|
||||
* Parent controller for this form
|
||||
|
@ -120,12 +122,11 @@ class ReviewContentHandler
|
|||
*/
|
||||
public function canSubmitReview($record)
|
||||
{
|
||||
if (!$record->canEdit()
|
||||
|| !$record->hasMethod('canBeReviewedBy')
|
||||
|| !$record->canBeReviewedBy(Security::getCurrentUser())
|
||||
) {
|
||||
// Ensure the parameter of correct data type
|
||||
if (!$record instanceof DataObject) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
return $this->isContentReviewable($record, Security::getCurrentUser());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ class ContentReviewNotificationJob extends AbstractQueuedJob implements QueuedJo
|
|||
{
|
||||
$this->queueNextRun();
|
||||
|
||||
$task = new ContentReviewEmails();
|
||||
$task = ContentReviewEmails::create();
|
||||
$task->run(new HTTPRequest("GET", "/dev/tasks/ContentReviewEmails"));
|
||||
|
||||
$this->currentStep = 1;
|
||||
|
@ -108,7 +108,7 @@ class ContentReviewNotificationJob extends AbstractQueuedJob implements QueuedJo
|
|||
$nextRun = new ContentReviewNotificationJob();
|
||||
|
||||
$nextRunTime = mktime(
|
||||
Config::inst()->get(__CLASS__, 'next_run_hour'),
|
||||
Config::inst()->get(__CLASS__, 'next_run_hour') ?? 0,
|
||||
Config::inst()->get(__CLASS__, 'next_run_minute'),
|
||||
0,
|
||||
date("m"),
|
||||
|
|
|
@ -77,8 +77,8 @@ class PagesDueForReviewReport extends Report
|
|||
public function columns()
|
||||
{
|
||||
$linkBase = singleton(CMSPageEditController::class)->Link("show");
|
||||
$linkPath = parse_url($linkBase, PHP_URL_PATH);
|
||||
$linkQuery = parse_url($linkBase, PHP_URL_QUERY);
|
||||
$linkPath = parse_url($linkBase ?? '', PHP_URL_PATH);
|
||||
$linkQuery = parse_url($linkBase ?? '', PHP_URL_QUERY);
|
||||
|
||||
$fields = [
|
||||
"Title" => [
|
||||
|
@ -148,16 +148,26 @@ class PagesDueForReviewReport extends Report
|
|||
|
||||
/**
|
||||
* @param array $params
|
||||
* @param array|string|null $sort
|
||||
* @param int|null $limit
|
||||
*
|
||||
* @return SS_List
|
||||
*/
|
||||
public function sourceRecords($params = [])
|
||||
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(
|
||||
|
@ -172,7 +182,7 @@ class PagesDueForReviewReport extends Report
|
|||
// TODO Get value from DateField->dataValue() once we have access to form elements here
|
||||
$nextReviewUnixSec = strtotime(
|
||||
' + 1 day',
|
||||
strtotime($params['ReviewDateBefore'])
|
||||
strtotime($params['ReviewDateBefore'] ?? '')
|
||||
);
|
||||
$records = $records->where(
|
||||
sprintf(
|
||||
|
@ -199,7 +209,7 @@ class PagesDueForReviewReport extends Report
|
|||
$virtualPageClasses = ClassInfo::subclassesFor(VirtualPage::class);
|
||||
$records = $records->where(sprintf(
|
||||
"\"SiteTree\".\"ClassName\" NOT IN ('%s')",
|
||||
implode("','", array_values($virtualPageClasses))
|
||||
implode("','", array_values($virtualPageClasses ?? []))
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
@ -46,8 +46,8 @@ class PagesWithoutReviewScheduleReport extends Report
|
|||
public function columns()
|
||||
{
|
||||
$linkBase = singleton(CMSPageEditController::class)->Link("show");
|
||||
$linkPath = parse_url($linkBase, PHP_URL_PATH);
|
||||
$linkQuery = parse_url($linkBase, PHP_URL_QUERY);
|
||||
$linkPath = parse_url($linkBase ?? '', PHP_URL_PATH);
|
||||
$linkQuery = parse_url($linkBase ?? '', PHP_URL_QUERY);
|
||||
|
||||
$fields = [
|
||||
"Title" => [
|
||||
|
@ -104,10 +104,12 @@ class PagesWithoutReviewScheduleReport extends Report
|
|||
|
||||
/**
|
||||
* @param array $params
|
||||
* @param array|string|null $sort
|
||||
* @param int|null $limit
|
||||
*
|
||||
* @return SS_List
|
||||
*/
|
||||
public function sourceRecords($params = [])
|
||||
public function sourceRecords($params = [], $sort = null, $limit = null)
|
||||
{
|
||||
Versioned::set_stage(Versioned::DRAFT);
|
||||
|
||||
|
@ -121,20 +123,22 @@ class PagesWithoutReviewScheduleReport extends Report
|
|||
$virtualPageClasses = ClassInfo::subclassesFor(VirtualPage::class);
|
||||
$records = $records->where(sprintf(
|
||||
"\"SiteTree\".\"ClassName\" NOT IN ('%s')",
|
||||
implode("','", array_values($virtualPageClasses))
|
||||
implode("','", array_values($virtualPageClasses ?? []))
|
||||
));
|
||||
}
|
||||
|
||||
$records->sort("ParentID");
|
||||
$records = $records->toArray();
|
||||
// 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 = ArrayList::create();
|
||||
foreach ($records as $record) {
|
||||
if (!$this->hasReviewSchedule($record)) {
|
||||
$list->push($record);
|
||||
}
|
||||
}
|
||||
$list = $records->filterByCallback(function ($record) {
|
||||
return !$this->hasReviewSchedule($record);
|
||||
});
|
||||
|
||||
ContentReviewCompatability::done($compatibility);
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace SilverStripe\ContentReview\Tasks;
|
||||
|
||||
use Page;
|
||||
use RuntimeException;
|
||||
use SilverStripe\ContentReview\Compatibility\ContentReviewCompatability;
|
||||
use SilverStripe\Control\Email\Email;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
|
@ -15,18 +16,29 @@ use SilverStripe\Security\Member;
|
|||
use SilverStripe\SiteConfig\SiteConfig;
|
||||
use SilverStripe\View\ArrayData;
|
||||
use SilverStripe\View\SSViewer;
|
||||
use SilverStripe\ContentReview\Models\ContentReviewLog;
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -42,6 +54,16 @@ class ContentReviewEmails extends BuildTask
|
|||
}
|
||||
|
||||
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)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -93,6 +115,13 @@ class ContentReviewEmails extends BuildTask
|
|||
// 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
|
||||
|
@ -159,4 +188,12 @@ class ContentReviewEmails extends BuildTask
|
|||
'ToEmail' => $recipient->Email,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check validity of email
|
||||
*/
|
||||
protected function isValidEmail(?string $email): bool
|
||||
{
|
||||
return (bool) filter_var($email, FILTER_VALIDATE_EMAIL);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -6,14 +6,17 @@ Feature: Set up reviews
|
|||
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" "EDITOR group" has permissions "CMS_ACCESS_LeftAndMain" and "FILE_EDIT_ALL"
|
||||
And the "group" "FILEONLY group" has permissions "FILE_EDIT_ALL"
|
||||
And a "member" "Ed" belonging to "EDITOR group" with "Email"="ed@example.com"
|
||||
And a "member" "Phil" belonging to "FILEONLY group" with "Email"="phil@example.com"
|
||||
# Login in as EDITOR once https://github.com/silverstripe/silverstripe-contentreview/pull/155 is merged
|
||||
# And I am logged in with "EDITOR" permissions
|
||||
And I am logged in with "ADMIN" permissions
|
||||
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
|
||||
|
@ -24,10 +27,11 @@ Feature: Set up reviews
|
|||
|
||||
# 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 group" label
|
||||
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
|
||||
|
@ -37,7 +41,7 @@ Feature: Set up reviews
|
|||
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 "ADMIN group" from "Groups"
|
||||
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
|
||||
|
|
|
@ -6,7 +6,8 @@ Feature: Set up reviews
|
|||
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 I am logged in with "ADMIN" permissions
|
||||
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
|
||||
|
@ -18,7 +19,7 @@ Feature: Set up reviews
|
|||
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 "ADMIN group" from "Groups"
|
||||
And I select "EDITOR" from "Groups"
|
||||
And I press "Save"
|
||||
Then I should see a "Content due for review" button
|
||||
|
||||
|
@ -29,7 +30,7 @@ Feature: Set up reviews
|
|||
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 "ADMIN group" from "Groups"
|
||||
And I select "EDITOR" from "Groups"
|
||||
And I press "Save"
|
||||
And I follow "Content due for review"
|
||||
And I wait for 3 seconds
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace SilverStripe\ContentReview\Tests;
|
||||
|
||||
use Page;
|
||||
use ReflectionClass;
|
||||
use SilverStripe\CMS\Model\SiteTree;
|
||||
use SilverStripe\CMS\Controllers\CMSPageEditController;
|
||||
use SilverStripe\ContentReview\Extensions\ContentReviewCMSExtension;
|
||||
|
@ -132,6 +133,26 @@ class ContentReviewNotificationTest extends SapphireTest
|
|||
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
|
||||
*
|
||||
|
|
|
@ -87,11 +87,11 @@ class ContentReviewReportTest extends FunctionalTest
|
|||
|
||||
$results = $report->sourceRecords();
|
||||
|
||||
$this->assertEquals([
|
||||
"Home",
|
||||
"About Us",
|
||||
"Page without review date",
|
||||
"Page owned by group",
|
||||
], $results->column("Title"));
|
||||
$this->assertListEquals([
|
||||
['Title' => 'Home'],
|
||||
['Title' => 'About Us'],
|
||||
['Title' => 'Page without review date'],
|
||||
['Title' => 'Page owned by group'],
|
||||
], $results);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace SilverStripe\ContentReview\Tests\Extensions;
|
||||
|
||||
use SilverStripe\CMS\Model\SiteTree;
|
||||
use SilverStripe\ContentReview\Extensions\ContentReviewCMSExtension;
|
||||
use SilverStripe\ContentReview\Forms\ReviewContentHandler;
|
||||
use SilverStripe\Control\Controller;
|
||||
|
@ -50,7 +51,7 @@ class ContentReviewCMSExtensionTest extends SapphireTest
|
|||
$mock->setOwner(new Controller);
|
||||
|
||||
// Return a DataObject without the content review extension applied
|
||||
$mock->expects($this->once())->method('findRecord')->with(['ID' => 123])->willReturn(new Member);
|
||||
$mock->expects($this->once())->method('findRecord')->with(['ID' => 123])->willReturn(new SiteTree);
|
||||
|
||||
$mock->getReviewContentForm(123);
|
||||
}
|
||||
|
|
|
@ -45,6 +45,13 @@ class ReviewContentHandlerTest extends SapphireTest
|
|||
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');
|
||||
|
|
|
@ -9,6 +9,7 @@ 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;
|
||||
|
@ -16,6 +17,7 @@ use SilverStripe\Security\Group;
|
|||
use SilverStripe\Security\Member;
|
||||
use SilverStripe\SiteConfig\SiteConfig;
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
use SilverStripe\ORM\ArrayList;
|
||||
|
||||
class SiteTreeContentReviewTest extends ContentReviewBaseTest
|
||||
{
|
||||
|
@ -53,7 +55,7 @@ class SiteTreeContentReviewTest extends ContentReviewBaseTest
|
|||
$page->write();
|
||||
|
||||
$this->assertTrue($page->canPublish());
|
||||
$this->assertTrue($page->doPublish());
|
||||
$this->assertTrue($page->publishRecursive());
|
||||
$this->assertEquals($page->OwnerNames, "Test Editor", "Test Editor should be the owner");
|
||||
|
||||
/** @var Page|SiteTreeContentReview $page */
|
||||
|
@ -117,7 +119,7 @@ class SiteTreeContentReviewTest extends ContentReviewBaseTest
|
|||
$page->ReviewPeriodDays = 10;
|
||||
$page->write();
|
||||
|
||||
$this->assertTrue($page->doPublish());
|
||||
$this->assertTrue($page->publishRecursive());
|
||||
$this->assertEquals(null, $page->NextReviewDate);
|
||||
}
|
||||
|
||||
|
@ -365,4 +367,38 @@ class SiteTreeContentReviewTest extends ContentReviewBaseTest
|
|||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
20
yarn.lock
20
yarn.lock
|
@ -253,10 +253,10 @@ async-foreach@^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.5.0"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-2.5.0.tgz#843190fd6b7357a0b9e1c956edddd5ec8462b54d"
|
||||
version "2.6.4"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221"
|
||||
dependencies:
|
||||
lodash "^4.14.0"
|
||||
lodash "^4.17.14"
|
||||
|
||||
asynckit@^0.4.0:
|
||||
version "0.4.0"
|
||||
|
@ -1392,8 +1392,8 @@ date-now@^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.8"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc"
|
||||
version "2.6.9"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
|
@ -2733,7 +2733,7 @@ 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.14.0, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@~4.17.10:
|
||||
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"
|
||||
|
||||
|
@ -2860,8 +2860,8 @@ minimalistic-crypto-utils@^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.4"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
|
||||
version "3.0.8"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.8.tgz#5e6a59bd11e2ab0de1cfb843eb2d82e546c321c1"
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
|
@ -3650,8 +3650,8 @@ q@^1.1.2:
|
|||
resolved "https://registry.yarnpkg.com/q/-/q-1.5.0.tgz#dd01bac9d06d30e6f219aecb8253ee9ebdc308f1"
|
||||
|
||||
qs@~6.5.2:
|
||||
version "6.5.2"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
|
||||
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"
|
||||
|
|
Loading…
Reference in New Issue