Merge pull request #42 from creative-commoners/pulls/2.0/new-version-feed-v2

Pulls/2.0/new version feed v2
This commit is contained in:
Robbie Averill 2017-12-12 10:37:41 +13:00 committed by GitHub
commit 17cf3d7487
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 276 additions and 153 deletions

View File

@ -1,9 +1,15 @@
inherit: true
build:
nodes:
analysis:
tests:
override: [php-scrutinizer-run]
checks:
php:
code_rating: true
duplication: true
filter:
paths: [code/*, tests/*]
paths: [src/*, tests/*]

View File

@ -1,34 +1,35 @@
# See https://github.com/silverstripe/silverstripe-travis-support for setup details
sudo: false
language: php
php:
- 5.3
- 5.4
- 5.5
env:
- DB=MYSQL CORE_RELEASE=3.5
global:
- COMPOSER_ROOT_VERSION=2.0.x-dev
matrix:
include:
- php: 5.6
env: DB=MYSQL CORE_RELEASE=3
- php: 5.6
env: DB=MYSQL CORE_RELEASE=3.1
- php: 5.6
env: DB=PGSQL CORE_RELEASE=3.2
env: DB=MYSQL PHPCS_TEST=1 PHPUNIT_TEST=1
- php: 7.0
env: DB=MYSQL PHPUNIT_TEST=1
- php: 7.1
env: DB=MYSQL CORE_RELEASE=3.6
env: DB=PGSQL PHPUNIT_COVERAGE_TEST=1
- php: 7.2
env: DB=MYSQL PHPUNIT_TEST=1
before_script:
- composer self-update || true
- git clone git://github.com/silverstripe/silverstripe-travis-support.git ~/travis-support
- php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss
- cd ~/builds/ss
- composer install
# Init PHP
- phpenv rehash
- phpenv config-rm xdebug.ini
# Install composer dependencies
- composer validate
- composer require --no-update silverstripe/recipe-core:1.0.x-dev
- if [[ $DB == PGSQL ]]; then composer require --no-update silverstripe/postgresql 2.0.x-dev; fi
- composer install --prefer-dist --no-interaction --no-progress --no-suggest --optimize-autoloader --verbose --profile
script:
- vendor/bin/phpunit versionfeed/tests
- if [[ $PHPUNIT_TEST ]]; then vendor/bin/phpunit; fi
- if [[ $PHPUNIT_COVERAGE_TEST ]]; then phpdbg -qrr vendor/bin/phpunit --coverage-clover=coverage.xml; fi
- if [[ $PHPCS_TEST ]]; then vendor/bin/phpcs src/ tests/; fi
after_success:
- if [[ $PHPUNIT_COVERAGE_TEST ]]; then bash <(curl -s https://codecov.io/bash) -f coverage.xml; fi

12
.upgrade.yml Normal file
View File

@ -0,0 +1,12 @@
mappings:
VersionFeed: SilverStripe\VersionFeed\VersionFeed
VersionFeed_Controller: SilverStripe\VersionFeed\VersionFeedController
VersionFeedSiteConfig: SilverStripe\VersionFeed\VersionFeedSiteConfig
CachedContentFilter: SilverStripe\VersionFeed\Filters\CachedContentFilter
ContentFilter: SilverStripe\VersionFeed\Filters\ContentFilter
RateLimitFilter: SilverStripe\VersionFeed\Filters\RateLimitFilter
\VersionFeed\Filters\CachedContentFilter: SilverStripe\VersionFeed\Filters\CachedContentFilter
\VersionFeed\Filters\ContentFilter: SilverStripe\VersionFeed\Filters\ContentFilter
\VersionFeed\Filters\RateLimitFilter: SilverStripe\VersionFeed\Filters\RateLimitFilter
VersionFeedFunctionalTest: SilverStripe\VersionFeed\Tests\VersionFeedFunctionalTest
VersionFeedTest: SilverStripe\VersionFeed\Tests\VersionFeedTest

View File

@ -1,21 +1,25 @@
---
Name: versionedfeedconfig
---
Injector:
RateLimitFilter: \VersionFeed\Filters\RateLimitFilter
SilverStripe\Core\Injector\Injector:
RateLimitFilter: SilverStripe\VersionFeed\Filters\RateLimitFilter
ContentFilter:
class: \VersionFeed\Filters\CachedContentFilter
class: SilverStripe\VersionFeed\Filters\CachedContentFilter
constructor:
- %$RateLimitFilter
SiteTree:
Psr\SimpleCache\CacheInterface.VersionFeedController:
factory: SilverStripe\Core\Cache\CacheFactory
constructor:
namespace: 'VersionFeedController'
SilverStripe\CMS\Model\SiteTree:
extensions:
- VersionFeed
SiteConfig:
- SilverStripe\VersionFeed\VersionFeed
SilverStripe\SiteConfig\SiteConfig:
extensions:
- VersionFeedSiteConfig
ContentController:
- SilverStripe\VersionFeed\VersionFeedSiteConfig
SilverStripe\CMS\Controllers\ContentController:
extensions:
- VersionFeed_Controller
VersionFeed_Controller:
- SilverStripe\VersionFeed\VersionFeedController
SilverStripe\VersionFeed\VersionFeedController:
dependencies:
ContentFilter: %$ContentFilter

View File

@ -1,29 +0,0 @@
# Changelog
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## [1.2.2]
* Consistent sorting for getDiffList()
## [1.2.1]
* Updated userguide documentation
* Added standard Scrutinizer config
* Added standard code of conduct
* Added standard gitattributes
* Added standard editor config
* Added standard license
* Added standard Travis config
* Updated license year
* Updated translations
## [1.2.0]
* Changelog added.
* Added Scrutinizer support
* Add `ContentFilter.cache_lifetime` config to set the cache lifetime.
* Update alternate xml link tag to be W3 compliant
* Added CWP keyword

1
codecov.yml Normal file
View File

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

View File

@ -42,7 +42,7 @@ Two filters are applied on top of one another:
server. This filter will only be applied if the `CachedContentFilter` does not have any cached record
for a request.
Either one of these can be replaced, added to, or removed, by adjusting the `VersionFeed_Controller.dependencies`
Either one of these can be replaced, added to, or removed, by adjusting the `SilverStripe\VersionFeed\VersionFeedController.dependencies`
config to point to a replacement (or no) filter.
For smaller servers where it's reasonable to apply a strict approach to rate limiting the default

View File

@ -1,4 +1,4 @@
Copyright (c) 2016, SilverStripe Limited
Copyright (c) 2017, SilverStripe Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

9
phpcs.xml.dist Normal file
View File

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

13
phpunit.xml.dist Normal file
View File

@ -0,0 +1,13 @@
<phpunit bootstrap="vendor/silverstripe/framework/tests/bootstrap.php" colors="true">
<testsuite name="Default">
<directory>tests/</directory>
</testsuite>
<filter>
<whitelist addUncoveredFilesFromWhitelist="true">
<directory suffix=".php">src/</directory>
<exclude>
<directory suffix=".php">tests/</directory>
</exclude>
</whitelist>
</filter>
</phpunit>

View File

@ -1,6 +1,12 @@
<?php
namespace VersionFeed\Filters;
namespace SilverStripe\VersionFeed\Filters;
use SilverStripe\Core\Config\Config;
/**
* Caches results of a callback
@ -19,15 +25,16 @@ class CachedContentFilter extends ContentFilter {
$cache = $this->getCache();
// Return cached value if available
$cacheEnabled = \Config::inst()->get(get_class(), 'cache_enabled');
$cacheEnabled = Config::inst()->get(get_class(), 'cache_enabled');
$result = (isset($_GET['flush']) || !$cacheEnabled)
? null
: $cache->load($key);
: $cache->get($key);
if($result) return $result;
// Fallback to generate result
$result = parent::getContent($key, $callback);
$cache->save($result, $key);
$lifetime = Config::inst()->get(ContentFilter::class, 'cache_lifetime') ?: null;
$cache->set($key, $result, $lifetime);
return $result;
}
}

View File

@ -1,6 +1,13 @@
<?php
namespace VersionFeed\Filters;
namespace SilverStripe\VersionFeed\Filters;
use SilverStripe\VersionFeed\VersionFeedController;
use SilverStripe\Core\Config\Configurable;
use Psr\SimpleCache\CacheInterface;
use SilverStripe\Core\Injector\Injector;
/**
* Conditionally executes a given callback, attempting to return the desired results
@ -8,6 +15,8 @@ namespace VersionFeed\Filters;
*/
abstract class ContentFilter {
use Configurable;
/**
* Nested content filter
*
@ -33,13 +42,9 @@ abstract class ContentFilter {
* @return Zend_Cache_Frontend
*/
protected function getCache() {
$cache = \SS_Cache::factory('VersionFeed_Controller');
$cache->setOption('automatic_serialization', true);
// Map 0 to null for unlimited lifetime
$lifetime = \Config::inst()->get(get_class($this), 'cache_lifetime') ?: null;
$cache->setLifetime($lifetime);
return $cache;
return Injector::inst()->get(
CacheInterface::class . '.VersionFeedController'
);
}
/**

View File

@ -1,6 +1,16 @@
<?php
namespace VersionFeed\Filters;
namespace SilverStripe\VersionFeed\Filters;
use SilverStripe\Core\Config\Config;
use SilverStripe\Control\Controller;
use SilverStripe\Control\HTTPResponse_Exception;
/**
* Provides rate limiting of execution of a callback
@ -60,13 +70,13 @@ class RateLimitFilter extends ContentFilter {
$key = self::CACHE_PREFIX;
// Add global identifier
if(\Config::inst()->get(get_class(), 'lock_bypage')) {
if($this->config()->get('lock_bypage')) {
$key .= '_' . md5($itemkey);
}
// Add user-specific identifier
if(\Config::inst()->get(get_class(), 'lock_byuserip') && \Controller::has_curr()) {
$ip = \Controller::curr()->getRequest()->getIP();
if($this->config()->get('lock_byuserip') && Controller::has_curr()) {
$ip = Controller::curr()->getRequest()->getIP();
$key .= '_' . md5($ip);
}
@ -76,7 +86,7 @@ class RateLimitFilter extends ContentFilter {
public function getContent($key, $callback) {
// Bypass rate limiting if flushing, or timeout isn't set
$timeout = \Config::inst()->get(get_class(), 'lock_timeout');
$timeout = $this->config()->get('lock_timeout');
if(isset($_GET['flush']) || !$timeout) {
return parent::getContent($key, $callback);
}
@ -84,28 +94,30 @@ class RateLimitFilter extends ContentFilter {
// Generate result with rate limiting enabled
$limitKey = $this->getCacheKey($key);
$cache = $this->getCache();
if($lockedUntil = $cache->load($limitKey)) {
if($lockedUntil = $cache->get($limitKey)) {
if(time() < $lockedUntil) {
// Politely inform visitor of limit
$response = new \SS_HTTPResponse_Exception('Too Many Requests.', 429);
$response = new HTTPResponse_Exception('Too Many Requests.', 429);
$response->getResponse()->addHeader('Retry-After', 1 + $lockedUntil - time());
throw $response;
}
}
$lifetime = Config::inst()->get(ContentFilter::class, 'cache_lifetime') ?: null;
// Apply rate limit
$cache->save(time() + $timeout, $limitKey);
$cache->set($limitKey, time() + $timeout, $lifetime);
// Generate results
$result = parent::getContent($key, $callback);
// Reset rate limit with optional cooldown
if($cooldown = \Config::inst()->get(get_class(), 'lock_cooldown')) {
if($cooldown = $this->config()->get('lock_cooldown')) {
// Set cooldown on successful query execution
$cache->save(time() + $cooldown, $limitKey);
$cache->set($limitKey, time() + $cooldown, $lifetime);
} else {
// Without cooldown simply disable lock
$cache->remove($limitKey);
$cache->delete($limitKey);
}
return $result;
}

View File

@ -1,5 +1,18 @@
<?php
namespace SilverStripe\VersionFeed;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\View\Parsers\Diff;
use SilverStripe\ORM\ArrayList;
use SilverStripe\Forms\FieldList;
use SilverStripe\Core\Config\Config;
use SilverStripe\Forms\CheckboxField;
use SilverStripe\Forms\FieldGroup;
use SilverStripe\Forms\LiteralField;
use SilverStripe\SiteConfig\SiteConfig;
use SilverStripe\CMS\Model\SiteTreeExtension;
class VersionFeed extends SiteTreeExtension {
private static $db = array(
@ -80,7 +93,7 @@ class VersionFeed extends SiteTreeExtension {
if ($version->Title != $previous->Title) {
$diffTitle = Diff::compareHTML($version->Title, $previous->Title);
$version->DiffTitle = new HTMLText();
$version->DiffTitle = DBField::create_field('HTMLText', null);
$version->DiffTitle->setValue(
sprintf(
'<div><em>%s</em> ' . $diffTitle . '</div>',
@ -93,12 +106,12 @@ class VersionFeed extends SiteTreeExtension {
if ($version->Content != $previous->Content) {
$diffContent = Diff::compareHTML($version->Content, $previous->Content);
$version->DiffContent = new HTMLText();
$version->DiffContent = DBField::create_field('HTMLText', null);
$version->DiffContent->setValue('<div>'.$diffContent.'</div>');
$changed = true;
}
// Copy the link so it can be cached by SS_Cache.
// Copy the link so it can be cached.
$version->GeneratedLink = $version->AbsoluteLink();
}
@ -117,9 +130,9 @@ class VersionFeed extends SiteTreeExtension {
// a diff on the initial version we will just get that version, verbatim.
if ($previous && $versions->count()<$qLimit) {
$first = clone($previous);
$first->DiffContent = new HTMLText();
$first->DiffContent = DBField::create_field('HTMLText', null);
$first->DiffContent->setValue('<div>' . $first->Content . '</div>');
// Copy the link so it can be cached by SS_Cache.
// Copy the link so it can be cached.
$first->GeneratedLink = $first->AbsoluteLink();
$changeList->push($first);
}

View File

@ -1,6 +1,22 @@
<?php
class VersionFeed_Controller extends Extension {
namespace SilverStripe\VersionFeed;
use SilverStripe\Core\Config\Config;
use SilverStripe\VersionFeed\VersionFeed;
use SilverStripe\Control\RSS\RSSFeed;
use SilverStripe\SiteConfig\SiteConfig;
use SilverStripe\ORM\DB;
use SilverStripe\Security\Member;
use SilverStripe\ORM\ArrayList;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Versioned\Versioned_Version;
use SilverStripe\Core\Convert;
use SilverStripe\View\Requirements;
use SilverStripe\Core\Extension;
use SilverStripe\VersionFeed\Filters\ContentFilter;
class VersionFeedController extends Extension {
private static $allowed_actions = array(
'changes',
@ -10,16 +26,16 @@ class VersionFeed_Controller extends Extension {
/**
* Content handler
*
* @var \VersionFeed\Filters\ContentFilter
* @var ContentFilter
*/
protected $contentFilter;
/**
* Sets the content filter
*
* @param \VersionFeed\Filters\ContentFilter $contentFilter
* @param ContentFilter $contentFilter
*/
public function setContentFilter(\VersionFeed\Filters\ContentFilter $contentFilter) {
public function setContentFilter(ContentFilter $contentFilter) {
$this->contentFilter = $contentFilter;
}
@ -48,7 +64,7 @@ class VersionFeed_Controller extends Extension {
*/
public function changes() {
// Check viewability of changes
if(!Config::inst()->get('VersionFeed', 'changes_enabled')
if(!Config::inst()->get(VersionFeed::class, 'changes_enabled')
|| !$this->owner->PublicHistory
|| $this->owner->Version == ''
) {
@ -59,7 +75,7 @@ class VersionFeed_Controller extends Extension {
$target = $this->owner;
$key = implode('_', array('changes', $this->owner->ID, $this->owner->Version));
$entries = $this->filterContent($key, function() use ($target) {
return $target->getDiffList(null, Config::inst()->get('VersionFeed', 'changes_limit'));
return $target->getDiffList(null, Config::inst()->get(VersionFeed::class, 'changes_limit'));
});
// Generate the output.
@ -74,13 +90,13 @@ class VersionFeed_Controller extends Extension {
*/
public function allchanges() {
// Check viewability of allchanges
if(!Config::inst()->get('VersionFeed', 'allchanges_enabled')
if(!Config::inst()->get(VersionFeed::class, 'allchanges_enabled')
|| !SiteConfig::current_site_config()->AllChangesEnabled
) {
return $this->owner->httpError(404, 'Global history not viewable');
}
$limit = (int)Config::inst()->get('VersionFeed', 'allchanges_limit');
$limit = (int)Config::inst()->get(VersionFeed::class, 'allchanges_limit');
$latestChanges = DB::query('
SELECT * FROM "SiteTree_versions"
WHERE "WasPublished" = \'1\'
@ -135,7 +151,7 @@ class VersionFeed_Controller extends Extension {
* Generates and embeds the RSS header link for the page-specific version rss feed
*/
public function linkToPageRSSFeed() {
if (!Config::inst()->get('VersionFeed', 'changes_enabled') || !$this->owner->PublicHistory) {
if (!Config::inst()->get(VersionFeed::class, 'changes_enabled') || !$this->owner->PublicHistory) {
return;
}
@ -152,7 +168,7 @@ class VersionFeed_Controller extends Extension {
* Generates and embeds the RSS header link for the global version rss feed
*/
public function linkToAllSiteRSSFeed() {
if(!Config::inst()->get('VersionFeed', 'allchanges_enabled')
if(!Config::inst()->get(VersionFeed::class, 'allchanges_enabled')
|| !SiteConfig::current_site_config()->AllChangesEnabled
) {
return;

View File

@ -1,5 +1,21 @@
<?php
namespace SilverStripe\VersionFeed;
use SilverStripe\Forms\FieldList;
use SilverStripe\Core\Config\Config;
use SilverStripe\VersionFeed\VersionFeed;
use SilverStripe\Forms\CheckboxField;
use SilverStripe\Forms\FieldGroup;
use SilverStripe\ORM\DataExtension;
/**
* Allows global configuration of all changes
*/
@ -17,8 +33,8 @@ class VersionFeedSiteConfig extends DataExtension {
$labels['AllChangesEnabled'] = _t('VersionFeedSiteConfig.ALLCHANGESLABEL', 'Make global changes feed public');
}
public function updateCMSFields(\FieldList $fields) {
if(!Config::inst()->get('VersionFeed', 'allchanges_enabled')) return;
public function updateCMSFields(FieldList $fields) {
if(!Config::inst()->get(VersionFeed::class, 'allchanges_enabled')) return;
$fields->addFieldToTab('Root.Access',
FieldGroup::create(new CheckboxField('AllChangesEnabled', $this->owner->fieldLabel('AllChangesEnabled')))

View File

@ -1,39 +1,63 @@
<?php
namespace SilverStripe\VersionFeed\Tests;
use Page;
use SilverStripe\VersionFeed\VersionFeed;
use SilverStripe\VersionFeed\Filters\CachedContentFilter;
use SilverStripe\VersionFeed\Filters\RateLimitFilter;
use SilverStripe\VersionFeed\VersionFeedController;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Versioned\Versioned;
use SilverStripe\SiteConfig\SiteConfig;
use SilverStripe\Dev\FunctionalTest;
use SilverStripe\Control\Director;
use Psr\SimpleCache\CacheInterface;
class VersionFeedFunctionalTest extends FunctionalTest {
protected $usesDatabase = true;
protected $requiredExtensions = array(
'Page' => array('VersionFeed'),
'Page_Controller' => array('VersionFeed_Controller'),
protected $baseURI = 'http://www.fakesite.test';
protected static $required_extensions = array(
'Page' => array(VersionFeed::class),
'PageController' => array(VersionFeedController::class),
);
protected $userIP;
public function setUp() {
protected function setUp() {
Director::config()->set('alternate_base_url', $this->baseURI);
parent::setUp();
$cache = SS_Cache::factory('VersionFeed_Controller');
$cache->clean(Zend_Cache::CLEANING_MODE_ALL);
$cache = Injector::inst()->get(
CacheInterface::class . '.VersionFeedController'
);
$cache->clear();
$this->userIP = isset($_SERVER['HTTP_CLIENT_IP']) ? $_SERVER['HTTP_CLIENT_IP'] : null;
$this->userIP = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null;
Config::nest();
// Enable history by default
Config::inst()->update('VersionFeed', 'changes_enabled', true);
Config::inst()->update('VersionFeed', 'allchanges_enabled', true);
Config::modify()->set(VersionFeed::class, 'changes_enabled', true);
Config::modify()->set(VersionFeed::class, 'allchanges_enabled', true);
// Disable caching and locking by default
Config::inst()->update('VersionFeed\Filters\CachedContentFilter', 'cache_enabled', false);
Config::inst()->update('VersionFeed\Filters\RateLimitFilter', 'lock_timeout', 0);
Config::inst()->update('VersionFeed\Filters\RateLimitFilter', 'lock_bypage', false);
Config::inst()->update('VersionFeed\Filters\RateLimitFilter', 'lock_byuserip', false);
Config::inst()->update('VersionFeed\Filters\RateLimitFilter', 'lock_cooldown', false);
Config::modify()->set(CachedContentFilter::class, 'cache_enabled', false);
Config::modify()->set(RateLimitFilter::class, 'lock_timeout', 0);
Config::modify()->set(RateLimitFilter::class, 'lock_bypage', false);
Config::modify()->set(RateLimitFilter::class, 'lock_byuserip', false);
Config::modify()->set(RateLimitFilter::class, 'lock_cooldown', false);
}
public function tearDown() {
Config::unnest();
Director::config()->set('alternate_base_url', null);
$_SERVER['HTTP_CLIENT_IP'] = $this->userIP;
$_SERVER['REMOTE_ADDR'] = $this->userIP;
parent::tearDown();
}
@ -64,17 +88,18 @@ class VersionFeedFunctionalTest extends FunctionalTest {
public function testRateLimiting() {
// Re-enable locking just for this test
Config::inst()->update('VersionFeed\Filters\RateLimitFilter', 'lock_timeout', 20);
Config::inst()->update('VersionFeed\Filters\CachedContentFilter', 'cache_enabled', true);
Config::modify()->set(RateLimitFilter::class, 'lock_timeout', 20);
Config::modify()->set(CachedContentFilter::class, 'cache_enabled', true);
$page1 = $this->createPageWithChanges(array('PublicHistory' => true, 'Title' => 'Page1'));
$page2 = $this->createPageWithChanges(array('PublicHistory' => true, 'Title' => 'Page2'));
// Artifically set cache lock
Config::inst()->update('VersionFeed\Filters\RateLimitFilter', 'lock_byuserip', false);
$cache = SS_Cache::factory('VersionFeed_Controller');
$cache->setOption('automatic_serialization', true);
$cache->save(time() + 10, \VersionFeed\Filters\RateLimitFilter::CACHE_PREFIX);
Config::modify()->set(RateLimitFilter::class, 'lock_byuserip', false);
$cache = Injector::inst()->get(
CacheInterface::class . '.VersionFeedController'
);
$cache->set(RateLimitFilter::CACHE_PREFIX, time() + 10);
// Test normal hit
$response = $this->get($page1->RelativeLink('changes'));
@ -85,39 +110,39 @@ class VersionFeedFunctionalTest extends FunctionalTest {
$this->assertGreaterThan(0, $response->getHeader('Retry-After'));
// Test page specific lock
Config::inst()->update('VersionFeed\Filters\RateLimitFilter', 'lock_bypage', true);
Config::modify()->set(RateLimitFilter::class, 'lock_bypage', true);
$key = implode('_', array(
'changes',
$page1->ID,
Versioned::get_versionnumber_by_stage('SiteTree', 'Live', $page1->ID, false)
Versioned::get_versionnumber_by_stage(SiteTree::class, 'Live', $page1->ID, false)
));
$key = \VersionFeed\Filters\RateLimitFilter::CACHE_PREFIX . '_' . md5($key);
$cache->save(time() + 10, $key);
$key = RateLimitFilter::CACHE_PREFIX . '_' . md5($key);
$cache->set($key, time() + 10);
$response = $this->get($page1->RelativeLink('changes'));
$this->assertEquals(429, $response->getStatusCode());
$this->assertGreaterThan(0, $response->getHeader('Retry-After'));
$response = $this->get($page2->RelativeLink('changes'));
$this->assertEquals(200, $response->getStatusCode());
Config::inst()->update('VersionFeed\Filters\RateLimitFilter', 'lock_bypage', false);
Config::modify()->set(RateLimitFilter::class, 'lock_bypage', false);
// Test rate limit hit by IP
Config::inst()->update('VersionFeed\Filters\RateLimitFilter', 'lock_byuserip', true);
$_SERVER['HTTP_CLIENT_IP'] = '127.0.0.1';
$cache->save(time() + 10, \VersionFeed\Filters\RateLimitFilter::CACHE_PREFIX . '_' . md5('127.0.0.1'));
Config::modify()->set(RateLimitFilter::class, 'lock_byuserip', true);
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$cache->set(RateLimitFilter::CACHE_PREFIX . '_' . md5('127.0.0.1'), time() + 10);
$response = $this->get($page1->RelativeLink('changes'));
$this->assertEquals(429, $response->getStatusCode());
$this->assertGreaterThan(0, $response->getHeader('Retry-After'));
// Test rate limit doesn't hit other IP
$_SERVER['HTTP_CLIENT_IP'] = '127.0.0.20';
$cache->save(time() + 10, \VersionFeed\Filters\RateLimitFilter::CACHE_PREFIX . '_' . md5('127.0.0.1'));
$_SERVER['REMOTE_ADDR'] = '127.0.0.20';
$cache->set(RateLimitFilter::CACHE_PREFIX . '_' . md5('127.0.0.1'), time() + 10);
$response = $this->get($page1->RelativeLink('changes'));
$this->assertEquals(200, $response->getStatusCode());
// Restore setting
Config::inst()->update('VersionFeed\Filters\RateLimitFilter', 'lock_byuserip', false);
Config::inst()->update('VersionFeed\Filters\RateLimitFilter', 'lock_timeout', 0);
Config::inst()->update('VersionFeed\Filters\CachedContentFilter', 'cache_enabled', false);
Config::modify()->set(RateLimitFilter::class, 'lock_byuserip', false);
Config::modify()->set(RateLimitFilter::class, 'lock_timeout', 0);
Config::modify()->set(CachedContentFilter::class, 'cache_enabled', false);
}
public function testContainsChangesForPageOnly() {
@ -195,7 +220,7 @@ class VersionFeedFunctionalTest extends FunctionalTest {
// Test requests to 'changes' action
foreach(array(true, false) as $publicHistory_Config) {
Config::inst()->update('VersionFeed', 'changes_enabled', $publicHistory_Config);
Config::modify()->set(VersionFeed::class, 'changes_enabled', $publicHistory_Config);
$expectedResponse = $publicHistory_Page && $publicHistory_Config ? 200 : 404;
$response = $this->get($page->RelativeLink('changes'));
$this->assertEquals($expectedResponse, $response->getStatusCode());
@ -204,7 +229,7 @@ class VersionFeedFunctionalTest extends FunctionalTest {
// Test requests to 'allchanges' action on each page
foreach(array(true, false) as $allChanges_Config) {
foreach(array(true, false) as $allChanges_SiteConfig) {
Config::inst()->update('VersionFeed', 'allchanges_enabled', $allChanges_Config);
Config::modify()->set(VersionFeed::class, 'allchanges_enabled', $allChanges_Config);
$siteConfig = SiteConfig::current_site_config();
$siteConfig->AllChangesEnabled = $allChanges_SiteConfig;
$siteConfig->write();

View File

@ -1,16 +1,28 @@
<?php
namespace SilverStripe\VersionFeed\Tests;
use Page;
use SilverStripe\VersionFeed\VersionFeed;
use SilverStripe\VersionFeed\VersionFeedController;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\CMS\Controllers\ContentController;
class VersionFeedTest extends SapphireTest {
protected $usesDatabase = true;
protected $requiredExtensions = array(
'SiteTree' => array('VersionFeed'),
'ContentController' => array('VersionFeed_Controller'),
);
protected static $required_extensions = [
SiteTree::class => [VersionFeed::class],
ContentController::class => [VersionFeedController::class],
];
protected $illegalExtensions = array(
'SiteTree' => array('Translatable')
);
protected $illegalExtensions = [
'SiteTree' => ['Translatable']
];
public function testDiffedChangesExcludesRestrictedItems() {
$this->markTestIncomplete();
@ -21,7 +33,7 @@ class VersionFeedTest extends SapphireTest {
}
public function testDiffedChangesTitle() {
$page = new Page(array('Title' => 'My Title'));
$page = new Page(['Title' => 'My Title']);
$page->write();
$page->publish('Stage', 'Live');