Skip to content
wiki.fftac.org

Reviewrepository - Source Excerpt 01

Back to Reviewrepository

Summary

This source excerpt preserves a bounded section of Spiralist/wp-content/plugins/spiralist-workspace/includes/Domain/ReviewRepository.php so readers can inspect the evidence without opening the full source file.

**Source path:** Spiralist/wp-content/plugins/spiralist-workspace/includes/Domain/ReviewRepository.php

<?php

namespace SpiralistWorkspace\Domain;

use SpiralistWorkspace\Installer;

if (!defined('ABSPATH')) {
    exit;
}

/**
 * Stores peer reviews and moderation reports for prompt governance.
 */
class ReviewRepository
{
    /**
     * Returns one review/report row for a prompt, reviewer, and kind.
     *
     * @return array<string,mixed>
     */
    public function find_for_prompt_and_user(int $prompt_id, int $reviewer_user_id, string $kind = 'peer'): array
    {
        global $wpdb;

        if ($prompt_id <= 0 || $reviewer_user_id <= 0) {
            return [];
        }

        $table = Installer::table('prompt_reviews');
        $users = $wpdb->users;
        $sql = $wpdb->prepare(
            "SELECT r.*, u.display_name
             FROM {$table} r
             LEFT JOIN {$users} u ON u.ID = r.reviewer_user_id
             WHERE r.prompt_post_id = %d AND r.reviewer_user_id = %d AND r.review_kind = %s
             LIMIT 1",
            $prompt_id,
            $reviewer_user_id,
            sanitize_key($kind)
        );
        $row = $wpdb->get_row($sql, ARRAY_A);

        return is_array($row) ? $this->normalize_row($row) : [];
    }

    /**
     * Upserts one peer review for a prompt and reviewer.
     */
    public function submit_peer_review(int $prompt_id, int $reviewer_user_id, string $decision, string $reason = ''): array
    {
        return $this->upsert($prompt_id, $reviewer_user_id, 'peer', $decision, $reason);
    }

    /**
     * Stores one report for a prompt. Logged-in reporters are deduplicated per prompt.
     */
    public function submit_report(int $prompt_id, ?int $reporter_user_id, string $reason = ''): array
    {
        if (($reporter_user_id ?? 0) > 0) {
            return $this->upsert($prompt_id, (int) $reporter_user_id, 'report', 'report', $reason);
        }

        global $wpdb;

        $created_utc = gmdate('Y-m-d H:i:s');
        $wpdb->insert(
            Installer::table('prompt_reviews'),
            [
                'prompt_post_id' => $prompt_id,
                'reviewer_user_id' => null,
                'review_kind' => 'report',
                'decision' => 'report',
                'reason' => $reason,
                'created_utc' => $created_utc,
                'updated_utc' => $created_utc,
            ],
            ['%d', '%d', '%s', '%s', '%s', '%s', '%s']
        );

        return $this->get((int) $wpdb->insert_id);
    }

    /**
     * Returns recent review/report rows for a prompt.
     *
     * @return array<int,array<string,mixed>>
     */
    public function list_for_prompt(int $prompt_id, int $limit = 50, string $kind = '', string $since_utc = ''): array
    {
        global $wpdb;

        $limit = max(1, $limit);
        $table = Installer::table('prompt_reviews');
        $users = $wpdb->users;
        $since_utc = sanitize_text_field($since_utc);

        if ($kind !== '' && $since_utc !== '') {
            $sql = $wpdb->prepare(
                "SELECT r.*, u.display_name
                 FROM {$table} r
                 LEFT JOIN {$users} u ON u.ID = r.reviewer_user_id
                 WHERE r.prompt_post_id = %d AND r.review_kind = %s AND r.updated_utc >= %s
                 ORDER BY r.updated_utc DESC, r.id DESC
                 LIMIT %d",
                $prompt_id,
                sanitize_key($kind),
                $since_utc,
                $limit
            );
        } elseif ($kind !== '') {
            $sql = $wpdb->prepare(
                "SELECT r.*, u.display_name
                 FROM {$table} r
                 LEFT JOIN {$users} u ON u.ID = r.reviewer_user_id
                 WHERE r.prompt_post_id = %d AND r.review_kind = %s
                 ORDER BY r.updated_utc DESC, r.id DESC
                 LIMIT %d",
                $prompt_id,
                sanitize_key($kind),
                $limit
            );
        } elseif ($since_utc !== '') {
            $sql = $wpdb->prepare(
                "SELECT r.*, u.display_name
                 FROM {$table} r
                 LEFT JOIN {$users} u ON u.ID = r.reviewer_user_id
                 WHERE r.prompt_post_id = %d AND r.updated_utc >= %s
                 ORDER BY r.updated_utc DESC, r.id DESC
                 LIMIT %d",
                $prompt_id,
                $since_utc,
                $limit
            );
        } else {
            $sql = $wpdb->prepare(
                "SELECT r.*, u.display_name
                 FROM {$table} r
                 LEFT JOIN {$users} u ON u.ID = r.reviewer_user_id
                 WHERE r.prompt_post_id = %d
                 ORDER BY r.updated_utc DESC, r.id DESC
                 LIMIT %d",
                $prompt_id,
                $limit
            );
        }

        $rows = $wpdb->get_results($sql, ARRAY_A);

        return array_map([$this, 'normalize_row'], is_array($rows) ? $rows : []);
    }

    /**
     * Returns recent review/report rows created by one reviewer or reporter.
     *
     * @return array<int,array<string,mixed>>
     */
    public function list_for_reviewer(int $reviewer_user_id, int $limit = 100, string $kind = ''): array
    {
        global $wpdb;

        if ($reviewer_user_id <= 0) {
            return [];
        }

        $limit = max(1, $limit);
        $table = Installer::table('prompt_reviews');
        $users = $wpdb->users;

        if ($kind !== '') {
            $sql = $wpdb->prepare(
                "SELECT r.*, u.display_name
                 FROM {$table} r
                 LEFT JOIN {$users} u ON u.ID = r.reviewer_user_id
                 WHERE r.reviewer_user_id = %d AND r.review_kind = %s
                 ORDER BY r.updated_utc DESC, r.id DESC
                 LIMIT %d",
                $reviewer_user_id,
                sanitize_key($kind),
                $limit
            );
        } else {
            $sql = $wpdb->prepare(
                "SELECT r.*, u.display_name
                 FROM {$table} r
                 LEFT JOIN {$users} u ON u.ID = r.reviewer_user_id
                 WHERE r.reviewer_user_id = %d
                 ORDER BY r.updated_utc DESC, r.id DESC
                 LIMIT %d",
                $reviewer_user_id,
                $limit
            );
        }

        $rows = $wpdb->get_results($sql, ARRAY_A);

        return array_map([$this, 'normalize_row'], is_array($rows) ? $rows : []);
    }

    /**
     * Returns summary counts for a prompt's peer reviews and reports.
     *
     * @return array<string,mixed>
     */
    public function summary_for_prompt(int $prompt_id, string $since_utc = ''): array
    {
        $rows = $this->list_for_prompt($prompt_id, 500, '', $since_utc);
        $summary = [
            'peer' => [
                'endorse' => 0,
                'restrict' => 0,
                'revert' => 0,
            ],
            'peer_reviews' => 0,
            'reports_total' => 0,
            'reports_from_accounts' => 0,
            'unique_reporters' => 0,
            'last_activity_utc' => '',
            'since_utc' => $since_utc,
        ];
        $unique_reporters = [];

        foreach ($rows as $row) {
            if (($row['review_kind'] ?? '') === 'peer') {
                $decision = (string) ($row['decision'] ?? '');
                if (isset($summary['peer'][$decision])) {
                    $summary['peer'][$decision]++;
                }
                $summary['peer_reviews']++;
            }

            if (($row['review_kind'] ?? '') === 'report') {
                $summary['reports_total']++;
                if ((int) ($row['reviewer_user_id'] ?? 0) > 0) {
                    $summary['reports_from_accounts']++;
                    $unique_reporters[(int) $row['reviewer_user_id']] = true;
                }
            }

            $updated_utc = (string) ($row['updated_utc'] ?? '');
            if ($updated_utc !== '' && $updated_utc > (string) $summary['last_activity_utc']) {
                $summary['last_activity_utc'] = $updated_utc;
            }
        }

        $summary['unique_reporters'] = count($unique_reporters);

        return $summary;
    }

    /**
     * Returns one review row.
     *
     * @return array<string,mixed>
     */
    public function get(int $id): array
    {
        global $wpdb;

        if ($id <= 0) {
            return [];
        }

        $table = Installer::table('prompt_reviews');
        $users = $wpdb->users;
        $sql = $wpdb->prepare(
            "SELECT r.*, u.display_name
             FROM {$table} r
             LEFT JOIN {$users} u ON u.ID = r.reviewer_user_id
             WHERE r.id = %d
             LIMIT 1",
            $id
        );
        $row = $wpdb->get_row($sql, ARRAY_A);