feat: change log tab with filters, revision links and clear button
ChangeLog gains query()/abilities()/clear() (filters: ability, user, result, date range - all optional and additive). LogTab/LogListTable render the "Protokoll" admin tab: WP_List_Table with pagination, links to the post/attachment/nav_menu edit screen by object_type, a revision link shown only when the user may edit the revision's parent post, and a nonce+manage_options-gated "Protokoll leeren" with a JS confirmation and highlighted 'partial' rows. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
This commit is contained in:
@@ -96,6 +96,80 @@ class ChangeLog
|
||||
return (int) $wpdb->query($wpdb->prepare("DELETE FROM {$table} WHERE created_at < %s", $cutoff));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads rows for the "Protokoll" admin tab (spec §8.3), newest first. All filters are
|
||||
* optional and whitelisted by the caller (LogTab); values only ever reach the query
|
||||
* through wpdb::prepare() placeholders.
|
||||
*
|
||||
* @param array{
|
||||
* ability?: string, user_id?: int, result?: string, date_from?: string, date_to?: string
|
||||
* } $filters
|
||||
* @return array{rows: list<array<string, mixed>>, total: int}
|
||||
*/
|
||||
public function query(array $filters, int $limit, int $offset): array
|
||||
{
|
||||
$wpdb = $this->db();
|
||||
$table = $this->tableName();
|
||||
$where = ['1 = %d'];
|
||||
$args = [1];
|
||||
if (($filters['ability'] ?? '') !== '') {
|
||||
$where[] = 'ability = %s';
|
||||
$args[] = (string) $filters['ability'];
|
||||
}
|
||||
if ((int) ($filters['user_id'] ?? 0) > 0) {
|
||||
$where[] = 'user_id = %d';
|
||||
$args[] = (int) $filters['user_id'];
|
||||
}
|
||||
if (($filters['result'] ?? '') !== '') {
|
||||
$where[] = 'result = %s';
|
||||
$args[] = (string) $filters['result'];
|
||||
}
|
||||
if (($filters['date_from'] ?? '') !== '') {
|
||||
$where[] = 'created_at >= %s';
|
||||
$args[] = $filters['date_from'] . ' 00:00:00';
|
||||
}
|
||||
if (($filters['date_to'] ?? '') !== '') {
|
||||
$where[] = 'created_at <= %s';
|
||||
$args[] = $filters['date_to'] . ' 23:59:59';
|
||||
}
|
||||
$whereSql = implode(' AND ', $where);
|
||||
|
||||
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare, WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber -- $whereSql holds one %s/%d per filter actually present.
|
||||
$total = (int) $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM {$table} WHERE {$whereSql}", ...$args));
|
||||
$rows = $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
"SELECT * FROM {$table} WHERE {$whereSql} ORDER BY id DESC LIMIT %d OFFSET %d",
|
||||
...array_merge($args, [$limit, $offset])
|
||||
),
|
||||
'ARRAY_A'
|
||||
);
|
||||
// phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare, WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber
|
||||
|
||||
return ['rows' => is_array($rows) ? array_values($rows) : [], 'total' => $total];
|
||||
}
|
||||
|
||||
/** @return list<string> */
|
||||
public function abilities(): array
|
||||
{
|
||||
$wpdb = $this->db();
|
||||
$table = $this->tableName();
|
||||
|
||||
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- own table name.
|
||||
$abilities = (array) $wpdb->get_col("SELECT DISTINCT ability FROM {$table} ORDER BY ability");
|
||||
|
||||
return array_values(array_map('strval', $abilities));
|
||||
}
|
||||
|
||||
/** Deletes every row (button "Protokoll leeren", spec §8.3). Irreversible. */
|
||||
public function clear(): void
|
||||
{
|
||||
$wpdb = $this->db();
|
||||
$table = $this->tableName();
|
||||
|
||||
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- own table name.
|
||||
$wpdb->query("DELETE FROM {$table}");
|
||||
}
|
||||
|
||||
/**
|
||||
* RequestContext::clientName() is a client-chosen string (app-password name or
|
||||
* OAuth client_id) – treat it as untrusted input before it lands in the DB.
|
||||
|
||||
Reference in New Issue
Block a user