mirror of
https://github.com/silverstripe/silverstripe-contentreview
synced 2024-10-22 17:05:47 +02:00
Adding default setting to the SiteConfig, broken email and tests though.
This commit is contained in:
parent
f673815eff
commit
78d84a57c6
@ -9,4 +9,7 @@ Member:
|
||||
- ContentReviewOwner
|
||||
CMSPageEditController:
|
||||
extensions:
|
||||
- ContentReviewCMSExtension
|
||||
- ContentReviewCMSExtension
|
||||
SiteConfig:
|
||||
extensions:
|
||||
- ContentReviewDefaultSettings
|
@ -4,10 +4,19 @@
|
||||
* Daily task to send emails to the owners of content items
|
||||
* when the review date rolls around
|
||||
*
|
||||
*
|
||||
* @todo create a page cache for the inherited so that we dont unneccesary need to look up parent pages
|
||||
* @package contentreview
|
||||
*/
|
||||
class ContentReviewEmails extends BuildTask {
|
||||
|
||||
/**
|
||||
* Holds a cached array for looking up members via their ID
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $member_cache = array();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param SS_HTTPRequest $request
|
||||
@ -21,52 +30,160 @@ class ContentReviewEmails extends BuildTask {
|
||||
|
||||
$now = class_exists('SS_Datetime') ? SS_Datetime::now()->URLDate() : SSDatetime::now()->URLDate();
|
||||
|
||||
// First grab all the pages with a custom setting
|
||||
$pages = Page::get('Page')
|
||||
->leftJoin('Group_SiteTreeContentReview', '"SiteTree"."ID" = "OwnerGroups"."SiteTreeID"', 'OwnerGroups')
|
||||
->leftJoin('Member_SiteTreeContentReview', '"SiteTree"."ID" = "OwnerUsers"."SiteTreeID"', "OwnerUsers")
|
||||
->where('"SiteTree"."NextReviewDate" <= \''.$now.'\' AND' .' ("OwnerGroups"."ID" IS NOT NULL OR "OwnerUsers"."ID" IS NOT NULL)')
|
||||
->where('"SiteTree"."ContentReviewType" != \'Custom\' AND "SiteTree"."NextReviewDate" <= \''.$now.'\' AND' .
|
||||
' ("OwnerGroups"."ID" IS NOT NULL OR "OwnerUsers"."ID" IS NOT NULL)')
|
||||
;
|
||||
|
||||
if ($pages && $pages->Count()) {
|
||||
foreach($pages as $page) {
|
||||
$owners = $page->ContentReviewOwners();
|
||||
if(!$owners->count()) {
|
||||
continue;
|
||||
}
|
||||
$sender = Security::findAnAdministrator();
|
||||
|
||||
foreach($owners as $recipient) {
|
||||
$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/pages/edit/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();
|
||||
|
||||
$message = '<strong>'._t('ContentReviewEmails.EMAIL_HEADING','Page due for review').'</strong><br/>'.
|
||||
'The page "'.$page->Title.'" is due for review today by you.<br/>
|
||||
<a href="admin/pages/edit/show/'.$page->ID.'">'. _t('ContentReviewEmails.REVIEWPAGELINK','Review the page in the CMS') .'</a> —
|
||||
<a href="#">'. _t('ContentReviewEmails.VIEWPUBLISHEDLINK','View this page on the website') .'</a>';
|
||||
if(class_exists('Notification')) {
|
||||
Notification::notify($recipient, $message);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->notify($pages);
|
||||
|
||||
// Then grab all the pages with that inherits their settings
|
||||
|
||||
$pages = Page::get('Page')
|
||||
->leftJoin('Group_SiteTreeContentReview', '"SiteTree"."ID" = "OwnerGroups"."SiteTreeID"', 'OwnerGroups')
|
||||
->leftJoin('Member_SiteTreeContentReview', '"SiteTree"."ID" = "OwnerUsers"."SiteTreeID"', "OwnerUsers")
|
||||
->where('"SiteTree"."ContentReviewType" = \'Inherit\'')
|
||||
;
|
||||
|
||||
$overduePages = $this->findInheritedSettings($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->notify_user($memberID, $pages);
|
||||
}
|
||||
|
||||
// Revert subsite filter (if installed)
|
||||
if (ClassInfo::exists('Subsite')) {
|
||||
if(ClassInfo::exists('Subsite')) {
|
||||
Subsite::$disable_subsite_filter = $oldSubsiteState;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param SS_list $pages
|
||||
* @return type
|
||||
*/
|
||||
protected function findInheritedSettings(SS_list $pages) {
|
||||
$overduePages = array();
|
||||
|
||||
foreach($pages as $page) {
|
||||
|
||||
$settings = $this->findContentSettingFor($page);
|
||||
// This page has a parent with the 'Disabled' option
|
||||
if(!$settings) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$owners = $settings->ContentReviewOwners();
|
||||
if(!$owners->count()) {
|
||||
continue;
|
||||
}
|
||||
if(!$settings->ReviewPeriodDays) {
|
||||
continue;
|
||||
}
|
||||
// Calculate next time this page should be reviewed from the LastEdited datea
|
||||
$nextReviewUnixSec = strtotime($page->LastEdited . ' + '.$settings->ReviewPeriodDays . ' days');
|
||||
if($nextReviewUnixSec > time()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach($owners as $owner) {
|
||||
if(!isset(self::$member_cache[$owner->ID])) {
|
||||
self::$member_cache[$owner->ID] = $owner;
|
||||
}
|
||||
if(!isset($overduePages[$owner->ID])) {
|
||||
$overduePages[$owner->ID] = array();
|
||||
}
|
||||
$overduePages[$owner->ID][] = $page;
|
||||
}
|
||||
}
|
||||
return $overduePages;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param SiteTree $page
|
||||
* @return DataObject or false if no settings found
|
||||
*/
|
||||
protected function findContentSettingFor($page) {
|
||||
while($parent = $page->Parent()) {
|
||||
// Root page, use siteconfig
|
||||
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 shouldnt really happen, as usual.');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param int $owner
|
||||
* @param array $pages
|
||||
*/
|
||||
protected function notify_user($ownerID, array $pages) {
|
||||
$owner = self::$member_cache[$ownerID];
|
||||
echo $owner->Email.PHP_EOL;
|
||||
foreach($pages as $page) {
|
||||
echo $page->Title.PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param SS_List $pages
|
||||
* @return void
|
||||
*/
|
||||
protected function notify(SS_List $pages) {
|
||||
if(!$pages) {
|
||||
return;
|
||||
}
|
||||
if(!$pages->Count()) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach($pages as $page) {
|
||||
// Resolve the content owner groups and members to a single list of members
|
||||
$owners = $page->ContentReviewOwners();
|
||||
if(!$owners->count()) {
|
||||
continue;
|
||||
}
|
||||
$sender = Security::findAnAdministrator();
|
||||
|
||||
foreach($owners as $recipient) {
|
||||
$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/pages/edit/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();
|
||||
$message = '<strong>'._t('ContentReviewEmails.EMAIL_HEADING','Page due for review').'</strong><br/>'.
|
||||
'The page "'.$page->Title.'" is due for review today by you.<br/>
|
||||
<a href="admin/pages/edit/show/'.$page->ID.'">'. _t('ContentReviewEmails.REVIEWPAGELINK','Review the page in the CMS') .'</a> —
|
||||
<a href="#">'. _t('ContentReviewEmails.VIEWPUBLISHEDLINK','View this page on the website') .'</a>';
|
||||
if(class_exists('Notification')) {
|
||||
// Notification::notify($recipient, $message);
|
||||
}
|
||||
// echo $page->Title.' - '.$recipient->Email.PHP_EOL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
110
code/extensions/ContentReviewDefaultSettings.php
Normal file
110
code/extensions/ContentReviewDefaultSettings.php
Normal file
@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This extensions add a default schema for new pages and pages without a content review setting
|
||||
*
|
||||
*/
|
||||
class ContentReviewDefaultSettings extends DataExtension {
|
||||
|
||||
/**
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $db = array(
|
||||
"ReviewPeriodDays" => "Int",
|
||||
);
|
||||
|
||||
/**
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $many_many = array(
|
||||
'ContentReviewGroups' => 'Group',
|
||||
'ContentReviewUsers' => 'Member'
|
||||
);
|
||||
|
||||
/**
|
||||
* @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('ContentReview.DEFAULTSETTINGSHELP', 'These content review '
|
||||
. 'settings will apply to all pages that does not have specific Content Review schedule.'));
|
||||
$fields->addFieldToTab('Root.ContentReview', $helpText);
|
||||
|
||||
$reviewFrequency = DropdownField::create("ReviewPeriodDays", _t("ContentReview.REVIEWFREQUENCY", "Review frequency"), SiteTreeContentReview::get_schedule())
|
||||
->setDescription(_t('ContentReview.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(array("CMS_ACCESS_CMSMain", "ADMIN"));
|
||||
|
||||
$usersMap = $users->map('ID', 'Title')->toArray();
|
||||
asort($usersMap);
|
||||
|
||||
$userField = ListboxField::create('OwnerUsers', _t("ContentReview.PAGEOWNERUSERS", "Users"), $usersMap)
|
||||
->setMultiple(true)
|
||||
->setAttribute('data-placeholder', _t('ContentReview.ADDUSERS', 'Add users'))
|
||||
->setDescription(_t('ContentReview.OWNERUSERSDESCRIPTION', 'Page owners that are responsible for reviews'));
|
||||
$fields->addFieldToTab('Root.ContentReview', $userField);
|
||||
|
||||
$groupsMap = array();
|
||||
foreach(Group::get() as $group) {
|
||||
// Listboxfield values are escaped, use ASCII char instead of »
|
||||
$groupsMap[$group->ID] = $group->getBreadcrumbs(' > ');
|
||||
}
|
||||
asort($groupsMap);
|
||||
|
||||
$groupField = ListboxField::create('OwnerGroups', _t("ContentReview.PAGEOWNERGROUPS", "Groups"), $groupsMap)
|
||||
->setMultiple(true)
|
||||
->setAttribute('data-placeholder', _t('ContentReview.ADDGROUP', 'Add groups'))
|
||||
->setDescription(_t('ContentReview.OWNERGROUPSDESCRIPTION', 'Page owners that are responsible for reviews'));
|
||||
$fields->addFieldToTab('Root.ContentReview', $groupField);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all Members that are default Content Owners
|
||||
*
|
||||
* This includes checking group hierarchy and adding any direct users
|
||||
*
|
||||
* @return \ArrayList
|
||||
*/
|
||||
public function ContentReviewOwners() {
|
||||
$contentReviewOwners = new ArrayList();
|
||||
$toplevelGroups = $this->OwnerGroups();
|
||||
if($toplevelGroups->count()) {
|
||||
$groupIDs = array();
|
||||
foreach($toplevelGroups 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')->where("\"Group\".\"ID\" IN (" . implode(",",$groupIDs) . ")")
|
||||
->leftJoin("Group_Members", "\"Member\".\"ID\" = \"Group_Members\".\"MemberID\"")
|
||||
->leftJoin("Group", "\"Group_Members\".\"GroupID\" = \"Group\".\"ID\"");
|
||||
$contentReviewOwners->merge($groupMembers);
|
||||
}
|
||||
}
|
||||
$contentReviewOwners->merge($this->OwnerUsers());
|
||||
$contentReviewOwners->removeDuplicates();
|
||||
return $contentReviewOwners;
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@ class SiteTreeContentReview extends DataExtension implements PermissionProvider
|
||||
* @var array
|
||||
*/
|
||||
private static $db = array(
|
||||
"ContentReviewType" => "Enum('Inherit, Disabled, Custom', 'Inherit')",
|
||||
"ReviewPeriodDays" => "Int",
|
||||
"NextReviewDate" => "Date",
|
||||
'LastEditedByName' => 'Varchar(255)',
|
||||
@ -39,7 +40,7 @@ class SiteTreeContentReview extends DataExtension implements PermissionProvider
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $daysToString = array(
|
||||
private static $schedule = array(
|
||||
0 => "No automatic review date",
|
||||
1 => "1 day",
|
||||
7 => "1 week",
|
||||
@ -110,6 +111,13 @@ class SiteTreeContentReview extends DataExtension implements PermissionProvider
|
||||
return $contentReviewOwners;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function get_schedule() {
|
||||
return self::$schedule;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ManyManyList
|
||||
*/
|
||||
@ -130,17 +138,19 @@ class SiteTreeContentReview extends DataExtension implements PermissionProvider
|
||||
* @return void
|
||||
*/
|
||||
public function updateSettingsFields(FieldList $fields) {
|
||||
|
||||
Requirements::javascript('contentreview/javascript/contentreview.js');
|
||||
$crFields = new FieldList();
|
||||
|
||||
// Display read-only version only
|
||||
if(!Permission::check("EDIT_CONTENT_REVIEW_FIELDS")) {
|
||||
|
||||
$schedule = self::get_schedule();
|
||||
$contentOwners = ReadonlyField::create('ROContentOwners', _t('ContentReview.CONTENTOWNERS', 'Content Owners'), $this->getOwnerNames());
|
||||
$nextReviewAt = DateField::create('RONextReviewDate', _t("ContentReview.NEXTREVIEWDATE", "Next review date"), $this->owner->NextReviewDate);
|
||||
if(!isset($this->daysToString[$this->owner->ReviewPeriodDays])) {
|
||||
$reviewFreq = ReadonlyField::create("ROReviewPeriodDays", _t("ContentReview.REVIEWFREQUENCY", "Review frequency"), $this->daysToString[0]);
|
||||
if(!isset($schedule[$this->owner->ReviewPeriodDays])) {
|
||||
$reviewFreq = ReadonlyField::create("ROReviewPeriodDays", _t("ContentReview.REVIEWFREQUENCY", "Review frequency"), $schedule[0]);
|
||||
} else {
|
||||
$reviewFreq = ReadonlyField::create("ROReviewPeriodDays", _t("ContentReview.REVIEWFREQUENCY", "Review frequency"), $this->daysToString[$this->owner->ReviewPeriodDays]);
|
||||
$reviewFreq = ReadonlyField::create("ROReviewPeriodDays", _t("ContentReview.REVIEWFREQUENCY", "Review frequency"), $schedule[$this->owner->ReviewPeriodDays]);
|
||||
}
|
||||
|
||||
$logConfig = GridFieldConfig::create()
|
||||
@ -162,6 +172,17 @@ class SiteTreeContentReview extends DataExtension implements PermissionProvider
|
||||
return;
|
||||
}
|
||||
|
||||
$options = array();
|
||||
$options["Disabled"] = _t('ContentReview.DISABLE', "Disable content review");
|
||||
$options["Inherit"] = _t('ContentReview.INHERIT', "Inherit from parent page");
|
||||
$options["Custom"] = _t('ContentReview.CUSTOM', "Custom settings");
|
||||
$viewersOptionsField = OptionsetField::create("ContentReviewType", _t('ContentReview.OPTIONS', "Options"), $options);
|
||||
|
||||
//$viewersOptionsField->setValue($this->owner->ContentReviewType);
|
||||
|
||||
#var_dump($this->owner->ContentReviewType);
|
||||
#die();
|
||||
|
||||
$users = Permission::get_members_by_permission(array("CMS_ACCESS_CMSMain", "ADMIN"));
|
||||
|
||||
$usersMap = $users->map('ID', 'Title')->toArray();
|
||||
@ -190,19 +211,22 @@ class SiteTreeContentReview extends DataExtension implements PermissionProvider
|
||||
->setConfig('datavalueformat', 'yyyy-MM-dd')
|
||||
->setDescription(_t('ContentReview.NEXTREVIEWDATADESCRIPTION', 'Leave blank for no review'));
|
||||
|
||||
$reviewFrequency = DropdownField::create("ReviewPeriodDays", _t("ContentReview.REVIEWFREQUENCY", "Review frequency"), $this->daysToString)
|
||||
$reviewFrequency = DropdownField::create("ReviewPeriodDays", _t("ContentReview.REVIEWFREQUENCY", "Review frequency"), self::get_schedule())
|
||||
->setDescription(_t('ContentReview.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());
|
||||
|
||||
$crFields->add(new HeaderField(_t('ContentReview.REVIEWHEADER', "Content review"), 2));
|
||||
$crFields->add($userField);
|
||||
$crFields->add($groupField);
|
||||
$crFields->add($reviewDate);
|
||||
$crFields->add($reviewFrequency);
|
||||
$crFields->add($notesField);
|
||||
|
||||
$fields->addFieldsToTab("Root.ContentReview", $crFields);
|
||||
$fields->addFieldsToTab("Root.ContentReview", array(
|
||||
new HeaderField(_t('ContentReview.REVIEWHEADER', "Content review"), 2),
|
||||
$viewersOptionsField,
|
||||
CompositeField::create(
|
||||
$userField,
|
||||
$groupField,
|
||||
$reviewDate,
|
||||
$reviewFrequency
|
||||
)->addExtraClass('contentReviewSettings'),
|
||||
$notesField
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4,5 +4,43 @@ jQuery(function($) {
|
||||
"use strict";
|
||||
|
||||
$.entwine('ss', function($) {
|
||||
|
||||
|
||||
/**
|
||||
* Class: .cms-edit-form #ContentReviewType
|
||||
*
|
||||
* Toggle display of group dropdown in "access" tab,
|
||||
* based on selection of radiobuttons.
|
||||
*/
|
||||
$('.cms-edit-form #ContentReviewType').entwine({
|
||||
// Constructor: onmatch
|
||||
onmatch: function() {
|
||||
// TODO Decouple
|
||||
var dropdown;
|
||||
if(this.attr('id') == 'ContentReviewType') dropdown = $('.contentReviewSettings');
|
||||
|
||||
this.find('.optionset :input').bind('change', function(e) {
|
||||
var wrapper = $(this).closest('.middleColumn').parent('div');
|
||||
if(e.target.value == 'Custom') {
|
||||
wrapper.addClass('remove-splitter');
|
||||
dropdown['show']();
|
||||
}
|
||||
else {
|
||||
wrapper.removeClass('remove-splitter');
|
||||
dropdown['hide']();
|
||||
}
|
||||
});
|
||||
|
||||
// initial state
|
||||
var currentVal = this.find('input[name=' + this.attr('id') + ']:checked').val();
|
||||
dropdown[currentVal == 'Custom' ? 'show' : 'hide']();
|
||||
|
||||
this._super();
|
||||
},
|
||||
onunmatch: function() {
|
||||
this._super();
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user