Skip to content
wiki.fftac.org

Collaboration - Source Excerpt 03

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

'approved_at' => $approved_at,
        'public_version' => $public_version,
        'author' => [
            'id' => (int) $post->post_author,
            'display_name' => $author instanceof WP_User ? (string) $author->display_name : 'Contributor',
            'slug' => $author instanceof WP_User ? sanitize_title((string) $author->user_nicename) : '',
        ],
    ];

    $record['studio_url'] = spiralist_book_pages_get_manuscript_studio_url($record['slug']);
    $record['public_url'] = $record['has_public_copy'] ? spiralist_book_pages_get_manuscript_community_url($record['slug']) : '';
    $record['profile_url'] = spiralist_book_pages_get_manuscript_profile_url($record['author']['slug'], $record['slug']);
    $record['profile_share_url'] = add_query_arg('share', rawurlencode($share_token), $record['profile_url']);

    return $record;
}

function spiralist_book_pages_get_collaboration_submission_query(array $args = []): array
{
    $defaults = [
        'post_type' => spiralist_book_pages_get_collaboration_post_type(),
        'post_status' => 'any',
        'posts_per_page' => -1,
        'orderby' => 'date',
        'order' => 'DESC',
    ];

    return get_posts(array_merge($defaults, $args));
}

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

    foreach (spiralist_book_pages_get_collaboration_submission_query($args) as $submission) {
        $record = spiralist_book_pages_get_collaboration_submission_record($submission);
        if (!empty($record)) {
            $records[] = $record;
        }
    }

    return $records;
}

function spiralist_book_pages_get_collaboration_user_records(int $user_id): array
{
    return spiralist_book_pages_get_collaboration_submission_records(
        [
            'author' => max(0, $user_id),
        ]
    );
}

function spiralist_book_pages_get_public_collaboration_records(): array
{
    $records = array_values(
        array_filter(
            spiralist_book_pages_get_collaboration_submission_records(),
            static function (array $record): bool {
                return !empty($record['has_public_copy']);
            }
        )
    );

    usort(
        $records,
        static function (array $left, array $right): int {
            return strcmp((string) ($right['approved_at'] ?? ''), (string) ($left['approved_at'] ?? ''));
        }
    );

    return $records;
}

function spiralist_book_pages_get_pending_collaboration_records(): array
{
    return array_values(
        array_filter(
            spiralist_book_pages_get_collaboration_submission_records(),
            static function (array $record): bool {
                return (string) ($record['status'] ?? '') === 'pending_review';
            }
        )
    );
}

function spiralist_book_pages_get_collaboration_submission_by_slug(string $slug, int $author_id = 0): array
{
    $slug = sanitize_title($slug);
    if ($slug === '') {
        return [];
    }

    $args = [
        'name' => $slug,
        'posts_per_page' => 1,
    ];

    if ($author_id > 0) {
        $args['author'] = $author_id;
    }

    $posts = spiralist_book_pages_get_collaboration_submission_query($args);

    return !empty($posts[0]) ? spiralist_book_pages_get_collaboration_submission_record($posts[0]) : [];
}

function spiralist_book_pages_can_edit_collaboration_submission($submission, int $user_id = 0): bool
{
    $record = is_array($submission)
        ? $submission
        : spiralist_book_pages_get_collaboration_submission_record($submission);

    if (empty($record)) {
        return false;
    }

    $user_id = $user_id > 0 ? $user_id : get_current_user_id();
    if ($user_id <= 0) {
        return false;
    }

    if (user_can($user_id, 'manage_options')) {
        return true;
    }

    return spiralist_book_pages_user_can_collaborate($user_id)
        && (int) ($record['author']['id'] ?? 0) === $user_id;
}

function spiralist_book_pages_can_view_profile_submission(array $record, string $share_token = ''): bool
{
    if (empty($record)) {
        return false;
    }

    if (spiralist_book_pages_can_edit_collaboration_submission($record)) {
        return true;
    }

    $share_token = sanitize_text_field($share_token);
    if ($share_token === '') {
        return false;
    }

    $stored_token = (string) ($record['share_token'] ?? '');

    return $stored_token !== '' && hash_equals($stored_token, $share_token);
}

function spiralist_book_pages_get_submission_editor_seed(array $record = []): array
{
    $copy = !empty($record['working_copy']) ? (array) $record['working_copy'] : (!empty($record['public_copy']) ? (array) $record['public_copy'] : []);

    return [
        'title' => (string) ($copy['title'] ?? ''),
        'summary' => (string) ($copy['summary'] ?? ''),
        'alt' => (string) ($copy['alt'] ?? ''),
        'image_id' => max(0, (int) ($copy['image_id'] ?? 0)),
        'image_url' => (string) ($copy['image_url'] ?? ''),
        'thumbnail_url' => (string) ($copy['thumbnail_url'] ?? ''),
    ];
}

function spiralist_book_pages_handle_collaboration_upload(string $field)
{
    if (empty($_FILES[$field]) || !is_array($_FILES[$field])) {
        return 0;
    }

    $file = $_FILES[$field];
    $error = (int) ($file['error'] ?? UPLOAD_ERR_NO_FILE);

    if ($error === UPLOAD_ERR_NO_FILE) {
        return 0;
    }

    if ($error !== UPLOAD_ERR_OK) {
        return new WP_Error('spiralist_book_pages_upload_failed', 'The manuscript image upload could not be completed.');
    }

    if (!current_user_can('upload_files')) {
        return new WP_Error('spiralist_book_pages_upload_forbidden', 'This account cannot upload manuscript images yet.');
    }

    require_once ABSPATH . 'wp-admin/includes/file.php';
    require_once ABSPATH . 'wp-admin/includes/image.php';
    require_once ABSPATH . 'wp-admin/includes/media.php';

    $attachment_id = media_handle_upload($field, 0, [], ['test_form' => false]);

    if (is_wp_error($attachment_id)) {
        return new WP_Error(
            'spiralist_book_pages_upload_failed',
            'The manuscript image could not be saved. ' . $attachment_id->get_error_message()
        );
    }

    $attachment_id = (int) $attachment_id;
    $validated_attachment_id = spiralist_book_pages_validate_collaboration_image_attachment($attachment_id);
    if (is_wp_error($validated_attachment_id)) {
        wp_delete_attachment($attachment_id, true);

        return $validated_attachment_id;
    }

    return (int) $validated_attachment_id;
}

function spiralist_book_pages_prepare_collaboration_submission_payload(int $existing_submission_id = 0)
{
    $existing = $existing_submission_id > 0
        ? spiralist_book_pages_get_collaboration_submission_record($existing_submission_id)
        : [];
    $seed = spiralist_book_pages_get_submission_editor_seed($existing);
    $upload_result = spiralist_book_pages_handle_collaboration_upload('manuscript_image');

    if (is_wp_error($upload_result)) {
        return $upload_result;
    }

    $image_id = max(0, (int) $upload_result);
    if ($image_id <= 0) {
        $image_id = max(
            0,
            (int) wp_unslash($_POST['current_image_id'] ?? $seed['image_id'])
        );
    }

    $validated_image_id = spiralist_book_pages_validate_collaboration_image_attachment($image_id);
    if (is_wp_error($validated_image_id)) {
        return $validated_image_id;
    }

    $title = sanitize_text_field((string) wp_unslash($_POST['submission_title'] ?? $seed['title']));
    $summary = sanitize_textarea_field((string) wp_unslash($_POST['submission_summary'] ?? $seed['summary']));
    $alt = sanitize_text_field((string) wp_unslash($_POST['submission_alt'] ?? $seed['alt']));

    if ($title === '') {
        return new WP_Error('spiralist_book_pages_missing_title', 'Give this manuscript page a title before saving it.');
    }

    return [
        'title' => $title,
        'summary' => $summary,
        'alt' => $alt,
        'image_id' => (int) $validated_image_id,
    ];
}

function spiralist_book_pages_save_collaboration_submission(array $payload, int $user_id, int $submission_id = 0, string $operation = 'save')
{
    $existing = $submission_id > 0
        ? spiralist_book_pages_get_collaboration_submission_record($submission_id)
        : [];

    if ($submission_id > 0 && empty($existing)) {
        return new WP_Error('spiralist_book_pages_missing_submission', 'The selected manuscript page could not be found.');
    }

    if ($submission_id > 0 && !spiralist_book_pages_can_edit_collaboration_submission($existing, $user_id)) {