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

[!!!][TASK] Remove tx_ter_extensions & queue & importer task

This change is the final change to remove any database tables
from "EXT:ter", and remove any migration from TER v1 (SOAP) to
TER v2 via a scheduler task.

This change removes:
* tx_ter_extensions (versions of an extension)
* tx_ter_extensionqueue (+ its UploadQueue API object)
* ImportExtensionsFromQueueTask (all migrated to ExtensionVersion for now)

All DB rows are written directly into tx_terfe2_domain_model_version and
its related tables.

The API "ExtensionVersion->upload()" now produces everything necessary
including notifications (which can be built via PSR-14 in the future).

This also actually means that extensions are automatically available
RIGHT AWAY after uploading an extension via the GUI or the SOAP API.

Next Steps:
* Refactor our upload API to make it more resistent and moving into a Event Sourcing concept (thinning out all underlying logic from ExtensionVersion again)
* Refactor the permission concept and integrate it nicely
* Remove dependencies to the SOAP API in EXT:ter_fe2
parent 9c4b489c
Pipeline #9400 passed with stages
in 8 minutes and 33 seconds
......@@ -238,11 +238,49 @@ class ExtensionKey
public function hasUploadedVersions(): bool
{
$conn = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('tx_ter_extensions');
$items = $conn->select(['*'], 'tx_ter_extensions', ['extensionkey' => $this->extensionKey])->fetchAll();
$conn = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('tx_terfe2_domain_model_version');
$items = $conn->select(['*'], 'tx_terfe2_domain_model_version', ['extension' => $this->getUid()])->fetchAll();
return !empty($items);
}
public function getUid(): ?int
{
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_terfe2_domain_model_extension');
$uid = $queryBuilder
->select('uid')
->from('tx_terfe2_domain_model_extension')
->where(
$queryBuilder->expr()->eq('ext_key', $queryBuilder->createNamedParameter($this->extensionKey))
)
->execute()
->fetchColumn();
return !empty($uid) ? (int)$uid : null;
}
public function validateComposerNameInExtension(array $composerInfo): void
{
if (empty($composerInfo) || empty($composerInfo['name'])) {
return;
}
$connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('tx_terfe2_domain_model_extension');
$queryBuilder = $connection->createQueryBuilder();
$persistedComposerName = $queryBuilder
->select('composer_name')
->from('tx_terfe2_domain_model_extension')
->where(
$queryBuilder->expr()->eq('ext_key', $queryBuilder->createNamedParameter($this->extensionKey, \PDO::PARAM_INT))
)
->execute()
->fetchColumn();
if (empty($persistedComposerName) || $persistedComposerName === $composerInfo['name']) {
return;
}
$connection->update('tx_terfe2_domain_model_extension', ['composer_name' => ''], ['ext_key' => $this->extensionKey]);
}
/**
* Check if a user with such a name exists, and return the username from the DB (= with proper lowercase etc)
* or null, if the user does not exist.
......
<?php
declare(strict_types = 1);
namespace T3o\Ter\Api;
/*
* This file is part of TYPO3 CMS-extension "ter", created by Benni Mack.
*
* 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.
*/
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* When a new extension version is uploaded via the API, a queue item is added
* and later processed in a scheduler task.
*/
class UploadQueue
{
private $tableName = 'tx_ter_extensionqueue';
public function addExtensionVersionToQueue(ExtensionVersion $extensionVersion)
{
$this->getConnection()->insert(
$this->tableName,
[
'crdate' => $GLOBALS['EXEC_TIME'],
'extensionkey' => (string)$extensionVersion->getExtensionKey(),
'extensionuid' => $extensionVersion->getUidOfExtensionVersion(),
'imported_to_fe' => 0,
'tstamp' => 0
]
);
}
public function getItemsInQueue(): ?array
{
$connection = $this->getConnection();
$items = $connection->select(['*'], $this->tableName, ['imported_to_fe' => 0], [], ['crdate' => 'ASC'])->fetchAll();
if (is_array($items)) {
return $items;
}
return null;
}
public function markAsProcessed(int $uidOfExtensionVersionRecord, string $extensionKey): void
{
$this->getConnection()->update(
$this->tableName,
['imported_to_fe' => 1, 'tstamp' => $GLOBALS['EXEC_TIME']],
['extensionuid' => $uidOfExtensionVersionRecord, 'extensionkey' => $extensionKey]
);
}
protected function getConnection(): Connection
{
return GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($this->tableName);
}
}
<?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_extensions',
'iconfile' => 'EXT:ter/tx_ter_extensions.gif',
],
'interface' => [
'showRecordFieldList' => '',
],
'columns' => [
'extensionkey' => [
'label' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensions.extensionkey',
'config' => [
'type' => 'input',
'size' => 40,
'max' => 30,
'eval' => 'trim',
],
],
'version' => [
'label' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensions.version',
'config' => [
'type' => 'input',
'size' => 40,
'max' => 50,
'eval' => 'trim',
],
],
'title' => [
'label' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensions.title',
'config' => [
'type' => 'input',
'size' => 40,
'max' => 50,
'eval' => 'trim',
],
],
'description' => [
'label' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensions.description',
'config' => [
'type' => 'text',
'cols' => 40,
'rows' => 3,
],
],
'state' => [
'label' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensions.state',
'config' => [
'type' => 'input',
'size' => 40,
'max' => 15,
'eval' => 'trim',
],
],
'reviewstate' => [
'label' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensions.reviewstate',
'config' => [
'type' => 'input',
'size' => 5,
'max' => 5,
],
],
'category' => [
'label' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensions.category',
'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' => 5,
],
],
'ismanualincluded' => [
'label' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensions.ismanualincluded',
'config' => [
'type' => 'check',
'default' => '0',
],
],
't3xfilemd5' => [
'label' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensions.t3xfilemd5',
'config' => [
'type' => 'input',
'size' => 32,
'max' => 32,
'eval' => 'trim',
],
],
'uploadcomment' => [
'label' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensions.uploadcomment',
'config' => [
'type' => 'text',
'cols' => 40,
'rows' => 3,
],
],
'lastuploadbyusername' => [
'label' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensions.lastuploadbyusername',
'config' => [
'type' => 'input',
'size' => 40,
'max' => 30,
'eval' => 'trim',
],
],
'lastuploaddate' => [
'label' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensions.lastuploaddate',
'config' => [
'type' => 'input',
'size' => 15,
'max' => 11,
],
],
'files' => [
'label' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensions.files',
'config' => [
'type' => 'text',
'cols' => 40,
'rows' => 3,
],
],
'techinfo' => [
'label' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensions.techinfo',
'config' => [
'type' => 'text',
'cols' => 40,
'rows' => 3,
],
],
'composerinfo' => [
'label' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensions.composerinfo',
'config' => [
'type' => 'text',
'cols' => 40,
'rows' => 3,
],
],
'dependencies' => [
'label' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensions.dependencies',
'config' => [
'type' => 'text',
'cols' => 40,
'rows' => 3,
],
],
'createdirs' => [
'label' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensions.createdirs',
'config' => [
'type' => 'text',
'cols' => 40,
'rows' => 3,
],
],
'uploadfolder' => [
'label' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensions.uploadfolder',
'config' => [
'type' => 'check',
'default' => '0',
],
],
'clearcacheonload' => [
'label' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensions.clearcacheonload',
'config' => [
'type' => 'check',
'default' => '0',
],
],
'authorname' => [
'label' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensions.authorname',
'config' => [
'type' => 'input',
'size' => 40,
'eval' => 'trim',
],
],
'authoremail' => [
'label' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensions.authoremail',
'config' => [
'type' => 'input',
'size' => 40,
'eval' => 'trim',
],
],
'authorcompany' => [
'label' => 'LLL:EXT:ter/locallang_tca.xml:tx_ter_extensions.authorcompany',
'config' => [
'type' => 'input',
'size' => 40,
'eval' => 'trim',
],
],
],
'types' => [
'1' => ['showitem' => 'extensionkey,version,title,description,state,reviewstate,category,downloadcounter,ismanualincluded,t3xfilemd5,uploadcomment,lastuploadbyusername,lastuploaddate,files,techinfo,dependencies,createdirs,uploadfolder,clearcacheonload,authorname,authoremail,authorcompany'],
]
];
#
# Table structure for table 'tx_ter_extensions'
#
CREATE TABLE tx_ter_extensions (
uid int(11) unsigned DEFAULT '0' NOT NULL auto_increment,
pid int(11) DEFAULT '0' NOT NULL,
tstamp int(11) unsigned DEFAULT '0' NOT NULL,
crdate int(11) unsigned DEFAULT '0' NOT NULL,
extensionkey varchar(30) DEFAULT '' NOT NULL,
version varchar(11) DEFAULT '' NOT NULL,
title varchar(50) DEFAULT '' NOT NULL,
description text NOT NULL,
state varchar(15) DEFAULT '' NOT NULL,
reviewstate int(11) DEFAULT '0' NOT NULL,
category varchar(30) DEFAULT '' NOT NULL,
downloadcounter int(11) DEFAULT '0' NOT NULL,
ismanualincluded int(11) DEFAULT '0' NOT NULL,
t3xfilemd5 varchar(32) DEFAULT '' NOT NULL,
uploadcomment TEXT DEFAULT '' NOT NULL,
lastuploadbyusername varchar(30) DEFAULT '0' NOT NULL,
lastuploaddate int(11) DEFAULT '0' NOT NULL,
files longtext NOT NULL,
techinfo text NOT NULL,
composerinfo text NOT NULL,
dependencies text NOT NULL,
createdirs text NOT NULL,
uploadfolder tinyint(4) DEFAULT '0' NOT NULL,
clearcacheonload tinyint(4) DEFAULT '0' NOT NULL,
authorname tinytext NOT NULL,
authoremail tinytext NOT NULL,
authorcompany tinytext NOT NULL,
PRIMARY KEY (uid),
KEY extkey (extensionkey,pid),
KEY extcat (category,pid),
KEY exttitle (title,pid)
);
#
# Table structure for table 'tx_ter_extensionqueue'
# not used as TCA, as there is no need for managing this via the TYPO3 Backend
#
CREATE TABLE tx_ter_extensionqueue (
uid int(11) unsigned DEFAULT '0' NOT NULL auto_increment,
extensionkey varchar(30) DEFAULT '' NOT NULL,
extensionuid int(11) DEFAULT '0' NOT NULL,
tstamp int(11) unsigned DEFAULT '0' NOT NULL,
crdate int(11) unsigned DEFAULT '0' NOT NULL,
imported_to_fe tinyint(4) DEFAULT '0' NOT NULL,
PRIMARY KEY (uid),
KEY imported (imported_to_fe)
);
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<T3locallang>
<meta type="array">
<description>language labels for ter extension</description>
<type>plugin</type>
</meta>
<data type="array">
<languageKey index="default" type="array">
<label index="tx_ter_extensions">Extension</label>
<label index="tx_ter_extensions.extensionkey">Extension key</label>
<label index="tx_ter_extensions.version">Version</label>
<label index="tx_ter_extensions.title">Title</label>
<label index="tx_ter_extensions.description">Description</label>
<label index="tx_ter_extensions.state">State</label>
<label index="tx_ter_extensions.reviewstate">Review state</label>
<label index="tx_ter_extensions.category">Category</label>
<label index="tx_ter_extensions.downloadcounter">Download counter</label>
<label index="tx_ter_extensions.ismanualincluded">Manual included</label>
<label index="tx_ter_extensions.t3xfilemd5">File hash</label>
<label index="tx_ter_extensions.uploadcomment">Upload comment</label>
<label index="tx_ter_extensions.lastuploadbyusername">Last uploaded by</label>
<label index="tx_ter_extensions.lastuploaddate">Last upload date</label>
<label index="tx_ter_extensions.files">Files</label>
<label index="tx_ter_extensions.techinfo">Technical information</label>
<label index="tx_ter_extensions.composerinfo">Some information extracted from composer.json</label>
<label index="tx_ter_extensions.dependencies">Dependencies</label>
<label index="tx_ter_extensions.createdirs">Create dirs</label>
<label index="tx_ter_extensions.uploadfolder">Upload folder</label>
<label index="tx_ter_extensions.clearcacheonload">Clear cache on load</label>
<label index="tx_ter_extensions.authorname">Author name</label>
<label index="tx_ter_extensions.authoremail">Author email</label>
<label index="tx_ter_extensions.authorcompany">Author company</label>
</languageKey>
</data>
</T3locallang>
\ No newline at end of file
......@@ -258,12 +258,6 @@
<trans-unit id="tx_terfe2_task_downloadcountertask.description" xml:space="preserve">
<source>Sums up the downloads of each version of each extension</source>
</trans-unit>
<trans-unit id="tx_terfe2_task_importextensionsfromqueuetask.name" xml:space="preserve">
<source>[TER FE2] Import extensions from queue</source>
</trans-unit>
<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_checkforoutdatedextensions.name" xml:space="preserve">
<source>[TER FE2] Check for outdated extensions</source>
</trans-unit>
......
Dear {notify.name},
there was just a new release of the extension "{notify.ext_key}" with version {extData.version}.
there was just a new release of the extension "{notify.ext_key}" with version {extData.version_string}.
Upload comment:
{extData.uploadcomment -> f:format.nl2br()}
{extData.upload_comment -> f:format.nl2br()}
URL: https://extensions.typo3.org/extension/{notify.ext_key}
Download as ZIP: https://extensions.typo3.org/extension/download/{notify.ext_key}/{extData.version}/
Download as ZIP: https://extensions.typo3.org/extension/download/{notify.ext_key}/{extData.version_string}/
<f:if condition="{notify.composer_name}">Composer command: composer update {notify.composer_name} --with-all-dependencies</f:if>
If you don't want to get notified anymore, go to https://extensions.typo3.org/extension/{notify.ext_key}, login and deactivate the notifications for this extension.
......
......@@ -34,13 +34,6 @@ if (!defined('TYPO3_MODE')) {
]
);
// Register import from queue task
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\T3o\TerFe2\Task\ImportExtensionsFromQueueTask::class] = [
'extension' => 'ter_fe2',
'title' => 'LLL:EXT:ter_fe2/Resources/Private/Language/locallang_db.xlf:tx_terfe2_task_importextensionsfromqueuetask.name',
'description' => 'LLL:EXT:ter_fe2/Resources/Private/Language/locallang_db.xlf:tx_terfe2_task_importextensionsfromqueuetask.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 .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment