Added Contabo starter

This commit is contained in:
DeathbotGaming 2024-03-31 10:03:34 -08:00
commit da359a606a
11 changed files with 780 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
.vscode/sftp.json

170
ContaboAPI.php Normal file
View file

@ -0,0 +1,170 @@
<?php
namespace App\Services\Contabo;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;
class ContaboAPI
{
/**
* Init connection with API
*/
public function api($method, $endpoint, $data = [])
{
$authenticate = Http::asForm()->post('https://auth.contabo.com/auth/realms/contabo/protocol/openid-connect/token', [
'client_id' => settings('contabo::client_id'),
'client_secret' => settings('encrypted::contabo::client_secret'),
'username' => settings('contabo::username'),
'password' => settings('encrypted::contabo::user_password'),
'grant_type' => 'password',
]);
if($authenticate->failed())
{
if($authenticate->unauthorized() OR $authenticate->forbidden()) {
throw new \Exception("[Contabo] This action is unauthorized! Confirm that the config is setup correctly");
}
// dd($authenticate);
if($authenticate->serverError()) {
throw new \Exception("[Contabo] Internal Server Error: {$authenticate->status()}");
}
throw new \Exception("[Contabo] Failed to connect to the API! Confirm that the config is setup correctly");
}
if(!isset($authenticate['access_token'])) {
throw new \Exception("[Contabo] Access token was not returned from the Contabo API.");
}
$accessToken = $authenticate['access_token'];
$response = Http::withHeaders([
'Authorization' => 'Bearer ' . $accessToken,
'x-request-id' => (string) Str::uuid(),
])->$method("https://api.contabo.com/v1{$endpoint}", $data);
if($response->failed())
{
if($response->unauthorized() OR $response->forbidden()) {
throw new \Exception("[Contabo] This action is unauthorized! Confirm that the config is setup correctly");
}
// dd($response);
if($response->serverError()) {
throw new \Exception("[Contabo] Internal Server Error: {$response->status()}");
}
throw new \Exception("[Contabo] Failed to connect to the API! Confirm that the config is setup correctly");
}
return $response;
}
/**
* Get the available images as a Laravel collection
*/
public function getImages()
{
return $this->api('get', '/compute/images', [
'size' => 100,
])->collect();
}
/**
* List all available servers
*/
public function getServers()
{
return $this->api('get', '/compute/instances', [
'size' => 100,
])->collect();
}
/**
* Create a new server
*/
public function createServer($data)
{
return $this->api('post', "/compute/instances", [
'displayName' => $data['display_name'],
'imageId' => $data['image'],
'productId' => $data['product'],
'region' => $data['region'],
'period' => $data['period'],
])->collect();
}
/**
* Get a server from ID
*/
public function getServer($serverID)
{
return $this->api('get', "/compute/instances/{$serverID}")->collect();
}
/**
* Get a server servers logs from ID
*/
public function getServerLogs($serverID)
{
return $this->api('get', "/compute/instances/actions/audits", [
'instanceId' => $serverID,
])->collect();
}
/**
* cancel a server from ID
*/
public function cancelServer($serverID): void
{
try {
$this->api('post', "/compute/instances/{$serverID}/cancel")->collect();
} catch (\Exception $e) {
ErrorLog("contabo::cancel::server::{$serverID}", $e->getMessage(), 'CRITICAL');
}
}
/**
* start a server from ID
*/
public function startServer($serverID)
{
return $this->api('post', "/compute/instances/{$serverID}/actions/start")->collect();
}
/**
* stop a server from ID
*/
public function stopServer($serverID)
{
return $this->api('post', "/compute/instances/{$serverID}/actions/stop")->collect();
}
/**
* shutdown a server from ID
*/
public function shutdownServer($serverID)
{
return $this->api('post', "/compute/instances/{$serverID}/actions/shutdown")->collect();
}
/**
* enable rescue mode for a server from ID
*/
public function enableRescueMode($serverID)
{
return $this->api('post', "/compute/instances/{$serverID}/actions/rescue")->collect();
}
/**
* reset password for a server from ID
*/
public function resetPassword($serverID, $password)
{
return $this->api('post', "/compute/instances/{$serverID}/actions/resetPassword", [
'rootPassword' => $password,
])->collect();
}
}

0
Providers/.gitkeep Normal file
View file

View file

@ -0,0 +1,172 @@
<?php
namespace App\Services\Contabo\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Database\Eloquent\Factory;
class ContaboServiceProvider extends ServiceProvider
{
/**
* @var string $moduleName
*/
protected $moduleName = 'Contabo';
/**
* @var string $moduleNameLower
*/
protected $moduleNameLower = 'contabo';
/**
* Register config (Config/config.php)
*
* @return bool
*/
protected $config = false;
/**
* Register commands (Console/)
*
* @return bool
*/
protected $commands = false;
/**
* Register migrations (Database/Migrations)
*
* @return bool
*/
protected $migrations = false;
/**
* Register routes (Routes)
*
* @return bool
*/
protected $routes = false;
/**
* Register views (Resources/views)
*
* @return bool
*/
protected $views = false;
/**
* Register language (Resources/lang)
*
* @return bool
*/
protected $languages = false;
/**
* Boot the application events.
*
* @return void
*/
public function boot()
{
if ($this->config) {
$this->registerConfig();
}
if ($this->views) {
$this->registerViews();
}
if ($this->migrations) {
$this->loadMigrationsFrom(module_path($this->moduleName, 'Database/Migrations'));
}
$this->registerTranslations();
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
if ($this->routes) {
$this->app->register(RouteServiceProvider::class);
}
}
/**
* Register config.
*
* @return void
*/
protected function registerConfig()
{
$this->publishes([
module_path($this->moduleName, 'Config/config.php') => config_path($this->moduleNameLower . '.php'),
], 'config');
$this->mergeConfigFrom(
module_path($this->moduleName, 'Config/config.php'), $this->moduleNameLower
);
}
/**
* Register views.
*
* @return void
*/
protected function registerViews()
{
$viewPath = resource_path('views/modules/' . $this->moduleNameLower);
$sourcePath = module_path($this->moduleName, 'Resources/views');
$this->publishes([
$sourcePath => $viewPath
], ['views', $this->moduleNameLower . '-module-views']);
$this->loadViewsFrom(array_merge($this->getPublishableViewPaths(), [$sourcePath]), $this->moduleNameLower);
}
/**
* Register translations.
*
* @return void
*/
protected function registerTranslations()
{
$langPath = resource_path('lang/modules/' . $this->moduleNameLower);
if (is_dir($langPath)) {
$this->loadTranslationsFrom($langPath, $this->moduleNameLower);
$this->loadJsonTranslationsFrom($langPath, $this->moduleNameLower);
} else {
$this->loadTranslationsFrom(module_path($this->moduleName, 'Resources/lang'), $this->moduleNameLower);
$this->loadJsonTranslationsFrom(module_path($this->moduleName, 'Resources/lang'), $this->moduleNameLower);
}
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return [];
}
/**
* Retrieve paths where views are published.
*
* @return array
*/
private function getPublishableViewPaths(): array
{
$paths = [];
foreach (\Config::get('view.paths') as $path) {
if (is_dir($path . '/modules/' . $this->moduleNameLower)) {
$paths[] = $path . '/modules/' . $this->moduleNameLower;
}
}
return $paths;
}
}

View file

@ -0,0 +1,86 @@
<?php
namespace App\Services\Contabo\Providers;
use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
class RouteServiceProvider extends ServiceProvider
{
/**
* The module namespace to assume when generating URLs to actions.
*
* @var string
*/
protected $moduleNamespace = 'App\Services\Contabo\Http\Controllers';
/**
* Called before routes are registered.
*
* Register any model bindings or pattern based filters.
*
* @return void
*/
public function boot()
{
parent::boot();
}
/**
* Define the routes for the application.
*
* @return void
*/
public function map()
{
$this->mapApiRoutes();
$this->mapWebRoutes();
$this->mapAdminRoutes();
}
/**
* Define the "web" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
*
* @return void
*/
protected function mapWebRoutes()
{
Route::middleware('web')
->namespace($this->moduleNamespace)
->group(module_path('contabo', '/Routes/web.php'));
}
/**
* Define the "admin" routes for the application.
*
* These routes all receive admin level permission status
*
* @return void
*/
protected function mapAdminRoutes()
{
Route::middleware('web', 'admin', 'permission')
->namespace($this->moduleNamespace)
->prefix('admin/contabo')
->group(module_path('contabo', '/Routes/admin.php'));
}
/**
* Define the "api" routes for the application.
*
* These routes are typically stateless.
*
* @return void
*/
protected function mapApiRoutes()
{
Route::prefix('api')
->middleware('api')
->namespace($this->moduleNamespace)
->group(module_path('contabo', '/Routes/api.php'));
}
}

2
README.md Normal file
View file

@ -0,0 +1,2 @@
# service-contabo
Resell virtual contabo servers

288
Service.php Normal file
View file

@ -0,0 +1,288 @@
<?php
namespace App\Services\Contabo;
use App\Services\ServiceInterface;
use App\Models\Package;
use App\Models\Order;
class Service implements ServiceInterface
{
/**
* Unique key used to store settings
* for this service.
*
* @return string
*/
public static $key = 'contabo';
public function __construct(Order $order)
{
$this->order = $order;
}
/**
* Returns the meta data about this Server/Service
*
* @return object
*/
public static function metaData(): object
{
return (object)
[
'display_name' => 'Contabo',
'author' => 'WemX',
'version' => '1.0.0',
'wemx_version' => ['dev', '>=1.8.0'],
];
}
/**
* Define the default configuration values required to setup this service
* i.e host, api key, or other values. Use Laravel validation rules for
*
* Laravel validation rules: https://laravel.com/docs/10.x/validation
*
* @return array
*/
public static function setConfig(): array
{
return [
[
"key" => "contabo::client_id",
"name" => "Client ID",
"description" => "ClientId of your contabo account",
"type" => "text",
"rules" => ['required'], // laravel validation rules
],
[
"key" => "encrypted::contabo::client_secret",
"name" => "Client Secret",
"description" => "Client Secret of your contabo account",
"type" => "password",
"rules" => ['required'], // laravel validation rules
],
[
"key" => "contabo::username",
"name" => "Contabo Username",
"description" => "Username of your contabo account",
"type" => "email",
"rules" => ['required', 'email'], // laravel validation rules
],
[
"key" => "encrypted::contabo::user_password",
"name" => "Contabo Account Password",
"description" => "Password of your contabo account",
"type" => "password",
"rules" => ['required'], // laravel validation rules
],
];
}
/**
* Define the default package configuration values required when creatig
* new packages. i.e maximum ram usage, allowed databases and backups etc.
*
* Laravel validation rules: https://laravel.com/docs/10.x/validation
*
* @return array
*/
public static function setPackageConfig(Package $package): array
{
return [
[
"col" => "col-12",
"key" => "product",
"name" => "Product ID",
"description" => "ID of the contabo product",
"type" => "select",
"options" => [
'V1' => 'VPS S SSD (200 GB SSD)',
'V35' => 'VPS S Storage (400 GB SSD)',
'V12' => 'VPS S NVMe (50 GB NVMe)',
'V2' => 'VPS M SSD (400 GB SSD)',
'V36' => 'VPS M Storage (800 GB SSD)',
'V13' => 'VPS M NVMe (100 GB NVMe)',
'V3' => 'VPS L SSD (800 GB SSD)',
'V37' => 'VPS L Storage (1600 GB SSD)',
'V14' => 'VPS L NVMe (200 GB NVMe)',
'V4' => 'VPS XL SSD (1600 GB SSD)',
'V38' => 'VPS XL Storage (3200 GB SSD)',
'V15' => 'VPS XL NVMe (400 GB NVMe)',
'V42' => 'VPS XXXL SSD (2400 GB SSD)',
'V44' => 'VPS XXXL Storage (4800 GB SSD)',
'V43' => 'VPS XXXL NVMe (600 GB NVMe)',
'V45' => 'VPS 1 SSD (400 GB SSD)',
'V46' => 'VPS 1 NVMe (100 GB NVMe)',
'V48' => 'VPS 2 SSD (400 GB SSD)',
'V49' => 'VPS 2 NVMe (200 GB NVMe)',
'V51' => 'VPS 3 SSD (1200 GB SSD)',
'V52' => 'VPS 3 NVMe (300 GB NVMe)',
'V54' => 'VPS 4 SSD (1600 GB SSD)',
'V55' => 'VPS 4 NVMe (400 GB NVMe)',
'V57' => 'VPS 5 SSD (2000 GB SSD)',
'V58' => 'VPS 5 NVMe (500 GB NVMe)',
'V60' => 'VPS 6 SSD (2400 GB SSD)',
'V61' => 'VPS 6 NVMe (600 GB NVMe)',
'V8' => 'VDS S (180 GB NVMe)',
'V9' => 'VDS M (240 GB NVMe)',
'V10' => 'VDS L (360 GB NVMe)',
'V11' => 'VDS XL (480 GB NVMe)',
'V16' => 'VDS XXL (720 GB NVMe)',
],
"default_value" => "V1",
"rules" => ['required'],
],
[
"col" => "col-12",
"key" => "region[]",
"name" => "Allowed Regions",
"description" => "Allowed regions for this package at checkout by the user",
"type" => "select",
"options" => [
'EU' => 'Germany (Europe)',
'UK' => 'United Kingdom (Europe)',
'US-central' => 'United States (Central)',
'US-east' => 'United States (East)',
'US-west' => 'United States (West)',
'SIN' => 'Singapore (Asia)',
'AUS' => 'Australia (Oceania)',
'JPN' => 'Japan (Asia)',
],
"multiple" => true,
"default_value" => "EU",
"rules" => ['required'],
],
];
}
/**
* Define the checkout config that is required at checkout and is fillable by
* the client. Its important to properly sanatize all inputted data with rules
*
* Laravel validation rules: https://laravel.com/docs/10.x/validation
*
* @return array
*/
public static function setCheckoutConfig(Package $package): array
{
return
[
// TO DO: Load the regions from the package config
[
"key" => "region",
"name" => "Region",
"description" => "Select the region for your server",
"type" => "select",
"options" => [
'EU' => 'Germany (Europe)',
'UK' => 'United Kingdom (Europe)',
'US-central' => 'United States (Central)',
'US-east' => 'United States (East)',
'US-west' => 'United States (West)',
'SIN' => 'Singapore (Asia)',
'AUS' => 'Australia (Oceania)',
'JPN' => 'Japan (Asia)',
],
"default_value" => "EU",
"rules" => ['required'],
],
// To Do: load OS types / images from API
[
"key" => "image",
"name" => "Image",
"description" => "Select the image for your server",
"type" => "select",
"options" => [
'04e0f898-37b4-48bc-a794-1a57abe6aa31' => 'Ubuntu 20.04',
],
"default_value" => "04e0f898-37b4-48bc-a794-1a57abe6aa31",
"rules" => ['required'],
],
];
}
/**
* Test API connection
*/
public static function testConnection()
{
try {
contabo()->getServers();
} catch(\Exception $error) {
return redirect()->back()->withError("Failed to connect to Contabo. <br><br>{$error->getMessage()}");
}
return redirect()->back()->withSuccess("Successfully connected with Contabo API");
}
/**
* Define buttons shown at order management page
*
* @return array
*/
public static function setServiceButtons(Order $order): array
{
return [];
}
/**
* This function is responsible for creating an instance of the
* service. This can be anything such as a server, vps or any other instance.
*
* @return void
*/
public function create(array $data = [])
{
return [];
}
/**
* This function is responsible for upgrading or downgrading
* an instance of this service. This method is optional
* If your service doesn't support upgrading, remove this method.
*
* Optional
* @return void
*/
public function upgrade(Package $oldPackage, Package $newPackage)
{
return [];
}
/**
* This function is responsible for suspending an instance of the
* service. This method is called when a order is expired or
* suspended by an admin
*
* @return void
*/
public function suspend(array $data = [])
{
return [];
}
/**
* This function is responsible for unsuspending an instance of the
* service. This method is called when a order is activated or
* unsuspended by an admin
*
* @return void
*/
public function unsuspend(array $data = [])
{
return [];
}
/**
* This function is responsible for deleting an instance of the
* service. This can be anything such as a server, vps or any other instance.
*
* @return void
*/
public function terminate(array $data = [])
{
return [];
}
}

25
composer.json Normal file
View file

@ -0,0 +1,25 @@
{
"name": "wemx/service-contabo",
"type": "laravel-module",
"description": "A contabo service for developers",
"authors": [
{
"name": "WemX",
"email": "mubeen@wemx.net"
}
],
"extra": {
"module-dir": "app/Services",
"laravel": {
"providers": [],
"aliases": {
}
}
},
"autoload": {
"psr-4": {
"App\\Services\\Contabo\\": ""
}
}
}

8
helpers.php Normal file
View file

@ -0,0 +1,8 @@
<?php
if (!function_exists('contabo')) {
function contabo()
{
return new App\Services\Contabo\ContaboAPI();
}
}

11
module.json Normal file
View file

@ -0,0 +1,11 @@
{
"name": "Contabo",
"alias": "contabo",
"description": "",
"keywords": [],
"priority": 0,
"providers": [
"App\\Services\\Contabo\\Providers\\ContaboServiceProvider"
],
"files": ["helpers.php"]
}

16
package.json Normal file
View file

@ -0,0 +1,16 @@
{
"private": true,
"scripts": {
"dev": "vite",
"build": "vite build"
},
"devDependencies": {
"axios": "^0.21.4",
"dotenv": "^10.0.0",
"dotenv-expand": "^5.1.0",
"laravel-vite-plugin": "^0.6.0",
"lodash": "^4.17.21",
"postcss": "^8.3.7",
"vite": "^3.0.9"
}
}