From d9dd9311d0ae0d6b67b94e7559b5ce3e31ee24f7 Mon Sep 17 00:00:00 2001 From: Robert Curry Date: Mon, 26 Nov 2012 13:22:30 +1300 Subject: [PATCH] Initial commit --- .gitignore | 0 README.md | 29 ++++++++++ _config.php | 4 ++ code/VersionFeed.php | 94 +++++++++++++++++++++++++++++++++ code/VersionFeed_Controller.php | 68 ++++++++++++++++++++++++ composer.json | 18 +++++++ 6 files changed, 213 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 _config.php create mode 100644 code/VersionFeed.php create mode 100644 code/VersionFeed_Controller.php create mode 100644 composer.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md new file mode 100644 index 0000000..c5f0de5 --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +# Version Feed + +## Overview + +The module creates an RSS feed on each page with their change history, as well as one for the entire site. + +## Requirements + + * SilverStripe 3.0+ + +## Installation + +Install with composer by running: + + composer require silverstripe/versionfeed:* + +in the root of your SilverStripe project. + +Or just clone/download the git repository into a subfolder (usually called "versionfeed") of your SilverStripe project. + +## Usage + +### Accessing RSS feeds + +The extensions will automatically add links to the RSS feeds, accessible by the actions 'changes' and 'allchanges'. You will encounter problems if you have functions called the same name on any controller. + +### Enabling / disabling + +You can enable or disable the feed on a per-page basis by interacting with the checkbox on the Settings tab of each page. \ No newline at end of file diff --git a/_config.php b/_config.php new file mode 100644 index 0000000..7b2a17e --- /dev/null +++ b/_config.php @@ -0,0 +1,4 @@ + 'Boolean' + ); + + static $defaults = array( + 'PublicHistory' => true + ); + + /** + * Compile a list of changes to the current page, excluding non-published and explicitly secured versions. + * + * @param int $highestVersion Top version number to consider. + * @param boolean $fullHistory Whether to get the full change history or just the previous version. + * + * @returns ArrayList List of cleaned records. + */ + public function getDiffedChanges($highestVersion = null, $fullHistory = true) { + // This can leak secured content if it was protected via inherited setting. + // For now the users will need to be aware about this shortcoming. + $offset = $highestVersion ? "AND \"SiteTree_versions\".\"Version\"<='".(int)$highestVersion."'" : ''; + $limit = $fullHistory ? null : 2; + $versions = $this->owner->allVersions("\"WasPublished\"='1' AND \"CanViewType\" IN ('Anyone', 'Inherit') $offset", "\"LastEdited\" DESC", $limit); + + // Process the list to add the comparisons. + $changeList = new ArrayList(); + $previous = null; + $count = 0; + foreach ($versions as $version) { + $changed = false; + + if (isset($previous)) { + // We have something to compare with. + $diff = $this->owner->compareVersions($version->Version, $previous->Version); + + // Produce the diff fields for use in the template. + if ($version->Title != $previous->Title) { + $version->DiffTitle = new HTMLText(); + $version->DiffTitle->setValue( + sprintf( + '
%s' . $diff->Title . '
', + _t('RSSHistory.TITLECHANGED', 'Title has changed:') + ) + ); + $changed = true; + } + if ($version->Content != $previous->Content) { + $version->DiffContent = new HTMLText(); + $version->DiffContent->setValue('
'.$diff->obj('Content')->forTemplate().'
'); + $changed = true; + } + } + + // Omit the versions that haven't been visibly changed (only takes the above fields into consideration). + if ($changed) { + $changeList->push($version); + $count++; + } + + // Store the last version for comparison. + $previous = $version; + } + + if ($fullHistory && $previous) { + $first = clone($previous); + $first->DiffContent = new HTMLText(); + $first->DiffContent->setValue('
' . $first->obj('Content')->forTemplate() . '
'); + $changeList->push($first); + } + + return $changeList; + } + + public function updateSettingsFields(FieldList $fields) { + // Add public history field. + $fields->addFieldToTab('Root.Settings', $publicHistory = new FieldGroup( + new CheckboxField('PublicHistory', $this->owner->fieldLabel(_t( + 'RSSHistory.LABEL', + 'Publish public RSS feed containing every published version of this page.')) + ))); + $publicHistory->setTitle($this->owner->fieldLabel('Public history')); + } + + public function getSiteRSSLink() { + // TODO: This link should be from the homepage, not this page. + return $this->owner->Link('allchanges'); + } + + public function getDefaultRSSLink() { + if ($this->owner->PublicHistory) return $this->owner->Link('changes'); + } +} \ No newline at end of file diff --git a/code/VersionFeed_Controller.php b/code/VersionFeed_Controller.php new file mode 100644 index 0000000..2fb1c07 --- /dev/null +++ b/code/VersionFeed_Controller.php @@ -0,0 +1,68 @@ +owner->PublicHistory) { + RSSFeed::linkToFeed($this->owner->Link() . 'changes', + sprintf( + _t('RSSHistory.SINGLEPAGEFEEDTITLE', 'Updates to %s page'), + $this->owner->Title + ) + ); + } + + $this->linkToAllSiteRSSFeed(); + + return $this; + } + + /** + * Get page-specific changes in a RSS feed. + */ + function changes() { + if(!$this->owner->PublicHistory) throw new SS_HTTPResponse_Exception('Page history not viewable', 404);; + + // Generate the output. + $title = sprintf(_t('RSSHistory.SINGLEPAGEFEEDTITLE', 'Updates to %s page'), $this->owner->Title); + $rss = new RSSFeed($this->owner->getDiffedChanges(), $this->owner->request->getURL(), $title, '', 'Title', '', null); + $rss->setTemplate('Page_changes_rss'); + return $rss->outputToBrowser(); + } + + /** + * Get all changes from the site in a RSS feed. + */ + function allchanges() { + // Fetch the latest changes on the entire site. + $latestChanges = DB::query('SELECT * FROM "SiteTree_versions" WHERE "WasPublished"=\'1\' AND "CanViewType" IN (\'Anyone\', \'Inherit\') AND "ShowInSearch"=1 AND ("PublicHistory" IS NULL OR "PublicHistory" = \'1\') ORDER BY "LastEdited" DESC LIMIT 20'); + + $changeList = new ArrayList(); + foreach ($latestChanges as $record) { + // Get the diff to the previous version. + $version = new Versioned_Version($record); + $changes = $version->getDiffedChanges($version->Version, false); + if ($changes && $changes->Count()) $changeList->push($changes->First()); + } + + // Produce output + $rss = new RSSFeed($changeList, $this->owner->request->getURL(), $this->linkToAllSitesRSSFeedTitle(), '', 'Title', '', null); + $rss->setTemplate('Page_allchanges_rss'); + return $rss->outputToBrowser(); + } + + function linkToAllSiteRSSFeed() { + // RSS feed to all-site changes. + RSSFeed::linkToFeed($this->owner->getSiteRSSLink(), $this->linkToAllSitesRSSFeedTitle()); + } + + function linkToAllSitesRSSFeedTitle() { + return sprintf(_t('RSSHistory.SITEFEEDTITLE', 'Updates to %s'), SiteConfig::current_site_config()->Title); + } +} \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..6fcc39b --- /dev/null +++ b/composer.json @@ -0,0 +1,18 @@ +{ + "name": "silverstripe/versionfeed", + "description": "Adds RSS feeds of content changes to SilverStripe", + "type": "silverstripe-module", + "keywords": ["silverstripe", "rss", "feed"], + "license": "BSD-3-Clause", + "authors": [ + { + "name": "Robert Curry", + "email": "robert@silverstripe.com" + } + ], + "require": + { + "silverstripe/framework": "3.*", + "silverstripe/cms": "3.*" + } +} \ No newline at end of file