diff --git a/code/ContentReviewEmails.php b/code/ContentReviewEmails.php
deleted file mode 100644
index 81e8a92..0000000
--- a/code/ContentReviewEmails.php
+++ /dev/null
@@ -1,154 +0,0 @@
-URLDate() : SSDatetime::now()->URLDate();
-
- // First grab all the pages with a custom setting
- //$customSettingsPages = Page::get('Page')
- // ->leftJoin('Group_SiteTreeContentReview', '"SiteTree"."ID" = "OwnerGroups"."SiteTreeID"', 'OwnerGroups')
- // ->leftJoin('Member_SiteTreeContentReview', '"SiteTree"."ID" = "OwnerUsers"."SiteTreeID"', "OwnerUsers")
- // ->where('"SiteTree"."ContentReviewType" = \'Custom\' AND "SiteTree"."NextReviewDate" <= \''.$now.'\' AND' .
- // ' ("OwnerGroups"."ID" IS NOT NULL OR "OwnerUsers"."ID" IS NOT NULL)')
- //;
-
- //$this->getOverduePagesForOwners($customSettingsPages, $overduePages);
-
- // Then grab all the pages with that inherits their settings
- //$inheritedSettingsPages = Page::get('Page')
- // ->leftJoin('Group_SiteTreeContentReview', '"SiteTree"."ID" = "OwnerGroups"."SiteTreeID"', 'OwnerGroups')
- // ->leftJoin('Member_SiteTreeContentReview', '"SiteTree"."ID" = "OwnerUsers"."SiteTreeID"', "OwnerUsers")
- // ->where('"SiteTree"."ContentReviewType" = \'Inherit\'')
- //;
-
-
- $pages = Page::get();
- $this->getOverduePagesForOwners($pages, $overduePages);
-
- // 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);
- }
-
- // Revert subsite filter (if installed)
- if(ClassInfo::exists('Subsite')) {
- Subsite::$disable_subsite_filter = $oldSubsiteState;
- }
- }
-
- /**
- *
- * @param SS_list $pages
- * @param array &$pages
- * @return array
- */
- protected function getOverduePagesForOwners(SS_list $pages, array &$overduePages) {
- foreach($pages as $page) {
- if(!$page->isContentReviewOverdue()) {
- continue;
- }
-
- $option = $page->getOptions();
- foreach($option->ContentReviewOwners() 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 int $owner
- * @param array $pages
- */
- protected function notifyOwner($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 = ''._t('ContentReviewEmails.EMAIL_HEADING','Page due for review').'
'.
- 'The page "'.$page->Title.'" is due for review today by you.
- '. _t('ContentReviewEmails.REVIEWPAGELINK','Review the page in the CMS') .' —
- '. _t('ContentReviewEmails.VIEWPUBLISHEDLINK','View this page on the website') .'';
- if(class_exists('Notification')) {
- // Notification::notify($recipient, $message);
- }
- // echo $page->Title.' - '.$recipient->Email.PHP_EOL;
- }
- }
- }
-}
diff --git a/code/tasks/ContentReviewEmails.php b/code/tasks/ContentReviewEmails.php
new file mode 100644
index 0000000..904f383
--- /dev/null
+++ b/code/tasks/ContentReviewEmails.php
@@ -0,0 +1,101 @@
+URLDate() : SSDatetime::now()->URLDate();
+
+ // First grab all the pages with a custom setting
+ $pages = Page::get('Page')->where('"SiteTree"."NextReviewDate" <= \''.$now.'\'');
+
+ $this->getOverduePagesForOwners($pages, $overduePages);
+
+
+ // 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);
+ }
+
+ // Revert subsite filter (if installed)
+ if(ClassInfo::exists('Subsite')) {
+ Subsite::$disable_subsite_filter = $oldSubsiteState;
+ }
+ }
+
+ /**
+ *
+ * @param SS_list $pages
+ * @param array &$pages
+ * @return array
+ */
+ protected function getOverduePagesForOwners(SS_list $pages, array &$overduePages) {
+
+ foreach($pages as $page) {
+ if(!$page->canBeReviewedBy()) {
+ continue;
+ }
+ $option = $page->getOptions();
+ foreach($option->ContentReviewOwners() as $owner) {
+ if(!isset(self::$member_cache[$owner->ID])) {
+ self::$member_cache[$owner->ID] = $owner;
+ }
+ if(!isset($overduePages[$owner->ID])) {
+ $overduePages[$owner->ID] = new ArrayList();
+ }
+ $overduePages[$owner->ID]->push($page);
+ }
+ }
+ return $overduePages;
+ }
+
+ /**
+ *
+ * @param int $owner
+ * @param array $pages
+ */
+ protected function notifyOwner($ownerID, SS_List $pages) {
+ $owner = self::$member_cache[$ownerID];
+ $sender = Security::findAnAdministrator();
+ $senderEmail = ($sender->Email) ? $sender->Email : Config::inst()->get('Email', 'admin_email');
+
+ $subject = _t('ContentReviewEmails.SUBJECT', 'Page(s) are due for content review');
+ $email = new Email();
+ $email->setTo($owner->Email);
+ $email->setFrom($senderEmail);
+ $email->setTemplate('ContentReviewEmail');
+ $email->setSubject($subject);
+ $email->populateTemplate(array(
+ "Recipient" => $owner,
+ "Sender" => $sender,
+ "Pages" => $pages
+ ));
+ $email->send();
+ }
+}
diff --git a/code/ContentReviewOwnerMigrationTask.php b/code/tasks/ContentReviewOwnerMigrationTask.php
similarity index 100%
rename from code/ContentReviewOwnerMigrationTask.php
rename to code/tasks/ContentReviewOwnerMigrationTask.php
diff --git a/templates/ContentReviewEmail.ss b/templates/ContentReviewEmail.ss
new file mode 100644
index 0000000..41cf052
--- /dev/null
+++ b/templates/ContentReviewEmail.ss
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+ <% _t('ContentReviewEmails.EMAIL_HEADING','Page(s) due for review') %>
+ There are $Pages.Count pages that are due for review today by you.
+ |
+
+ <% loop Pages %>
+
+ $Title |
+ <% _t('ContentReviewEmails.REVIEWPAGELINK','Review the page in the CMS') %>
+ <% _t('ContentReviewEmails.VIEWPUBLISHEDLINK','View this page on the website') %>
+ |
+
+ <% end_loop %>
+
+
+
+
\ No newline at end of file
diff --git a/templates/ContentReviewEmails.ss b/templates/ContentReviewEmails.ss
deleted file mode 100644
index ccbbd17..0000000
--- a/templates/ContentReviewEmails.ss
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
-
-
- <% _t('ContentReviewEmails.EMAIL_HEADING','Page due for review') %>
-
- The page $Page.Title is due for review today by you
-
- Actions
-
- |
-
-
-
-
-
\ No newline at end of file
diff --git a/tests/ContentReviewNotificationTest.php b/tests/ContentReviewNotificationTest.php
index 0646b6c..7e8cd70 100644
--- a/tests/ContentReviewNotificationTest.php
+++ b/tests/ContentReviewNotificationTest.php
@@ -2,14 +2,28 @@
class ContentReviewNotificationTest extends SapphireTest {
+ public static $fixture_file = 'contentreview/tests/ContentReviewTest.yml';
+
public function testContentReviewEmails() {
- $this->markTestIncomplete();
- SS_Datetime::set_mock_now('2010-02-14 12:00:00');
+ SS_Datetime::set_mock_now('2010-02-24 12:00:00');
+
+ // This propagates the next review date to 'contact-child' page from the parent page
+ $childParentPage = $this->objFromFixture('Page', 'contact');
+ $childParentPage->NextReviewDate = '2010-02-23';
+ $childParentPage->write();
$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'));
+ $expectedSubject = _t('ContentReviewEmails.SUBJECT', 'Page(s) are due for content review');
+ $email = $this->findEmail('author@example.com', null, $expectedSubject);
+
+ $this->assertNotNull($email, 'Email haven\'t been sent.');
+
+ $this->assertContains('There are 3 pages that are due for review today by you.', $email['htmlContent']);
+ $this->assertContains('Staff', $email['htmlContent']);
+ $this->assertContains('Contact Us', $email['htmlContent']);
+ $this->assertContains('Contact Us Child', $email['htmlContent']);
SS_Datetime::clear_mock_now();
}
diff --git a/tests/ContentReviewTest.yml b/tests/ContentReviewTest.yml
index 3896143..380d94c 100644
--- a/tests/ContentReviewTest.yml
+++ b/tests/ContentReviewTest.yml
@@ -36,11 +36,13 @@ Member:
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
@@ -62,10 +64,12 @@ Page:
Title: Contact Us Child
ContentReviewType: inherit
ParentID: =>Page.contact
+# Cant be reviewed, no NextReviewDate
no-review:
Title: Page without review date
ContentReviewType: Custom
ContentReviewUsers: =>Member.author
+# Cant be reviewed, no NextReviewDate
group-owned:
Title: Page owned by group
ContentReviewType: Custom
diff --git a/tests/SiteTreeContentReviewTest.php b/tests/SiteTreeContentReviewTest.php
index c7cf858..be01187 100644
--- a/tests/SiteTreeContentReviewTest.php
+++ b/tests/SiteTreeContentReviewTest.php
@@ -4,103 +4,109 @@ class SiteTreeContentReviewTest extends FunctionalTest {
public static $fixture_file = 'contentreview/tests/ContentReviewTest.yml';
-// public function testPermissionsExists() {
-// $perms = singleton('SiteTreeContentReview')->providePermissions();
-// $this->assertTrue(isset($perms['EDIT_CONTENT_REVIEW_FIELDS']));
-// }
-//
-// public function testUserWithPermissionCanEdit() {
-// $editor = $this->objFromFixture('Member', 'editor');
-// $this->logInAs($editor);
-// $page = new Page();
-// $fields = $page->getSettingsFields();
-// $this->assertNotNull($fields->dataFieldByName('NextReviewDate'));
-// }
-//
-// public function testUserWithoutPermissionCannotEdit() {
-// $author = $this->objFromFixture('Member', 'author');
-// $this->logInAs($author);
-// $page = new Page();
-// $fields = $page->getSettingsFields();
-// $this->assertNull($fields->dataFieldByName('NextReviewDate'));
-// }
-//
-// public function testAutomaticallyToNotSetReviewDate() {
-// $editor = $this->objFromFixture('Member', 'editor');
-// $this->logInAs($editor);
-//
-// $page = new Page();
-// $page->ReviewPeriodDays = 10;
-// $page->write();
-// $this->assertTrue($page->doPublish());
-// $this->assertEquals(null, $page->NextReviewDate);
-// }
-//
-// public function testAddReviewNote() {
-// $author = $this->objFromFixture('Member', 'author');
-// $page = $this->objFromFixture('Page', 'home');
-// $page->addReviewNote($author, 'This is a message');
-//
-// // Get the page again to make sure it's not only cached in memory
-// $homepage = $this->objFromFixture('Page', 'home');
-// $this->assertEquals(1, $homepage->ReviewLogs()->count());
-// $this->assertEquals('This is a message', $homepage->ReviewLogs()->first()->Note);
-// }
-//
-// public function testGetContentReviewOwners() {
-// $page = $this->objFromFixture('Page', 'group-owned');
-// $owners = $page->ContentReviewOwners();
-// $this->assertEquals(1, $owners->count());
-// $this->assertEquals('author@example.com', $owners->first()->Email);
-// }
-//
-// public function testCanNotBeReviewBecauseNoReviewDate() {
-// SS_Datetime::set_mock_now('2010-01-01 12:00:00');
-// $author = $this->objFromFixture('Member', 'author');
-// $page = $this->objFromFixture('Page', 'no-review');
-// // page 'no-review' is owned by author, but there is no review date
-// $this->assertFalse($page->canBeReviewedBy($author));
-// }
-//
-// public function testCanNotBeReviewedBecauseInFuture() {
-// SS_Datetime::set_mock_now('2010-01-01 12:00:00');
-// $author = $this->objFromFixture('Member', 'author');
-// $page = $this->objFromFixture('Page', 'staff');
-// // page 'staff' is owned by author, but the review date is in the future
-// $this->assertFalse($page->canBeReviewedBy($author));
-// }
-//
-// public function testCanNotBeReviewedByUser() {
-// SS_Datetime::set_mock_now('2010-03-01 12:00:00');
-// $author = $this->objFromFixture('Member', 'author');
-// $page = $this->objFromFixture('Page', 'home');
-// // page 'home' doesnt have any owners
-// $this->assertFalse($page->canBeReviewedBy($author));
-// }
-//
-// public function testCanBeReviewedByUser() {
-// SS_Datetime::set_mock_now('2010-03-01 12:00:00');
-// $author = $this->objFromFixture('Member', 'author');
-// $page = $this->objFromFixture('Page', 'staff');
-// // page 'staff' is owned by author
-// $this->assertTrue($page->canBeReviewedBy($author));
-// }
-//
-// public function testCanNotBeReviewedByGroup() {
-// SS_Datetime::set_mock_now('2010-03-01 12:00:00');
-// $author = $this->objFromFixture('Member', 'editor');
-// $page = $this->objFromFixture('Page', 'contact');
-// // page 'contact' is owned by the authorgroup
-// $this->assertFalse($page->canBeReviewedBy($author));
-// }
-//
-// public function testCanBeReviewedByGroup() {
-// SS_Datetime::set_mock_now('2010-03-01 12:00:00');
-// $author = $this->objFromFixture('Member', 'author');
-// $page = $this->objFromFixture('Page', 'contact');
-// // page 'contact' is owned by the authorgroup
-// $this->assertTrue($page->canBeReviewedBy($author));
-// }
+ public function testPermissionsExists() {
+ $perms = singleton('SiteTreeContentReview')->providePermissions();
+ $this->assertTrue(isset($perms['EDIT_CONTENT_REVIEW_FIELDS']));
+ }
+
+ public function testUserWithPermissionCanEdit() {
+ $editor = $this->objFromFixture('Member', 'editor');
+ $this->logInAs($editor);
+ $page = new Page();
+ $fields = $page->getSettingsFields();
+ $this->assertNotNull($fields->dataFieldByName('NextReviewDate'));
+ }
+
+ public function testUserWithoutPermissionCannotEdit() {
+ $author = $this->objFromFixture('Member', 'author');
+ $this->logInAs($author);
+ $page = new Page();
+ $fields = $page->getSettingsFields();
+ $this->assertNull($fields->dataFieldByName('NextReviewDate'));
+ }
+
+ public function testAutomaticallyToNotSetReviewDate() {
+ $editor = $this->objFromFixture('Member', 'editor');
+ $this->logInAs($editor);
+
+ $page = new Page();
+ $page->ReviewPeriodDays = 10;
+ $page->write();
+ $this->assertTrue($page->doPublish());
+ $this->assertEquals(null, $page->NextReviewDate);
+ }
+
+ public function testAddReviewNote() {
+ $author = $this->objFromFixture('Member', 'author');
+ $page = $this->objFromFixture('Page', 'home');
+ $page->addReviewNote($author, 'This is a message');
+
+ // Get the page again to make sure it's not only cached in memory
+ $homepage = $this->objFromFixture('Page', 'home');
+ $this->assertEquals(1, $homepage->ReviewLogs()->count());
+ $this->assertEquals('This is a message', $homepage->ReviewLogs()->first()->Note);
+ }
+
+ public function testGetContentReviewOwners() {
+ $page = $this->objFromFixture('Page', 'group-owned');
+ $owners = $page->ContentReviewOwners();
+ $this->assertEquals(1, $owners->count());
+ $this->assertEquals('author@example.com', $owners->first()->Email);
+ }
+
+ public function testCanNotBeReviewBecauseNoReviewDate() {
+ SS_Datetime::set_mock_now('2010-01-01 12:00:00');
+ $author = $this->objFromFixture('Member', 'author');
+ $page = $this->objFromFixture('Page', 'no-review');
+ // page 'no-review' is owned by author, but there is no review date
+ $this->assertFalse($page->canBeReviewedBy($author));
+ SS_Datetime::clear_mock_now();
+ }
+
+ public function testCanNotBeReviewedBecauseInFuture() {
+ SS_Datetime::set_mock_now('2010-01-01 12:00:00');
+ $author = $this->objFromFixture('Member', 'author');
+ $page = $this->objFromFixture('Page', 'staff');
+ // page 'staff' is owned by author, but the review date is in the future
+ $this->assertFalse($page->canBeReviewedBy($author));
+ SS_Datetime::clear_mock_now();
+ }
+
+ public function testCanNotBeReviewedByUser() {
+ SS_Datetime::set_mock_now('2010-03-01 12:00:00');
+ $author = $this->objFromFixture('Member', 'author');
+ $page = $this->objFromFixture('Page', 'home');
+ // page 'home' doesnt have any owners
+ $this->assertFalse($page->canBeReviewedBy($author));
+ SS_Datetime::clear_mock_now();
+ }
+
+ public function testCanBeReviewedByUser() {
+ SS_Datetime::set_mock_now('2010-03-01 12:00:00');
+ $author = $this->objFromFixture('Member', 'author');
+ $page = $this->objFromFixture('Page', 'staff');
+ // page 'staff' is owned by author
+ $this->assertTrue($page->canBeReviewedBy($author));
+ SS_Datetime::clear_mock_now();
+ }
+
+ public function testCanNotBeReviewedByGroup() {
+ SS_Datetime::set_mock_now('2010-03-01 12:00:00');
+ $author = $this->objFromFixture('Member', 'editor');
+ $page = $this->objFromFixture('Page', 'contact');
+ // page 'contact' is owned by the authorgroup
+ $this->assertFalse($page->canBeReviewedBy($author));
+ SS_Datetime::clear_mock_now();
+ }
+
+ public function testCanBeReviewedByGroup() {
+ SS_Datetime::set_mock_now('2010-03-01 12:00:00');
+ $author = $this->objFromFixture('Member', 'author');
+ $page = $this->objFromFixture('Page', 'contact');
+ // page 'contact' is owned by the authorgroup
+ $this->assertTrue($page->canBeReviewedBy($author));
+ SS_Datetime::clear_mock_now();
+ }
public function testCanBeReviewedFromInheritedSetting() {
SS_Datetime::set_mock_now('2013-03-01 12:00:00');
@@ -112,25 +118,28 @@ class SiteTreeContentReviewTest extends FunctionalTest {
$page = $this->objFromFixture('Page', 'contact-child');
$this->assertTrue($page->canBeReviewedBy($author));
+ SS_Datetime::clear_mock_now();
}
-// public function testReviewActionVisibleForAuthor() {
-// SS_Datetime::set_mock_now('2020-03-01 12:00:00');
-// $page = $this->objFromFixture('Page', 'contact');
-// $author = $this->objFromFixture('Member', 'author');
-// $this->logInAs($author);
-//
-// $fields = $page->getCMSActions();
-// $this->assertNotNull($fields->fieldByName('action_reviewed'));
-// }
-//
-// public function testReviewActionNotVisibleForEditor() {
-// SS_Datetime::set_mock_now('2020-03-01 12:00:00');
-// $page = $this->objFromFixture('Page', 'contact');
-// $author = $this->objFromFixture('Member', 'editor');
-// $this->logInAs($author);
-//
-// $fields = $page->getCMSActions();
-// $this->assertNull($fields->fieldByName('action_reviewed'));
-// }
+ public function testReviewActionVisibleForAuthor() {
+ SS_Datetime::set_mock_now('2020-03-01 12:00:00');
+ $page = $this->objFromFixture('Page', 'contact');
+ $author = $this->objFromFixture('Member', 'author');
+ $this->logInAs($author);
+
+ $fields = $page->getCMSActions();
+ $this->assertNotNull($fields->fieldByName('action_reviewed'));
+ SS_Datetime::clear_mock_now();
+ }
+
+ public function testReviewActionNotVisibleForEditor() {
+ SS_Datetime::set_mock_now('2020-03-01 12:00:00');
+ $page = $this->objFromFixture('Page', 'contact');
+ $author = $this->objFromFixture('Member', 'editor');
+ $this->logInAs($author);
+
+ $fields = $page->getCMSActions();
+ $this->assertNull($fields->fieldByName('action_reviewed'));
+ SS_Datetime::clear_mock_now();
+ }
}