PM-Detailseite: Direktlinks zur öffentlichen Seite je Portal
Veröffentlichte PMs zeigten im Backend nur den Status-Badge, ohne Weg zur öffentlichen Seite. Im Seitenkopf stehen jetzt Direktlinks — bei Portal::Both einer je Portal (QA-Befund 07.07.). Die URL-Logik ist als PressRelease::publicPortalLinks() zentralisiert (vorher doppelt in der Published-Mail und fehlerhaft im Nachweis-PDF: dort fehlte das /de/press-release/-Segment, die dokumentierte URL lief ins Leere; bei Both nennt der Nachweis jetzt beide URLs). Edition folgt der PM-Sprache statt hart „de". Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
930760a056
commit
28de92e18b
6 changed files with 128 additions and 13 deletions
|
|
@ -16,6 +16,14 @@ class PressReleasePublished extends Mailable
|
|||
|
||||
public string $showUrl;
|
||||
|
||||
/**
|
||||
* Öffentliche Detailseiten je Portal, auf dem die PM erschienen ist
|
||||
* (bei Portal::Both beide Spokes).
|
||||
*
|
||||
* @var list<array{label: string, url: string}>
|
||||
*/
|
||||
public array $portalLinks;
|
||||
|
||||
public function __construct(
|
||||
public readonly User $user,
|
||||
public readonly PressRelease $pressRelease,
|
||||
|
|
@ -23,6 +31,8 @@ class PressReleasePublished extends Mailable
|
|||
$this->showUrl = $user->canAccessAdmin()
|
||||
? route('admin.press-releases.show', $pressRelease->id)
|
||||
: route('me.press-releases.show', $pressRelease->id);
|
||||
|
||||
$this->portalLinks = $pressRelease->publicPortalLinks();
|
||||
}
|
||||
|
||||
public function envelope(): Envelope
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use App\Enums\PressReleaseClassification;
|
|||
use App\Enums\PressReleaseContentTier;
|
||||
use App\Enums\PressReleasePlaceholder;
|
||||
use App\Enums\PressReleaseStatus;
|
||||
use App\Http\Middleware\SetEdition;
|
||||
use App\Models\Concerns\HasUniqueSlug;
|
||||
use App\Scopes\PortalScope;
|
||||
use App\Services\PressRelease\PressReleaseHtmlSanitizer;
|
||||
|
|
@ -165,6 +166,44 @@ class PressRelease extends Model
|
|||
return $this->hasMany(PressReleaseStatusLog::class)->orderByDesc('created_at');
|
||||
}
|
||||
|
||||
/**
|
||||
* Öffentliche Detailseiten je Portal, auf dem die PM erscheint
|
||||
* (bei Portal::Both beide Spokes). Zentrale Quelle für Mail,
|
||||
* Nachweis-PDF und Detailansicht.
|
||||
*
|
||||
* @return list<array{portal: Portal, label: string, url: string}>
|
||||
*/
|
||||
public function publicPortalLinks(): array
|
||||
{
|
||||
if (! $this->slug) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$portals = match ($this->portal) {
|
||||
Portal::Both => [Portal::Presseecho, Portal::Businessportal24],
|
||||
null => [],
|
||||
default => [$this->portal],
|
||||
};
|
||||
|
||||
$edition = in_array($this->language, SetEdition::EDITIONS, true)
|
||||
? $this->language
|
||||
: 'de';
|
||||
|
||||
return array_map(fn (Portal $portal): array => [
|
||||
'portal' => $portal,
|
||||
'label' => $portal->label(),
|
||||
'url' => sprintf(
|
||||
'%s/%s/press-release/%s',
|
||||
rtrim((string) match ($portal) {
|
||||
Portal::Presseecho => config('domains.domain_presseecho_url'),
|
||||
default => config('domains.domain_businessportal_url'),
|
||||
}, '/'),
|
||||
$edition,
|
||||
$this->slug,
|
||||
),
|
||||
], $portals);
|
||||
}
|
||||
|
||||
public function kiAudits(): HasMany
|
||||
{
|
||||
return $this->hasMany(KiAudit::class)->orderByDesc('created_at');
|
||||
|
|
|
|||
|
|
@ -90,25 +90,21 @@ class ProofPdfRenderer
|
|||
*/
|
||||
private function metaRows(PressRelease $pressRelease, string $portalLabel, string $dateLabel): array
|
||||
{
|
||||
// Bei Portal::Both dokumentiert der Nachweis beide öffentlichen URLs.
|
||||
$links = $pressRelease->publicPortalLinks();
|
||||
$urlRows = array_map(static fn (array $link): array => [
|
||||
count($links) > 1 ? 'URL '.$link['label'] : 'URL',
|
||||
$link['url'],
|
||||
], $links);
|
||||
|
||||
return array_values(array_filter([
|
||||
['Portal', $portalLabel],
|
||||
['Veröffentlicht', $dateLabel],
|
||||
['URL', $this->publicUrl($pressRelease)],
|
||||
...$urlRows,
|
||||
$pressRelease->category?->name ? ['Kategorie', (string) $pressRelease->category->name] : null,
|
||||
]));
|
||||
}
|
||||
|
||||
private function publicUrl(PressRelease $pressRelease): string
|
||||
{
|
||||
$base = match ($pressRelease->portal) {
|
||||
Portal::Presseecho => config('domains.domain_presseecho_url'),
|
||||
Portal::Businessportal24 => config('domains.domain_businessportal_url'),
|
||||
default => config('app.url'),
|
||||
};
|
||||
|
||||
return rtrim((string) $base, '/').'/'.ltrim((string) $pressRelease->slug, '/');
|
||||
}
|
||||
|
||||
private function previewText(PressRelease $pressRelease): string
|
||||
{
|
||||
$plain = trim(html_entity_decode(strip_tags((string) $pressRelease->text)));
|
||||
|
|
|
|||
|
|
@ -209,6 +209,9 @@ new #[Layout('components.layouts.app'), Title('Pressemitteilung')] class extends
|
|||
|
||||
return [
|
||||
'pr' => $pr,
|
||||
'publicLinks' => $pr->status === PressReleaseStatus::Published
|
||||
? $pr->publicPortalLinks()
|
||||
: [],
|
||||
'creditBalance' => $user->creditBalance(),
|
||||
'canBoost' => $boostService->canBoost($pr),
|
||||
'isBoosted' => $boostService->isBoosted($pr),
|
||||
|
|
@ -353,7 +356,17 @@ new #[Layout('components.layouts.app'), Title('Pressemitteilung')] class extends
|
|||
</p>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2 flex-shrink-0">
|
||||
<div class="flex items-center gap-2 flex-shrink-0 flex-wrap justify-end">
|
||||
{{-- Direktlinks zur öffentlichen Seite (QA-Befund 07.07.):
|
||||
bei Portal::Both je Portal ein eigener Button. --}}
|
||||
@foreach ($publicLinks as $link)
|
||||
<flux:button variant="primary" icon="arrow-top-right-on-square"
|
||||
href="{{ $link['url'] }}" target="_blank" rel="noopener">
|
||||
{{ count($publicLinks) > 1
|
||||
? __('Auf :portal ansehen', ['portal' => $link['label']])
|
||||
: __('Öffentlich ansehen') }}
|
||||
</flux:button>
|
||||
@endforeach
|
||||
@if ($canEdit)
|
||||
<flux:button variant="filled" icon="pencil" href="{{ route('me.press-releases.edit', $pr->id) }}" wire:navigate>
|
||||
{{ __('Bearbeiten') }}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
|
||||
use App\Enums\Portal;
|
||||
use App\Enums\PressReleaseStatus;
|
||||
use App\Models\Category;
|
||||
use App\Models\Company;
|
||||
|
|
@ -127,6 +128,48 @@ test('customer show zeigt Boilerplate-Override nicht wenn leer', function () {
|
|||
->assertDontSee('Eigener Abbinder (Boilerplate)');
|
||||
});
|
||||
|
||||
test('customer show links to the public page of a published release', function () {
|
||||
/** @var TestCase $this */
|
||||
['customer' => $customer, 'pr' => $pr] = makeCustomerForShowPhase8a([
|
||||
'status' => PressReleaseStatus::Published,
|
||||
'published_at' => now()->subHour(),
|
||||
'slug' => 'oeffentliche-pm',
|
||||
'language' => 'de',
|
||||
]);
|
||||
$this->actingAs($customer);
|
||||
|
||||
LivewireVolt::test('customer.press-releases.show', ['id' => $pr->id])
|
||||
->assertSee('Öffentlich ansehen')
|
||||
->assertSee(config('domains.domain_presseecho_url').'/de/press-release/oeffentliche-pm', escape: false);
|
||||
});
|
||||
|
||||
test('customer show links to both portals when the release is published on both', function () {
|
||||
/** @var TestCase $this */
|
||||
['customer' => $customer, 'pr' => $pr] = makeCustomerForShowPhase8a([
|
||||
'status' => PressReleaseStatus::Published,
|
||||
'published_at' => now()->subHour(),
|
||||
'portal' => Portal::Both,
|
||||
'slug' => 'beide-portale-pm',
|
||||
'language' => 'de',
|
||||
]);
|
||||
$this->actingAs($customer);
|
||||
|
||||
LivewireVolt::test('customer.press-releases.show', ['id' => $pr->id])
|
||||
->assertSee('Auf Presseecho ansehen')
|
||||
->assertSee('Auf Businessportal24 ansehen')
|
||||
->assertSee(config('domains.domain_presseecho_url').'/de/press-release/beide-portale-pm', escape: false)
|
||||
->assertSee(config('domains.domain_businessportal_url').'/de/press-release/beide-portale-pm', escape: false);
|
||||
});
|
||||
|
||||
test('customer show shows no public link for drafts', function () {
|
||||
/** @var TestCase $this */
|
||||
['customer' => $customer, 'pr' => $pr] = makeCustomerForShowPhase8a();
|
||||
$this->actingAs($customer);
|
||||
|
||||
LivewireVolt::test('customer.press-releases.show', ['id' => $pr->id])
|
||||
->assertDontSee('Öffentlich ansehen');
|
||||
});
|
||||
|
||||
test('admin show zeigt den Untertitel direkt unter dem Titel', function () {
|
||||
/** @var TestCase $this */
|
||||
$admin = makeAdminForShowPhase8a();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
|
||||
use App\Enums\Portal;
|
||||
use App\Enums\PressReleaseStatus;
|
||||
use App\Enums\SinglePurchaseStatus;
|
||||
use App\Enums\SinglePurchaseType;
|
||||
|
|
@ -87,6 +88,19 @@ test('the rendered proof is a non-trivial pdf document', function () {
|
|||
expect(strlen($pdf))->toBeGreaterThan(800);
|
||||
});
|
||||
|
||||
test('the rendered proof documents the real public url of the release', function () {
|
||||
$pr = PressRelease::factory()->published()->create([
|
||||
'portal' => Portal::Presseecho,
|
||||
'slug' => 'nachweis-pm',
|
||||
'language' => 'de',
|
||||
]);
|
||||
|
||||
$pdf = app(ProofPdfRenderer::class)->render($pr);
|
||||
|
||||
// Vorher fehlte das /de/press-release/-Segment — die URL im Nachweis lief ins Leere.
|
||||
expect($pdf)->toContain(config('domains.domain_presseecho_url').'/de/press-release/nachweis-pm');
|
||||
});
|
||||
|
||||
test('the proof download requires a prior purchase', function () {
|
||||
$user = customerWithRole();
|
||||
$pr = PressRelease::factory()->published()->create(['user_id' => $user->id]);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue