fix: detach meldet nicht „alles erledigt“, solange nicht lesbare Fundstellen Verweise enthalten können; PageRewriter::apply liefert hidden_count; Tests für Sperre durch nicht lesbare Seiten und post_ids über der Obergrenze

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Jan-Niclas Loosen
2026-10-18 17:38:01 +02:00
co-authored by Claude Sonnet 5.5
parent b805ed64dd
commit 06398242d6
7 changed files with 132 additions and 11 deletions
@@ -223,8 +223,10 @@ final class DiviDesignDetachAbility implements Ability
$target['name']
);
$done = self::finished($target, $preview['skipped'], $preview['hidden_count']);
return PageRewriteReport::nothingToDo(
$summary . (self::finished($target, $preview['skipped']) ? ' ' . self::DELETE_HINT : ''),
$summary . ($done ? ' ' . self::DELETE_HINT : ''),
$preview,
$notes
);
@@ -343,7 +345,8 @@ final class DiviDesignDetachAbility implements Ability
if ($wrotePresets) {
$summary = $presets['summary'] . ' ' . $summary;
}
if ($pages['remaining'] === 0 && self::finished($target, $pages['skipped'])) {
$done = self::finished($target, $pages['skipped'], $pages['hidden_count']);
if ($pages['remaining'] === 0 && $done) {
$summary .= ' ' . self::DELETE_HINT;
}
@@ -354,6 +357,7 @@ final class DiviDesignDetachAbility implements Ability
->with('saved', $pages['saved'])
->with('remaining', $pages['remaining'])
->with('skipped', $pages['skipped'])
->with('hidden_count', $pages['hidden_count'])
->with('diff', $presets['diff'] ?? [])
->with('design_rev', $presets['design_rev'] ?? null)
->toArray();
@@ -399,14 +403,15 @@ final class DiviDesignDetachAbility implements Ability
}
/**
* Whether nothing is left to detach before lit/divi-presets-delete: all usages, nothing skipped.
* Whether nothing is left to detach before lit/divi-presets-delete: all usages, nothing skipped, and no usage
* this account may not read (delete would still answer in_use).
*
* @param array<string, mixed> $target
* @param list<array<string, mixed>> $skipped
*/
private static function finished(array $target, array $skipped): bool
private static function finished(array $target, array $skipped, int $hidden): bool
{
return $target['post_ids'] === null && $skipped === [];
return $target['post_ids'] === null && $skipped === [] && $hidden === 0;
}
/**
@@ -147,6 +147,7 @@ final class DiviPresetsAssignAbility implements Ability
->with('saved', $result['saved'])
->with('remaining', $result['remaining'])
->with('skipped', $result['skipped'])
->with('hidden_count', $result['hidden_count'])
->toArray();
}
@@ -58,10 +58,22 @@ final class PageRewriteReport
if ($result['skipped'] !== []) {
return $summary . sprintf(' Übersprungen: %d (siehe skipped).', count($result['skipped']));
}
if (($result['hidden_count'] ?? 0) > 0) {
return $summary . ' ' . self::hiddenNote($result['hidden_count']);
}
return $summary . ' Alle Fundstellen sind erledigt.';
}
/** The caveat when posts this account may not read could still carry references. */
public static function hiddenNote(int $hidden): string
{
return sprintf(
'Hinweis: %d für diesen Zugang nicht sichtbare Fundstellen können noch Verweise enthalten.',
$hidden
);
}
/**
* @param array<string, mixed> $preview
* @param list<string> $warnings
@@ -97,6 +109,10 @@ final class PageRewriteReport
],
],
'remaining' => ['type' => 'integer'],
'hidden_count' => [
'type' => 'integer',
'description' => 'Fundstellen, die dieses Konto nicht lesen darf (nicht geändert).',
],
'skipped' => [
'type' => 'array',
'items' => [
+12 -4
View File
@@ -123,8 +123,9 @@ class PageRewriter
* @param Closure(): NodeRewrite $rewrite A fresh strategy per post.
* @param list<int>|null $postIds Only these posts; null = every usage.
* @return array{saved: list<array{post_id: int, revision_id: ?int, nodes: int}>, remaining: int,
* warnings: list<string>, skipped: list<array{post_id: int, reason: string}>}|WP_Error
* unsupported (above HARD_CAP), forbidden (blocked), partial_write (data.saved)
* warnings: list<string>, skipped: list<array{post_id: int, reason: string}>, hidden_count: int}|WP_Error
* hidden_count = usages this account may not read (never rewritten, as in preview(); 0 with post_ids);
* errors: unsupported (above HARD_CAP), forbidden (blocked), partial_write (data.saved)
* @throws WriteFailed When saving the first post fails.
* @throws DiviLocked When Divi is not released – before the first post is written.
*/
@@ -136,7 +137,8 @@ class PageRewriter
string $summary
): array|WP_Error {
$ids = self::ids($postIds);
$refusal = $this->refusal($this->usages->reportFor($query), $ids);
$report = $this->usages->reportFor($query);
$refusal = $this->refusal($report, $ids);
if ($refusal !== null) {
return $refusal;
}
@@ -158,7 +160,13 @@ class PageRewriter
}
}
return ['saved' => $saved, 'remaining' => $remaining, 'warnings' => $warnings, 'skipped' => $skipped];
return [
'saved' => $saved,
'remaining' => $remaining,
'warnings' => $warnings,
'skipped' => $skipped,
'hidden_count' => $ids === null ? $report->hidden : 0,
];
}
/**