Merge branch 'development' into main

This commit is contained in:
Dennis 2023-04-25 09:15:46 +02:00 committed by GitHub
commit 3810b487cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
171 changed files with 7472 additions and 5023 deletions

View file

@ -62,3 +62,6 @@ PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
# Settings Cache
SETTINGS_CACHE_ENABLED=true

View file

@ -2,46 +2,68 @@
namespace App\Classes;
use App\Models\Egg;
use App\Models\Nest;
use App\Models\Node;
use App\Models\Pterodactyl\Egg;
use App\Models\Pterodactyl\Nest;
use App\Models\Pterodactyl\Node;
use App\Models\Product;
use App\Models\Server;
use App\Models\User;
use Exception;
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Http\Client\Response;
use Illuminate\Support\Facades\Http;
use App\Settings\PterodactylSettings;
use App\Settings\ServerSettings;
class Pterodactyl
class PterodactylClient
{
//TODO: Extend error handling (maybe logger for more errors when debugging)
private int $per_page_limit = 200;
private int $allocation_limit = 200;
public PendingRequest $client;
public PendingRequest $application;
public function __construct(PterodactylSettings $ptero_settings)
{
$server_settings = new ServerSettings();
try {
$this->client = $this->client($ptero_settings);
$this->application = $this->clientAdmin($ptero_settings);
$this->per_page_limit = $ptero_settings->per_page_limit;
$this->allocation_limit = $server_settings->allocation_limit;
} catch (Exception $exception) {
logger('Failed to construct Pterodactyl client, Settings table not available?', ['exception' => $exception]);
}
}
/**
* @return PendingRequest
*/
public static function client()
public function client(PterodactylSettings $ptero_settings)
{
return Http::withHeaders([
'Authorization' => 'Bearer ' . config('SETTINGS::SYSTEM:PTERODACTYL:TOKEN'),
'Authorization' => 'Bearer ' . $ptero_settings->user_token,
'Content-type' => 'application/json',
'Accept' => 'Application/vnd.pterodactyl.v1+json',
])->baseUrl(config('SETTINGS::SYSTEM:PTERODACTYL:URL') . '/api');
])->baseUrl($ptero_settings->getUrl() . 'api' . '/');
}
public static function clientAdmin()
public function clientAdmin(PterodactylSettings $ptero_settings)
{
return Http::withHeaders([
'Authorization' => 'Bearer ' . config('SETTINGS::SYSTEM:PTERODACTYL:ADMIN_USER_TOKEN'),
'Authorization' => 'Bearer ' . $ptero_settings->admin_token,
'Content-type' => 'application/json',
'Accept' => 'Application/vnd.pterodactyl.v1+json',
])->baseUrl(config('SETTINGS::SYSTEM:PTERODACTYL:URL') . '/api');
])->baseUrl($ptero_settings->getUrl() . 'api' . '/');
}
/**
* @return Exception
*/
private static function getException(string $message = '', int $status = 0): Exception
private function getException(string $message = '', int $status = 0): Exception
{
if ($status == 404) {
return new Exception('Ressource does not exist on pterodactyl - ' . $message, 404);
@ -68,10 +90,10 @@ class Pterodactyl
*
* @throws Exception
*/
public static function getEggs(Nest $nest)
public function getEggs(Nest $nest)
{
try {
$response = self::client()->get("/application/nests/{$nest->id}/eggs?include=nest,variables&per_page=" . config('SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT'));
$response = $this->application->get("application/nests/{$nest->id}/eggs?include=nest,variables&per_page=" . $this->per_page_limit);
} catch (Exception $e) {
throw self::getException($e->getMessage());
}
@ -87,10 +109,10 @@ class Pterodactyl
*
* @throws Exception
*/
public static function getNodes()
public function getNodes()
{
try {
$response = self::client()->get('/application/nodes?per_page=' . config('SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT'));
$response = $this->application->get('application/nodes?per_page=' . $this->per_page_limit);
} catch (Exception $e) {
throw self::getException($e->getMessage());
}
@ -107,10 +129,10 @@ class Pterodactyl
* @throws Exception
* @description Returns the infos of a single node
*/
public static function getNode($id)
public function getNode($id)
{
try {
$response = self::client()->get('/application/nodes/' . $id);
$response = $this->application->get('application/nodes/' . $id);
} catch (Exception $e) {
throw self::getException($e->getMessage());
}
@ -121,10 +143,10 @@ class Pterodactyl
return $response->json()['attributes'];
}
public static function getServers()
public function getServers()
{
try {
$response = self::client()->get('/application/servers?per_page=' . config('SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT'));
$response = $this->application->get('application/servers?per_page=' . $this->per_page_limit);
} catch (Exception $e) {
throw self::getException($e->getMessage());
}
@ -140,10 +162,10 @@ class Pterodactyl
*
* @throws Exception
*/
public static function getNests()
public function getNests()
{
try {
$response = self::client()->get('/application/nests?per_page=' . config('SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT'));
$response = $this->application->get('application/nests?per_page=' . $this->per_page_limit);
} catch (Exception $e) {
throw self::getException($e->getMessage());
}
@ -159,10 +181,10 @@ class Pterodactyl
*
* @throws Exception
*/
public static function getLocations()
public function getLocations()
{
try {
$response = self::client()->get('/application/locations?per_page=' . config('SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT'));
$response = $this->application->get('application/locations?per_page=' . $this->per_page_limit);
} catch (Exception $e) {
throw self::getException($e->getMessage());
}
@ -179,7 +201,7 @@ class Pterodactyl
*
* @throws Exception
*/
public static function getFreeAllocationId(Node $node)
public function getFreeAllocationId(Node $node)
{
return self::getFreeAllocations($node)[0]['attributes']['id'] ?? null;
}
@ -190,7 +212,7 @@ class Pterodactyl
*
* @throws Exception
*/
public static function getFreeAllocations(Node $node)
public function getFreeAllocations(Node $node)
{
$response = self::getAllocations($node);
$freeAllocations = [];
@ -214,11 +236,10 @@ class Pterodactyl
*
* @throws Exception
*/
public static function getAllocations(Node $node)
public function getAllocations(Node $node)
{
$per_page = config('SETTINGS::SERVER:ALLOCATION_LIMIT', 200);
try {
$response = self::client()->get("/application/nodes/{$node->id}/allocations?per_page={$per_page}");
$response = $this->application->get("application/nodes/{$node->id}/allocations?per_page={$this->allocation_limit}");
} catch (Exception $e) {
throw self::getException($e->getMessage());
}
@ -229,24 +250,15 @@ class Pterodactyl
return $response->json();
}
/**
* @param string $route
* @return string
*/
public static function url(string $route): string
{
return config('SETTINGS::SYSTEM:PTERODACTYL:URL') . $route;
}
/**
* @param Server $server
* @param Egg $egg
* @param int $allocationId
* @return Response
*/
public static function createServer(Server $server, Egg $egg, int $allocationId)
public function createServer(Server $server, Egg $egg, int $allocationId)
{
return self::client()->post('/application/servers', [
return $this->application->post('application/servers', [
'name' => $server->name,
'external_id' => $server->id,
'user' => $server->user->pterodactyl_id,
@ -272,10 +284,10 @@ class Pterodactyl
]);
}
public static function suspendServer(Server $server)
public function suspendServer(Server $server)
{
try {
$response = self::client()->post("/application/servers/$server->pterodactyl_id/suspend");
$response = $this->application->post("application/servers/$server->pterodactyl_id/suspend");
} catch (Exception $e) {
throw self::getException($e->getMessage());
}
@ -286,10 +298,10 @@ class Pterodactyl
return $response;
}
public static function unSuspendServer(Server $server)
public function unSuspendServer(Server $server)
{
try {
$response = self::client()->post("/application/servers/$server->pterodactyl_id/unsuspend");
$response = $this->application->post("application/servers/$server->pterodactyl_id/unsuspend");
} catch (Exception $e) {
throw self::getException($e->getMessage());
}
@ -309,7 +321,7 @@ class Pterodactyl
public function getUser(int $pterodactylId)
{
try {
$response = self::client()->get("/application/users/{$pterodactylId}");
$response = $this->application->get("application/users/{$pterodactylId}");
} catch (Exception $e) {
throw self::getException($e->getMessage());
}
@ -326,10 +338,10 @@ class Pterodactyl
* @param int $pterodactylId
* @return mixed
*/
public static function getServerAttributes(int $pterodactylId, bool $deleteOn404 = false)
public function getServerAttributes(int $pterodactylId, bool $deleteOn404 = false)
{
try {
$response = self::client()->get("/application/servers/{$pterodactylId}?include=egg,node,nest,location");
$response = $this->application->get("application/servers/{$pterodactylId}?include=egg,node,nest,location");
} catch (Exception $e) {
throw self::getException($e->getMessage());
}
@ -356,9 +368,9 @@ class Pterodactyl
* @param Product $product
* @return Response
*/
public static function updateServer(Server $server, Product $product)
public function updateServer(Server $server, Product $product)
{
return self::client()->patch("/application/servers/{$server->pterodactyl_id}/build", [
return $this->application->patch("application/servers/{$server->pterodactyl_id}/build", [
'allocation' => $server->allocation,
'memory' => $product->memory,
'swap' => $product->swap,
@ -381,9 +393,9 @@ class Pterodactyl
* @param Server $server
* @return mixed
*/
public static function updateServerOwner(Server $server, int $userId)
public function updateServerOwner(Server $server, int $userId)
{
return self::client()->patch("/application/servers/{$server->pterodactyl_id}/details", [
return $this->application->patch("application/servers/{$server->pterodactyl_id}/details", [
'name' => $server->name,
'user' => $userId,
]);
@ -396,9 +408,9 @@ class Pterodactyl
* @param string $action
* @return Response
*/
public static function powerAction(Server $server, $action)
public function powerAction(Server $server, $action)
{
return self::clientAdmin()->post("/client/servers/{$server->identifier}/power", [
return $this->client->post("client/servers/{$server->identifier}/power", [
'signal' => $action,
]);
}
@ -406,9 +418,9 @@ class Pterodactyl
/**
* Get info about user
*/
public static function getClientUser()
public function getClientUser()
{
return self::clientAdmin()->get('/client/account');
return $this->client->get('client/account');
}
/**
@ -419,10 +431,10 @@ class Pterodactyl
* @param int $requireDisk
* @return bool
*/
public static function checkNodeResources(Node $node, int $requireMemory, int $requireDisk)
public function checkNodeResources(Node $node, int $requireMemory, int $requireDisk)
{
try {
$response = self::client()->get("/application/nodes/{$node->id}");
$response = $this->application->get("application/nodes/{$node->id}");
} catch (Exception $e) {
throw self::getException($e->getMessage());
}

View file

@ -1,47 +0,0 @@
<?php
namespace App\Classes\Settings;
use App\Models\Settings;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
class Invoices
{
public function __construct()
{
}
public function updateSettings(Request $request)
{
$request->validate([
'logo' => 'nullable|max:10000|mimes:jpg,png,jpeg',
]);
$values = [
//SETTINGS::VALUE => REQUEST-VALUE (coming from the html-form)
'SETTINGS::INVOICE:COMPANY_NAME' => 'company-name',
'SETTINGS::INVOICE:COMPANY_ADDRESS' => 'company-address',
'SETTINGS::INVOICE:COMPANY_PHONE' => 'company-phone',
'SETTINGS::INVOICE:COMPANY_MAIL' => 'company-mail',
'SETTINGS::INVOICE:COMPANY_VAT' => 'company-vat',
'SETTINGS::INVOICE:COMPANY_WEBSITE' => 'company-web',
'SETTINGS::INVOICE:PREFIX' => 'invoice-prefix',
'SETTINGS::INVOICE:ENABLED' => 'enable-invoices',
];
foreach ($values as $key => $value) {
$param = $request->get($value);
Settings::where('key', $key)->updateOrCreate(['key' => $key], ['value' => $param]);
Cache::forget('setting'.':'.$key);
}
if ($request->hasFile('logo')) {
$request->file('logo')->storeAs('public', 'logo.png');
}
return redirect(route('admin.settings.index').'#invoices')->with('success', __('Invoice settings updated!'));
}
}

View file

@ -1,56 +0,0 @@
<?php
namespace App\Classes\Settings;
use App\Models\Settings;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Validator;
class Language
{
public function __construct()
{
}
public function updateSettings(Request $request)
{
$validator = Validator::make($request->all(), [
'autotranslate' => 'string',
'canClientChangeLanguage' => 'string',
'defaultLanguage' => 'required|string',
'languages' => 'required|array',
'languages.*' => 'required|string',
'datatable-language' => 'required|string',
]);
if ($validator->fails()) {
return redirect(route('admin.settings.index').'#language')->with('error', __('Language settings have not been updated!'))->withErrors($validator);
}
$values = [
//SETTINGS::VALUE => REQUEST-VALUE (coming from the html-form)
'SETTINGS::LOCALE:DEFAULT' => 'defaultLanguage',
'SETTINGS::LOCALE:DYNAMIC' => 'autotranslate',
'SETTINGS::LOCALE:CLIENTS_CAN_CHANGE' => 'canClientChangeLanguage',
'SETTINGS::LOCALE:AVAILABLE' => 'languages',
'SETTINGS::LOCALE:DATATABLES' => 'datatable-language',
];
foreach ($values as $key => $value) {
$param = $request->get($value);
if (is_array($param)) {
$param = implode(',', $param);
}
Settings::where('key', $key)->updateOrCreate(['key' => $key], ['value' => $param]);
Cache::forget('setting'.':'.$key);
Session::remove('locale');
}
return redirect(route('admin.settings.index').'#language')->with('success', __('Language settings updated!'));
}
}

View file

@ -1,107 +0,0 @@
<?php
namespace App\Classes\Settings;
use App\Models\Settings;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Validator;
class Misc
{
public function __construct()
{
}
public function updateSettings(Request $request)
{
$validator = Validator::make($request->all(), [
'icon' => 'nullable|max:10000|mimes:jpg,png,jpeg',
'favicon' => 'nullable|max:10000|mimes:ico',
'discord-bot-token' => 'nullable|string',
'discord-client-id' => 'nullable|string',
'discord-client-secret' => 'nullable|string',
'discord-guild-id' => 'nullable|string',
'discord-invite-url' => 'nullable|string',
'discord-role-id' => 'nullable|string',
'recaptcha-site-key' => 'nullable|string',
'recaptcha-secret-key' => 'nullable|string',
'enable-recaptcha' => 'nullable|string',
'mailservice' => 'nullable|string',
'mailhost' => 'nullable|string',
'mailport' => 'nullable|string',
'mailusername' => 'nullable|string',
'mailpassword' => 'nullable|string',
'mailencryption' => 'nullable|string',
'mailfromadress' => 'nullable|string',
'mailfromname' => 'nullable|string',
'enable_referral' => 'nullable|string',
'referral_reward' => 'nullable|numeric',
'referral_allowed' => 'nullable|string',
'always_give_commission' => 'nullable|string',
'referral_percentage' => 'nullable|numeric',
'referral_mode' => 'nullable|string',
'ticket_enabled' => 'nullable|string',
'ticket_notify' => 'string',
]);
$validator->after(function ($validator) use ($request) {
// if enable-recaptcha is true then recaptcha-site-key and recaptcha-secret-key must be set
if ($request->get('enable-recaptcha') == 'true' && (! $request->get('recaptcha-site-key') || ! $request->get('recaptcha-secret-key'))) {
$validator->errors()->add('recaptcha-site-key', 'The site key is required if recaptcha is enabled.');
$validator->errors()->add('recaptcha-secret-key', 'The secret key is required if recaptcha is enabled.');
}
});
if ($validator->fails()) {
return redirect(route('admin.settings.index').'#misc')->with('error', __('Misc settings have not been updated!'))->withErrors($validator)
->withInput();
}
if ($request->hasFile('icon')) {
$request->file('icon')->storeAs('public', 'icon.png');
}
if ($request->hasFile('favicon')) {
$request->file('favicon')->storeAs('public', 'favicon.ico');
}
$values = [
'SETTINGS::DISCORD:BOT_TOKEN' => 'discord-bot-token',
'SETTINGS::DISCORD:CLIENT_ID' => 'discord-client-id',
'SETTINGS::DISCORD:CLIENT_SECRET' => 'discord-client-secret',
'SETTINGS::DISCORD:GUILD_ID' => 'discord-guild-id',
'SETTINGS::DISCORD:INVITE_URL' => 'discord-invite-url',
'SETTINGS::DISCORD:ROLE_ID' => 'discord-role-id',
'SETTINGS::RECAPTCHA:SITE_KEY' => 'recaptcha-site-key',
'SETTINGS::RECAPTCHA:SECRET_KEY' => 'recaptcha-secret-key',
'SETTINGS::RECAPTCHA:ENABLED' => 'enable-recaptcha',
'SETTINGS::MAIL:MAILER' => 'mailservice',
'SETTINGS::MAIL:HOST' => 'mailhost',
'SETTINGS::MAIL:PORT' => 'mailport',
'SETTINGS::MAIL:USERNAME' => 'mailusername',
'SETTINGS::MAIL:PASSWORD' => 'mailpassword',
'SETTINGS::MAIL:ENCRYPTION' => 'mailencryption',
'SETTINGS::MAIL:FROM_ADDRESS' => 'mailfromadress',
'SETTINGS::MAIL:FROM_NAME' => 'mailfromname',
'SETTINGS::REFERRAL::ENABLED' => 'enable_referral',
'SETTINGS::REFERRAL::REWARD' => 'referral_reward',
'SETTINGS::REFERRAL::ALLOWED' => 'referral_allowed',
'SETTINGS::REFERRAL:MODE' => 'referral_mode',
'SETTINGS::REFERRAL::ALWAYS_GIVE_COMMISSION' => 'always_give_commission',
'SETTINGS::REFERRAL:PERCENTAGE' => 'referral_percentage',
'SETTINGS::TICKET:ENABLED' => 'ticket_enabled',
'SETTINGS::TICKET:NOTIFY' => 'ticket_notify',
];
foreach ($values as $key => $value) {
$param = $request->get($value);
Settings::where('key', $key)->updateOrCreate(['key' => $key], ['value' => $param]);
Cache::forget('setting'.':'.$key);
}
return redirect(route('admin.settings.index').'#misc')->with('success', __('Misc settings updated!'));
}
}

View file

@ -1,58 +0,0 @@
<?php
namespace App\Classes\Settings;
use App\Models\Settings;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Validator;
class Payments
{
public function __construct()
{
}
public function updateSettings(Request $request)
{
$validator = Validator::make($request->all(), [
'paypal-client_id' => 'nullable|string',
'paypal-client-secret' => 'nullable|string',
'paypal-sandbox-secret' => 'nullable|string',
'stripe-secret-key' => 'nullable|string',
'stripe-endpoint-secret' => 'nullable|string',
'stripe-test-secret-key' => 'nullable|string',
'stripe-test-endpoint-secret' => 'nullable|string',
'stripe-methods' => 'nullable|string',
'sales-tax' => 'nullable|numeric',
]);
if ($validator->fails()) {
return redirect(route('admin.settings.index').'#payment')->with('error', __('Payment settings have not been updated!'))->withErrors($validator)
->withInput();
}
$values = [
//SETTINGS::VALUE => REQUEST-VALUE (coming from the html-form)
'SETTINGS::PAYMENTS:PAYPAL:SECRET' => 'paypal-client-secret',
'SETTINGS::PAYMENTS:PAYPAL:CLIENT_ID' => 'paypal-client-id',
'SETTINGS::PAYMENTS:PAYPAL:SANDBOX_SECRET' => 'paypal-sandbox-secret',
'SETTINGS::PAYMENTS:PAYPAL:SANDBOX_CLIENT_ID' => 'paypal-sandbox-id',
'SETTINGS::PAYMENTS:STRIPE:SECRET' => 'stripe-secret',
'SETTINGS::PAYMENTS:STRIPE:ENDPOINT_SECRET' => 'stripe-endpoint-secret',
'SETTINGS::PAYMENTS:STRIPE:TEST_SECRET' => 'stripe-test-secret',
'SETTINGS::PAYMENTS:STRIPE:ENDPOINT_TEST_SECRET' => 'stripe-endpoint-test-secret',
'SETTINGS::PAYMENTS:STRIPE:METHODS' => 'stripe-methods',
'SETTINGS::PAYMENTS:SALES_TAX' => 'sales-tax',
];
foreach ($values as $key => $value) {
$param = $request->get($value);
Settings::where('key', $key)->updateOrCreate(['key' => $key], ['value' => $param]);
Cache::forget('setting'.':'.$key);
}
return redirect(route('admin.settings.index').'#payment')->with('success', __('Payment settings updated!'));
}
}

View file

@ -1,154 +0,0 @@
<?php
namespace App\Classes\Settings;
use App\Classes\Pterodactyl;
use App\Models\Settings;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Validator;
use Qirolab\Theme\Theme;
class System
{
public function __construct()
{
}
public function checkPteroClientkey()
{
$response = Pterodactyl::getClientUser();
if ($response->failed()) {
return redirect()->back()->with('error', __('Your Key or URL is not correct'));
}
return redirect()->back()->with('success', __('Everything is good!'));
}
public function updateSettings(Request $request)
{
$validator = Validator::make($request->all(), [
'register-ip-check' => 'string',
'server-create-charge-first-hour' => 'string',
'credits-display-name' => 'required|string',
'allocation-limit' => 'required|min:0|integer',
'force-email-verification' => 'string',
'force-discord-verification' => 'string',
'initial-credits' => 'required|min:0|integer',
'initial-server-limit' => 'required|min:0|integer',
'credits-reward-amount-discord' => 'required|min:0|integer',
'credits-reward-amount-email' => 'required|min:0|integer',
'server-limit-discord' => 'required|min:0|integer',
'server-limit-email' => 'required|min:0|integer',
'server-limit-purchase' => 'required|min:0|integer',
'pterodactyl-api-key' => 'required|string',
'pterodactyl-url' => 'required|string',
'per-page-limit' => 'required|min:0|integer',
'pterodactyl-admin-api-key' => 'required|string',
'enable-upgrades' => 'string',
'enable-disable-servers' => 'string',
'enable-disable-new-users' => 'string',
'show-imprint' => 'string',
'show-privacy' => 'string',
'show-tos' => 'string',
'alert-enabled' => 'string',
'alter-type' => 'string',
'alert-message' => 'string|nullable',
'motd-enabled' => 'string',
'usefullinks-enabled' => 'string',
'motd-message' => 'string|nullable',
'seo-title' => 'string|nullable',
'seo-description' => 'string|nullable',
]);
$validator->after(function ($validator) use ($request) {
// if enable-recaptcha is true then recaptcha-site-key and recaptcha-secret-key must be set
if ($request->get('enable-upgrades') == 'true' && (! $request->get('pterodactyl-admin-api-key'))) {
$validator->errors()->add('pterodactyl-admin-api-key', 'The admin api key is required when upgrades are enabled.');
}
});
if ($validator->fails()) {
return redirect(route('admin.settings.index').'#system')->with('error', __('System settings have not been updated!'))->withErrors($validator)
->withInput();
}
// update Icons from request
$this->updateIcons($request);
$values = [
"SETTINGS::SYSTEM:REGISTER_IP_CHECK" => "register-ip-check",
"SETTINGS::SYSTEM:SERVER_CREATE_CHARGE_FIRST_HOUR" => "server-create-charge-first-hour",
"SETTINGS::SYSTEM:CREDITS_DISPLAY_NAME" => "credits-display-name",
"SETTINGS::SERVER:ALLOCATION_LIMIT" => "allocation-limit",
"SETTINGS::USER:MINIMUM_REQUIRED_CREDITS_TO_MAKE_SERVER" => "minimum-credits",
"SETTINGS::USER:FORCE_DISCORD_VERIFICATION" => "force-discord-verification",
"SETTINGS::USER:FORCE_EMAIL_VERIFICATION" => "force-email-verification",
"SETTINGS::USER:INITIAL_CREDITS" => "initial-credits",
"SETTINGS::USER:INITIAL_SERVER_LIMIT" => "initial-server-limit",
"SETTINGS::USER:CREDITS_REWARD_AFTER_VERIFY_DISCORD" => "credits-reward-amount-discord",
"SETTINGS::USER:CREDITS_REWARD_AFTER_VERIFY_EMAIL" => "credits-reward-amount-email",
"SETTINGS::USER:SERVER_LIMIT_REWARD_AFTER_VERIFY_DISCORD" => "server-limit-discord",
"SETTINGS::USER:SERVER_LIMIT_REWARD_AFTER_VERIFY_EMAIL" => "server-limit-email",
"SETTINGS::USER:SERVER_LIMIT_AFTER_IRL_PURCHASE" => "server-limit-purchase",
"SETTINGS::MISC:PHPMYADMIN:URL" => "phpmyadmin-url",
"SETTINGS::SYSTEM:PTERODACTYL:URL" => "pterodactyl-url",
'SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT' => "per-page-limit",
"SETTINGS::SYSTEM:PTERODACTYL:TOKEN" => "pterodactyl-api-key",
"SETTINGS::SYSTEM:ENABLE_LOGIN_LOGO" => "enable-login-logo",
"SETTINGS::SYSTEM:PTERODACTYL:ADMIN_USER_TOKEN" => "pterodactyl-admin-api-key",
"SETTINGS::SYSTEM:ENABLE_UPGRADE" => "enable-upgrade",
"SETTINGS::SYSTEM:CREATION_OF_NEW_SERVERS" => "enable-disable-servers",
"SETTINGS::SYSTEM:CREATION_OF_NEW_USERS" => "enable-disable-new-users",
"SETTINGS::SYSTEM:SHOW_IMPRINT" => "show-imprint",
"SETTINGS::SYSTEM:SHOW_PRIVACY" => "show-privacy",
"SETTINGS::SYSTEM:SHOW_TOS" => "show-tos",
"SETTINGS::SYSTEM:ALERT_ENABLED" => "alert-enabled",
"SETTINGS::SYSTEM:ALERT_TYPE" => "alert-type",
"SETTINGS::SYSTEM:ALERT_MESSAGE" => "alert-message",
"SETTINGS::SYSTEM:THEME" => "theme",
"SETTINGS::SYSTEM:MOTD_ENABLED" => "motd-enabled",
"SETTINGS::SYSTEM:MOTD_MESSAGE" => "motd-message",
"SETTINGS::SYSTEM:USEFULLINKS_ENABLED" => "usefullinks-enabled",
"SETTINGS::SYSTEM:SEO_TITLE" => "seo-title",
"SETTINGS::SYSTEM:SEO_DESCRIPTION" => "seo-description",
];
foreach ($values as $key => $value) {
$param = $request->get($value);
Settings::where('key', $key)->updateOrCreate(['key' => $key], ['value' => $param]);
Cache::forget('setting'.':'.$key);
}
//SET THEME
$theme = $request->get('theme');
Theme::set($theme);
return redirect(route('admin.settings.index').'#system')->with('success', __('System settings updated!'));
}
private function updateIcons(Request $request)
{
$request->validate([
'icon' => 'nullable|max:10000|mimes:jpg,png,jpeg',
'logo' => 'nullable|max:10000|mimes:jpg,png,jpeg',
'favicon' => 'nullable|max:10000|mimes:ico',
]);
if ($request->hasFile('icon')) {
$request->file('icon')->storeAs('public', 'icon.png');
}
if ($request->hasFile('logo')) {
$request->file('logo')->storeAs('public', 'logo.png');
}
if ($request->hasFile('favicon')) {
$request->file('favicon')->storeAs('public', 'favicon.ico');
}
}
}

View file

@ -2,18 +2,20 @@
namespace App\Console\Commands;
use App\Classes\Pterodactyl;
use App\Classes\PterodactylClient;
use App\Models\User;
use App\Settings\PterodactylSettings;
use App\Traits\Referral;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
class MakeUserCommand extends Command
{
use Referral;
private $pterodactyl;
/**
* The name and signature of the console command.
*
@ -28,17 +30,14 @@ class MakeUserCommand extends Command
*/
protected $description = 'Create an admin account with the Artisan Console';
private Pterodactyl $pterodactyl;
/**
* Create a new command instance.
*
* @return void
*/
public function __construct(Pterodactyl $pterodactyl)
public function __construct()
{
parent::__construct();
$this->pterodactyl = $pterodactyl;
}
@ -47,8 +46,9 @@ class MakeUserCommand extends Command
*
* @return int
*/
public function handle()
public function handle(PterodactylSettings $ptero_settings)
{
$this->pterodactyl = new PterodactylClient($ptero_settings);
$ptero_id = $this->option('ptero_id') ?? $this->ask('Please specify your Pterodactyl ID.');
$password = $this->secret('password') ?? $this->ask('Please specify your password.');

View file

@ -0,0 +1,146 @@
<?php
namespace App\Extensions\PaymentGateways\Mollie;
use App\Helpers\AbstractExtension;
use App\Events\PaymentEvent;
use App\Events\UserUpdateCreditsEvent;
use App\Models\PartnerDiscount;
use App\Models\Payment;
use App\Models\ShopProduct;
use App\Models\User;
use Exception;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Http;
/**
* Summary of PayPalExtension
*/
class MollieExtension extends AbstractExtension
{
public static function getConfig(): array
{
return [
"name" => "Mollie",
"RoutesIgnoreCsrf" => [
"payment/MollieWebhook"
],
];
}
static function pay(Request $request): void
{
$url = 'https://api.mollie.com/v2/payments';
$settings = new MollieSettings();
$user = Auth::user();
$shopProduct = ShopProduct::findOrFail($request->shopProduct);
$discount = PartnerDiscount::getDiscount();
// create a new payment
$payment = Payment::create([
'user_id' => $user->id,
'payment_id' => null,
'payment_method' => 'mollie',
'type' => $shopProduct->type,
'status' => 'open',
'amount' => $shopProduct->quantity,
'price' => $shopProduct->price - ($shopProduct->price * $discount / 100),
'tax_value' => $shopProduct->getTaxValue(),
'tax_percent' => $shopProduct->getTaxPercent(),
'total_price' => $shopProduct->getTotalPrice(),
'currency_code' => $shopProduct->currency_code,
'shop_item_product_id' => $shopProduct->id,
]);
try {
$response = Http::withHeaders([
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $settings->api_key,
])->post($url, [
'amount' => [
'currency' => $shopProduct->currency_code,
'value' => number_format($shopProduct->getTotalPrice(), 2, '.', ''),
],
'description' => "Order #{$payment->id} - " . $shopProduct->name,
'redirectUrl' => route('payment.MollieSuccess'),
'cancelUrl' => route('payment.Cancel'),
'webhookUrl' => url('/extensions/payment/MollieWebhook'),
'metadata' => [
'payment_id' => $payment->id,
],
]);
if ($response->status() != 201) {
Log::error('Mollie Payment: ' . $response->body());
$payment->delete();
Redirect::route('store.index')->with('error', __('Payment failed'))->send();
return;
}
$payment->update([
'payment_id' => $response->json()['id'],
]);
Redirect::away($response->json()['_links']['checkout']['href'])->send();
return;
} catch (Exception $ex) {
Log::error('Mollie Payment: ' . $ex->getMessage());
$payment->delete();
Redirect::route('store.index')->with('error', __('Payment failed'))->send();
return;
}
}
static function success(Request $request): void
{
$payment = Payment::findOrFail($request->input('payment'));
$payment->status = 'pending';
Redirect::route('home')->with('success', 'Your payment is being processed')->send();
return;
}
static function webhook(Request $request): JsonResponse
{
$url = 'https://api.mollie.com/v2/payments/' . $request->id;
$settings = new MollieSettings();
try {
$response = Http::withHeaders([
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $settings->api_key,
])->get($url);
if ($response->status() != 200) {
Log::error('Mollie Payment Webhook: ' . $response->json()['title']);
return response()->json(['success' => false]);
}
$payment = Payment::findOrFail($response->json()['metadata']['payment_id']);
$payment->status->update([
'status' => $response->json()['status'],
]);
$shopProduct = ShopProduct::findOrFail($payment->shop_item_product_id);
event(new PaymentEvent($payment, $payment, $shopProduct));
if ($response->json()['status'] == 'paid') {
$user = User::findOrFail($payment->user_id);
event(new UserUpdateCreditsEvent($user));
}
} catch (Exception $ex) {
Log::error('Mollie Payment Webhook: ' . $ex->getMessage());
return response()->json(['success' => false]);
}
// return a 200 status code
return response()->json(['success' => true]);
}
}

View file

@ -0,0 +1,41 @@
<?php
namespace App\Extensions\PaymentGateways\Mollie;
use Spatie\LaravelSettings\Settings;
class MollieSettings extends Settings
{
public bool $enabled = false;
public ?string $api_key;
public static function group(): string
{
return 'mollie';
}
public static function encrypted(): array
{
return [
'api_key',
];
}
public static function getOptionInputData()
{
return [
'category_icon' => 'fas fa-dollar-sign',
'api_key' => [
'type' => 'string',
'label' => 'API Key',
'description' => 'The API Key of your Mollie App',
],
'enabled' => [
'type' => 'boolean',
'label' => 'Enabled',
'description' => 'Enable or disable this payment gateway',
],
];
}
}

View file

@ -0,0 +1,18 @@
<?php
use Spatie\LaravelSettings\Migrations\SettingsMigration;
class CreateMollieSettings extends SettingsMigration
{
public function up(): void
{
$this->migrator->addEncrypted('mollie.api_key', null);
$this->migrator->add('mollie.enabled', false);
}
public function down(): void
{
$this->migrator->delete('mollie.api_key');
$this->migrator->delete('mollie.enabled');
}
}

View file

@ -0,0 +1,22 @@
<?php
use Illuminate\Support\Facades\Route;
use App\Extensions\PaymentGateways\Mollie\MollieExtension;
Route::middleware(['web', 'auth'])->group(function () {
Route::get('payment/MolliePay/{shopProduct}', function () {
MollieExtension::pay(request());
})->name('payment.MolliePay');
Route::get(
'payment/MollieSuccess',
function () {
MollieExtension::success(request());
}
)->name('payment.MollieSuccess');
});
Route::post('payment/MollieWebhook', function () {
MollieExtension::webhook(request());
})->name('payment.MollieWebhook');

View file

@ -0,0 +1,197 @@
<?php
namespace App\Extensions\PaymentGateways\PayPal;
use App\Helpers\AbstractExtension;
use App\Events\PaymentEvent;
use App\Events\UserUpdateCreditsEvent;
use App\Extensions\PaymentGateways\PayPal\PayPalSettings;
use App\Models\PartnerDiscount;
use App\Models\Payment;
use App\Models\ShopProduct;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Log;
use PayPalCheckoutSdk\Core\PayPalHttpClient;
use PayPalCheckoutSdk\Core\ProductionEnvironment;
use PayPalCheckoutSdk\Core\SandboxEnvironment;
use PayPalCheckoutSdk\Orders\OrdersCaptureRequest;
use PayPalCheckoutSdk\Orders\OrdersCreateRequest;
use PayPalHttp\HttpException;
/**
* Summary of PayPalExtension
*/
class PayPalExtension extends AbstractExtension
{
public static function getConfig(): array
{
return [
"name" => "PayPal",
"RoutesIgnoreCsrf" => [],
];
}
static function PaypalPay(Request $request): void
{
/** @var User $user */
$user = Auth::user();
$shopProduct = ShopProduct::findOrFail($request->shopProduct);
$discount = PartnerDiscount::getDiscount();
// create a new payment
$payment = Payment::create([
'user_id' => $user->id,
'payment_id' => null,
'payment_method' => 'paypal',
'type' => $shopProduct->type,
'status' => 'open',
'amount' => $shopProduct->quantity,
'price' => $shopProduct->price - ($shopProduct->price * $discount / 100),
'tax_value' => $shopProduct->getTaxValue(),
'tax_percent' => $shopProduct->getTaxPercent(),
'total_price' => $shopProduct->getTotalPrice(),
'currency_code' => $shopProduct->currency_code,
'shop_item_product_id' => $shopProduct->id,
]);
$request = new OrdersCreateRequest();
$request->prefer('return=representation');
$request->body = [
"intent" => "CAPTURE",
"purchase_units" => [
[
"reference_id" => uniqid(),
"description" => $shopProduct->display . ($discount ? (" (" . __('Discount') . " " . $discount . '%)') : ""),
"amount" => [
"value" => $shopProduct->getTotalPrice(),
'currency_code' => strtoupper($shopProduct->currency_code),
'breakdown' => [
'item_total' =>
[
'currency_code' => strtoupper($shopProduct->currency_code),
'value' => $shopProduct->getPriceAfterDiscount(),
],
'tax_total' =>
[
'currency_code' => strtoupper($shopProduct->currency_code),
'value' => $shopProduct->getTaxValue(),
]
]
]
]
],
"application_context" => [
"cancel_url" => route('payment.Cancel'),
"return_url" => route('payment.PayPalSuccess', ['payment' => $payment->id]),
'brand_name' => config('app.name', 'Controlpanel.GG'),
'shipping_preference' => 'NO_SHIPPING'
]
];
try {
// Call API with your client and get a response for your call
$response = self::getPayPalClient()->execute($request);
// check for any errors in the response
if ($response->statusCode != 201) {
throw new \Exception($response->statusCode);
}
// make sure the link is not empty
if (empty($response->result->links[1]->href)) {
throw new \Exception('No redirect link found');
}
Redirect::away($response->result->links[1]->href)->send();
return;
} catch (HttpException $ex) {
Log::error('PayPal Payment: ' . $ex->getMessage());
$payment->delete();
Redirect::route('store.index')->with('error', __('Payment failed'))->send();
return;
}
}
static function PaypalSuccess(Request $laravelRequest): void
{
$user = Auth::user();
$user = User::findOrFail($user->id);
$payment = Payment::findOrFail($laravelRequest->payment);
$shopProduct = ShopProduct::findOrFail($payment->shop_item_product_id);
$request = new OrdersCaptureRequest($laravelRequest->input('token'));
$request->prefer('return=representation');
try {
// Call API with your client and get a response for your call
$response = self::getPayPalClient()->execute($request);
if ($response->statusCode == 201 || $response->statusCode == 200) {
//update payment
$payment->update([
'status' => 'paid',
'payment_id' => $response->result->id,
]);
event(new UserUpdateCreditsEvent($user));
event(new PaymentEvent($user, $payment, $shopProduct));
// redirect to the payment success page with success message
Redirect::route('home')->with('success', 'Payment successful')->send();
} elseif (env('APP_ENV') == 'local') {
// If call returns body in response, you can get the deserialized version from the result attribute of the response
$payment->delete();
dd($response);
} else {
$payment->update([
'status' => 'cancelled',
'payment_id' => $response->result->id,
]);
abort(500);
}
} catch (HttpException $ex) {
if (env('APP_ENV') == 'local') {
echo $ex->statusCode;
$payment->delete();
dd($ex->getMessage());
} else {
$payment->update([
'status' => 'cancelled',
'payment_id' => $response->result->id,
]);
abort(422);
}
}
}
static function getPayPalClient(): PayPalHttpClient
{
$environment = env('APP_ENV') == 'local'
? new SandboxEnvironment(self::getPaypalClientId(), self::getPaypalClientSecret())
: new ProductionEnvironment(self::getPaypalClientId(), self::getPaypalClientSecret());
return new PayPalHttpClient($environment);
}
/**
* @return string
*/
static function getPaypalClientId(): string
{
$settings = new PayPalSettings();
return env('APP_ENV') == 'local' ? $settings->sandbox_client_id : $settings->client_id;
}
/**
* @return string
*/
static function getPaypalClientSecret(): string
{
$settings = new PayPalSettings();
return env('APP_ENV') == 'local' ? $settings->sandbox_client_secret : $settings->client_secret;
}
}

View file

@ -0,0 +1,67 @@
<?php
namespace App\Extensions\PaymentGateways\PayPal;
use Spatie\LaravelSettings\Settings;
class PayPalSettings extends Settings
{
public bool $enabled = false;
public ?string $client_id;
public ?string $client_secret;
public ?string $sandbox_client_id;
public ?string $sandbox_client_secret;
public static function group(): string
{
return 'paypal';
}
public static function encrypted(): array
{
return [
'client_id',
'client_secret',
'sandbox_client_id',
'sandbox_client_secret'
];
}
/**
* Summary of optionInputData array
* Only used for the settings page
* @return array<array<'type'|'label'|'description'|'options', string|bool|float|int|array<string, string>>>
*/
public static function getOptionInputData()
{
return [
'category_icon' => 'fas fa-dollar-sign',
'client_id' => [
'type' => 'string',
'label' => 'Client ID',
'description' => 'The Client ID of your PayPal App',
],
'client_secret' => [
'type' => 'string',
'label' => 'Client Secret',
'description' => 'The Client Secret of your PayPal App',
],
'enabled' => [
'type' => 'boolean',
'label' => 'Enabled',
'description' => 'Enable this payment gateway',
],
'sandbox_client_id' => [
'type' => 'string',
'label' => 'Sandbox Client ID',
'description' => 'The Sandbox Client ID used when app_env = local',
],
'sandbox_client_secret' => [
'type' => 'string',
'label' => 'Sandbox Client Secret',
'description' => 'The Sandbox Client Secret used when app_env = local',
],
];
}
}

View file

@ -1,13 +0,0 @@
<?php
namespace App\Extensions\PaymentGateways\PayPal;
function getConfig()
{
return [
"name" => "PayPal",
"description" => "PayPal payment gateway",
"RoutesIgnoreCsrf" => [],
"enabled" => (config('SETTINGS::PAYMENTS:PAYPAL:SECRET') && config('SETTINGS::PAYMENTS:PAYPAL:CLIENT_ID')) || (config('SETTINGS::PAYMENTS:PAYPAL:SANDBOX_SECRET') && config('SETTINGS::PAYMENTS:PAYPAL:SANDBOX_CLIENT_ID') && env("APP_ENV") === "local"),
];
}

View file

@ -1,186 +0,0 @@
<?php
use App\Events\PaymentEvent;
use App\Events\UserUpdateCreditsEvent;
use App\Models\PartnerDiscount;
use App\Models\Payment;
use App\Models\ShopProduct;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Log;
use PayPalCheckoutSdk\Core\PayPalHttpClient;
use PayPalCheckoutSdk\Core\ProductionEnvironment;
use PayPalCheckoutSdk\Core\SandboxEnvironment;
use PayPalCheckoutSdk\Orders\OrdersCaptureRequest;
use PayPalCheckoutSdk\Orders\OrdersCreateRequest;
use PayPalHttp\HttpException;
/**
* @param Request $request
* @param ShopProduct $shopProduct
*/
function PaypalPay(Request $request)
{
/** @var User $user */
$user = Auth::user();
$shopProduct = ShopProduct::findOrFail($request->shopProduct);
$discount = PartnerDiscount::getDiscount();
// create a new payment
$payment = Payment::create([
'user_id' => $user->id,
'payment_id' => null,
'payment_method' => 'paypal',
'type' => $shopProduct->type,
'status' => 'open',
'amount' => $shopProduct->quantity,
'price' => $shopProduct->price - ($shopProduct->price * $discount / 100),
'tax_value' => $shopProduct->getTaxValue(),
'tax_percent' => $shopProduct->getTaxPercent(),
'total_price' => $shopProduct->getTotalPrice(),
'currency_code' => $shopProduct->currency_code,
'shop_item_product_id' => $shopProduct->id,
]);
$request = new OrdersCreateRequest();
$request->prefer('return=representation');
$request->body = [
"intent" => "CAPTURE",
"purchase_units" => [
[
"reference_id" => uniqid(),
"description" => $shopProduct->display . ($discount ? (" (" . __('Discount') . " " . $discount . '%)') : ""),
"amount" => [
"value" => $shopProduct->getTotalPrice(),
'currency_code' => strtoupper($shopProduct->currency_code),
'breakdown' => [
'item_total' =>
[
'currency_code' => strtoupper($shopProduct->currency_code),
'value' => $shopProduct->getPriceAfterDiscount(),
],
'tax_total' =>
[
'currency_code' => strtoupper($shopProduct->currency_code),
'value' => $shopProduct->getTaxValue(),
]
]
]
]
],
"application_context" => [
"cancel_url" => route('payment.Cancel'),
"return_url" => route('payment.PayPalSuccess', ['payment' => $payment->id]),
'brand_name' => config('app.name', 'Controlpanel.GG'),
'shipping_preference' => 'NO_SHIPPING'
]
];
try {
// Call API with your client and get a response for your call
$response = getPayPalClient()->execute($request);
// check for any errors in the response
if ($response->statusCode != 201) {
throw new \Exception($response->statusCode);
}
// make sure the link is not empty
if (empty($response->result->links[1]->href)) {
throw new \Exception('No redirect link found');
}
Redirect::away($response->result->links[1]->href)->send();
return;
} catch (HttpException $ex) {
Log::error('PayPal Payment: ' . $ex->getMessage());
$payment->delete();
Redirect::route('store.index')->with('error', __('Payment failed'))->send();
return;
}
}
/**
* @param Request $laravelRequest
*/
function PaypalSuccess(Request $laravelRequest)
{
$user = Auth::user();
$user = User::findOrFail($user->id);
$payment = Payment::findOrFail($laravelRequest->payment);
$shopProduct = ShopProduct::findOrFail($payment->shop_item_product_id);
$request = new OrdersCaptureRequest($laravelRequest->input('token'));
$request->prefer('return=representation');
try {
// Call API with your client and get a response for your call
$response = getPayPalClient()->execute($request);
if ($response->statusCode == 201 || $response->statusCode == 200) {
//update payment
$payment->update([
'status' => 'paid',
'payment_id' => $response->result->id,
]);
event(new UserUpdateCreditsEvent($user));
event(new PaymentEvent($user, $payment, $shopProduct));
// redirect to the payment success page with success message
Redirect::route('home')->with('success', 'Payment successful')->send();
} elseif (env('APP_ENV') == 'local') {
// If call returns body in response, you can get the deserialized version from the result attribute of the response
$payment->delete();
dd($response);
} else {
$payment->update([
'status' => 'cancelled',
'payment_id' => $response->result->id,
]);
abort(500);
}
} catch (HttpException $ex) {
if (env('APP_ENV') == 'local') {
echo $ex->statusCode;
$payment->delete();
dd($ex->getMessage());
} else {
$payment->update([
'status' => 'cancelled',
'payment_id' => $response->result->id,
]);
abort(422);
}
}
}
/**
* @return PayPalHttpClient
*/
function getPayPalClient()
{
$environment = env('APP_ENV') == 'local'
? new SandboxEnvironment(getPaypalClientId(), getPaypalClientSecret())
: new ProductionEnvironment(getPaypalClientId(), getPaypalClientSecret());
return new PayPalHttpClient($environment);
}
/**
* @return string
*/
function getPaypalClientId()
{
return env('APP_ENV') == 'local' ? config("SETTINGS::PAYMENTS:PAYPAL:SANDBOX_CLIENT_ID") : config("SETTINGS::PAYMENTS:PAYPAL:CLIENT_ID");
}
/**
* @return string
*/
function getPaypalClientSecret()
{
return env('APP_ENV') == 'local' ? config("SETTINGS::PAYMENTS:PAYPAL:SANDBOX_SECRET") : config("SETTINGS::PAYMENTS:PAYPAL:SECRET");
}

View file

@ -0,0 +1,100 @@
<?php
use Spatie\LaravelSettings\Migrations\SettingsMigration;
use Illuminate\Support\Facades\DB;
class CreatePayPalSettings extends SettingsMigration
{
public function up(): void
{
$table_exists = DB::table('settings_old')->exists();
$this->migrator->addEncrypted('paypal.client_id', $table_exists ? $this->getOldValue('SETTINGS::PAYMENTS:PAYPAL:CLIENT_ID') : null);
$this->migrator->addEncrypted('paypal.client_secret', $table_exists ? $this->getOldValue('SETTINGS::PAYMENTS:PAYPAL:SECRET') : null);
$this->migrator->addEncrypted('paypal.sandbox_client_id', $table_exists ? $this->getOldValue('SETTINGS::PAYMENTS:PAYPAL:SANDBOX_CLIENT_ID') : null);
$this->migrator->addEncrypted('paypal.sandbox_client_secret', $table_exists ? $this->getOldValue('SETTINGS::PAYMENTS:PAYPAL:SANDBOX_SECRET') : null);
$this->migrator->add('paypal.enabled', false);
}
public function down(): void
{
DB::table('settings_old')->insert([
[
'key' => 'SETTINGS::PAYMENTS:PAYPAL:CLIENT_ID',
'value' => $this->getNewValue('client_id'),
'type' => 'string',
'description' => 'The Client ID of your PayPal App'
],
[
'key' => 'SETTINGS::PAYMENTS:PAYPAL:SECRET',
'value' => $this->getNewValue('client_secret'),
'type' => 'string',
'description' => 'The Client Secret of your PayPal App'
],
[
'key' => 'SETTINGS::PAYMENTS:PAYPAL:SANDBOX_CLIENT_ID',
'value' => $this->getNewValue('sandbox_client_id'),
'type' => 'string',
'description' => 'The Sandbox Client ID of your PayPal App'
],
[
'key' => 'SETTINGS::PAYMENTS:PAYPAL:SANDBOX_SECRET',
'value' => $this->getNewValue('sandbox_client_secret'),
'type' => 'string',
'description' => 'The Sandbox Client Secret of your PayPal App'
]
]);
$this->migrator->delete('paypal.client_id');
$this->migrator->delete('paypal.client_secret');
$this->migrator->delete('paypal.enabled');
$this->migrator->delete('paypal.sandbox_client_id');
$this->migrator->delete('paypal.sandbox_client_secret');
}
public function getNewValue(string $name)
{
$new_value = DB::table('settings')->where([['group', '=', 'paypal'], ['name', '=', $name]])->get(['payload'])->first();
// Some keys returns '""' as a value.
if ($new_value->payload === '""') {
return null;
}
// remove the quotes from the string
if (substr($new_value->payload, 0, 1) === '"' && substr($new_value->payload, -1) === '"') {
return substr($new_value->payload, 1, -1);
}
return $new_value->payload;
}
public function getOldValue(string $key)
{
// Always get the first value of the key.
$old_value = DB::table('settings_old')->where('key', '=', $key)->get(['value', 'type'])->first();
// Handle the old values to return without it being a string in all cases.
if ($old_value->type === "string" || $old_value->type === "text") {
if (is_null($old_value->value)) {
return '';
}
// Some values have the type string, but their values are boolean.
if ($old_value->value === "false" || $old_value->value === "true") {
return filter_var($old_value->value, FILTER_VALIDATE_BOOL);
}
return $old_value->value;
}
if ($old_value->type === "boolean") {
return filter_var($old_value->value, FILTER_VALIDATE_BOOL);
}
return filter_var($old_value->value, FILTER_VALIDATE_INT);
}
}

View file

@ -1,18 +1,17 @@
<?php
use Illuminate\Support\Facades\Route;
include_once(__DIR__ . '/index.php');
use App\Extensions\PaymentGateways\PayPal\PayPalExtension;
Route::middleware(['web', 'auth'])->group(function () {
Route::get('payment/PayPalPay/{shopProduct}', function () {
PaypalPay(request());
PayPalExtension::PaypalPay(request());
})->name('payment.PayPalPay');
Route::get(
'payment/PayPalSuccess',
function () {
PaypalSuccess(request());
PayPalExtension::PaypalSuccess(request());
}
)->name('payment.PayPalSuccess');
});

View file

@ -0,0 +1,390 @@
<?php
namespace App\Extensions\PaymentGateways\Stripe;
use App\Helpers\AbstractExtension;
use App\Events\PaymentEvent;
use App\Events\UserUpdateCreditsEvent;
use App\Extensions\PaymentGateways\Stripe\StripeSettings;
use App\Models\PartnerDiscount;
use App\Models\Payment;
use App\Models\ShopProduct;
use App\Models\User;
use App\Notifications\ConfirmPaymentNotification;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Redirect;
use Stripe\Exception\SignatureVerificationException;
use Stripe\Stripe;
use Stripe\StripeClient;
class StripeExtension extends AbstractExtension
{
public static function getConfig(): array
{
return [
"name" => "Stripe",
"RoutesIgnoreCsrf" => [
"payment/StripeWebhooks",
],
];
}
/**
* @param Request $request
* @param ShopProduct $shopProduct
*/
public static function StripePay(Request $request)
{
$user = Auth::user();
$shopProduct = ShopProduct::findOrFail($request->shopProduct);
// check if the price is valid for stripe
if (!self::checkPriceAmount($shopProduct->getTotalPrice(), strtoupper($shopProduct->currency_code), 'stripe')) {
Redirect::route('home')->with('error', __('The product you chose can\'t be purchased with this payment method. The total amount is too small. Please buy a bigger amount or try a different payment method.'))->send();
return;
}
$discount = PartnerDiscount::getDiscount();
// create payment
$payment = Payment::create([
'user_id' => $user->id,
'payment_id' => null,
'payment_method' => 'stripe',
'type' => $shopProduct->type,
'status' => 'open',
'amount' => $shopProduct->quantity,
'price' => $shopProduct->price - ($shopProduct->price * $discount / 100),
'tax_value' => $shopProduct->getTaxValue(),
'total_price' => $shopProduct->getTotalPrice(),
'tax_percent' => $shopProduct->getTaxPercent(),
'currency_code' => $shopProduct->currency_code,
'shop_item_product_id' => $shopProduct->id,
]);
$stripeClient = self::getStripeClient();
$request = $stripeClient->checkout->sessions->create([
'line_items' => [
[
'price_data' => [
'currency' => $shopProduct->currency_code,
'product_data' => [
'name' => $shopProduct->display . ($discount ? (' (' . __('Discount') . ' ' . $discount . '%)') : ''),
'description' => $shopProduct->description,
],
'unit_amount_decimal' => round($shopProduct->getPriceAfterDiscount() * 100, 2),
],
'quantity' => 1,
],
[
'price_data' => [
'currency' => $shopProduct->currency_code,
'product_data' => [
'name' => __('Tax'),
'description' => $shopProduct->getTaxPercent() . '%',
],
'unit_amount_decimal' => round($shopProduct->getTaxValue(), 2) * 100,
],
'quantity' => 1,
],
],
'mode' => 'payment',
'success_url' => route('payment.StripeSuccess', ['payment' => $payment->id]) . '&session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => route('payment.Cancel'),
'payment_intent_data' => [
'metadata' => [
'payment_id' => $payment->id,
],
],
]);
Redirect::to($request->url)->send();
}
/**
* @param Request $request
*/
public static function StripeSuccess(Request $request)
{
$user = Auth::user();
$user = User::findOrFail($user->id);
$payment = Payment::findOrFail($request->input('payment'));
$shopProduct = ShopProduct::findOrFail($payment->shop_item_product_id);
Redirect::route('home')->with('success', 'Please wait for success')->send();
$stripeClient = self::getStripeClient();
try {
//get stripe data
$paymentSession = $stripeClient->checkout->sessions->retrieve($request->input('session_id'));
$paymentIntent = $stripeClient->paymentIntents->retrieve($paymentSession->payment_intent);
//get DB entry of this payment ID if existing
$paymentDbEntry = Payment::where('payment_id', $paymentSession->payment_intent)->count();
// check if payment is 100% completed and payment does not exist in db already
if ($paymentSession->status == 'complete' && $paymentIntent->status == 'succeeded' && $paymentDbEntry == 0) {
//update payment
$payment->update([
'payment_id' => $paymentSession->payment_intent,
'status' => 'paid',
]);
//payment notification
$user->notify(new ConfirmPaymentNotification($payment));
event(new UserUpdateCreditsEvent($user));
event(new PaymentEvent($user, $payment, $shopProduct));
//redirect back to home
Redirect::route('home')->with('success', 'Payment successful')->send();
} else {
if ($paymentIntent->status == 'processing') {
//update payment
$payment->update([
'payment_id' => $paymentSession->payment_intent,
'status' => 'processing',
]);
event(new PaymentEvent($user, $payment, $shopProduct));
Redirect::route('home')->with('success', 'Your payment is being processed')->send();
}
if ($paymentDbEntry == 0 && $paymentIntent->status != 'processing') {
$stripeClient->paymentIntents->cancel($paymentIntent->id);
//redirect back to home
Redirect::route('home')->with('info', __('Your payment has been canceled!'))->send();
} else {
abort(402);
}
}
} catch (Exception $e) {
if (env('APP_ENV') == 'local') {
dd($e->getMessage());
} else {
abort(422);
}
}
}
/**
* @param Request $request
*/
public static function handleStripePaymentSuccessHook($paymentIntent)
{
try {
$payment = Payment::where('id', $paymentIntent->metadata->payment_id)->with('user')->first();
$user = User::where('id', $payment->user_id)->first();
$shopProduct = ShopProduct::findOrFail($payment->shop_item_product_id);
if ($paymentIntent->status == 'succeeded' && $payment->status == 'processing') {
//update payment db entry status
$payment->update([
'payment_id' => $payment->payment_id ?? $paymentIntent->id,
'status' => 'paid'
]);
//payment notification
$user->notify(new ConfirmPaymentNotification($payment));
event(new UserUpdateCreditsEvent($user));
event(new PaymentEvent($user, $payment, $shopProduct));
}
// return 200
return response()->json(['success' => true], 200);
} catch (Exception $ex) {
abort(422);
}
}
/**
* @param Request $request
*/
public static function StripeWebhooks(Request $request)
{
Stripe::setApiKey(self::getStripeSecret());
try {
$payload = @file_get_contents('php://input');
$sig_header = $request->header('Stripe-Signature');
$event = null;
$event = \Stripe\Webhook::constructEvent(
$payload,
$sig_header,
self::getStripeEndpointSecret()
);
} catch (\UnexpectedValueException $e) {
// Invalid payload
abort(400);
} catch (SignatureVerificationException $e) {
// Invalid signature
abort(400);
}
// Handle the event
switch ($event->type) {
case 'payment_intent.succeeded':
$paymentIntent = $event->data->object; // contains a \Stripe\PaymentIntent
self::handleStripePaymentSuccessHook($paymentIntent);
break;
default:
echo 'Received unknown event type ' . $event->type;
}
}
/**
* @return \Stripe\StripeClient
*/
public static function getStripeClient()
{
return new StripeClient(self::getStripeSecret());
}
/**
* @return string
*/
public static function getStripeSecret()
{
$settings = new StripeSettings();
return env('APP_ENV') == 'local'
? $settings->test_secret_key
: $settings->secret_key;
}
/**
* @return string
*/
public static function getStripeEndpointSecret()
{
$settings = new StripeSettings();
return env('APP_ENV') == 'local'
? $settings->test_endpoint_secret
: $settings->endpoint_secret;
}
/**
* @param $amount
* @param $currencyCode
* @param $payment_method
* @return bool
* @description check if the amount is higher than the minimum amount for the stripe gateway
*/
public static function checkPriceAmount($amount, $currencyCode, $payment_method)
{
$minimums = [
"USD" => [
"paypal" => 0,
"stripe" => 0.5
],
"AED" => [
"paypal" => 0,
"stripe" => 2
],
"AUD" => [
"paypal" => 0,
"stripe" => 0.5
],
"BGN" => [
"paypal" => 0,
"stripe" => 1
],
"BRL" => [
"paypal" => 0,
"stripe" => 0.5
],
"CAD" => [
"paypal" => 0,
"stripe" => 0.5
],
"CHF" => [
"paypal" => 0,
"stripe" => 0.5
],
"CZK" => [
"paypal" => 0,
"stripe" => 15
],
"DKK" => [
"paypal" => 0,
"stripe" => 2.5
],
"EUR" => [
"paypal" => 0,
"stripe" => 0.5
],
"GBP" => [
"paypal" => 0,
"stripe" => 0.3
],
"HKD" => [
"paypal" => 0,
"stripe" => 4
],
"HRK" => [
"paypal" => 0,
"stripe" => 0.5
],
"HUF" => [
"paypal" => 0,
"stripe" => 175
],
"INR" => [
"paypal" => 0,
"stripe" => 0.5
],
"JPY" => [
"paypal" => 0,
"stripe" => 0.5
],
"MXN" => [
"paypal" => 0,
"stripe" => 10
],
"MYR" => [
"paypal" => 0,
"stripe" => 2
],
"NOK" => [
"paypal" => 0,
"stripe" => 3
],
"NZD" => [
"paypal" => 0,
"stripe" => 0.5
],
"PLN" => [
"paypal" => 0,
"stripe" => 2
],
"RON" => [
"paypal" => 0,
"stripe" => 2
],
"SEK" => [
"paypal" => 0,
"stripe" => 3
],
"SGD" => [
"paypal" => 0,
"stripe" => 0.5
],
"THB" => [
"paypal" => 0,
"stripe" => 10
]
];
return $amount >= $minimums[$currencyCode][$payment_method];
}
}

View file

@ -0,0 +1,63 @@
<?php
namespace App\Extensions\PaymentGateways\Stripe;
use Spatie\LaravelSettings\Settings;
class StripeSettings extends Settings
{
public bool $enabled = false;
public ?string $secret_key;
public ?string $endpoint_secret;
public ?string $test_secret_key;
public ?string $test_endpoint_secret;
public static function group(): string
{
return 'stripe';
}
public static function encrypted(): array
{
return [
"secret_key",
"endpoint_secret",
"test_secret_key",
"test_endpoint_secret"
];
}
public static function getOptionInputData()
{
return [
'category_icon' => 'fas fa-dollar-sign',
'secret_key' => [
'type' => 'string',
'label' => 'Secret Key',
'description' => 'The Secret Key of your Stripe App',
],
'endpoint_secret' => [
'type' => 'string',
'label' => 'Endpoint Secret',
'description' => 'The Endpoint Secret of your Stripe App',
],
'test_secret_key' => [
'type' => 'string',
'label' => 'Test Secret Key',
'description' => 'The Test Secret Key used when app_env = local',
],
'test_endpoint_secret' => [
'type' => 'string',
'label' => 'Test Endpoint Secret',
'description' => 'The Test Endpoint Secret used when app_env = local',
],
'enabled' => [
'type' => 'boolean',
'label' => 'Enabled',
'description' => 'Enable this payment gateway',
]
];
}
}

View file

@ -1,15 +0,0 @@
<?php
namespace App\Extensions\PaymentGateways\Stripe;
function getConfig()
{
return [
"name" => "Stripe",
"description" => "Stripe payment gateway",
"RoutesIgnoreCsrf" => [
"payment/StripeWebhooks",
],
"enabled" => config('SETTINGS::PAYMENTS:STRIPE:SECRET') && config('SETTINGS::PAYMENTS:STRIPE:ENDPOINT_SECRET') || config('SETTINGS::PAYMENTS:STRIPE:ENDPOINT_TEST_SECRET') && config('SETTINGS::PAYMENTS:STRIPE:TEST_SECRET') && env("APP_ENV") === "local",
];
}

View file

@ -1,373 +0,0 @@
<?php
use App\Events\PaymentEvent;
use App\Events\UserUpdateCreditsEvent;
use App\Models\PartnerDiscount;
use App\Models\Payment;
use App\Models\ShopProduct;
use App\Models\User;
use App\Notifications\ConfirmPaymentNotification;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Redirect;
use Stripe\Exception\SignatureVerificationException;
use Stripe\Stripe;
use Stripe\StripeClient;
/**
* @param Request $request
* @param ShopProduct $shopProduct
*/
function StripePay(Request $request)
{
$user = Auth::user();
$shopProduct = ShopProduct::findOrFail($request->shopProduct);
// check if the price is valid for stripe
if (!checkPriceAmount($shopProduct->getTotalPrice(), strtoupper($shopProduct->currency_code), 'stripe')) {
Redirect::route('home')->with('error', __('The product you chose can\'t be purchased with this payment method. The total amount is too small. Please buy a bigger amount or try a different payment method.'))->send();
return;
}
$discount = PartnerDiscount::getDiscount();
// create payment
$payment = Payment::create([
'user_id' => $user->id,
'payment_id' => null,
'payment_method' => 'stripe',
'type' => $shopProduct->type,
'status' => 'open',
'amount' => $shopProduct->quantity,
'price' => $shopProduct->price - ($shopProduct->price * $discount / 100),
'tax_value' => $shopProduct->getTaxValue(),
'total_price' => $shopProduct->getTotalPrice(),
'tax_percent' => $shopProduct->getTaxPercent(),
'currency_code' => $shopProduct->currency_code,
'shop_item_product_id' => $shopProduct->id,
]);
$stripeClient = getStripeClient();
$request = $stripeClient->checkout->sessions->create([
'line_items' => [
[
'price_data' => [
'currency' => $shopProduct->currency_code,
'product_data' => [
'name' => $shopProduct->display . ($discount ? (' (' . __('Discount') . ' ' . $discount . '%)') : ''),
'description' => $shopProduct->description,
],
'unit_amount_decimal' => round($shopProduct->getPriceAfterDiscount() * 100, 2),
],
'quantity' => 1,
],
[
'price_data' => [
'currency' => $shopProduct->currency_code,
'product_data' => [
'name' => __('Tax'),
'description' => $shopProduct->getTaxPercent() . '%',
],
'unit_amount_decimal' => round($shopProduct->getTaxValue(), 2) * 100,
],
'quantity' => 1,
],
],
'mode' => 'payment',
'payment_method_types' => str_getcsv(config('SETTINGS::PAYMENTS:STRIPE:METHODS')),
'success_url' => route('payment.StripeSuccess', ['payment' => $payment->id]) . '&session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => route('payment.Cancel'),
'payment_intent_data' => [
'metadata' => [
'payment_id' => $payment->id,
],
],
]);
Redirect::to($request->url)->send();
}
/**
* @param Request $request
*/
function StripeSuccess(Request $request)
{
$user = Auth::user();
$user = User::findOrFail($user->id);
$payment = Payment::findOrFail($request->input('payment'));
$shopProduct = ShopProduct::findOrFail($payment->shop_item_product_id);
Redirect::route('home')->with('success', 'Please wait for success')->send();
$stripeClient = getStripeClient();
try {
//get stripe data
$paymentSession = $stripeClient->checkout->sessions->retrieve($request->input('session_id'));
$paymentIntent = $stripeClient->paymentIntents->retrieve($paymentSession->payment_intent);
//get DB entry of this payment ID if existing
$paymentDbEntry = Payment::where('payment_id', $paymentSession->payment_intent)->count();
// check if payment is 100% completed and payment does not exist in db already
if ($paymentSession->status == 'complete' && $paymentIntent->status == 'succeeded' && $paymentDbEntry == 0) {
//update payment
$payment->update([
'payment_id' => $paymentSession->payment_intent,
'status' => 'paid',
]);
//payment notification
$user->notify(new ConfirmPaymentNotification($payment));
event(new UserUpdateCreditsEvent($user));
event(new PaymentEvent($user, $payment, $shopProduct));
//redirect back to home
Redirect::route('home')->with('success', 'Payment successful')->send();
} else {
if ($paymentIntent->status == 'processing') {
//update payment
$payment->update([
'payment_id' => $paymentSession->payment_intent,
'status' => 'processing',
]);
event(new PaymentEvent($user, $payment, $shopProduct));
Redirect::route('home')->with('success', 'Your payment is being processed')->send();
}
if ($paymentDbEntry == 0 && $paymentIntent->status != 'processing') {
$stripeClient->paymentIntents->cancel($paymentIntent->id);
//redirect back to home
Redirect::route('home')->with('info', __('Your payment has been canceled!'))->send();
} else {
abort(402);
}
}
} catch (Exception $e) {
if (env('APP_ENV') == 'local') {
dd($e->getMessage());
} else {
abort(422);
}
}
}
/**
* @param Request $request
*/
function handleStripePaymentSuccessHook($paymentIntent)
{
try {
$payment = Payment::where('id', $paymentIntent->metadata->payment_id)->with('user')->first();
$user = User::where('id', $payment->user_id)->first();
$shopProduct = ShopProduct::findOrFail($payment->shop_item_product_id);
if ($paymentIntent->status == 'succeeded' && $payment->status == 'processing') {
//update payment db entry status
$payment->update([
'payment_id' => $payment->payment_id ?? $paymentIntent->id,
'status' => 'paid'
]);
//payment notification
$user->notify(new ConfirmPaymentNotification($payment));
event(new UserUpdateCreditsEvent($user));
event(new PaymentEvent($user, $payment, $shopProduct));
}
// return 200
return response()->json(['success' => true], 200);
} catch (Exception $ex) {
abort(422);
}
}
/**
* @param Request $request
*/
function StripeWebhooks(Request $request)
{
Stripe::setApiKey(getStripeSecret());
try {
$payload = @file_get_contents('php://input');
$sig_header = $request->header('Stripe-Signature');
$event = null;
$event = \Stripe\Webhook::constructEvent(
$payload,
$sig_header,
getStripeEndpointSecret()
);
} catch (\UnexpectedValueException $e) {
// Invalid payload
abort(400);
} catch (SignatureVerificationException $e) {
// Invalid signature
abort(400);
}
// Handle the event
switch ($event->type) {
case 'payment_intent.succeeded':
$paymentIntent = $event->data->object; // contains a \Stripe\PaymentIntent
handleStripePaymentSuccessHook($paymentIntent);
break;
default:
echo 'Received unknown event type ' . $event->type;
}
}
/**
* @return \Stripe\StripeClient
*/
function getStripeClient()
{
return new StripeClient(getStripeSecret());
}
/**
* @return string
*/
function getStripeSecret()
{
return env('APP_ENV') == 'local'
? config('SETTINGS::PAYMENTS:STRIPE:TEST_SECRET')
: config('SETTINGS::PAYMENTS:STRIPE:SECRET');
}
/**
* @return string
*/
function getStripeEndpointSecret()
{
return env('APP_ENV') == 'local'
? config('SETTINGS::PAYMENTS:STRIPE:ENDPOINT_TEST_SECRET')
: config('SETTINGS::PAYMENTS:STRIPE:ENDPOINT_SECRET');
}
/**
* @param $amount
* @param $currencyCode
* @param $payment_method
* @return bool
* @description check if the amount is higher than the minimum amount for the stripe gateway
*/
function checkPriceAmount($amount, $currencyCode, $payment_method)
{
$minimums = [
"USD" => [
"paypal" => 0,
"stripe" => 0.5
],
"AED" => [
"paypal" => 0,
"stripe" => 2
],
"AUD" => [
"paypal" => 0,
"stripe" => 0.5
],
"BGN" => [
"paypal" => 0,
"stripe" => 1
],
"BRL" => [
"paypal" => 0,
"stripe" => 0.5
],
"CAD" => [
"paypal" => 0,
"stripe" => 0.5
],
"CHF" => [
"paypal" => 0,
"stripe" => 0.5
],
"CZK" => [
"paypal" => 0,
"stripe" => 15
],
"DKK" => [
"paypal" => 0,
"stripe" => 2.5
],
"EUR" => [
"paypal" => 0,
"stripe" => 0.5
],
"GBP" => [
"paypal" => 0,
"stripe" => 0.3
],
"HKD" => [
"paypal" => 0,
"stripe" => 4
],
"HRK" => [
"paypal" => 0,
"stripe" => 0.5
],
"HUF" => [
"paypal" => 0,
"stripe" => 175
],
"INR" => [
"paypal" => 0,
"stripe" => 0.5
],
"JPY" => [
"paypal" => 0,
"stripe" => 0.5
],
"MXN" => [
"paypal" => 0,
"stripe" => 10
],
"MYR" => [
"paypal" => 0,
"stripe" => 2
],
"NOK" => [
"paypal" => 0,
"stripe" => 3
],
"NZD" => [
"paypal" => 0,
"stripe" => 0.5
],
"PLN" => [
"paypal" => 0,
"stripe" => 2
],
"RON" => [
"paypal" => 0,
"stripe" => 2
],
"SEK" => [
"paypal" => 0,
"stripe" => 3
],
"SGD" => [
"paypal" => 0,
"stripe" => 0.5
],
"THB" => [
"paypal" => 0,
"stripe" => 10
]
];
return $amount >= $minimums[$currencyCode][$payment_method];
}

View file

@ -0,0 +1,98 @@
<?php
use Spatie\LaravelSettings\Migrations\SettingsMigration;
use Illuminate\Support\Facades\DB;
class CreateStripeSettings extends SettingsMigration
{
public function up(): void
{
$table_exists = DB::table('settings_old')->exists();
$this->migrator->addEncrypted('stripe.secret_key', $table_exists ? $this->getOldValue('SETTINGS::PAYMENTS:STRIPE:SECRET') : null);
$this->migrator->addEncrypted('stripe.endpoint_secret', $table_exists ? $this->getOldValue('SETTINGS::PAYMENTS:STRIPE:ENDPOINT_SECRET') : null);
$this->migrator->addEncrypted('stripe.test_secret_key', $table_exists ? $this->getOldValue('SETTINGS::PAYMENTS:STRIPE:TEST_SECRET') : null);
$this->migrator->addEncrypted('stripe.test_endpoint_secret', $table_exists ? $this->getOldValue('SETTINGS::PAYMENTS:STRIPE:ENDPOINT_TEST_SECRET') : null);
$this->migrator->add('stripe.enabled', false);
}
public function down(): void
{
DB::table('settings_old')->insert([
[
'key' => 'SETTINGS::PAYMENTS:STRIPE:SECRET',
'value' => $this->getNewValue('secret_key'),
'type' => 'string',
'description' => 'The Secret Key of your Stripe App'
],
[
'key' => 'SETTINGS::PAYMENTS:STRIPE:ENDPOINT_SECRET',
'value' => $this->getNewValue('endpoint_secret'),
'type' => 'string',
'description' => 'The Endpoint Secret of your Stripe App'
],
[
'key' => 'SETTINGS::PAYMENTS:STRIPE:TEST_SECRET',
'value' => $this->getNewValue('test_secret_key'),
'type' => 'string',
'description' => 'The Test Secret Key of your Stripe App'
],
[
'key' => 'SETTINGS::PAYMENTS:STRIPE:ENDPOINT_TEST_SECRET',
'value' => $this->getNewValue('test_endpoint_secret'),
'type' => 'string',
'description' => 'The Test Endpoint Secret of your Stripe App'
]
]);
$this->migrator->delete('stripe.secret_key');
$this->migrator->delete('stripe.endpoint_secret');
$this->migrator->delete('stripe.enabled');
$this->migrator->delete('stripe.test_secret_key');
$this->migrator->delete('stripe.test_endpoint_secret');
}
public function getNewValue(string $name)
{
$new_value = DB::table('settings')->where([['group', '=', 'stripe'], ['name', '=', $name]])->get(['payload'])->first();
// Some keys returns '""' as a value.
if ($new_value->payload === '""') {
return null;
}
// remove the quotes from the string
if (substr($new_value->payload, 0, 1) === '"' && substr($new_value->payload, -1) === '"') {
return substr($new_value->payload, 1, -1);
}
return $new_value->payload;
}
public function getOldValue(string $key)
{
// Always get the first value of the key.
$old_value = DB::table('settings_old')->where('key', '=', $key)->get(['value', 'type'])->first();
// Handle the old values to return without it being a string in all cases.
if ($old_value->type === "string" || $old_value->type === "text") {
if (is_null($old_value->value)) {
return '';
}
// Some values have the type string, but their values are boolean.
if ($old_value->value === "false" || $old_value->value === "true") {
return filter_var($old_value->value, FILTER_VALIDATE_BOOL);
}
return $old_value->value;
}
if ($old_value->type === "boolean") {
return filter_var($old_value->value, FILTER_VALIDATE_BOOL);
}
return filter_var($old_value->value, FILTER_VALIDATE_INT);
}
}

View file

@ -1,17 +1,17 @@
<?php
use Illuminate\Support\Facades\Route;
use App\Extensions\PaymentGateways\Stripe\StripeExtension;
include_once(__DIR__ . '/index.php');
Route::middleware(['web', 'auth'])->group(function () {
Route::get('payment/StripePay/{shopProduct}', function () {
StripePay(request());
StripeExtension::StripePay(request());
})->name('payment.StripePay');
Route::get(
'payment/StripeSuccess',
function () {
StripeSuccess(request());
StripeExtension::StripeSuccess(request());
}
)->name('payment.StripeSuccess');
});
@ -19,5 +19,5 @@ Route::middleware(['web', 'auth'])->group(function () {
// Stripe WebhookRoute -> validation in Route Handler
Route::post('payment/StripeWebhooks', function () {
StripeWebhooks(request());
StripeExtension::StripeWebhooks(request());
})->name('payment.StripeWebhooks');

View file

@ -0,0 +1,9 @@
<?php
namespace App\Helpers;
// create a abstract class for the extension that will contain all the methods that will be used in the extension
abstract class AbstractExtension
{
abstract public static function getConfig(): array;
}

View file

@ -2,65 +2,14 @@
namespace App\Helpers;
/**
* Summary of ExtensionHelper
*/
class ExtensionHelper
{
/**
* Get a config of an extension by its name
* @param string $extensionName
* @param string $configname
*/
public static function getExtensionConfig(string $extensionName, string $configname)
{
$extensions = ExtensionHelper::getAllExtensions();
// call the getConfig function of the config file of the extension like that
// call_user_func("App\\Extensions\\PaymentGateways\\Stripe" . "\\getConfig");
foreach ($extensions as $extension) {
if (!(basename($extension) == $extensionName)) {
continue;
}
$configFile = $extension . '/config.php';
if (file_exists($configFile)) {
include_once $configFile;
$config = call_user_func('App\\Extensions\\' . basename(dirname($extension)) . '\\' . basename($extension) . "\\getConfig");
}
if (isset($config[$configname])) {
return $config[$configname];
}
}
return null;
}
public static function getAllCsrfIgnoredRoutes()
{
$extensions = ExtensionHelper::getAllExtensions();
$routes = [];
foreach ($extensions as $extension) {
$configFile = $extension . '/config.php';
if (file_exists($configFile)) {
include_once $configFile;
$config = call_user_func('App\\Extensions\\' . basename(dirname($extension)) . '\\' . basename($extension) . "\\getConfig");
}
if (isset($config['RoutesIgnoreCsrf'])) {
$routes = array_merge($routes, $config['RoutesIgnoreCsrf']);
}
// map over the routes and add the extension name as prefix
$result = array_map(fn ($item) => "extensions/{$item}", $routes);
}
return $result;
}
/**
* Get all extensions
* @return array
* @return array array of all extensions e.g. ["App\Extensions\PayPal", "App\Extensions\Stripe"]
*/
public static function getAllExtensions()
{
@ -69,14 +18,195 @@ class ExtensionHelper
foreach ($extensionNamespaces as $extensionNamespace) {
$extensions = array_merge($extensions, glob($extensionNamespace . '/*', GLOB_ONLYDIR));
}
// remove base path from every extension but keep app/Extensions/...
$extensions = array_map(fn ($item) => str_replace('/', '\\', str_replace(app_path() . '/', 'App/', $item)), $extensions);
return $extensions;
}
/**
* Get all extensions by namespace
* @param string $namespace case sensitive namespace of the extension e.g. PaymentGateways
* @return array array of all extensions e.g. ["App\Extensions\PayPal", "App\Extensions\Stripe"]
*/
public static function getAllExtensionsByNamespace(string $namespace)
{
$extensions = glob(app_path() . '/Extensions/' . $namespace . '/*', GLOB_ONLYDIR);
// remove base path from every extension but keep app/Extensions/...
$extensions = array_map(fn ($item) => str_replace('/', '\\', str_replace(app_path() . '/', 'App/', $item)), $extensions);
return $extensions;
}
/**
* Get an extension by its name
* @param string $extensionName case sensitive name of the extension e.g. PayPal
* @return string|null the path of the extension e.g. App\Extensions\PayPal
*/
public static function getExtension(string $extensionName)
{
$extensions = self::getAllExtensions();
// filter the extensions by the extension name
$extensions = array_filter($extensions, fn ($item) => basename($item) == $extensionName);
// return the only extension
return array_shift($extensions);
}
/**
* Get all extension classes
* @return array array of all extension classes e.g. ["App\Extensions\PayPal\PayPalExtension", "App\Extensions\Stripe\StripeExtension"]
*/
public static function getAllExtensionClasses()
{
$extensions = self::getAllExtensions();
// add the ExtensionClass to the end of the namespace
$extensions = array_map(fn ($item) => $item . '\\' . basename($item) . 'Extension', $extensions);
// filter out non existing extension classes
$extensions = array_filter($extensions, fn ($item) => class_exists($item));
return $extensions;
}
/**
* Get all extension classes by namespace
* @param string $namespace case sensitive namespace of the extension e.g. PaymentGateways
* @return array array of all extension classes e.g. ["App\Extensions\PayPal\PayPalExtension", "App\Extensions\Stripe\StripeExtension"]
*/
public static function getAllExtensionClassesByNamespace(string $namespace)
{
$extensions = self::getAllExtensionsByNamespace($namespace);
// add the ExtensionClass to the end of the namespace
$extensions = array_map(fn ($item) => $item . '\\' . basename($item) . 'Extension', $extensions);
// filter out non existing extension classes
$extensions = array_filter($extensions, fn ($item) => class_exists($item));
return $extensions;
}
/**
* Get the class of an extension by its name
* @param string $extensionName case sensitive name of the extension e.g. PayPal
* @return string|null the class name of the extension e.g. App\Extensions\PayPal\PayPalExtension
*/
public static function getExtensionClass(string $extensionName)
{
$extensions = self::getAllExtensions();
foreach ($extensions as $extension) {
if (!(basename($extension) == $extensionName)) {
continue;
}
$extensionClass = $extension . '\\' . $extensionName . 'Extension';
return $extensionClass;
}
}
/**
* Get a config of an extension by its name
* @param string $extensionName
* @param string $configname
*/
public static function getExtensionConfig(string $extensionName, string $configname)
{
$extension = self::getExtensionClass($extensionName);
$config = $extension::getConfig();
if (isset($config[$configname])) {
return $config[$configname];
}
return null;
}
public static function getAllCsrfIgnoredRoutes()
{
$extensions = self::getAllExtensionClasses();
$routes = [];
foreach ($extensions as $extension) {
$config = $extension::getConfig();
if (isset($config['RoutesIgnoreCsrf'])) {
$routes = array_merge($routes, $config['RoutesIgnoreCsrf']);
}
}
// map over the routes and add the extension name as prefix
$result = array_map(fn ($item) => "extensions/{$item}", $routes);
return $result;
}
/**
* Summary of getAllExtensionMigrations
* @return array of all migration paths look like: app/Extensions/ExtensionNamespace/ExtensionName/migrations/
*/
public static function getAllExtensionMigrations()
{
$extensions = self::getAllExtensions();
// Transform the extensions to a path
$extensions = array_map(fn ($item) => self::extensionNameToPath($item), $extensions);
// get all migration directories of the extensions and return them as array
$migrations = [];
foreach ($extensions as $extension) {
$migrationDir = $extension . '/migrations';
if (file_exists($migrationDir)) {
$migrations[] = $migrationDir;
}
}
return $migrations;
}
/**
* Summary of getAllExtensionSettings
* @return array of all setting classes look like: App\Extensions\PaymentGateways\PayPal\PayPalSettings
*/
public static function getAllExtensionSettingsClasses()
{
$extensions = self::getAllExtensions();
$settings = [];
foreach ($extensions as $extension) {
$extensionName = basename($extension);
$settingsClass = $extension . '\\' . $extensionName . 'Settings';
if (class_exists($settingsClass)) {
$settings[] = $settingsClass;
}
}
return $settings;
}
public static function getExtensionSettings(string $extensionName)
{
$extension = self::getExtension($extensionName);
$settingClass = $extension . '\\' . $extensionName . 'Settings';
if (class_exists($settingClass)) {
return new $settingClass();
}
}
/**
* Transforms a extension name to a path
* @param string $extensionName e.g. App\Extensions\PaymentGateways\PayPal
* @return string e.g. C:\xampp\htdocs\laravel\app/Extensions/PaymentGateways/PayPal
*/
private static function extensionNameToPath(string $extensionName)
{
return app_path() . '/' . str_replace('\\', '/', str_replace('App\\', '', $extensionName));
}
}

View file

@ -4,6 +4,7 @@ namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\ApplicationApi;
use App\Settings\LocaleSettings;
use Exception;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\View\Factory;
@ -20,9 +21,11 @@ class ApplicationApiController extends Controller
*
* @return Application|Factory|View|Response
*/
public function index()
public function index(LocaleSettings $locale_settings)
{
return view('admin.api.index');
return view('admin.api.index', [
'locale_datatables' => $locale_settings->datatables
]);
}
/**

View file

@ -15,7 +15,7 @@ class InvoiceController extends Controller
$zip = new ZipArchive;
$zip_safe_path = storage_path('invoices.zip');
$res = $zip->open($zip_safe_path, ZipArchive::CREATE | ZipArchive::OVERWRITE);
$result = $this::rglob(storage_path('app/invoice/*'));
$result = $this->rglob(storage_path('app/invoice/*'));
if ($res === true) {
$zip->addFromString('1. Info.txt', __('Created at').' '.now()->format('d.m.Y'));
foreach ($result as $file) {
@ -38,7 +38,7 @@ class InvoiceController extends Controller
{
$files = glob($pattern, $flags);
foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR | GLOB_NOSORT) as $dir) {
$files = array_merge($files, $this::rglob($dir.'/'.basename($pattern), $flags));
$files = array_merge($files, $this->rglob($dir.'/'.basename($pattern), $flags));
}
return $files;

View file

@ -2,12 +2,14 @@
namespace App\Http\Controllers\Admin;
use App\Classes\Pterodactyl;
use App\Classes\PterodactylClient;
use App\Settings\PterodactylSettings;
use App\Settings\GeneralSettings;
use App\Http\Controllers\Controller;
use App\Models\Egg;
use App\Models\Location;
use App\Models\Nest;
use App\Models\Node;
use App\Models\Pterodactyl\Egg;
use App\Models\Pterodactyl\Location;
use App\Models\Pterodactyl\Nest;
use App\Models\Pterodactyl\Node;
use App\Models\Payment;
use App\Models\Product;
use App\Models\Server;
@ -19,7 +21,14 @@ class OverViewController extends Controller
{
public const TTL = 86400;
public function index()
private $pterodactyl;
public function __construct(PterodactylSettings $ptero_settings)
{
$this->pterodactyl = new PterodactylClient($ptero_settings);
}
public function index(GeneralSettings $general_settings)
{
//Get counters
$counters = collect();
@ -134,7 +143,7 @@ class OverViewController extends Controller
//Get node information and prepare collection
$pteroNodeIds = [];
foreach (Pterodactyl::getNodes() as $pteroNode) {
foreach ($this->pterodactyl->getNodes() as $pteroNode) {
array_push($pteroNodeIds, $pteroNode['attributes']['id']);
}
$nodes = collect();
@ -145,7 +154,7 @@ class OverViewController extends Controller
} //Check if node exists on pterodactyl too, if not, skip
$nodes->put($nodeId, collect());
$nodes[$nodeId]->name = $DBnode['name'];
$pteroNode = Pterodactyl::getNode($nodeId);
$pteroNode = $this->pterodactyl->getNode($nodeId);
$nodes[$nodeId]->usagePercent = round(max($pteroNode['allocated_resources']['memory'] / ($pteroNode['memory'] * ($pteroNode['memory_overallocate'] + 100) / 100), $pteroNode['allocated_resources']['disk'] / ($pteroNode['disk'] * ($pteroNode['disk_overallocate'] + 100) / 100)) * 100, 2);
$counters['totalUsagePercent'] += $nodes[$nodeId]->usagePercent;
@ -156,7 +165,7 @@ class OverViewController extends Controller
}
$counters['totalUsagePercent'] = ($DBnodes->count()) ? round($counters['totalUsagePercent'] / $DBnodes->count(), 2) : 0;
foreach (Pterodactyl::getServers() as $server) { //gets all servers from Pterodactyl and calculates total of credit usage for each node separately + total
foreach ($this->pterodactyl->getServers() as $server) { //gets all servers from Pterodactyl and calculates total of credit usage for each node separately + total
$nodeId = $server['attributes']['node'];
if ($CPServer = Server::query()->where('pterodactyl_id', $server['attributes']['id'])->first()) {
@ -207,6 +216,7 @@ class OverViewController extends Controller
'deletedNodesPresent' => ($DBnodes->count() != count($pteroNodeIds)) ? true : false,
'perPageLimit' => ($counters['servers']->total != Server::query()->count()) ? true : false,
'tickets' => $tickets,
'credits_display_name' => $general_settings->credits_display_name
]);
}

View file

@ -5,13 +5,17 @@ namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\PartnerDiscount;
use App\Models\User;
use App\Settings\LocaleSettings;
use App\Settings\ReferralSettings;
use Illuminate\Http\Request;
class PartnerController extends Controller
{
public function index()
public function index(LocaleSettings $locale_settings)
{
return view('admin.partners.index');
return view('admin.partners.index', [
'locale_datatables' => $locale_settings->datatables
]);
}
/**
@ -117,19 +121,19 @@ class PartnerController extends Controller
';
})
->addColumn('user', function (PartnerDiscount $partner) {
return ($user = User::where('id', $partner->user_id)->first()) ? '<a href="'.route('admin.users.show', $partner->user_id).'">'.$user->name.'</a>' : __('Unknown user');
return ($user = User::where('id', $partner->user_id)->first()) ? '<a href="'.route('admin.users.show', $partner->user_id) . '">' . $user->name . '</a>' : __('Unknown user');
})
->editColumn('created_at', function (PartnerDiscount $partner) {
return $partner->created_at ? $partner->created_at->diffForHumans() : '';
})
->editColumn('partner_discount', function (PartnerDiscount $partner) {
return $partner->partner_discount ? $partner->partner_discount.'%' : '0%';
return $partner->partner_discount ? $partner->partner_discount . '%' : '0%';
})
->editColumn('registered_user_discount', function (PartnerDiscount $partner) {
return $partner->registered_user_discount ? $partner->registered_user_discount.'%' : '0%';
return $partner->registered_user_discount ? $partner->registered_user_discount . '%' : '0%';
})
->editColumn('referral_system_commission', function (PartnerDiscount $partner) {
return $partner->referral_system_commission >= 0 ? $partner->referral_system_commission.'%' : __('Default').' ('.config('SETTINGS::REFERRAL:PERCENTAGE').'%)';
->editColumn('referral_system_commission', function (PartnerDiscount $partner, ReferralSettings $referral_settings) {
return $partner->referral_system_commission >= 0 ? $partner->referral_system_commission . '%' : __('Default') . ' ('.$referral_settings->percentage . '%)';
})
->rawColumns(['user', 'actions'])
->make();

View file

@ -18,17 +18,19 @@ use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Helpers\ExtensionHelper;
use App\Settings\GeneralSettings;
use App\Settings\LocaleSettings;
class PaymentController extends Controller
{
/**
* @return Application|Factory|View
*/
public function index()
public function index(LocaleSettings $locale_settings)
{
return view('admin.payments.index')->with([
'payments' => Payment::paginate(15),
'locale_datatables' => $locale_settings->datatables
]);
}
@ -37,7 +39,7 @@ class PaymentController extends Controller
* @param ShopProduct $shopProduct
* @return Application|Factory|View
*/
public function checkOut(ShopProduct $shopProduct)
public function checkOut(ShopProduct $shopProduct, GeneralSettings $general_settings)
{
$discount = PartnerDiscount::getDiscount();
$price = $shopProduct->price - ($shopProduct->price * $discount / 100);
@ -49,7 +51,10 @@ class PaymentController extends Controller
// build a paymentgateways array that contains the routes for the payment gateways and the image path for the payment gateway which lays in public/images/Extensions/PaymentGateways with the extensionname in lowercase
foreach ($extensions as $extension) {
$extensionName = basename($extension);
if (!ExtensionHelper::getExtensionConfig($extensionName, 'enabled')) continue; // skip if not enabled
$extensionSettings = ExtensionHelper::getExtensionSettings($extensionName);
if ($extensionSettings->enabled == false) continue;
$payment = new \stdClass();
$payment->name = ExtensionHelper::getExtensionConfig($extensionName, 'name');
@ -58,11 +63,6 @@ class PaymentController extends Controller
}
}
return view('store.checkout')->with([
'product' => $shopProduct,
'discountpercent' => $discount,
@ -73,6 +73,7 @@ class PaymentController extends Controller
'total' => $shopProduct->getTotalPrice(),
'paymentGateways' => $paymentGateways,
'productIsFree' => $price <= 0,
'credits_display_name' => $general_settings->credits_display_name
]);
}

View file

@ -3,9 +3,12 @@
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\Location;
use App\Models\Nest;
use App\Models\Pterodactyl\Location;
use App\Models\Pterodactyl\Nest;
use App\Models\Product;
use App\Settings\GeneralSettings;
use App\Settings\LocaleSettings;
use App\Settings\UserSettings;
use Exception;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\View\Factory;
@ -21,9 +24,11 @@ class ProductController extends Controller
*
* @return Application|Factory|View
*/
public function index()
public function index(LocaleSettings $locale_settings)
{
return view('admin.products.index');
return view('admin.products.index', [
'locale_datatables' => $locale_settings->datatables
]);
}
/**
@ -31,15 +36,16 @@ class ProductController extends Controller
*
* @return Application|Factory|View
*/
public function create()
public function create(GeneralSettings $general_settings)
{
return view('admin.products.create', [
'locations' => Location::with('nodes')->get(),
'nests' => Nest::with('eggs')->get(),
'credits_display_name' => $general_settings->credits_display_name
]);
}
public function clone(Request $request, Product $product)
public function clone(Product $product)
{
return view('admin.products.create', [
'product' => $product,
@ -90,11 +96,12 @@ class ProductController extends Controller
* @param Product $product
* @return Application|Factory|View
*/
public function show(Product $product)
public function show(Product $product, UserSettings $user_settings, GeneralSettings $general_settings)
{
return view('admin.products.show', [
'product' => $product,
'minimum_credits' => config('SETTINGS::USER:MINIMUM_REQUIRED_CREDITS_TO_MAKE_SERVER'),
'minimum_credits' => $user_settings->min_credits_to_make_server,
'credits_display_name' => $general_settings->credits_display_name
]);
}
@ -104,12 +111,13 @@ class ProductController extends Controller
* @param Product $product
* @return Application|Factory|View
*/
public function edit(Product $product)
public function edit(Product $product, GeneralSettings $general_settings)
{
return view('admin.products.edit', [
'product' => $product,
'locations' => Location::with('nodes')->get(),
'nests' => Nest::with('eggs')->get(),
'credits_display_name' => $general_settings->credits_display_name
]);
}
@ -157,7 +165,7 @@ class ProductController extends Controller
* @param Product $product
* @return RedirectResponse
*/
public function disable(Request $request, Product $product)
public function disable(Product $product)
{
$product->update(['disabled' => ! $product->disabled]);
@ -190,7 +198,6 @@ class ProductController extends Controller
public function dataTable()
{
$query = Product::with(['servers']);
return datatables($query)
->addColumn('actions', function (Product $product) {
return '
@ -219,18 +226,18 @@ class ProductController extends Controller
$checked = $product->disabled == false ? 'checked' : '';
return '
<form class="d-inline" onsubmit="return submitResult();" method="post" action="'.route('admin.products.disable', $product->id).'">
'.csrf_field().'
'.method_field('PATCH').'
<div class="custom-control custom-switch">
<input '.$checked.' name="disabled" onchange="this.form.submit()" type="checkbox" class="custom-control-input" id="switch'.$product->id.'">
<label class="custom-control-label" for="switch'.$product->id.'"></label>
</div>
</form>
<form class="d-inline" onsubmit="return submitResult();" method="post" action="'.route('admin.products.disable', $product->id).'">
'.csrf_field().'
'.method_field('PATCH').'
<div class="custom-control custom-switch">
<input '.$checked.' name="disabled" onchange="this.form.submit()" type="checkbox" class="custom-control-input" id="switch'.$product->id.'">
<label class="custom-control-label" for="switch'.$product->id.'"></label>
</div>
</form>
';
})
->editColumn('minimum_credits', function (Product $product) {
return $product->minimum_credits==-1 ? config('SETTINGS::USER:MINIMUM_REQUIRED_CREDITS_TO_MAKE_SERVER') : $product->minimum_credits;
->editColumn('minimum_credits', function (Product $product, UserSettings $user_settings) {
return $product->minimum_credits==-1 ? $user_settings->min_credits_to_make_server : $product->minimum_credits;
})
->editColumn('created_at', function (Product $product) {
return $product->created_at ? $product->created_at->diffForHumans() : '';

View file

@ -2,10 +2,12 @@
namespace App\Http\Controllers\Admin;
use App\Classes\Pterodactyl;
use App\Http\Controllers\Controller;
use App\Models\Server;
use App\Models\User;
use App\Settings\LocaleSettings;
use App\Settings\PterodactylSettings;
use App\Classes\PterodactylClient;
use Exception;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\View\Factory;
@ -18,14 +20,23 @@ use Illuminate\Support\Facades\Log;
class ServerController extends Controller
{
private $pterodactyl;
public function __construct(PterodactylSettings $ptero_settings)
{
$this->pterodactyl = new PterodactylClient($ptero_settings);
}
/**
* Display a listing of the resource.
*
* @return Application|Factory|View|Response
*/
public function index()
public function index(LocaleSettings $locale_settings)
{
return view('admin.servers.index');
return view('admin.servers.index', [
'locale_datatables' => $locale_settings->datatables
]);
}
/**
@ -65,7 +76,7 @@ class ServerController extends Controller
// try to update the owner on pterodactyl
try {
$response = Pterodactyl::updateServerOwner($server, $user->pterodactyl_id);
$response = $this->pterodactyl->updateServerOwner($server, $user->pterodactyl_id);
if ($response->getStatusCode() != 200) {
return redirect()->back()->with('error', 'Failed to update server owner on pterodactyl');
}
@ -118,7 +129,6 @@ class ServerController extends Controller
public function syncServers()
{
$pteroServers = Pterodactyl::getServers();
$CPServers = Server::get();
$CPIDArray = [];
@ -129,7 +139,7 @@ class ServerController extends Controller
}
}
foreach ($pteroServers as $server) { //go thru all ptero servers, if server exists, change value to true in array.
foreach ($this->pterodactyl->getServers() as $server) { //go thru all ptero servers, if server exists, change value to true in array.
if (isset($CPIDArray[$server['attributes']['id']])) {
$CPIDArray[$server['attributes']['id']] = true;
@ -149,7 +159,7 @@ class ServerController extends Controller
}, ARRAY_FILTER_USE_BOTH); //Array of servers, that dont exist on ptero (value == false)
$deleteCount = 0;
foreach ($filteredArray as $key => $CPID) { //delete servers that dont exist on ptero anymore
if (!Pterodactyl::getServerAttributes($key, true)) {
if (!$this->pterodactyl->getServerAttributes($key, true)) {
$deleteCount++;
}
}
@ -216,8 +226,8 @@ class ServerController extends Controller
->editColumn('suspended', function (Server $server) {
return $server->suspended ? $server->suspended->diffForHumans() : '';
})
->editColumn('name', function (Server $server) {
return '<a class="text-info" target="_blank" href="' . config('SETTINGS::SYSTEM:PTERODACTYL:URL') . '/admin/servers/view/' . $server->pterodactyl_id . '">' . strip_tags($server->name) . '</a>';
->editColumn('name', function (Server $server, PterodactylSettings $ptero_settings) {
return '<a class="text-info" target="_blank" href="' . $ptero_settings->panel_url . '/admin/servers/view/' . $server->pterodactyl_id . '">' . strip_tags($server->name) . '</a>';
})
->rawColumns(['user', 'actions', 'status', 'name'])
->make();

View file

@ -2,11 +2,15 @@
namespace App\Http\Controllers\Admin;
use App\Helpers\ExtensionHelper;
use App\Http\Controllers\Controller;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\View\Factory;
use Illuminate\Contracts\View\View;
use Illuminate\Http\Response;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Validator;
use Qirolab\Theme\Theme;
class SettingsController extends Controller
@ -19,37 +23,109 @@ class SettingsController extends Controller
public function index()
{
// get all other settings in app/Settings directory
// group items by file name like $categories
$settings = collect();
$settings_classes = [];
//Get all tabs as laravel view paths
$tabs = [];
if(file_exists(Theme::getViewPaths()[0] . '/admin/settings/tabs/')){
$tabspath = glob(Theme::getViewPaths()[0] . '/admin/settings/tabs/*.blade.php');
}else{
$tabspath = glob(Theme::path($path = 'views', $themeName = 'default').'/admin/settings/tabs/*.blade.php');
// get all app settings
$app_settings = scandir(app_path('Settings'));
$app_settings = array_diff($app_settings, ['.', '..']);
// append App\Settings to class name
foreach ($app_settings as $app_setting) {
$settings_classes[] = 'App\\Settings\\' . str_replace('.php', '', $app_setting);
}
// get all extension settings
$settings_files = array_merge($settings_classes, ExtensionHelper::getAllExtensionSettingsClasses());
foreach ($settings_files as $file) {
$className = $file;
// instantiate the class and call toArray method to get all options
$options = (new $className())->toArray();
// call getOptionInputData method to get all options
if (method_exists($className, 'getOptionInputData')) {
$optionInputData = $className::getOptionInputData();
} else {
$optionInputData = [];
}
// collect all option input data
$optionsData = [];
foreach ($options as $key => $value) {
$optionsData[$key] = [
'value' => $value,
'label' => $optionInputData[$key]['label'] ?? ucwords(str_replace('_', ' ', $key)),
'type' => $optionInputData[$key]['type'] ?? 'string',
'description' => $optionInputData[$key]['description'] ?? '',
'options' => $optionInputData[$key]['options'] ?? [],
];
}
// collect category icon if available
if (isset($optionInputData['category_icon'])) {
$optionsData['category_icon'] = $optionInputData['category_icon'];
}
$optionsData['settings_class'] = $className;
$settings[str_replace('Settings', '', class_basename($className))] = $optionsData;
}
foreach ($tabspath as $filename) {
$tabs[] = 'admin.settings.tabs.'.basename($filename, '.blade.php');
}
$settings->sort();
//Generate a html list item for each tab based on tabs file basename, set first tab as active
$tabListItems = [];
foreach ($tabs as $tab) {
$tabName = str_replace('admin.settings.tabs.', '', $tab);
$tabListItems[] = '<li class="nav-item">
<a class="nav-link '.(empty($tabListItems) ? 'active' : '').'" data-toggle="pill" href="#'.$tabName.'">
'.__(ucfirst($tabName)).'
</a></li>';
}
$themes = array_diff(scandir(base_path('themes')), array('..', '.'));
return view('admin.settings.index', [
'tabs' => $tabs,
'tabListItems' => $tabListItems,
'settings' => $settings->all(),
'themes' => $themes,
'active_theme' => Theme::active(),
]);
}
/**
* Update the specified resource in storage.
*
*/
public function update(Request $request)
{
$category = request()->get('category');
$settings_class = request()->get('settings_class');
if (method_exists($settings_class, 'getValidations')) {
$validations = $settings_class::getValidations();
} else {
$validations = [];
}
$validator = Validator::make($request->all(), $validations);
if ($validator->fails()) {
return Redirect::to('admin/settings' . '#' . $category)->withErrors($validator)->withInput();
}
$settingsClass = new $settings_class();
foreach ($settingsClass->toArray() as $key => $value) {
// Get the type of the settingsclass property
$rp = new \ReflectionProperty($settingsClass, $key);
$rpType = $rp->getType();
if ($rpType == 'bool') {
$settingsClass->$key = $request->has($key);
continue;
}
$nullable = $rpType->allowsNull();
if ($nullable) $settingsClass->$key = $request->input($key) ?? null;
else $settingsClass->$key = $request->input($key);
}
$settingsClass->save();
return Redirect::to('admin/settings' . '#' . $category)->with('success', 'Settings updated successfully.');
}
}

View file

@ -3,6 +3,8 @@
namespace App\Http\Controllers\Admin;
use App\Models\ShopProduct;
use App\Settings\GeneralSettings;
use App\Settings\LocaleSettings;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\View\Factory;
use Illuminate\Contracts\View\View;
@ -20,20 +22,14 @@ class ShopProductController extends Controller
*
* @return Application|Factory|View|Response
*/
public function index(Request $request)
public function index(LocaleSettings $locale_settings, GeneralSettings $general_settings)
{
$isPaymentSetup = false;
$isStoreEnabled = $general_settings->store_enabled;
if (
env('APP_ENV') == 'local' ||
config('SETTINGS::PAYMENTS:PAYPAL:SECRET') && config('SETTINGS::PAYMENTS:PAYPAL:CLIENT_ID') ||
config('SETTINGS::PAYMENTS:STRIPE:SECRET') && config('SETTINGS::PAYMENTS:STRIPE:ENDPOINT_SECRET') && config('SETTINGS::PAYMENTS:STRIPE:METHODS')
) {
$isPaymentSetup = true;
}
return view('admin.store.index', [
'isPaymentSetup' => $isPaymentSetup,
'isStoreEnabled' => $isStoreEnabled,
'locale_datatables' => $locale_settings->datatables
]);
}
@ -42,10 +38,11 @@ class ShopProductController extends Controller
*
* @return Application|Factory|View|Response
*/
public function create()
public function create(GeneralSettings $general_settings)
{
return view('admin.store.create', [
'currencyCodes' => config('currency_codes'),
'credits_display_name' => $general_settings->credits_display_name
]);
}
@ -79,11 +76,12 @@ class ShopProductController extends Controller
* @param ShopProduct $shopProduct
* @return Application|Factory|View|Response
*/
public function edit(ShopProduct $shopProduct)
public function edit(ShopProduct $shopProduct, GeneralSettings $general_settings)
{
return view('admin.store.edit', [
'currencyCodes' => config('currency_codes'),
'shopProduct' => $shopProduct,
'credits_display_name' => $general_settings->credits_display_name
]);
}
@ -117,7 +115,7 @@ class ShopProductController extends Controller
* @param ShopProduct $shopProduct
* @return RedirectResponse
*/
public function disable(Request $request, ShopProduct $shopProduct)
public function disable(ShopProduct $shopProduct)
{
$shopProduct->update(['disabled' => !$shopProduct->disabled]);

View file

@ -5,6 +5,7 @@ namespace App\Http\Controllers\Admin;
use App\Enums\UsefulLinkLocation;
use App\Http\Controllers\Controller;
use App\Models\UsefulLink;
use App\Settings\LocaleSettings;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\View\Factory;
use Illuminate\Contracts\View\View;
@ -19,9 +20,11 @@ class UsefulLinkController extends Controller
*
* @return Application|Factory|View|Response
*/
public function index()
public function index(LocaleSettings $locale_settings)
{
return view('admin.usefullinks.index');
return view('admin.usefullinks.index', [
'locale_datatables' => $locale_settings->datatables
]);
}
/**

View file

@ -2,11 +2,14 @@
namespace App\Http\Controllers\Admin;
use App\Classes\Pterodactyl;
use App\Events\UserUpdateCreditsEvent;
use App\Http\Controllers\Controller;
use App\Models\User;
use App\Notifications\DynamicNotification;
use App\Settings\LocaleSettings;
use App\Settings\PterodactylSettings;
use App\Classes\PterodactylClient;
use App\Settings\GeneralSettings;
use Exception;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\View\Factory;
@ -26,12 +29,11 @@ use Spatie\QueryBuilder\QueryBuilder;
class UserController extends Controller
{
private $pterodactyl;
private Pterodactyl $pterodactyl;
public function __construct(Pterodactyl $pterodactyl)
public function __construct(PterodactylSettings $ptero_settings)
{
$this->pterodactyl = $pterodactyl;
$this->pterodactyl = new PterodactylClient($ptero_settings);
}
/**
@ -40,9 +42,12 @@ class UserController extends Controller
* @param Request $request
* @return Application|Factory|View|Response
*/
public function index(Request $request)
public function index(LocaleSettings $locale_settings, GeneralSettings $general_settings)
{
return view('admin.users.index');
return view('admin.users.index', [
'locale_datatables' => $locale_settings->datatables,
'credits_display_name' => $general_settings->credits_display_name
]);
}
/**
@ -51,7 +56,7 @@ class UserController extends Controller
* @param User $user
* @return Application|Factory|View|Response
*/
public function show(User $user)
public function show(User $user, LocaleSettings $locale_settings, GeneralSettings $general_settings)
{
//QUERY ALL REFERRALS A USER HAS
//i am not proud of this at all.
@ -65,6 +70,8 @@ class UserController extends Controller
return view('admin.users.show')->with([
'user' => $user,
'referrals' => $allReferals,
'locale_datatables' => $locale_settings->datatables,
'credits_display_name' => $general_settings->credits_display_name
]);
}
@ -99,10 +106,11 @@ class UserController extends Controller
* @param User $user
* @return Application|Factory|View|Response
*/
public function edit(User $user)
public function edit(User $user, GeneralSettings $general_settings)
{
return view('admin.users.edit')->with([
'user' => $user,
'credits_display_name' => $general_settings->credits_display_name
]);
}
@ -158,6 +166,10 @@ class UserController extends Controller
*/
public function destroy(User $user)
{
if ($user->role === 'admin' && User::query()->where('role', 'admin')->count() === 1) {
return redirect()->back()->with('error', __('You can not delete the last admin!'));
}
$user->delete();
return redirect()->back()->with('success', __('user has been removed!'));
@ -169,7 +181,7 @@ class UserController extends Controller
* @param User $user
* @return RedirectResponse
*/
public function verifyEmail(Request $request, User $user)
public function verifyEmail(User $user)
{
$user->verifyEmail();
@ -207,7 +219,7 @@ class UserController extends Controller
* @param User $user
* @return Application|Factory|View|Response
*/
public function notifications(User $user)
public function notifications()
{
return view('admin.users.notifications');
}
@ -248,7 +260,11 @@ class UserController extends Controller
}
$all = $data['all'] ?? false;
$users = $all ? User::all() : User::whereIn('id', $data['users'])->get();
Notification::send($users, new DynamicNotification($data['via'], $database, $mail));
try {
Notification::send($users, new DynamicNotification($data['via'], $database, $mail));
} catch (Exception $e) {
return redirect()->route('admin.users.notifications')->with('error', __('The attempt to send the email failed with the error: ' . $e->getMessage()));
}
return redirect()->route('admin.users.notifications')->with('success', __('Notification sent!'));
}
@ -333,8 +349,8 @@ class UserController extends Controller
->editColumn('last_seen', function (User $user) {
return $user->last_seen ? $user->last_seen->diffForHumans() : __('Never');
})
->editColumn('name', function (User $user) {
return '<a class="text-info" target="_blank" href="' . config('SETTINGS::SYSTEM:PTERODACTYL:URL') . '/admin/users/view/' . $user->pterodactyl_id . '">' . strip_tags($user->name) . '</a>';
->editColumn('name', function (User $user, PterodactylSettings $ptero_settings) {
return '<a class="text-info" target="_blank" href="' . $ptero_settings->panel_url . '/admin/users/view/' . $user->pterodactyl_id . '">' . strip_tags($user->name) . '</a>';
})
->rawColumns(['avatar', 'name', 'credits', 'role', 'usage', 'actions'])
->make();

View file

@ -6,6 +6,8 @@ use App\Events\UserUpdateCreditsEvent;
use App\Http\Controllers\Controller;
use App\Models\User;
use App\Models\Voucher;
use App\Settings\GeneralSettings;
use App\Settings\LocaleSettings;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\View\Factory;
use Illuminate\Contracts\View\View;
@ -22,9 +24,12 @@ class VoucherController extends Controller
*
* @return Application|Factory|View
*/
public function index()
public function index(LocaleSettings $locale_settings, GeneralSettings $general_settings)
{
return view('admin.vouchers.index');
return view('admin.vouchers.index', [
'locale_datatables' => $locale_settings->datatables,
'credits_display_name' => $general_settings->credits_display_name
]);
}
/**
@ -32,9 +37,11 @@ class VoucherController extends Controller
*
* @return Application|Factory|View
*/
public function create()
public function create(GeneralSettings $general_settings)
{
return view('admin.vouchers.create');
return view('admin.vouchers.create', [
'credits_display_name' => $general_settings->credits_display_name
]);
}
/**
@ -75,10 +82,11 @@ class VoucherController extends Controller
* @param Voucher $voucher
* @return Application|Factory|View
*/
public function edit(Voucher $voucher)
public function edit(Voucher $voucher, GeneralSettings $general_settings)
{
return view('admin.vouchers.edit', [
'voucher' => $voucher,
'credits_display_name' => $general_settings->credits_display_name
]);
}
@ -117,10 +125,12 @@ class VoucherController extends Controller
return redirect()->back()->with('success', __('voucher has been removed!'));
}
public function users(Voucher $voucher)
public function users(Voucher $voucher, LocaleSettings $locale_settings, GeneralSettings $general_settings)
{
return view('admin.vouchers.users', [
'voucher' => $voucher,
'locale_datatables' => $locale_settings->datatables,
'credits_display_name' => $general_settings->credits_display_name
]);
}
@ -130,7 +140,7 @@ class VoucherController extends Controller
*
* @throws ValidationException
*/
public function redeem(Request $request)
public function redeem(Request $request, GeneralSettings $general_settings)
{
//general validations
$request->validate([
@ -161,7 +171,7 @@ class VoucherController extends Controller
if ($request->user()->credits + $voucher->credits >= 99999999) {
throw ValidationException::withMessages([
'code' => "You can't redeem this voucher because you would exceed the limit of ".CREDITS_DISPLAY_NAME,
'code' => "You can't redeem this voucher because you would exceed the limit of " . $general_settings->credits_display_name,
]);
}
@ -171,7 +181,7 @@ class VoucherController extends Controller
event(new UserUpdateCreditsEvent($request->user()));
return response()->json([
'success' => "{$voucher->credits} ".CREDITS_DISPLAY_NAME.' '.__('have been added to your balance!'),
'success' => "{$voucher->credits} ". $general_settings->credits_display_name .' '.__('have been added to your balance!'),
]);
}

View file

@ -14,6 +14,7 @@ use Illuminate\Support\Facades\Notification;
use Illuminate\Support\HtmlString;
use Illuminate\Validation\ValidationException;
use Spatie\ValidationRules\Rules\Delimited;
use Exception;
class NotificationController extends Controller
{
@ -104,8 +105,12 @@ class NotificationController extends Controller
'users' => ['No users found!'],
]);
}
Notification::send($users, new DynamicNotification($via, $database, $mail));
try {
Notification::send($users, new DynamicNotification($via, $database, $mail));
}
catch (Exception $e) {
return response()->json(['message' => 'The attempt to send the email failed with the error: ' . $e->getMessage()], 500);
}
return response()->json(['message' => 'Notification successfully sent.', 'user_count' => $users->count()]);
}

View file

@ -2,13 +2,16 @@
namespace App\Http\Controllers\Api;
use App\Classes\Pterodactyl;
use App\Events\UserUpdateCreditsEvent;
use App\Http\Controllers\Controller;
use App\Models\DiscordUser;
use App\Models\User;
use App\Notifications\ReferralNotification;
use App\Traits\Referral;
use App\Settings\PterodactylSettings;
use App\Classes\PterodactylClient;
use App\Settings\ReferralSettings;
use App\Settings\UserSettings;
use Carbon\Carbon;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
@ -34,6 +37,13 @@ class UserController extends Controller
const ALLOWED_FILTERS = ['name', 'server_limit', 'email', 'pterodactyl_id', 'role', 'suspended'];
private $pterodactyl;
public function __construct(PterodactylSettings $ptero_settings)
{
$this->pterodactyl = new PterodactylClient($ptero_settings);
}
/**
* Display a listing of the resource.
*
@ -95,7 +105,7 @@ class UserController extends Controller
//Update Users Password on Pterodactyl
//Username,Mail,First and Lastname are required aswell
$response = Pterodactyl::client()->patch('/application/users/' . $user->pterodactyl_id, [
$response = $this->pterodactyl->application->patch('/application/users/' . $user->pterodactyl_id, [
'username' => $request->name,
'first_name' => $request->name,
'last_name' => $request->name,
@ -203,7 +213,7 @@ class UserController extends Controller
*
* @throws ValidationException
*/
public function suspend(Request $request, int $id)
public function suspend(int $id)
{
$discordUser = DiscordUser::find($id);
$user = $discordUser ? $discordUser->user : User::findOrFail($id);
@ -227,7 +237,7 @@ class UserController extends Controller
*
* @throws ValidationException
*/
public function unsuspend(Request $request, int $id)
public function unsuspend(int $id)
{
$discordUser = DiscordUser::find($id);
$user = $discordUser ? $discordUser->user : User::findOrFail($id);
@ -246,7 +256,7 @@ class UserController extends Controller
/**
* @throws ValidationException
*/
public function store(Request $request)
public function store(Request $request, UserSettings $user_settings, ReferralSettings $referral_settings)
{
$request->validate([
'name' => ['required', 'string', 'max:30', 'min:4', 'alpha_num', 'unique:users'],
@ -255,7 +265,7 @@ class UserController extends Controller
]);
// Prevent the creation of new users via API if this is enabled.
if (!config('SETTINGS::SYSTEM:CREATION_OF_NEW_USERS', 'true')) {
if (!$user_settings->creation_enabled) {
throw ValidationException::withMessages([
'error' => 'The creation of new users has been blocked by the system administrator.',
]);
@ -264,13 +274,13 @@ class UserController extends Controller
$user = User::create([
'name' => $request->input('name'),
'email' => $request->input('email'),
'credits' => config('SETTINGS::USER:INITIAL_CREDITS', 150),
'server_limit' => config('SETTINGS::USER:INITIAL_SERVER_LIMIT', 1),
'credits' => $user_settings->initial_credits,
'server_limit' => $user_settings->initial_server_limit,
'password' => Hash::make($request->input('password')),
'referral_code' => $this->createReferralCode(),
]);
$response = Pterodactyl::client()->post('/application/users', [
$response = $this->pterodactyl->application->post('/application/users', [
'external_id' => App::environment('local') ? Str::random(16) : (string) $user->id,
'username' => $user->name,
'email' => $user->email,
@ -297,8 +307,8 @@ class UserController extends Controller
$ref_code = $request->input('referral_code');
$new_user = $user->id;
if ($ref_user = User::query()->where('referral_code', '=', $ref_code)->first()) {
if (config('SETTINGS::REFERRAL:MODE') == 'register' || config('SETTINGS::REFERRAL:MODE') == 'both') {
$ref_user->increment('credits', config('SETTINGS::REFERRAL::REWARD'));
if ($referral_settings->mode === 'register' || $referral_settings->mode === 'both') {
$ref_user->increment('credits', $referral_settings->reward);
$ref_user->notify(new ReferralNotification($ref_user->id, $new_user));
}
//INSERT INTO USER_REFERRALS TABLE

View file

@ -3,6 +3,7 @@
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Settings\GeneralSettings;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
use Illuminate\Http\Request;
@ -31,13 +32,13 @@ class ForgotPasswordController extends Controller
$this->middleware('guest');
}
protected function validateEmail(Request $request)
protected function validateEmail(Request $request, GeneralSettings $general_settings)
{
$this->validate($request, [
'email' => ['required', 'string', 'email', 'max:255'],
]);
if (config('SETTINGS::RECAPTCHA:ENABLED') == 'true') {
if ($general_settings->recaptcha_enabled) {
$this->validate($request, [
'g-recaptcha-response' => 'required|recaptcha',
]);

View file

@ -4,6 +4,7 @@ namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use App\Settings\GeneralSettings;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
@ -53,13 +54,13 @@ class LoginController extends Controller
return $field;
}
public function login(Request $request)
public function login(Request $request, GeneralSettings $general_settings)
{
$validationRules = [
$this->username() => 'required|string',
'password' => 'required|string',
];
if (config('SETTINGS::RECAPTCHA:ENABLED') == 'true') {
if ($general_settings->recaptcha_enabled) {
$validationRules['g-recaptcha-response'] = ['required', 'recaptcha'];
}
$request->validate($validationRules);

View file

@ -2,13 +2,18 @@
namespace App\Http\Controllers\Auth;
use App\Classes\Pterodactyl;
use App\Http\Controllers\Controller;
use App\Models\User;
use App\Notifications\ReferralNotification;
use App\Providers\RouteServiceProvider;
use App\Traits\Referral;
use Carbon\Carbon;
use App\Settings\PterodactylSettings;
use App\Classes\PterodactylClient;
use App\Settings\GeneralSettings;
use App\Settings\ReferralSettings;
use App\Settings\UserSettings;
use App\Settings\WebsiteSettings;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\DB;
@ -20,6 +25,24 @@ use Illuminate\Validation\ValidationException;
class RegisterController extends Controller
{
private $pterodactyl;
private $credits_display_name;
private $recaptcha_enabled;
private $website_show_tos;
private $register_ip_check;
private $initial_credits;
private $initial_server_limit;
private $referral_mode;
private $referral_reward;
/*
|--------------------------------------------------------------------------
| Register Controller
@ -45,9 +68,18 @@ class RegisterController extends Controller
*
* @return void
*/
public function __construct()
public function __construct(PterodactylSettings $ptero_settings, GeneralSettings $general_settings, WebsiteSettings $website_settings, UserSettings $user_settings, ReferralSettings $referral_settings)
{
$this->middleware('guest');
$this->pterodactyl = new PterodactylClient($ptero_settings);
$this->credits_display_name = $general_settings->credits_display_name;
$this->recaptcha_enabled = $general_settings->recaptcha_enabled;
$this->website_show_tos = $website_settings->show_tos;
$this->register_ip_check = $user_settings->register_ip_check;
$this->initial_credits = $user_settings->initial_credits;
$this->initial_server_limit = $user_settings->initial_server_limit;
$this->referral_mode = $referral_settings->mode;
$this->referral_reward = $referral_settings->reward;
}
/**
@ -63,14 +95,14 @@ class RegisterController extends Controller
'email' => ['required', 'string', 'email', 'max:64', 'unique:users'],
'password' => ['required', 'string', 'min:8', 'confirmed'],
];
if (config('SETTINGS::RECAPTCHA:ENABLED') == 'true') {
if ($this->recaptcha_enabled) {
$validationRules['g-recaptcha-response'] = ['required', 'recaptcha'];
}
if (config('SETTINGS::SYSTEM:SHOW_TOS') == 'true') {
if ($this->website_show_tos) {
$validationRules['terms'] = ['required'];
}
if (config('SETTINGS::SYSTEM:REGISTER_IP_CHECK', 'true') == 'true') {
if ($this->register_ip_check) {
//check if ip has already made an account
$data['ip'] = session()->get('ip') ?? request()->ip();
@ -99,15 +131,16 @@ class RegisterController extends Controller
$user = User::create([
'name' => $data['name'],
'email' => $data['email'],
'credits' => config('SETTINGS::USER:INITIAL_CREDITS', 150),
'server_limit' => config('SETTINGS::USER:INITIAL_SERVER_LIMIT', 1),
'credits' => $this->initial_credits,
'server_limit' => $this->initial_server_limit,
'password' => Hash::make($data['password']),
'referral_code' => $this->createReferralCode(),
'pterodactyl_id' => Str::uuid(),
]);
$response = Pterodactyl::client()->post('/application/users', [
'external_id' => App::environment('local') ? Str::random(16) : (string) $user->id,
$response = $this->pterodactyl->application->post('/application/users', [
'external_id' => $user->pterodactyl_id,
'username' => $user->name,
'email' => $user->email,
'first_name' => $user->name,
@ -125,24 +158,23 @@ class RegisterController extends Controller
]);
}
$user->update([
'pterodactyl_id' => $response->json()['attributes']['id'],
]);
// delete activity log for user creation where description = 'created' or 'deleted' and subject_id = user_id
DB::table('activity_log')->where('description', 'created')->orWhere('description', 'deleted')->where('subject_id', $user->id)->delete();
//INCREMENT REFERRAL-USER CREDITS
if (!empty($data['referral_code'])) {
$ref_code = $data['referral_code'];
$new_user = $user->id;
if ($ref_user = User::query()->where('referral_code', '=', $ref_code)->first()) {
if (config('SETTINGS::REFERRAL:MODE') == 'sign-up' || config('SETTINGS::REFERRAL:MODE') == 'both') {
$ref_user->increment('credits', config('SETTINGS::REFERRAL::REWARD'));
if ($this->referral_mode === 'sign-up' || $this->referral_mode === 'both') {
$ref_user->increment('credits', $this->referral_reward);
$ref_user->notify(new ReferralNotification($ref_user->id, $new_user));
//LOGS REFERRALS IN THE ACTIVITY LOG
activity()
->performedOn($user)
->causedBy($ref_user)
->log('gained ' . config('SETTINGS::REFERRAL::REWARD') . ' ' . config('SETTINGS::SYSTEM:CREDITS_DISPLAY_NAME') . ' for sign-up-referral of ' . $user->name . ' (ID:' . $user->id . ')');
->log('gained ' . $this->referral_reward . ' ' . $this->credits_display_name . ' for sign-up-referral of ' . $user->name . ' (ID:' . $user->id . ')');
}
//INSERT INTO USER_REFERRALS TABLE
DB::table('user_referrals')->insert([

View file

@ -5,22 +5,24 @@ namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Models\DiscordUser;
use App\Models\User;
use App\Settings\DiscordSettings;
use App\Settings\UserSettings;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Http;
use Laravel\Socialite\Facades\Socialite;
class SocialiteController extends Controller
{
public function redirect()
public function redirect(DiscordSettings $discord_settings)
{
$scopes = ! empty(config('SETTINGS::DISCORD:BOT_TOKEN')) && ! empty(config('SETTINGS::DISCORD:GUILD_ID')) ? ['guilds.join'] : [];
$scopes = !empty($discord_settings->bot_token) && !empty($discord_settings->guild_id) ? ['guilds.join'] : [];
return Socialite::driver('discord')
->scopes($scopes)
->redirect();
}
public function callback()
public function callback(DiscordSettings $discord_settings, UserSettings $user_settings)
{
if (Auth::guest()) {
return abort(500);
@ -29,9 +31,9 @@ class SocialiteController extends Controller
/** @var User $user */
$user = Auth::user();
$discord = Socialite::driver('discord')->user();
$botToken = config('SETTINGS::DISCORD:BOT_TOKEN');
$guildId = config('SETTINGS::DISCORD:GUILD_ID');
$roleId = config('SETTINGS::DISCORD:ROLE_ID');
$botToken = $discord_settings->bot_token;
$guildId = $discord_settings->guild_id;
$roleId = $discord_settings->role_id;
//save / update discord_users
@ -49,8 +51,8 @@ class SocialiteController extends Controller
DiscordUser::create(array_merge($discord->user, ['user_id' => Auth::user()->id]));
//update user
Auth::user()->increment('credits', config('SETTINGS::USER:CREDITS_REWARD_AFTER_VERIFY_DISCORD'));
Auth::user()->increment('server_limit', config('SETTINGS::USER:SERVER_LIMIT_REWARD_AFTER_VERIFY_DISCORD'));
Auth::user()->increment('credits', $user_settings->credits_reward_after_verify_discord);
Auth::user()->increment('server_limit', $user_settings->server_limit_after_verify_discord);
Auth::user()->update(['discord_verified_at' => now()]);
} else {
$user->discordUser->update($discord->user);

View file

@ -4,7 +4,9 @@ namespace App\Http\Controllers;
use App\Models\PartnerDiscount;
use App\Models\UsefulLink;
use Illuminate\Http\Request;
use App\Settings\GeneralSettings;
use App\Settings\WebsiteSettings;
use App\Settings\ReferralSettings;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
@ -89,7 +91,7 @@ class HomeController extends Controller
}
/** Show the application dashboard. */
public function index(Request $request)
public function index(GeneralSettings $general_settings, WebsiteSettings $website_settings, ReferralSettings $referral_settings)
{
$usage = Auth::user()->creditUsage();
$credits = Auth::user()->Credits();
@ -120,6 +122,9 @@ class HomeController extends Controller
'numberOfReferrals' => DB::table('user_referrals')->where('referral_id', '=', Auth::user()->id)->count(),
'partnerDiscount' => PartnerDiscount::where('user_id', Auth::user()->id)->first(),
'myDiscount' => PartnerDiscount::getDiscount(),
'general_settings' => $general_settings,
'website_settings' => $website_settings,
'referral_settings' => $referral_settings
]);
}
}

View file

@ -10,20 +10,23 @@ use App\Models\TicketCategory;
use App\Models\TicketComment;
use App\Models\User;
use App\Notifications\Ticket\User\ReplyNotification;
use App\Settings\LocaleSettings;
use App\Settings\PterodactylSettings;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class TicketsController extends Controller
{
public function index()
public function index(LocaleSettings $locale_settings)
{
$tickets = Ticket::orderBy('id', 'desc')->paginate(10);
$ticketcategories = TicketCategory::all();
return view('moderator.ticket.index', compact('tickets', 'ticketcategories'));
return view('moderator.ticket.index', [
'tickets' => Ticket::orderBy('id', 'desc')->paginate(10),
'ticketcategories' => TicketCategory::all(),
'locale_datatables' => $locale_settings->datatables
]);
}
public function show($ticket_id)
public function show($ticket_id, PterodactylSettings $ptero_settings)
{
try {
$ticket = Ticket::where('ticket_id', $ticket_id)->firstOrFail();
@ -34,8 +37,9 @@ class TicketsController extends Controller
$ticketcomments = $ticket->ticketcomments;
$ticketcategory = $ticket->ticketcategory;
$server = Server::where('id', $ticket->server)->first();
$pterodactyl_url = $ptero_settings->panel_url;
return view('moderator.ticket.show', compact('ticket', 'ticketcategory', 'ticketcomments', 'server'));
return view('moderator.ticket.show', compact('ticket', 'ticketcategory', 'ticketcomments', 'server', 'pterodactyl_url'));
}
public function changeStatus($ticket_id)
@ -164,9 +168,11 @@ class TicketsController extends Controller
->make(true);
}
public function blacklist()
public function blacklist(LocaleSettings $locale_settings)
{
return view('moderator.ticket.blacklist');
return view('moderator.ticket.blacklist', [
'locale_datatables' => $locale_settings->datatables
]);
}
public function blacklistAdd(Request $request)

View file

@ -2,18 +2,26 @@
namespace App\Http\Controllers;
use App\Classes\Pterodactyl;
use App\Models\Egg;
use App\Models\Location;
use App\Models\Node;
use App\Classes\PterodactylClient;
use App\Models\Pterodactyl\Egg;
use App\Models\Pterodactyl\Location;
use App\Models\Pterodactyl\Node;
use App\Models\Product;
use App\Settings\PterodactylSettings;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
class ProductController extends Controller
{
{
private $pterodactyl;
public function __construct(PterodactylSettings $ptero_settings)
{
$this->pterodactyl = new PterodactylClient($ptero_settings);
}
/**
* @description get product locations based on selected egg
*
@ -60,7 +68,7 @@ class ProductController extends Controller
{
$nodes = $this->getNodesBasedOnEgg($request, $egg);
foreach ($nodes as $key => $node) {
$pteroNode = Pterodactyl::getNode($node->id);
$pteroNode = $this->pterodactyl->getNode($node->id);
if ($pteroNode['allocated_resources']['memory'] >= ($pteroNode['memory'] * ($pteroNode['memory_overallocate'] + 100) / 100) || $pteroNode['allocated_resources']['disk'] >= ($pteroNode['disk'] * ($pteroNode['disk_overallocate'] + 100) / 100)) {
$nodes->forget($key);
}
@ -109,7 +117,7 @@ class ProductController extends Controller
})
->get();
$pteroNode = Pterodactyl::getNode($node->id);
$pteroNode = $this->pterodactyl->getNode($node->id);
foreach ($products as $key => $product) {
if ($product->memory > ($pteroNode['memory'] * ($pteroNode['memory_overallocate'] + 100) / 100) - $pteroNode['allocated_resources']['memory'] || $product->disk > ($pteroNode['disk'] * ($pteroNode['disk_overallocate'] + 100) / 100) - $pteroNode['allocated_resources']['disk']) {
$product->doesNotFit = true;

View file

@ -2,8 +2,12 @@
namespace App\Http\Controllers;
use App\Classes\Pterodactyl;
use App\Models\User;
use App\Settings\UserSettings;
use App\Settings\PterodactylSettings;
use App\Classes\PterodactylClient;
use App\Settings\DiscordSettings;
use App\Settings\ReferralSettings;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
@ -12,8 +16,15 @@ use Illuminate\Validation\ValidationException;
class ProfileController extends Controller
{
private $pterodactyl;
public function __construct(PterodactylSettings $ptero_settings)
{
$this->pterodactyl = new PterodactylClient($ptero_settings);
}
/** Display a listing of the resource. */
public function index()
public function index(UserSettings $user_settings, DiscordSettings $discord_settings, ReferralSettings $referral_settings)
{
switch (Auth::user()->role) {
case 'admin':
@ -32,10 +43,14 @@ class ProfileController extends Controller
return view('profile.index')->with([
'user' => Auth::user(),
'credits_reward_after_verify_discord' => config('SETTINGS::USER:CREDITS_REWARD_AFTER_VERIFY_DISCORD'),
'force_email_verification' => config('SETTINGS::USER:FORCE_EMAIL_VERIFICATION'),
'force_discord_verification' => config('SETTINGS::USER:FORCE_DISCORD_VERIFICATION'),
'credits_reward_after_verify_discord' => $user_settings->credits_reward_after_verify_discord,
'force_email_verification' => $user_settings->force_email_verification,
'force_discord_verification' => $user_settings->force_discord_verification,
'badgeColor' => $badgeColor,
'discord_client_id' => $discord_settings->client_id,
'discord_client_secret' => $discord_settings->client_secret,
'referral_enabled' => $referral_settings->enabled,
'referral_allowed' => $referral_settings->allowed
]);
}
@ -63,15 +78,15 @@ class ProfileController extends Controller
$user = User::findOrFail($id);
//update password if necessary
if (! is_null($request->input('new_password'))) {
if (!is_null($request->input('new_password'))) {
//validate password request
$request->validate([
'current_password' => [
'required',
function ($attribute, $value, $fail) use ($user) {
if (! Hash::check($value, $user->password)) {
$fail('The '.$attribute.' is invalid.');
if (!Hash::check($value, $user->password)) {
$fail('The ' . $attribute . ' is invalid.');
}
},
],
@ -81,7 +96,7 @@ class ProfileController extends Controller
//Update Users Password on Pterodactyl
//Username,Mail,First and Lastname are required aswell
$response = Pterodactyl::client()->patch('/application/users/'.$user->pterodactyl_id, [
$response = $this->pterodactyl->application->patch('/application/users/' . $user->pterodactyl_id, [
'password' => $request->input('new_password'),
'username' => $request->input('name'),
'first_name' => $request->input('name'),
@ -103,13 +118,13 @@ class ProfileController extends Controller
//validate request
$request->validate([
'name' => 'required|min:4|max:30|alpha_num|unique:users,name,'.$id.',id',
'email' => 'required|email|max:64|unique:users,email,'.$id.',id',
'name' => 'required|min:4|max:30|alpha_num|unique:users,name,' . $id . ',id',
'email' => 'required|email|max:64|unique:users,email,' . $id . ',id',
'avatar' => 'nullable',
]);
//update avatar
if (! is_null($request->input('avatar'))) {
if (!is_null($request->input('avatar'))) {
$avatar = json_decode($request->input('avatar'));
if ($avatar->input->size > 3000000) {
abort(500);
@ -125,7 +140,7 @@ class ProfileController extends Controller
}
//update name and email on Pterodactyl
$response = Pterodactyl::client()->patch('/application/users/'.$user->pterodactyl_id, [
$response = $this->pterodactyl->application->patch('/application/users/' . $user->pterodactyl_id, [
'username' => $request->input('name'),
'first_name' => $request->input('name'),
'last_name' => $request->input('name'),

View file

@ -2,14 +2,18 @@
namespace App\Http\Controllers;
use App\Classes\Pterodactyl;
use App\Models\Egg;
use App\Models\Location;
use App\Models\Nest;
use App\Models\Node;
use App\Models\Pterodactyl\Egg;
use App\Models\Pterodactyl\Location;
use App\Models\Pterodactyl\Nest;
use App\Models\Pterodactyl\Node;
use App\Models\Product;
use App\Models\Server;
use App\Notifications\ServerCreationError;
use App\Settings\UserSettings;
use App\Settings\ServerSettings;
use App\Settings\PterodactylSettings;
use App\Classes\PterodactylClient;
use App\Settings\GeneralSettings;
use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Client\Response;
@ -20,8 +24,15 @@ use Illuminate\Support\Facades\Request as FacadesRequest;
class ServerController extends Controller
{
private $pterodactyl;
public function __construct(PterodactylSettings $ptero_settings)
{
$this->pterodactyl = new PterodactylClient($ptero_settings);
}
/** Display a listing of the resource. */
public function index()
public function index(GeneralSettings $general_settings, PterodactylSettings $ptero_settings)
{
$servers = Auth::user()->servers;
@ -29,7 +40,7 @@ class ServerController extends Controller
foreach ($servers as $server) {
//Get server infos from ptero
$serverAttributes = Pterodactyl::getServerAttributes($server->pterodactyl_id, true);
$serverAttributes = $this->pterodactyl->getServerAttributes($server->pterodactyl_id);
if (! $serverAttributes) {
continue;
}
@ -61,14 +72,19 @@ class ServerController extends Controller
return view('servers.index')->with([
'servers' => $servers,
'credits_display_name' => $general_settings->credits_display_name,
'pterodactyl_url' => $ptero_settings->panel_url,
'phpmyadmin_url' => $general_settings->phpmyadmin_url
]);
}
/** Show the form for creating a new resource. */
public function create()
public function create(UserSettings $user_settings, ServerSettings $server_settings, GeneralSettings $general_settings)
{
if (! is_null($this->validateConfigurationRules())) {
return $this->validateConfigurationRules();
$validate_configuration = $this->validateConfigurationRules($user_settings, $server_settings);
if (!is_null($validate_configuration)) {
return $validate_configuration;
}
$productCount = Product::query()->where('disabled', '=', false)->count();
@ -98,13 +114,16 @@ class ServerController extends Controller
'locations' => $locations,
'eggs' => $eggs,
'user' => Auth::user(),
'server_creation_enabled' => $server_settings->creation_enabled,
'min_credits_to_make_server' => $user_settings->min_credits_to_make_server,
'credits_display_name' => $general_settings->credits_display_name
]);
}
/**
* @return null|RedirectResponse
*/
private function validateConfigurationRules()
private function validateConfigurationRules(UserSettings $user_settings, ServerSettings $server_settings)
{
//limit validation
if (Auth::user()->servers()->count() >= Auth::user()->server_limit) {
@ -120,35 +139,31 @@ class ServerController extends Controller
$nodeName = $node->name;
// Check if node has enough memory and disk space
$checkResponse = Pterodactyl::checkNodeResources($node, $product->memory, $product->disk);
$checkResponse = $this->pterodactyl->checkNodeResources($node, $product->memory, $product->disk);
if ($checkResponse == false) {
return redirect()->route('servers.index')->with('error', __("The node '".$nodeName."' doesn't have the required memory or disk left to allocate this product."));
}
// Min. Credits
if (
Auth::user()->credits <
($product->minimum_credits == -1
? config('SETTINGS::USER:MINIMUM_REQUIRED_CREDITS_TO_MAKE_SERVER', 50)
: $product->minimum_credits)
) {
if (Auth::user()->credits < ($product->minimum_credits == -1
? $user_settings->min_credits_to_make_server
: $product->minimum_credits)) {
return redirect()->route('servers.index')->with('error', 'You do not have the required amount of '.CREDITS_DISPLAY_NAME.' to use this product!');
}
}
//Required Verification for creating an server
if (config('SETTINGS::USER:FORCE_EMAIL_VERIFICATION', 'false') === 'true' && ! Auth::user()->hasVerifiedEmail()) {
if ($user_settings->force_email_verification && !Auth::user()->hasVerifiedEmail()) {
return redirect()->route('profile.index')->with('error', __('You are required to verify your email address before you can create a server.'));
}
//Required Verification for creating an server
if (! config('SETTINGS::SYSTEM:CREATION_OF_NEW_SERVERS', 'true') && Auth::user()->role != 'admin') {
if (!$server_settings->creation_enabled && Auth::user()->role != 'admin') {
return redirect()->route('servers.index')->with('error', __('The system administrator has blocked the creation of new servers.'));
}
//Required Verification for creating an server
if (config('SETTINGS::USER:FORCE_DISCORD_VERIFICATION', 'false') === 'true' && ! Auth::user()->discordUser) {
if ($user_settings->force_discord_verification && !Auth::user()->discordUser) {
return redirect()->route('profile.index')->with('error', __('You are required to link your discord account before you can create a server.'));
}
@ -156,13 +171,15 @@ class ServerController extends Controller
}
/** Store a newly created resource in storage. */
public function store(Request $request)
public function store(Request $request, UserSettings $user_settings, ServerSettings $server_settings)
{
/** @var Node $node */
/** @var Egg $egg */
/** @var Product $product */
if (! is_null($this->validateConfigurationRules())) {
return $this->validateConfigurationRules();
$validate_configuration = $this->validateConfigurationRules($user_settings, $server_settings);
if (!is_null($validate_configuration)) {
return $validate_configuration;
}
$request->validate([
@ -183,13 +200,13 @@ class ServerController extends Controller
]);
//get free allocation ID
$allocationId = Pterodactyl::getFreeAllocationId($node);
$allocationId = $this->pterodactyl->getFreeAllocationId($node);
if (! $allocationId) {
return $this->noAllocationsError($server);
}
//create server on pterodactyl
$response = Pterodactyl::createServer($server, $egg, $allocationId);
$response = $this->pterodactyl->createServer($server, $egg, $allocationId);
if ($response->failed()) {
return $this->serverCreationFailed($response, $server);
}
@ -201,7 +218,7 @@ class ServerController extends Controller
'identifier' => $serverAttributes['identifier'],
]);
if (config('SETTINGS::SYSTEM:SERVER_CREATE_CHARGE_FIRST_HOUR', 'true') == 'true') {
if ($server_settings->charge_first_hour) {
if ($request->user()->credits >= $server->product->getHourlyPrice()) {
$request->user()->decrement('credits', $server->product->getHourlyPrice());
}
@ -252,12 +269,12 @@ class ServerController extends Controller
}
/** Show Server Settings */
public function show(Server $server)
public function show(Server $server, ServerSettings $server_settings, GeneralSettings $general_settings)
{
if ($server->user_id != Auth::user()->id) {
return back()->with('error', __('´This is not your Server!'));
return back()->with('error', __('This is not your Server!'));
}
$serverAttributes = Pterodactyl::getServerAttributes($server->pterodactyl_id);
$serverAttributes = $this->pterodactyl->getServerAttributes($server->pterodactyl_id);
$serverRelationships = $serverAttributes['relationships'];
$serverLocationAttributes = $serverRelationships['location']['attributes'];
@ -273,7 +290,7 @@ class ServerController extends Controller
$server->name = $serverAttributes['name'];
$server->egg = $serverRelationships['egg']['attributes']['name'];
$pteroNode = Pterodactyl::getNode($serverRelationships['node']['attributes']['id']);
$pteroNode = $this->pterodactyl->getNode($serverRelationships['node']['attributes']['id']);
$products = Product::orderBy('created_at')
->whereHas('nodes', function (Builder $builder) use ($serverRelationships) { //Only show products for that node
@ -292,6 +309,8 @@ class ServerController extends Controller
return view('servers.settings')->with([
'server' => $server,
'products' => $products,
'server_enable_upgrade' => $server_settings->enable_upgrade,
'credits_display_name' => $general_settings->credits_display_name
]);
}
@ -306,7 +325,7 @@ class ServerController extends Controller
$user = Auth::user();
$oldProduct = Product::where('id', $server->product->id)->first();
$newProduct = Product::where('id', $request->product_upgrade)->first();
$serverAttributes = Pterodactyl::getServerAttributes($server->pterodactyl_id);
$serverAttributes = $this->pterodactyl->getServerAttributes($server->pterodactyl_id);
$serverRelationships = $serverAttributes['relationships'];
// Get node resource allocation info
@ -317,7 +336,7 @@ class ServerController extends Controller
// Check if node has enough memory and disk space
$requireMemory = $newProduct->memory - $oldProduct->memory;
$requiredisk = $newProduct->disk - $oldProduct->disk;
$checkResponse = Pterodactyl::checkNodeResources($node, $requireMemory, $requiredisk);
$checkResponse = $this->pterodactyl->checkNodeResources($node, $requireMemory, $requiredisk);
if ($checkResponse == false) {
return redirect()->route('servers.index')->with('error', __("The node '".$nodeName."' doesn't have the required memory or disk left to upgrade the server."));
}
@ -331,14 +350,12 @@ class ServerController extends Controller
$server->product_id = $request->product_upgrade;
$server->update();
$server->allocation = $serverAttributes['allocation'];
$response = Pterodactyl::updateServer($server, $newProduct);
if ($response->failed()) {
return $this->serverCreationFailed($response, $server);
}
$response = $this->pterodactyl->updateServer($server, $newProduct);
if ($response->failed()) return redirect()->route('servers.index')->with('error', __("The system was unable to update your server product. Please try again later or contact support."));
//update user balance
$user->decrement('credits', $priceupgrade);
//restart the server
$response = Pterodactyl::powerAction($server, 'restart');
$response = $this->pterodactyl->powerAction($server, 'restart');
if ($response->failed()) {
return redirect()->route('servers.index')->with('error', $response->json()['errors'][0]['detail']);
}

View file

@ -3,36 +3,31 @@
namespace App\Http\Controllers;
use App\Models\ShopProduct;
use App\Settings\GeneralSettings;
use App\Settings\UserSettings;
use Illuminate\Support\Facades\Auth;
class StoreController extends Controller
{
/** Display a listing of the resource. */
public function index()
public function index(UserSettings $user_settings, GeneralSettings $general_settings)
{
$isPaymentSetup = false;
if (
env('APP_ENV') == 'local' ||
config('SETTINGS::PAYMENTS:PAYPAL:SECRET') && config('SETTINGS::PAYMENTS:PAYPAL:CLIENT_ID') ||
config('SETTINGS::PAYMENTS:STRIPE:SECRET') && config('SETTINGS::PAYMENTS:STRIPE:ENDPOINT_SECRET') && config('SETTINGS::PAYMENTS:STRIPE:METHODS')
) {
$isPaymentSetup = true;
}
$isStoreEnabled = $general_settings->store_enabled;
//Required Verification for creating an server
if (config('SETTINGS::USER:FORCE_EMAIL_VERIFICATION', false) === 'true' && ! Auth::user()->hasVerifiedEmail()) {
if ($user_settings->force_email_verification && !Auth::user()->hasVerifiedEmail()) {
return redirect()->route('profile.index')->with('error', __('You are required to verify your email address before you can purchase credits.'));
}
//Required Verification for creating an server
if (config('SETTINGS::USER:FORCE_DISCORD_VERIFICATION', false) === 'true' && ! Auth::user()->discordUser) {
if ($user_settings->force_discord_verification && !Auth::user()->discordUser) {
return redirect()->route('profile.index')->with('error', __('You are required to link your discord account before you can purchase Credits'));
}
return view('store.index')->with([
'products' => ShopProduct::where('disabled', '=', false)->orderBy('type', 'asc')->orderBy('price', 'asc')->get(),
'isPaymentSetup' => $isPaymentSetup,
'isStoreEnabled' => $isStoreEnabled,
'credits_display_name' => $general_settings->credits_display_name
]);
}
}

View file

@ -11,6 +11,9 @@ use App\Models\User;
use App\Notifications\Ticket\Admin\AdminCreateNotification;
use App\Notifications\Ticket\Admin\AdminReplyNotification;
use App\Notifications\Ticket\User\CreateNotification;
use App\Settings\LocaleSettings;
use App\Settings\PterodactylSettings;
use App\Settings\TicketSettings;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Notification;
@ -18,23 +21,28 @@ use Illuminate\Support\Str;
class TicketsController extends Controller
{
public function index()
public function index(LocaleSettings $locale_settings)
{
$tickets = Ticket::where('user_id', Auth::user()->id)->paginate(10);
$ticketcategories = TicketCategory::all();
return view('ticket.index', compact('tickets', 'ticketcategories'));
return view('ticket.index', [
'tickets' => Ticket::where('user_id', Auth::user()->id)->paginate(10),
'ticketcategories' => TicketCategory::all(),
'locale_datatables' => $locale_settings->datatables
]);
}
public function store(Request $request)
public function store(Request $request, TicketSettings $ticket_settings)
{
$this->validate($request, [
$this->validate(
$request,
[
'title' => 'required',
'ticketcategory' => 'required',
'priority' => 'required',
'message' => 'required',]
'message' => 'required',
]
);
$ticket = new Ticket([
$ticket = new Ticket(
[
'title' => $request->input('title'),
'user_id' => Auth::user()->id,
'ticket_id' => strtoupper(Str::random(8)),
@ -42,28 +50,28 @@ class TicketsController extends Controller
'priority' => $request->input('priority'),
'message' => $request->input('message'),
'status' => 'Open',
'server' => $request->input('server'),]
'server' => $request->input('server'),
]
);
$ticket->save();
$user = Auth::user();
if (config('SETTINGS::TICKET:NOTIFY') == "all") {
$admin = User::where('role', 'admin')->orWhere('role', 'mod')->get();
}
if (config('SETTINGS::TICKET:NOTIFY') == "admin") {
$admin = User::where('role', 'admin')->get();
}
if (config('SETTINGS::TICKET:NOTIFY') == "moderator") {
$admin = User::where('role', 'mod')->get();
switch ($ticket_settings->notify) {
case 'all':
$admin = User::where('role', 'admin')->orWhere('role', 'mod')->get();
Notification::send($admin, new AdminCreateNotification($ticket, $user));
case 'admin':
$admin = User::where('role', 'admin')->get();
Notification::send($admin, new AdminCreateNotification($ticket, $user));
case 'moderator':
$admin = User::where('role', 'mod')->get();
Notification::send($admin, new AdminCreateNotification($ticket, $user));
}
$user->notify(new CreateNotification($ticket));
if (config('SETTINGS::TICKET:NOTIFY') != "none") {
Notification::send($admin, new AdminCreateNotification($ticket, $user));
}
return redirect()->route('ticket.index')->with('success', __('A ticket has been opened, ID: #') . $ticket->ticket_id);
}
public function show($ticket_id)
public function show($ticket_id, PterodactylSettings $ptero_settings)
{
try {
$ticket = Ticket::where('ticket_id', $ticket_id)->firstOrFail();
@ -73,8 +81,9 @@ class TicketsController extends Controller
$ticketcomments = $ticket->ticketcomments;
$ticketcategory = $ticket->ticketcategory;
$server = Server::where('id', $ticket->server)->first();
$pterodactyl_url = $ptero_settings->panel_url;
return view('ticket.show', compact('ticket', 'ticketcategory', 'ticketcomments', 'server'));
return view('ticket.show', compact('ticket', 'ticketcategory', 'ticketcomments', 'server', 'pterodactyl_url'));
}
public function reply(Request $request)
@ -170,8 +179,10 @@ class TicketsController extends Controller
return __($tickets->priority);
})
->editColumn('updated_at', function (Ticket $tickets) {
return ['display' => $tickets->updated_at ? $tickets->updated_at->diffForHumans() : '',
'raw' => $tickets->updated_at ? strtotime($tickets->updated_at) : ''];
return [
'display' => $tickets->updated_at ? $tickets->updated_at->diffForHumans() : '',
'raw' => $tickets->updated_at ? strtotime($tickets->updated_at) : ''
];
})
->addColumn('actions', function (Ticket $tickets) {
$statusButtonColor = ($tickets->status == "Closed") ? 'btn-success' : 'btn-warning';

View file

@ -16,8 +16,6 @@ class GlobalNames
*/
public function handle(Request $request, Closure $next)
{
define('CREDITS_DISPLAY_NAME', config('SETTINGS::SYSTEM:CREDITS_DISPLAY_NAME', 'Credits'));
$unsupported_lang_array = explode(',', config('app.unsupported_locales'));
$unsupported_lang_array = array_map('strtolower', $unsupported_lang_array);
define('UNSUPPORTED_LANGS', $unsupported_lang_array);

View file

@ -2,6 +2,7 @@
namespace App\Http\Middleware;
use App\Settings\LocaleSettings;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
@ -9,6 +10,12 @@ use Illuminate\Support\Facades\Session;
class SetLocale
{
private $locale_settings;
public function __construct(LocaleSettings $locale_settings)
{
$this->locale_settings = $locale_settings;
}
/**
* Handle an incoming request.
*
@ -19,15 +26,15 @@ class SetLocale
public function handle($request, Closure $next)
{
if (Session::has('locale')) {
$locale = Session::get('locale', config('SETTINGS::LOCALE:DEFAULT'));
$locale = Session::get('locale', $this->locale_settings->default);
} else {
if (config('SETTINGS::LOCALE:DYNAMIC') !== 'true') {
$locale = config('SETTINGS::LOCALE:DEFAULT');
if (!$this->locale_settings->dynamic) {
$locale = $this->locale_settings->default;
} else {
$locale = substr($request->server('HTTP_ACCEPT_LANGUAGE'), 0, 2);
if (! in_array($locale, explode(',', config('SETTINGS::LOCALE:AVAILABLE')))) {
$locale = config('SETTINGS::LOCALE:DEFAULT');
if (! in_array($locale, explode(',', $this->locale_settings->available))) {
$locale = $this->locale_settings->default;
}
}
}

View file

@ -3,13 +3,27 @@
namespace App\Listeners;
use App\Events\PaymentEvent;
use App\Settings\InvoiceSettings;
use App\Traits\Invoiceable;
class CreateInvoice
{
use Invoiceable;
private $invoice_enabled;
private $invoice_settings;
/**
* Create the event listener.
*
* @return void
*/
public function __construct(InvoiceSettings $invoice_settings)
{
$this->invoice_enabled = $invoice_settings->enabled;
$this->invoice_settings = $invoice_settings;
}
/**
* Handle the event.
*
@ -18,9 +32,9 @@ class CreateInvoice
*/
public function handle(PaymentEvent $event)
{
if (config('SETTINGS::INVOICE:ENABLED') == 'true') {
if ($this->invoice_enabled) {
// create invoice using the trait
$this->createInvoice($event->payment, $event->shopProduct);
$this->createInvoice($event->payment, $event->shopProduct, $this->invoice_settings);
}
}
}

View file

@ -4,11 +4,24 @@ namespace App\Listeners;
use App\Events\UserUpdateCreditsEvent;
use App\Models\Server;
use App\Settings\UserSettings;
use Exception;
use Illuminate\Contracts\Queue\ShouldQueue;
class UnsuspendServers implements ShouldQueue
{
private $min_credits_to_make_server;
/**
* Create the event listener.
*
* @return void
*/
public function __construct(UserSettings $user_settings)
{
$this->min_credits_to_make_server = $user_settings->min_credits_to_make_server;
}
/**
* Handle the event.
*
@ -19,7 +32,7 @@ class UnsuspendServers implements ShouldQueue
*/
public function handle(UserUpdateCreditsEvent $event)
{
if ($event->user->credits > config('SETTINGS::USER:MINIMUM_REQUIRED_CREDITS_TO_MAKE_SERVER', 50)) {
if ($event->user->credits > $this->min_credits_to_make_server) {
/** @var Server $server */
foreach ($event->user->servers as $server) {
if ($server->isSuspended()) {

View file

@ -6,11 +6,36 @@ use App\Events\PaymentEvent;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use App\Models\PartnerDiscount;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use App\Settings\GeneralSettings;
use App\Settings\ReferralSettings;
use App\Settings\UserSettings;
class UserPayment
{
private $server_limit_after_irl_purchase;
private $referral_mode;
private $referral_percentage;
private $referral_always_give_commission;
private $credits_display_name;
/**
* Create the event listener.
*
* @return void
*/
public function __construct(UserSettings $user_settings, ReferralSettings $referral_settings, GeneralSettings $general_settings)
{
$this->server_limit_after_irl_purchase = $user_settings->server_limit_after_irl_purchase;
$this->referral_mode = $referral_settings->mode;
$this->referral_percentage = $referral_settings->percentage;
$this->referral_always_give_commission = $referral_settings->always_give_commission;
$this->credits_display_name = $general_settings->credits_display_name;
}
/**
* Handle the event.
*
@ -28,8 +53,8 @@ class UserPayment
}
//update server limit
if (config('SETTINGS::USER:SERVER_LIMIT_AFTER_IRL_PURCHASE') !== 0 && $user->server_limit < config('SETTINGS::USER:SERVER_LIMIT_AFTER_IRL_PURCHASE')) {
$user->update(['server_limit' => config('SETTINGS::USER:SERVER_LIMIT_AFTER_IRL_PURCHASE')]);
if ($this->server_limit_after_irl_purchase !== 0 && $user->server_limit < $this->server_limit_after_irl_purchase) {
$user->update(['server_limit' => $this->server_limit_after_irl_purchase]);
}
//update User with bought item
@ -40,17 +65,17 @@ class UserPayment
}
//give referral commission always
if ((config("SETTINGS::REFERRAL:MODE") == "commission" || config("SETTINGS::REFERRAL:MODE") == "both") && $shopProduct->type == "Credits" && config("SETTINGS::REFERRAL::ALWAYS_GIVE_COMMISSION") == "true") {
if (($this->referral_mode === "commission" || $this->referral_mode === "both") && $shopProduct->type == "Credits" && $this->referral_always_give_commission) {
if ($ref_user = DB::table("user_referrals")->where('registered_user_id', '=', $user->id)->first()) {
$ref_user = User::findOrFail($ref_user->referral_id);
$increment = number_format($shopProduct->quantity * (PartnerDiscount::getCommission($ref_user->id)) / 100, 0, "", "");
$increment = number_format($shopProduct->quantity * (PartnerDiscount::getCommission($ref_user->id, $this->referral_percentage)) / 100, 0, "", "");
$ref_user->increment('credits', $increment);
//LOGS REFERRALS IN THE ACTIVITY LOG
activity()
->performedOn($user)
->causedBy($ref_user)
->log('gained ' . $increment . ' ' . config("SETTINGS::SYSTEM:CREDITS_DISPLAY_NAME") . ' for commission-referral of ' . $user->name . ' (ID:' . $user->id . ')');
->log('gained ' . $increment . ' ' . $this->credits_display_name . ' for commission-referral of ' . $user->name . ' (ID:' . $user->id . ')');
}
}
//update role give Referral-reward
@ -58,17 +83,17 @@ class UserPayment
$user->update(['role' => 'client']);
//give referral commission only on first purchase
if ((config("SETTINGS::REFERRAL:MODE") == "commission" || config("SETTINGS::REFERRAL:MODE") == "both") && $shopProduct->type == "Credits" && config("SETTINGS::REFERRAL::ALWAYS_GIVE_COMMISSION") == "false") {
if (($this->referral_mode === "commission" || $this->referral_mode === "both") && $shopProduct->type == "Credits" && !$this->referral_always_give_commission) {
if ($ref_user = DB::table("user_referrals")->where('registered_user_id', '=', $user->id)->first()) {
$ref_user = User::findOrFail($ref_user->referral_id);
$increment = number_format($shopProduct->quantity * (PartnerDiscount::getCommission($ref_user->id)) / 100, 0, "", "");
$increment = number_format($shopProduct->quantity * (PartnerDiscount::getCommission($ref_user->id, $this->referral_percentage)) / 100, 0, "", "");
$ref_user->increment('credits', $increment);
//LOGS REFERRALS IN THE ACTIVITY LOG
activity()
->performedOn($user)
->causedBy($ref_user)
->log('gained ' . $increment . ' ' . config("SETTINGS::SYSTEM:CREDITS_DISPLAY_NAME") . ' for commission-referral of ' . $user->name . ' (ID:' . $user->id . ')');
->log('gained ' . $increment . ' ' . $this->credits_display_name . ' for commission-referral of ' . $user->name . ' (ID:' . $user->id . ')');
}
}
}

View file

@ -2,16 +2,23 @@
namespace App\Listeners;
use App\Settings\UserSettings;
class Verified
{
private $server_limit_after_verify_email;
private $credits_reward_after_verify_email;
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
public function __construct(UserSettings $user_settings)
{
//
$this->server_limit_after_verify_email = $user_settings->server_limit_after_verify_email;
$this->credits_reward_after_verify_email = $user_settings->credits_reward_after_verify_email;
}
/**
@ -23,8 +30,8 @@ class Verified
public function handle($event)
{
if (! $event->user->email_verified_reward) {
$event->user->increment('server_limit', config('SETTINGS::USER:SERVER_LIMIT_REWARD_AFTER_VERIFY_EMAIL'));
$event->user->increment('credits', config('SETTINGS::USER:CREDITS_REWARD_AFTER_VERIFY_EMAIL'));
$event->user->increment('server_limit', $this->server_limit_after_verify_email);
$event->user->increment('credits', $this->credits_reward_after_verify_email);
}
}
}

View file

@ -33,7 +33,7 @@ class PartnerDiscount extends Model
return 0;
}
public static function getCommission($user_id)
public static function getCommission($user_id, $percentage)
{
if ($partnerDiscount = PartnerDiscount::where('user_id', $user_id)->first()) {
if ($partnerDiscount->referral_system_commission >= 0) {
@ -41,6 +41,6 @@ class PartnerDiscount extends Model
}
}
return config('SETTINGS::REFERRAL:PERCENTAGE');
return $percentage;
}
}

View file

@ -9,6 +9,8 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Spatie\Activitylog\LogOptions;
use Spatie\Activitylog\Traits\LogsActivity;
use App\Models\Pterodactyl\Egg;
use App\Models\Pterodactyl\Node;
class Product extends Model
{

View file

@ -1,12 +1,14 @@
<?php
namespace App\Models;
namespace App\Models\Pterodactyl;
use App\Classes\Pterodactyl;
use App\Classes\PterodactylClient;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use App\Models\Pterodactyl\Nest;
use App\Models\Product;
class Egg extends Model
{
@ -37,9 +39,9 @@ class Egg extends Model
public static function syncEggs()
{
Nest::syncNests();
Nest::all()->each(function (Nest $nest) {
$eggs = Pterodactyl::getEggs($nest);
$client = app(PterodactylClient::class);
Nest::all()->each(function (Nest $nest) use ($client) {
$eggs = $client->getEggs($nest);
foreach ($eggs as $egg) {
$array = [];

View file

@ -1,8 +1,8 @@
<?php
namespace App\Models;
namespace App\Models\Pterodactyl;
use App\Classes\Pterodactyl;
use App\Classes\PterodactylClient;
use Exception;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
@ -33,7 +33,8 @@ class Location extends Model
*/
public static function syncLocations()
{
$locations = Pterodactyl::getLocations();
$client = app(PterodactylClient::class);
$locations = $client->getLocations();
//map response
$locations = array_map(function ($val) {

View file

@ -1,8 +1,8 @@
<?php
namespace App\Models;
namespace App\Models\Pterodactyl;
use App\Classes\Pterodactyl;
use App\Classes\PterodactylClient;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
@ -32,7 +32,8 @@ class Nest extends Model
public static function syncNests()
{
$nests = Pterodactyl::getNests();
$client = app(PterodactylClient::class);
$nests = $client->getNests();
//map response
$nests = array_map(function ($nest) {

View file

@ -1,13 +1,14 @@
<?php
namespace App\Models;
namespace App\Models\Pterodactyl;
use App\Classes\Pterodactyl;
use App\Classes\PterodactylClient;
use Exception;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use App\Models\Product;
class Node extends Model
{
@ -32,7 +33,8 @@ class Node extends Model
public static function syncNodes()
{
Location::syncLocations();
$nodes = Pterodactyl::getNodes();
$client = app(PterodactylClient::class);
$nodes = $client->getNodes();
//map response
$nodes = array_map(function ($node) {

View file

@ -2,7 +2,8 @@
namespace App\Models;
use App\Classes\Pterodactyl;
use App\Classes\PterodactylClient;
use App\Settings\PterodactylSettings;
use Exception;
use GuzzleHttp\Promise\PromiseInterface;
use Hidehalo\Nanoid\Client;
@ -21,13 +22,17 @@ class Server extends Model
{
use HasFactory;
use LogsActivity;
private PterodactylClient $pterodactyl;
public function getActivitylogOptions(): LogOptions
{
return LogOptions::defaults()
-> logOnlyDirty()
-> logOnly(['*'])
-> dontSubmitEmptyLogs();
->logOnlyDirty()
->logOnly(['*'])
->dontSubmitEmptyLogs();
}
/**
* @var bool
*/
@ -62,6 +67,12 @@ class Server extends Model
'suspended' => 'datetime',
];
public function __construct()
{
$ptero_settings = new PterodactylSettings();
$this->pterodactyl = new PterodactylClient($ptero_settings);
}
public static function boot()
{
parent::boot();
@ -73,8 +84,8 @@ class Server extends Model
});
static::deleting(function (Server $server) {
$response = Pterodactyl::client()->delete("/application/servers/{$server->pterodactyl_id}");
if ($response->failed() && ! is_null($server->pterodactyl_id)) {
$response = $server->pterodactyl->application->delete("/application/servers/{$server->pterodactyl_id}");
if ($response->failed() && !is_null($server->pterodactyl_id)) {
//only return error when it's not a 404 error
if ($response['errors'][0]['status'] != '404') {
throw new Exception($response['errors'][0]['code']);
@ -88,7 +99,7 @@ class Server extends Model
*/
public function isSuspended()
{
return ! is_null($this->suspended);
return !is_null($this->suspended);
}
/**
@ -96,7 +107,7 @@ class Server extends Model
*/
public function getPterodactylServer()
{
return Pterodactyl::client()->get("/application/servers/{$this->pterodactyl_id}");
return $this->pterodactyl->application->get("/application/servers/{$this->pterodactyl_id}");
}
/**
@ -104,7 +115,7 @@ class Server extends Model
*/
public function suspend()
{
$response = Pterodactyl::suspendServer($this);
$response = $this->pterodactyl->suspendServer($this);
if ($response->successful()) {
$this->update([
@ -120,7 +131,7 @@ class Server extends Model
*/
public function unSuspend()
{
$response = Pterodactyl::unSuspendServer($this);
$response = $this->pterodactyl->unSuspendServer($this);
if ($response->successful()) {
$this->update([

View file

@ -4,48 +4,8 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Cache;
class Settings extends Model
{
use HasFactory;
protected $table = 'settings';
public const CACHE_TAG = 'setting';
public $primaryKey = 'key';
public $incrementing = false;
protected $keyType = 'string';
protected $fillable = [
'key',
'value',
'type',
];
public static function boot()
{
parent::boot();
static::updated(function (Settings $settings) {
Cache::forget(self::CACHE_TAG.':'.$settings->key);
});
}
/**
* @param string $key
* @param $default
* @return mixed
*/
public static function getValueByKey(string $key, $default = null)
{
return Cache::rememberForever(self::CACHE_TAG.':'.$key, function () use ($default, $key) {
$settings = self::find($key);
return $settings ? $settings->value : $default;
});
}
}

View file

@ -2,9 +2,12 @@
namespace App\Models;
use App\Classes\Pterodactyl;
use App\Notifications\Auth\QueuedVerifyEmail;
use App\Notifications\WelcomeMessage;
use App\Settings\GeneralSettings;
use App\Settings\UserSettings;
use App\Classes\PterodactylClient;
use App\Settings\PterodactylSettings;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
@ -23,6 +26,8 @@ class User extends Authenticatable implements MustVerifyEmail
{
use HasFactory, Notifiable, LogsActivity, CausesActivity;
private PterodactylClient $pterodactyl;
/**
* @var string[]
*/
@ -85,12 +90,18 @@ class User extends Authenticatable implements MustVerifyEmail
'server_limit' => 'float',
];
public function __construct()
{
$ptero_settings = new PterodactylSettings();
$this->pterodactyl = new PterodactylClient($ptero_settings);
}
public static function boot()
{
parent::boot();
static::created(function (User $user) {
$user->notify(new WelcomeMessage($user));
static::created(function (User $user, GeneralSettings $general_settings, UserSettings $user_settings) {
$user->notify(new WelcomeMessage($user, $general_settings, $user_settings));
});
static::deleting(function (User $user) {
@ -111,7 +122,7 @@ class User extends Authenticatable implements MustVerifyEmail
$user->discordUser()->delete();
Pterodactyl::client()->delete("/application/users/{$user->pterodactyl_id}");
$user->pterodactyl->application->delete("/application/users/{$user->pterodactyl_id}");
});
}
@ -184,9 +195,6 @@ class User extends Authenticatable implements MustVerifyEmail
return $this->suspended;
}
/**
* @throws Exception
*/
public function suspend()
{
foreach ($this->servers as $server) {
@ -200,9 +208,6 @@ class User extends Authenticatable implements MustVerifyEmail
return $this;
}
/**
* @throws Exception
*/
public function unSuspend()
{
foreach ($this->getServersWithProduct() as $server) {
@ -230,23 +235,9 @@ class User extends Authenticatable implements MustVerifyEmail
*/
public function getAvatar()
{
//TODO loading the images to confirm they exist is causing to much load time. alternative has to be found :) maybe onerror tag on the <img tags>
// if ($this->discordUser()->exists()) {
// if(@getimagesize($this->discordUser->getAvatar())) {
// $avatar = $this->discordUser->getAvatar();
// } else {
// $avatar = "https://www.gravatar.com/avatar/" . md5(strtolower(trim($this->email)));
// }
// } else {
// $avatar = "https://www.gravatar.com/avatar/" . md5(strtolower(trim($this->email)));
// }
return 'https://www.gravatar.com/avatar/' . md5(strtolower(trim($this->email)));
}
/**
* @return string
*/
public function creditUsage()
{
$usage = 0;

View file

@ -3,6 +3,8 @@
namespace App\Notifications;
use App\Models\User;
use App\Settings\GeneralSettings;
use App\Settings\ReferralSettings;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
@ -15,6 +17,8 @@ class ReferralNotification extends Notification
*/
private $user;
private $ref_user;
/**
* Create a new notification instance.
*
@ -43,13 +47,13 @@ class ReferralNotification extends Notification
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
public function toArray($notifiable, GeneralSettings $general_settings, ReferralSettings $referral_settings)
{
return [
'title' => __('Someone registered using your Code!'),
'content' => '
<p>You received '.config('SETTINGS::REFERRAL::REWARD').' '.config('SETTINGS::SYSTEM:CREDITS_DISPLAY_NAME').'</p>
<p>because '.$this->ref_user->name.' registered with your Referral-Code!</p>
<p>You received '. $referral_settings->reward . ' ' . $general_settings->credits_display_name . '</p>
<p>because ' . $this->ref_user->name . ' registered with your Referral-Code!</p>
<p>Thank you very much for supporting us!.</p>
<p>'.config('app.name', 'Laravel').'</p>
',

View file

@ -3,6 +3,8 @@
namespace App\Notifications;
use App\Models\User;
use App\Settings\GeneralSettings;
use App\Settings\UserSettings;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
@ -16,14 +18,29 @@ class WelcomeMessage extends Notification implements ShouldQueue
*/
private $user;
private $credits_display_name;
private $credits_reward_after_verify_discord;
private $credits_reward_after_verify_email;
private $server_limit_after_verify_discord;
private $server_limit_after_verify_email;
/**
* Create a new notification instance.
*
* @param User $user
*/
public function __construct(User $user)
public function __construct(User $user, GeneralSettings $general_settings, UserSettings $user_settings)
{
$this->user = $user;
$this->credits_display_name = $general_settings->credits_display_name;
$this->credits_reward_after_verify_discord = $user_settings->credits_reward_after_verify_discord;
$this->credits_reward_after_verify_email = $user_settings->credits_reward_after_verify_email;
$this->server_limit_after_verify_discord = $user_settings->server_limit_after_verify_discord;
$this->server_limit_after_verify_email = $user_settings->server_limit_after_verify_email;
}
/**
@ -40,18 +57,18 @@ class WelcomeMessage extends Notification implements ShouldQueue
public function AdditionalLines()
{
$AdditionalLine = '';
if (config('SETTINGS::USER:CREDITS_REWARD_AFTER_VERIFY_EMAIL') != 0) {
$AdditionalLine .= __('Verifying your e-mail address will grant you ').config('SETTINGS::USER:CREDITS_REWARD_AFTER_VERIFY_EMAIL').' '.__('additional').' '.config('SETTINGS::SYSTEM:CREDITS_DISPLAY_NAME').'. <br />';
if ($this->credits_reward_after_verify_email != 0) {
$AdditionalLine .= __('Verifying your e-mail address will grant you ').$this->credits_reward_after_verify_email.' '.__('additional').' '.$this->credits_display_name.'. <br />';
}
if (config('SETTINGS::USER:SERVER_LIMIT_REWARD_AFTER_VERIFY_EMAIL') != 0) {
$AdditionalLine .= __('Verifying your e-mail will also increase your Server Limit by ').config('SETTINGS::USER:SERVER_LIMIT_REWARD_AFTER_VERIFY_EMAIL').'. <br />';
if ($this->server_limit_after_verify_email != 0) {
$AdditionalLine .= __('Verifying your e-mail will also increase your Server Limit by ').$this->server_limit_after_verify_email.'. <br />';
}
$AdditionalLine .= '<br />';
if (config('SETTINGS::USER:CREDITS_REWARD_AFTER_VERIFY_DISCORD') != 0) {
$AdditionalLine .= __('You can also verify your discord account to get another ').config('SETTINGS::USER:CREDITS_REWARD_AFTER_VERIFY_DISCORD').' '.config('SETTINGS::SYSTEM:CREDITS_DISPLAY_NAME').'. <br />';
if ($this->credits_reward_after_verify_discord != 0) {
$AdditionalLine .= __('You can also verify your discord account to get another ').$this->credits_reward_after_verify_discord.' '.$this->credits_display_name.'. <br />';
}
if (config('SETTINGS::USER:SERVER_LIMIT_REWARD_AFTER_VERIFY_DISCORD') != 0) {
$AdditionalLine .= __('Verifying your Discord account will also increase your Server Limit by ').config('SETTINGS::USER:SERVER_LIMIT_REWARD_AFTER_VERIFY_DISCORD').'. <br />';
if ($this->server_limit_after_verify_discord != 0) {
$AdditionalLine .= __('Verifying your Discord account will also increase your Server Limit by ').$this->server_limit_after_verify_discord.'. <br />';
}
return $AdditionalLine;

View file

@ -2,16 +2,17 @@
namespace App\Providers;
use App\Models\Settings;
use App\Extensions\PaymentGateways\PayPal\PayPalSettings;
use App\Models\UsefulLink;
use App\Settings\MailSettings;
use Exception;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\ServiceProvider;
use Qirolab\Theme\Theme;
class AppServiceProvider extends ServiceProvider
{
@ -54,6 +55,14 @@ class AppServiceProvider extends ServiceProvider
return $ok;
});
// Force HTTPS if APP_URL is set to https
if (config('app.url') && parse_url(config('app.url'), PHP_URL_SCHEME) === 'https') {
URL::forceScheme('https');
}
// Do not run this code if no APP_KEY is set
if (config('app.key') == null) return;
try {
if (Schema::hasColumn('useful_links', 'position')) {
$useful_links = UsefulLink::where("position", "like", "%topbar%")->get()->sortby("id");
@ -63,92 +72,8 @@ class AppServiceProvider extends ServiceProvider
Log::error("Couldnt find useful_links. Probably the installation is not completet. " . $e);
}
//only run if the installer has been executed
try {
$settings = Settings::all();
// Set all configs from database
foreach ($settings as $setting) {
config([$setting->key => $setting->value]);
}
if (!file_exists(base_path('themes') . "/" . config("SETTINGS::SYSTEM:THEME"))) {
config(['SETTINGS::SYSTEM:THEME' => "default"]);
}
if (config('SETTINGS::SYSTEM:THEME') && config('SETTINGS::SYSTEM:THEME') !== config('theme.active')) {
Theme::set(config("SETTINGS::SYSTEM:THEME", "default"), "default");
} else {
Theme::set("default", "default");
}
// Set Mail Config
//only update config if mail settings have changed in DB
if (
config('mail.default') != config('SETTINGS:MAIL:MAILER') ||
config('mail.mailers.smtp.host') != config('SETTINGS:MAIL:HOST') ||
config('mail.mailers.smtp.port') != config('SETTINGS:MAIL:PORT') ||
config('mail.mailers.smtp.username') != config('SETTINGS:MAIL:USERNAME') ||
config('mail.mailers.smtp.password') != config('SETTINGS:MAIL:PASSWORD') ||
config('mail.mailers.smtp.encryption') != config('SETTINGS:MAIL:ENCRYPTION') ||
config('mail.from.address') != config('SETTINGS:MAIL:FROM_ADDRESS') ||
config('mail.from.name') != config('SETTINGS:MAIL:FROM_NAME')
) {
config(['mail.default' => config('SETTINGS::MAIL:MAILER')]);
config(['mail.mailers.smtp' => [
'transport' => 'smtp',
'host' => config('SETTINGS::MAIL:HOST'),
'port' => config('SETTINGS::MAIL:PORT'),
'encryption' => config('SETTINGS::MAIL:ENCRYPTION'),
'username' => config('SETTINGS::MAIL:USERNAME'),
'password' => config('SETTINGS::MAIL:PASSWORD'),
'timeout' => null,
'auth_mode' => null,
]]);
config(['mail.from' => ['address' => config('SETTINGS::MAIL:FROM_ADDRESS'), 'name' => config('SETTINGS::MAIL:FROM_NAME')]]);
Artisan::call('queue:restart');
}
// Set Recaptcha API Config
// Load recaptcha package if recaptcha is enabled
if (config('SETTINGS::RECAPTCHA:ENABLED') == 'true') {
$this->app->register(\Biscolab\ReCaptcha\ReCaptchaServiceProvider::class);
}
//only update config if recaptcha settings have changed in DB
if (
config('recaptcha.api_site_key') != config('SETTINGS::RECAPTCHA:SITE_KEY') ||
config('recaptcha.api_secret_key') != config('SETTINGS::RECAPTCHA:SECRET_KEY')
) {
config(['recaptcha.api_site_key' => config('SETTINGS::RECAPTCHA:SITE_KEY')]);
config(['recaptcha.api_secret_key' => config('SETTINGS::RECAPTCHA:SECRET_KEY')]);
Artisan::call('config:clear');
Artisan::call('cache:clear');
}
try {
$stringfromfile = file(base_path() . '/.git/HEAD');
$firstLine = $stringfromfile[0]; //get the string from the array
$explodedstring = explode('/', $firstLine, 3); //seperate out by the "/" in the string
$branchname = $explodedstring[2]; //get the one that is always the branch name
} catch (Exception $e) {
$branchname = 'unknown';
Log::notice($e);
}
config(['BRANCHNAME' => $branchname]);
// Set Discord-API Config
config(['services.discord.client_id' => config('SETTINGS::DISCORD:CLIENT_ID')]);
config(['services.discord.client_secret' => config('SETTINGS::DISCORD:CLIENT_SECRET')]);
} catch (Exception $e) {
error_log('Settings Error: Could not load settings from database. The Installation probably is not done yet.');
error_log($e);
Log::error('Settings Error: Could not load settings from database. The Installation probably is not done yet.');
Log::error($e);
}
$settings = $this->app->make(MailSettings::class);
$settings->setConfig();
}
}

View file

@ -0,0 +1,87 @@
<?php
namespace App\Settings;
use Spatie\LaravelSettings\Settings;
class DiscordSettings extends Settings
{
public ?string $bot_token;
public ?string $client_id;
public ?string $client_secret;
public ?string $guild_id;
public ?string $invite_url;
public ?string $role_id;
public static function group(): string
{
return 'discord';
}
public static function encrypted(): array
{
return [
'bot_token',
'client_id',
'client_secret'
];
}
/**
* Summary of validations array
* @return array<string, string>
*/
public static function getValidations()
{
return [
'bot_token' => 'nullable|string',
'client_id' => 'nullable|string',
'client_secret' => 'nullable|string',
'guild_id' => 'nullable|string',
'invite_url' => 'nullable|string|url',
'role_id' => 'nullable|string',
];
}
/**
* Summary of optionInputData array
* Only used for the settings page
* @return array<array<'type'|'label'|'description'|'options', string|bool|float|int|array<string, string>>>
*/
public static function getOptionInputData()
{
return [
'category_icon' => 'fas fa-user-friends',
'bot_token' => [
'label' => 'Bot Token',
'type' => 'string',
'description' => 'The bot token for your Discord bot.',
],
'client_id' => [
'label' => 'Client ID',
'type' => 'string',
'description' => 'The client ID for your Discord bot.',
],
'client_secret' => [
'label' => 'Client Secret',
'type' => 'string',
'description' => 'The client secret for your Discord bot.',
],
'guild_id' => [
'label' => 'Guild ID',
'type' => 'string',
'description' => 'The guild ID for your Discord server.',
],
'invite_url' => [
'label' => 'Invite URL',
'type' => 'string',
'description' => 'The invite URL for your Discord server.',
],
'role_id' => [
'label' => 'Role ID',
'type' => 'string',
'description' => 'The role ID for your Discord server.',
],
];
}
}

View file

@ -0,0 +1,138 @@
<?php
namespace App\Settings;
use Spatie\LaravelSettings\Settings;
class GeneralSettings extends Settings
{
public bool $store_enabled;
public string $credits_display_name;
public bool $recaptcha_enabled;
public string $recaptcha_site_key;
public string $recaptcha_secret_key;
public string $phpmyadmin_url;
public bool $alert_enabled;
public string $alert_type;
public string $alert_message;
public string $theme;
//public int $initial_user_role; wait for Roles & Permissions PR.
public static function group(): string
{
return 'general';
}
public static function encrypted(): array
{
return [
'recaptcha_site_key',
'recaptcha_secret_key'
];
}
/**
* Summary of validations array
* @return array<string, string>
*/
public static function getValidations()
{
return [
'store_enabled' => 'boolean',
'credits_display_name' => 'required|string',
'recaptcha_enabled' => 'nullable|boolean',
'recaptcha_site_key' => 'nullable|string',
'recaptcha_secret_key' => 'nullable|string',
'phpmyadmin_url' => 'nullable|string',
'alert_enabled' => 'nullable|boolean',
'alert_type' => 'required|in:primary,secondary,success,danger,warning,info',
'alert_message' => 'required|string',
'theme' => 'required|in:default,BlueInfinity' // TODO: themes should be made/loaded dynamically
];
}
/**
* Summary of optionTypes
* Only used for the settings page
* @return array<array<'type'|'label'|'description'|'options', string|bool|float|int|array<string, string>>>
*/
public static function getOptionInputData()
{
return [
'category_icon' => "fas fa-cog",
'store_enabled' => [
'type' => 'boolean',
'label' => 'Enable Store',
'description' => 'Enable the store for users to purchase credits.'
],
'credits_display_name' => [
'type' => 'string',
'label' => 'Credits Display Name',
'description' => 'The name of the currency used.'
],
'initial_user_credits' => [
'type' => 'number',
'label' => 'Initial User Credits',
'description' => 'The amount of credits a user gets when they register.'
],
'initial_server_limit' => [
'type' => 'number',
'label' => 'Initial Server Limit',
'description' => 'The amount of servers a user can create when they register.'
],
'recaptcha_enabled' => [
'type' => 'boolean',
'label' => 'Enable reCAPTCHA',
'description' => 'Enable reCAPTCHA on the login page.'
],
'recaptcha_site_key' => [
'type' => 'string',
'label' => 'reCAPTCHA Site Key',
'description' => 'The site key for reCAPTCHA.'
],
'recaptcha_secret_key' => [
'type' => 'string',
'label' => 'reCAPTCHA Secret Key',
'description' => 'The secret key for reCAPTCHA.'
],
'phpmyadmin_url' => [
'type' => 'string',
'label' => 'phpMyAdmin URL',
'description' => 'The URL of your phpMyAdmin installation.'
],
'alert_enabled' => [
'type' => 'boolean',
'label' => 'Enable Alert',
'description' => 'Enable an alert to be displayed on the home page.'
],
'alert_type' => [
'type' => 'select',
'label' => 'Alert Type',
'options' => [
'primary' => 'Blue',
'secondary' => 'Grey',
'success' => 'Green',
'danger' => 'Red',
'warning' => 'Orange',
'info' => 'Cyan',
],
'description' => 'The type of alert to display.'
],
'alert_message' => [
'type' => 'string',
'label' => 'Alert Message',
'description' => 'The message to display in the alert.'
],
'theme' => [
'type' => 'select',
'label' => 'Theme',
'options' => [
'default' => 'Default',
'BlueInfinity' => 'Blue Infinity',
], // TODO: themes should be made/loaded dynamically
'description' => 'The theme to use for the site.'
],
];
}
}

View file

@ -0,0 +1,92 @@
<?php
namespace App\Settings;
use Spatie\LaravelSettings\Settings;
class InvoiceSettings extends Settings
{
public ?string $company_address;
public ?string $company_mail;
public ?string $company_name;
public ?string $company_phone;
public ?string $company_vat;
public ?string $company_website;
public bool $enabled;
public ?string $prefix;
public static function group(): string
{
return 'invoice';
}
/**
* Summary of validations array
* @return array<string, string>
*/
public static function getValidations()
{
return [
'company_address' => 'nullable|string',
'company_mail' => 'nullable|string',
'company_name' => 'nullable|string',
'company_phone' => 'nullable|string',
'company_vat' => 'nullable|string',
'company_website' => 'nullable|string',
'enabled' => 'nullable|boolean',
'prefix' => 'nullable|string',
];
}
/**
* Summary of optionTypes
* Only used for the settings page
* @return array<array<'type'|'label'|'description'|'options', string|bool|float|int|array<string, string>>>
*/
public static function getOptionInputData()
{
return [
'category_icon' => 'fas fa-file-invoice-dollar',
'company_address' => [
'label' => 'Company Address',
'type' => 'string',
'description' => 'The address of your company.',
],
'company_mail' => [
'label' => 'Company Mail',
'type' => 'string',
'description' => 'The mail of your company.',
],
'company_name' => [
'label' => 'Company Name',
'type' => 'string',
'description' => 'The name of your company.',
],
'company_phone' => [
'label' => 'Company Phone',
'type' => 'string',
'description' => 'The phone of your company.',
],
'company_vat' => [
'label' => 'Company VAT ID',
'type' => 'string',
'description' => 'The VAT ID of your company.',
],
'company_website' => [
'label' => 'Company Website',
'type' => 'string',
'description' => 'The website of your company.',
],
'enabled' => [
'label' => 'Enabled',
'type' => 'boolean',
'description' => 'Enable or disable invoices.',
],
'prefix' => [
'label' => 'Prefix',
'type' => 'string',
'description' => 'The prefix of your invoices.',
],
];
}
}

View file

@ -0,0 +1,73 @@
<?php
namespace App\Settings;
use Spatie\LaravelSettings\Settings;
class LocaleSettings extends Settings
{
public ?string $available;
public bool $clients_can_change;
public ?string $datatables;
public string $default;
public bool $dynamic;
public static function group(): string
{
return 'locale';
}
/**
* Summary of validations array
* @return array<string, string>
*/
public static function getValidations()
{
return [
'available' => 'nullable|array',
'clients_can_change' => 'nullable|boolean',
'datatables' => 'nullable|string',
'default' => 'required|in:' . implode(',', config('app.available_locales')),
'dynamic' => 'nullable|boolean',
];
}
/**
* Summary of optionTypes
* Only used for the settings page
* @return array<array<'type'|'label'|'description'|'options', string|bool|float|int|array<string, string>>>
*/
public static function getOptionInputData()
{
return [
'category_icon' => 'fas fa-globe',
'available' => [
'label' => 'Available Locales',
'type' => 'multiselect',
'description' => 'The locales that are available for the user to choose from.',
'options' => config('app.available_locales'),
],
'clients_can_change' => [
'label' => 'Clients Can Change',
'type' => 'boolean',
'description' => 'Whether clients can change their locale.',
],
'datatables' => [
'label' => 'Datatables Locale',
'type' => 'string',
'description' => 'The datatables lang-code. <br><strong>Example:</strong> en-gb, fr_fr, de_de<br>More Information: <a href="https://datatables.net/plug-ins/i18n/">https://datatables.net/plug-ins/i18n/</a>',
],
'default' => [
'label' => 'Default Locale',
'type' => 'select',
'description' => 'The default locale to use.',
'options' => config('app.available_locales'),
],
'dynamic' => [
'label' => 'Dynamic Locale',
'type' => 'boolean',
'description' => 'Whether to use the dynamic locale.',
],
];
}
}

View file

@ -0,0 +1,119 @@
<?php
namespace App\Settings;
use Spatie\LaravelSettings\Settings;
class MailSettings extends Settings
{
public ?string $mail_host;
public ?int $mail_port;
public ?string $mail_username;
public ?string $mail_password;
public ?string $mail_encryption;
public ?string $mail_from_address;
public ?string $mail_from_name;
public ?string $mail_mailer;
public bool $mail_enabled;
public static function group(): string
{
return 'mail';
}
public static function encrypted(): array
{
return [
'mail_password'
];
}
public function setConfig()
{
try {
config()->set('mail.mailers.smtp.host', $this->mail_host);
config()->set('mail.mailers.smtp.port', $this->mail_port);
config()->set('mail.mailers.smtp.encryption', $this->mail_encryption);
config()->set('mail.mailers.smtp.username', $this->mail_username);
config()->set('mail.mailers.smtp.password', $this->mail_password);
config()->set('mail.from.address', $this->mail_from_address);
config()->set('mail.from.name', $this->mail_from_name);
} catch (\Exception) {
}
}
/**
* Summary of validations array
* @return array<string, string>
*/
public static function getValidations()
{
return [
'mail_host' => 'nullable|string',
'mail_port' => 'nullable|int',
'mail_username' => 'nullable|string',
'mail_password' => 'nullable|string',
'mail_encryption' => 'nullable|string',
'mail_from_address' => 'nullable|string',
'mail_from_name' => 'nullable|string',
'mail_mailer' => 'nullable|string',
'mail_enabled' => 'nullable|boolean',
];
}
/**
* Summary of optionTypes
* Only used for the settings page
* @return array<array<'type'|'label'|'description'|'options', string|bool|float|int|array<string, string>>>
*/
public static function getOptionInputData()
{
return [
'category_icon' => 'fas fa-envelope',
'mail_host' => [
'label' => 'Mail Host',
'type' => 'string',
'description' => 'The host of your mail server.',
],
'mail_port' => [
'label' => 'Mail Port',
'type' => 'number',
'description' => 'The port of your mail server.',
],
'mail_username' => [
'label' => 'Mail Username',
'type' => 'string',
'description' => 'The username of your mail server.',
],
'mail_password' => [
'label' => 'Mail Password',
'type' => 'string',
'description' => 'The password of your mail server.',
],
'mail_encryption' => [
'label' => 'Mail Encryption',
'type' => 'string',
'description' => 'The encryption of your mail server.',
],
'mail_from_address' => [
'label' => 'Mail From Address',
'type' => 'string',
'description' => 'The from address of your mail server.',
],
'mail_from_name' => [
'label' => 'Mail From Name',
'type' => 'string',
'description' => 'The from name of your mail server.',
],
'mail_mailer' => [
'label' => 'Mail Mailer',
'type' => 'string',
'description' => 'The mailer of your mail server.',
],
'mail_enabled' => [
'label' => 'Mail Enabled',
'type' => 'boolean',
],
];
}
}

View file

@ -0,0 +1,82 @@
<?php
namespace App\Settings;
use Spatie\LaravelSettings\Settings;
class PterodactylSettings extends Settings
{
public string $admin_token;
public string $user_token;
public string $panel_url;
public int $per_page_limit;
public static function group(): string
{
return 'pterodactyl';
}
public static function encrypted(): array
{
return [
'admin_token',
'user_token'
];
}
/**
* Get url with ensured ending backslash
*
* @return string
*/
public function getUrl(): string
{
return str_ends_with($this->panel_url, '/') ? $this->panel_url : $this->panel_url . '/';
}
/**
* Summary of validations array
* @return array<string, string>
*/
public static function getValidations()
{
return [
'panel_url' => 'required|string|url',
'admin_token' => 'required|string',
'user_token' => 'required|string',
'per_page_limit' => 'required|integer|min:1|max:10000',
];
}
/**
* Summary of optionTypes
* Only used for the settings page
* @return array<array<'type'|'label'|'description'|'options', string|bool|float|int|array<string, string>>>
*/
public static function getOptionInputData()
{
return [
'category_icon' => 'fas fa-server',
'panel_url' => [
'label' => 'Panel URL',
'type' => 'string',
'description' => 'The URL to your Pterodactyl panel.',
],
'admin_token' => [
'label' => 'Admin Token',
'type' => 'string',
'description' => 'The admin user token for your Pterodactyl panel.',
],
'user_token' => [
'label' => 'User Token',
'type' => 'string',
'description' => 'The user token for your Pterodactyl panel.',
],
'per_page_limit' => [
'label' => 'Per Page Limit',
'type' => 'number',
'description' => 'The number of servers to show per page.',
],
];
}
}

View file

@ -0,0 +1,87 @@
<?php
namespace App\Settings;
use Spatie\LaravelSettings\Settings;
class ReferralSettings extends Settings
{
public string $allowed;
public bool $always_give_commission;
public bool $enabled;
public ?float $reward;
public string $mode;
public ?int $percentage;
public static function group(): string
{
return 'referral';
}
/**
* Summary of validations array
* @return array<string, string>
*/
public static function getValidations()
{
return [
'allowed' => 'required|in:Everyone,Clients',
'always_give_commission' => 'nullable|boolean',
'enabled' => 'nullable|boolean',
'reward' => 'nullable|numeric',
'mode' => 'required|in:Commission,Sign-Up,Both',
'percentage' => 'nullable|numeric',
];
}
/**
* Summary of optionTypes
* Only used for the settings page
* @return array<array<'type'|'label'|'description'|'options', string|bool|float|int|array<string, string>>>
*/
public static function getOptionInputData()
{
return [
'category_icon' => 'fas fa-user-friends',
'allowed' => [
'label' => 'Allowed',
'type' => 'select',
'description' => 'Who is allowed to see their referral-URL',
'options' => [
'everyone' => 'Everyone',
'clients' => 'Clients',
],
],
'always_give_commission' => [
'label' => 'Always Give Commission',
'type' => 'boolean',
'description' => 'Always give commission to the referrer.',
],
'enabled' => [
'label' => 'Enabled',
'type' => 'boolean',
'description' => 'Enable referral system.',
],
'reward' => [
'label' => 'Reward',
'type' => 'number',
'description' => 'Reward for the referrer.',
],
'mode' => [
'label' => 'Mode',
'type' => 'select',
'description' => 'Referral mode.',
'options' => [
'commission' => 'Commission',
'sign-up' => 'Sign-Up',
'both' => 'Both',
],
],
'percentage' => [
'label' => 'Percentage',
'type' => 'number',
'description' => 'If a referred user buys credits, the referral-user will get x% of the Credits the referred user bought.',
],
];
}
}

View file

@ -0,0 +1,64 @@
<?php
namespace App\Settings;
use Spatie\LaravelSettings\Settings;
class ServerSettings extends Settings
{
public int $allocation_limit;
public bool $creation_enabled;
public bool $enable_upgrade;
public bool $charge_first_hour;
public static function group(): string
{
return 'server';
}
/**
* Summary of validations array
* @return array<string, string>
*/
public static function getValidations()
{
return [
'allocation_limit' => 'required|integer|min:0',
'creation_enabled' => 'nullable|boolean',
'enable_upgrade' => 'nullable|boolean',
'charge_first_hour' => 'nullable|boolean',
];
}
/**
* Summary of optionTypes
* Only used for the settings page
* @return array<array<'type'|'label'|'description'|'options', string|bool|float|int|array<string, string>>>
*/
public static function getOptionInputData()
{
return [
'category_icon' => 'fas fa-server',
'allocation_limit' => [
'label' => 'Allocation Limit',
'type' => 'number',
'description' => 'The maximum amount of allocations to pull per node for automatic deployment, if more allocations are being used than this limit is set to, no new servers can be created.',
],
'creation_enabled' => [
'label' => 'Creation Enabled',
'type' => 'boolean',
'description' => 'Whether or not users can create servers.',
],
'enable_upgrade' => [
'label' => 'Enable Upgrade',
'type' => 'boolean',
'description' => 'Whether or not users can upgrade their servers.',
],
'charge_first_hour' => [
'label' => 'Charge First Hour',
'type' => 'boolean',
'description' => 'Whether or not the first hour of a server is charged.',
],
];
}
}

View file

@ -0,0 +1,56 @@
<?php
namespace App\Settings;
use Spatie\LaravelSettings\Settings;
class TicketSettings extends Settings
{
public bool $enabled;
public string $notify;
public static function group(): string
{
return 'ticket';
}
/**
* Summary of validations array
* @return array<string, string>
*/
public static function getValidations()
{
return [
'enabled' => 'nullable|boolean',
'notify' => 'nullable|string',
];
}
/**
* Summary of optionTypes
* Only used for the settings page
* @return array<array<'type'|'label'|'description'|'options', string|bool|float|int|array<string, string>>>
*/
public static function getOptionInputData()
{
return [
'category_icon' => 'fas fa-ticket-alt',
'enabled' => [
'label' => 'Enabled',
'type' => 'boolean',
'description' => 'Enable or disable the ticket system.',
],
'notify' => [
'label' => 'Notify',
'type' => 'select',
'description' => 'Who will receive an E-Mail when a new Ticket is created.',
'options' => [
'admin' => 'Admins',
'moderator' => 'Moderators',
'all' => 'Admins and Moderators',
'none' => 'Nobody',
],
],
];
}
}

View file

@ -0,0 +1,120 @@
<?php
namespace App\Settings;
use Spatie\LaravelSettings\Settings;
class UserSettings extends Settings
{
public float $credits_reward_after_verify_discord;
public float $credits_reward_after_verify_email;
public bool $force_discord_verification;
public bool $force_email_verification;
public float $initial_credits;
public int $initial_server_limit;
public float $min_credits_to_make_server;
public int $server_limit_after_irl_purchase;
public int $server_limit_after_verify_discord;
public int $server_limit_after_verify_email;
public bool $register_ip_check;
public bool $creation_enabled;
public static function group(): string
{
return 'user';
}
/**
* Summary of validations array
* @return array<string, string>
*/
public static function getValidations()
{
return [
'credits_reward_after_verify_discord' => 'required|numeric',
'credits_reward_after_verify_email' => 'required|numeric',
'force_discord_verification' => 'nullable|boolean',
'force_email_verification' => 'nullable|boolean',
'initial_credits' => 'required|numeric',
'initial_server_limit' => 'required|numeric',
'min_credits_to_make_server' => 'required|numeric',
'server_limit_after_irl_purchase' => 'required|numeric',
'server_limit_after_verify_discord' => 'required|numeric',
'server_limit_after_verify_email' => 'required|numeric',
'register_ip_check' => 'nullable|boolean',
'creation_enabled' => 'nullable|boolean',
];
}
/**
* Summary of optionTypes
* Only used for the settings page
* @return array<array<'type'|'label'|'description'|'options', string|boolean|number|array<string, string>>>
*/
public static function getOptionInputData()
{
return [
'category_icon' => 'fas fa-user',
'credits_reward_after_verify_discord' => [
'label' => 'Credits Reward After Verify Discord',
'type' => 'number',
'description' => 'The amount of credits a user gets after verifying their discord account.',
],
'credits_reward_after_verify_email' => [
'label' => 'Credits Reward After Verify Email',
'type' => 'number',
'description' => 'The amount of credits a user gets after verifying their email.',
],
'force_discord_verification' => [
'label' => 'Force Discord Verification',
'type' => 'boolean',
'description' => 'Force users to verify their discord account.',
],
'force_email_verification' => [
'label' => 'Force Email Verification',
'type' => 'boolean',
'description' => 'Force users to verify their email.',
],
'initial_credits' => [
'label' => 'Initial Credits',
'type' => 'number',
'description' => 'The amount of credits a user gets when they register.',
],
'initial_server_limit' => [
'label' => 'Initial Server Limit',
'type' => 'number',
'description' => 'The amount of servers a user can create when they register.',
],
'min_credits_to_make_server' => [
'label' => 'Min Credits To Make Server',
'type' => 'number',
'description' => 'The minimum amount of credits a user needs to create a server.',
],
'server_limit_after_irl_purchase' => [
'label' => 'Server Limit After IRL Purchase',
'type' => 'number',
'description' => 'The amount of servers a user can create after they purchase a server.',
],
'server_limit_after_verify_discord' => [
'label' => 'Server Limit After Verify Discord',
'type' => 'number',
'description' => 'The amount of servers a user can create after they verify their discord account.',
],
'server_limit_after_verify_email' => [
'label' => 'Server Limit After Verify Email',
'type' => 'number',
'description' => 'The amount of servers a user can create after they verify their email.',
],
'register_ip_check' => [
'label' => 'Register IP Check',
'type' => 'boolean',
'description' => 'Check if the IP a user is registering from is already in use.',
],
'creation_enabled' => [
'label' => 'Creation Enabled',
'type' => 'boolean',
'description' => 'Whether or not users can create servers.',
],
];
}
}

View file

@ -0,0 +1,103 @@
<?php
namespace App\Settings;
use Spatie\LaravelSettings\Settings;
class WebsiteSettings extends Settings
{
public bool $show_imprint;
public bool $show_privacy;
public bool $show_tos;
public bool $useful_links_enabled;
public bool $enable_login_logo;
public ?string $seo_title;
public ?string $seo_description;
public bool $motd_enabled;
public ?string $motd_message;
public static function group(): string
{
return 'website';
}
/**
* Summary of validations array
* @return array<string, string>
*/
public static function getValidations()
{
return [
'motd_enabled' => 'nullable|boolean',
'motd_message' => 'nullable|string',
'show_imprint' => 'nullable|boolean',
'show_privacy' => 'nullable|boolean',
'show_tos' => 'nullable|boolean',
'useful_links_enabled' => 'nullable|boolean',
'enable_login_logo' => 'nullable|boolean',
'seo_title' => 'nullable|string',
'seo_description' => 'nullable|string',
];
}
/**
* Summary of optionTypes
* Only used for the settings page
* @return array<array<'type'|'label'|'description'|'options', string|array<string, string>>>
*/
public static function getOptionInputData()
{
return [
'category_icon' => 'fas fa-globe',
'motd_enabled' => [
'label' => 'Enable MOTD',
'type' => 'boolean',
'description' => 'Enable the MOTD (Message of the day) on the dashboard.',
],
'motd_message' => [
'label' => 'MOTD Message',
'type' => 'textarea',
'description' => 'The message of the day.',
],
'show_imprint' => [
'label' => 'Show Imprint',
'type' => 'boolean',
'description' => 'Show the imprint on the website.',
],
'show_privacy' => [
'label' => 'Show Privacy',
'type' => 'boolean',
'description' => 'Show the privacy on the website.',
],
'show_tos' => [
'label' => 'Show TOS',
'type' => 'boolean',
'description' => 'Show the TOS on the website.',
],
'useful_links_enabled' => [
'label' => 'Enable Useful Links',
'type' => 'boolean',
'description' => 'Enable the useful links on the dashboard.',
],
'seo_title' => [
'label' => 'SEO Title',
'type' => 'string',
'description' => 'The title of the website.',
],
'seo_description' => [
'label' => 'SEO Description',
'type' => 'string',
'description' => 'The description of the website.',
],
'enable_login_logo' => [
'label' => 'Enable Login Logo',
'type' => 'boolean',
'description' => 'Enable the logo on the login page.',
],
];
}
}

View file

@ -5,32 +5,34 @@ namespace App\Traits;
use App\Models\PartnerDiscount;
use App\Models\Payment;
use App\Models\ShopProduct;
use App\Models\Invoice;
use App\Notifications\InvoiceNotification;
use App\Settings\InvoiceSettings;
use Illuminate\Support\Facades\Storage;
use LaravelDaily\Invoices\Classes\Buyer;
use LaravelDaily\Invoices\Classes\InvoiceItem;
use LaravelDaily\Invoices\Classes\Party;
use LaravelDaily\Invoices\Invoice;
use LaravelDaily\Invoices\Invoice as DailyInvoice;
use Symfony\Component\Intl\Currencies;
trait Invoiceable
{
public function createInvoice(Payment $payment, ShopProduct $shopProduct)
public function createInvoice(Payment $payment, ShopProduct $shopProduct, InvoiceSettings $invoice_settings)
{
$user = $payment->user;
//create invoice
$lastInvoiceID = \App\Models\Invoice::where("invoice_name", "like", "%" . now()->format('mY') . "%")->count("id");
$lastInvoiceID = Invoice::where("invoice_name", "like", "%" . now()->format('mY') . "%")->count("id");
$newInvoiceID = $lastInvoiceID + 1;
$logoPath = storage_path('app/public/logo.png');
$seller = new Party([
'name' => config("SETTINGS::INVOICE:COMPANY_NAME"),
'phone' => config("SETTINGS::INVOICE:COMPANY_PHONE"),
'address' => config("SETTINGS::INVOICE:COMPANY_ADDRESS"),
'vat' => config("SETTINGS::INVOICE:COMPANY_VAT"),
'name' => $invoice_settings->company_name,
'phone' => $invoice_settings->company_phone,
'address' => $invoice_settings->company_address,
'vat' => $invoice_settings->company_vat,
'custom_fields' => [
'E-Mail' => config("SETTINGS::INVOICE:COMPANY_MAIL"),
"Web" => config("SETTINGS::INVOICE:COMPANY_WEBSITE")
'E-Mail' => $invoice_settings->company_mail,
"Web" => $invoice_settings->company_website
],
]);
@ -51,7 +53,7 @@ trait Invoiceable
$notes = implode("<br>", $notes);
$invoice = Invoice::make()
$invoice = DailyInvoice::make()
->template('controlpanel')
->name(__("Invoice"))
->buyer($customer)
@ -64,7 +66,7 @@ trait Invoiceable
->series(now()->format('mY'))
->delimiter("-")
->sequence($newInvoiceID)
->serialNumberFormat(config("SETTINGS::INVOICE:PREFIX") . '{DELIMITER}{SERIES}{SEQUENCE}')
->serialNumberFormat($invoice_settings->prefix . '{DELIMITER}{SERIES}{SEQUENCE}')
->currencyCode(strtoupper($payment->currency_code))
->currencySymbol(Currencies::getSymbol(strtoupper($payment->currency_code)))
->notes($notes);
@ -78,7 +80,7 @@ trait Invoiceable
$invoice->render();
Storage::disk("local")->put("invoice/" . $user->id . "/" . now()->format('Y') . "/" . $invoice->filename, $invoice->output);
\App\Models\Invoice::create([
Invoice::create([
'invoice_user' => $user->id,
'invoice_name' => $invoice->getSerialNumber(),
'payment_id' => $payment->payment_id,

View file

@ -11,36 +11,38 @@
"php": "^8.1",
"ext-intl": "*",
"biscolab/laravel-recaptcha": "^5.4",
"doctrine/dbal": "^3.1",
"guzzlehttp/guzzle": "^7.2",
"hidehalo/nanoid-php": "^1.1",
"doctrine/dbal": "^3.5.3",
"guzzlehttp/guzzle": "^7.5",
"hidehalo/nanoid-php": "^1.1.12",
"kkomelin/laravel-translatable-string-exporter": "^1.18",
"laravel/framework": "^9.46",
"laravel/tinker": "^2.7",
"laravel/ui": "^3.3",
"laraveldaily/laravel-invoices": "^3.0",
"league/flysystem-aws-s3-v3": "^3.0",
"paypal/paypal-checkout-sdk": "^1.0",
"paypal/rest-api-sdk-php": "^1.14",
"qirolab/laravel-themer": "^2.0",
"socialiteproviders/discord": "^4.1",
"spatie/laravel-activitylog": "^4.4",
"spatie/laravel-query-builder": "^5.0",
"spatie/laravel-validation-rules": "^3.2",
"stripe/stripe-php": "^7.107",
"symfony/http-client": "^6.2",
"symfony/intl": "^6.0",
"symfony/mailgun-mailer": "^6.2",
"yajra/laravel-datatables-oracle": "^9.19"
"laravel/framework": "^9.50.2",
"laravel/tinker": "^2.8",
"laravel/ui": "^3.4.6",
"laraveldaily/laravel-invoices": "^3.0.2",
"league/flysystem-aws-s3-v3": "^3.12.2",
"paypal/paypal-checkout-sdk": "^1.0.2",
"paypal/rest-api-sdk-php": "^1.14.0",
"predis/predis": "*",
"qirolab/laravel-themer": "^2.0.2",
"socialiteproviders/discord": "^4.1.2",
"spatie/laravel-activitylog": "^4.7.3",
"spatie/laravel-query-builder": "^5.1.2",
"spatie/laravel-settings": "^2.7",
"spatie/laravel-validation-rules": "^3.2.2",
"stripe/stripe-php": "^7.128",
"symfony/http-client": "^6.2.6",
"symfony/intl": "^6.2.5",
"symfony/mailgun-mailer": "^6.2.5",
"yajra/laravel-datatables-oracle": "^9.21.2"
},
"require-dev": {
"barryvdh/laravel-debugbar": "^3.6",
"fakerphp/faker": "^1.9.1",
"laravel/sail": "^1.15",
"mockery/mockery": "^1.4.4",
"nunomaduro/collision": "^6.3",
"phpunit/phpunit": "^9.5.10",
"spatie/laravel-ignition": "^1.4"
"barryvdh/laravel-debugbar": "^3.7",
"fakerphp/faker": "^1.21",
"laravel/sail": "^1.19",
"mockery/mockery": "^1.5.1",
"nunomaduro/collision": "^6.4",
"phpunit/phpunit": "^9.6",
"spatie/laravel-ignition": "^1.6"
},
"config": {
"optimize-autoloader": true,

1501
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -210,9 +210,8 @@ return [
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
Yajra\DataTables\DataTablesServiceProvider::class,
KKomelin\TranslatableStringExporter\Providers\ExporterServiceProvider::class,
Biscolab\ReCaptcha\ReCaptchaServiceProvider::class,
],
/*

View file

@ -93,7 +93,7 @@ return [
'from' => [
'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),
'name' => env('MAIL_FROM_NAME', 'Example'),
'name' => env('MAIL_FROM_NAME', 'ControlPanel'),
],
/*

111
config/settings.php Normal file
View file

@ -0,0 +1,111 @@
<?php
use App\Helpers\ExtensionHelper;
use App\Settings\GeneralSettings;
use App\Settings\DiscordSettings;
use App\Settings\InvoiceSettings;
use App\Settings\LocaleSettings;
use App\Settings\MailSettings;
use App\Settings\PterodactylSettings;
use App\Settings\ReferralSettings;
use App\Settings\ServerSettings;
use App\Settings\UserSettings;
use App\Settings\WebsiteSettings;
use App\Settings\TicketSettings;
return [
/*
* Each settings class used in your application must be registered, you can
* put them (manually) here.
*/
'settings' => [
GeneralSettings::class,
DiscordSettings::class,
InvoiceSettings::class,
LocaleSettings::class,
MailSettings::class,
PterodactylSettings::class,
ReferralSettings::class,
ServerSettings::class,
UserSettings::class,
WebsiteSettings::class,
TicketSettings::class,
],
/*
* The path where the settings classes will be created.
*/
'setting_class_path' => app_path('Settings'),
/*
* In these directories settings migrations will be stored and ran when migrating. A settings
* migration created via the make:settings-migration command will be stored in the first path or
* a custom defined path when running the command.
*/
'migrations_paths' => [
database_path('settings'),
...ExtensionHelper::getAllExtensionMigrations()
],
/*
* When no repository was set for a settings class the following repository
* will be used for loading and saving settings.
*/
'default_repository' => 'database',
/*
* Settings will be stored and loaded from these repositories.
*/
'repositories' => [
'database' => [
'type' => Spatie\LaravelSettings\SettingsRepositories\DatabaseSettingsRepository::class,
'model' => null,
'table' => null,
'connection' => null,
],
'redis' => [
'type' => Spatie\LaravelSettings\SettingsRepositories\RedisSettingsRepository::class,
'connection' => null,
'prefix' => null,
],
],
/*
* The contents of settings classes can be cached through your application,
* settings will be stored within a provided Laravel store and can have an
* additional prefix.
*/
'cache' => [
'enabled' => env('SETTINGS_CACHE_ENABLED', true),
'store' => 'redis',
'prefix' => 'setting',
'ttl' => null,
],
/*
* These global casts will be automatically used whenever a property within
* your settings class isn't a default PHP type.
*/
'global_casts' => [
DateTimeInterface::class => Spatie\LaravelSettings\SettingsCasts\DateTimeInterfaceCast::class,
DateTimeZone::class => Spatie\LaravelSettings\SettingsCasts\DateTimeZoneCast::class,
// Spatie\DataTransferObject\DataTransferObject::class => Spatie\LaravelSettings\SettingsCasts\DtoCast::class,
Spatie\LaravelData\Data::class => Spatie\LaravelSettings\SettingsCasts\DataCast::class,
],
/*
* The package will look for settings in these paths and automatically
* register them.
*/
'auto_discover_settings' => [
app()->path(),
],
/*
* Automatically discovered settings classes can be cached so they don't
* need to be searched each time the application boots up.
*/
'discovered_settings_cache_path' => storage_path('app/laravel-settings'),
];

View file

@ -0,0 +1,45 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
// rename old settings table
Schema::table('settings', function (Blueprint $table) {
$table->rename('settings_old');
});
// create new settings table
Schema::create('settings', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->json('payload')->nullable();
$table->string('group')->index();
$table->boolean('locked');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('settings');
Schema::table('settings_old', function (Blueprint $table) {
$table->rename("settings");
});
}
};

View file

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::dropIfExists('settings_old');
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::create('settings_old', function (Blueprint $table) {
$table->string('key', 191)->primary();
$table->text('value')->nullable();
$table->string('type');
$table->longText('description')->nullable();
$table->timestamps();
});
}
};

View file

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('pterodactyl_id')->change();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->integer('pterodactyl_id')->nullable->change();
});
}
};

View file

@ -2,8 +2,8 @@
namespace Database\Seeders;
use Database\Seeders\Seeds\SettingsSeeder;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Schema;
class DatabaseSeeder extends Seeder
{
@ -14,8 +14,6 @@ class DatabaseSeeder extends Seeder
*/
public function run()
{
$this->call([
SettingsSeeder::class,
]);
// Schema::dropIfExists('settings_old');
}
}

View file

@ -1,656 +0,0 @@
<?php
namespace Database\Seeders\Seeds;
use App\Models\Settings;
use Illuminate\Database\Seeder;
class SettingsSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
//initials
Settings::firstOrCreate([
'key' => 'SETTINGS::USER:INITIAL_CREDITS',
], [
'value' => '250',
'type' => 'integer',
'description' => 'The initial amount of credits the user starts with.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::USER:INITIAL_SERVER_LIMIT',
], [
'value' => '1',
'type' => 'integer',
'description' => 'The initial server limit the user starts with.',
]);
//verify email event
Settings::firstOrCreate([
'key' => 'SETTINGS::USER:CREDITS_REWARD_AFTER_VERIFY_EMAIL',
], [
'value' => '250',
'type' => 'integer',
'description' => 'Increase in credits after the user has verified their email account.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::USER:SERVER_LIMIT_REWARD_AFTER_VERIFY_EMAIL',
], [
'value' => '2',
'type' => 'integer',
'description' => 'Increase in server limit after the user has verified their email account.',
]);
//verify discord event
Settings::firstOrCreate([
'key' => 'SETTINGS::USER:CREDITS_REWARD_AFTER_VERIFY_DISCORD',
], [
'value' => '375',
'type' => 'integer',
'description' => 'Increase in credits after the user has verified their discord account.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::USER:SERVER_LIMIT_REWARD_AFTER_VERIFY_DISCORD',
], [
'value' => '2',
'type' => 'integer',
'description' => 'Increase in server limit after the user has verified their discord account.',
]);
//other
Settings::firstOrCreate([
'key' => 'SETTINGS::USER:MINIMUM_REQUIRED_CREDITS_TO_MAKE_SERVER',
], [
'value' => '50',
'type' => 'integer',
'description' => 'The minimum amount of credits the user would need to make a server.',
]);
//purchasing
Settings::firstOrCreate([
'key' => 'SETTINGS::USER:SERVER_LIMIT_AFTER_IRL_PURCHASE',
], [
'value' => '10',
'type' => 'integer',
'description' => 'updates the users server limit to this amount (unless the user already has a higher server limit) after making a purchase with real money, set to 0 to ignore this.',
]);
//force email and discord verification
Settings::firstOrCreate([
'key' => 'SETTINGS::USER:FORCE_EMAIL_VERIFICATION',
], [
'value' => 'false',
'type' => 'boolean',
'description' => 'Force an user to verify the email adress before creating a server / buying credits.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::USER:FORCE_DISCORD_VERIFICATION',
], [
'value' => 'false',
'type' => 'boolean',
'description' => 'Force an user to link an Discord Account before creating a server / buying credits.',
]);
//disable ip check on register
Settings::firstOrCreate([
'key' => 'SETTINGS::SYSTEM:REGISTER_IP_CHECK',
], [
'value' => 'true',
'type' => 'boolean',
'description' => 'Prevent users from making multiple accounts using the same IP address',
]);
//per_page on allocations request
Settings::firstOrCreate([
'key' => 'SETTINGS::SERVER:ALLOCATION_LIMIT',
], [
'value' => '200',
'type' => 'integer',
'description' => 'The maximum amount of allocations to pull per node for automatic deployment, if more allocations are being used than this limit is set to, no new servers can be created!',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::USER:MINIMUM_REQUIRED_CREDITS_TO_MAKE_SERVER',
], [
'value' => '0',
'type' => 'integer',
'description' => 'The minimum amount of credits user has to have to create a server. Can be overridden by package limits.'
]);
//credits display name
Settings::firstOrCreate([
'key' => 'SETTINGS::SYSTEM:CREDITS_DISPLAY_NAME',
], [
'value' => 'Credits',
'type' => 'string',
'description' => 'The display name of your currency.',
]);
//credits display name
Settings::firstOrCreate([
'key' => 'SETTINGS::SYSTEM:SERVER_CREATE_CHARGE_FIRST_HOUR',
], [
'value' => 'true',
'type' => 'boolean',
'description' => 'Charges the first hour worth of credits upon creating a server.',
]);
//sales tax
Settings::firstOrCreate([
'key' => 'SETTINGS::PAYMENTS:SALES_TAX',
], [
'value' => '0',
'type' => 'integer',
'description' => 'The %-value of tax that will be added to the product price on checkout.',
]);
//Invoices enabled
Settings::firstOrCreate([
'key' => 'SETTINGS::INVOICE:ENABLED',
], [
'value' => 'false',
'type' => 'boolean',
'description' => 'Enables or disables the invoice feature for payments.',
]);
//Invoice company name
Settings::firstOrCreate([
'key' => 'SETTINGS::INVOICE:COMPANY_NAME',
], [
'value' => '',
'type' => 'string',
'description' => 'The name of the Company on the Invoices.',
]);
//Invoice company address
Settings::firstOrCreate([
'key' => 'SETTINGS::INVOICE:COMPANY_ADDRESS',
], [
'value' => '',
'type' => 'string',
'description' => 'The address of the Company on the Invoices.',
]);
//Invoice company phone
Settings::firstOrCreate([
'key' => 'SETTINGS::INVOICE:COMPANY_PHONE',
], [
'value' => '',
'type' => 'string',
'description' => 'The phone number of the Company on the Invoices.',
]);
//Invoice company mail
Settings::firstOrCreate([
'key' => 'SETTINGS::INVOICE:COMPANY_MAIL',
], [
'value' => '',
'type' => 'string',
'description' => 'The email address of the Company on the Invoices.',
]);
//Invoice VAT
Settings::firstOrCreate([
'key' => 'SETTINGS::INVOICE:COMPANY_VAT',
], [
'value' => '',
'type' => 'string',
'description' => 'The VAT-Number of the Company on the Invoices.',
]);
//Invoice Website
Settings::firstOrCreate([
'key' => 'SETTINGS::INVOICE:COMPANY_WEBSITE',
], [
'value' => '',
'type' => 'string',
'description' => 'The Website of the Company on the Invoices.',
]);
//Invoice Website
Settings::firstOrCreate([
'key' => 'SETTINGS::INVOICE:PREFIX',
], [
'value' => 'INV',
'type' => 'string',
'description' => 'The invoice prefix.',
]);
//Locale
Settings::firstOrCreate([
'key' => 'SETTINGS::LOCALE:DEFAULT',
], [
'value' => 'en',
'type' => 'string',
'description' => 'The default dashboard language.',
]);
//Dynamic locale
Settings::firstOrCreate([
'key' => 'SETTINGS::LOCALE:DYNAMIC',
], [
'value' => 'false',
'type' => 'boolean',
'description' => 'If this is true, the Language will change to the Clients browserlanguage or default.',
]);
//User can change Locale
Settings::firstOrCreate([
'key' => 'SETTINGS::LOCALE:CLIENTS_CAN_CHANGE',
], [
'value' => 'false',
'type' => 'boolean',
'description' => 'If this is true, the clients will be able to change their Locale.',
]);
//Locale
Settings::firstOrCreate([
'key' => 'SETTINGS::LOCALE:AVAILABLE',
], [
'value' => 'en',
'type' => 'string',
'description' => 'The available languages.',
]);
//Locale
Settings::firstOrCreate([
'key' => 'SETTINGS::LOCALE:DATATABLES',
], [
'value' => 'en-gb',
'type' => 'string',
'description' => 'The Language of the Datatables. Grab the Language-Codes from here https://datatables.net/plug-ins/i18n/',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::PAYMENTS:PAYPAL:SECRET',
], [
'value' => env('PAYPAL_SECRET', ''),
'type' => 'string',
'description' => 'Your PayPal Secret-Key (https://developer.paypal.com/docs/integration/direct/rest/).',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::PAYMENTS:PAYPAL:CLIENT_ID',
], [
'value' => env('PAYPAL_CLIENT_ID', ''),
'type' => 'string',
'description' => 'Your PayPal Client_ID.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::PAYMENTS:PAYPAL:SANDBOX_SECRET',
], [
'value' => env('PAYPAL_SANDBOX_SECRET', ''),
'type' => 'string',
'description' => 'Your PayPal SANDBOX Secret-Key used for testing.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::PAYMENTS:PAYPAL:SANDBOX_CLIENT_ID',
], [
'value' => env('PAYPAL_SANDBOX_CLIENT_ID', ''),
'type' => 'string',
'description' => 'Your PayPal SANDBOX Client-ID used for testing.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::PAYMENTS:STRIPE:SECRET',
], [
'value' => env('STRIPE_SECRET', ''),
'type' => 'string',
'description' => 'Your Stripe Secret-Key (https://dashboard.stripe.com/account/apikeys).',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::PAYMENTS:STRIPE:ENDPOINT_SECRET',
], [
'value' => env('STRIPE_ENDPOINT_SECRET', ''),
'type' => 'string',
'description' => 'Your Stripe endpoint secret-key.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::PAYMENTS:STRIPE:TEST_SECRET',
], [
'value' => env('STRIPE_TEST_SECRET', ''),
'type' => 'string',
'description' => 'Your Stripe test secret-key.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::PAYMENTS:STRIPE:ENDPOINT_TEST_SECRET',
], [
'value' => env('STRIPE_ENDPOINT_TEST_SECRET', ''),
'type' => 'string',
'description' => 'Your Stripe endpoint test secret-key.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::PAYMENTS:STRIPE:METHODS',
], [
'value' => env('STRIPE_METHODS', 'card,sepa_debit'),
'type' => 'string',
'description' => 'Comma seperated list of payment methods that are enabled (https://stripe.com/docs/payments/payment-methods/integration-options).',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::DISCORD:CLIENT_ID',
], [
'value' => env('DISCORD_CLIENT_ID', ''),
'type' => 'string',
'description' => 'Discord API Credentials (https://discordapp.com/developers/applications/).',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::DISCORD:CLIENT_SECRET',
], [
'value' => env('DISCORD_CLIENT_SECRET', ''),
'type' => 'string',
'description' => 'Discord API Credentials (https://discordapp.com/developers/applications/).',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::DISCORD:BOT_TOKEN',
], [
'value' => env('DISCORD_BOT_TOKEN', ''),
'type' => 'string',
'description' => 'Discord API Credentials (https://discordapp.com/developers/applications/).',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::DISCORD:GUILD_ID',
], [
'value' => env('DISCORD_GUILD_ID', ''),
'type' => 'string',
'description' => 'Discord API Credentials (https://discordapp.com/developers/applications/).',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::DISCORD:ROLE_ID',
], [
'value' => env('DISCORD_ROLE_ID', ''),
'type' => 'string',
'description' => 'Discord role that will be assigned to users when they register.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::DISCORD:INVITE_URL',
], [
'value' => env('DISCORD_INVITE_URL', ''),
'type' => 'string',
'description' => 'The invite URL to your Discord Server.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::SYSTEM:PTERODACTYL:TOKEN',
], [
'value' => env('PTERODACTYL_TOKEN', ''),
'type' => 'string',
'description' => 'Admin API Token from Pterodactyl Panel - necessary for the Panel to work. The Key needs all read&write permissions!',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::SYSTEM:PTERODACTYL:URL',
], [
'value' => env('PTERODACTYL_URL', ''),
'type' => 'string',
'description' => 'The URL to your Pterodactyl Panel. Must not end with a / ',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT',
], [
'value' => 200,
'type' => 'integer',
'description' => 'The Pterodactyl API perPage limit. It is necessary to set it higher than your server count.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::MISC:PHPMYADMIN:URL',
], [
'value' => env('PHPMYADMIN_URL', ''),
'type' => 'string',
'description' => 'The URL to your PHPMYADMIN Panel. Must not end with a /, remove to remove database button',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::RECAPTCHA:SITE_KEY',
], [
'value' => env('RECAPTCHA_SITE_KEY', '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI'),
'type' => 'string',
'description' => 'Google Recaptcha API Credentials (https://www.google.com/recaptcha/admin) - reCaptcha V2 (not v3)',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::RECAPTCHA:SECRET_KEY',
], [
'value' => env('RECAPTCHA_SECRET_KEY', '6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe'),
'type' => 'string',
'description' => 'Google Recaptcha API Credentials (https://www.google.com/recaptcha/admin) - reCaptcha V2 (not v3)',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::RECAPTCHA:ENABLED',
], [
'value' => 'true',
'type' => 'boolean',
'description' => 'Enables or disables the ReCaptcha feature on the registration/login page.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::MAIL:MAILER',
], [
'value' => env('MAIL_MAILER', 'smtp'),
'type' => 'string',
'description' => 'Selected Mailer (smtp, mailgun, sendgrid, mailtrap).',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::MAIL:HOST',
], [
'value' => env('MAIL_HOST', 'localhost'),
'type' => 'string',
'description' => 'Mailer Host Address.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::MAIL:PORT',
], [
'value' => env('MAIL_PORT', '25'),
'type' => 'string',
'description' => 'Mailer Server Port.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::MAIL:USERNAME',
], [
'value' => env('MAIL_USERNAME', ''),
'type' => 'string',
'description' => 'Mailer Username.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::MAIL:PASSWORD',
], [
'value' => env('MAIL_PASSWORD', ''),
'type' => 'string',
'description' => 'Mailer Password.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::MAIL:ENCRYPTION',
], [
'value' => env('MAIL_ENCRYPTION', 'tls'),
'type' => 'string',
'description' => 'Mailer Encryption (tls, ssl).',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::MAIL:FROM_ADDRESS',
], [
'value' => env('MAIL_FROM_ADDRESS', ''),
'type' => 'string',
'description' => 'Mailer From Address.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::MAIL:FROM_NAME',
], [
'value' => env('APP_NAME', 'Controlpanel'),
'type' => 'string',
'description' => 'Mailer From Name.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::REFERRAL::ENABLED',
], [
'value' => 'false',
'type' => 'string',
'description' => 'Enable or disable the referral system.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::REFERRAL::ALWAYS_GIVE_COMMISSION',
], [
'value' => 'false',
'type' => 'string',
'description' => 'Whether referrals get percentage commission only on first purchase or on every purchase',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::REFERRAL::REWARD',
], [
'value' => 100,
'type' => 'integer',
'description' => 'Credit reward a user should receive when a user registers with his referral code',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::REFERRAL::ALLOWED',
], [
'value' => 'client',
'type' => 'string',
'description' => 'Who should be allowed to to use the referral code. all/client',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::REFERRAL:MODE',
], [
'value' => 'sign-up',
'type' => 'string',
'description' => 'Whether referrals get Credits on User-Registration or if a User buys credits',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::REFERRAL:PERCENTAGE',
], [
'value' => 100,
'type' => 'integer',
'description' => 'The Percentage value a referred user gets.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::SYSTEM:PTERODACTYL:ADMIN_USER_TOKEN',
], [
'value' => '',
'type' => 'string',
'description' => 'The Client API Key of an Pterodactyl Admin Account.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::SYSTEM:ENABLE_UPGRADE',
], [
'value' => 'false',
'type' => 'boolean',
'description' => 'Enables the updgrade/downgrade feature for servers.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::SYSTEM:CREATION_OF_NEW_SERVERS',
], [
'value' => 'true',
'type' => 'boolean',
'description' => 'Enable creation of new servers',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::SYSTEM:CREATION_OF_NEW_USERS',
], [
'value' => 'true',
'type' => 'boolean',
'description' => 'Enable creation of new users',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::SYSTEM:SHOW_IMPRINT',
], [
'value' => "false",
'type' => 'boolean',
'description' => 'Enable imprint in footer.'
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::SYSTEM:SHOW_PRIVACY',
], [
'value' => "false",
'type' => 'boolean',
'description' => 'Enable privacy policy in footer.'
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::SYSTEM:SHOW_TOS',
], [
'value' => 'false',
'type' => 'boolean',
'description' => 'Enable Terms of Service in footer.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::SYSTEM:ALERT_ENABLED',
], [
'value' => 'false',
'type' => 'boolean',
'description' => 'Enable Alerts on Homepage.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::SYSTEM:ALERT_TYPE',
], [
'value' => 'dark',
'type' => 'text',
'description' => 'Changes the Color of the Alert.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::SYSTEM:ALERT_MESSAGE',
], [
'value' => '',
'type' => 'text',
'description' => 'Changes the Content the Alert.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::SYSTEM:THEME',
], [
'value' => 'default',
'type' => 'text',
'description' => 'Current active theme.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::SYSTEM:USEFULLINKS_ENABLED',
], [
'value' => 'true',
'type' => 'boolean',
'description' => 'Enable Useful Links on Homepage.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::SYSTEM:MOTD_ENABLED',
], [
'value' => 'true',
'type' => 'boolean',
'description' => 'Enable MOTD on Homepage.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::SYSTEM:MOTD_MESSAGE',
], [
'value' => '<h1 style="text-align: center;"><img style="display: block; margin-left: auto; margin-right: auto;" src="https://controlpanel.gg/img/controlpanel.png" alt="" width="200" height="200"><span style="font-size: 36pt;">Controlpanel.gg</span></h1>
<p><span style="font-size: 18pt;">Thank you for using our Software</span></p>
<p><span style="font-size: 18pt;">If you have any questions, make sure to join our <a href="https://discord.com/invite/4Y6HjD2uyU" target="_blank" rel="noopener">Discord</a></span></p>
<p><span style="font-size: 10pt;">(you can change this message in the <a href="admin/settings#system">Settings</a> )</span></p>',
'type' => 'text',
'description' => 'MOTD Message.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::SYSTEM:SEO_TITLE',
], [
'value' => 'Controlpanel.gg',
'type' => 'text',
'description' => 'The SEO Title.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::SYSTEM:SEO_DESCRIPTION',
], [
'value' => 'Billing software for Pterodactyl Dashboard!',
'type' => 'text',
'description' => 'SEO Description.',
]);
Settings::firstOrCreate([
'key' => 'SETTINGS::TICKET:NOTIFY',
], [
'value' => 'all',
'type' => 'text',
'description' => 'Who will get a Email Notifcation on new Tickets.',
]);
}
}

View file

@ -0,0 +1,139 @@
<?php
use Spatie\LaravelSettings\Migrations\SettingsMigration;
use Illuminate\Support\Facades\DB;
class CreateGeneralSettings extends SettingsMigration
{
public function up(): void
{
$table_exists = DB::table('settings_old')->exists();
// Get the user-set configuration values from the old table.
$this->migrator->add('general.store_enabled', true);
$this->migrator->add('general.credits_display_name', $table_exists ? $this->getOldValue('SETTINGS::SYSTEM:CREDITS_DISPLAY_NAME') : 'Credits');
$this->migrator->addEncrypted('general.recaptcha_site_key', $table_exists ? $this->getOldValue("SETTINGS::RECAPTCHA:SITE_KEY") : env('RECAPTCHA_SITE_KEY', '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI'));
$this->migrator->addEncrypted('general.recaptcha_secret_key', $table_exists ? $this->getOldValue("SETTINGS::RECAPTCHA:SECRET_KEY") : env('RECAPTCHA_SECRET_KEY', '6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe'));
$this->migrator->add('general.recaptcha_enabled', $table_exists ? $this->getOldValue("SETTINGS::RECAPTCHA:ENABLED") : true);
$this->migrator->add('general.phpmyadmin_url', $table_exists ? $this->getOldValue("SETTINGS::MISC:PHPMYADMIN:URL") : env('PHPMYADMIN_URL', ''));
$this->migrator->add('general.alert_enabled', $table_exists ? $this->getOldValue("SETTINGS::SYSTEM:ALERT_ENABLED") : false);
$this->migrator->add('general.alert_type', $table_exists ? $this->getOldValue("SETTINGS::SYSTEM:ALERT_TYPE") : 'dark');
$this->migrator->add('general.alert_message', $table_exists ? $this->getOldValue("SETTINGS::SYSTEM:ALERT_MESSAGE") : '');
$this->migrator->add('general.theme', $table_exists ? $this->getOldValue("SETTINGS::SYSTEM:THEME") : 'default');
}
public function down(): void
{
DB::table('settings_old')->insert([
[
'key' => 'SETTINGS::SYSTEM:CREDITS_DISPLAY_NAME',
'value' => $this->getNewValue('credits_display_name'),
'type' => 'string',
'description' => 'The name of the credits on the panel.'
],
[
'key' => 'SETTINGS::SYSTEM:ALERT_ENABLED',
'value' => $this->getNewValue('alert_enabled'),
'type' => 'boolean',
'description' => 'Enable the alert at the top of the panel.'
],
[
'key' => 'SETTINGS::SYSTEM:ALERT_TYPE',
'value' => $this->getNewValue('alert_type'),
'type' => 'string',
'description' => 'The type of alert to display.'
],
[
'key' => 'SETTINGS::SYSTEM:ALERT_MESSAGE',
'value' => $this->getNewValue('alert_message'),
'type' => 'text',
'description' => 'The message to display in the alert.'
],
[
'key' => 'SETTINGS::SYSTEM:THEME',
'value' => $this->getNewValue('theme'),
'type' => 'string',
'description' => 'The theme to use for the panel.'
],
[
'key' => 'SETTINGS::RECAPTCHA:SITE_KEY',
'value' => $this->getNewValue('recaptcha_site_key'),
'type' => 'string',
'description' => 'The site key for reCAPTCHA.'
],
[
'key' => 'SETTINGS::RECAPTCHA:SECRET_KEY',
'value' => $this->getNewValue('recaptcha_secret_key'),
'type' => 'string',
'description' => 'The secret key for reCAPTCHA.'
],
[
'key' => 'SETTINGS::RECAPTCHA:ENABLED',
'value' => $this->getNewValue('recaptcha_enabled'),
'type' => 'boolean',
'description' => 'Enable reCAPTCHA on the panel.'
],
[
'key' => 'SETTINGS::MISC:PHPMYADMIN:URL',
'value' => $this->getNewValue('phpmyadmin_url'),
'type' => 'string',
'description' => 'The URL to your phpMyAdmin installation.'
],
]);
$this->migrator->delete('general.store_enabled');
$this->migrator->delete('general.credits_display_name');
$this->migrator->delete('general.recaptcha_site_key');
$this->migrator->delete('general.recaptcha_secret_key');
$this->migrator->delete('general.recaptcha_enabled');
$this->migrator->delete('general.phpmyadmin_url');
$this->migrator->delete('general.alert_enabled');
$this->migrator->delete('general.alert_type');
$this->migrator->delete('general.alert_message');
$this->migrator->delete('general.theme');
}
public function getNewValue(string $name)
{
$new_value = DB::table('settings')->where([['group', '=', 'general'], ['name', '=', $name]])->get(['payload'])->first();
// Some keys returns '""' as a value.
if ($new_value->payload === '""') {
return null;
}
// remove the quotes from the string
if (substr($new_value->payload, 0, 1) === '"' && substr($new_value->payload, -1) === '"') {
return substr($new_value->payload, 1, -1);
}
return $new_value->payload;
}
public function getOldValue(string $key)
{
// Always get the first value of the key.
$old_value = DB::table('settings_old')->where('key', '=', $key)->get(['value', 'type'])->first();
// Handle the old values to return without it being a string in all cases.
if ($old_value->type === "string" || $old_value->type === "text") {
if (is_null($old_value->value)) {
return '';
}
// Some values have the type string, but their values are boolean.
if ($old_value->value === "false" || $old_value->value === "true") {
return filter_var($old_value->value, FILTER_VALIDATE_BOOL);
}
return $old_value->value;
}
if ($old_value->type === "boolean") {
return filter_var($old_value->value, FILTER_VALIDATE_BOOL);
}
return filter_var($old_value->value, FILTER_VALIDATE_INT);
}
}

View file

@ -0,0 +1,98 @@
<?php
use Spatie\LaravelSettings\Migrations\SettingsMigration;
use Illuminate\Support\Facades\DB;
class CreatePterodactylSettings extends SettingsMigration
{
public function up(): void
{
$table_exists = DB::table('settings_old')->exists();
// Get the user-set configuration values from the old table.
$this->migrator->addEncrypted('pterodactyl.admin_token', $table_exists ? $this->getOldValue('SETTINGS::SYSTEM:PTERODACTYL:TOKEN') : env('PTERODACTYL_TOKEN', ''));
$this->migrator->addEncrypted('pterodactyl.user_token', $table_exists ? $this->getOldValue('SETTINGS::SYSTEM:PTERODACTYL:ADMIN_USER_TOKEN') : '');
$this->migrator->add('pterodactyl.panel_url', $table_exists ? $this->getOldValue('SETTINGS::SYSTEM:PTERODACTYL:URL') : env('PTERODACTYL_URL', ''));
$this->migrator->add('pterodactyl.per_page_limit', $table_exists ? $this->getOldValue('SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT') : 200);
}
public function down(): void
{
DB::table('settings_old')->insert([
[
'key' => 'SETTINGS::SYSTEM:PTERODACTYL:TOKEN',
'value' => $this->getNewValue('admin_token'),
'type' => 'string',
'description' => 'The admin token for the Pterodactyl panel.',
],
[
'key' => 'SETTINGS::SYSTEM:PTERODACTYL:ADMIN_USER_TOKEN',
'value' => $this->getNewValue('user_token'),
'type' => 'string',
'description' => 'The user token for the Pterodactyl panel.',
],
[
'key' => 'SETTINGS::SYSTEM:PTERODACTYL:URL',
'value' => $this->getNewValue('panel_url'),
'type' => 'string',
'description' => 'The URL for the Pterodactyl panel.',
],
[
'key' => 'SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT',
'value' => $this->getNewValue('per_page_limit'),
'type' => 'integer',
'description' => 'The number of servers to show per page.',
],
]);
$this->migrator->delete('pterodactyl.admin_token');
$this->migrator->delete('pterodactyl.user_token');
$this->migrator->delete('pterodactyl.panel_url');
$this->migrator->delete('pterodactyl.per_page_limit');
}
public function getNewValue(string $name)
{
$new_value = DB::table('settings')->where([['group', '=', 'pterodactyl'], ['name', '=', $name]])->get(['payload'])->first();
// Some keys returns '""' as a value.
if ($new_value->payload === '""') {
return null;
}
// remove the quotes from the string
if (substr($new_value->payload, 0, 1) === '"' && substr($new_value->payload, -1) === '"') {
return substr($new_value->payload, 1, -1);
}
return $new_value->payload;
}
public function getOldValue(string $key)
{
// Always get the first value of the key.
$old_value = DB::table('settings_old')->where('key', '=', $key)->get(['value', 'type'])->first();
// Handle the old values to return without it being a string in all cases.
if ($old_value->type === "string" || $old_value->type === "text") {
if (is_null($old_value->value)) {
return '';
}
// Some values have the type string, but their values are boolean.
if ($old_value->value === "false" || $old_value->value === "true") {
return filter_var($old_value->value, FILTER_VALIDATE_BOOL);
}
return $old_value->value;
}
if ($old_value->type === "boolean") {
return filter_var($old_value->value, FILTER_VALIDATE_BOOL);
}
return filter_var($old_value->value, FILTER_VALIDATE_INT);
}
}

View file

@ -0,0 +1,136 @@
<?php
use Spatie\LaravelSettings\Migrations\SettingsMigration;
use Illuminate\Support\Facades\DB;
class CreateMailSettings extends SettingsMigration
{
public function up(): void
{
$table_exists = DB::table('settings_old')->exists();
// Get the user-set configuration values from the old table.
$this->migrator->add('mail.mail_host', $table_exists ? $this->getOldValue('SETTINGS::MAIL:HOST') : env('MAIL_HOST', 'localhost'));
$this->migrator->add('mail.mail_port', $table_exists ? $this->getOldValue('SETTINGS::MAIL:PORT') : env('MAIL_PORT', 25));
$this->migrator->add('mail.mail_username', $table_exists ? $this->getOldValue('SETTINGS::MAIL:USERNAME') : env('MAIL_USERNAME', ''));
$this->migrator->addEncrypted('mail.mail_password', $table_exists ? $this->getOldValue('SETTINGS::MAIL:PASSWORD') : env('MAIL_PASSWORD', ''));
$this->migrator->add('mail.mail_encryption', $table_exists ? $this->getOldValue('SETTINGS::MAIL:ENCRYPTION') : env('MAIL_ENCRYPTION', 'tls'));
$this->migrator->add('mail.mail_from_address', $table_exists ? $this->getOldValue('SETTINGS::MAIL:FROM_ADDRESS') : env('MAIL_FROM_ADDRESS', 'example@example.com'));
$this->migrator->add('mail.mail_from_name', $table_exists ? $this->getOldValue('SETTINGS::MAIL:FROM_NAME') : env('APP_NAME', 'ControlPanel.gg'));
$this->migrator->add('mail.mail_mailer', $table_exists ? $this->getOldValue('SETTINGS::MAIL:MAILER') : env('MAIL_MAILER', 'smtp'));
$this->migrator->add('mail.mail_enabled', true);
}
public function down(): void
{
DB::table('settings_old')->insert([
[
'key' => 'SETTINGS::MAIL:HOST',
'value' => $this->getNewValue('mail_host'),
'type' => 'string',
'description' => 'The host of the mail server.',
],
[
'key' => 'SETTINGS::MAIL:PORT',
'value' => $this->getNewValue('mail_port'),
'type' => 'integer',
'description' => 'The port of the mail server.',
],
[
'key' => 'SETTINGS::MAIL:USERNAME',
'value' => $this->getNewValue('mail_username'),
'type' => 'string',
'description' => 'The username of the mail server.',
],
[
'key' => 'SETTINGS::MAIL:PASSWORD',
'value' => $this->getNewValue('mail_password'),
'type' => 'string',
'description' => 'The password of the mail server.',
],
[
'key' => 'SETTINGS::MAIL:ENCRYPTION',
'value' => $this->getNewValue('mail_encryption'),
'type' => 'string',
'description' => 'The encryption of the mail server.',
],
[
'key' => 'SETTINGS::MAIL:FROM_ADDRESS',
'value' => $this->getNewValue('mail_from_address'),
'type' => 'string',
'description' => 'The from address of the mail server.',
],
[
'key' => 'SETTINGS::MAIL:FROM_NAME',
'value' => $this->getNewValue('mail_from_name'),
'type' => 'string',
'description' => 'The from name of the mail server.',
],
[
'key' => 'SETTINGS::MAIL:MAILER',
'value' => $this->getNewValue('mail_mailer'),
'type' => 'string',
'description' => 'The mailer of the mail server.',
],
[
'key' => 'SETTINGS::MAIL:ENABLED',
'value' => $this->getNewValue('mail_enabled'),
'type' => 'boolean',
'description' => 'The enabled state of the mail server.',
],
]);
$this->migrator->delete('mail.mail_host');
$this->migrator->delete('mail.mail_port');
$this->migrator->delete('mail.mail_username');
$this->migrator->delete('mail.mail_password');
$this->migrator->delete('mail.mail_encryption');
$this->migrator->delete('mail.mail_from_address');
$this->migrator->delete('mail.mail_from_name');
$this->migrator->delete('mail.mail_mailer');
$this->migrator->delete('mail.mail_enabled');
}
public function getNewValue(string $name)
{
$new_value = DB::table('settings')->where([['group', '=', 'mail'], ['name', '=', $name]])->get(['payload'])->first();
// Some keys returns '""' as a value.
if ($new_value->payload === '""') {
return null;
}
// remove the quotes from the string
if (substr($new_value->payload, 0, 1) === '"' && substr($new_value->payload, -1) === '"') {
return substr($new_value->payload, 1, -1);
}
return $new_value->payload;
}
public function getOldValue(string $key)
{
// Always get the first value of the key.
$old_value = DB::table('settings_old')->where('key', '=', $key)->get(['value', 'type'])->first();
// Handle the old values to return without it being a string in all cases.
if ($old_value->type === "string" || $old_value->type === "text") {
if (is_null($old_value->value)) {
return '';
}
// Some values have the type string, but their values are boolean.
if ($old_value->value === "false" || $old_value->value === "true") {
return filter_var($old_value->value, FILTER_VALIDATE_BOOL);
}
return $old_value->value;
}
if ($old_value->type === "boolean") {
return filter_var($old_value->value, FILTER_VALIDATE_BOOL);
}
return filter_var($old_value->value, FILTER_VALIDATE_INT);
}
}

View file

@ -0,0 +1,163 @@
<?php
use Spatie\LaravelSettings\Migrations\SettingsMigration;
use Illuminate\Support\Facades\DB;
class CreateUserSettings extends SettingsMigration
{
public function up(): void
{
$table_exists = DB::table('settings_old')->exists();
// Get the user-set configuration values from the old table.
$this->migrator->add('user.credits_reward_after_verify_discord', $table_exists ? $this->getOldValue('SETTINGS::USER:CREDITS_REWARD_AFTER_VERIFY_DISCORD') : 250);
$this->migrator->add('user.credits_reward_after_verify_email', $table_exists ? $this->getOldValue('SETTINGS::USER:CREDITS_REWARD_AFTER_VERIFY_EMAIL') : 250);
$this->migrator->add('user.force_discord_verification', $table_exists ? $this->getOldValue('SETTINGS::USER:FORCE_DISCORD_VERIFICATION') : false);
$this->migrator->add('user.force_email_verification', $table_exists ? $this->getOldValue('SETTINGS::USER:FORCE_EMAIL_VERIFICATION') : false);
$this->migrator->add('user.initial_credits', $table_exists ? $this->getOldValue('SETTINGS::USER:INITIAL_CREDITS') : 250);
$this->migrator->add('user.initial_server_limit', $table_exists ? $this->getOldValue('SETTINGS::USER:INITIAL_SERVER_LIMIT') : 1);
$this->migrator->add('user.min_credits_to_make_server', $table_exists ? $this->getOldValue('SETTINGS::USER:MINIMUM_REQUIRED_CREDITS_TO_MAKE_SERVER') : 50);
$this->migrator->add('user.server_limit_after_irl_purchase', $table_exists ? $this->getOldValue('SETTINGS::USER:SERVER_LIMIT_AFTER_IRL_PURCHASE') : 10);
$this->migrator->add('user.server_limit_after_verify_discord', $table_exists ? $this->getOldValue('SETTINGS::USER:SERVER_LIMIT_REWARD_AFTER_VERIFY_DISCORD') : 2);
$this->migrator->add('user.server_limit_after_verify_email', $table_exists ? $this->getOldValue('SETTINGS::USER:SERVER_LIMIT_REWARD_AFTER_VERIFY_EMAIL') : 2);
$this->migrator->add('user.register_ip_check', $table_exists ? $this->getOldValue("SETTINGS::SYSTEM:REGISTER_IP_CHECK") : true);
$this->migrator->add('user.creation_enabled', $table_exists ? $this->getOldValue("SETTINGS::SYSTEM:CREATION_OF_NEW_USERS") : true);
}
public function down(): void
{
DB::table('settings_old')->insert([
[
'key' => 'SETTINGS::USER:CREDITS_REWARD_AFTER_VERIFY_DISCORD',
'value' => $this->getNewValue('credits_reward_after_verify_discord'),
'type' => 'integer',
'description' => 'The amount of credits that the user will receive after verifying their Discord account.',
],
[
'key' => 'SETTINGS::USER:CREDITS_REWARD_AFTER_VERIFY_EMAIL',
'value' => $this->getNewValue('credits_reward_after_verify_email'),
'type' => 'integer',
'description' => 'The amount of credits that the user will receive after verifying their email.',
],
[
'key' => 'SETTINGS::USER:FORCE_DISCORD_VERIFICATION',
'value' => $this->getNewValue('force_discord_verification'),
'type' => 'boolean',
'description' => 'If the user must verify their Discord account to use the panel.',
],
[
'key' => 'SETTINGS::USER:FORCE_EMAIL_VERIFICATION',
'value' => $this->getNewValue('force_email_verification'),
'type' => 'boolean',
'description' => 'If the user must verify their email to use the panel.',
],
[
'key' => 'SETTINGS::USER:INITIAL_CREDITS',
'value' => $this->getNewValue('initial_credits'),
'type' => 'integer',
'description' => 'The amount of credits that the user will receive when they register.',
],
[
'key' => 'SETTINGS::USER:INITIAL_SERVER_LIMIT',
'value' => $this->getNewValue('initial_server_limit'),
'type' => 'integer',
'description' => 'The amount of servers that the user will be able to create when they register.',
],
[
'key' => 'SETTINGS::USER:MINIMUM_REQUIRED_CREDITS_TO_MAKE_SERVER',
'value' => $this->getNewValue('min_credits_to_make_server'),
'type' => 'integer',
'description' => 'The minimum amount of credits that the user must have to create a server.',
],
[
'key' => 'SETTINGS::USER:SERVER_LIMIT_AFTER_IRL_PURCHASE',
'value' => $this->getNewValue('server_limit_after_irl_purchase'),
'type' => 'integer',
'description' => 'The amount of servers that the user will be able to create after making a real purchase.',
],
[
'key' => 'SETTINGS::USER:SERVER_LIMIT_REWARD_AFTER_VERIFY_DISCORD',
'value' => $this->getNewValue('server_limit_after_verify_discord'),
'type' => 'integer',
'description' => 'The amount of servers that the user will be able to create after verifying their Discord account.',
],
[
'key' => 'SETTINGS::USER:SERVER_LIMIT_REWARD_AFTER_VERIFY_EMAIL',
'value' => $this->getNewValue('server_limit_after_verify_email'),
'type' => 'integer',
'description' => 'The amount of servers that the user will be able to create after verifying their email.',
],
[
'key' => 'SETTINGS::SYSTEM:REGISTER_IP_CHECK',
'value' => $this->getNewValue('register_ip_check'),
'type' => 'boolean',
'description' => 'If the user must verify their IP address to register.',
],
[
'key' => 'SETTINGS::SYSTEM:CREATION_OF_NEW_USERS',
'value' => $this->getNewValue('creation_enabled'),
'type' => 'boolean',
'description' => 'If the user can register.',
],
]);
$this->migrator->delete('user.credits_reward_after_verify_discord');
$this->migrator->delete('user.credits_reward_after_verify_email');
$this->migrator->delete('user.force_discord_verification');
$this->migrator->delete('user.force_email_verification');
$this->migrator->delete('user.initial_credits');
$this->migrator->delete('user.initial_server_limit');
$this->migrator->delete('user.min_credits_to_make_server');
$this->migrator->delete('user.server_limit_after_irl_purchase');
$this->migrator->delete('user.server_limit_after_verify_discord');
$this->migrator->delete('user.server_limit_after_verify_email');
$this->migrator->delete('user.register_ip_check');
$this->migrator->delete('user.creation_enabled');
}
public function getNewValue(string $name)
{
$new_value = DB::table('settings')->where([['group', '=', 'user'], ['name', '=', $name]])->get(['payload'])->first();
// Some keys returns '""' as a value.
if ($new_value->payload === '""') {
return null;
}
// remove the quotes from the string
if (substr($new_value->payload, 0, 1) === '"' && substr($new_value->payload, -1) === '"') {
return substr($new_value->payload, 1, -1);
}
return $new_value->payload;
}
public function getOldValue(string $key)
{
// Always get the first value of the key.
$old_value = DB::table('settings_old')->where('key', '=', $key)->get(['value', 'type'])->first();
// Handle the old values to return without it being a string in all cases.
if ($old_value->type === "string" || $old_value->type === "text") {
if (is_null($old_value->value)) {
return '';
}
// Some values have the type string, but their values are boolean.
if ($old_value->value === "false" || $old_value->value === "true") {
return filter_var($old_value->value, FILTER_VALIDATE_BOOL);
}
return $old_value->value;
}
if ($old_value->type === "boolean") {
return filter_var($old_value->value, FILTER_VALIDATE_BOOL);
}
return filter_var($old_value->value, FILTER_VALIDATE_INT);
}
}

View file

@ -0,0 +1,96 @@
<?php
use Spatie\LaravelSettings\Migrations\SettingsMigration;
use Illuminate\Support\Facades\DB;
class CreateServerSettings extends SettingsMigration
{
public function up(): void
{
$table_exists = DB::table('settings_old')->exists();
// Get the user-set configuration values from the old table.
$this->migrator->add('server.allocation_limit', $table_exists ? $this->getOldValue('SETTINGS::SERVER:ALLOCATION_LIMIT') : 200);
$this->migrator->add('server.creation_enabled', $table_exists ? $this->getOldValue('SETTINGS::SYSTEM:CREATION_OF_NEW_SERVERS') : true);
$this->migrator->add('server.enable_upgrade', $table_exists ? $this->getOldValue('SETTINGS::SYSTEM:ENABLE_UPGRADE') : false);
$this->migrator->add('server.charge_first_hour', $table_exists ? $this->getOldValue('SETTINGS::SYSTEM:SERVER_CREATE_CHARGE_FIRST_HOUR') : false);
}
public function down(): void
{
DB::table('settings_old')->insert([
[
'key' => 'SETTINGS::SERVER:ALLOCATION_LIMIT',
'value' => $this->getNewValue('allocation_limit'),
'type' => 'integer',
'description' => 'The number of servers to show per page.',
],
[
'key' => 'SETTINGS::SYSTEM:CREATION_OF_NEW_SERVERS',
'value' => $this->getNewValue('creation_enabled'),
'type' => 'boolean',
'description' => 'Whether or not users can create new servers.',
],
[
'key' => 'SETTINGS::SYSTEM:ENABLE_UPGRADE',
'value' => $this->getNewValue('enable_upgrade'),
'type' => 'boolean',
'description' => 'Whether or not users can upgrade their servers.',
],
[
'key' => 'SETTINGS::SYSTEM:SERVER_CREATE_CHARGE_FIRST_HOUR',
'value' => $this->getNewValue('charge_first_hour'),
'type' => 'boolean',
'description' => 'Whether or not to charge the user for the first hour of their server.',
],
]);
$this->migrator->delete('server.allocation_limit');
$this->migrator->delete('server.creation_enabled');
$this->migrator->delete('server.enable_upgrade');
$this->migrator->delete('server.charge_first_hour');
}
public function getNewValue(string $name)
{
$new_value = DB::table('settings')->where([['group', '=', 'server'], ['name', '=', $name]])->get(['payload'])->first();
// Some keys returns '""' as a value.
if ($new_value->payload === '""') {
return null;
}
// remove the quotes from the string
if (substr($new_value->payload, 0, 1) === '"' && substr($new_value->payload, -1) === '"') {
return substr($new_value->payload, 1, -1);
}
return $new_value->payload;
}
public function getOldValue(string $key)
{
// Always get the first value of the key.
$old_value = DB::table('settings_old')->where('key', '=', $key)->get(['value', 'type'])->first();
// Handle the old values to return without it being a string in all cases.
if ($old_value->type === "string" || $old_value->type === "text") {
if (is_null($old_value->value)) {
return '';
}
// Some values have the type string, but their values are boolean.
if ($old_value->value === "false" || $old_value->value === "true") {
return filter_var($old_value->value, FILTER_VALIDATE_BOOL);
}
return $old_value->value;
}
if ($old_value->type === "boolean") {
return filter_var($old_value->value, FILTER_VALIDATE_BOOL);
}
return filter_var($old_value->value, FILTER_VALIDATE_INT);
}
}

View file

@ -0,0 +1,128 @@
<?php
use Spatie\LaravelSettings\Migrations\SettingsMigration;
use Illuminate\Support\Facades\DB;
class CreateInvoiceSettings extends SettingsMigration
{
public function up(): void
{
$table_exists = DB::table('settings_old')->exists();
// Get the user-set configuration values from the old table.
$this->migrator->add('invoice.company_address', $table_exists ? $this->getOldValue('SETTINGS::INVOICE:COMPANY_ADDRESS') : '');
$this->migrator->add('invoice.company_mail', $table_exists ? $this->getOldValue('SETTINGS::INVOICE:COMPANY_MAIL') : '');
$this->migrator->add('invoice.company_name', $table_exists ? $this->getOldValue('SETTINGS::INVOICE:COMPANY_NAME') : '');
$this->migrator->add('invoice.company_phone', $table_exists ? $this->getOldValue('SETTINGS::INVOICE:COMPANY_PHONE') : '');
$this->migrator->add('invoice.company_vat', $table_exists ? $this->getOldValue('SETTINGS::INVOICE:COMPANY_VAT') : '');
$this->migrator->add('invoice.company_website', $table_exists ? $this->getOldValue('SETTINGS::INVOICE:COMPANY_WEBSITE') : '');
$this->migrator->add('invoice.enabled', $table_exists ? $this->getOldValue('SETTINGS::INVOICE:ENABLED') : true);
$this->migrator->add('invoice.prefix', $table_exists ? $this->getOldValue('SETTINGS::INVOICE:PREFIX') : 'INV');
}
public function down(): void
{
DB::table('settings_old')->insert([
[
'key' => 'SETTINGS::INVOICE:COMPANY_ADDRESS',
'value' => $this->getNewValue('company_address'),
'type' => 'string',
'description' => 'The address of the company.',
],
[
'key' => 'SETTINGS::INVOICE:COMPANY_MAIL',
'value' => $this->getNewValue('company_mail'),
'type' => 'string',
'description' => 'The email address of the company.',
],
[
'key' => 'SETTINGS::INVOICE:COMPANY_NAME',
'value' => $this->getNewValue('company_name'),
'type' => 'string',
'description' => 'The name of the company.',
],
[
'key' => 'SETTINGS::INVOICE:COMPANY_PHONE',
'value' => $this->getNewValue('company_phone'),
'type' => 'string',
'description' => 'The phone number of the company.',
],
[
'key' => 'SETTINGS::INVOICE:COMPANY_VAT',
'value' => $this->getNewValue('company_vat'),
'type' => 'string',
'description' => 'The VAT number of the company.',
],
[
'key' => 'SETTINGS::INVOICE:COMPANY_WEBSITE',
'value' => $this->getNewValue('company_website'),
'type' => 'string',
'description' => 'The website of the company.',
],
[
'key' => 'SETTINGS::INVOICE:ENABLED',
'value' => $this->getNewValue('enabled'),
'type' => 'boolean',
'description' => 'Enable or disable the invoice system.',
],
[
'key' => 'SETTINGS::INVOICE:PREFIX',
'value' => $this->getNewValue('prefix'),
'type' => 'string',
'description' => 'The prefix of the invoice.',
],
]);
$this->migrator->delete('invoice.company_address');
$this->migrator->delete('invoice.company_mail');
$this->migrator->delete('invoice.company_name');
$this->migrator->delete('invoice.company_phone');
$this->migrator->delete('invoice.company_vat');
$this->migrator->delete('invoice.company_website');
$this->migrator->delete('invoice.enabled');
$this->migrator->delete('invoice.prefix');
}
public function getNewValue(string $name)
{
$new_value = DB::table('settings')->where([['group', '=', 'invoice'], ['name', '=', $name]])->get(['payload'])->first();
// Some keys returns '""' as a value.
if ($new_value->payload === '""') {
return null;
}
// remove the quotes from the string
if (substr($new_value->payload, 0, 1) === '"' && substr($new_value->payload, -1) === '"') {
return substr($new_value->payload, 1, -1);
}
return $new_value->payload;
}
public function getOldValue(string $key)
{
// Always get the first value of the key.
$old_value = DB::table('settings_old')->where('key', '=', $key)->get(['value', 'type'])->first();
// Handle the old values to return without it being a string in all cases.
if ($old_value->type === "string" || $old_value->type === "text") {
if (is_null($old_value->value)) {
return '';
}
// Some values have the type string, but their values are boolean.
if ($old_value->value === "false" || $old_value->value === "true") {
return filter_var($old_value->value, FILTER_VALIDATE_BOOL);
}
return $old_value->value;
}
if ($old_value->type === "boolean") {
return filter_var($old_value->value, FILTER_VALIDATE_BOOL);
}
return filter_var($old_value->value, FILTER_VALIDATE_INT);
}
}

View file

@ -0,0 +1,113 @@
<?php
use Spatie\LaravelSettings\Migrations\SettingsMigration;
use Illuminate\Support\Facades\DB;
class CreateDiscordSettings extends SettingsMigration
{
public function up(): void
{
$table_exists = DB::table('settings_old')->exists();
// Get the user-set configuration values from the old table.
$this->migrator->addEncrypted('discord.bot_token', $table_exists ? $this->getOldValue('SETTINGS::DISCORD:BOT_TOKEN') : '');
$this->migrator->addEncrypted('discord.client_id', $table_exists ? $this->getOldValue('SETTINGS::DISCORD:CLIENT_ID') : '');
$this->migrator->addEncrypted('discord.client_secret', $table_exists ? $this->getOldValue('SETTINGS::DISCORD:CLIENT_SECRET') : '');
$this->migrator->add('discord.guild_id', $table_exists ? $this->getOldValue('SETTINGS::DISCORD:GUILD_ID') : '');
$this->migrator->add('discord.invite_url', $table_exists ? $this->getOldValue('SETTINGS::DISCORD:INVITE_URL') : '');
$this->migrator->add('discord.role_id', $table_exists ? $this->getOldValue('SETTINGS::DISCORD:ROLE_ID') : '');
}
public function down(): void
{
DB::table('settings_old')->insert([
[
'key' => 'SETTINGS::DISCORD:BOT_TOKEN',
'value' => $this->getNewValue('bot_token'),
'type' => 'string',
'description' => 'The bot token for the Discord bot.',
],
[
'key' => 'SETTINGS::DISCORD:CLIENT_ID',
'value' => $this->getNewValue('client_id'),
'type' => 'string',
'description' => 'The client ID for the Discord bot.',
],
[
'key' => 'SETTINGS::DISCORD:CLIENT_SECRET',
'value' => $this->getNewValue('client_secret'),
'type' => 'string',
'description' => 'The client secret for the Discord bot.',
],
[
'key' => 'SETTINGS::DISCORD:GUILD_ID',
'value' => $this->getNewValue('guild_id'),
'type' => 'string',
'description' => 'The guild ID for the Discord bot.',
],
[
'key' => 'SETTINGS::DISCORD:INVITE_URL',
'value' => $this->getNewValue('invite_url'),
'type' => 'string',
'description' => 'The invite URL for the Discord bot.',
],
[
'key' => 'SETTINGS::DISCORD:ROLE_ID',
'value' => $this->getNewValue('role_id'),
'type' => 'string',
'description' => 'The role ID for the Discord bot.',
]
]);
$this->migrator->delete('discord.bot_token');
$this->migrator->delete('discord.client_id');
$this->migrator->delete('discord.client_secret');
$this->migrator->delete('discord.guild_id');
$this->migrator->delete('discord.invite_url');
$this->migrator->delete('discord.role_id');
}
public function getNewValue(string $name)
{
$new_value = DB::table('settings')->where([['group', '=', 'discord'], ['name', '=', $name]])->get(['payload'])->first();
// Some keys returns '""' as a value.
if ($new_value->payload === '""') {
return null;
}
// remove the quotes from the string
if (substr($new_value->payload, 0, 1) === '"' && substr($new_value->payload, -1) === '"') {
return substr($new_value->payload, 1, -1);
}
return $new_value->payload;
}
public function getOldValue(string $key)
{
// Always get the first value of the key.
$old_value = DB::table('settings_old')->where('key', '=', $key)->get(['value', 'type'])->first();
// Handle the old values to return without it being a string in all cases.
if ($old_value->type === "string" || $old_value->type === "text") {
if (is_null($old_value->value)) {
return '';
}
// Some values have the type string, but their values are boolean.
if ($old_value->value === "false" || $old_value->value === "true") {
return filter_var($old_value->value, FILTER_VALIDATE_BOOL);
}
return $old_value->value;
}
if ($old_value->type === "boolean") {
return filter_var($old_value->value, FILTER_VALIDATE_BOOL);
}
return filter_var($old_value->value, FILTER_VALIDATE_INT);
}
}

View file

@ -0,0 +1,104 @@
<?php
use Spatie\LaravelSettings\Migrations\SettingsMigration;
use Illuminate\Support\Facades\DB;
class CreateLocaleSettings extends SettingsMigration
{
public function up(): void
{
$table_exists = DB::table('settings_old')->exists();
// Get the user-set configuration values from the old table.
$this->migrator->add('locale.available', $table_exists ? $this->getOldValue('SETTINGS::LOCALE:AVAILABLE') : '');
$this->migrator->add('locale.clients_can_change', $table_exists ? $this->getOldValue('SETTINGS::LOCALE:CLIENTS_CAN_CHANGE') : true);
$this->migrator->add('locale.datatables', $table_exists ? $this->getOldValue('SETTINGS::LOCALE:DATATABLES') : 'en-gb');
$this->migrator->add('locale.default', $table_exists ? $this->getOldValue('SETTINGS::LOCALE:DEFAULT') : 'en');
$this->migrator->add('locale.dynamic', $table_exists ? $this->getOldValue('SETTINGS::LOCALE:DYNAMIC') : false);
}
public function down(): void
{
DB::table('settings_old')->insert([
[
'key' => 'SETTINGS::LOCALE:AVAILABLE',
'value' => $this->getNewValue('available'),
'type' => 'string',
'description' => 'The available locales.',
],
[
'key' => 'SETTINGS::LOCALE:CLIENTS_CAN_CHANGE',
'value' => $this->getNewValue('clients_can_change'),
'type' => 'boolean',
'description' => 'If clients can change their locale.',
],
[
'key' => 'SETTINGS::LOCALE:DATATABLES',
'value' => $this->getNewValue('datatables'),
'type' => 'string',
'description' => 'The locale for datatables.',
],
[
'key' => 'SETTINGS::LOCALE:DEFAULT',
'value' => $this->getNewValue('default'),
'type' => 'string',
'description' => 'The default locale.',
],
[
'key' => 'SETTINGS::LOCALE:DYNAMIC',
'value' => $this->getNewValue('dynamic'),
'type' => 'boolean',
'description' => 'If the locale should be dynamic.',
],
]);
$this->migrator->delete('locale.available');
$this->migrator->delete('locale.clients_can_change');
$this->migrator->delete('locale.datatables');
$this->migrator->delete('locale.default');
$this->migrator->delete('locale.dynamic');
}
public function getNewValue(string $name)
{
$new_value = DB::table('settings')->where([['group', '=', 'locale'], ['name', '=', $name]])->get(['payload'])->first();
// Some keys returns '""' as a value.
if ($new_value->payload === '""') {
return null;
}
// remove the quotes from the string
if (substr($new_value->payload, 0, 1) === '"' && substr($new_value->payload, -1) === '"') {
return substr($new_value->payload, 1, -1);
}
return $new_value->payload;
}
public function getOldValue(string $key)
{
// Always get the first value of the key.
$old_value = DB::table('settings_old')->where('key', '=', $key)->get(['value', 'type'])->first();
// Handle the old values to return without it being a string in all cases.
if ($old_value->type === "string" || $old_value->type === "text") {
if (is_null($old_value->value)) {
return '';
}
// Some values have the type string, but their values are boolean.
if ($old_value->value === "false" || $old_value->value === "true") {
return filter_var($old_value->value, FILTER_VALIDATE_BOOL);
}
return $old_value->value;
}
if ($old_value->type === "boolean") {
return filter_var($old_value->value, FILTER_VALIDATE_BOOL);
}
return filter_var($old_value->value, FILTER_VALIDATE_INT);
}
}

View file

@ -0,0 +1,112 @@
<?php
use Spatie\LaravelSettings\Migrations\SettingsMigration;
use Illuminate\Support\Facades\DB;
class CreateReferralSettings extends SettingsMigration
{
public function up(): void
{
$table_exists = DB::table('settings_old')->exists();
// Get the user-set configuration values from the old table.
$this->migrator->add('referral.allowed', $table_exists ? $this->getOldValue('SETTINGS::REFERRAL::ALLOWED') : 'client');
$this->migrator->add('referral.always_give_commission', $table_exists ? $this->getOldValue('SETTINGS::REFERRAL::ALWAYS_GIVE_COMMISSION') : false);
$this->migrator->add('referral.enabled', $table_exists ? $this->getOldValue('SETTINGS::REFERRAL::ENABLED') : false);
$this->migrator->add('referral.reward', $table_exists ? $this->getOldValue('SETTINGS::REFERRAL::REWARD') : 100);
$this->migrator->add('referral.mode', $table_exists ? $this->getOldValue('SETTINGS::REFERRAL:MODE') : 'sign-up');
$this->migrator->add('referral.percentage', $table_exists ? $this->getOldValue('SETTINGS::REFERRAL:PERCENTAGE') : 100);
}
public function down(): void
{
DB::table('settings_old')->insert([
[
'key' => 'SETTINGS::REFERRAL::ALLOWED',
'value' => $this->getNewValue('allowed'),
'type' => 'string',
'description' => 'The allowed referral types.',
],
[
'key' => 'SETTINGS::REFERRAL::ALWAYS_GIVE_COMMISSION',
'value' => $this->getNewValue('always_give_commission'),
'type' => 'boolean',
'description' => 'Whether to always give commission to the referrer.',
],
[
'key' => 'SETTINGS::REFERRAL::ENABLED',
'value' => $this->getNewValue('enabled'),
'type' => 'boolean',
'description' => 'Whether to enable the referral system.',
],
[
'key' => 'SETTINGS::REFERRAL::REWARD',
'value' => $this->getNewValue('reward'),
'type' => 'integer',
'description' => 'The reward for the referral.',
],
[
'key' => 'SETTINGS::REFERRAL:MODE',
'value' => $this->getNewValue('mode'),
'type' => 'string',
'description' => 'The referral mode.',
],
[
'key' => 'SETTINGS::REFERRAL:PERCENTAGE',
'value' => $this->getNewValue('percentage'),
'type' => 'integer',
'description' => 'The referral percentage.',
],
]);
$this->migrator->delete('referral.allowed');
$this->migrator->delete('referral.always_give_commission');
$this->migrator->delete('referral.enabled');
$this->migrator->delete('referral.reward');
$this->migrator->delete('referral.mode');
$this->migrator->delete('referral.percentage');
}
public function getNewValue(string $name)
{
$new_value = DB::table('settings')->where([['group', '=', 'referral'], ['name', '=', $name]])->get(['payload'])->first();
// Some keys returns '""' as a value.
if ($new_value->payload === '""') {
return null;
}
// remove the quotes from the string
if (substr($new_value->payload, 0, 1) === '"' && substr($new_value->payload, -1) === '"') {
return substr($new_value->payload, 1, -1);
}
return $new_value->payload;
}
public function getOldValue(string $key)
{
// Always get the first value of the key.
$old_value = DB::table('settings_old')->where('key', '=', $key)->get(['value', 'type'])->first();
// Handle the old values to return without it being a string in all cases.
if ($old_value->type === "string" || $old_value->type === "text") {
if (is_null($old_value->value)) {
return '';
}
// Some values have the type string, but their values are boolean.
if ($old_value->value === "false" || $old_value->value === "true") {
return filter_var($old_value->value, FILTER_VALIDATE_BOOL);
}
return $old_value->value;
}
if ($old_value->type === "boolean") {
return filter_var($old_value->value, FILTER_VALIDATE_BOOL);
}
return filter_var($old_value->value, FILTER_VALIDATE_INT);
}
}

Some files were not shown because too many files have changed in this diff Show more