coolify/app/Models/GithubApp.php
Andras Bacsai 06ee7d0132 fix: GitHub source creation and configuration issues
Fixed multiple issues with GitHub App source creation and management:

1. **Fixed null property assignment error on component mount**
   - Changed property types to nullable in Change component (appId, installationId, clientId, etc.)
   - Updated validation rules to allow nullable values
   - Allows mounting component with newly created GitHub Apps that don't have these fields set yet

2. **Fixed Livewire morphing error on manual creation**
   - Modified createGithubAppManually() to redirect after saving
   - Prevents "Cannot read properties of null" error when view structure changes
   - Fields now properly populated after manual creation without requiring page refresh

3. **Fixed is_system_wide not being saved on creation**
   - Removed backwards logic that only saved is_system_wide on cloud instances
   - Added is_system_wide to GithubApp model casts for proper boolean handling
   - System-wide checkbox now works correctly on self-hosted instances

4. **Fixed misleading preview deployment checkbox**
   - Removed instantSave attribute from permission checkboxes in unconfigured state
   - These are configuration options for GitHub App creation, not database fields
   - Prevents "GitHub App updated" success message when nothing was actually saved

5. **Added validation for Refetch Permissions button**
   - Validates App ID and Private Key are set before attempting to fetch
   - Shows clear error messages: "Cannot fetch permissions. Please set the following required fields first: App ID, Private Key"
   - Prevents crash when private key is null or invalid

6. **Better error handling for unsupported private key formats**
   - Detects OpenSSH format keys vs RSA PEM format
   - Shows helpful message: "Please use an RSA private key in PEM format (BEGIN RSA PRIVATE KEY). OpenSSH format keys are not supported."
   - GitHub Apps require RSA PEM format, not OpenSSH format

7. **Made GitHub App view mobile responsive**
   - Updated all flex layouts to stack vertically on mobile (flex-col sm:flex-row)
   - Form fields, buttons, and sections now properly responsive
   - No more cut-off fields on small screens

Added comprehensive test coverage:
- GithubSourceChangeTest.php with 7 tests
- GithubSourceCreateTest.php with 6 tests

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-25 10:49:09 +02:00

88 lines
2.3 KiB
PHP

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Casts\Attribute;
class GithubApp extends BaseModel
{
protected $guarded = [];
protected $appends = ['type'];
protected $casts = [
'is_public' => 'boolean',
'is_system_wide' => 'boolean',
'type' => 'string',
];
protected $hidden = [
'client_secret',
'webhook_secret',
];
protected static function booted(): void
{
static::deleting(function (GithubApp $github_app) {
$applications_count = Application::where('source_id', $github_app->id)->count();
if ($applications_count > 0) {
throw new \Exception('You cannot delete this GitHub App because it is in use by '.$applications_count.' application(s). Delete them first.');
}
$github_app->privateKey()->delete();
});
}
public static function ownedByCurrentTeam()
{
return GithubApp::where(function ($query) {
$query->where('team_id', currentTeam()->id)
->orWhere('is_system_wide', true);
});
}
public static function public()
{
return GithubApp::where(function ($query) {
$query->where(function ($q) {
$q->where('team_id', currentTeam()->id)
->orWhere('is_system_wide', true);
})->where('is_public', true);
})->whereNotNull('app_id')->get();
}
public static function private()
{
return GithubApp::where(function ($query) {
$query->where(function ($q) {
$q->where('team_id', currentTeam()->id)
->orWhere('is_system_wide', true);
})->where('is_public', false);
})->whereNotNull('app_id')->get();
}
public function team()
{
return $this->belongsTo(Team::class);
}
public function applications()
{
return $this->morphMany(Application::class, 'source');
}
public function privateKey()
{
return $this->belongsTo(PrivateKey::class);
}
public function type(): Attribute
{
return Attribute::make(
get: function () {
if ($this->getMorphClass() === \App\Models\GithubApp::class) {
return 'github';
}
},
);
}
}