feat: restore the disturber content element, port the groups.swiss export

The 404 page (and other pages TYPO3 13 renders) contain disturber elements,
which logged 'no rendering definition' on every 404. The CType is back with
its TypoScript, templates and FlexForm; the TCA uses the TYPO3 13 API.

ep:groups-swiss replaces the TYPO3 10 scheduler tasks, which stopped with
PHP 7.4. It reads the calendar from MyE&P (contingents/calendar, synced from
bpn-connect) instead of bpn-connect directly, so it needs no new credentials,
and publishes all houses from groupsSwissHouses in secrets.php (or one house
given as arguments, as the scheduler tasks did). The ranges match the TYPO3 10
algorithm on 2000 random calendars; --dry-run shows them without sending.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
frommeandClaude Opus 5.5 committed 2026-10-21 21:25:26 +02:00
1 parent cdf04823b0
commit 42e02095ce
12 files changed
+575

No files matched your search

@@ -0,0 +1,64 @@
<T3DataStructure>
<meta>
<langDisable>1</langDisable>
</meta>
<sheets>
<sDEF>
<ROOT>
<TCEforms>
<sheetTitle>Konfiguration</sheetTitle>
</TCEforms>
<type>array</type>
<el>
<buttons>
<section>1</section>
<type>array</type>
<el>
<container>
<title>Button</title>
<type>array</type>
<el>
<label>
<TCEforms>
<label>Label</label>
<config>
<type>input</type>
<size>32</size>
</config>
</TCEforms>
</label>
<link>
<TCEforms>
<exclude>1</exclude>
<label>Button</label>
<config>
<type>input</type>
<eval>trim</eval>
<size>30</size>
<wizards type="array">
<_PADDING type="integer">2</_PADDING>
<link type="array">
<type>popup</type>
<title>Link</title>
<icon>EXT:backend/Resources/Public/Images/FormFieldWizard/wizard_link.gif</icon>
<module>
<name>wizard_link</name>
<urlParameters>
<mode>wizard</mode>
</urlParameters>
</module>
<JSopenParams>height=300,width=500,status=0,menubar=0,scrollbars=1</JSopenParams>
</link>
</wizards>
</config>
</TCEforms>
</link>
</el>
</container>
</el>
</buttons>
</el>
</ROOT>
</sDEF>
</sheets>
</T3DataStructure>
@@ -0,0 +1,61 @@
<?php
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
defined('TYPO3') or die();
call_user_func(function () {
$frontendLanguageFilePrefix = 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:';
ExtensionManagementUtility::addTcaSelectItem(
'tt_content',
'CType',
[
'label' => 'Störer',
'value' => 'disturber',
'icon' => 'content-image'
],
'teaser_product',
'after'
);
$GLOBALS['TCA']['tt_content']['types']['disturber'] = [
'showitem' => '
--palette--;' . $frontendLanguageFilePrefix . 'palette.general;general,
--palette--;' . $frontendLanguageFilePrefix . 'palette.header;header, bodytext, pi_flexform,
--div--;Bild,
assets,
--div--;' . $frontendLanguageFilePrefix . 'tabs.appearance,
layout;' . $frontendLanguageFilePrefix . 'layout_formlabel, tx_eptheme_background,
--div--;' . $frontendLanguageFilePrefix . 'tabs.access,
hidden;' . $frontendLanguageFilePrefix . 'field.default.hidden,
--div--;' . $frontendLanguageFilePrefix . 'tabs.extended
',
'columnsOverrides' => [
'bodytext' => [
'label' => 'Text',
'config' => [
'enableRichtext' => true,
]
],
'assets' => [
'label' => 'Bild',
'config' => [
'type' => 'file',
'allowed' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['mediafile_ext'],
'appearance' => [
'createNewRelationLinkTitle' => 'Hinzufügen'
],
'maxitems' => 1,
'minitems' => 0,
]
]
]
];
ExtensionManagementUtility::addPiFlexFormValue(
'*',
'FILE:EXT:ep_theme/Configuration/FlexForms/flexform_disturber.xml',
'disturber'
);
});
@@ -0,0 +1,8 @@
tt_content.disturber =< lib.contentElement
tt_content.disturber {
templateName = Disturber
dataProcessing {
10 = EP\EpTheme\DataProcessing\TeaserImageProcessor
20 = EP\EpTheme\DataProcessing\FlexFormProcessor
}
}
@@ -0,0 +1,64 @@
<html data-namespace-typo3-fluid="true" lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:v="http://typo3.org/ns/FluidTYPO3/Vhs/ViewHelpers"
xmlns:ep="http://typo3.org/ns/EP/EpTheme/ViewHelpers"
xmlns:f="http://typo3.org/ns/fluid/ViewHelpers">
<div class="{ep:themeClasses(classes: '{ep: \'bg-ep-primary-dark\', sbw: \'bg-sbw-primary/80\', snz: \'bg-snz-primary/80\', suz: \'bg-suz-primary/80\', uch: \'bg-uch-primary/80\'}', key: settings.themekey)} my-2">
<f:if condition="{settings.themeKey} == 'ep'">
<f:render partial="Disrupter/Outlines"
section="Top1"
arguments="{classes: 'hidden md:block -translate-y-2 {f:if(condition: \'{background} == 1 || {background} == 3\', then: \'text-ep-primary-bg\', else: \'text-white\')}'}"/>
</f:if>
<div class="relative container grid grid-cols-2 gap-8 py-8">
<div class="col-span-2 md:col-span-1">
<div class="relative max-w-md mx-auto mb-8">
<f:if condition="{teaserImage}">
<f:image image="{teaserImage}"
loading="lazy"
class="block w-full h-auto rounded-full"
width="400"
height="400c"
alt="{teaserImage.alternative}" />
</f:if>
<a href="tel:{settings.phoneNumber -> v:format.pregReplace(pattern: '/[\-\s]/', replacement: '')}"
rel="nofollow"
class="absolute bottom-0 left-1/2 -translate-x-1/2 -mb-8 rounded-full py-4 px-6 flex items-center space-x-2 {ep:themeClasses(classes: '{ep: \'bg-ep-secondary\', sbw: \'bg-sbw-secondary\', snz: \'bg-snz-secondary\', suz: \'bg-suz-secondary\', uch: \'bg-uch-secondary\'}', key: settings.themekey)}">
{ep:icon(icon: 'phone', class: 'w-10 h-10 text-white')}
<div class="text-center text-white">
<span class="block whitespace-nowrap">
Ihr habt Fragen?
</span>
<span class="block whitespace-nowrap">
Wir helfen euch gerne!
</span>
</div>
</a>
</div>
</div>
<div class="col-span-2 md:col-span-1" data-rte-content>
<span class="headline--secondary font-light text-white">{data.subheader}</span>
<span class="headline--secondary uppercase font-light text-white mb-4">{data.header}</span>
<div class="text-white" data-rte-content>
{data.bodytext -> f:format.html()}
</div>
<f:if condition="{data.flexForm.buttons}">
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4 lg:gap-8">
<f:for each="{data.flexForm.buttons}" as="button">
<f:link.typolink parameter="{button.container.link}"
class="button bg-button--secondary shadow-lg">
{button.container.label}
</f:link.typolink>
</f:for>
</div>
</f:if>
</div>
</div>
<f:if condition="{settings.themeKey} == 'ep'">
<f:render partial="Disrupter/Outlines"
section="Bottom1"
arguments="{classes: 'hidden md:block sbw:md:hidden translate-y-2 {f:if(condition: \'{background} == 2 || {background} == 3\', then: \'text-ep-primary-bg\', else: \'text-white\')}'}"/>
</f:if>
</div>
</html>
@@ -0,0 +1,21 @@
<html data-namespace-typo3-fluid="true" lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:v="http://typo3.org/ns/FluidTYPO3/Vhs/ViewHelpers"
xmlns:f="http://typo3.org/ns/fluid/ViewHelpers">
<div class="container-fluid ep-disturber-last-chance">
<div data-rte-content>
{data.header}
</div>
<div data-rte-content>
{data.bodytext -> f:format.html()}
</div>
<div>
{data.flexForm.buttons -> v:iterator.first() -> v:variable.set(name: 'button')}
<a href="{f:uri.typolink(parameter: button.container.link)}" class="button bg-button--secondary">
{button.container.label -> f:format.raw()}
</a>
</div>
</div>
</html>
@@ -0,0 +1,32 @@
<html data-namespace-typo3-fluid="true" lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://typo3.org/ns/fluid/ViewHelpers">
<f:alias map="{button: data.flexForm.buttons.0}">
<div class="container-fluid ep-disturber-reminder">
<div data-rte-content>
{data.header}
</div>
<div class="col-md-6">
<a href="{f:uri.typolink(parameter: button.container.link)}" title="{button.container.label -> f:format.raw()}">
<f:if condition="{teaserImage}">
<f:image image="{teaserImage}"
loading="lazy"
class="block w-full h-auto rounded-full"
width="400"
alt="{teaserImage.alternative}" />
</f:if>
</a>
</div>
<div class="col-md-6" data-rte-content>
<div>
{data.bodytext -> f:format.html()}
</div>
</div>
<a href="{f:uri.typolink(parameter: button.container.link)}" class="btn btn-info">
{button.container.label -> f:format.raw()}
</a>
</div>
</f:alias>
</html>
@@ -0,0 +1,42 @@
<html data-namespace-typo3-fluid="true" lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ep="http://typo3.org/ns/EP/EpTheme/ViewHelpers"
xmlns:f="http://typo3.org/ns/fluid/ViewHelpers">
<div class="{ep:themeClasses(classes: '{ep: \'bg-ep-primary-dark\', sbw: \'bg-sbw-primary/80\', snz: \'bg-snz-primary/80\', suz: \'bg-suz-primary/80\', uch: \'bg-uch-primary/80\'}', key: settings.themekey)} my-2">
<f:render partial="Disrupter/Outlines"
section="Top1"
arguments="{classes: 'hidden md:block -translate-y-2 {f:if(condition: \'{data.tx_eptheme_background} == 1 || {data.tx_eptheme_background} == 3\', then: \'text-ep-primary-bg\', else: \'text-white\')}'}"/>
<div class="max-w-screen-lg mx-auto">
<div class="md:flex md:items-start py-4">
<div class="px-16 pb-4 md:px-4 md:pb-0 md:w-1/6">
<f:if condition="{teaserImage}">
<f:image image="{teaserImage}"
loading="lazy"
class="block w-full h-auto rounded-full"
width="400"
height="400c"
alt="{teaserImage.alternative}" />
</f:if>
</div>
<div class="px-16 md:px-4 md:w-5/6 md:pl-8 text-center text-white md:text-left" data-rte-content>
<span class="headline--3 text-white uppercase">{data.header}</span>
{data.bodytext -> f:format.html()}
<div class="flex flex-col space-y-4 md:flex-row md:items-center md:space-y-0 md:space-x-4">
<f:for each="{data.flexForm.buttons}" as="button" iteration="iteration">
<f:if condition="{iteration.cycle} <= 3">
<f:link.typolink parameter="{button.container.link}" class="button bg-button--secondary shadow-lg">
{button.container.label}
</f:link.typolink>
</f:if>
</f:for>
</div>
</div>
</div>
</div>
<f:render partial="Disrupter/Outlines"
section="Bottom1"
arguments="{classes: 'hidden md:block translate-y-2 {f:if(condition: \'{data.tx_eptheme_background} == 2 || {data.tx_eptheme_background} == 3\', then: \'text-ep-primary-bg\', else: \'text-white\')}'}"/>
</div>
</html>
@@ -0,0 +1,25 @@
<html data-namespace-typo3-fluid="true" lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:v="http://typo3.org/ns/FluidTYPO3/Vhs/ViewHelpers"
xmlns:f="http://typo3.org/ns/fluid/ViewHelpers">
<f:layout name="Default"/>
<f:section name="Main">
<f:switch expression="{data.layout}">
<f:case value="0">
<f:render partial="Disturber/Small" arguments="{_all}"/>
</f:case>
<f:case value="1">
<f:render partial="Disturber/Large" arguments="{_all}"/>
</f:case>
<f:case value="2">
<f:render partial="Disturber/LastChance" arguments="{_all}"/>
</f:case>
<f:case value="3">
<f:render partial="Disturber/Reminder" arguments="{_all}"/>
</f:case>
</f:switch>
</f:section>
</html>