Commit f0e6e466 authored by Tomas Norre Mikkelsen's avatar Tomas Norre Mikkelsen Committed by Thomas Löffler

[FEATURE] Scheduler task to check for outdated extensions

Adds unit test for the scheduler.
Searches for outdated extension versions!
Adds change to review_state = 0 when new extension version was uploaded.
Adds check for beta versions for the last active supported version.

Change-Id: Ife63a7fe9a2b292aab096f7cde5e748bec262e25
Resolves: #54383
Reviewed-on: https://review.typo3.org/29026
Reviewed-by: Philipp Gampe
Tested-by: Philipp Gampe
Reviewed-by: Thomas Löffler
Tested-by: Thomas Löffler
parent b6649cc5
......@@ -207,7 +207,7 @@
$extension instanceof Tx_TerFe2_Domain_Model_Extension &&
(
$this->securityRole->isReviewer() ||
($extension->getLastVersion() and $extension->getLastVersion()->getReviewState() > -1)
($extension->getLastVersion() && $extension->getLastVersion()->getReviewState() != -1)
)
) {
$versionHistory = $this->versionRepository->getVersionHistory($extension, $versionHistoryCount, $skipLatestVersion);
......
......@@ -204,28 +204,24 @@
return $this->hudsonLink;
}
/**
* Setter for lastUpload
* Sets lastUpdate
*
* @param DateTime $lastUpload lastUpload
* @return void
* @param \DateTime $lastUpdate
*/
public function setLastUpload(DateTime $lastUpload) {
$this->lastUpload = $lastUpload;
public function setLastUpdate($lastUpdate) {
$this->lastUpdate = $lastUpdate;
}
/**
* Getter for lastUpdate
* Gets lastUpdate
*
* @return DateTime lastUpload
* @return \DateTime
*/
public function getLastUpload() {
return $this->lastUpload;
public function getLastUpdate() {
return $this->lastUpdate;
}
/**
* Setter for crdate
*
......@@ -471,7 +467,6 @@
return $this->lastVersion;
}
/**
* Setter for frontendUser
*
......
......@@ -186,7 +186,7 @@
protected $cglComplianceNote;
/**
* Review state (-1=insecure, 0=standard, 1=reviewed)
* Review state (-2=outdated, -1=insecure, 0=standard, 1=reviewed)
* @var integer
*/
protected $reviewState;
......@@ -259,6 +259,12 @@
*/
protected $zipFileSize;
/**
* Crdate from database
* @var DateTime
*/
protected $creationDate;
/**
* Constructor. Initializes all Tx_Extbase_Persistence_ObjectStorage instances.
*/
......@@ -527,6 +533,22 @@
return $this->state;
}
/**
* @param \DateTime $creationDate
* @return void
*/
public function setCreationDate($creationDate)
{
$this->creationDate = $creationDate;
}
/**
* @return \DateTime
*/
public function getCreationDate()
{
return $this->creationDate;
}
/**
* Setter for emCategory
......
......@@ -84,7 +84,7 @@
}
$query->matching($query->logicalAnd(
$query->greaterThanOrEqual('lastVersion.reviewState', 0),
$query->logicalNot($query->equals('lastVersion.reviewState', -1)),
$constraint
));
}
......@@ -142,7 +142,6 @@
return $this->findAll(0, $latestCount, $ordering);
}
/**
* Returns top rated extensions
*
......
<?php
/*******************************************************************
* Copyright notice
*
* (c) 2014 Tomas Norre <tomas.norre@gmail.com>
* (c) 2014 Thorsten Schneider <mail@thorsten-schneider.org>
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
******************************************************************/
/**
* Class Tx_TerFe2_Task_CheckForOutdatedExtensions
*/
class Tx_TerFe2_Task_CheckForOutdatedExtensions extends tx_scheduler_Task {
/**
* @var Tx_Extbase_Persistence_Manager
*/
protected $persistenceManager;
/**
* @var Tx_TerFe2_Domain_Repository_VersionRepository
*/
protected $versionRepository;
/**
* @var array
*/
protected $coreVersions;
/**
* @var Tx_Extbase_Object_ObjectManager
*/
protected $objectManager;
/**
* @var array
*/
protected $supportedCoreVersions = array();
/**
* Initialize Task
*
* @return void
*/
public function initializeTask() {
$this->objectManager = t3lib_div::makeInstance('Tx_Extbase_Object_ObjectManager');
$this->persistenceManager = $this->objectManager->get('Tx_Extbase_Persistence_Manager');
$this->versionRepository = $this->objectManager->get('Tx_TerFe2_Domain_Repository_VersionRepository');
$this->coreVersions = json_decode(t3lib_div::getUrl(PATH_site . $GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'] . 'currentcoredata.json'), TRUE);
}
/**
* Execute Task
*
* @return bool
*/
public function execute() {
$this->initializeTask();
// Find all extension versions which are not outdated.
$versions = $this->getNotOutdatedAndSecureVersions();
$this->getLatestAndOldestSupportedTypo3Versions();
$releaseDateOfOldestSupportedTypo3Version = $this->getReleaseDateOfOldestSupportedTypo3Version($supportedCoreVersions);
// Foreach extension
foreach ($versions as $version) {
/** @var Tx_TerFe2_Domain_Model_Version $version */
$version = $this->versionRepository->findByUid($version['uid']);
if(!$version instanceof Tx_TerFe2_Domain_Model_Version) {
continue;
}
$isOutdated = FALSE;
if ($version->getUploadDate() === NULL) {
$isOutdated = TRUE;
// Check if date is set
} elseif ($version->getUploadDate() < $releaseDateOfOldestSupportedTypo3Version) {
$isOutdated = TRUE;
// Check upload date against oldestActiveTYPO3Version first release date.
} elseif (!$this->isVersionDependingOnAnActiveSupportedTypo3Version($version->getTypo3Dependency())) {
$isOutdated = TRUE;
// Check against dependency against TYPO3 not actively supported
}
if ($isOutdated) {
$GLOBALS['TYPO3_DB']->exec_UPDATEquery(
'tx_terfe2_domain_model_version',
'uid = ' . $version->getUid(),
array(
'review_state' => -2
)
);
}
}
return TRUE;
}
/**
* Get not outdated extensions
*
* @return mixed
*/
public function getNotOutdatedAndSecureVersions() {
$rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
'uid',
'tx_terfe2_domain_model_version',
'NOT deleted AND NOT hidden AND review_state >= 0',
'',
'',
100
);
return $rows;
}
/**
* Get the release date of the oldest supported TYPO3 Version.
*
* @return int
*/
public function getReleaseDateOfOldestSupportedTypo3Version() {
$oldestMinorVersion = explode('.', $this->supportedCoreVersions['oldest']);
$oldestMinorVersion = $oldestMinorVersion[0] . '.' . $oldestMinorVersion[1];
$releaseDate = $this->coreVersions[$oldestMinorVersion]['releases'][$this->supportedCoreVersions['oldest']]['date'];
return strtotime($releaseDate);
}
/**
* Get the latest and oldest supported TYPO3 Versions.
*
* @throws RuntimeException
* @return void
*/
public function getLatestAndOldestSupportedTypo3Versions() {
if ($this->coreVersions === NULL) {
throw new RuntimeException('typo3.org JSON not accessible!', 1399140291);
}
// Collect currently supported core versions
$oldestSupportedCoreVersion = '99.99.99';
$latestSupportedCoreVersion = '0.0.0';
$allSupportedCoreVersions = array();
foreach ($this->coreVersions as $version => $coreInfo) {
// Only use keys that represent a branch number
if (preg_match('/^\d+\.\d+$/', $version)) {
if ($coreInfo['active'] == TRUE) {
$allSupportedCoreVersions[] = $version;
// Checks the latest version
$latestBranchVersion = $coreInfo['latest'];
if (!preg_match('/dev|alpha/', $latestBranchVersion)) {
if (version_compare($latestSupportedCoreVersion, $latestBranchVersion, '<')) {
$latestSupportedCoreVersion = $latestBranchVersion;
}
}
// Check the oldest active version
if (version_compare($version . '.0', $oldestSupportedCoreVersion, '<')) {
$oldestSupportedCoreVersion = $version;
}
}
}
}
// get first beta of oldest active version
$oldestSupportedCoreVersionReleases = array_reverse($this->coreVersions[$oldestSupportedCoreVersion]['releases']);
foreach ($oldestSupportedCoreVersionReleases as $subVersion => $subVersionInfo) {
if (!preg_match('/dev|alpha/', $subVersion)) {
$oldestSupportedCoreVersion = $subVersion;
break;
}
}
$this->supportedCoreVersions = array(
'latest' => $latestSupportedCoreVersion,
'oldest' => $oldestSupportedCoreVersion,
'all' => $allSupportedCoreVersions,
);
}
/**
* @param Tx_TerFe2_Domain_Model_Relation $dependency
*
* @return boolean
*/
public function isVersionDependingOnAnActiveSupportedTypo3Version($dependency) {
$result = FALSE;
if ($dependency instanceof Tx_TerFe2_Domain_Model_Relation) {
$extensionMinimumVersion = $dependency->getMinimumVersion();
$extensionMaximumVersion = $dependency->getMaximumVersion();
foreach ($this->supportedCoreVersions['all'] as $version) {
// gets core version x.x.0
$supportedMinimumVersion = t3lib_utility_VersionNumber::convertVersionNumberToInteger($version . '.0');
if ($supportedMinimumVersion >= $extensionMinimumVersion && $supportedMinimumVersion <= $extensionMaximumVersion) {
$result = TRUE;
break;
}
}
}
return $result;
}
}
\ No newline at end of file
......@@ -68,6 +68,9 @@ plugin.tx_terfe2 {
mapping {
tableName = cache_extensions
recordType = Tx_TerFe2_Domain_Model_ExtensionManagerCacheEntry
columns {
crdate.mapOnProperty = creationDate
}
}
}
}
......@@ -81,6 +84,15 @@ plugin.tx_terfe2 {
}
}
config.tx_extbase.persistence.classes {
Tx_TerFe2_Domain_Model_Version {
mapping {
columns {
crdate.mapOnProperty = creationDate
}
}
}
}
# ======================================================================
# Page object configuration of the extension "ter_fe2"
......
......@@ -16,6 +16,7 @@
<label index="tags.description">All tags</label>
<label index="versions.description">All versions</label>
<label index="last_version.description">Last version</label>
<label index="outdated.description">Outdated</label>
<label index="frontend_user.description">Frontend user</label>
</languageKey>
</data>
......
......@@ -145,6 +145,10 @@
<label index="tx_terfe2_task_importextensionsfromqueuetask.description">Imports extensions out of the queue table of TER</label>
<label index="tx_terfe2_task_importallextensionstask.name">[TER FE2] Import all extensions</label>
<label index="tx_terfe2_task_importallextensionstask.description">Import all extensions from TER tables (use it only for maintenance purposes)</label>
<label index="tx_terfe2_task_checkforoutdatedextensions.name">[TER FE2] Check for outdated extensions</label>
<label index="tx_terfe2_task_checkforoutdatedextensions.description">Check for outdated extensions, if extension is outdated the outdated flag is set.</label>
<label index="tx_terfe2_provider_mirrorprovider.name">Mirror Servers</label>
<label index="tx_terfe2_provider_fileprovider.name">Local Filesystem</label>
......
......@@ -4,7 +4,7 @@
<f:for each="{versionHistory}" as="version">
<tr
<f:if condition="{version} == {version.extension.lastVersion}">class="latest-version-row"</f:if>
<f:if condition="{version.reviewState} < 0">class="insecure-version-row"</f:if>
<f:if condition="{version.reviewState} == -1">class="insecure-version-row"</f:if>
>
<td class="col1">
<strong>{version.versionString}</strong>
......@@ -21,7 +21,7 @@
</f:if>
</td>
<td class="col3">
<f:if condition="{version.reviewState} > -1">
<f:if condition="{version.reviewState} != -1">
<f:then>
<f:link.action controller="Extension" action="download" arguments="{extension : extension, versionString : version.versionString, format : 't3x'}" title="{f:translate(key:'filesize')}: {version.t3xFileSize -> terfe2:filesize()}" class="ter-download-icon ter-download-icon-t3x"><f:translate key="download_t3x"/></f:link.action>
<f:if condition="{version.hasZipFile}">
......
<?php
/*******************************************************************
* Copyright notice
*
* (c) 2014 Thomas Löffler <thomas.loeffler@typo3.org>
* (c) 2014 Philipp Gampe <philipp.gampe@typo3.org>
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
******************************************************************/
class Tx_TerFe2_Test_Task_CheckForOutdatedExtensionsTest extends tx_phpunit_testcase {
/**
* @var Tx_TerFe2_Task_CheckForOutdatedExtensions
*/
protected $subject = NULL;
/**
* @return void
*/
public function setUp() {
$this->subject = $this->getAccessibleMock(
'Tx_TerFe2_Task_CheckForOutdatedExtensions',
array('dummy')
);
}
/**
* @test
* @return void
*/
public function subjectExists() {
$this->assertInstanceOf(
'Tx_TerFe2_Task_CheckForOutdatedExtensions',
$this->subject
);
}
/**
* @test
* @param Tx_TerFe2_Domain_Model_Relation $dependency
* @param array $supportedCoreVersions
* @dataProvider isVersionDependingOnAnActiveSupportedTypo3VersionReturnsTrueForSupportedVersionsDataProvider
* @return void
*/
public function isVersionDependingOnAnActiveSupportedTypo3VersionReturnsTrueForSupportedVersions($dependency, $supportedCoreVersions) {
$this->subject->_set('supportedCoreVersions', $supportedCoreVersions);
$this->assertTrue(
$this->subject->isVersionDependingOnAnActiveSupportedTypo3Version($dependency)
);
}
/**
* Data provider for isVersionDependingOnAnActiveSupportedTypo3VersionReturnsTrueForSupportedVersions
*
* @return array
*/
public function isVersionDependingOnAnActiveSupportedTypo3VersionReturnsTrueForSupportedVersionsDataProvider() {
$supportedCoreVersions = array(
'latest' => '6.2.1',
'oldest' => '4.5.0beta1',
'all' => array(
'4.5',
'4.7',
'6.0',
'6.1',
'6.2'
)
);
return array(
'Extension version 4.5 only is valid' => array(
$this->buildRelation('4.5.0', '4.5.99'),
$supportedCoreVersions
),
'Extension version 4.3 - 4.6 is valid because of supported 4.5' => array(
$this->buildRelation('4.3.0', '4.6.99'),
$supportedCoreVersions
),
'Extension version 4.7 only is valid' => array(
$this->buildRelation('4.7.0', '4.7.99'),
$supportedCoreVersions
),
'Extension version 6.0 only is valid' => array(
$this->buildRelation('6.0.0', '6.0.99'),
$supportedCoreVersions
),
'Extension version 6.1 only is valid' => array(
$this->buildRelation('6.1.0', '6.1.99'),
$supportedCoreVersions
),
'Extension version 6.2 only is valid' => array(
$this->buildRelation('6.2.0', '6.2.99'),
$supportedCoreVersions
),
);
}
/**
* @test
* @param Tx_TerFe2_Domain_Model_Relation $dependency
* @param array $supportedCoreVersions
* @dataProvider isVersionDependingOnAnActiveSupportedTypo3VersionReturnsFalseForUnsupportedVersionsDataProvider
* @return void
*/
public function isVersionDependingOnAnActiveSupportedTypo3VersionReturnsFalseForUnsupportedVersions($dependency, $supportedCoreVersions) {
$this->subject->_set('supportedCoreVersions', $supportedCoreVersions);
$this->assertFalse(
$this->subject->isVersionDependingOnAnActiveSupportedTypo3Version($dependency)
);
}
/**
* Data provider for isVersionDependingOnAnActiveSupportedTypo3VersionReturnsTrueForSupportedVersions
*
* @return array
*/
public function isVersionDependingOnAnActiveSupportedTypo3VersionReturnsFalseForUnsupportedVersionsDataProvider() {
$supportedCoreVersions = array(
'latest' => '6.2.1',
'oldest' => '4.5.0beta1',
'all' => array(
'4.5',
'4.7',
'6.0',
'6.1',
'6.2'
)
);
return array(
'Extension version 4.3 only is invalid' => array(
$this->buildRelation('4.3.0', '4.3.99'),
$supportedCoreVersions
),
'Extension version 4.6 only is invalid' => array(
$this->buildRelation('4.6.0', '4.6.99'),
$supportedCoreVersions
),
);
}
/**
* @param string $minVersion
* @param string $maxVersion
*
* @return Tx_TerFe2_Domain_Model_Relation
*/
protected function buildRelation($minVersion, $maxVersion) {
$relation = new Tx_TerFe2_Domain_Model_Relation();
$relation->setMinimumVersion(t3lib_utility_VersionNumber::convertVersionNumberToInteger($minVersion));
$relation->setMaximumVersion(t3lib_utility_VersionNumber::convertVersionNumberToInteger($maxVersion));
return $relation;
}
}
\ No newline at end of file
......@@ -62,6 +62,7 @@ return array(
'tx_terfe2_task_downloadcountertask' => $extensionClassesPath . 'Task/DownloadCounterTask.php',
'tx_terfe2_task_importextensionsfromqueuetask' => $extensionClassesPath . 'Task/ImportExtensionsFromQueueTask.php',
'tx_terfe2_task_importallextensionstask' => $extensionClassesPath . 'Task/ImportAllExtensionsTask.php',
'tx_terfe2_task_checkforoutdatedextensions' => $extensionClassesPath . 'Task/CheckForOutdatedExtensions.php',
'tx_terfe2_utility_archive' => $extensionClassesPath . 'Utility/Archive.php',
'tx_terfe2_utility_array' => $extensionClassesPath . 'Utility/Array.php',
'tx_terfe2_utility_datetime' => $extensionClassesPath . 'Utility/Datetime.php',
......
......@@ -114,4 +114,14 @@ $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks']['Tx_TerFe2_Task_
'title' => 'LLL:EXT:' . $_EXTKEY . '/Resources/Private/Language/locallang_db.xml:tx_terfe2_task_importallextensionstask.name',
'description' => 'LLL:EXT:' . $_EXTKEY . '/Resources/Private/Language/locallang_db.xml:tx_terfe2_task_importallextensionstask.description',
);
// Register check for outdated extensions tassk
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks']['Tx_TerFe2_Task_CheckForOutdatedExtensions'] = array(
'extension' => $_EXTKEY,
'title' => 'LLL:EXT:' . $_EXTKEY . '/Resources/Private/Language/locallang_db.xml:tx_terfe2_task_checkforoutdatedextensions.name',
'description' => 'LLL:EXT:' . $_EXTKEY . '/Resources/Private/Language/locallang_db.xml:tx_terfe2_task_checkforoutdatedextensions.description',
);
?>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment