Skip to content

Commit

Permalink
Merge branch 'release/6.0.23'
Browse files Browse the repository at this point in the history
  • Loading branch information
andreaskienast committed Dec 5, 2024
2 parents 2311d6b + 5f0f21c commit 41ac1da
Show file tree
Hide file tree
Showing 24 changed files with 321,306 additions and 71 deletions.
7 changes: 4 additions & 3 deletions .mage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ magephp:
- ./.env.local
- ./.env.test
- ./.mage.yml
- ./.php_cs.cache
- ./.php_cs.dist
- ./assets
- ./build
- ./legacy_hook/tests
- ./node_modules
- ./.php_cs.cache
- ./.php_cs.dist
- ./auth.json
- ./tests
- ./auth.json
- ./phpunit.xml.dist
- ./package.json
- ./README.md
Expand Down
48 changes: 41 additions & 7 deletions config/nginx/redirects.conf
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,19 @@ location = /Home/Extensions.html {
return 303 /Home/ExtensionManuals.html#extension-manuals;
}

# Redirect minor versions to their LTS cuonterpart
location ~ ^/c/typo3/([^/]+)/11.[0-4]/(.*)$ {
return 303 /c/typo3/$1/11.5/$2;
}

location ~ ^/c/typo3/([^/]+)/12.[0-3]/(.*)$ {
return 303 /c/typo3/$1/12.4/$2;
}

location ~ ^/c/typo3/([^/]+)/13.[0-3]/(.*)$ {
return 303 /c/typo3/$1/13.4/$2;
}

# Add short links

location = /installation {
Expand All @@ -87,6 +100,16 @@ location ~ ^/m/typo3/guide-installation/(main|13.4|12.4)/en-us/(.*)$ {
return 303 /m/typo3/reference-coreapi/$1/en-us/Administration/Upgrade/$2;
}

# Rewrite TypoScript in 45 min guide links to new position in TypoScript reference
location ~ ^/m/typo3/tutorial-typoscript-in-45-minutes/(main|13.4|12.4)/en-us/(.*)$ {
return 303 /m/typo3/reference-typoscript/$1/en-us/Guide/$2;
}

# Move TypoScript Syntax into TypoScript reference
location ~ ^/m/typo3/reference-coreapi/(main|13.4|12.4)/en-us/Configuration/TypoScript/Syntax/(.*)/Index.html$ {
return 303 /m/typo3/reference-typoscript/$1/en-us/Syntax/$2/Index.html;
}

# Rewrite Fluid VH reference links to new position
location ~ ^/typo3cms/ViewHelperReference/latest(.*)$ {
return 303 /other/typo3/view-helper-reference/main/en-us$1;
Expand All @@ -95,6 +118,11 @@ location ~ ^/typo3cms/ViewHelperReference(.*)$ {
return 303 /other/typo3/view-helper-reference/main/en-us$1;
}

# Redirect from 1.0 to main in how to document
location ~ ^/m/typo3/docs-how-to-document/1.0/en-us/(.*) {
return 303 /m/typo3/docs-how-to-document/main/en-us/$1;
}

# Redirect from old rest reference to new
location ~ ^/m/typo3/docs-how-to-document/main/en-us/WritingReST/Reference/(.*) {
return 303 /m/typo3/docs-how-to-document/main/en-us/Reference/ReStructuredText/$1;
Expand Down Expand Up @@ -165,7 +193,7 @@ location ~ ^/m/typo3/reference-coreapi/(main|11.5)/en-us/ApiOverview/UpdateWizar
}

location ~ ^/m/typo3/reference-coreapi/(main|11.5|10.4)/en-us/TypoScriptSyntax(.*) {
return 303 /m/typo3/reference-coreapi/$1/en-us/Configuration/TypoScriptSyntax$2;
return 303 /m/typo3/reference-typoscript/$1/en-us/Syntax$2;
}
location ~ ^/m/typo3/reference-coreapi/(main|11.5|10.4)/en-us/ApiOverview/Hooks(.*) {
return 303 /m/typo3/reference-coreapi/$1/en-us/ApiOverview/Events$2;
Expand Down Expand Up @@ -358,10 +386,16 @@ location ~ ^/typo3cms/TSconfigReference/8.7(.*) {
return 303 /m/typo3/reference-tsconfig/8.7/en-us$1;
}
location ~ ^/typo3cms/TSconfigReference/(master|main|stable|latest)(.*) {
return 303 /m/typo3/reference-tsconfig/main/en-us$2;
return 303 /m/typo3/reference-typoscript/main/en-us$2;
}
location ~ ^/typo3cms/TSconfigReference(.*) {
return 303 /m/typo3/reference-tsconfig/main/en-us$1;
return 303 /m/typo3/reference-typoscript/main/en-us$1;
}
location ~ ^/m/typo3/reference-tsconfig/(main|13.4|12.4)/en-us/UsingSetting(.*) {
return 303 /m/typo3/reference-typoscript/$1/en-us/UsingSettingTSconfig$2;
}
location ~ ^/m/typo3/reference-tsconfig/(main|13.4|12.4)/en-us(.*) {
return 303 /m/typo3/reference-typoscript/$1/en-us$2;
}

# typo3/docs-how-to-document
Expand Down Expand Up @@ -489,10 +523,10 @@ location ~ ^/typo3cms/TyposcriptIn45MinutesTutorial/7.6(.*) {
return 303 /m/typo3/tutorial-typoscript-in-45-minutes/7.6/en-us$1;
}
location ~ ^/typo3cms/TyposcriptIn45MinutesTutorial/(master|main|stable|latest)(.*) {
return 303 /m/typo3/tutorial-typoscript-in-45-minutes/main/en-us$2;
return 303 /m/typo3/reference-typoscript/main/en-us/Guide/$2;
}
location ~ ^/typo3cms/TyposcriptIn45MinutesTutorial(.*) {
return 303 /m/typo3/tutorial-typoscript-in-45-minutes/main/en-us$1;
return 303 /m/typo3/reference-typoscript/main/en-us/Guide/$1;
}

# typo3/tutorial-templating-with-fluid
Expand Down Expand Up @@ -569,10 +603,10 @@ location ~ ^/m/typo3/reference-coding-guidelines/(6.2|7.6|8.7|9.5|master|main|st
# was merged into TYPO3 Explained and will be taken offline and archived
# >> redirect all to new location in reference-coreapi (301)
location ~ ^/typo3cms/TyposcriptSyntaxReference/(6.2|7.6|8.7|master|main|stable|latest)/.* {
return 301 /m/typo3/reference-coreapi/($1)/en-us/ApiOverview/TypoScriptSyntax/Index.html;
return 301 /m/typo3/reference-typoscript/($1)/en-us/Syntax/Index.html;
}
location ~ ^/m/typo3/reference-typoscript-syntax/(6.2|7.6|8.7|master|main|stable|latest)/.* {
return 303 /m/typo3/reference-coreapi/$1/en-us/ApiOverview/TypoScriptSyntax/Index.html;
return 303 /m/typo3/reference-typoscript/$1/en-us/Syntax/Index.html;
}

# typo3/reference-services
Expand Down
2 changes: 1 addition & 1 deletion legacy_hook/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"psr/http-message": "^1.1",
"symfony/cache": "^5.4",
"symfony/finder": "^5.4",
"t3docs/typo3-version-handling": "^0.14.0"
"t3docs/typo3-version-handling": "^0.21.0"
},
"require-dev": {
"roave/security-advisories": "dev-latest",
Expand Down
18 changes: 9 additions & 9 deletions legacy_hook/composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

118 changes: 74 additions & 44 deletions legacy_hook/src/DocumentationLinker.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Contracts\Cache\ItemInterface;
use T3Docs\VersionHandling\DefaultInventories;
use T3Docs\VersionHandling\Typo3VersionMapping;

/**
* Redirect to a specify interlink target, example:
Expand All @@ -32,6 +33,9 @@
* linkToDocs.php?shortcode=t3coreapi:caching@main
* -> forwards to: https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/CachingFramework/Index.html#caching
*
* linkToDocs.php?shortcode=georgringer-news:start@main
* -> forwards to: https://docs.typo3.org/p/georgringer/news/en-us/Index.html#start
*
* Also, all TYPO3 core extensions can be resolved via "typo3-cms-XXX" prefixing:
* linkToDocs.php?shortcode=typo3-cms-seo:introduction@main
* -> forwards to: https://docs.typo3.org/c/typo3/cms-seo/main/en-us/Introduction/Index.html#introduction
Expand Down Expand Up @@ -80,9 +84,9 @@
* https://docs.typo3.org/c/typo3/cms-XXX/main/en-us/objects.inv.json
*
* Additional TYPO3 Manuals:
* https://docs.typo3.org/other/typo3/cms-XXX/main/en-us/objects.inv.json
* https://docs.typo3.org/other/typo3/XXX/main/en-us/objects.inv.json
*
* Public TYPO3 extensions (not within the scope of redirection at the moment):
* Public TYPO3 extensions (xxx/yyy is the composer packagist key):
* https://docs.typo3.org/p/XXX/YYY/main/en-us/objects.inv.json
*
* The logic is this:
Expand All @@ -99,6 +103,8 @@
* https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/objects.inv.json
* https://docs.typo3.org/other/t3docs/render-guides/objects.inv.json
* https://docs.typo3.org/p/georgringer/news/main/en-us/objects.inv.json
*
* @see Unit Test in legacy_hook/tests/Unit/PermalinksTest.php for examples.
*/
final readonly class DocumentationLinker
{
Expand All @@ -125,53 +131,61 @@ public function redirectToLink(): Response
$responseDescriber = $this->cache->get($cacheKey, function (ItemInterface $item) use ($url): ResponseDescriber {
$item->expiresAfter($this->cacheTime);

if (preg_match(
'/^' .
'([a-z0-9\-_]+):' . // $repository
'([a-z0-9\-_]+)' . // $index
'(@[a-z0-9\.-]+)?' . // $version
'$/imsU',
$url,
$matches)
) {
[, $repository, $index] = $matches;
$version = str_replace('@', '', $matches[3] ?? '') ?: self::MAIN_IDENTIFIER;
$entrypoint = $this->resolveEntryPoint($repository, $version);
$objectsContents = $this->getObjectsFile($entrypoint);
return $this->resolvePermalink($url);
});

if ($objectsContents === '' && $version !== self::MAIN_IDENTIFIER) {
// soft-fail to resolve a maybe not-yet released version to main.
$entrypoint = $this->resolveEntryPoint($repository, self::MAIN_IDENTIFIER);
$objectsContents = $this->getObjectsFile($entrypoint);
}
return new Response($responseDescriber->statusCode, $responseDescriber->headers, $responseDescriber->body);
}

if ($objectsContents === '') {
return new ResponseDescriber(404, [], 'Invalid shortcode, no objects.inv.json found.');
}
public function resolvePermalink(string $url): ResponseDescriber
{
if (preg_match(
'/^' .
'([a-z0-9\-_]+):' . // $repository
'([a-z0-9\-_]+)' . // $index
'(@[a-z0-9\.-]+)?' . // $version
'$/imsU',
$url,
$matches)
) {
[, $repository, $index] = $matches;
$repository = mb_strtolower($repository);
$index = mb_strtolower($index);
$version = mb_strtolower(str_replace('@', '', $matches[3] ?? '') ?: self::MAIN_IDENTIFIER);

if (function_exists('json_validate') && !json_validate($objectsContents)) {
return new ResponseDescriber(404, [], 'Invalid shortcode, defective objects.inv.json.');
}
$entrypoint = $this->resolveEntryPoint($repository, $version);
$objectsContents = $this->getObjectsFile($entrypoint);

$json = json_decode($objectsContents, true);
if (!is_array($json)) {
return new ResponseDescriber(404, [], 'Invalid shortcode, invalid objects.inv.json.');
}
if ($objectsContents === '' && $version !== self::MAIN_IDENTIFIER) {
// soft-fail to resolve a maybe not-yet released version to main.
$entrypoint = $this->resolveEntryPoint($repository, self::MAIN_IDENTIFIER);
$objectsContents = $this->getObjectsFile($entrypoint);
}

$link = $this->parseInventoryForIndex($index, $json);
if ($link === '') {
return new ResponseDescriber(404, [], 'Invalid shortcode, could not find index.');
}
if ($objectsContents === '') {
return new ResponseDescriber(404, [], 'Invalid shortcode, no objects.inv.json found.');
}

$forwardUrl = 'https://docs.typo3.org/' . $entrypoint . $link;
if (function_exists('json_validate') && !json_validate($objectsContents)) {
return new ResponseDescriber(404, [], 'Invalid shortcode, defective objects.inv.json.');
}

return new ResponseDescriber(307, ['Location' => $forwardUrl], 'Redirect to ' . $forwardUrl);
$json = json_decode($objectsContents, true);
if (!is_array($json)) {
return new ResponseDescriber(404, [], 'Invalid shortcode, invalid objects.inv.json.');
}

return new ResponseDescriber(404, [], 'Invalid shortcode.');
});
$link = $this->parseInventoryForIndex($index, $json);
if ($link === '') {
return new ResponseDescriber(404, [], 'Invalid shortcode, could not find index.');
}

return new Response($responseDescriber->statusCode, $responseDescriber->headers, $responseDescriber->body);
$forwardUrl = 'https://docs.typo3.org/' . $entrypoint . $link;

return new ResponseDescriber(307, ['Location' => $forwardUrl], 'Redirect to ' . $forwardUrl);
}

return new ResponseDescriber(404, [], 'Invalid shortcode.');
}

private function parseInventoryForIndex(string $index, array $json): string
Expand Down Expand Up @@ -214,21 +228,37 @@ private function parseInventoryForIndex(string $index, array $json): string
// Note: Currently hardcoded to 'en-us'
private function resolveEntryPoint(string $repository, string $version): string
{
$useCoreVersionResolving = true;
if (preg_match('/^typo3-(cms-[0-9a-z\-]+)$/i', $repository, $repositoryParts)) {
// CASE: TYPO3 core manuals
$entrypoint = 'https://docs.typo3.org/c/typo3/' . strtolower($repositoryParts[1]) . '/{typo3_version}/en-us/';
} elseif ($inventory = DefaultInventories::tryFrom($repository)) {
$entrypoint = $inventory->getUrl();
// CASE: Official TYPO3 Documentation with known inventories. Provides "{typo3_version}" internally
// (some inventories DO NOT have that and always go to 'main'!)
$entrypoint = $inventory->getUrl($version);
} else {
// CASE: Third party documentation, based on composer-keys like https://docs.typo3.org/p/georgringer/news
// A permalink like https://docs.typo3.org/permalink/someVendor-some-extension/ is resolved to https://docs.typo3.org/p/somevendor/some-extension/
$entrypoint = 'https://docs.typo3.org/p/' . preg_replace('/-/', '/', strtolower($repository), 1) . '/{typo3_version}/en-us/';
$useCoreVersionResolving = false;
}

if ($useCoreVersionResolving) {
// Core Version resolving. Uses the composer package t3docs/typo3-version-handling which allows to
// interpret strings as "dev", "stable", "oldstable" and can map "12" to latest 12.4.x version.
// If not resolvable, uses the raw version number as lookup (for example "12.4"). An invalid version
// string like "99.9999" will later fail when searching for the directory.
$resolvedVersion = Typo3VersionMapping::tryFrom($version)?->getVersion() ?? $version;
} else {
// $entrypoint = 'https://docs.typo3.org/p/' . strtolower($repository) . '/{typo3_version}/en-us/';
// The '/p/' notation is currently out-of-scope. Would need special handling of slashes.
$entrypoint = '';
// Third party extensions use their own versioning.
$resolvedVersion = $version;
}

// Do replacements.
// The 'https://docs.typo3.org/' notation comes from the external dependency,
// normalize it again here, strip any hostname component to only get a directory.
// @todo maybe make this prettier, security-wise this only allows domain names coming from DefaultInventories.
$entrypoint = str_replace('{typo3_version}', $version, $entrypoint);
$entrypoint = str_replace('{typo3_version}', $resolvedVersion, $entrypoint);
return preg_replace('/^.*:\/\/[^\/]+\//msU', '', $entrypoint);
}

Expand Down
Loading

0 comments on commit 41ac1da

Please sign in to comment.