Skip to the content.

← Back to Plugin Architecture

5.5 GitHubIssueSubmitter Plugin

Last Updated: July 17, 2025
Status: Complete
Plugin: GitHubIssueSubmitter

The GitHubIssueSubmitter plugin allows users to submit feedback and bug reports directly to the project’s GitHub repository.

Purpose

This plugin provides an in-application interface for capturing user feedback and automatically creating GitHub issues, streamlining the bug reporting and feature request process.

Key Features

Configuration

The plugin requires GitHub API credentials configured in the app_settings table through StaticHelpers:

GitHub Repository Configuration:

Plugin Operation Settings:

Architecture Overview

The GitHubIssueSubmitter plugin provides a complete feedback collection system with anonymous submission capabilities and direct GitHub integration. The plugin follows KMP’s standard architecture patterns with clear separation of concerns between controllers, view cells, policies, and frontend components.

Core Components

Configuration Management

The plugin uses a version-based configuration system through StaticHelpers:

// Configuration settings initialized automatically
StaticHelpers::getAppSetting("GitHubIssueSubmitter.configVersion", "25.01.11.a");
StaticHelpers::getAppSetting("KMP.GitHub.Owner", "Ansteorra"); 
StaticHelpers::getAppSetting("KMP.GitHub.Project", "KMP");
StaticHelpers::getAppSetting("Plugin.GitHubIssueSubmitter.Active", "yes");
StaticHelpers::getAppSetting("Plugin.GitHubIssueSubmitter.PopupMessage", "...");

Complete Feedback Submission Workflow

1. Plugin Activation and Initialization

The plugin initializes during application bootstrap:

// Automatic configuration version management
$currentConfigVersion = "25.01.11.a";
$configVersion = StaticHelpers::getAppSetting("GitHubIssueSubmitter.configVersion");
if ($configVersion != $currentConfigVersion) {
    // Initialize/update all plugin settings
    StaticHelpers::setAppSetting("GitHubIssueSubmitter.configVersion", $currentConfigVersion);
    // ... other settings initialization
}

Process Flow:

  1. Plugin loads during application bootstrap
  2. Configuration version is checked and updated if needed
  3. GitHub repository settings are initialized with defaults
  4. Plugin activation status is set
  5. User guidance message is configured

2. User Interface Presentation

The feedback interface is displayed through view cells with conditional rendering:

// IssueSubmitterCell.php display logic
public function display()
{
    if (!StaticHelpers::pluginEnabled("GitHubIssueSubmitter")) {
        return; // Don't render if plugin is inactive
    }
    // Render feedback form modal
}

UI Components:

3. Anonymous Form Submission

Users submit feedback without authentication through AJAX:

// Stimulus controller handles form submission
submit(event) {
    event.preventDefault();
    let formData = new FormData(this.formTarget);
    
    fetch(this.urlValue, {
        method: 'POST',
        body: formData
    }).then(response => response.json())
      .then(data => {
          // Handle success/error response
      });
}

Form Processing:

4. Input Validation and Sanitization

The controller processes and sanitizes all user input before API transmission:

// Data sanitization in IssuesController
$title = htmlspecialchars(stripslashes($this->request->getData('title')), ENT_QUOTES);
$body = htmlspecialchars(stripslashes($this->request->getData('body')), ENT_QUOTES);
$category = $this->request->getData('feedbackType');

Security Measures:

5. GitHub API Integration

The controller communicates directly with GitHub’s REST API:

// GitHub API request formation
$url = "https://api.github.com/repos/$owner/$repo/issues";
$header = [
    'Content-type: application/x-www-form-urlencoded',
    'Authorization: token ' . $token,
];
$postData = json_encode([
    'title' => $title,
    'body' => $body,
    'labels' => ['web', $category],
]);

API Integration Details:

6. Response Processing and User Feedback

The system processes GitHub’s response and provides immediate user feedback:

// Response handling
$decoded = json_decode($response, true);
if (isset($decoded['message'])) {
    $responseJson["message"] = $decoded['message']; // Error case
} else {
    $responseJson = [
        "url" => $decoded["html_url"], 
        "number" => $decoded["number"]
    ]; // Success case
}

Response Types:

7. UI State Management

The frontend controller manages UI transitions based on submission results:

// Success state handling
.then(data => {
    if (data.message) {
        alert("Error: " + data.message);
        return;
    }
    // Update UI for successful submission
    this.formBlockTarget.style.display = 'none';
    this.submitBtnTarget.style.display = 'none';
    this.issueLinkTarget.href = data.url;
    this.successTarget.style.display = 'block';
});

UI Transitions:

Configuration Management Documentation

Version Control System

The plugin implements automatic configuration management:

class GitHubIssueSubmitterPlugin extends BasePlugin
{
    public function bootstrap(PluginApplicationInterface $app): void
    {
        $currentConfigVersion = "25.01.11.a"; // Updated with each config change
        
        $configVersion = StaticHelpers::getAppSetting("GitHubIssueSubmitter.configVersion", "0.0.0");
        if ($configVersion != $currentConfigVersion) {
            // Perform configuration initialization/update
        }
    }
}

GitHub Repository Configuration

Configure the target GitHub repository through StaticHelpers:

// Required GitHub settings - actual implementation
StaticHelpers::setAppSetting('KMP.GitHub.Owner', 'YourOrganization');
StaticHelpers::setAppSetting('KMP.GitHub.Project', 'YourRepository');

// Token is stored as nested array structure
$githubSettings = StaticHelpers::getAppSetting('KMP.GitHub', []);
$githubSettings['Token'] = 'github_pat_...';
StaticHelpers::setAppSetting('KMP.GitHub', $githubSettings);

Repository Settings:

Plugin Operation Configuration

// Plugin operation settings
StaticHelpers::setAppSetting('Plugin.GitHubIssueSubmitter.Active', 'yes');
StaticHelpers::setAppSetting('Plugin.GitHubIssueSubmitter.PopupMessage', 
    'This Feedback form is anonymous and will be submitted to the KMP GitHub repository. Please do not include any pii or use this for support requests.');

Label Management and Issue Categorization

Issues are automatically categorized with labels:

// Automatic label assignment
$postData = json_encode([
    'title' => $title,
    'body' => $body,
    'labels' => ['web', $category], // 'web' + user-selected category
]);

Standard Labels:

Security Architecture and Considerations

Anonymous Submission Safety

The plugin allows anonymous access while maintaining security:

// Anonymous access configuration in IssuesController
public function beforeFilter(EventInterface $event)
{
    parent::beforeFilter($event);
    $this->Authentication->allowUnauthenticated(["submit"]);
}

Security Measures:

Data Protection and Privacy

// Input sanitization pipeline
$title = htmlspecialchars(stripslashes($title), ENT_QUOTES);
$body = htmlspecialchars(stripslashes($body), ENT_QUOTES);

Protection Features:

API Token Security

// Secure token handling - actual implementation
$token = StaticHelpers::getAppSetting("KMP.GitHub", "")["Token"];
$header = [
    'Authorization: token ' . $token,
];

Token Security:

Abuse Prevention Strategies

Rate Limiting Considerations:

Integration Patterns and Deployment

KMP Application Integration

The plugin integrates seamlessly with KMP’s architecture:

// Application.php bootstrap integration
$this->addPlugin('GitHubIssueSubmitter', [
    'bootstrap' => true,
    'routes' => true
]);

Integration Points:

Routing Configuration

// Plugin routes configuration
public function routes(RouteBuilder $routes): void
{
    $routes->plugin(
        'GitHubIssueSubmitter',
        ['path' => '/git-hub-issue-submitter'],
        function (RouteBuilder $builder) {
            $builder->fallbacks(); // Standard CakePHP routing conventions
        }
    );
}

Available Routes:

Deployment Considerations

GitHub API Token Configuration:

  1. Create GitHub personal access token with public_repo scope (or repo for private repositories)
  2. Configure token in KMP application settings using the nested array structure:
    $githubSettings = StaticHelpers::getAppSetting('KMP.GitHub', []);
    $githubSettings['Token'] = 'github_pat_your_token_here';
    StaticHelpers::setAppSetting('KMP.GitHub', $githubSettings);
    
  3. Verify repository access and permissions
  4. Test issue creation before production deployment

Repository Setup:

  1. Ensure target repository exists and is accessible
  2. Configure appropriate issue templates (optional)
  3. Set up repository labels for categorization
  4. Configure issue notification settings

Monitoring and Maintenance

GitHub API Integration Monitoring:

Maintenance Procedures:

Troubleshooting Guide

Common Issues and Solutions:

  1. API Authentication Errors:
    • Verify token validity and permissions
    • Check repository access rights
    • Confirm token scope includes public_repo
  2. Network Connectivity Issues:
    • Verify HTTPS connectivity to api.github.com
    • Check firewall and proxy settings
    • Test API connectivity from server
  3. Form Submission Failures:
    • Verify CSRF token configuration
    • Check form field validation rules
    • Confirm JavaScript controller loading
  4. Configuration Problems:
    • Verify StaticHelpers setting storage
    • Check plugin activation status
    • Confirm configuration version updates

References and Additional Resources

Plugin Architecture Documentation

GitHub API Documentation

CakePHP Framework References

Frontend Technologies

Security Best Practices


Last Updated: July 19, 2025
Plugin Version: 25.01.11.a
Documentation Status: Complete - All workflow documentation implemented
Fact-Check Status: ✅ Verified against source code implementation

Documentation Fact-Check Summary

This documentation has been fact-checked against the actual source code implementation and corrected for accuracy:

✅ Verified Implementations:

🔧 Corrected Configuration Details:

📋 Implementation Notes: