Commit e5ee1dcd authored by Benni Mack's avatar Benni Mack
Browse files

[!!!][TASK] Drop usage of tx_ter_extensionkeys

The database table tx_ter_extensionkeys containing all registered
extensionkeys is dropped in favor of "tx_terfe2_domain_model_extension".

This table was synced already anyways, and can now be used within extensions.typo3.org
without having to sync with a cronjob anymore.

Breaking: The information about "title" and "description" is removed, as it wasn't
required via the Web GUI when registering a key already.

The sync task / TER importer now only imports the uploaded versions, the SOAP API
now creates records directly in tx_terfe2_domain_model_extension when
registering a new extension key.

The One-Time-Migration-Script by tomalo (ImportAllExtensionKeysTask) is
now removed as it is not needed anymore.
parent 008ae27a
Pipeline #9269 passed with stages
in 8 minutes and 13 seconds
......@@ -61,12 +61,12 @@ class ExtensionKey
public function isRegistered(): bool
{
$cleanedExtensionKey = str_replace('_', '', $this->extensionKey);
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_ter_extensionkeys');
$result = $queryBuilder->select('extensionkey')
->from('tx_ter_extensionkeys')
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_terfe2_domain_model_extension');
$result = $queryBuilder->select('ext_key')
->from('tx_terfe2_domain_model_extension')
->add(
'where',
'REPLACE(extensionkey, "_", "") = ' . $queryBuilder->createNamedParameter($cleanedExtensionKey)
'REPLACE(ext_key, "_", "") = ' . $queryBuilder->createNamedParameter($cleanedExtensionKey)
)
->execute()
->rowCount();
......@@ -76,12 +76,12 @@ class ExtensionKey
public function getOwner(): ?string
{
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_ter_extensionkeys');
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_terfe2_domain_model_extension');
$ownerUserName = $queryBuilder
->select('ownerusername')
->from('tx_ter_extensionkeys')
->select('frontend_user')
->from('tx_terfe2_domain_model_extension')
->where(
$queryBuilder->expr()->eq('extensionkey', $queryBuilder->createNamedParameter($this->extensionKey))
$queryBuilder->expr()->eq('ext_key', $queryBuilder->createNamedParameter($this->extensionKey))
)
->execute()
->fetchColumn();
......@@ -117,8 +117,6 @@ class ExtensionKey
* Add a new extension key.
*
* @param ApiUser $authenticatedUser
* @param string $title
* @param string $description
* @param string $ownerUserName
* @return bool
* @throws ExtensionKeyAlreadyInUseException
......@@ -127,12 +125,8 @@ class ExtensionKey
* @throws UnauthorizedException
* @throws UserNotFoundException
*/
public function registerKey(
ApiUser $authenticatedUser,
string $title,
string $description,
string $ownerUserName
) {
public function registerKey(ApiUser $authenticatedUser, string $ownerUserName)
{
if (!$authenticatedUser->isAuthenticated()) {
throw new UnauthorizedException('Access denied.', ResultCodes::ERROR_GENERAL_USERNOTFOUND);
}
......@@ -159,13 +153,14 @@ class ExtensionKey
'pid' => GeneralUtility::makeInstance(Configuration::class)->getStoragePid(),
'tstamp' => $GLOBALS['EXEC_TIME'],
'crdate' => $GLOBALS['EXEC_TIME'],
'extensionkey' => $this->extensionKey,
'title' => mb_strcut($title, 0, 50, 'utf-8'),
'description' => mb_strcut($description, 0, 255, 'utf-8'),
'ownerusername' => $ownerUserName
'ext_key' => $this->extensionKey,
'frontend_user' => $ownerUserName,
'last_upload' => 0,
'versions' => 0,
'last_version' => 0,
];
$conn = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('tx_ter_extensionkeys');
$result = $conn->insert('tx_ter_extensionkeys', $extensionKeysRow);
$conn = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('tx_terfe2_domain_model_extension');
$result = $conn->insert('tx_terfe2_domain_model_extension', $extensionKeysRow);
if ($result === 0) {
throw new InternalServerErrorException(
'Database error while inserting extension key.',
......@@ -206,11 +201,11 @@ class ExtensionKey
throw new UserNotFoundException('The user is not an active typo3.org user', ResultCodes::ERROR_GENERAL_USERNOTFOUND);
}
$conn = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('tx_ter_extensionkeys');
$conn = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('tx_terfe2_domain_model_extension');
$affectedRows = $conn->update(
'tx_ter_extensionkeys',
['ownerusername' => $newOwnerName],
['extensionkey' => $this->extensionKey]
'tx_terfe2_domain_model_extension',
['frontend_user' => $newOwnerName],
['ext_key' => $this->extensionKey]
);
if (!$affectedRows) {
throw new InternalServerErrorException(
......@@ -240,8 +235,8 @@ class ExtensionKey
if (!empty($items)) {
throw new VersionExistsException('Cannot delete an extension, versions still exist', ResultCodes::ERROR_DELETEEXTENSIONKEY_CANTDELETEBECAUSEVERSIONSEXIST);
}
$conn = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('tx_ter_extensionkeys');
$conn->delete('tx_ter_extensionkeys', ['extensionkey' => $this->extensionKey]);
$conn = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('tx_terfe2_domain_model_extension');
$conn->delete('tx_terfe2_domain_model_extension', ['ext_key' => $this->extensionKey]);
}
/**
......@@ -305,42 +300,26 @@ class ExtensionKey
* @todo: this method does not belong here, should be moved to a different location and return objects in the future
*
* @param string|null $limitToUserName
* @param string|null $limitToTitle
* @param string|null $limitToDescription
* @param string|null $limitToExtensionKey
* @return array|null
*/
public static function findExtensionKeys(
?string $limitToUserName,
?string $limitToTitle,
?string $limitToDescription,
?string $limitToExtensionKey
): ?array {
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_ter_extensionkeys');
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_terfe2_domain_model_extension');
$queryBuilder
->select('extensionkey,title,description,ownerusername')
->from('tx_ter_extensionkeys');
->select('ext_key', 'frontend_user')
->from('tx_terfe2_domain_model_extension');
if ($limitToUserName) {
$queryBuilder->andWhere(
$queryBuilder->expr()->eq('ownerusername', $queryBuilder->createNamedParameter($limitToUserName))
);
}
if ($limitToTitle) {
$queryBuilder->andWhere(
$queryBuilder->expr()->eq('title', $queryBuilder->createNamedParameter($limitToTitle))
);
}
if ($limitToDescription) {
$queryBuilder->andWhere(
$queryBuilder->expr()->eq('description', $queryBuilder->createNamedParameter($limitToDescription))
$queryBuilder->expr()->eq('frontend_user', $queryBuilder->createNamedParameter($limitToUserName))
);
}
if ($limitToExtensionKey) {
$queryBuilder->andWhere(
$queryBuilder->expr()->eq('extensionkey', $queryBuilder->createNamedParameter($limitToExtensionKey))
$queryBuilder->expr()->eq('ext_key', $queryBuilder->createNamedParameter($limitToExtensionKey))
);
}
......
<?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!
*/
return [
'ctrl' => [
'label' => 'extensionkey',
'default_sortby' => 'ORDER BY extensionkey',
'tstamp' => 'tstamp',
'crdate' => 'crdate',
'title' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensionkeys',
'iconfile' => 'EXT:ter/tx_ter_extensionkeys.gif',
],
'interface' => [
'showRecordFieldList' => 'extensionkey',
],
'columns' => [
'title' => [
'label' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensionkeys.title',
'config' => [
'type' => 'input',
'size' => 40,
'max' => 250,
'eval' => 'trim,required',
],
],
'description' => [
'label' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensionkeys.description',
'config' => [
'type' => 'text',
'cols' => 40,
'rows' => 5,
],
],
'extensionkey' => [
'label' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensionkeys.extensionkey',
'config' => [
'type' => 'input',
'size' => 40,
'max' => 30,
'eval' => 'trim,unique,required',
],
],
'ownerusername' => [
'label' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensionkeys.ownerusername',
'config' => [
'type' => 'input',
'size' => 40,
'max' => 30,
'eval' => 'trim',
],
],
'downloadcounter' => [
'label' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensions.downloadcounter',
'config' => [
'type' => 'input',
'size' => 5,
'max' => 11,
],
],
],
'types' => [
'1' => ['showitem' => 'title,description,extensionkey,ownerusername,downloadcounter'],
]
];
......@@ -237,8 +237,6 @@ class tx_ter_api
$extensionKeyObject = new ExtensionKey($registerExtensionKeyData->extensionKey);
$extensionKeyObject->registerKey(
$user,
$registerExtensionKeyData->title ?? '',
$registerExtensionKeyData->description ?? '',
$registerExtensionKeyData->ownerUsername ?? $user->getUsername()
);
$resultCode = ResultCodes::RESULT_EXTENSIONKEYSUCCESSFULLYREGISTERED;
......@@ -270,13 +268,22 @@ class tx_ter_api
{
$extensionKeyDataArr = ExtensionKey::findExtensionKeys(
$extensionKeyFilterOptions->username ?? null,
$extensionKeyFilterOptions->title ?? null,
$extensionKeyFilterOptions->description ?? null,
$extensionKeyFilterOptions->extensionKey ?? null
);
// Format to legacy structure
$extensionKeys = [];
foreach ($extensionKeyDataArr as $extensionKey) {
$extensionKeys[] = [
'extensionkey' => $extensionKey['ext_key'],
'title' => '',
'description' => '',
'ownerusername' => $extensionKey['frontend_user']
];
}
return [
'simpleResult' => $this->formatAsSimpleResult(ResultCodes::RESULT_GENERAL_OK),
'extensionKeyData' => $extensionKeyDataArr
'extensionKeyData' => $extensionKeys
];
}
......
#
# Table structure for table 'tx_ter_extensionkeys'
#
CREATE TABLE tx_ter_extensionkeys (
uid int(11) unsigned DEFAULT '0' NOT NULL auto_increment,
pid int(11) unsigned DEFAULT '0' NOT NULL,
tstamp int(11) unsigned DEFAULT '0' NOT NULL,
crdate int(11) unsigned DEFAULT '0' NOT NULL,
title varchar(50) DEFAULT '' NOT NULL,
description text NOT NULL,
extensionkey varchar(30) DEFAULT '' NOT NULL,
ownerusername varchar(30) DEFAULT '' NOT NULL,
downloadcounter int(11) DEFAULT '0' NOT NULL,
PRIMARY KEY (uid),
KEY extkey (extensionkey,pid),
KEY exttitle (title,pid)
);
#
# Table structure for table 'tx_ter_extensions'
......
......@@ -6,12 +6,6 @@
</meta>
<data type="array">
<languageKey index="default" type="array">
<label index="tx_ter_extensionkeys">Extension key</label>
<label index="tx_ter_extensionkeys.title">Title</label>
<label index="tx_ter_extensionkeys.description">Description</label>
<label index="tx_ter_extensionkeys.extensionkey">Extension key</label>
<label index="tx_ter_extensionkeys.ownerusername">Owner username</label>
<label index="tx_ter_extensionkeys.downloadcounter">Download counter</label>
<label index="tx_ter_extensions">Extension</label>
<label index="tx_ter_extensions.extensionkey">Extension key</label>
<label index="tx_ter_extensions.version">Version</label>
......
......@@ -14,6 +14,7 @@ namespace T3o\TerFe2\Controller;
* The TYPO3 project - inspiring people to share!
*/
use T3o\Ter\Api\ExtensionKey;
use T3o\TerFe2\Validation\Validator\ComposerNameValidator;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Page\PageRenderer;
......@@ -593,17 +594,12 @@ class ExtensionController extends \T3o\TerFe2\Controller\AbstractController
return false;
}
$connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('tx_ter_extensionkeys');
$isAllowedToUploadKey = $connection->count(
'uid',
'tx_ter_extensionkeys',
[
'ownerusername' => $this->frontendUser['username'],
'extensionkey' => $extensionKey
]
);
return !empty($isAllowedToUploadKey);
// Let's use a proper API in the future here.
$extensionKeyObject = GeneralUtility::makeInstance(ExtensionKey::class, $extensionKey);
if (strtolower($extensionKeyObject->getOwner()) === strtolower($this->frontendUser['username'])) {
return true;
}
return false;
}
/**
......
......@@ -20,8 +20,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
* This class combines all data of an extension and all versions from various database tables
*
* tx_ter_extensions -> contains all versions of all extensions
* tx_ter_extensionkeys -> contains all registered extension keys (even if there was no version uploaded)
* tx_terfe2_domain_model_extension -> contains information of an external manual
* tx_terfe2_domain_model_extension -> contains all registered extension keys and meta data (even if there was no version uploaded)
*
* Currently this class is used as a wrapper, but should vanish once we migrated the database structures properly
*/
......@@ -47,29 +46,20 @@ class CombinedExtensionRepository
{
$basicExtensionInformation = [];
foreach ($extensionKeys as $extensionKey) {
$keysQueryBuilder = $this->getQueryBuilder('tx_ter_extensionkeys');
$keysQueryBuilder = $this->getQueryBuilder('tx_terfe2_domain_model_extension');
$extensionKeyRow = $keysQueryBuilder
->select('ownerusername', 'downloadcounter')
->from('tx_ter_extensionkeys')
->where(
$keysQueryBuilder->expr()->eq('extensionkey', $keysQueryBuilder->createNamedParameter($extensionKey))
)
->execute()
->fetch();
$manualQueryBuilder = $this->getQueryBuilder('tx_terfe2_domain_model_extension');
$manualRecord = $manualQueryBuilder
->select('uid', 'external_manual')
->select('uid', 'frontend_user', 'downloadcounter', 'external_manual')
->from('tx_terfe2_domain_model_extension')
->where(
$manualQueryBuilder->expr()->eq('ext_key', $manualQueryBuilder->createNamedParameter($extensionKey))
$keysQueryBuilder->expr()->eq('ext_key', $keysQueryBuilder->createNamedParameter($extensionKey))
)
->execute()
->fetch();
$basicExtensionInformation[$extensionKey] = [
'ownerusername' => $extensionKeyRow['ownerusername'],
'downloads' => $extensionKeyRow['downloadcounter'],
'external_manual' => $manualRecord['external_manual'] ?: ''
'ownerusername' => $extensionKeyRow['frontend_user'],
'downloads' => $extensionKeyRow['downloads'],
'external_manual' => $extensionKey['external_manual'] ?: ''
];
}
return $basicExtensionInformation;
......
......@@ -227,6 +227,7 @@ class CheckForExpiredExtensions extends Task
}
/**
* This method can be removed as soon as tx_ter_extensions is not in use anymore.
* @param $extensionKey
* @return bool|resource
*/
......@@ -246,12 +247,7 @@ class CheckForExpiredExtensions extends Task
if (!$versionCount || $versionCount === 0) {
$this->logger->info(sprintf('Deleted extension key %s as it did not have versions.', $extensionKey));
return $extensionsConnection->delete(
'tx_ter_extensionkeys',
[
'extensionkey' => $extensionKey
]
);
return true;
}
return false;
......
<?php
namespace T3o\TerFe2\Task;
/*
* 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!
*/
use T3o\TerFe2\Domain\Model\Extension;
use T3o\TerFe2\Domain\Repository\ExtensionRepository;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Extensionmanager\Domain\Repository\RepositoryRepository;
/**
* This is a one-time task to get all extension keys from ter tables
* to the new ter_fe2 tables.
* Then the process for expired extensions can run.
*
* @author Thomas Löffler <loeffler@spooner-web.de>
*/
class ImportAllExtensionKeysTask extends \TYPO3\CMS\Extbase\Scheduler\Task
{
/**
* PID for all extension related records
*
* @var int $pid
*/
protected $pid = 2;
/**
* @var ObjectManager
*/
protected $objectManager;
/**
* @var ExtensionRepository
*/
protected $extensionRepository;
/**
* @param ObjectManager $objectManager
*/
protected function injectObjectManager(ObjectManager $objectManager)
{
$this->objectManager = $objectManager;
}
/**
* executes the importer
*
* @return bool
*/
public function execute()
{
$this->extensionRepository = $this->objectManager->get(RepositoryRepository::class);
$extensionKeysFromTer = $this->getAllExtensionKeysFromTer();
foreach ($extensionKeysFromTer as $extensionData) {
if (!$this->extensionExists($extensionData)) {
$versionCount = $this->getVersionCount($extensionData['extensionkey']);
if ($versionCount === 0) {
$this->createExtension($extensionData);
}
}
}
return true;
}
/**
* Gets the extension key data out of ter tables
*
* @return array $extData
*/
public function getAllExtensionKeysFromTer(): array
{
$extData = [];
$connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('tx_ter_extensionkeys');
$result = $connection->select(
['*'],
'tx_ter_extensionkeys'
);
while ($row = $result->fetch()) {
$extData[] = $row;
}
return $extData;
}
/**
* @param array $extData
* @return bool|int
* @deprecated Will be removed June 2020
*/
public function extensionExists($extData)
{
$extensionRepository = $this->objectManager->get(ExtensionRepository::class);
$extension = $extensionRepository->findOneByExtKey($extData['extensionkey']);
if ($extension instanceof Extension) {
return $extension->getUid();
}
return false;
}
/**
* @param $extensionKey
* @return int
*/
public function getVersionCount($extensionKey)
{
$extensionRepository = $this->objectManager->get(ExtensionRepository::class);
return $extensionRepository->countByExtKey($extensionKey);
}
/**
* @param array $extData
*/
public function createExtension($extData)
{
$insertExtension = [
'pid' => $this->pid,
'ext_key' => $extData['extensionkey'],
'last_upload' => 0,
'versions' => 0,
'last_version' => 0,
'frontend_user' => $extData['ownerusername'],
'crdate' => $extData['crdate'],
'tstamp' => $extData['tstamp'],
];
$connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('tx_terfe2_domain_model_extension');
$connection->insert(
'tx_terfe2_domain_model_extension',
$insertExtension
);
}
}
......@@ -303,12 +303,6 @@
<trans-unit id="tx_terfe2_task_importextensionsfromqueuetask.description" xml:space="preserve">
<source>Imports extensions out of the queue table of TER</source>
</trans-unit>
<trans-unit id="tx_terfe2_task_importallextensionstask.name" xml:space="preserve">
<source>[TER FE2] Import all extensions</source>
</trans-unit>
<trans-unit id="tx_terfe2_task_importallextensionstask.description" xml:space="preserve">
<source>Import all extensions from TER tables (use it only for maintenance purposes)</source>
</trans-unit>
<trans-unit id="tx_terfe2_task_checkforoutdatedextensions.name" xml:space="preserve">
<source>[TER FE2] Check for outdated extensions</source>
</trans-unit>
......
......@@ -74,13 +74,6 @@ $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\T3o\TerFe2\Task
'description' => 'LLL:EXT:ter_fe2/Resources/Private/Language/locallang_db.xlf:tx_terfe2_task_importextensionsfromqueuetask.description',
];
// Register import all extensions
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\T3o\TerFe2\Task\ImportAllExtensionKeysTask::class] = [
'extension' => 'ter_fe2',
'title' => 'LLL:EXT:ter_fe2/Resources/Private/Language/locallang_db.xlf:tx_terfe2_task_importallextensionstask.name',
'description' => 'LLL:EXT:ter_fe2/Resources/Private/Language/locallang_db.xlf:tx_terfe2_task_importallextensionstask.description',
];
// Register check for outdated extensions tassk
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\T3o\TerFe2\Task\CheckForOutdatedExtensions::class] = [
'extension' => 'ter_fe2',
......
Markdown is supported
0% or