Commit fbf3f928 authored by Thomas Löffler's avatar Thomas Löffler

[TASK] Introduces extension key expire process

Change-Id: I4dbd0b04844e1ea2932234de02bae9005bd96133
Resolves: #76882
Reviewed-on: https://review.typo3.org/48751Tested-by: Thomas Löffler's avatarThomas Löffler <loeffler@spooner-web.de>
Reviewed-by: Andreas Beutel's avatarAndreas Beutel <Andreas.Beutel@mehrwert.de>
Reviewed-by: Jigal van Hemert's avatarJigal van Hemert <jigal.van.hemert@typo3.org>
Reviewed-by: Thomas Löffler's avatarThomas Löffler <loeffler@spooner-web.de>
parent 8bee5bb9
......@@ -76,7 +76,9 @@ class Tx_TerFe2_Controller_RegisterkeyController extends Tx_TerFe2_Controller_Ab
// get extensions by user if a user is logged in
if (!empty($this->frontendUser)) {
$extensions = $this->extensionRepository->findByFrontendUser($this->frontendUser['username']);
$expiringExtensions = $this->extensionRepository->findByFrontendUserAndExpiring($this->frontendUser['username']);
$this->view->assign('extensions', $extensions);
$this->view->assign('expiringExtensions', $expiringExtensions);
$this->view->assign('uploaded', $uploaded);
}
}
......@@ -450,6 +452,21 @@ class Tx_TerFe2_Controller_RegisterkeyController extends Tx_TerFe2_Controller_Ab
$this->redirect('index', 'Registerkey');
}
/**
* Sets the expire back to zero and touches the extension
* The process for getting expiring extensions will be back in 1 year
*
* @param \Tx_TerFe2_Domain_Model_Extension $extension
* @dontvalidate $extension
* @return void
* @throws \Tx_Extbase_MVC_Exception_UnsupportedRequestType
*/
public function keepAction(Tx_TerFe2_Domain_Model_Extension $extension) {
$extension->setExpire(0);
$this->extensionRepository->update($extension);
$this->redirect('index', 'Registerkey');
}
/**
* Delete an extension version from ter server
*
......
......@@ -134,6 +134,11 @@
*/
protected $paypalUrl;
/**
* @var \DateTime
*/
protected $expire;
/**
* Constructor. Initializes all Tx_Extbase_Persistence_ObjectStorage instances.
......@@ -641,6 +646,19 @@
return $this->flattrData;
}
/**
* @return \DateTime
*/
public function getExpire() {
return $this->expire;
}
/**
* @param \DateTime $expire
*/
public function setExpire($expire) {
$this->expire = $expire;
}
/**
* Recalculate sum of all downloads
......
......@@ -107,7 +107,7 @@
$this->match($query, $query->logicalNot($query->equals('lastVersion.title', '')));
return $query->execute();
}
/**
* Returns all objects of this repository
*
......@@ -202,7 +202,7 @@
}
/**
*
*
* @param string $frontendUser
* @return Tx_Extbase_Persistence_ObjectStorage Objects
*/
......@@ -211,11 +211,37 @@
$query->setOrderings(
array('extKey' => Tx_Extbase_Persistence_QueryInterface::ORDER_ASCENDING)
);
$this->match($query, $query->like('frontendUser', $frontendUser));
return $query->execute();
}
/**
*
* @param string $frontendUser
* @return Tx_Extbase_Persistence_QueryResult|NULL
*/
public function findByFrontendUserAndExpiring($frontendUser) {
$query = $this->createQuery();
$query->setOrderings(
array('expire' => Tx_Extbase_Persistence_QueryInterface::ORDER_ASCENDING)
);
$olderThanOneYear = strtotime('-1 year');
$query->matching(
$query->logicalAnd(
array(
$query->equals('frontendUser', $frontendUser),
$query->equals('versions', 0),
$query->greaterThan('expire', 0),
$query->lessThanOrEqual('tstamp', $olderThanOneYear)
)
)
);
return $query->execute();
}
/**
* Search extensions by search words and filters
*
......
<?php
/**
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
/**
* Class Tx_TerFe2_Task_CheckForExpiredExtensions
*/
class Tx_TerFe2_Task_CheckForExpiredExtensions extends tx_scheduler_Task {
/**
* @var array
*/
protected $blacklistUsers = array();
/**
* Execute Task
*
* @return bool
*/
public function execute() {
$this->blacklistUsers = array(
'abandoned_extensions',
'typo3v4'
);
$expiringExtensions = $this->getDatabaseConnection()->exec_SELECTgetRows(
'uid, ext_key, frontend_user',
'tx_terfe2_domain_model_extension',
'NOT deleted AND NOT expire AND versions = 0 AND tstamp <= ' . strtotime('-1 year'),
'',
'frontend_user'
);
// group extensions by owner
$expiredExtensionsByOwner = array();
foreach ($expiringExtensions as $expiringExtension) {
if ($expiringExtension['ext_key'] && $expiringExtension['frontend_user']) {
$expiredExtensionsByOwner[$expiringExtension['frontend_user']][] = $expiringExtension;
}
}
foreach ($expiredExtensionsByOwner as $username => $extensions) {
if (in_array($username, $this->blacklistUsers, TRUE)) {
continue;
}
$frontendUser = $this->getDatabaseConnection()->exec_SELECTgetSingleRow(
'uid, email',
'fe_users',
'username = ' . $this->getDatabaseConnection()->fullQuoteStr($username, 'fe_users')
. t3lib_BEfunc::BEenableFields('fe_users') . t3lib_BEfunc::deleteClause('fe_users')
);
if (!empty($frontendUser) && t3lib_div::validEmail($frontendUser['email'])) {
$to = $frontendUser['email'];
$subject = 'Your extension keys are going to expire!';
/** @var Tx_Fluid_View_StandaloneView $body */
$body = t3lib_div::makeInstance('Tx_Fluid_View_StandaloneView');
$body->setTemplatePathAndFilename(t3lib_div::getFileAbsFileName('EXT:ter_fe2/Resources/Private/Templates/Mail/ExpiredExtensions.html'));
$body->assign('extensions', $extensions);
/** @var t3lib_mail_Message $mail */
$mail = t3lib_div::makeInstance('t3lib_mail_Message');
$mail->addFrom('maintenance@typo3.org');
$mail->setTo($to);
$mail->setSubject($subject);
$mail->setBody($body->render());
if ($mail->send()) {
// set every extension of the owner to expire in 30 days
foreach ($extensions as $extension) {
$this->getDatabaseConnection()->exec_UPDATEquery(
'tx_terfe2_domain_model_extension',
'uid = ' . (int)$extension['uid'],
array(
'expire' => strtotime('+30 days')
)
);
}
}
}
}
// remove expired extensions
$expiredExtensions = $this->getDatabaseConnection()->exec_SELECTgetRows(
'uid, ext_key',
'tx_terfe2_domain_model_extension',
'NOT deleted AND expire > 0 AND expire <= ' . time() . ' AND versions = 0'
);
foreach ($expiredExtensions as $expiredExtension) {
// Deleted in ter, then delete the key in the ter_fe2 extension table
if ($expiredExtension['ext_key'] && $this->deleteExtensionKeyInTer($expiredExtension['ext_key'])) {
$this->getDatabaseConnection()->exec_DELETEquery(
'tx_terfe2_domain_model_extension',
'uid = ' . $expiredExtension['uid']
);
}
}
return TRUE;
}
/**
* @param $extensionKey
* @return bool|resource
*/
protected function deleteExtensionKeyInTer($extensionKey) {
// check if there are extension versions
$versions = $this->getDatabaseConnection()->exec_SELECTcountRows(
'extensionkey',
'tx_ter_extensions',
'extensionkey=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($extensionKey, 'tx_ter_extensions')
);
if (!$versions || $versions === 0) {
return $this->getDatabaseConnection()->exec_DELETEquery(
'tx_ter_extensionkeys',
'extensionkey=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($extensionKey, 'tx_ter_extensions')
);
}
return FALSE;
}
/**
* @return t3lib_DB
*/
protected function getDatabaseConnection() {
return $GLOBALS['TYPO3_DB'];
}
}
\ No newline at end of file
......@@ -24,7 +24,7 @@
</numIndex>
<numIndex index="1" type="array">
<numIndex index="0">LLL:EXT:ter_fe2/Resources/Private/Language/locallang_db.xml:tt_content.flexform_pi1.s_def.switchableControllerActions.1</numIndex>
<numIndex index="1">Registerkey->index;Registerkey->admin;Registerkey->create;Registerkey->edit;Registerkey->manage;Registerkey->update;Registerkey->delete;Registerkey->deleteExtensionVersion;Registerkey->transfer;Registerkey->salvage;Extension->uploadVersion;Extension->createVersion;Extension->edit;Extension->update;Extension->removeTag</numIndex>
<numIndex index="1">Registerkey->index;Registerkey->admin;Registerkey->create;Registerkey->edit;Registerkey->manage;Registerkey->update;Registerkey->delete;Registerkey->deleteExtensionVersion;Registerkey->transfer;Registerkey->salvage;Extension->uploadVersion;Extension->createVersion;Extension->edit;Extension->update;Extension->removeTag;Registerkey->keep</numIndex>
</numIndex>
<numIndex index="2" type="array">
<numIndex index="0">LLL:EXT:ter_fe2/Resources/Private/Language/locallang_db.xml:tt_content.flexform_pi1.s_def.switchableControllerActions.2</numIndex>
......
......@@ -6,10 +6,10 @@
$GLOBALS['TCA']['tx_terfe2_domain_model_extension'] = array(
'ctrl' => $GLOBALS['TCA']['tx_terfe2_domain_model_extension']['ctrl'],
'interface' => array(
'showRecordFieldList' => 'ext_key,forge_link,last_update,last_maintained,categories,tags,versions,last_version,frontend_user,downloads,repository_url,repository_clone_url,paypal_url,external_manual',
'showRecordFieldList' => 'ext_key,forge_link,last_update,last_maintained,categories,tags,versions,last_version,frontend_user,downloads,repository_url,repository_clone_url,paypal_url,external_manual,expire',
),
'types' => array(
'1' => array('showitem' => 'ext_key,forge_link,last_update,last_maintained,categories,tags,versions,last_version,frontend_user,downloads,repository_url,repository_clone_url,paypal_url,external_manual'),
'1' => array('showitem' => 'ext_key,forge_link,last_update,last_maintained,categories,tags,versions,last_version,frontend_user,downloads,repository_url,repository_clone_url,paypal_url,external_manual,expire'),
),
'palettes' => array(
'1' => array('showitem' => ''),
......@@ -239,6 +239,14 @@
'eval' => 'trim',
),
),
'expire' => array(
'exclude' => 1,
'label' => 'LLL:EXT:ter_fe2/Resources/Private/Language/locallang_db.xml:tx_terfe2_domain_model_extension.expire',
'config' => array(
'type' => 'none',
'format' => 'datetime'
),
),
),
);
?>
\ No newline at end of file
......@@ -114,6 +114,7 @@
<label index="msg.createVersionUploadNotAllowed">You are not allowed to upload this extension.</label>
<label index="msg.createVersionUploadSuccess"><![CDATA[Thank you for the upload of your new extension version. It may take up to 15 minutes until it appears in TER.]]></label>
<label index="msg.createVersionUploadFailed">Extension upload failed.</label>
<label index="msg.expiringExtensions">These extension keys will expire within 30 days. If no action is taken on your part the extension key will be released for reuse.</label>
<label index="msg.acceptGPL">Please confirm, that your extension is GPL v2 or any later version compliant!</label>
<label index="header.latest_extensions">Latest Extensions</label>
......@@ -305,10 +306,13 @@
<label index="modifiy-button">Modifiy</label>
<label index="delete-button">Delete</label>
<label index="edit-button">Edit</label>
<label index="release-button">Release to community</label>
<label index="uploadVersion-button">Upload</label>
<label index="editExtension-button">Edit</label>
<label index="keepExtension-button">Keep</label>
<label index="register-extension-key">Register extension key</label>
<label index="manage-extension-keys">Manage extension keys</label>
<label index="manage-expiring-extension-keys">Expiring extension keys</label>
<label index="modifiy-extension-key">Modifiy extension keys</label>
<label index="transfer-extension-key">Transfer extension key</label>
......
......@@ -22,6 +22,7 @@
<label index="tx_terfe2_domain_model_extension.repository_clone_url">Publicly accessible clone url</label>
<label index="tx_terfe2_domain_model_extension.external_manual">External manual</label>
<label index="tx_terfe2_domain_model_extension.donate_url">Sponsoring link</label>
<label index="tx_terfe2_domain_model_extension.expire">Extension key expires at</label>
<label index="tx_terfe2_domain_model_category">Category</label>
<label index="tx_terfe2_domain_model_category.title">Title</label>
......@@ -146,6 +147,8 @@
<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_task_checkforexpiredextensions.name">[TER FE2] Check for expired extensions</label>
<label index="tx_terfe2_task_checkforexpiredextensions.description">Check for expired extensions, if extension is expired a mail to the owner is sent.</label>
......
Dear extension owner,
You have {extensions -> f:count()} extension key[s] in your repository which have never had an upload or weren't touched for one year.
Due to cleanup process we want to inform you that these extension keys will expire in 30 days unless you take action (see below):
<f:for each="{extensions}" as="extension"># {extension.ext_key}
</f:for>
Log into typo3.org and visit the page https://typo3.org/extensions/extension-keys/ to get a list of these keys and available actions:
* Releasing the extension key to the public, so another developer can use this key
* Keep the extension key (the process of expiration will be started again in one year)
* Upload a version of this extension to the TER
Warning: If no action is taken the extension keys listed above will be released to the community (deleted from the list of registered keys). Extension keys with publicly released extension versions in the TER won't be affected.
Best regards,
Your typo3.org maintenance and Extension Coordination team
--
This is an automatic message from the typo3.org system
Contact us: https://typo3.org/teams-committees/typo3org/ or just reply to this email
\ No newline at end of file
......@@ -15,6 +15,13 @@
<div class="b-tabs">
<ul class="tabs lite-tabs">
<f:if condition="{expiringExtensions}">
<li>
<a href="#tx_terfe2_tab_manageexpiringkeys">
<f:translate key="manage-expiring-extension-keys" />
</a>
</li>
</f:if>
<li>
<a href="#tx_terfe2_tab_managekeys">
<f:translate key="manage-extension-keys" />
......@@ -43,6 +50,80 @@
<div class="tab-panes">
<!-- open expiring tab -->
<f:if condition="{expiringExtensions}">
<div class="tab-content lite-tab-panes-black">
<f:if condition="{loggedIn}">
<f:then>
<div class="tx_terfe2_messages">
<div class="typo3-messages">
<div class="typo3-message message-notice">
<div class="message-body">
<f:translate key="LLL:EXT:ter_fe2/Resources/Private/Language/locallang.xml:msg.expiringExtensions" />
</div>
</div>
</div>
</div>
<p>
<strong>In this list there are only extension keys which have not been used for an extension yet!</strong><br />
The following actions are available for your expiring extension keys:
</p>
<ul>
<li><strong>Release to community</strong>: Extension key will be deleted and set free for re-registration.</li>
<li><strong>Keep</strong>: You'll keep the extension key for one more year. If there is no upload within this time then the expiry process will repeat.</li>
<li><strong>Upload</strong>: You may upload a new version for this extension.</li>
</ul>
<table class="manage-keys">
<thead>
<tr>
<th>
<f:translate key="extensionKey" />
</th>
</tr>
</thead>
<tbody>
<f:for each="{expiringExtensions}" as="extension">
<!-- cycle values for rows -->
<f:cycle values="{0: 'tr-odd', 1: 'tr-even'}" as="columCycle">
<tr class="{columCycle}">
<td>
<div class="terfe-buttons">
<f:link.action class="bu bu-mini dark-grey"
onclick="if (confirm('Really release?')) return true; else return false;"
action="delete" controller="Registerkey"
arguments="{extension: extension}">
<f:translate key="release-button" />
</f:link.action>
<f:link.action class="bu bu-mini" action="keep" controller="Registerkey"
arguments="{extension: extension}">
<f:translate key="keepExtension-button" />
</f:link.action>
<f:link.action class="bu bu-mini manage-keys-submit" action="uploadVersion"
controller="Extension" arguments="{extension: extension}"
pageUid="{settings.pages.uploadVersionPID}">
<f:translate key="uploadVersion-button" />
</f:link.action>
</div>
{extension.extKey}
<br />
<span class="b-comment-date">Expires: {extension.expire -> f:format.date(format:'d.m.Y H:i (T)')}</span>
</td>
</tr>
</f:cycle>
</f:for>
</tbody>
</table>
</f:then>
<f:else>
<f:translate key="registerkey.notloggedin" />
</f:else>
</f:if>
</div>
</f:if>
<!-- open manage tab -->
<div class="tab-content lite-tab-panes-black">
......
......@@ -63,6 +63,7 @@ return array(
'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_task_checkforexpiredextensions' => $extensionClassesPath . 'Task/CheckForExpiredExtensions.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',
......
......@@ -14,7 +14,7 @@ Tx_Extbase_Utility_Extension::configurePlugin(
'Author' => 'list, edit, update, show',
'Media' => 'list, new, create, edit, update, delete, show',
# 'Registerkey' => 'index, create, manage, update, edit, transfer, delete',
'Registerkey' => 'index, admin, deleteExtensionVersion, create, manage, transfer, delete, salvage',
'Registerkey' => 'index, admin, deleteExtensionVersion, create, manage, transfer, delete, salvage, keep',
'Review' => 'update',
),
array(
......@@ -24,7 +24,7 @@ Tx_Extbase_Utility_Extension::configurePlugin(
'Author' => 'update',
'Media' => 'create, delete',
# 'Registerkey' => 'index, create, manage, update, edit, transfer, delete',
'Registerkey' => 'index, admin, deleteExtensionVersion, create, manage, transfer, delete, salvage',
'Registerkey' => 'index, admin, deleteExtensionVersion, create, manage, transfer, delete, salvage, keep',
'Review' => 'update',
)
);
......@@ -122,6 +122,13 @@ $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks']['Tx_TerFe2_Task_
'description' => 'LLL:EXT:' . $_EXTKEY . '/Resources/Private/Language/locallang_db.xml:tx_terfe2_task_checkforoutdatedextensions.description',
);
// Register check for expired extensions tassk
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks']['Tx_TerFe2_Task_CheckForExpiredExtensions'] = array(
'extension' => $_EXTKEY,
'title' => 'LLL:EXT:' . $_EXTKEY . '/Resources/Private/Language/locallang_db.xml:tx_terfe2_task_checkforexpiredextensions.name',
'description' => 'LLL:EXT:' . $_EXTKEY . '/Resources/Private/Language/locallang_db.xml:tx_terfe2_task_checkforexpiredextensions.description',
);
$GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['ter_fe2:extension'] = 'EXT:ter_fe2/Classes/Controller/Eid/ExtensionController.php';
......
......@@ -21,6 +21,7 @@ CREATE TABLE tx_terfe2_domain_model_extension (
repository_clone_url varchar(255) DEFAULT '' NOT NULL,
external_manual varchar(255) DEFAULT '' NOT NULL,
paypal_url varchar(255) DEFAULT '' NOT NULL,
expire int(11) unsigned default '0' NOT NULL,
tstamp int(11) unsigned DEFAULT '0' NOT NULL,
crdate int(11) unsigned DEFAULT '0' NOT NULL,
......
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