diff --git a/app/Enums/FirewallRuleStatus.php b/app/Enums/FirewallRuleStatus.php index fbda689..34e1775 100644 --- a/app/Enums/FirewallRuleStatus.php +++ b/app/Enums/FirewallRuleStatus.php @@ -11,4 +11,5 @@ enum FirewallRuleStatus: string case NOT_APPLIED = 'not-applied'; case APPLIED = 'applied'; case FAILED = 'failed'; + case REMOVED = 'removed'; } \ No newline at end of file diff --git a/app/Enums/ServiceCategory.php b/app/Enums/ServiceCategory.php index f846208..7e71e3b 100644 --- a/app/Enums/ServiceCategory.php +++ b/app/Enums/ServiceCategory.php @@ -24,7 +24,7 @@ enum ServiceCategory: string return match ($category) { self::APPLICATION => 'The base container image for your application', self::DATABASE => 'Postgres or MySQL', - self::GATEWAY => 'The gateway is the first point of contact for your application', + self::GATEWAY => 'The first point of contact for your application', self::STORAGE => 'S3 or S3-compatible service', self::CACHE => 'Redis, Memcached or similar', }; diff --git a/app/Models/FirewallRule.php b/app/Models/FirewallRule.php index 2426d19..96c2742 100644 --- a/app/Models/FirewallRule.php +++ b/app/Models/FirewallRule.php @@ -15,7 +15,7 @@ class FirewallRule extends Model parent::boot(); static::created(function (self $firewallRule) { - $firewallRule->execute(); + $firewallRule->install(); }); } @@ -31,7 +31,7 @@ class FirewallRule extends Model return $this->belongsTo(Server::class); } - public function execute(): void + public function install(): void { $ssh = $this->server->sshClient(); @@ -62,4 +62,36 @@ class FirewallRule extends Model 'status' => FirewallRuleStatus::APPLIED, ]); } + + public function remove(): void + { + $ssh = $this->server->sshClient(); + + $command = "ufw"; + + if ($this->type === 'allow') { + $command .= " delete allow"; + } elseif ($this->type === 'deny') { + $command .= " delete deny"; + } + + if ($this->from) { + $command .= " from {$this->from}"; + $command .= " to any port"; + } + + $command .= " {$this->ports}"; + + $result = $ssh->execute($command); + + if (! $result->isSuccessful()) { + $this->update([ + 'status' => FirewallRuleStatus::FAILED, + ]); + return; + } + $this->update([ + 'status' => FirewallRuleStatus::REMOVED, + ]); + } } diff --git a/resources/js/enums/DeploymentStatus.js b/resources/js/enums/DeploymentStatus.js index 8476012..87a392d 100644 --- a/resources/js/enums/DeploymentStatus.js +++ b/resources/js/enums/DeploymentStatus.js @@ -1,5 +1,5 @@ // This is a generated file. -// Published at 2025-04-01 16:27:12 +// Published at 2025-04-06 16:01:50 export default { "PENDING": "pending", diff --git a/resources/js/enums/FirewallRuleStatus.js b/resources/js/enums/FirewallRuleStatus.js index 9147c14..1017eb8 100644 --- a/resources/js/enums/FirewallRuleStatus.js +++ b/resources/js/enums/FirewallRuleStatus.js @@ -1,5 +1,5 @@ // This is a generated file. -// Published at 2025-04-01 16:27:12 +// Published at 2025-04-06 16:01:50 export default { "NOT_APPLIED": "not-applied", diff --git a/resources/js/enums/OrganisationRole.js b/resources/js/enums/OrganisationRole.js index 1e14361..9235a23 100644 --- a/resources/js/enums/OrganisationRole.js +++ b/resources/js/enums/OrganisationRole.js @@ -1,5 +1,5 @@ // This is a generated file. -// Published at 2025-04-01 16:27:12 +// Published at 2025-04-06 16:01:50 export default { "ADMIN": "admin", diff --git a/resources/js/enums/RepositoryType.js b/resources/js/enums/RepositoryType.js index 6ed3b2a..8610d49 100644 --- a/resources/js/enums/RepositoryType.js +++ b/resources/js/enums/RepositoryType.js @@ -1,5 +1,5 @@ // This is a generated file. -// Published at 2025-04-01 16:27:12 +// Published at 2025-04-06 16:01:50 export default { "GIT": "git" diff --git a/resources/js/enums/ServerProvider.js b/resources/js/enums/ServerProvider.js index 6bdc42a..9673fdc 100644 --- a/resources/js/enums/ServerProvider.js +++ b/resources/js/enums/ServerProvider.js @@ -1,5 +1,5 @@ // This is a generated file. -// Published at 2025-04-01 16:27:12 +// Published at 2025-04-06 16:01:50 export default { "HETZNER": "hetzner", diff --git a/resources/js/enums/ServerStatus.js b/resources/js/enums/ServerStatus.js index 37c27d1..c9a1404 100644 --- a/resources/js/enums/ServerStatus.js +++ b/resources/js/enums/ServerStatus.js @@ -1,5 +1,5 @@ // This is a generated file. -// Published at 2025-04-01 16:27:12 +// Published at 2025-04-06 16:01:50 export default { "WAITING_FOR_PROVIDER": "waiting-for-provider", diff --git a/resources/js/enums/ServiceCategory.js b/resources/js/enums/ServiceCategory.js index 2cf8754..9beaa70 100644 --- a/resources/js/enums/ServiceCategory.js +++ b/resources/js/enums/ServiceCategory.js @@ -1,5 +1,5 @@ // This is a generated file. -// Published at 2025-04-01 16:27:12 +// Published at 2025-04-06 16:01:50 export default { "DATABASE": "database", @@ -12,7 +12,7 @@ export default { export const DescriptionMap = { "DATABASE": "Postgres or MySQL", "APPLICATION": "The base container image for your application", - "GATEWAY": "The gateway is the first point of contact for your application", + "GATEWAY": "The first point of contact for your application", "STORAGE": "S3 or S3-compatible service", "CACHE": "Redis, Memcached or similar" } diff --git a/resources/js/enums/ServiceStatus.js b/resources/js/enums/ServiceStatus.js index fb09c1d..f16d057 100644 --- a/resources/js/enums/ServiceStatus.js +++ b/resources/js/enums/ServiceStatus.js @@ -1,5 +1,5 @@ // This is a generated file. -// Published at 2025-04-01 16:27:12 +// Published at 2025-04-06 16:01:50 export default { "NOT_INSTALLED": "not-installed", diff --git a/resources/js/enums/ServiceType.js b/resources/js/enums/ServiceType.js index 67b1ead..72dc399 100644 --- a/resources/js/enums/ServiceType.js +++ b/resources/js/enums/ServiceType.js @@ -1,5 +1,5 @@ // This is a generated file. -// Published at 2025-04-01 16:27:12 +// Published at 2025-04-06 16:01:50 export default { "FRANKENPHP": "frankenphp", diff --git a/resources/js/pages/services/Create.vue b/resources/js/pages/services/Create.vue index fa27daa..b67929d 100644 --- a/resources/js/pages/services/Create.vue +++ b/resources/js/pages/services/Create.vue @@ -7,6 +7,7 @@ import { Input } from '@/components/ui/input'; import InputError from '@/components/InputError.vue'; import ServiceCategory, { DescriptionMap as serviceCategoryDescriptions } from '@/enums/ServiceCategory'; import RadioButton from '@/components/RadioButton.vue'; +import { AppWindowIcon, ArchiveIcon, DatabaseIcon, DatabaseZapIcon, DoorOpenIcon } from 'lucide-vue-next'; const props = defineProps({}); @@ -15,6 +16,23 @@ const form = useForm({ category: null, type: null, }); + +function getIcon(category) { + switch (category) { + case ServiceCategory.DATABASE: + return DatabaseIcon; + case ServiceCategory.CACHE: + return DatabaseZapIcon; + case ServiceCategory.APPLICATION: + return AppWindowIcon; + case ServiceCategory.GATEWAY: + return DoorOpenIcon; + case ServiceCategory.STORAGE: + return ArchiveIcon; + default: + return null; + } +}