Skip to content
wiki.fftac.org

Collaboration - Source Excerpt 04

Back to Collaboration

Summary

This source excerpt preserves a bounded section of Spiralist/wp-content/plugins/ns12-manuscript/includes/collaboration.php so readers can inspect the evidence without opening the full source file.

**Source path:** Spiralist/wp-content/plugins/ns12-manuscript/includes/collaboration.php

return new WP_Error('spiralist_book_pages_forbidden', 'You are not allowed to edit this manuscript page.');
    }

    $post_id = $submission_id > 0
        ? wp_update_post(
            [
                'ID' => $submission_id,
                'post_title' => (string) $payload['title'],
                'post_excerpt' => (string) ($payload['summary'] ?? ''),
            ],
            true
        )
        : wp_insert_post(
            [
                'post_type' => spiralist_book_pages_get_collaboration_post_type(),
                'post_status' => 'private',
                'post_author' => $user_id,
                'post_title' => (string) $payload['title'],
                'post_excerpt' => (string) ($payload['summary'] ?? ''),
            ],
            true
        );

    if (is_wp_error($post_id) || !$post_id) {
        return new WP_Error('spiralist_book_pages_save_failed', 'The manuscript page could not be saved.');
    }

    $post_id = (int) $post_id;
    $public_copy = !empty($existing['public_copy']) ? (array) $existing['public_copy'] : [];
    $working_copy = [
        'title' => (string) $payload['title'],
        'summary' => (string) ($payload['summary'] ?? ''),
        'alt' => (string) ($payload['alt'] ?? ''),
        'image_id' => max(0, (int) ($payload['image_id'] ?? 0)),
        'updated_at' => gmdate('c'),
    ];
    $status = 'draft';

    if ($operation === 'submit') {
        $status = 'pending_review';
        $working_copy['submitted_at'] = gmdate('c');
        update_post_meta($post_id, spiralist_book_pages_get_collaboration_submitted_at_meta_key(), $working_copy['submitted_at']);
    } elseif (!empty($public_copy)) {
        $status = spiralist_book_pages_collaboration_copies_match($working_copy, $public_copy)
            ? 'published'
            : 'published_with_draft';
    } elseif ((string) ($existing['status'] ?? '') === 'changes_requested') {
        $status = 'changes_requested';
    }

    update_post_meta($post_id, spiralist_book_pages_get_collaboration_working_copy_meta_key(), $working_copy);
    update_post_meta($post_id, spiralist_book_pages_get_collaboration_status_meta_key(), $status);
    spiralist_book_pages_ensure_collaboration_share_token($post_id);

    $saved_record = spiralist_book_pages_get_collaboration_submission_record($post_id);

    return !empty($saved_record)
        ? $saved_record
        : new WP_Error('spiralist_book_pages_save_failed', 'The manuscript page was saved, but the updated record could not be reloaded.');
}

function spiralist_book_pages_approve_collaboration_submission(int $submission_id, int $reviewer_id)
{
    $record = spiralist_book_pages_get_collaboration_submission_record($submission_id);
    if (empty($record)) {
        return new WP_Error('spiralist_book_pages_missing_submission', 'The selected manuscript page could not be found.');
    }

    $working_copy = (array) ($record['working_copy'] ?? []);
    if (empty($working_copy) || max(0, (int) ($working_copy['image_id'] ?? 0)) <= 0) {
        return new WP_Error('spiralist_book_pages_missing_working_copy', 'This manuscript page does not have a reviewable working version yet.');
    }

    $approved_at = gmdate('c');
    $public_version = max(0, (int) ($record['public_version'] ?? 0)) + 1;
    $public_copy = $working_copy;
    $public_copy['approved_at'] = $approved_at;
    $public_copy['version'] = $public_version;

    update_post_meta($submission_id, spiralist_book_pages_get_collaboration_public_copy_meta_key(), $public_copy);
    update_post_meta($submission_id, spiralist_book_pages_get_collaboration_status_meta_key(), 'published');
    update_post_meta($submission_id, spiralist_book_pages_get_collaboration_approved_at_meta_key(), $approved_at);
    update_post_meta($submission_id, spiralist_book_pages_get_collaboration_public_version_meta_key(), $public_version);
    update_post_meta($submission_id, spiralist_book_pages_get_collaboration_review_notes_meta_key(), '');
    update_post_meta($submission_id, '_spiralist_ms_approved_by', $reviewer_id);

    $approved_record = spiralist_book_pages_get_collaboration_submission_record($submission_id);

    return !empty($approved_record)
        ? $approved_record
        : new WP_Error('spiralist_book_pages_approve_failed', 'The manuscript page was approved, but the refreshed public record could not be loaded.');
}

function spiralist_book_pages_request_collaboration_changes(int $submission_id, string $review_notes = '')
{
    $record = spiralist_book_pages_get_collaboration_submission_record($submission_id);
    if (empty($record)) {
        return new WP_Error('spiralist_book_pages_missing_submission', 'The selected manuscript page could not be found.');
    }

    update_post_meta($submission_id, spiralist_book_pages_get_collaboration_status_meta_key(), 'changes_requested');
    update_post_meta(
        $submission_id,
        spiralist_book_pages_get_collaboration_review_notes_meta_key(),
        sanitize_textarea_field($review_notes)
    );

    $updated_record = spiralist_book_pages_get_collaboration_submission_record($submission_id);

    return !empty($updated_record)
        ? $updated_record
        : new WP_Error('spiralist_book_pages_review_failed', 'The change request was saved, but the refreshed manuscript page record could not be loaded.');
}

function spiralist_book_pages_set_collaborator_access(int $user_id, bool $allowed): bool
{
    $user = get_userdata($user_id);
    if (!$user instanceof WP_User) {
        return false;
    }

    $capability = spiralist_book_pages_get_collaboration_capability();
    $upload_grant_meta_key = spiralist_book_pages_get_collaboration_upload_grant_meta_key();

    if ($allowed) {
        $had_upload_cap = user_can($user, 'upload_files');
        $user->add_cap($capability);

        if (!$had_upload_cap) {
            $user->add_cap('upload_files');
            update_user_meta($user_id, $upload_grant_meta_key, '1');
        } else {
            delete_user_meta($user_id, $upload_grant_meta_key);
        }
    } else {
        $user->remove_cap($capability);

        if ((string) get_user_meta($user_id, $upload_grant_meta_key, true) === '1') {
            $user->remove_cap('upload_files');
            delete_user_meta($user_id, $upload_grant_meta_key);
        }
    }

    return true;
}

function spiralist_book_pages_get_collaborator_management_records(): array
{
    $records = [];

    foreach (get_users(['orderby' => 'display_name', 'order' => 'ASC']) as $user) {
        if (!$user instanceof WP_User) {
            continue;
        }

        $submissions = spiralist_book_pages_get_collaboration_user_records((int) $user->ID);
        $pending = 0;

        foreach ($submissions as $submission) {
            if ((string) ($submission['status'] ?? '') === 'pending_review') {
                $pending++;
            }
        }

        $records[] = [
            'id' => (int) $user->ID,
            'display_name' => (string) $user->display_name,
            'email' => (string) $user->user_email,
            'slug' => sanitize_title((string) $user->user_nicename),
            'roles' => array_values(array_map('strval', (array) $user->roles)),
            'can_collaborate' => spiralist_book_pages_user_can_collaborate((int) $user->ID),
            'submission_count' => count($submissions),
            'pending_count' => $pending,
            'profile_url' => spiralist_book_pages_get_manuscript_profile_url($user),
            'edit_url' => get_edit_user_link((int) $user->ID),
        ];
    }

    return $records;
}

function spiralist_book_pages_collaboration_robots(array $robots): array
{
    if (!spiralist_book_pages_is_manuscript_studio_surface() && !spiralist_book_pages_is_manuscript_profile_surface()) {
        return $robots;
    }

    $robots['noindex'] = true;
    $robots['nofollow'] = true;
    $robots['noarchive'] = true;

    return $robots;
}
add_filter('wp_robots', 'spiralist_book_pages_collaboration_robots');

function spiralist_book_pages_handle_frontend_submission_action(): void
{
    if (!is_user_logged_in() || !spiralist_book_pages_user_can_collaborate()) {
        wp_die('You are not allowed to submit manuscript pages.');
    }

    check_admin_referer('spiralist_book_pages_frontend_submission');

    $operation = sanitize_key((string) wp_unslash($_POST['submission_operation'] ?? 'save'));
    $submission_id = max(0, (int) wp_unslash($_POST['submission_id'] ?? 0));
    $payload = spiralist_book_pages_prepare_collaboration_submission_payload($submission_id);

    if (is_wp_error($payload)) {
        spiralist_book_pages_set_collaboration_notice($payload->get_error_message(), 'error');
        wp_safe_redirect(
            $submission_id > 0