Files
coolify/app/Livewire/Project/Application/Source.php
T

240 lines
8.5 KiB
PHP

<?php
namespace App\Livewire\Project\Application;
use App\Models\Application;
use App\Models\GiteaApp;
use App\Models\GithubApp;
use App\Models\GitlabApp;
use App\Models\PrivateKey;
use App\Rules\ValidGitBranch;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Validation\ValidationException;
use Livewire\Attributes\Locked;
use Livewire\Attributes\Validate;
use Livewire\Component;
class Source extends Component
{
use AuthorizesRequests;
public Application $application;
#[Locked]
public $privateKeys;
#[Validate(['nullable', 'string'])]
public ?string $privateKeyName = null;
#[Locked]
public ?int $privateKeyId = null;
#[Validate(['required', 'string'])]
public string $gitRepository;
#[Validate(['required', 'string', new ValidGitBranch])]
public string $gitBranch;
#[Validate(['nullable', 'string', 'regex:/^[a-zA-Z0-9][a-zA-Z0-9._\-\/]*$/'])]
public ?string $gitCommitSha = null;
#[Locked]
public $sources;
#[Validate(['nullable', 'string', 'max:255', 'regex:/^[^:\r\n]*$/'])]
public ?string $gitHttpsUsername = null;
/**
* Write-only: the saved password or token is never sent to the browser.
*/
#[Validate(['nullable', 'string', 'max:2048', 'regex:/^[^\r\n]*$/'])]
public ?string $gitHttpsPassword = null;
#[Locked]
public bool $hasGitHttpsPassword = false;
public function mount()
{
try {
$this->syncData();
$this->getPrivateKeys();
$this->getSources();
} catch (\Throwable $e) {
handleError($e, $this);
}
}
public function updatedGitRepository()
{
$this->gitRepository = trim($this->gitRepository);
}
public function updatedGitBranch()
{
$this->gitBranch = trim($this->gitBranch);
}
public function updatedGitCommitSha()
{
$this->gitCommitSha = trim($this->gitCommitSha);
}
private function syncData(bool $toModel = false): void
{
if ($toModel) {
$this->validate();
$this->application->fill([
'git_repository' => $this->gitRepository,
'git_branch' => $this->gitBranch,
'git_commit_sha' => $this->gitCommitSha,
'private_key_id' => $this->privateKeyId,
]);
if (filled($this->gitHttpsPassword)) {
$this->application->git_https_username = $this->gitHttpsUsername;
$this->application->git_https_password = $this->gitHttpsPassword;
} elseif ($this->hasGitHttpsPassword) {
$this->application->git_https_username = $this->gitHttpsUsername;
}
$this->application->save();
// Refresh to get the trimmed values from the model
$this->application->refresh();
$this->syncData(false);
} else {
$this->gitRepository = $this->application->git_repository;
$this->gitBranch = $this->application->git_branch;
$this->gitCommitSha = $this->application->git_commit_sha;
$this->privateKeyId = $this->application->private_key_id;
$this->privateKeyName = data_get($this->application, 'private_key.name');
$this->gitHttpsUsername = $this->application->git_https_username;
$this->gitHttpsPassword = null;
$this->hasGitHttpsPassword = filled($this->application->git_https_password);
}
}
private function getPrivateKeys()
{
$this->privateKeys = PrivateKey::where('team_id', $this->application->team()->id)->get()->reject(function ($key) {
return $key->id == $this->privateKeyId;
});
}
private function getSources()
{
$this->sources = $this->application->team()->sources()->filter(function ($source) {
if ($source->id === $this->application->source_id
&& $source->getMorphClass() === $this->application->source_type) {
return false;
}
if ($source instanceof GithubApp) {
return ! is_null($source->app_id);
}
if ($source instanceof GitlabApp || $source instanceof GiteaApp) {
return $source->isConnected();
}
return true;
})->sortBy('name');
}
public function setPrivateKey(int $privateKeyId)
{
try {
$this->authorize('update', $this->application);
$key = PrivateKey::where('team_id', $this->application->team()->id)->findOrFail($privateKeyId);
$this->privateKeyId = $key->id;
$this->syncData(true);
$this->getPrivateKeys();
$this->application->refresh();
$this->privateKeyName = $this->application->private_key->name;
$this->dispatch('success', 'Private key updated!');
$this->dispatch('configurationChanged');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function submit()
{
try {
$this->authorize('update', $this->application);
if (str($this->gitCommitSha)->isEmpty()) {
$this->gitCommitSha = 'HEAD';
}
if (filled($this->gitHttpsUsername) && blank($this->gitHttpsPassword) && ! $this->hasGitHttpsPassword) {
throw ValidationException::withMessages(['gitHttpsPassword' => 'Enter the password or token for this username.']);
}
$this->syncData(true);
$this->dispatch('success', 'Application source updated!');
$this->dispatch('configurationChanged');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function removeGitHttpsCredential()
{
try {
$this->authorize('update', $this->application);
$this->application->forceFill([
'git_https_username' => null,
'git_https_password' => null,
])->save();
$this->syncData();
$this->dispatch('success', 'HTTPS credentials removed.');
$this->dispatch('configurationChanged');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function changeSource($sourceId, $sourceType)
{
try {
$this->authorize('update', $this->application);
$allowedSourceTypes = [GithubApp::class, GitlabApp::class, GiteaApp::class];
abort_unless(in_array($sourceType, $allowedSourceTypes, true), 404);
$teamId = $this->application->team()->id;
$source = $sourceType::query()
->where(fn ($query) => $query->where('team_id', $teamId)->orWhere('is_system_wide', true))
->findOrFail($sourceId);
$this->application->update([
'source_id' => $source->id,
'source_type' => $sourceType,
]);
$this->dispatch('configurationChanged');
['repository' => $customRepository] = $this->application->customRepository();
$repository_project_id = null;
if ($sourceType === GithubApp::class) {
$repository = githubApi($source, "repos/{$customRepository}");
$repository_project_id = data_get($repository, 'data.id');
} elseif ($sourceType === GitlabApp::class) {
if ($source->isConnected()) {
$encoded = urlencode($customRepository);
$project = gitlabApi($source, "/projects/{$encoded}");
$repository_project_id = data_get($project, 'data.id');
}
} elseif ($sourceType === GiteaApp::class) {
if ($source->isConnected()) {
$repositoryPath = collect(explode('/', $customRepository, 2))->map(fn ($part) => rawurlencode($part))->implode('/');
$repository = giteaApi($source, "/repos/{$repositoryPath}");
$repository_project_id = data_get($repository, 'data.id');
}
}
if (isset($repository_project_id) && $this->application->repository_project_id !== $repository_project_id) {
$this->application->repository_project_id = $repository_project_id;
$this->application->save();
}
$this->application->refresh();
$this->getSources();
$this->dispatch('success', 'Source updated!');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
}