Compare commits
15 commits
feature/fi
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
4358d071b3 | ||
|
e7aad7ee6c | ||
|
6623f957a1 | ||
|
335951b7e6 | ||
|
9299eac552 | ||
|
aed5b9d16e | ||
|
2d6f6f6848 | ||
|
36626f2d76 | ||
|
9fab5451f5 | ||
|
79670657a4 | ||
|
441d89767d | ||
|
43ea446b2a | ||
|
63692b557c | ||
|
31b303b9fd | ||
|
0c067e26c8 |
|
@ -3,9 +3,9 @@ root = true
|
||||||
[*]
|
[*]
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
end_of_line = lf
|
end_of_line = lf
|
||||||
indent_size = 2
|
|
||||||
indent_style = space
|
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
[*.md]
|
[*.md]
|
||||||
|
@ -13,24 +13,3 @@ trim_trailing_whitespace = false
|
||||||
|
|
||||||
[*.{yml,yaml}]
|
[*.{yml,yaml}]
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|
||||||
[docker-compose.yml]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
[*.php]
|
|
||||||
indent_size = 4
|
|
||||||
|
|
||||||
[*.blade.php]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
[*.js]
|
|
||||||
indent_size = 4
|
|
||||||
|
|
||||||
[*.jsx]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
[*.tsx]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
[*.json]
|
|
||||||
indent_size = 4
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
### --- App Settings --- ###
|
### --- App Settings --- ###
|
||||||
APP_NAME=CtrlPanel.gg
|
APP_NAME=Ctrlpanel.gg
|
||||||
APP_ENV=production
|
APP_ENV=production
|
||||||
APP_KEY=
|
APP_KEY=
|
||||||
APP_DEBUG=false
|
APP_DEBUG=false
|
||||||
|
@ -62,6 +62,3 @@ PUSHER_APP_CLUSTER=mt1
|
||||||
|
|
||||||
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
||||||
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||||
|
|
||||||
# Settings Cache
|
|
||||||
SETTINGS_CACHE_ENABLED=true
|
|
||||||
|
|
4
.github/ISSUE_TEMPLATE/bug.yml
vendored
4
.github/ISSUE_TEMPLATE/bug.yml
vendored
|
@ -31,9 +31,9 @@ body:
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: controlpanel-logs
|
id: ctrlpanel-logs
|
||||||
attributes:
|
attributes:
|
||||||
label: Controlpanel Logs
|
label: Ctrlpanel Logs
|
||||||
description: Please copy and paste your laravel-log output. You may also provide a link to it using the following command `tail -n 100 /var/www/controlpanel/storage/logs/laravel.log | nc pteropaste.com 99`
|
description: Please copy and paste your laravel-log output. You may also provide a link to it using the following command `tail -n 100 /var/www/controlpanel/storage/logs/laravel.log | nc pteropaste.com 99`
|
||||||
render: Shell
|
render: Shell
|
||||||
- type: textarea
|
- type: textarea
|
||||||
|
|
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
|
@ -5,4 +5,4 @@ contact_links:
|
||||||
about: Please visit our Discord for help with your installation.
|
about: Please visit our Discord for help with your installation.
|
||||||
- name: ❓ General Question
|
- name: ❓ General Question
|
||||||
url: https://discord.gg/4Y6HjD2uyU
|
url: https://discord.gg/4Y6HjD2uyU
|
||||||
about: Please visit our Discord for general questions about the CtrlPanel.
|
about: Please visit our Discord for general questions about the ControlPanel.
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -10,7 +10,6 @@ storage/debugbar
|
||||||
.env.backup
|
.env.backup
|
||||||
.idea
|
.idea
|
||||||
.phpunit.result.cache
|
.phpunit.result.cache
|
||||||
.editorconfig
|
|
||||||
docker-compose.override.yml
|
docker-compose.override.yml
|
||||||
Homestead.json
|
Homestead.json
|
||||||
Homestead.yaml
|
Homestead.yaml
|
||||||
|
|
10
README.md
10
README.md
|
@ -1,7 +1,7 @@
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
- PayPal, Stripe and Mollie Integration
|
- PayPal Integration
|
||||||
- Hourly, Weekely, Monthly, Quarterly and Annual billing Cycles
|
- Stripe Integration
|
||||||
- Referral System
|
- Referral System
|
||||||
- Partner System
|
- Partner System
|
||||||
- Ticket System
|
- Ticket System
|
||||||
|
@ -24,12 +24,12 @@
|
||||||
|
|
||||||
![](https://img.shields.io/endpoint?label=v0.9%20Installations&url=https%3A%2F%2Fmarket.ctrlpanel.gg%2Fcallhome.php%3Fgetinstalls)
|
![](https://img.shields.io/endpoint?label=v0.9%20Installations&url=https%3A%2F%2Fmarket.ctrlpanel.gg%2Fcallhome.php%3Fgetinstalls)
|
||||||
![](https://img.shields.io/badge/Overall%20Installations-5000%2B-green)
|
![](https://img.shields.io/badge/Overall%20Installations-5000%2B-green)
|
||||||
![](https://img.shields.io/github/stars/ctrlpanel-gg/dashboard) ![](https://img.shields.io/github/forks/ctrlpanel-gg/panel) ![](https://img.shields.io/github/tag/ctrlpanel-gg/panel) [![Crowdin](https://badges.crowdin.com/project/controlpanelgg/localized.svg)](https://crowdin.com/project/controlpanelgg) ![](https://img.shields.io/github/issues/ctrlpanel-gg/panel) ![](https://img.shields.io/github/license/ctrlpanel-gg/panel) ![](https://img.shields.io/discord/787829714483019826)
|
![](https://img.shields.io/github/stars/CtrlPanel-gg/panel) ![](https://img.shields.io/github/forks/CtrlPanel-gg/panel) ![](https://img.shields.io/github/tag/CtrlPanel-gg/panel) [![Crowdin](https://badges.crowdin.net/controlpanelgg/localized.svg)](https://crowdin.com/project/controlpanelgg) ![](https://img.shields.io/github/issues/CtrlPanel-gg/panel) ![](https://img.shields.io/github/license/CtrlPanel-gg/panel) ![](https://img.shields.io/discord/787829714483019826)
|
||||||
## About
|
## About
|
||||||
|
|
||||||
CtrlPanel's Dashboard is a dashboard application designed to offer clients a management tool to manage their pterodactyl servers. This dashboard comes with a credit-based billing solution that charges users depending on the billing cycle you chose for each server they have and suspends them if they run out of credits.
|
CtrlPanel's Dashboard is a dashboard application designed to offer clients a management tool to manage their pterodactyl servers. This dashboard comes with a credit-based billing solution that credits users hourly for each server they have and suspends them if they run out of credits.
|
||||||
|
|
||||||
This dashboard offers an easy to use and free billing solution for all starting and experienced hosting providers. This dashboard has many customisation options and added discord Oauth verification to offer a solid link between your discord server and your dashboard. You can check our [Demo here](https://demo.CtrlPanel.gg "Demo").
|
This dashboard offers an easy to use and free billing solution for all starting and experienced hosting providers. This dashboard has many customisation options and added discord Oauth verification to offer a solid link between your discord server and your dashboard. You can check our [Demo here](https://demo.ctrlpanel.gg "Demo").
|
||||||
|
|
||||||
### [Installation](https://ctrlpanel.gg/docs/intro "Installation")
|
### [Installation](https://ctrlpanel.gg/docs/intro "Installation")
|
||||||
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Classes;
|
|
||||||
|
|
||||||
abstract class AbstractExtension
|
|
||||||
{
|
|
||||||
abstract public static function getConfig(): array;
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Classes;
|
|
||||||
|
|
||||||
use Exception;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Spatie\LaravelSettings\Migrations\SettingsMigration;
|
|
||||||
|
|
||||||
|
|
||||||
abstract class LegacySettingsMigration extends SettingsMigration
|
|
||||||
{
|
|
||||||
public function getNewValue(string $name, string $group)
|
|
||||||
{
|
|
||||||
$new_value = DB::table('settings')->where([['group', '=', $group], ['name', '=', $name]])->get(['payload'])->first();
|
|
||||||
|
|
||||||
if (is_null($new_value) || is_null($new_value->payload)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the old value from the settings_old table.
|
|
||||||
* @param string $key The key to get the value from table.
|
|
||||||
* @param int|string|bool|null $default The default value to return if the value is null. If value is not nullable, a default must be provided.
|
|
||||||
*/
|
|
||||||
public function getOldValue(string $key, int|string|bool|null $default = null)
|
|
||||||
{
|
|
||||||
$old_value = DB::table('settings_old')->where('key', '=', $key)->get(['value', 'type'])->first();
|
|
||||||
|
|
||||||
if (is_null($old_value) || is_null($old_value->value)) {
|
|
||||||
return $default;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($old_value->type) {
|
|
||||||
case 'string':
|
|
||||||
case 'text':
|
|
||||||
// Edgecase: The value is a boolean, but it's stored as a string.
|
|
||||||
if ($old_value->value === "false" || $old_value->value === "true") {
|
|
||||||
return filter_var($old_value->value, FILTER_VALIDATE_BOOL);
|
|
||||||
}
|
|
||||||
return $old_value->value;
|
|
||||||
case 'boolean':
|
|
||||||
return filter_var($old_value->value, FILTER_VALIDATE_BOOL);
|
|
||||||
case 'integer':
|
|
||||||
return filter_var($old_value->value, FILTER_VALIDATE_INT);
|
|
||||||
default:
|
|
||||||
throw new Exception("Unknown type: {$old_value->type}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Classes;
|
|
||||||
|
|
||||||
use App\Models\Payment;
|
|
||||||
use App\Models\ShopProduct;
|
|
||||||
|
|
||||||
abstract class PaymentExtension extends AbstractExtension
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Returns the redirect url of the payment gateway to redirect the user to
|
|
||||||
*/
|
|
||||||
abstract public static function getRedirectUrl(Payment $payment, ShopProduct $shopProduct, string $totalPriceString): string;
|
|
||||||
}
|
|
|
@ -2,68 +2,46 @@
|
||||||
|
|
||||||
namespace App\Classes;
|
namespace App\Classes;
|
||||||
|
|
||||||
use App\Models\Pterodactyl\Egg;
|
use App\Models\Egg;
|
||||||
use App\Models\Pterodactyl\Nest;
|
use App\Models\Nest;
|
||||||
use App\Models\Pterodactyl\Node;
|
use App\Models\Node;
|
||||||
use App\Models\Product;
|
use App\Models\Product;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
|
use App\Models\User;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Http\Client\PendingRequest;
|
use Illuminate\Http\Client\PendingRequest;
|
||||||
use Illuminate\Http\Client\Response;
|
use Illuminate\Http\Client\Response;
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
use App\Settings\PterodactylSettings;
|
|
||||||
use App\Settings\ServerSettings;
|
|
||||||
|
|
||||||
class PterodactylClient
|
class Pterodactyl
|
||||||
{
|
{
|
||||||
//TODO: Extend error handling (maybe logger for more errors when debugging)
|
//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
|
* @return PendingRequest
|
||||||
*/
|
*/
|
||||||
public function client(PterodactylSettings $ptero_settings)
|
public static function client()
|
||||||
{
|
{
|
||||||
return Http::withHeaders([
|
return Http::withHeaders([
|
||||||
'Authorization' => 'Bearer ' . $ptero_settings->user_token,
|
'Authorization' => 'Bearer ' . config('SETTINGS::SYSTEM:PTERODACTYL:TOKEN'),
|
||||||
'Content-type' => 'application/json',
|
'Content-type' => 'application/json',
|
||||||
'Accept' => 'Application/vnd.pterodactyl.v1+json',
|
'Accept' => 'Application/vnd.pterodactyl.v1+json',
|
||||||
])->baseUrl($ptero_settings->getUrl() . 'api' . '/');
|
])->baseUrl(config('SETTINGS::SYSTEM:PTERODACTYL:URL') . '/api');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function clientAdmin(PterodactylSettings $ptero_settings)
|
public static function clientAdmin()
|
||||||
{
|
{
|
||||||
return Http::withHeaders([
|
return Http::withHeaders([
|
||||||
'Authorization' => 'Bearer ' . $ptero_settings->admin_token,
|
'Authorization' => 'Bearer ' . config('SETTINGS::SYSTEM:PTERODACTYL:ADMIN_USER_TOKEN'),
|
||||||
'Content-type' => 'application/json',
|
'Content-type' => 'application/json',
|
||||||
'Accept' => 'Application/vnd.pterodactyl.v1+json',
|
'Accept' => 'Application/vnd.pterodactyl.v1+json',
|
||||||
])->baseUrl($ptero_settings->getUrl() . 'api' . '/');
|
])->baseUrl(config('SETTINGS::SYSTEM:PTERODACTYL:URL') . '/api');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Exception
|
* @return Exception
|
||||||
*/
|
*/
|
||||||
private function getException(string $message = '', int $status = 0): Exception
|
private static function getException(string $message = '', int $status = 0): Exception
|
||||||
{
|
{
|
||||||
if ($status == 404) {
|
if ($status == 404) {
|
||||||
return new Exception('Ressource does not exist on pterodactyl - ' . $message, 404);
|
return new Exception('Ressource does not exist on pterodactyl - ' . $message, 404);
|
||||||
|
@ -90,10 +68,10 @@ class PterodactylClient
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function getEggs(Nest $nest)
|
public static function getEggs(Nest $nest)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$response = $this->application->get("application/nests/{$nest->id}/eggs?include=nest,variables&per_page=" . $this->per_page_limit);
|
$response = self::client()->get("/application/nests/{$nest->id}/eggs?include=nest,variables&per_page=" . config('SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT'));
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
throw self::getException($e->getMessage());
|
throw self::getException($e->getMessage());
|
||||||
}
|
}
|
||||||
|
@ -109,10 +87,10 @@ class PterodactylClient
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function getNodes()
|
public static function getNodes()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$response = $this->application->get('application/nodes?per_page=' . $this->per_page_limit);
|
$response = self::client()->get('/application/nodes?per_page=' . config('SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT'));
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
throw self::getException($e->getMessage());
|
throw self::getException($e->getMessage());
|
||||||
}
|
}
|
||||||
|
@ -129,10 +107,10 @@ class PterodactylClient
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
* @description Returns the infos of a single node
|
* @description Returns the infos of a single node
|
||||||
*/
|
*/
|
||||||
public function getNode($id)
|
public static function getNode($id)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$response = $this->application->get('application/nodes/' . $id);
|
$response = self::client()->get('/application/nodes/' . $id);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
throw self::getException($e->getMessage());
|
throw self::getException($e->getMessage());
|
||||||
}
|
}
|
||||||
|
@ -143,10 +121,10 @@ class PterodactylClient
|
||||||
return $response->json()['attributes'];
|
return $response->json()['attributes'];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getServers()
|
public static function getServers()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$response = $this->application->get('application/servers?per_page=' . $this->per_page_limit);
|
$response = self::client()->get('/application/servers?per_page=' . config('SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT'));
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
throw self::getException($e->getMessage());
|
throw self::getException($e->getMessage());
|
||||||
}
|
}
|
||||||
|
@ -162,10 +140,10 @@ class PterodactylClient
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function getNests()
|
public static function getNests()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$response = $this->application->get('application/nests?per_page=' . $this->per_page_limit);
|
$response = self::client()->get('/application/nests?per_page=' . config('SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT'));
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
throw self::getException($e->getMessage());
|
throw self::getException($e->getMessage());
|
||||||
}
|
}
|
||||||
|
@ -181,10 +159,10 @@ class PterodactylClient
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function getLocations()
|
public static function getLocations()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$response = $this->application->get('application/locations?per_page=' . $this->per_page_limit);
|
$response = self::client()->get('/application/locations?per_page=' . config('SETTINGS::SYSTEM:PTERODACTYL:PER_PAGE_LIMIT'));
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
throw self::getException($e->getMessage());
|
throw self::getException($e->getMessage());
|
||||||
}
|
}
|
||||||
|
@ -201,7 +179,7 @@ class PterodactylClient
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function getFreeAllocationId(Node $node)
|
public static function getFreeAllocationId(Node $node)
|
||||||
{
|
{
|
||||||
return self::getFreeAllocations($node)[0]['attributes']['id'] ?? null;
|
return self::getFreeAllocations($node)[0]['attributes']['id'] ?? null;
|
||||||
}
|
}
|
||||||
|
@ -212,7 +190,7 @@ class PterodactylClient
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function getFreeAllocations(Node $node)
|
public static function getFreeAllocations(Node $node)
|
||||||
{
|
{
|
||||||
$response = self::getAllocations($node);
|
$response = self::getAllocations($node);
|
||||||
$freeAllocations = [];
|
$freeAllocations = [];
|
||||||
|
@ -236,10 +214,11 @@ class PterodactylClient
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function getAllocations(Node $node)
|
public static function getAllocations(Node $node)
|
||||||
{
|
{
|
||||||
|
$per_page = config('SETTINGS::SERVER:ALLOCATION_LIMIT', 200);
|
||||||
try {
|
try {
|
||||||
$response = $this->application->get("application/nodes/{$node->id}/allocations?per_page={$this->allocation_limit}");
|
$response = self::client()->get("/application/nodes/{$node->id}/allocations?per_page={$per_page}");
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
throw self::getException($e->getMessage());
|
throw self::getException($e->getMessage());
|
||||||
}
|
}
|
||||||
|
@ -250,15 +229,24 @@ class PterodactylClient
|
||||||
return $response->json();
|
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 Server $server
|
||||||
* @param Egg $egg
|
* @param Egg $egg
|
||||||
* @param int $allocationId
|
* @param int $allocationId
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
public function createServer(Server $server, Egg $egg, int $allocationId)
|
public static function createServer(Server $server, Egg $egg, int $allocationId)
|
||||||
{
|
{
|
||||||
return $this->application->post('application/servers', [
|
return self::client()->post('/application/servers', [
|
||||||
'name' => $server->name,
|
'name' => $server->name,
|
||||||
'external_id' => $server->id,
|
'external_id' => $server->id,
|
||||||
'user' => $server->user->pterodactyl_id,
|
'user' => $server->user->pterodactyl_id,
|
||||||
|
@ -266,7 +254,6 @@ class PterodactylClient
|
||||||
'docker_image' => $egg->docker_image,
|
'docker_image' => $egg->docker_image,
|
||||||
'startup' => $egg->startup,
|
'startup' => $egg->startup,
|
||||||
'environment' => $egg->getEnvironmentVariables(),
|
'environment' => $egg->getEnvironmentVariables(),
|
||||||
'oom_disabled' => !$server->product->oom_killer,
|
|
||||||
'limits' => [
|
'limits' => [
|
||||||
'memory' => $server->product->memory,
|
'memory' => $server->product->memory,
|
||||||
'swap' => $server->product->swap,
|
'swap' => $server->product->swap,
|
||||||
|
@ -285,10 +272,10 @@ class PterodactylClient
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function suspendServer(Server $server)
|
public static function suspendServer(Server $server)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$response = $this->application->post("application/servers/$server->pterodactyl_id/suspend");
|
$response = self::client()->post("/application/servers/$server->pterodactyl_id/suspend");
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
throw self::getException($e->getMessage());
|
throw self::getException($e->getMessage());
|
||||||
}
|
}
|
||||||
|
@ -299,10 +286,10 @@ class PterodactylClient
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function unSuspendServer(Server $server)
|
public static function unSuspendServer(Server $server)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$response = $this->application->post("application/servers/$server->pterodactyl_id/unsuspend");
|
$response = self::client()->post("/application/servers/$server->pterodactyl_id/unsuspend");
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
throw self::getException($e->getMessage());
|
throw self::getException($e->getMessage());
|
||||||
}
|
}
|
||||||
|
@ -322,7 +309,7 @@ class PterodactylClient
|
||||||
public function getUser(int $pterodactylId)
|
public function getUser(int $pterodactylId)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$response = $this->application->get("application/users/{$pterodactylId}");
|
$response = self::client()->get("/application/users/{$pterodactylId}");
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
throw self::getException($e->getMessage());
|
throw self::getException($e->getMessage());
|
||||||
}
|
}
|
||||||
|
@ -339,10 +326,10 @@ class PterodactylClient
|
||||||
* @param int $pterodactylId
|
* @param int $pterodactylId
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function getServerAttributes(int $pterodactylId, bool $deleteOn404 = false)
|
public static function getServerAttributes(int $pterodactylId, bool $deleteOn404 = false)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$response = $this->application->get("application/servers/{$pterodactylId}?include=egg,node,nest,location");
|
$response = self::client()->get("/application/servers/{$pterodactylId}?include=egg,node,nest,location");
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
throw self::getException($e->getMessage());
|
throw self::getException($e->getMessage());
|
||||||
}
|
}
|
||||||
|
@ -369,9 +356,9 @@ class PterodactylClient
|
||||||
* @param Product $product
|
* @param Product $product
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
public function updateServer(Server $server, Product $product)
|
public static function updateServer(Server $server, Product $product)
|
||||||
{
|
{
|
||||||
return $this->application->patch("application/servers/{$server->pterodactyl_id}/build", [
|
return self::client()->patch("/application/servers/{$server->pterodactyl_id}/build", [
|
||||||
'allocation' => $server->allocation,
|
'allocation' => $server->allocation,
|
||||||
'memory' => $product->memory,
|
'memory' => $product->memory,
|
||||||
'swap' => $product->swap,
|
'swap' => $product->swap,
|
||||||
|
@ -379,7 +366,6 @@ class PterodactylClient
|
||||||
'io' => $product->io,
|
'io' => $product->io,
|
||||||
'cpu' => $product->cpu,
|
'cpu' => $product->cpu,
|
||||||
'threads' => null,
|
'threads' => null,
|
||||||
'oom_disabled' => !$server->product->oom_killer,
|
|
||||||
'feature_limits' => [
|
'feature_limits' => [
|
||||||
'databases' => $product->databases,
|
'databases' => $product->databases,
|
||||||
'backups' => $product->backups,
|
'backups' => $product->backups,
|
||||||
|
@ -395,9 +381,9 @@ class PterodactylClient
|
||||||
* @param Server $server
|
* @param Server $server
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function updateServerOwner(Server $server, int $userId)
|
public static function updateServerOwner(Server $server, int $userId)
|
||||||
{
|
{
|
||||||
return $this->application->patch("application/servers/{$server->pterodactyl_id}/details", [
|
return self::client()->patch("/application/servers/{$server->pterodactyl_id}/details", [
|
||||||
'name' => $server->name,
|
'name' => $server->name,
|
||||||
'user' => $userId,
|
'user' => $userId,
|
||||||
]);
|
]);
|
||||||
|
@ -410,9 +396,9 @@ class PterodactylClient
|
||||||
* @param string $action
|
* @param string $action
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
public function powerAction(Server $server, $action)
|
public static function powerAction(Server $server, $action)
|
||||||
{
|
{
|
||||||
return $this->client->post("client/servers/{$server->identifier}/power", [
|
return self::clientAdmin()->post("/client/servers/{$server->identifier}/power", [
|
||||||
'signal' => $action,
|
'signal' => $action,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -420,9 +406,9 @@ class PterodactylClient
|
||||||
/**
|
/**
|
||||||
* Get info about user
|
* Get info about user
|
||||||
*/
|
*/
|
||||||
public function getClientUser()
|
public static function getClientUser()
|
||||||
{
|
{
|
||||||
return $this->client->get('client/account');
|
return self::clientAdmin()->get('/client/account');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -433,10 +419,10 @@ class PterodactylClient
|
||||||
* @param int $requireDisk
|
* @param int $requireDisk
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function checkNodeResources(Node $node, int $requireMemory, int $requireDisk)
|
public static function checkNodeResources(Node $node, int $requireMemory, int $requireDisk)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$response = $this->application->get("application/nodes/{$node->id}");
|
$response = self::client()->get("/application/nodes/{$node->id}");
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
throw self::getException($e->getMessage());
|
throw self::getException($e->getMessage());
|
||||||
}
|
}
|
47
app/Classes/Settings/Invoices.php
Normal file
47
app/Classes/Settings/Invoices.php
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<?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!'));
|
||||||
|
}
|
||||||
|
}
|
56
app/Classes/Settings/Language.php
Normal file
56
app/Classes/Settings/Language.php
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
<?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!'));
|
||||||
|
}
|
||||||
|
}
|
107
app/Classes/Settings/Misc.php
Normal file
107
app/Classes/Settings/Misc.php
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
<?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!'));
|
||||||
|
}
|
||||||
|
}
|
58
app/Classes/Settings/Payments.php
Normal file
58
app/Classes/Settings/Payments.php
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
<?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!'));
|
||||||
|
}
|
||||||
|
}
|
154
app/Classes/Settings/System.php
Normal file
154
app/Classes/Settings/System.php
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
<?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');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,139 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Console\Commands;
|
|
||||||
|
|
||||||
use App\Models\Server;
|
|
||||||
use App\Notifications\ServersSuspendedNotification;
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use Illuminate\Console\Command;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
|
|
||||||
class ChargeServers extends Command
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The name and signature of the console command.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $signature = 'servers:charge';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The console command description.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $description = 'Charge all users with severs that are due to be charged';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of users that have to be notified
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected $usersToNotify = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new command instance.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
parent::__construct();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the console command.
|
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function handle()
|
|
||||||
{
|
|
||||||
Server::whereNull('suspended')->with('user', 'product')->chunk(10, function ($servers) {
|
|
||||||
/** @var Server $server */
|
|
||||||
foreach ($servers as $server) {
|
|
||||||
/** @var Product $product */
|
|
||||||
$product = $server->product;
|
|
||||||
/** @var User $user */
|
|
||||||
$user = $server->user;
|
|
||||||
|
|
||||||
$billing_period = $product->billing_period;
|
|
||||||
|
|
||||||
|
|
||||||
// check if server is due to be charged by comparing its last_billed date with the current date and the billing period
|
|
||||||
$newBillingDate = null;
|
|
||||||
switch ($billing_period) {
|
|
||||||
case 'annually':
|
|
||||||
$newBillingDate = Carbon::parse($server->last_billed)->addYear();
|
|
||||||
break;
|
|
||||||
case 'half-annually':
|
|
||||||
$newBillingDate = Carbon::parse($server->last_billed)->addMonths(6);
|
|
||||||
break;
|
|
||||||
case 'quarterly':
|
|
||||||
$newBillingDate = Carbon::parse($server->last_billed)->addMonths(3);
|
|
||||||
break;
|
|
||||||
case 'monthly':
|
|
||||||
$newBillingDate = Carbon::parse($server->last_billed)->addMonth();
|
|
||||||
break;
|
|
||||||
case 'weekly':
|
|
||||||
$newBillingDate = Carbon::parse($server->last_billed)->addWeek();
|
|
||||||
break;
|
|
||||||
case 'daily':
|
|
||||||
$newBillingDate = Carbon::parse($server->last_billed)->addDay();
|
|
||||||
break;
|
|
||||||
case 'hourly':
|
|
||||||
$newBillingDate = Carbon::parse($server->last_billed)->addHour();
|
|
||||||
default:
|
|
||||||
$newBillingDate = Carbon::parse($server->last_billed)->addHour();
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!($newBillingDate->isPast())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if the server is canceled or if user has enough credits to charge the server or
|
|
||||||
if ($server->canceled || $user->credits <= $product->price) {
|
|
||||||
try {
|
|
||||||
// suspend server
|
|
||||||
$this->line("<fg=yellow>{$server->name}</> from user: <fg=blue>{$user->name}</> has been <fg=red>suspended!</>");
|
|
||||||
$server->suspend();
|
|
||||||
|
|
||||||
// add user to notify list
|
|
||||||
if (!in_array($user, $this->usersToNotify)) {
|
|
||||||
array_push($this->usersToNotify, $user);
|
|
||||||
}
|
|
||||||
} catch (\Exception $exception) {
|
|
||||||
$this->error($exception->getMessage());
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// charge credits to user
|
|
||||||
$this->line("<fg=blue>{$user->name}</> Current credits: <fg=green>{$user->credits}</> Credits to be removed: <fg=red>{$product->price}</>");
|
|
||||||
$user->decrement('credits', $product->price);
|
|
||||||
|
|
||||||
// update server last_billed date in db
|
|
||||||
DB::table('servers')->where('id', $server->id)->update(['last_billed' => $newBillingDate]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->notifyUsers();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function notifyUsers()
|
|
||||||
{
|
|
||||||
if (!empty($this->usersToNotify)) {
|
|
||||||
/** @var User $user */
|
|
||||||
foreach ($this->usersToNotify as $user) {
|
|
||||||
$this->line("<fg=yellow>Notified user:</> <fg=blue>{$user->name}</>");
|
|
||||||
$user->notify(new ServersSuspendedNotification());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#reset array
|
|
||||||
$this->usersToNotify = array();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Console\Commands;
|
|
||||||
|
|
||||||
use App\Settings\CouponSettings;
|
|
||||||
use App\Models\Coupon;
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use Illuminate\Console\Command;
|
|
||||||
|
|
||||||
|
|
||||||
class DeleteExpiredCoupons extends Command
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The name and signature of the console command.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $signature = 'coupons:delete';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The console command description.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $description = 'Delete expired coupons from DB.';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the console command.
|
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function handle(CouponSettings $couponSettings)
|
|
||||||
{
|
|
||||||
if ($couponSettings->delete_coupon_on_expires) {
|
|
||||||
$expired_coupons = Coupon::where('expires_at', '<=', Carbon::now(config('app.timezone')))->get();
|
|
||||||
|
|
||||||
foreach ($expired_coupons as $expired_coupon) {
|
|
||||||
$expired_coupon->delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,20 +2,18 @@
|
||||||
|
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
use App\Classes\PterodactylClient;
|
use App\Classes\Pterodactyl;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Settings\PterodactylSettings;
|
|
||||||
use App\Traits\Referral;
|
use App\Traits\Referral;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use Illuminate\Support\Facades\Hash;
|
use Illuminate\Support\Facades\Hash;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class MakeUserCommand extends Command
|
class MakeUserCommand extends Command
|
||||||
{
|
{
|
||||||
use Referral;
|
use Referral;
|
||||||
|
|
||||||
private $pterodactyl;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name and signature of the console command.
|
* The name and signature of the console command.
|
||||||
*
|
*
|
||||||
|
@ -30,14 +28,17 @@ class MakeUserCommand extends Command
|
||||||
*/
|
*/
|
||||||
protected $description = 'Create an admin account with the Artisan Console';
|
protected $description = 'Create an admin account with the Artisan Console';
|
||||||
|
|
||||||
|
private Pterodactyl $pterodactyl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new command instance.
|
* Create a new command instance.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function __construct()
|
public function __construct(Pterodactyl $pterodactyl)
|
||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
|
$this->pterodactyl = $pterodactyl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,9 +47,8 @@ class MakeUserCommand extends Command
|
||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function handle(PterodactylSettings $ptero_settings)
|
public function handle()
|
||||||
{
|
{
|
||||||
$this->pterodactyl = new PterodactylClient($ptero_settings);
|
|
||||||
$ptero_id = $this->option('ptero_id') ?? $this->ask('Please specify your Pterodactyl ID.');
|
$ptero_id = $this->option('ptero_id') ?? $this->ask('Please specify your Pterodactyl ID.');
|
||||||
$password = $this->secret('password') ?? $this->ask('Please specify your password.');
|
$password = $this->secret('password') ?? $this->ask('Please specify your password.');
|
||||||
|
|
||||||
|
@ -101,8 +101,6 @@ class MakeUserCommand extends Command
|
||||||
['Referral code', $user->referral_code],
|
['Referral code', $user->referral_code],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$user->syncRoles(1);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,17 +8,6 @@ use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
class Kernel extends ConsoleKernel
|
class Kernel extends ConsoleKernel
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* The Artisan commands provided by your application.
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected $commands = [
|
|
||||||
Commands\ChargeCreditsCommand::class,
|
|
||||||
Commands\ChargeServers::class,
|
|
||||||
Commands\DeleteExpiredCoupons::class,
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define the application's command schedule.
|
* Define the application's command schedule.
|
||||||
*
|
*
|
||||||
|
@ -27,10 +16,9 @@ class Kernel extends ConsoleKernel
|
||||||
*/
|
*/
|
||||||
protected function schedule(Schedule $schedule)
|
protected function schedule(Schedule $schedule)
|
||||||
{
|
{
|
||||||
$schedule->command('servers:charge')->everyMinute();
|
$schedule->command('credits:charge')->hourly();
|
||||||
$schedule->command('cp:versioncheck:get')->daily();
|
$schedule->command('cp:versioncheck:get')->daily();
|
||||||
$schedule->command('payments:open:clear')->daily();
|
$schedule->command('payments:open:clear')->daily();
|
||||||
$schedule->command('coupons:delete')->daily();
|
|
||||||
|
|
||||||
//log cronjob activity
|
//log cronjob activity
|
||||||
$schedule->call(function () {
|
$schedule->call(function () {
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Enums;
|
|
||||||
|
|
||||||
// Payment status are open, processing, paid and canceled
|
|
||||||
enum PaymentStatus: String
|
|
||||||
{
|
|
||||||
case OPEN = "open";
|
|
||||||
case PROCESSING = "processing";
|
|
||||||
case PAID = "paid";
|
|
||||||
case CANCELED = "canceled";
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Events;
|
|
||||||
|
|
||||||
use App\Models\Coupon;
|
|
||||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
|
||||||
use Illuminate\Foundation\Events\Dispatchable;
|
|
||||||
use Illuminate\Queue\SerializesModels;
|
|
||||||
|
|
||||||
class CouponUsedEvent
|
|
||||||
{
|
|
||||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
|
||||||
|
|
||||||
public Coupon $coupon;
|
|
||||||
public string $couponCode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new event instance.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __construct(string $couponCode)
|
|
||||||
{
|
|
||||||
|
|
||||||
$this->couponCode = $couponCode;
|
|
||||||
$this->coupon = Coupon::where('code', $couponCode)->first();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,119 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Extensions\PaymentGateways\Mollie;
|
|
||||||
|
|
||||||
use App\Classes\AbstractExtension;
|
|
||||||
use App\Enums\PaymentStatus;
|
|
||||||
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\Models\Coupon;
|
|
||||||
use App\Traits\Coupon as CouponTrait;
|
|
||||||
use App\Events\CouponUsedEvent;
|
|
||||||
use Exception;
|
|
||||||
use Illuminate\Http\JsonResponse;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
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
|
|
||||||
{
|
|
||||||
use CouponTrait;
|
|
||||||
|
|
||||||
public static function getConfig(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
"name" => "Mollie",
|
|
||||||
"RoutesIgnoreCsrf" => [
|
|
||||||
"payment/MollieWebhook"
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getRedirectUrl(Payment $payment, ShopProduct $shopProduct, string $totalPriceString): string
|
|
||||||
{
|
|
||||||
$url = 'https://api.mollie.com/v2/payments';
|
|
||||||
$settings = new MollieSettings();
|
|
||||||
try {
|
|
||||||
$response = Http::withHeaders([
|
|
||||||
'Content-Type' => 'application/json',
|
|
||||||
'Authorization' => 'Bearer ' . $settings->api_key,
|
|
||||||
])->post($url, [
|
|
||||||
'amount' => [
|
|
||||||
'currency' => $shopProduct->currency_code,
|
|
||||||
'value' => $totalPriceString,
|
|
||||||
],
|
|
||||||
'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());
|
|
||||||
throw new Exception('Payment failed');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $response->json()['_links']['checkout']['href'];
|
|
||||||
} catch (Exception $ex) {
|
|
||||||
Log::error('Mollie Payment: ' . $ex->getMessage());
|
|
||||||
throw new Exception('Payment failed');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static function success(Request $request): void
|
|
||||||
{
|
|
||||||
$payment = Payment::findOrFail($request->input('payment'));
|
|
||||||
$payment->status = PaymentStatus::PROCESSING;
|
|
||||||
$payment->save();
|
|
||||||
|
|
||||||
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']);
|
|
||||||
$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);
|
|
||||||
$payment->status = PaymentStatus::PAID;
|
|
||||||
$payment->save();
|
|
||||||
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]);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
<?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 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',
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
<?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');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Route;
|
|
||||||
use App\Extensions\PaymentGateways\Mollie\MollieExtension;
|
|
||||||
|
|
||||||
Route::middleware(['web', 'auth'])->group(function () {
|
|
||||||
Route::get(
|
|
||||||
'payment/MollieSuccess',
|
|
||||||
function () {
|
|
||||||
MollieExtension::success(request());
|
|
||||||
}
|
|
||||||
)->name('payment.MollieSuccess');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
Route::post('payment/MollieWebhook', function () {
|
|
||||||
MollieExtension::webhook(request());
|
|
||||||
})->name('payment.MollieWebhook');
|
|
|
@ -1,178 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Extensions\PaymentGateways\PayPal;
|
|
||||||
|
|
||||||
use App\Events\CouponUsedEvent;
|
|
||||||
use App\Events\PaymentEvent;
|
|
||||||
use App\Events\UserUpdateCreditsEvent;
|
|
||||||
use App\Extensions\PaymentGateways\PayPal\PayPalSettings;
|
|
||||||
use App\Classes\PaymentExtension;
|
|
||||||
use App\Enums\PaymentStatus;
|
|
||||||
use App\Models\PartnerDiscount;
|
|
||||||
use App\Models\Payment;
|
|
||||||
use App\Models\ShopProduct;
|
|
||||||
use App\Models\User;
|
|
||||||
use App\Models\Coupon;
|
|
||||||
use App\Traits\Coupon as CouponTrait;
|
|
||||||
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 PaymentExtension
|
|
||||||
{
|
|
||||||
use CouponTrait;
|
|
||||||
|
|
||||||
public static function getConfig(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
"name" => "PayPal",
|
|
||||||
"RoutesIgnoreCsrf" => [],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getRedirectUrl(Payment $payment, ShopProduct $shopProduct, string $totalPriceString): string
|
|
||||||
{
|
|
||||||
$request = new OrdersCreateRequest();
|
|
||||||
$request->prefer('return=representation');
|
|
||||||
$request->body = [
|
|
||||||
"intent" => "CAPTURE",
|
|
||||||
"purchase_units" => [
|
|
||||||
[
|
|
||||||
"reference_id" => uniqid(),
|
|
||||||
"description" => $shopProduct->display,
|
|
||||||
"amount" => [
|
|
||||||
"value" => $totalPriceString,
|
|
||||||
'currency_code' => strtoupper($shopProduct->currency_code),
|
|
||||||
'breakdown' => [
|
|
||||||
'item_total' => [
|
|
||||||
'currency_code' => strtoupper($shopProduct->currency_code),
|
|
||||||
'value' => $totalPriceString
|
|
||||||
],
|
|
||||||
'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', 'CtrlPanel.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');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $response->result->links[1]->href;
|
|
||||||
} catch (HttpException $ex) {
|
|
||||||
Log::error('PayPal Payment: ' . $ex->getMessage());
|
|
||||||
|
|
||||||
throw new \Exception('PayPal Payment: ' . $ex->getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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' => PaymentStatus::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' => PaymentStatus::CANCELED,
|
|
||||||
'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' => PaymentStatus::CANCELED,
|
|
||||||
'payment_id' => $response->result->id,
|
|
||||||
]);
|
|
||||||
abort(422);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static function getPayPalClient(): PayPalHttpClient
|
|
||||||
{
|
|
||||||
|
|
||||||
$environment = config('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 config('app.env') == 'local' ? $settings->sandbox_client_id : $settings->client_id;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
static function getPaypalClientSecret(): string
|
|
||||||
{
|
|
||||||
$settings = new PayPalSettings();
|
|
||||||
return config('app.env') == 'local' ? $settings->sandbox_client_secret : $settings->client_secret;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
<?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';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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',
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
13
app/Extensions/PaymentGateways/PayPal/config.php
Normal file
13
app/Extensions/PaymentGateways/PayPal/config.php
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?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"),
|
||||||
|
];
|
||||||
|
}
|
186
app/Extensions/PaymentGateways/PayPal/index.php
Normal file
186
app/Extensions/PaymentGateways/PayPal/index.php
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
<?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', 'CtrlPanel.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");
|
||||||
|
}
|
|
@ -1,104 +0,0 @@
|
||||||
<?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();
|
|
||||||
|
|
||||||
if (is_null($old_value)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +1,18 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
use App\Extensions\PaymentGateways\PayPal\PayPalExtension;
|
|
||||||
|
include_once(__DIR__ . '/index.php');
|
||||||
|
|
||||||
Route::middleware(['web', 'auth'])->group(function () {
|
Route::middleware(['web', 'auth'])->group(function () {
|
||||||
|
Route::get('payment/PayPalPay/{shopProduct}', function () {
|
||||||
|
PaypalPay(request());
|
||||||
|
})->name('payment.PayPalPay');
|
||||||
|
|
||||||
Route::get(
|
Route::get(
|
||||||
'payment/PayPalSuccess',
|
'payment/PayPalSuccess',
|
||||||
function () {
|
function () {
|
||||||
PayPalExtension::PaypalSuccess(request());
|
PaypalSuccess(request());
|
||||||
}
|
}
|
||||||
)->name('payment.PayPalSuccess');
|
)->name('payment.PayPalSuccess');
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,368 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Extensions\PaymentGateways\Stripe;
|
|
||||||
|
|
||||||
use App\Classes\AbstractExtension;
|
|
||||||
use App\Enums\PaymentStatus;
|
|
||||||
use App\Events\PaymentEvent;
|
|
||||||
use App\Events\CouponUsedEvent;
|
|
||||||
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\Models\Coupon;
|
|
||||||
use App\Traits\Coupon as CouponTrait;
|
|
||||||
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
|
|
||||||
{
|
|
||||||
use CouponTrait;
|
|
||||||
|
|
||||||
public static function getConfig(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
"name" => "Stripe",
|
|
||||||
"RoutesIgnoreCsrf" => [
|
|
||||||
"payment/StripeWebhooks",
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getRedirectUrl(Payment $payment, ShopProduct $shopProduct, string $totalPriceString): string
|
|
||||||
{
|
|
||||||
// check if the total price is valid for stripe
|
|
||||||
$totalPriceNumber = floatval($totalPriceString);
|
|
||||||
if (!self::checkPriceAmount($totalPriceNumber, strtoupper($shopProduct->currency_code), 'stripe')) {
|
|
||||||
throw new Exception('Invalid price amount');
|
|
||||||
}
|
|
||||||
|
|
||||||
$stripeClient = self::getStripeClient();
|
|
||||||
$request = $stripeClient->checkout->sessions->create([
|
|
||||||
'line_items' => [
|
|
||||||
[
|
|
||||||
'price_data' => [
|
|
||||||
'currency' => $shopProduct->currency_code,
|
|
||||||
'product_data' => [
|
|
||||||
'name' => $shopProduct->display,
|
|
||||||
'description' => $shopProduct->description,
|
|
||||||
],
|
|
||||||
'unit_amount_decimal' => $totalPriceString,
|
|
||||||
],
|
|
||||||
'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,
|
|
||||||
],
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
return $request->url;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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' => PaymentStatus::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' => PaymentStatus::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' => PaymentStatus::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(float $amount, string $currencyCode, string $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];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
<?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 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',
|
|
||||||
]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
15
app/Extensions/PaymentGateways/Stripe/config.php
Normal file
15
app/Extensions/PaymentGateways/Stripe/config.php
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?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",
|
||||||
|
];
|
||||||
|
}
|
373
app/Extensions/PaymentGateways/Stripe/index.php
Normal file
373
app/Extensions/PaymentGateways/Stripe/index.php
Normal file
|
@ -0,0 +1,373 @@
|
||||||
|
<?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];
|
||||||
|
}
|
|
@ -1,102 +0,0 @@
|
||||||
<?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->add('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->add('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();
|
|
||||||
|
|
||||||
if (is_null($old_value)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +1,17 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
use App\Extensions\PaymentGateways\Stripe\StripeExtension;
|
|
||||||
|
|
||||||
|
include_once(__DIR__ . '/index.php');
|
||||||
Route::middleware(['web', 'auth'])->group(function () {
|
Route::middleware(['web', 'auth'])->group(function () {
|
||||||
|
Route::get('payment/StripePay/{shopProduct}', function () {
|
||||||
|
StripePay(request());
|
||||||
|
})->name('payment.StripePay');
|
||||||
|
|
||||||
Route::get(
|
Route::get(
|
||||||
'payment/StripeSuccess',
|
'payment/StripeSuccess',
|
||||||
function () {
|
function () {
|
||||||
StripeExtension::StripeSuccess(request());
|
StripeSuccess(request());
|
||||||
}
|
}
|
||||||
)->name('payment.StripeSuccess');
|
)->name('payment.StripeSuccess');
|
||||||
});
|
});
|
||||||
|
@ -15,5 +19,5 @@ Route::middleware(['web', 'auth'])->group(function () {
|
||||||
|
|
||||||
// Stripe WebhookRoute -> validation in Route Handler
|
// Stripe WebhookRoute -> validation in Route Handler
|
||||||
Route::post('payment/StripeWebhooks', function () {
|
Route::post('payment/StripeWebhooks', function () {
|
||||||
StripeExtension::StripeWebhooks(request());
|
StripeWebhooks(request());
|
||||||
})->name('payment.StripeWebhooks');
|
})->name('payment.StripeWebhooks');
|
||||||
|
|
|
@ -2,14 +2,65 @@
|
||||||
|
|
||||||
namespace App\Helpers;
|
namespace App\Helpers;
|
||||||
|
|
||||||
/**
|
|
||||||
* Summary of ExtensionHelper
|
|
||||||
*/
|
|
||||||
class 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
|
* Get all extensions
|
||||||
* @return array array of all extensions e.g. ["App\Extensions\PayPal", "App\Extensions\Stripe"]
|
* @return array
|
||||||
*/
|
*/
|
||||||
public static function getAllExtensions()
|
public static function getAllExtensions()
|
||||||
{
|
{
|
||||||
|
@ -19,207 +70,13 @@ class ExtensionHelper
|
||||||
$extensions = array_merge($extensions, glob($extensionNamespace . '/*', GLOB_ONLYDIR));
|
$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(app_path() . '/', 'App/', $item), $extensions);
|
|
||||||
|
|
||||||
return $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)
|
public static function getAllExtensionsByNamespace(string $namespace)
|
||||||
{
|
{
|
||||||
$extensions = glob(app_path() . '/Extensions/' . $namespace . '/*', GLOB_ONLYDIR);
|
$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(app_path() . '/', 'App/', $item), $extensions);
|
|
||||||
|
|
||||||
return $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();
|
|
||||||
|
|
||||||
// replace all slashes with backslashes
|
|
||||||
$extensions = array_map(fn ($item) => str_replace('/', '\\', $item), $extensions);
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// replace all slashes with backslashes
|
|
||||||
$extensions = array_map(fn ($item) => str_replace('/', '\\', $item), $extensions);
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
$extension = str_replace('/', '\\', $extension);
|
|
||||||
$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);
|
|
||||||
|
|
||||||
// replace all slashes with backslashes
|
|
||||||
$extension = str_replace('/', '\\', $extension);
|
|
||||||
$settingsClass = $extension . '\\' . $extensionName . 'Settings';
|
|
||||||
if (class_exists($settingsClass)) {
|
|
||||||
$settings[] = $settingsClass;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getExtensionSettings(string $extensionName)
|
|
||||||
{
|
|
||||||
$extension = self::getExtension($extensionName);
|
|
||||||
// replace all slashes with backslashes
|
|
||||||
$extension = str_replace('/', '\\', $extension);
|
|
||||||
|
|
||||||
$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('App/', '', $extensionName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@ use Spatie\Activitylog\Models\Activity;
|
||||||
|
|
||||||
class ActivityLogController extends Controller
|
class ActivityLogController extends Controller
|
||||||
{
|
{
|
||||||
const VIEW_PERMISSION = "admin.logs.read";
|
|
||||||
/**
|
/**
|
||||||
* Display a listing of the resource.
|
* Display a listing of the resource.
|
||||||
*
|
*
|
||||||
|
@ -22,9 +21,6 @@ class ActivityLogController extends Controller
|
||||||
*/
|
*/
|
||||||
public function index(Request $request)
|
public function index(Request $request)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::VIEW_PERMISSION);
|
|
||||||
|
|
||||||
|
|
||||||
$cronLogs = Storage::disk('logs')->exists('cron.log') ? Storage::disk('logs')->get('cron.log') : null;
|
$cronLogs = Storage::disk('logs')->exists('cron.log') ? Storage::disk('logs')->get('cron.log') : null;
|
||||||
|
|
||||||
if ($request->input('search')) {
|
if ($request->input('search')) {
|
||||||
|
|
|
@ -4,7 +4,6 @@ namespace App\Http\Controllers\Admin;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\ApplicationApi;
|
use App\Models\ApplicationApi;
|
||||||
use App\Settings\LocaleSettings;
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Contracts\Foundation\Application;
|
use Illuminate\Contracts\Foundation\Application;
|
||||||
use Illuminate\Contracts\View\Factory;
|
use Illuminate\Contracts\View\Factory;
|
||||||
|
@ -16,20 +15,14 @@ use Illuminate\Http\Response;
|
||||||
|
|
||||||
class ApplicationApiController extends Controller
|
class ApplicationApiController extends Controller
|
||||||
{
|
{
|
||||||
const READ_PERMISSION = "admin.api.read";
|
|
||||||
const WRITE_PERMISSION = "admin.api.write";
|
|
||||||
/**
|
/**
|
||||||
* Display a listing of the resource.
|
* Display a listing of the resource.
|
||||||
*
|
*
|
||||||
* @return Application|Factory|View|Response
|
* @return Application|Factory|View|Response
|
||||||
*/
|
*/
|
||||||
public function index(LocaleSettings $locale_settings)
|
public function index()
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::READ_PERMISSION);
|
return view('admin.api.index');
|
||||||
|
|
||||||
return view('admin.api.index', [
|
|
||||||
'locale_datatables' => $locale_settings->datatables
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,8 +32,6 @@ class ApplicationApiController extends Controller
|
||||||
*/
|
*/
|
||||||
public function create()
|
public function create()
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
|
|
||||||
return view('admin.api.create');
|
return view('admin.api.create');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +73,6 @@ class ApplicationApiController extends Controller
|
||||||
*/
|
*/
|
||||||
public function edit(ApplicationApi $applicationApi)
|
public function edit(ApplicationApi $applicationApi)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
return view('admin.api.edit', [
|
return view('admin.api.edit', [
|
||||||
'applicationApi' => $applicationApi,
|
'applicationApi' => $applicationApi,
|
||||||
]);
|
]);
|
||||||
|
@ -114,8 +104,6 @@ class ApplicationApiController extends Controller
|
||||||
*/
|
*/
|
||||||
public function destroy(ApplicationApi $applicationApi)
|
public function destroy(ApplicationApi $applicationApi)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
|
|
||||||
$applicationApi->delete();
|
$applicationApi->delete();
|
||||||
|
|
||||||
return redirect()->back()->with('success', __('api key has been removed!'));
|
return redirect()->back()->with('success', __('api key has been removed!'));
|
||||||
|
|
|
@ -1,242 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Models\Coupon;
|
|
||||||
use App\Settings\LocaleSettings;
|
|
||||||
use App\Traits\Coupon as CouponTrait;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Carbon\Carbon;
|
|
||||||
|
|
||||||
class CouponController extends Controller
|
|
||||||
{
|
|
||||||
const READ_PERMISSION = "admin.coupons.read";
|
|
||||||
const WRITE_PERMISSION = "admin.coupons.write";
|
|
||||||
|
|
||||||
use CouponTrait;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display a listing of the resource.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
|
||||||
public function index(LocaleSettings $localeSettings)
|
|
||||||
{
|
|
||||||
$this->checkPermission(self::READ_PERMISSION);
|
|
||||||
|
|
||||||
return view('admin.coupons.index', [
|
|
||||||
'locale_datatables' => $localeSettings->datatables
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for creating a new resource.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
|
||||||
public function create()
|
|
||||||
{
|
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
|
|
||||||
return view('admin.coupons.create');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store a newly created resource in storage.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
|
||||||
public function store(Request $request)
|
|
||||||
{
|
|
||||||
$coupon_code = $request->input('code');
|
|
||||||
$random_codes_amount = $request->input('range_codes');
|
|
||||||
$rules = $this->requestRules($request);
|
|
||||||
|
|
||||||
// If for some reason you pass both fields at once.
|
|
||||||
if ($coupon_code && $random_codes_amount) {
|
|
||||||
return redirect()->back()->with('error', __('Only one of the two code inputs must be provided.'))->withInput($request->all());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$coupon_code && !$random_codes_amount) {
|
|
||||||
return redirect()->back()->with('error', __('At least one of the two code inputs must be provided.'))->withInput($request->all());
|
|
||||||
}
|
|
||||||
|
|
||||||
$request->validate($rules);
|
|
||||||
|
|
||||||
if (array_key_exists('range_codes', $rules)) {
|
|
||||||
$data = [];
|
|
||||||
$coupons = Coupon::generateRandomCoupon($random_codes_amount);
|
|
||||||
|
|
||||||
// Scroll through all the randomly generated coupons.
|
|
||||||
foreach ($coupons as $coupon) {
|
|
||||||
$data[] = [
|
|
||||||
'code' => $coupon,
|
|
||||||
'type' => $request->input('type'),
|
|
||||||
'value' => $request->input('value'),
|
|
||||||
'max_uses' => $request->input('max_uses'),
|
|
||||||
'expires_at' => $request->input('expires_at'),
|
|
||||||
'created_at' => Carbon::now(), // Does not fill in by itself when using the 'insert' method.
|
|
||||||
'updated_at' => Carbon::now()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
Coupon::insert($data);
|
|
||||||
} else {
|
|
||||||
Coupon::create($request->except('_token'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirect()->route('admin.coupons.index')->with('success', __("The coupon's was registered successfully."));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display the specified resource.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Coupon $coupon
|
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
|
||||||
public function show(Coupon $coupon)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for editing the specified resource.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Coupon $coupon
|
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
|
||||||
public function edit(Coupon $coupon)
|
|
||||||
{
|
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
|
|
||||||
return view('admin.coupons.edit', [
|
|
||||||
'coupon' => $coupon,
|
|
||||||
'expired_at' => $coupon->expires_at ? Carbon::createFromTimestamp($coupon->expires_at) : null
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the specified resource in storage.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @param \App\Models\Coupon $coupon
|
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
|
||||||
public function update(Request $request, Coupon $coupon)
|
|
||||||
{
|
|
||||||
$coupon_code = $request->input('code');
|
|
||||||
$random_codes_amount = $request->input('range_codes');
|
|
||||||
$rules = $this->requestRules($request);
|
|
||||||
|
|
||||||
// If for some reason you pass both fields at once.
|
|
||||||
if ($coupon_code && $random_codes_amount) {
|
|
||||||
return redirect()->back()->with('error', __('Only one of the two code inputs must be provided.'))->withInput($request->all());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$coupon_code && !$random_codes_amount) {
|
|
||||||
return redirect()->back()->with('error', __('At least one of the two code inputs must be provided.'))->withInput($request->all());
|
|
||||||
}
|
|
||||||
|
|
||||||
$request->validate($rules);
|
|
||||||
$coupon->update($request->except('_token'));
|
|
||||||
|
|
||||||
return redirect()->route('admin.coupons.index')->with('success', __('coupon has been updated!'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the specified resource from storage.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Coupon $coupon
|
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
|
||||||
public function destroy(Coupon $coupon)
|
|
||||||
{
|
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
$coupon->delete();
|
|
||||||
|
|
||||||
return redirect()->back()->with('success', __('coupon has been removed!'));
|
|
||||||
}
|
|
||||||
|
|
||||||
private function requestRules(Request $request)
|
|
||||||
{
|
|
||||||
$coupon_code = $request->input('code');
|
|
||||||
$random_codes_amount = $request->input('range_codes');
|
|
||||||
$rules = [
|
|
||||||
"type" => "required|string|in:percentage,amount",
|
|
||||||
"max_uses" => "required|integer|digits_between:1,100",
|
|
||||||
"value" => "required|numeric|between:0,100",
|
|
||||||
"expires_at" => "nullable|date|after:" . Carbon::now()->format(Coupon::formatDate())
|
|
||||||
];
|
|
||||||
|
|
||||||
if ($coupon_code) {
|
|
||||||
$rules['code'] = "required|string|min:4";
|
|
||||||
} elseif ($random_codes_amount) {
|
|
||||||
$rules['range_codes'] = 'required|integer|digits_between:1,100';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $rules;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function redeem(Request $request)
|
|
||||||
{
|
|
||||||
return $this->validateCoupon($request->user(), $request->input('couponCode'), $request->input('productId'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function dataTable()
|
|
||||||
{
|
|
||||||
$query = Coupon::selectRaw('
|
|
||||||
coupons.*,
|
|
||||||
CASE
|
|
||||||
WHEN coupons.uses >= coupons.max_uses THEN "USES_LIMIT_REACHED"
|
|
||||||
WHEN coupons.expires_at IS NOT NULL AND coupons.expires_at < NOW() THEN "EXPIRED"
|
|
||||||
ELSE "VALID"
|
|
||||||
END as derived_status
|
|
||||||
');
|
|
||||||
|
|
||||||
return datatables($query)
|
|
||||||
->addColumn('actions', function(Coupon $coupon) {
|
|
||||||
return '
|
|
||||||
<a data-content="'.__('Edit').'" data-toggle="popover" data-trigger="hover" data-placement="top" href="'.route('admin.coupons.edit', $coupon->id).'" class="mr-1 btn btn-sm btn-info"><i class="fas fa-pen"></i></a>
|
|
||||||
|
|
||||||
<form class="d-inline" onsubmit="return submitResult();" method="post" action="'.route('admin.coupons.destroy', $coupon->id).'">
|
|
||||||
'.csrf_field().'
|
|
||||||
'.method_field('DELETE').'
|
|
||||||
<button data-content="'.__('Delete').'" data-toggle="popover" data-trigger="hover" data-placement="top" class="mr-1 btn btn-sm btn-danger"><i class="fas fa-trash"></i></button>
|
|
||||||
</form>
|
|
||||||
';
|
|
||||||
})
|
|
||||||
->addColumn('status', function (Coupon $coupon) {
|
|
||||||
$color = ($coupon->derived_status == 'VALID') ? 'success' : 'danger';
|
|
||||||
$status = str_replace('_', ' ', $coupon->derived_status);
|
|
||||||
|
|
||||||
return '<span class="badge badge-'.$color.'">'.$status.'</span>';
|
|
||||||
})
|
|
||||||
->editColumn('uses', function (Coupon $coupon) {
|
|
||||||
return "{$coupon->uses} / {$coupon->max_uses}";
|
|
||||||
})
|
|
||||||
->editColumn('value', function (Coupon $coupon) {
|
|
||||||
if ($coupon->type === 'percentage') {
|
|
||||||
return $coupon->value . "%";
|
|
||||||
}
|
|
||||||
|
|
||||||
return number_format($coupon->value, 2, '.', '');
|
|
||||||
})
|
|
||||||
->editColumn('expires_at', function (Coupon $coupon) {
|
|
||||||
if (!$coupon->expires_at) {
|
|
||||||
return __('Never');
|
|
||||||
}
|
|
||||||
|
|
||||||
return Carbon::createFromTimestamp($coupon->expires_at);
|
|
||||||
})
|
|
||||||
->editColumn('created_at', function(Coupon $coupon) {
|
|
||||||
return Carbon::createFromTimeString($coupon->created_at);
|
|
||||||
})
|
|
||||||
->editColumn('code', function (Coupon $coupon) {
|
|
||||||
return "<code>{$coupon->code}</code>";
|
|
||||||
})
|
|
||||||
->orderColumn('status', 'derived_status $1')
|
|
||||||
->rawColumns(['actions', 'code', 'status'])
|
|
||||||
->make();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -15,7 +15,7 @@ class InvoiceController extends Controller
|
||||||
$zip = new ZipArchive;
|
$zip = new ZipArchive;
|
||||||
$zip_safe_path = storage_path('invoices.zip');
|
$zip_safe_path = storage_path('invoices.zip');
|
||||||
$res = $zip->open($zip_safe_path, ZipArchive::CREATE | ZipArchive::OVERWRITE);
|
$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) {
|
if ($res === true) {
|
||||||
$zip->addFromString('1. Info.txt', __('Created at').' '.now()->format('d.m.Y'));
|
$zip->addFromString('1. Info.txt', __('Created at').' '.now()->format('d.m.Y'));
|
||||||
foreach ($result as $file) {
|
foreach ($result as $file) {
|
||||||
|
@ -38,7 +38,7 @@ class InvoiceController extends Controller
|
||||||
{
|
{
|
||||||
$files = glob($pattern, $flags);
|
$files = glob($pattern, $flags);
|
||||||
foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR | GLOB_NOSORT) as $dir) {
|
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;
|
return $files;
|
||||||
|
|
|
@ -10,8 +10,6 @@ use Qirolab\Theme\Theme;
|
||||||
|
|
||||||
class LegalController extends Controller
|
class LegalController extends Controller
|
||||||
{
|
{
|
||||||
const READ_PERMISSION = "admin.legal.read";
|
|
||||||
const WRITE_PERMISSION = "admin.legal.write";
|
|
||||||
/**
|
/**
|
||||||
* Display
|
* Display
|
||||||
*
|
*
|
||||||
|
@ -19,8 +17,6 @@ class LegalController extends Controller
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::READ_PERMISSION);
|
|
||||||
|
|
||||||
$tos = File::get(Theme::path($path = 'views', "default") . '/information/tos-content.blade.php');
|
$tos = File::get(Theme::path($path = 'views', "default") . '/information/tos-content.blade.php');
|
||||||
$privacy = File::get(Theme::path($path = 'views', "default") . '/information/privacy-content.blade.php');
|
$privacy = File::get(Theme::path($path = 'views', "default") . '/information/privacy-content.blade.php');
|
||||||
$imprint = File::get(Theme::path($path = 'views', "default") . '/information/imprint-content.blade.php');
|
$imprint = File::get(Theme::path($path = 'views', "default") . '/information/imprint-content.blade.php');
|
||||||
|
@ -33,8 +29,6 @@ class LegalController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(Request $request){
|
public function update(Request $request){
|
||||||
$this->checkPermission(self::READ_PERMISSION);
|
|
||||||
|
|
||||||
$tos = $request->tos;
|
$tos = $request->tos;
|
||||||
$privacy = $request->privacy;
|
$privacy = $request->privacy;
|
||||||
$imprint = $request->imprint;
|
$imprint = $request->imprint;
|
||||||
|
|
|
@ -2,14 +2,12 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
namespace App\Http\Controllers\Admin;
|
||||||
|
|
||||||
use App\Classes\PterodactylClient;
|
use App\Classes\Pterodactyl;
|
||||||
use App\Settings\PterodactylSettings;
|
|
||||||
use App\Settings\GeneralSettings;
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\Pterodactyl\Egg;
|
use App\Models\Egg;
|
||||||
use App\Models\Pterodactyl\Location;
|
use App\Models\Location;
|
||||||
use App\Models\Pterodactyl\Nest;
|
use App\Models\Nest;
|
||||||
use App\Models\Pterodactyl\Node;
|
use App\Models\Node;
|
||||||
use App\Models\Payment;
|
use App\Models\Payment;
|
||||||
use App\Models\Product;
|
use App\Models\Product;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
|
@ -19,28 +17,15 @@ use Carbon\Carbon;
|
||||||
|
|
||||||
class OverViewController extends Controller
|
class OverViewController extends Controller
|
||||||
{
|
{
|
||||||
const READ_PERMISSION = "admin.overview.read";
|
|
||||||
const SYNC_PERMISSION = "admin.overview.sync";
|
|
||||||
public const TTL = 86400;
|
public const TTL = 86400;
|
||||||
|
|
||||||
private $pterodactyl;
|
public function index()
|
||||||
|
|
||||||
public function __construct(PterodactylSettings $ptero_settings)
|
|
||||||
{
|
{
|
||||||
$this->pterodactyl = new PterodactylClient($ptero_settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function index(GeneralSettings $general_settings)
|
|
||||||
{
|
|
||||||
$this->checkPermission(self::READ_PERMISSION);
|
|
||||||
|
|
||||||
//Get counters
|
//Get counters
|
||||||
$counters = collect();
|
$counters = collect();
|
||||||
//Set basic variables in the collection
|
//Set basic variables in the collection
|
||||||
$counters->put('users', collect());
|
$counters->put('users', User::query()->count());
|
||||||
$counters['users']->active = User::where("suspended", 0)->count();
|
$counters->put('credits', number_format(User::query()->where('role', '!=', 'admin')->sum('credits'), 2, '.', ''));
|
||||||
$counters['users']->total = User::query()->count();
|
|
||||||
$counters->put('credits', number_format(User::query()->whereHas("roles", function($q){ $q->where("id", "!=", "1"); })->sum('credits'), 2, '.', ''));
|
|
||||||
$counters->put('payments', Payment::query()->count());
|
$counters->put('payments', Payment::query()->count());
|
||||||
$counters->put('eggs', Egg::query()->count());
|
$counters->put('eggs', Egg::query()->count());
|
||||||
$counters->put('nests', Nest::query()->count());
|
$counters->put('nests', Nest::query()->count());
|
||||||
|
@ -149,7 +134,7 @@ class OverViewController extends Controller
|
||||||
|
|
||||||
//Get node information and prepare collection
|
//Get node information and prepare collection
|
||||||
$pteroNodeIds = [];
|
$pteroNodeIds = [];
|
||||||
foreach ($this->pterodactyl->getNodes() as $pteroNode) {
|
foreach (Pterodactyl::getNodes() as $pteroNode) {
|
||||||
array_push($pteroNodeIds, $pteroNode['attributes']['id']);
|
array_push($pteroNodeIds, $pteroNode['attributes']['id']);
|
||||||
}
|
}
|
||||||
$nodes = collect();
|
$nodes = collect();
|
||||||
|
@ -160,7 +145,7 @@ class OverViewController extends Controller
|
||||||
} //Check if node exists on pterodactyl too, if not, skip
|
} //Check if node exists on pterodactyl too, if not, skip
|
||||||
$nodes->put($nodeId, collect());
|
$nodes->put($nodeId, collect());
|
||||||
$nodes[$nodeId]->name = $DBnode['name'];
|
$nodes[$nodeId]->name = $DBnode['name'];
|
||||||
$pteroNode = $this->pterodactyl->getNode($nodeId);
|
$pteroNode = 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);
|
$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;
|
$counters['totalUsagePercent'] += $nodes[$nodeId]->usagePercent;
|
||||||
|
|
||||||
|
@ -171,12 +156,11 @@ class OverViewController extends Controller
|
||||||
}
|
}
|
||||||
$counters['totalUsagePercent'] = ($DBnodes->count()) ? round($counters['totalUsagePercent'] / $DBnodes->count(), 2) : 0;
|
$counters['totalUsagePercent'] = ($DBnodes->count()) ? round($counters['totalUsagePercent'] / $DBnodes->count(), 2) : 0;
|
||||||
|
|
||||||
foreach ($this->pterodactyl->getServers() as $server) { //gets all servers from Pterodactyl and calculates total of credit usage for each node separately + total
|
foreach (Pterodactyl::getServers() as $server) { //gets all servers from Pterodactyl and calculates total of credit usage for each node separately + total
|
||||||
$nodeId = $server['attributes']['node'];
|
$nodeId = $server['attributes']['node'];
|
||||||
|
|
||||||
if ($CPServer = Server::query()->where('pterodactyl_id', $server['attributes']['id'])->first()) {
|
if ($CPServer = Server::query()->where('pterodactyl_id', $server['attributes']['id'])->first()) {
|
||||||
$product = Product::query()->where('id', $CPServer->product_id)->first();
|
$price = Product::query()->where('id', $CPServer->product_id)->first()->price;
|
||||||
$price = $product->getMonthlyPrice();
|
|
||||||
if (! $CPServer->suspended) {
|
if (! $CPServer->suspended) {
|
||||||
$counters['earnings']->active += $price;
|
$counters['earnings']->active += $price;
|
||||||
$counters['servers']->active++;
|
$counters['servers']->active++;
|
||||||
|
@ -223,7 +207,6 @@ class OverViewController extends Controller
|
||||||
'deletedNodesPresent' => ($DBnodes->count() != count($pteroNodeIds)) ? true : false,
|
'deletedNodesPresent' => ($DBnodes->count() != count($pteroNodeIds)) ? true : false,
|
||||||
'perPageLimit' => ($counters['servers']->total != Server::query()->count()) ? true : false,
|
'perPageLimit' => ($counters['servers']->total != Server::query()->count()) ? true : false,
|
||||||
'tickets' => $tickets,
|
'tickets' => $tickets,
|
||||||
'credits_display_name' => $general_settings->credits_display_name
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,8 +215,6 @@ class OverViewController extends Controller
|
||||||
*/
|
*/
|
||||||
public function syncPterodactyl()
|
public function syncPterodactyl()
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::SYNC_PERMISSION);
|
|
||||||
|
|
||||||
Node::syncNodes();
|
Node::syncNodes();
|
||||||
Egg::syncEggs();
|
Egg::syncEggs();
|
||||||
|
|
||||||
|
|
|
@ -5,21 +5,13 @@ namespace App\Http\Controllers\Admin;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\PartnerDiscount;
|
use App\Models\PartnerDiscount;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Settings\LocaleSettings;
|
|
||||||
use App\Settings\ReferralSettings;
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
class PartnerController extends Controller
|
class PartnerController extends Controller
|
||||||
{
|
{
|
||||||
const READ_PERMISSION = "admin.partners.read";
|
public function index()
|
||||||
const WRITE_PERMISSION = "admin.partners.write";
|
|
||||||
public function index(LocaleSettings $locale_settings)
|
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::READ_PERMISSION);
|
return view('admin.partners.index');
|
||||||
|
|
||||||
return view('admin.partners.index', [
|
|
||||||
'locale_datatables' => $locale_settings->datatables
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,8 +21,6 @@ class PartnerController extends Controller
|
||||||
*/
|
*/
|
||||||
public function create()
|
public function create()
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
|
|
||||||
return view('admin.partners.create', [
|
return view('admin.partners.create', [
|
||||||
'partners' => PartnerDiscount::get(),
|
'partners' => PartnerDiscount::get(),
|
||||||
'users' => User::orderBy('name')->get(),
|
'users' => User::orderBy('name')->get(),
|
||||||
|
@ -68,8 +58,6 @@ class PartnerController extends Controller
|
||||||
*/
|
*/
|
||||||
public function edit(PartnerDiscount $partner)
|
public function edit(PartnerDiscount $partner)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
|
|
||||||
return view('admin.partners.edit', [
|
return view('admin.partners.edit', [
|
||||||
'partners' => PartnerDiscount::get(),
|
'partners' => PartnerDiscount::get(),
|
||||||
'partner' => $partner,
|
'partner' => $partner,
|
||||||
|
@ -106,8 +94,6 @@ class PartnerController extends Controller
|
||||||
*/
|
*/
|
||||||
public function destroy(PartnerDiscount $partner)
|
public function destroy(PartnerDiscount $partner)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
|
|
||||||
$partner->delete();
|
$partner->delete();
|
||||||
|
|
||||||
return redirect()->back()->with('success', __('partner has been removed!'));
|
return redirect()->back()->with('success', __('partner has been removed!'));
|
||||||
|
@ -122,11 +108,11 @@ class PartnerController extends Controller
|
||||||
return datatables($query)
|
return datatables($query)
|
||||||
->addColumn('actions', function (PartnerDiscount $partner) {
|
->addColumn('actions', function (PartnerDiscount $partner) {
|
||||||
return '
|
return '
|
||||||
<a data-content="'.__('Edit').'" data-toggle="popover" data-trigger="hover" data-placement="top" href="'.route('admin.partners.edit', $partner->id).'" class="mr-1 btn btn-sm btn-info"><i class="fas fa-pen"></i></a>
|
<a data-content="'.__('Edit').'" data-toggle="popover" data-trigger="hover" data-placement="top" href="'.route('admin.partners.edit', $partner->id).'" class="btn btn-sm btn-info mr-1"><i class="fas fa-pen"></i></a>
|
||||||
<form class="d-inline" onsubmit="return submitResult();" method="post" action="'.route('admin.partners.destroy', $partner->id).'">
|
<form class="d-inline" onsubmit="return submitResult();" method="post" action="'.route('admin.partners.destroy', $partner->id).'">
|
||||||
'.csrf_field().'
|
'.csrf_field().'
|
||||||
'.method_field('DELETE').'
|
'.method_field('DELETE').'
|
||||||
<button data-content="'.__('Delete').'" data-toggle="popover" data-trigger="hover" data-placement="top" class="mr-1 btn btn-sm btn-danger"><i class="fas fa-trash"></i></button>
|
<button data-content="'.__('Delete').'" data-toggle="popover" data-trigger="hover" data-placement="top" class="btn btn-sm btn-danger mr-1"><i class="fas fa-trash"></i></button>
|
||||||
</form>
|
</form>
|
||||||
';
|
';
|
||||||
})
|
})
|
||||||
|
@ -142,10 +128,9 @@ class PartnerController extends Controller
|
||||||
->editColumn('registered_user_discount', function (PartnerDiscount $partner) {
|
->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, ReferralSettings $referral_settings) {
|
->editColumn('referral_system_commission', function (PartnerDiscount $partner) {
|
||||||
return $partner->referral_system_commission >= 0 ? $partner->referral_system_commission . '%' : __('Default') . ' ('.$referral_settings->percentage . '%)';
|
return $partner->referral_system_commission >= 0 ? $partner->referral_system_commission.'%' : __('Default').' ('.config('SETTINGS::REFERRAL:PERCENTAGE').'%)';
|
||||||
})
|
})
|
||||||
->orderColumn('user', 'user_id $1')
|
|
||||||
->rawColumns(['user', 'actions'])
|
->rawColumns(['user', 'actions'])
|
||||||
->make();
|
->make();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
namespace App\Http\Controllers\Admin;
|
||||||
|
|
||||||
use App\Events\CouponUsedEvent;
|
|
||||||
use App\Events\PaymentEvent;
|
use App\Events\PaymentEvent;
|
||||||
use App\Events\UserUpdateCreditsEvent;
|
use App\Events\UserUpdateCreditsEvent;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
@ -10,7 +9,6 @@ use App\Models\PartnerDiscount;
|
||||||
use App\Models\Payment;
|
use App\Models\Payment;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Models\ShopProduct;
|
use App\Models\ShopProduct;
|
||||||
use App\Traits\Coupon as CouponTrait;
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Contracts\Foundation\Application;
|
use Illuminate\Contracts\Foundation\Application;
|
||||||
use Illuminate\Contracts\View\Factory;
|
use Illuminate\Contracts\View\Factory;
|
||||||
|
@ -20,29 +18,17 @@ use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use App\Helpers\ExtensionHelper;
|
use App\Helpers\ExtensionHelper;
|
||||||
use App\Settings\CouponSettings;
|
|
||||||
use App\Settings\GeneralSettings;
|
|
||||||
use App\Settings\LocaleSettings;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
|
|
||||||
class PaymentController extends Controller
|
class PaymentController extends Controller
|
||||||
{
|
{
|
||||||
const BUY_PERMISSION = 'user.shop.buy';
|
|
||||||
const VIEW_PERMISSION = "admin.payments.read";
|
|
||||||
|
|
||||||
use CouponTrait;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Application|Factory|View
|
* @return Application|Factory|View
|
||||||
*/
|
*/
|
||||||
public function index(LocaleSettings $locale_settings)
|
public function index()
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::VIEW_PERMISSION);
|
|
||||||
|
|
||||||
|
|
||||||
return view('admin.payments.index')->with([
|
return view('admin.payments.index')->with([
|
||||||
'payments' => Payment::paginate(15),
|
'payments' => Payment::paginate(15),
|
||||||
'locale_datatables' => $locale_settings->datatables
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,10 +37,8 @@ class PaymentController extends Controller
|
||||||
* @param ShopProduct $shopProduct
|
* @param ShopProduct $shopProduct
|
||||||
* @return Application|Factory|View
|
* @return Application|Factory|View
|
||||||
*/
|
*/
|
||||||
public function checkOut(ShopProduct $shopProduct, GeneralSettings $general_settings, CouponSettings $coupon_settings)
|
public function checkOut(ShopProduct $shopProduct)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::BUY_PERMISSION);
|
|
||||||
|
|
||||||
$discount = PartnerDiscount::getDiscount();
|
$discount = PartnerDiscount::getDiscount();
|
||||||
$price = $shopProduct->price - ($shopProduct->price * $discount / 100);
|
$price = $shopProduct->price - ($shopProduct->price * $discount / 100);
|
||||||
|
|
||||||
|
@ -65,10 +49,7 @@ 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
|
// 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) {
|
foreach ($extensions as $extension) {
|
||||||
$extensionName = basename($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 = new \stdClass();
|
||||||
$payment->name = ExtensionHelper::getExtensionConfig($extensionName, 'name');
|
$payment->name = ExtensionHelper::getExtensionConfig($extensionName, 'name');
|
||||||
|
@ -77,6 +58,11 @@ class PaymentController extends Controller
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return view('store.checkout')->with([
|
return view('store.checkout')->with([
|
||||||
'product' => $shopProduct,
|
'product' => $shopProduct,
|
||||||
'discountpercent' => $discount,
|
'discountpercent' => $discount,
|
||||||
|
@ -87,8 +73,6 @@ class PaymentController extends Controller
|
||||||
'total' => $shopProduct->getTotalPrice(),
|
'total' => $shopProduct->getTotalPrice(),
|
||||||
'paymentGateways' => $paymentGateways,
|
'paymentGateways' => $paymentGateways,
|
||||||
'productIsFree' => $price <= 0,
|
'productIsFree' => $price <= 0,
|
||||||
'credits_display_name' => $general_settings->credits_display_name,
|
|
||||||
'isCouponsEnabled' => $coupon_settings->enabled,
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,67 +113,16 @@ class PaymentController extends Controller
|
||||||
|
|
||||||
public function pay(Request $request)
|
public function pay(Request $request)
|
||||||
{
|
{
|
||||||
try {
|
$product = ShopProduct::find($request->product_id);
|
||||||
$user = Auth::user();
|
|
||||||
$user = User::findOrFail($user->id);
|
|
||||||
$productId = $request->product_id;
|
|
||||||
$shopProduct = ShopProduct::findOrFail($productId);
|
|
||||||
$discount = PartnerDiscount::getDiscount();
|
|
||||||
|
|
||||||
|
|
||||||
$paymentGateway = $request->payment_method;
|
$paymentGateway = $request->payment_method;
|
||||||
$couponCode = $request->coupon_code;
|
|
||||||
|
|
||||||
$subtotal = $shopProduct->price;
|
// on free products, we don't need to use a payment gateway
|
||||||
|
$realPrice = $product->price - ($product->price * PartnerDiscount::getDiscount() / 100);
|
||||||
// Apply Coupon
|
if ($realPrice <= 0) {
|
||||||
if ($couponCode) {
|
return $this->handleFreeProduct($product);
|
||||||
if ($this->isCouponValid($couponCode, $user, $shopProduct->id)) {
|
|
||||||
$subtotal = $this->applyCoupon($couponCode, $subtotal);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply Partner Discount
|
return redirect()->route('payment.' . $paymentGateway . 'Pay', ['shopProduct' => $product->id]);
|
||||||
$subtotal = $subtotal - ($subtotal * $discount / 100);
|
|
||||||
if ($subtotal <= 0) {
|
|
||||||
if ($couponCode) {
|
|
||||||
event(new CouponUsedEvent($couponCode));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->handleFreeProduct($shopProduct);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format the total price to a readable string
|
|
||||||
$totalPriceString = number_format($subtotal, 2, '.', '');
|
|
||||||
|
|
||||||
// create a new payment
|
|
||||||
$payment = Payment::create([
|
|
||||||
'user_id' => $user->id,
|
|
||||||
'payment_id' => null,
|
|
||||||
'payment_method' => $paymentGateway,
|
|
||||||
'type' => $shopProduct->type,
|
|
||||||
'status' => 'open',
|
|
||||||
'amount' => $shopProduct->quantity,
|
|
||||||
'price' => $totalPriceString,
|
|
||||||
'tax_value' => $shopProduct->getTaxValue(),
|
|
||||||
'tax_percent' => $shopProduct->getTaxPercent(),
|
|
||||||
'total_price' => $shopProduct->getTotalPrice(),
|
|
||||||
'currency_code' => $shopProduct->currency_code,
|
|
||||||
'shop_item_product_id' => $shopProduct->id,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$paymentGatewayExtension = ExtensionHelper::getExtensionClass($paymentGateway);
|
|
||||||
$redirectUrl = $paymentGatewayExtension::getRedirectUrl($payment, $shopProduct, $totalPriceString);
|
|
||||||
|
|
||||||
if ($couponCode) {
|
|
||||||
event(new CouponUsedEvent($couponCode));
|
|
||||||
}
|
|
||||||
} catch (Exception $e) {
|
|
||||||
Log::error($e->getMessage());
|
|
||||||
return redirect()->route('store.index')->with('error', __('Oops, something went wrong! Please try again later.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirect()->away($redirectUrl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -3,12 +3,9 @@
|
||||||
namespace App\Http\Controllers\Admin;
|
namespace App\Http\Controllers\Admin;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\Pterodactyl\Location;
|
use App\Models\Location;
|
||||||
use App\Models\Pterodactyl\Nest;
|
use App\Models\Nest;
|
||||||
use App\Models\Product;
|
use App\Models\Product;
|
||||||
use App\Settings\GeneralSettings;
|
|
||||||
use App\Settings\LocaleSettings;
|
|
||||||
use App\Settings\UserSettings;
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Contracts\Foundation\Application;
|
use Illuminate\Contracts\Foundation\Application;
|
||||||
use Illuminate\Contracts\View\Factory;
|
use Illuminate\Contracts\View\Factory;
|
||||||
|
@ -19,22 +16,14 @@ use Illuminate\Http\Request;
|
||||||
|
|
||||||
class ProductController extends Controller
|
class ProductController extends Controller
|
||||||
{
|
{
|
||||||
const READ_PERMISSION = "admin.products.read";
|
|
||||||
const WRITE_PERMISSION = "admin.products.write";
|
|
||||||
const EDIT_PERMISSION = "admin.products.edit";
|
|
||||||
const DELETE_PERMISSION = "admin.products.delete";
|
|
||||||
/**
|
/**
|
||||||
* Display a listing of the resource.
|
* Display a listing of the resource.
|
||||||
*
|
*
|
||||||
* @return Application|Factory|View
|
* @return Application|Factory|View
|
||||||
*/
|
*/
|
||||||
public function index(LocaleSettings $locale_settings)
|
public function index()
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::READ_PERMISSION);
|
return view('admin.products.index');
|
||||||
|
|
||||||
return view('admin.products.index', [
|
|
||||||
'locale_datatables' => $locale_settings->datatables
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -42,23 +31,18 @@ class ProductController extends Controller
|
||||||
*
|
*
|
||||||
* @return Application|Factory|View
|
* @return Application|Factory|View
|
||||||
*/
|
*/
|
||||||
public function create(GeneralSettings $general_settings)
|
public function create()
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
return view('admin.products.create', [
|
return view('admin.products.create', [
|
||||||
'locations' => Location::with('nodes')->get(),
|
'locations' => Location::with('nodes')->get(),
|
||||||
'nests' => Nest::with('eggs')->get(),
|
'nests' => Nest::with('eggs')->get(),
|
||||||
'credits_display_name' => $general_settings->credits_display_name
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function clone(Product $product, GeneralSettings $general_settings)
|
public function clone(Request $request, Product $product)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
|
|
||||||
return view('admin.products.create', [
|
return view('admin.products.create', [
|
||||||
'product' => $product,
|
'product' => $product,
|
||||||
'credits_display_name' => $general_settings->credits_display_name,
|
|
||||||
'locations' => Location::with('nodes')->get(),
|
'locations' => Location::with('nodes')->get(),
|
||||||
'nests' => Nest::with('eggs')->get(),
|
'nests' => Nest::with('eggs')->get(),
|
||||||
]);
|
]);
|
||||||
|
@ -88,14 +72,10 @@ class ProductController extends Controller
|
||||||
'nodes.*' => 'required|exists:nodes,id',
|
'nodes.*' => 'required|exists:nodes,id',
|
||||||
'eggs.*' => 'required|exists:eggs,id',
|
'eggs.*' => 'required|exists:eggs,id',
|
||||||
'disabled' => 'nullable',
|
'disabled' => 'nullable',
|
||||||
'oom_killer' => 'nullable',
|
|
||||||
'billing_period' => 'required|in:hourly,daily,weekly,monthly,quarterly,half-annually,annually',
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
$disabled = ! is_null($request->input('disabled'));
|
$disabled = ! is_null($request->input('disabled'));
|
||||||
$oomkiller = ! is_null($request->input('oom_killer'));
|
$product = Product::create(array_merge($request->all(), ['disabled' => $disabled]));
|
||||||
$product = Product::create(array_merge($request->all(), ['disabled' => $disabled, 'oom_killer' => $oomkiller]));
|
|
||||||
|
|
||||||
//link nodes and eggs
|
//link nodes and eggs
|
||||||
$product->eggs()->attach($request->input('eggs'));
|
$product->eggs()->attach($request->input('eggs'));
|
||||||
|
@ -110,14 +90,11 @@ class ProductController extends Controller
|
||||||
* @param Product $product
|
* @param Product $product
|
||||||
* @return Application|Factory|View
|
* @return Application|Factory|View
|
||||||
*/
|
*/
|
||||||
public function show(Product $product, UserSettings $user_settings, GeneralSettings $general_settings)
|
public function show(Product $product)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::READ_PERMISSION);
|
|
||||||
|
|
||||||
return view('admin.products.show', [
|
return view('admin.products.show', [
|
||||||
'product' => $product,
|
'product' => $product,
|
||||||
'minimum_credits' => $user_settings->min_credits_to_make_server,
|
'minimum_credits' => config('SETTINGS::USER:MINIMUM_REQUIRED_CREDITS_TO_MAKE_SERVER'),
|
||||||
'credits_display_name' => $general_settings->credits_display_name
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,15 +104,12 @@ class ProductController extends Controller
|
||||||
* @param Product $product
|
* @param Product $product
|
||||||
* @return Application|Factory|View
|
* @return Application|Factory|View
|
||||||
*/
|
*/
|
||||||
public function edit(Product $product, GeneralSettings $general_settings)
|
public function edit(Product $product)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::EDIT_PERMISSION);
|
|
||||||
|
|
||||||
return view('admin.products.edit', [
|
return view('admin.products.edit', [
|
||||||
'product' => $product,
|
'product' => $product,
|
||||||
'locations' => Location::with('nodes')->get(),
|
'locations' => Location::with('nodes')->get(),
|
||||||
'nests' => Nest::with('eggs')->get(),
|
'nests' => Nest::with('eggs')->get(),
|
||||||
'credits_display_name' => $general_settings->credits_display_name
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,13 +138,10 @@ class ProductController extends Controller
|
||||||
'nodes.*' => 'required|exists:nodes,id',
|
'nodes.*' => 'required|exists:nodes,id',
|
||||||
'eggs.*' => 'required|exists:eggs,id',
|
'eggs.*' => 'required|exists:eggs,id',
|
||||||
'disabled' => 'nullable',
|
'disabled' => 'nullable',
|
||||||
'oom_killer' => 'nullable',
|
|
||||||
'billing_period' => 'required|in:hourly,daily,weekly,monthly,quarterly,half-annually,annually',
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$disabled = ! is_null($request->input('disabled'));
|
$disabled = ! is_null($request->input('disabled'));
|
||||||
$oomkiller = ! is_null($request->input('oom_killer'));
|
$product->update(array_merge($request->all(), ['disabled' => $disabled]));
|
||||||
$product->update(array_merge($request->all(), ['disabled' => $disabled, 'oom_killer' => $oomkiller]));
|
|
||||||
|
|
||||||
//link nodes and eggs
|
//link nodes and eggs
|
||||||
$product->eggs()->detach();
|
$product->eggs()->detach();
|
||||||
|
@ -186,10 +157,8 @@ class ProductController extends Controller
|
||||||
* @param Product $product
|
* @param Product $product
|
||||||
* @return RedirectResponse
|
* @return RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function disable(Product $product)
|
public function disable(Request $request, Product $product)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
|
|
||||||
$product->update(['disabled' => ! $product->disabled]);
|
$product->update(['disabled' => ! $product->disabled]);
|
||||||
|
|
||||||
return redirect()->route('admin.products.index')->with('success', 'Product has been updated!');
|
return redirect()->route('admin.products.index')->with('success', 'Product has been updated!');
|
||||||
|
@ -203,8 +172,6 @@ class ProductController extends Controller
|
||||||
*/
|
*/
|
||||||
public function destroy(Product $product)
|
public function destroy(Product $product)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::DELETE_PERMISSION);
|
|
||||||
|
|
||||||
$servers = $product->servers()->count();
|
$servers = $product->servers()->count();
|
||||||
if ($servers > 0) {
|
if ($servers > 0) {
|
||||||
return redirect()->back()->with('error', "Product cannot be removed while it's linked to {$servers} servers");
|
return redirect()->back()->with('error', "Product cannot be removed while it's linked to {$servers} servers");
|
||||||
|
@ -227,14 +194,14 @@ class ProductController extends Controller
|
||||||
return datatables($query)
|
return datatables($query)
|
||||||
->addColumn('actions', function (Product $product) {
|
->addColumn('actions', function (Product $product) {
|
||||||
return '
|
return '
|
||||||
<a data-content="'.__('Show').'" data-toggle="popover" data-trigger="hover" data-placement="top" href="'.route('admin.products.show', $product->id).'" class="mr-1 text-white btn btn-sm btn-warning"><i class="fas fa-eye"></i></a>
|
<a data-content="'.__('Show').'" data-toggle="popover" data-trigger="hover" data-placement="top" href="'.route('admin.products.show', $product->id).'" class="btn btn-sm text-white btn-warning mr-1"><i class="fas fa-eye"></i></a>
|
||||||
<a data-content="'.__('Clone').'" data-toggle="popover" data-trigger="hover" data-placement="top" href="'.route('admin.products.clone', $product->id).'" class="mr-1 text-white btn btn-sm btn-primary"><i class="fas fa-clone"></i></a>
|
<a data-content="'.__('Clone').'" data-toggle="popover" data-trigger="hover" data-placement="top" href="'.route('admin.products.clone', $product->id).'" class="btn btn-sm text-white btn-primary mr-1"><i class="fas fa-clone"></i></a>
|
||||||
<a data-content="'.__('Edit').'" data-toggle="popover" data-trigger="hover" data-placement="top" href="'.route('admin.products.edit', $product->id).'" class="mr-1 btn btn-sm btn-info"><i class="fas fa-pen"></i></a>
|
<a data-content="'.__('Edit').'" data-toggle="popover" data-trigger="hover" data-placement="top" href="'.route('admin.products.edit', $product->id).'" class="btn btn-sm btn-info mr-1"><i class="fas fa-pen"></i></a>
|
||||||
|
|
||||||
<form class="d-inline" onsubmit="return submitResult();" method="post" action="'.route('admin.products.destroy', $product->id).'">
|
<form class="d-inline" onsubmit="return submitResult();" method="post" action="'.route('admin.products.destroy', $product->id).'">
|
||||||
'.csrf_field().'
|
'.csrf_field().'
|
||||||
'.method_field('DELETE').'
|
'.method_field('DELETE').'
|
||||||
<button data-content="'.__('Delete').'" data-toggle="popover" data-trigger="hover" data-placement="top" class="mr-1 btn btn-sm btn-danger"><i class="fas fa-trash"></i></button>
|
<button data-content="'.__('Delete').'" data-toggle="popover" data-trigger="hover" data-placement="top" class="btn btn-sm btn-danger mr-1"><i class="fas fa-trash"></i></button>
|
||||||
</form>
|
</form>
|
||||||
';
|
';
|
||||||
})
|
})
|
||||||
|
@ -248,7 +215,7 @@ class ProductController extends Controller
|
||||||
->addColumn('eggs', function (Product $product) {
|
->addColumn('eggs', function (Product $product) {
|
||||||
return $product->eggs()->count();
|
return $product->eggs()->count();
|
||||||
})
|
})
|
||||||
->editColumn('disabled', function (Product $product) {
|
->addColumn('disabled', function (Product $product) {
|
||||||
$checked = $product->disabled == false ? 'checked' : '';
|
$checked = $product->disabled == false ? 'checked' : '';
|
||||||
|
|
||||||
return '
|
return '
|
||||||
|
@ -262,11 +229,8 @@ class ProductController extends Controller
|
||||||
</form>
|
</form>
|
||||||
';
|
';
|
||||||
})
|
})
|
||||||
->editColumn('minimum_credits', function (Product $product, UserSettings $user_settings) {
|
->editColumn('minimum_credits', function (Product $product) {
|
||||||
return $product->minimum_credits==-1 ? $user_settings->min_credits_to_make_server : $product->minimum_credits;
|
return $product->minimum_credits==-1 ? config('SETTINGS::USER:MINIMUM_REQUIRED_CREDITS_TO_MAKE_SERVER') : $product->minimum_credits;
|
||||||
})
|
|
||||||
->editColumn('oom_killer', function (Product $product) {
|
|
||||||
return $product->oom_killer ? __("enabled") : __("disabled");
|
|
||||||
})
|
})
|
||||||
->editColumn('created_at', function (Product $product) {
|
->editColumn('created_at', function (Product $product) {
|
||||||
return $product->created_at ? $product->created_at->diffForHumans() : '';
|
return $product->created_at ? $product->created_at->diffForHumans() : '';
|
||||||
|
|
|
@ -1,219 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Models\User;
|
|
||||||
use Exception;
|
|
||||||
use Illuminate\Contracts\Foundation\Application;
|
|
||||||
use Illuminate\Contracts\View\Factory;
|
|
||||||
use Illuminate\Contracts\View\View;
|
|
||||||
use Illuminate\Http\RedirectResponse;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
use Spatie\Permission\Models\Permission;
|
|
||||||
use Spatie\Permission\Models\Role;
|
|
||||||
|
|
||||||
class RoleController extends Controller
|
|
||||||
{
|
|
||||||
|
|
||||||
const READ_PERMISSION = "admin.roles.read";
|
|
||||||
const CREATE_PERMISSION = "admin.roles.create";
|
|
||||||
const EDIT_PERMISSION = "admin.roles.edit";
|
|
||||||
const DELETE_PERMISSION = "admin.roles.delete";
|
|
||||||
/**
|
|
||||||
* Display a listing of the resource.
|
|
||||||
*
|
|
||||||
* @param Request $request
|
|
||||||
* @return mixed
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
public function index(Request $request)
|
|
||||||
{
|
|
||||||
|
|
||||||
$this->checkPermission(self::READ_PERMISSION);
|
|
||||||
|
|
||||||
//datatables
|
|
||||||
if ($request->ajax()) {
|
|
||||||
return $this->dataTableQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
$html = $this->dataTable();
|
|
||||||
return view('admin.roles.index', compact('html'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for creating a new resource.
|
|
||||||
*
|
|
||||||
* @return Application|Factory|View
|
|
||||||
*/
|
|
||||||
public function create()
|
|
||||||
{
|
|
||||||
$this->checkPermission(self::CREATE_PERMISSION);
|
|
||||||
|
|
||||||
$permissions = Permission::all();
|
|
||||||
|
|
||||||
return view('admin.roles.edit', compact('permissions'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store a newly created resource in storage.
|
|
||||||
*
|
|
||||||
* @return RedirectResponse
|
|
||||||
*/
|
|
||||||
public function store(Request $request): RedirectResponse
|
|
||||||
{
|
|
||||||
$this->checkPermission(self::CREATE_PERMISSION);
|
|
||||||
|
|
||||||
$role = Role::create([
|
|
||||||
'name' => $request->name,
|
|
||||||
'color' => $request->color,
|
|
||||||
'power' => $request->power
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($request->permissions) {
|
|
||||||
$role->givePermissionTo($request->permissions);
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirect()
|
|
||||||
->route('admin.roles.index')
|
|
||||||
->with('success', __('Role saved'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display the specified resource.
|
|
||||||
*/
|
|
||||||
public function show()
|
|
||||||
{
|
|
||||||
abort(404);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for editing the specified resource.
|
|
||||||
*
|
|
||||||
* @param Role $role
|
|
||||||
* @return Application|Factory|View
|
|
||||||
*/
|
|
||||||
public function edit(Role $role)
|
|
||||||
{
|
|
||||||
$this->checkPermission(self::EDIT_PERMISSION);
|
|
||||||
|
|
||||||
if(Auth::user()->roles[0]->power < $role->power){
|
|
||||||
return back()->with("error","You dont have enough Power to edit that Role");
|
|
||||||
}
|
|
||||||
|
|
||||||
$permissions = Permission::all();
|
|
||||||
|
|
||||||
return view('admin.roles.edit', compact('role', 'permissions'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the specified resource in storage.
|
|
||||||
*
|
|
||||||
* @param Role $role
|
|
||||||
* @return RedirectResponse
|
|
||||||
*/
|
|
||||||
public function update(Request $request, Role $role)
|
|
||||||
{
|
|
||||||
$this->checkPermission(self::EDIT_PERMISSION);
|
|
||||||
|
|
||||||
if(Auth::user()->roles[0]->power < $role->power){
|
|
||||||
return back()->with("error","You dont have enough Power to edit that Role");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($request->permissions) {
|
|
||||||
if($role->id != 1){ //disable admin permissions change
|
|
||||||
$role->syncPermissions($request->permissions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//if($role->id == 1 || $role->id == 3 || $role->id == 4){ //dont let the user change the names of these roles
|
|
||||||
// $role->update([
|
|
||||||
// 'color' => $request->color
|
|
||||||
// ]);
|
|
||||||
//}else{
|
|
||||||
$role->update([
|
|
||||||
'name' => $request->name,
|
|
||||||
'color' => $request->color
|
|
||||||
]);
|
|
||||||
//}
|
|
||||||
|
|
||||||
//if($role->id == 1){
|
|
||||||
// return redirect()->route('admin.roles.index')->with('success', __('Role updated. Name and Permissions of this Role cannot be changed'));
|
|
||||||
//}elseif($role->id == 4 || $role->id == 3){
|
|
||||||
// return redirect()->route('admin.roles.index')->with('success', __('Role updated. Name of this Role cannot be changed'));
|
|
||||||
// }else{
|
|
||||||
return redirect()
|
|
||||||
->route('admin.roles.index')
|
|
||||||
->with('success', __('Role saved'));
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the specified resource from storage.
|
|
||||||
*
|
|
||||||
* @return RedirectResponse
|
|
||||||
*/
|
|
||||||
public function destroy(Role $role)
|
|
||||||
{
|
|
||||||
$this->checkPermission(self::DELETE_PERMISSION);
|
|
||||||
|
|
||||||
if($role->id == 1 || $role->id == 3 || $role->id == 4){ //cannot delete the hard coded roles
|
|
||||||
return back()->with("error","You cannot delete that role");
|
|
||||||
}
|
|
||||||
|
|
||||||
$users = User::role($role)->get();
|
|
||||||
|
|
||||||
foreach($users as $user){
|
|
||||||
//$user->syncRoles(['Member']);
|
|
||||||
$user->syncRoles(4);
|
|
||||||
}
|
|
||||||
|
|
||||||
$role->delete();
|
|
||||||
|
|
||||||
return redirect()
|
|
||||||
->route('admin.roles.index')
|
|
||||||
->with('success', __('Role removed'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return mixed
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
public function dataTable()
|
|
||||||
{
|
|
||||||
$query = Role::query()->withCount(['users', 'permissions'])->get();
|
|
||||||
|
|
||||||
return datatables($query)
|
|
||||||
->editColumn('id', function (Role $role) {
|
|
||||||
return $role->id;
|
|
||||||
})
|
|
||||||
->addColumn('actions', function (Role $role) {
|
|
||||||
return '
|
|
||||||
<a title="Edit" href="'.route("admin.roles.edit", $role).'" class="btn btn-sm btn-info"><i
|
|
||||||
class="fa fas fa-edit"></i></a>
|
|
||||||
<form class="d-inline" method="post" action="'.route("admin.roles.destroy", $role).'">
|
|
||||||
' . csrf_field() . '
|
|
||||||
' . method_field("DELETE") . '
|
|
||||||
<button title="Delete" type="submit" class="btn btn-sm btn-danger confirm"><i
|
|
||||||
class="fa fas fa-trash"></i></button>
|
|
||||||
</form>
|
|
||||||
';
|
|
||||||
})
|
|
||||||
|
|
||||||
->editColumn('name', function (Role $role) {
|
|
||||||
return "<span style='background-color: $role->color' class='badge'>$role->name</span>";
|
|
||||||
})
|
|
||||||
->editColumn('users_count', function ($query) {
|
|
||||||
return $query->users_count;
|
|
||||||
})
|
|
||||||
->editColumn('permissions_count', function ($query){
|
|
||||||
return $query->permissions_count;
|
|
||||||
})
|
|
||||||
->editColumn('power', function (Role $role){
|
|
||||||
return $role->power;
|
|
||||||
})
|
|
||||||
->rawColumns(['actions', 'name'])
|
|
||||||
->make(true);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,12 +2,10 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
namespace App\Http\Controllers\Admin;
|
||||||
|
|
||||||
|
use App\Classes\Pterodactyl;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Settings\LocaleSettings;
|
|
||||||
use App\Settings\PterodactylSettings;
|
|
||||||
use App\Classes\PterodactylClient;
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Contracts\Foundation\Application;
|
use Illuminate\Contracts\Foundation\Application;
|
||||||
use Illuminate\Contracts\View\Factory;
|
use Illuminate\Contracts\View\Factory;
|
||||||
|
@ -20,32 +18,14 @@ use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class ServerController extends Controller
|
class ServerController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
const READ_PERMISSION = "admin.servers.read";
|
|
||||||
const WRITE_PERMISSION = "admin.servers.write";
|
|
||||||
const SUSPEND_PERMISSION = "admin.servers.suspend";
|
|
||||||
const CHANGEOWNER_PERMISSION = "admin.servers.write.owner";
|
|
||||||
const CHANGE_IDENTIFIER_PERMISSION = "admin.servers.write.identifier";
|
|
||||||
const DELETE_PERMISSION = "admin.servers.delete";
|
|
||||||
private $pterodactyl;
|
|
||||||
|
|
||||||
public function __construct(PterodactylSettings $ptero_settings)
|
|
||||||
{
|
|
||||||
$this->pterodactyl = new PterodactylClient($ptero_settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display a listing of the resource.
|
* Display a listing of the resource.
|
||||||
*
|
*
|
||||||
* @return Application|Factory|View|Response
|
* @return Application|Factory|View|Response
|
||||||
*/
|
*/
|
||||||
public function index(LocaleSettings $locale_settings)
|
public function index()
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::READ_PERMISSION);
|
return view('admin.servers.index');
|
||||||
|
|
||||||
return view('admin.servers.index', [
|
|
||||||
'locale_datatables' => $locale_settings->datatables
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -56,8 +36,6 @@ class ServerController extends Controller
|
||||||
*/
|
*/
|
||||||
public function edit(Server $server)
|
public function edit(Server $server)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
|
|
||||||
// get all users from the database
|
// get all users from the database
|
||||||
$users = User::all();
|
$users = User::all();
|
||||||
|
|
||||||
|
@ -81,13 +59,13 @@ class ServerController extends Controller
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
if ($request->get('user_id') != $server->user_id && $this->can(self::CHANGEOWNER_PERMISSION)) {
|
if ($request->get('user_id') != $server->user_id) {
|
||||||
// find the user
|
// find the user
|
||||||
$user = User::findOrFail($request->get('user_id'));
|
$user = User::findOrFail($request->get('user_id'));
|
||||||
|
|
||||||
// try to update the owner on pterodactyl
|
// try to update the owner on pterodactyl
|
||||||
try {
|
try {
|
||||||
$response = $this->pterodactyl->updateServerOwner($server, $user->pterodactyl_id);
|
$response = Pterodactyl::updateServerOwner($server, $user->pterodactyl_id);
|
||||||
if ($response->getStatusCode() != 200) {
|
if ($response->getStatusCode() != 200) {
|
||||||
return redirect()->back()->with('error', 'Failed to update server owner on pterodactyl');
|
return redirect()->back()->with('error', 'Failed to update server owner on pterodactyl');
|
||||||
}
|
}
|
||||||
|
@ -100,10 +78,7 @@ class ServerController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the identifier
|
// update the identifier
|
||||||
if ($this->can(self::CHANGE_IDENTIFIER_PERMISSION)) {
|
|
||||||
|
|
||||||
$server->identifier = $request->get('identifier');
|
$server->identifier = $request->get('identifier');
|
||||||
}
|
|
||||||
$server->save();
|
$server->save();
|
||||||
|
|
||||||
return redirect()->route('admin.servers.index')->with('success', 'Server updated!');
|
return redirect()->route('admin.servers.index')->with('success', 'Server updated!');
|
||||||
|
@ -117,7 +92,6 @@ class ServerController extends Controller
|
||||||
*/
|
*/
|
||||||
public function destroy(Server $server)
|
public function destroy(Server $server)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::DELETE_PERMISSION);
|
|
||||||
try {
|
try {
|
||||||
$server->delete();
|
$server->delete();
|
||||||
|
|
||||||
|
@ -127,32 +101,12 @@ class ServerController extends Controller
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancel the Server billing cycle.
|
|
||||||
*
|
|
||||||
* @param Server $server
|
|
||||||
* @return RedirectResponse|Response
|
|
||||||
*/
|
|
||||||
public function cancel(Server $server)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$server->update([
|
|
||||||
'canceled' => now(),
|
|
||||||
]);
|
|
||||||
return redirect()->route('servers.index')->with('success', __('Server canceled'));
|
|
||||||
} catch (Exception $e) {
|
|
||||||
return redirect()->route('servers.index')->with('error', __('An exception has occurred while trying to cancel the server"') . $e->getMessage() . '"');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Server $server
|
* @param Server $server
|
||||||
* @return RedirectResponse
|
* @return RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function toggleSuspended(Server $server)
|
public function toggleSuspended(Server $server)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::SUSPEND_PERMISSION);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$server->isSuspended() ? $server->unSuspend() : $server->suspend();
|
$server->isSuspended() ? $server->unSuspend() : $server->suspend();
|
||||||
} catch (Exception $exception) {
|
} catch (Exception $exception) {
|
||||||
|
@ -164,6 +118,7 @@ class ServerController extends Controller
|
||||||
|
|
||||||
public function syncServers()
|
public function syncServers()
|
||||||
{
|
{
|
||||||
|
$pteroServers = Pterodactyl::getServers();
|
||||||
$CPServers = Server::get();
|
$CPServers = Server::get();
|
||||||
|
|
||||||
$CPIDArray = [];
|
$CPIDArray = [];
|
||||||
|
@ -174,7 +129,7 @@ class ServerController extends Controller
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->pterodactyl->getServers() as $server) { //go thru all ptero servers, if server exists, change value to true in array.
|
foreach ($pteroServers as $server) { //go thru all ptero servers, if server exists, change value to true in array.
|
||||||
if (isset($CPIDArray[$server['attributes']['id']])) {
|
if (isset($CPIDArray[$server['attributes']['id']])) {
|
||||||
$CPIDArray[$server['attributes']['id']] = true;
|
$CPIDArray[$server['attributes']['id']] = true;
|
||||||
|
|
||||||
|
@ -194,7 +149,7 @@ class ServerController extends Controller
|
||||||
}, ARRAY_FILTER_USE_BOTH); //Array of servers, that dont exist on ptero (value == false)
|
}, ARRAY_FILTER_USE_BOTH); //Array of servers, that dont exist on ptero (value == false)
|
||||||
$deleteCount = 0;
|
$deleteCount = 0;
|
||||||
foreach ($filteredArray as $key => $CPID) { //delete servers that dont exist on ptero anymore
|
foreach ($filteredArray as $key => $CPID) { //delete servers that dont exist on ptero anymore
|
||||||
if (!$this->pterodactyl->getServerAttributes($key, true)) {
|
if (!Pterodactyl::getServerAttributes($key, true)) {
|
||||||
$deleteCount++;
|
$deleteCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -261,8 +216,8 @@ class ServerController extends Controller
|
||||||
->editColumn('suspended', function (Server $server) {
|
->editColumn('suspended', function (Server $server) {
|
||||||
return $server->suspended ? $server->suspended->diffForHumans() : '';
|
return $server->suspended ? $server->suspended->diffForHumans() : '';
|
||||||
})
|
})
|
||||||
->editColumn('name', function (Server $server, PterodactylSettings $ptero_settings) {
|
->editColumn('name', function (Server $server) {
|
||||||
return '<a class="text-info" target="_blank" href="' . $ptero_settings->panel_url . '/admin/servers/view/' . $server->pterodactyl_id . '">' . strip_tags($server->name) . '</a>';
|
return '<a class="text-info" target="_blank" href="' . config('SETTINGS::SYSTEM:PTERODACTYL:URL') . '/admin/servers/view/' . $server->pterodactyl_id . '">' . strip_tags($server->name) . '</a>';
|
||||||
})
|
})
|
||||||
->rawColumns(['user', 'actions', 'status', 'name'])
|
->rawColumns(['user', 'actions', 'status', 'name'])
|
||||||
->make();
|
->make();
|
||||||
|
|
|
@ -2,21 +2,15 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
namespace App\Http\Controllers\Admin;
|
||||||
|
|
||||||
use App\Helpers\ExtensionHelper;
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Contracts\Foundation\Application;
|
use Illuminate\Contracts\Foundation\Application;
|
||||||
use Illuminate\Contracts\View\Factory;
|
use Illuminate\Contracts\View\Factory;
|
||||||
use Illuminate\Contracts\View\View;
|
use Illuminate\Contracts\View\View;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\Redirect;
|
|
||||||
use Illuminate\Support\Facades\Validator;
|
|
||||||
use Qirolab\Theme\Theme;
|
use Qirolab\Theme\Theme;
|
||||||
|
|
||||||
class SettingsController extends Controller
|
class SettingsController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display a listing of the resource.
|
* Display a listing of the resource.
|
||||||
*
|
*
|
||||||
|
@ -26,138 +20,36 @@ class SettingsController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
// get all other settings in app/Settings directory
|
//Get all tabs as laravel view paths
|
||||||
// group items by file name like $categories
|
$tabs = [];
|
||||||
$settings = collect();
|
if(file_exists(Theme::getViewPaths()[0] . '/admin/settings/tabs/')){
|
||||||
$settings_classes = [];
|
$tabspath = glob(Theme::getViewPaths()[0] . '/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{
|
}else{
|
||||||
$optionInputData = [];
|
$tabspath = glob(Theme::path($path = 'views', $themeName = 'default').'/admin/settings/tabs/*.blade.php');
|
||||||
}
|
}
|
||||||
|
|
||||||
// collect all option input data
|
foreach ($tabspath as $filename) {
|
||||||
$optionsData = [];
|
$tabs[] = 'admin.settings.tabs.'.basename($filename, '.blade.php');
|
||||||
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'] ?? [],
|
|
||||||
'identifier' => $optionInputData[$key]['identifier'] ?? 'option'
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// collect category icon if available
|
|
||||||
if (isset($optionInputData['category_icon'])) {
|
//Generate a html list item for each tab based on tabs file basename, set first tab as active
|
||||||
$optionsData['category_icon'] = $optionInputData['category_icon'];
|
$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>';
|
||||||
}
|
}
|
||||||
$optionsData['settings_class'] = $className;
|
|
||||||
|
|
||||||
$settings[str_replace('Settings', '', class_basename($className))] = $optionsData;
|
|
||||||
}
|
|
||||||
|
|
||||||
$settings->sort();
|
|
||||||
|
|
||||||
|
|
||||||
$themes = array_diff(scandir(base_path('themes')), array('..', '.'));
|
$themes = array_diff(scandir(base_path('themes')), array('..', '.'));
|
||||||
|
|
||||||
return view('admin.settings.index', [
|
return view('admin.settings.index', [
|
||||||
'settings' => $settings->all(),
|
'tabs' => $tabs,
|
||||||
|
'tabListItems' => $tabListItems,
|
||||||
'themes' => $themes,
|
'themes' => $themes,
|
||||||
'active_theme' => Theme::active(),
|
'active_theme' => Theme::active(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the specified resource in storage.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public function update(Request $request)
|
|
||||||
{
|
|
||||||
$category = request()->get('category');
|
|
||||||
|
|
||||||
$this->checkPermission("settings." . strtolower($category) . ".write");
|
|
||||||
|
|
||||||
$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;
|
|
||||||
}
|
|
||||||
if ($rp->name == 'available') {
|
|
||||||
$settingsClass->$key = implode(",", $request->$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.');
|
|
||||||
}
|
|
||||||
|
|
||||||
public 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');
|
|
||||||
}
|
|
||||||
|
|
||||||
return Redirect::to('admin/settings')->with('success', 'Icons updated successfully.');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,40 +2,38 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
namespace App\Http\Controllers\Admin;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Models\ShopProduct;
|
use App\Models\ShopProduct;
|
||||||
use App\Settings\GeneralSettings;
|
|
||||||
use App\Settings\LocaleSettings;
|
|
||||||
use Illuminate\Contracts\Foundation\Application;
|
use Illuminate\Contracts\Foundation\Application;
|
||||||
use Illuminate\Contracts\View\Factory;
|
use Illuminate\Contracts\View\Factory;
|
||||||
use Illuminate\Contracts\View\View;
|
use Illuminate\Contracts\View\View;
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
|
use Illuminate\Routing\Controller;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
class ShopProductController extends Controller
|
class ShopProductController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
const READ_PERMISSION = 'admin.store.read';
|
|
||||||
const WRITE_PERMISSION = 'admin.store.write';
|
|
||||||
const DISABLE_PERMISSION = 'admin.store.disable';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display a listing of the resource.
|
* Display a listing of the resource.
|
||||||
*
|
*
|
||||||
* @return Application|Factory|View|Response
|
* @return Application|Factory|View|Response
|
||||||
*/
|
*/
|
||||||
public function index(LocaleSettings $locale_settings, GeneralSettings $general_settings)
|
public function index(Request $request)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::READ_PERMISSION);
|
$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', [
|
return view('admin.store.index', [
|
||||||
'isStoreEnabled' => $isStoreEnabled,
|
'isPaymentSetup' => $isPaymentSetup,
|
||||||
'locale_datatables' => $locale_settings->datatables
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,13 +42,10 @@ class ShopProductController extends Controller
|
||||||
*
|
*
|
||||||
* @return Application|Factory|View|Response
|
* @return Application|Factory|View|Response
|
||||||
*/
|
*/
|
||||||
public function create(GeneralSettings $general_settings)
|
public function create()
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
|
|
||||||
return view('admin.store.create', [
|
return view('admin.store.create', [
|
||||||
'currencyCodes' => config('currency_codes'),
|
'currencyCodes' => config('currency_codes'),
|
||||||
'credits_display_name' => $general_settings->credits_display_name
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,14 +79,11 @@ class ShopProductController extends Controller
|
||||||
* @param ShopProduct $shopProduct
|
* @param ShopProduct $shopProduct
|
||||||
* @return Application|Factory|View|Response
|
* @return Application|Factory|View|Response
|
||||||
*/
|
*/
|
||||||
public function edit(ShopProduct $shopProduct, GeneralSettings $general_settings)
|
public function edit(ShopProduct $shopProduct)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
|
|
||||||
return view('admin.store.edit', [
|
return view('admin.store.edit', [
|
||||||
'currencyCodes' => config('currency_codes'),
|
'currencyCodes' => config('currency_codes'),
|
||||||
'shopProduct' => $shopProduct,
|
'shopProduct' => $shopProduct,
|
||||||
'credits_display_name' => $general_settings->credits_display_name
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,10 +117,8 @@ class ShopProductController extends Controller
|
||||||
* @param ShopProduct $shopProduct
|
* @param ShopProduct $shopProduct
|
||||||
* @return RedirectResponse
|
* @return RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function disable(ShopProduct $shopProduct)
|
public function disable(Request $request, ShopProduct $shopProduct)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::DISABLE_PERMISSION);
|
|
||||||
|
|
||||||
$shopProduct->update(['disabled' => !$shopProduct->disabled]);
|
$shopProduct->update(['disabled' => !$shopProduct->disabled]);
|
||||||
|
|
||||||
return redirect()->route('admin.store.index')->with('success', __('Product has been updated!'));
|
return redirect()->route('admin.store.index')->with('success', __('Product has been updated!'));
|
||||||
|
@ -142,7 +132,6 @@ class ShopProductController extends Controller
|
||||||
*/
|
*/
|
||||||
public function destroy(ShopProduct $shopProduct)
|
public function destroy(ShopProduct $shopProduct)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
$shopProduct->delete();
|
$shopProduct->delete();
|
||||||
|
|
||||||
return redirect()->back()->with('success', __('Store item has been removed!'));
|
return redirect()->back()->with('success', __('Store item has been removed!'));
|
||||||
|
@ -156,16 +145,16 @@ class ShopProductController extends Controller
|
||||||
return datatables($query)
|
return datatables($query)
|
||||||
->addColumn('actions', function (ShopProduct $shopProduct) {
|
->addColumn('actions', function (ShopProduct $shopProduct) {
|
||||||
return '
|
return '
|
||||||
<a data-content="' . __('Edit') . '" data-toggle="popover" data-trigger="hover" data-placement="top" href="' . route('admin.store.edit', $shopProduct->id) . '" class="mr-1 btn btn-sm btn-info"><i class="fas fa-pen"></i></a>
|
<a data-content="' . __('Edit') . '" data-toggle="popover" data-trigger="hover" data-placement="top" href="' . route('admin.store.edit', $shopProduct->id) . '" class="btn btn-sm btn-info mr-1"><i class="fas fa-pen"></i></a>
|
||||||
|
|
||||||
<form class="d-inline" onsubmit="return submitResult();" method="post" action="' . route('admin.store.destroy', $shopProduct->id) . '">
|
<form class="d-inline" onsubmit="return submitResult();" method="post" action="' . route('admin.store.destroy', $shopProduct->id) . '">
|
||||||
' . csrf_field() . '
|
' . csrf_field() . '
|
||||||
' . method_field('DELETE') . '
|
' . method_field('DELETE') . '
|
||||||
<button data-content="' . __('Delete') . '" data-toggle="popover" data-trigger="hover" data-placement="top" class="mr-1 btn btn-sm btn-danger"><i class="fas fa-trash"></i></button>
|
<button data-content="' . __('Delete') . '" data-toggle="popover" data-trigger="hover" data-placement="top" class="btn btn-sm btn-danger mr-1"><i class="fas fa-trash"></i></button>
|
||||||
</form>
|
</form>
|
||||||
';
|
';
|
||||||
})
|
})
|
||||||
->editColumn('disabled', function (ShopProduct $shopProduct) {
|
->addColumn('disabled', function (ShopProduct $shopProduct) {
|
||||||
$checked = $shopProduct->disabled == false ? 'checked' : '';
|
$checked = $shopProduct->disabled == false ? 'checked' : '';
|
||||||
|
|
||||||
return '
|
return '
|
||||||
|
|
|
@ -5,7 +5,6 @@ namespace App\Http\Controllers\Admin;
|
||||||
use App\Enums\UsefulLinkLocation;
|
use App\Enums\UsefulLinkLocation;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\UsefulLink;
|
use App\Models\UsefulLink;
|
||||||
use App\Settings\LocaleSettings;
|
|
||||||
use Illuminate\Contracts\Foundation\Application;
|
use Illuminate\Contracts\Foundation\Application;
|
||||||
use Illuminate\Contracts\View\Factory;
|
use Illuminate\Contracts\View\Factory;
|
||||||
use Illuminate\Contracts\View\View;
|
use Illuminate\Contracts\View\View;
|
||||||
|
@ -15,19 +14,14 @@ use Illuminate\Http\Response;
|
||||||
|
|
||||||
class UsefulLinkController extends Controller
|
class UsefulLinkController extends Controller
|
||||||
{
|
{
|
||||||
const READ_PERMISSION = "admin.useful_links.read";
|
|
||||||
const WRITE_PERMISSION = "admin.useful_links.write";
|
|
||||||
/**
|
/**
|
||||||
* Display a listing of the resource.
|
* Display a listing of the resource.
|
||||||
*
|
*
|
||||||
* @return Application|Factory|View|Response
|
* @return Application|Factory|View|Response
|
||||||
*/
|
*/
|
||||||
public function index(LocaleSettings $locale_settings)
|
public function index()
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::READ_PERMISSION);
|
return view('admin.usefullinks.index');
|
||||||
return view('admin.usefullinks.index', [
|
|
||||||
'locale_datatables' => $locale_settings->datatables
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,7 +31,6 @@ class UsefulLinkController extends Controller
|
||||||
*/
|
*/
|
||||||
public function create()
|
public function create()
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
$positions = UsefulLinkLocation::cases();
|
$positions = UsefulLinkLocation::cases();
|
||||||
return view('admin.usefullinks.create')->with('positions', $positions);
|
return view('admin.usefullinks.create')->with('positions', $positions);
|
||||||
}
|
}
|
||||||
|
@ -88,8 +81,6 @@ class UsefulLinkController extends Controller
|
||||||
*/
|
*/
|
||||||
public function edit(UsefulLink $usefullink)
|
public function edit(UsefulLink $usefullink)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
|
|
||||||
$positions = UsefulLinkLocation::cases();
|
$positions = UsefulLinkLocation::cases();
|
||||||
return view('admin.usefullinks.edit', [
|
return view('admin.usefullinks.edit', [
|
||||||
'link' => $usefullink,
|
'link' => $usefullink,
|
||||||
|
@ -132,7 +123,6 @@ class UsefulLinkController extends Controller
|
||||||
*/
|
*/
|
||||||
public function destroy(UsefulLink $usefullink)
|
public function destroy(UsefulLink $usefullink)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
$usefullink->delete();
|
$usefullink->delete();
|
||||||
|
|
||||||
return redirect()->back()->with('success', __('product has been removed!'));
|
return redirect()->back()->with('success', __('product has been removed!'));
|
||||||
|
|
|
@ -2,14 +2,11 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
namespace App\Http\Controllers\Admin;
|
||||||
|
|
||||||
|
use App\Classes\Pterodactyl;
|
||||||
use App\Events\UserUpdateCreditsEvent;
|
use App\Events\UserUpdateCreditsEvent;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Notifications\DynamicNotification;
|
use App\Notifications\DynamicNotification;
|
||||||
use App\Settings\LocaleSettings;
|
|
||||||
use App\Settings\PterodactylSettings;
|
|
||||||
use App\Classes\PterodactylClient;
|
|
||||||
use App\Settings\GeneralSettings;
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Contracts\Foundation\Application;
|
use Illuminate\Contracts\Foundation\Application;
|
||||||
use Illuminate\Contracts\View\Factory;
|
use Illuminate\Contracts\View\Factory;
|
||||||
|
@ -26,29 +23,15 @@ use Illuminate\Support\HtmlString;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
use Spatie\QueryBuilder\QueryBuilder;
|
use Spatie\QueryBuilder\QueryBuilder;
|
||||||
use Spatie\Permission\Models\Role;
|
|
||||||
|
|
||||||
class UserController extends Controller
|
class UserController extends Controller
|
||||||
{
|
{
|
||||||
const READ_PERMISSION = "admin.users.read";
|
|
||||||
const WRITE_PERMISSION = "admin.users.write";
|
|
||||||
const SUSPEND_PERMISSION = "admin.users.suspend";
|
|
||||||
const CHANGE_EMAIL_PERMISSION = "admin.users.write.email";
|
|
||||||
const CHANGE_CREDITS_PERMISSION = "admin.users.write.credits";
|
|
||||||
const CHANGE_USERNAME_PERMISSION = "admin.users.write.username";
|
|
||||||
const CHANGE_PASSWORD_PERMISSION = "admin.users.write.password";
|
|
||||||
const CHANGE_ROLE_PERMISSION ="admin.users.write.role";
|
|
||||||
const CHANGE_REFERAL_PERMISSION ="admin.users.write.referal";
|
|
||||||
const CHANGE_PTERO_PERMISSION = "admin.users.write.pterodactyl";
|
|
||||||
const DELETE_PERMISSION = "admin.users.delete";
|
|
||||||
const NOTIFY_PERMISSION = "admin.users.notify";
|
|
||||||
const LOGIN_PERMISSION = "admin.users.login_as";
|
|
||||||
|
|
||||||
private $pterodactyl;
|
private Pterodactyl $pterodactyl;
|
||||||
|
|
||||||
public function __construct(PterodactylSettings $ptero_settings)
|
public function __construct(Pterodactyl $pterodactyl)
|
||||||
{
|
{
|
||||||
$this->pterodactyl = new PterodactylClient($ptero_settings);
|
$this->pterodactyl = $pterodactyl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,14 +40,9 @@ class UserController extends Controller
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @return Application|Factory|View|Response
|
* @return Application|Factory|View|Response
|
||||||
*/
|
*/
|
||||||
public function index(LocaleSettings $locale_settings, GeneralSettings $general_settings)
|
public function index(Request $request)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::READ_PERMISSION);
|
return view('admin.users.index');
|
||||||
|
|
||||||
return view('admin.users.index', [
|
|
||||||
'locale_datatables' => $locale_settings->datatables,
|
|
||||||
'credits_display_name' => $general_settings->credits_display_name
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -73,10 +51,8 @@ class UserController extends Controller
|
||||||
* @param User $user
|
* @param User $user
|
||||||
* @return Application|Factory|View|Response
|
* @return Application|Factory|View|Response
|
||||||
*/
|
*/
|
||||||
public function show(User $user, LocaleSettings $locale_settings, GeneralSettings $general_settings)
|
public function show(User $user)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::READ_PERMISSION);
|
|
||||||
|
|
||||||
//QUERY ALL REFERRALS A USER HAS
|
//QUERY ALL REFERRALS A USER HAS
|
||||||
//i am not proud of this at all.
|
//i am not proud of this at all.
|
||||||
$allReferals = [];
|
$allReferals = [];
|
||||||
|
@ -89,8 +65,6 @@ class UserController extends Controller
|
||||||
return view('admin.users.show')->with([
|
return view('admin.users.show')->with([
|
||||||
'user' => $user,
|
'user' => $user,
|
||||||
'referrals' => $allReferals,
|
'referrals' => $allReferals,
|
||||||
'locale_datatables' => $locale_settings->datatables,
|
|
||||||
'credits_display_name' => $general_settings->credits_display_name
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,15 +99,10 @@ class UserController extends Controller
|
||||||
* @param User $user
|
* @param User $user
|
||||||
* @return Application|Factory|View|Response
|
* @return Application|Factory|View|Response
|
||||||
*/
|
*/
|
||||||
public function edit(User $user, GeneralSettings $general_settings)
|
public function edit(User $user)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
|
|
||||||
$roles = Role::all();
|
|
||||||
return view('admin.users.edit')->with([
|
return view('admin.users.edit')->with([
|
||||||
'user' => $user,
|
'user' => $user,
|
||||||
'credits_display_name' => $general_settings->credits_display_name,
|
|
||||||
'roles' => $roles
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,27 +117,23 @@ class UserController extends Controller
|
||||||
*/
|
*/
|
||||||
public function update(Request $request, User $user)
|
public function update(Request $request, User $user)
|
||||||
{
|
{
|
||||||
$data = $request->validate([
|
$request->validate([
|
||||||
'name' => 'required|string|min:4|max:30',
|
'name' => 'required|string|min:4|max:30',
|
||||||
'pterodactyl_id' => "required|numeric|unique:users,pterodactyl_id,{$user->id}",
|
'pterodactyl_id' => "required|numeric|unique:users,pterodactyl_id,{$user->id}",
|
||||||
'email' => 'required|string|email',
|
'email' => 'required|string|email',
|
||||||
'credits' => 'required|numeric|min:0|max:99999999',
|
'credits' => 'required|numeric|min:0|max:99999999',
|
||||||
'server_limit' => 'required|numeric|min:0|max:1000000',
|
'server_limit' => 'required|numeric|min:0|max:1000000',
|
||||||
|
'role' => Rule::in(['admin', 'moderator', 'client', 'member']),
|
||||||
'referral_code' => "required|string|min:2|max:32|unique:users,referral_code,{$user->id}",
|
'referral_code' => "required|string|min:2|max:32|unique:users,referral_code,{$user->id}",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
//update roles
|
|
||||||
if ($request->roles && $this->can(self::CHANGE_ROLE_PERMISSION)) {
|
|
||||||
$user->syncRoles($request->roles);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($this->pterodactyl->getUser($request->input('pterodactyl_id'))['errors'])) {
|
if (isset($this->pterodactyl->getUser($request->input('pterodactyl_id'))['errors'])) {
|
||||||
throw ValidationException::withMessages([
|
throw ValidationException::withMessages([
|
||||||
'pterodactyl_id' => [__("User does not exists on pterodactyl's panel")],
|
'pterodactyl_id' => [__("User does not exists on pterodactyl's panel")],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_null($request->input('new_password')) && $this->can(self::CHANGE_PASSWORD_PERMISSION)) {
|
if (!is_null($request->input('new_password'))) {
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'new_password' => 'required|string|min:8',
|
'new_password' => 'required|string|min:8',
|
||||||
'new_password_confirmation' => 'required|same:new_password',
|
'new_password_confirmation' => 'required|same:new_password',
|
||||||
|
@ -179,24 +144,7 @@ class UserController extends Controller
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if($this->can(self::CHANGE_USERNAME_PERMISSION)){
|
$user->update($request->all());
|
||||||
// $user->name = $request->name;
|
|
||||||
// }
|
|
||||||
// if($this->can(self::CHANGE_CREDITS_PERMISSION)){
|
|
||||||
// $user->credits = $request->credits;
|
|
||||||
// }
|
|
||||||
// if($this->can(self::CHANGE_PTERO_PERMISSION)){
|
|
||||||
// $user->pterodactyl_id = $request->pterodactyl_id;
|
|
||||||
// }
|
|
||||||
// if($this->can(self::CHANGE_REFERAL_PERMISSION)){
|
|
||||||
// $user->referral_code = $request->referral_code;
|
|
||||||
// }
|
|
||||||
// if($this->can(self::CHANGE_EMAIL_PERMISSION)){
|
|
||||||
// $user->email = $request->email;
|
|
||||||
// }
|
|
||||||
|
|
||||||
$user->update($data);
|
|
||||||
|
|
||||||
event(new UserUpdateCreditsEvent($user));
|
event(new UserUpdateCreditsEvent($user));
|
||||||
|
|
||||||
return redirect()->route('admin.users.index')->with('success', 'User updated!');
|
return redirect()->route('admin.users.index')->with('success', 'User updated!');
|
||||||
|
@ -210,12 +158,6 @@ class UserController extends Controller
|
||||||
*/
|
*/
|
||||||
public function destroy(User $user)
|
public function destroy(User $user)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::DELETE_PERMISSION);
|
|
||||||
|
|
||||||
if ($user->hasRole(1) && User::role(1)->count() === 1) {
|
|
||||||
return redirect()->back()->with('error', __('You can not delete the last admin!'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$user->delete();
|
$user->delete();
|
||||||
|
|
||||||
return redirect()->back()->with('success', __('user has been removed!'));
|
return redirect()->back()->with('success', __('user has been removed!'));
|
||||||
|
@ -227,7 +169,7 @@ class UserController extends Controller
|
||||||
* @param User $user
|
* @param User $user
|
||||||
* @return RedirectResponse
|
* @return RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function verifyEmail(User $user)
|
public function verifyEmail(Request $request, User $user)
|
||||||
{
|
{
|
||||||
$user->verifyEmail();
|
$user->verifyEmail();
|
||||||
|
|
||||||
|
@ -241,8 +183,6 @@ class UserController extends Controller
|
||||||
*/
|
*/
|
||||||
public function loginAs(Request $request, User $user)
|
public function loginAs(Request $request, User $user)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::LOGIN_PERMISSION);
|
|
||||||
|
|
||||||
$request->session()->put('previousUser', Auth::user()->id);
|
$request->session()->put('previousUser', Auth::user()->id);
|
||||||
Auth::login($user);
|
Auth::login($user);
|
||||||
|
|
||||||
|
@ -255,7 +195,6 @@ class UserController extends Controller
|
||||||
*/
|
*/
|
||||||
public function logBackIn(Request $request)
|
public function logBackIn(Request $request)
|
||||||
{
|
{
|
||||||
|
|
||||||
Auth::loginUsingId($request->session()->get('previousUser'), true);
|
Auth::loginUsingId($request->session()->get('previousUser'), true);
|
||||||
$request->session()->remove('previousUser');
|
$request->session()->remove('previousUser');
|
||||||
|
|
||||||
|
@ -268,13 +207,9 @@ class UserController extends Controller
|
||||||
* @param User $user
|
* @param User $user
|
||||||
* @return Application|Factory|View|Response
|
* @return Application|Factory|View|Response
|
||||||
*/
|
*/
|
||||||
public function notifications()
|
public function notifications(User $user)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::NOTIFY_PERMISSION);
|
return view('admin.users.notifications');
|
||||||
|
|
||||||
$roles = Role::all();
|
|
||||||
|
|
||||||
return view('admin.users.notifications')->with(["roles" => $roles]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -288,16 +223,12 @@ class UserController extends Controller
|
||||||
*/
|
*/
|
||||||
public function notify(Request $request)
|
public function notify(Request $request)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::NOTIFY_PERMISSION);
|
|
||||||
|
|
||||||
//TODO: reimplement the required validation on all,users and roles . didnt work -- required_without:users,roles
|
|
||||||
$data = $request->validate([
|
$data = $request->validate([
|
||||||
'via' => 'required|min:1|array',
|
'via' => 'required|min:1|array',
|
||||||
'via.*' => 'required|string|in:mail,database',
|
'via.*' => 'required|string|in:mail,database',
|
||||||
'all' => 'boolean',
|
'all' => 'required_without:users|boolean',
|
||||||
'users' => 'min:1|array',
|
'users' => 'required_without:all|min:1|array',
|
||||||
'roles' => 'min:1|array',
|
'users.*' => 'exists:users,id',
|
||||||
'roles.*' => 'required_without:all,users|exists:roles,id',
|
|
||||||
'title' => 'required|string|min:1',
|
'title' => 'required|string|min:1',
|
||||||
'content' => 'required|string|min:1',
|
'content' => 'required|string|min:1',
|
||||||
]);
|
]);
|
||||||
|
@ -316,19 +247,8 @@ class UserController extends Controller
|
||||||
->line(new HtmlString($data['content']));
|
->line(new HtmlString($data['content']));
|
||||||
}
|
}
|
||||||
$all = $data['all'] ?? false;
|
$all = $data['all'] ?? false;
|
||||||
$roles = $data['roles'] ?? false;
|
|
||||||
if(!$roles){
|
|
||||||
$users = $all ? User::all() : User::whereIn('id', $data['users'])->get();
|
$users = $all ? User::all() : User::whereIn('id', $data['users'])->get();
|
||||||
} else{
|
|
||||||
$users = User::role($data["roles"])->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
|
||||||
Notification::send($users, new DynamicNotification($data['via'], $database, $mail));
|
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!'));
|
return redirect()->route('admin.users.notifications')->with('success', __('Notification sent!'));
|
||||||
}
|
}
|
||||||
|
@ -339,12 +259,6 @@ class UserController extends Controller
|
||||||
*/
|
*/
|
||||||
public function toggleSuspended(User $user)
|
public function toggleSuspended(User $user)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::SUSPEND_PERMISSION);
|
|
||||||
|
|
||||||
if (Auth::user()->id === $user->id) {
|
|
||||||
return redirect()->back()->with('error', __('You can not suspend yourself!'));
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
!$user->isSuspended() ? $user->suspend() : $user->unSuspend();
|
!$user->isSuspended() ? $user->suspend() : $user->unSuspend();
|
||||||
} catch (Exception $exception) {
|
} catch (Exception $exception) {
|
||||||
|
@ -359,19 +273,17 @@ class UserController extends Controller
|
||||||
*/
|
*/
|
||||||
public function dataTable(Request $request)
|
public function dataTable(Request $request)
|
||||||
{
|
{
|
||||||
$query = User::query()
|
$query = User::with('discordUser')->withCount('servers');
|
||||||
->withCount('servers')
|
// manually count referrals in user_referrals table
|
||||||
->leftJoin('model_has_roles', 'users.id', '=', 'model_has_roles.model_id')
|
$query->selectRaw('users.*, (SELECT COUNT(*) FROM user_referrals WHERE user_referrals.referral_id = users.id) as referrals_count');
|
||||||
->leftJoin('roles', 'model_has_roles.role_id', '=', 'roles.id')
|
|
||||||
->selectRaw('users.*, roles.name as role_name, (SELECT COUNT(*) FROM user_referrals WHERE user_referrals.referral_id = users.id) as referrals_count')
|
|
||||||
->where('model_has_roles.model_type', User::class);
|
|
||||||
|
|
||||||
return datatables($query)
|
return datatables($query)
|
||||||
->addColumn('avatar', function (User $user) {
|
->addColumn('avatar', function (User $user) {
|
||||||
return '<img width="28px" height="28px" class="ml-1 rounded-circle" src="' . $user->getAvatar() . '">';
|
return '<img width="28px" height="28px" class="rounded-circle ml-1" src="' . $user->getAvatar() . '">';
|
||||||
})
|
})
|
||||||
->addColumn('credits', function (User $user) {
|
->addColumn('credits', function (User $user) {
|
||||||
return '<i class="mr-2 fas fa-coins"></i> ' . $user->credits();
|
return '<i class="fas fa-coins mr-2"></i> ' . $user->credits();
|
||||||
})
|
})
|
||||||
->addColumn('verified', function (User $user) {
|
->addColumn('verified', function (User $user) {
|
||||||
return $user->getVerifiedStatus();
|
return $user->getVerifiedStatus();
|
||||||
|
@ -385,10 +297,10 @@ class UserController extends Controller
|
||||||
$suspendText = $user->isSuspended() ? __('Unsuspend') : __('Suspend');
|
$suspendText = $user->isSuspended() ? __('Unsuspend') : __('Suspend');
|
||||||
|
|
||||||
return '
|
return '
|
||||||
<a data-content="' . __('Login as User') . '" data-toggle="popover" data-trigger="hover" data-placement="top" href="' . route('admin.users.loginas', $user->id) . '" class="mr-1 btn btn-sm btn-primary"><i class="fas fa-sign-in-alt"></i></a>
|
<a data-content="' . __('Login as User') . '" data-toggle="popover" data-trigger="hover" data-placement="top" href="' . route('admin.users.loginas', $user->id) . '" class="btn btn-sm btn-primary mr-1"><i class="fas fa-sign-in-alt"></i></a>
|
||||||
<a data-content="' . __('Verify') . '" data-toggle="popover" data-trigger="hover" data-placement="top" href="' . route('admin.users.verifyEmail', $user->id) . '" class="mr-1 btn btn-sm btn-secondary"><i class="fas fa-envelope"></i></a>
|
<a data-content="' . __('Verify') . '" data-toggle="popover" data-trigger="hover" data-placement="top" href="' . route('admin.users.verifyEmail', $user->id) . '" class="btn btn-sm btn-secondary mr-1"><i class="fas fa-envelope"></i></a>
|
||||||
<a data-content="' . __('Show') . '" data-toggle="popover" data-trigger="hover" data-placement="top" href="' . route('admin.users.show', $user->id) . '" class="mr-1 text-white btn btn-sm btn-warning"><i class="fas fa-eye"></i></a>
|
<a data-content="' . __('Show') . '" data-toggle="popover" data-trigger="hover" data-placement="top" href="' . route('admin.users.show', $user->id) . '" class="btn btn-sm text-white btn-warning mr-1"><i class="fas fa-eye"></i></a>
|
||||||
<a data-content="' . __('Edit') . '" data-toggle="popover" data-trigger="hover" data-placement="top" href="' . route('admin.users.edit', $user->id) . '" class="mr-1 btn btn-sm btn-info"><i class="fas fa-pen"></i></a>
|
<a data-content="' . __('Edit') . '" data-toggle="popover" data-trigger="hover" data-placement="top" href="' . route('admin.users.edit', $user->id) . '" class="btn btn-sm btn-info mr-1"><i class="fas fa-pen"></i></a>
|
||||||
<form class="d-inline" method="post" action="' . route('admin.users.togglesuspend', $user->id) . '">
|
<form class="d-inline" method="post" action="' . route('admin.users.togglesuspend', $user->id) . '">
|
||||||
' . csrf_field() . '
|
' . csrf_field() . '
|
||||||
<button data-content="' . $suspendText . '" data-toggle="popover" data-trigger="hover" data-placement="top" class="btn btn-sm ' . $suspendColor . ' text-white mr-1"><i class="far ' . $suspendIcon . '"></i></button>
|
<button data-content="' . $suspendText . '" data-toggle="popover" data-trigger="hover" data-placement="top" class="btn btn-sm ' . $suspendColor . ' text-white mr-1"><i class="far ' . $suspendIcon . '"></i></button>
|
||||||
|
@ -396,26 +308,34 @@ class UserController extends Controller
|
||||||
<form class="d-inline" onsubmit="return submitResult();" method="post" action="' . route('admin.users.destroy', $user->id) . '">
|
<form class="d-inline" onsubmit="return submitResult();" method="post" action="' . route('admin.users.destroy', $user->id) . '">
|
||||||
' . csrf_field() . '
|
' . csrf_field() . '
|
||||||
' . method_field('DELETE') . '
|
' . method_field('DELETE') . '
|
||||||
<button data-content="' . __('Delete') . '" data-toggle="popover" data-trigger="hover" data-placement="top" class="mr-1 btn btn-sm btn-danger"><i class="fas fa-trash"></i></button>
|
<button data-content="' . __('Delete') . '" data-toggle="popover" data-trigger="hover" data-placement="top" class="btn btn-sm btn-danger mr-1"><i class="fas fa-trash"></i></button>
|
||||||
</form>
|
</form>
|
||||||
';
|
';
|
||||||
})
|
})
|
||||||
->editColumn('role', function (User $user) {
|
->editColumn('role', function (User $user) {
|
||||||
$html = '';
|
switch ($user->role) {
|
||||||
|
case 'admin':
|
||||||
foreach ($user->roles as $role) {
|
$badgeColor = 'badge-danger';
|
||||||
$html .= "<span style='background-color: $role->color' class='badge'>$role->name</span>";
|
break;
|
||||||
|
case 'moderator':
|
||||||
|
$badgeColor = 'badge-info';
|
||||||
|
break;
|
||||||
|
case 'client':
|
||||||
|
$badgeColor = 'badge-success';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$badgeColor = 'badge-secondary';
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $html;
|
return '<span class="badge ' . $badgeColor . '">' . $user->role . '</span>';
|
||||||
})
|
})
|
||||||
->editColumn('last_seen', function (User $user) {
|
->editColumn('last_seen', function (User $user) {
|
||||||
return $user->last_seen ? $user->last_seen->diffForHumans() : __('Never');
|
return $user->last_seen ? $user->last_seen->diffForHumans() : __('Never');
|
||||||
})
|
})
|
||||||
->editColumn('name', function (User $user, PterodactylSettings $ptero_settings) {
|
->editColumn('name', function (User $user) {
|
||||||
return '<a class="text-info" target="_blank" href="' . $ptero_settings->panel_url . '/admin/users/view/' . $user->pterodactyl_id . '">' . strip_tags($user->name) . '</a>';
|
return '<a class="text-info" target="_blank" href="' . config('SETTINGS::SYSTEM:PTERODACTYL:URL') . '/admin/users/view/' . $user->pterodactyl_id . '">' . strip_tags($user->name) . '</a>';
|
||||||
})
|
})
|
||||||
->orderColumn('role', 'role_name $1')
|
|
||||||
->rawColumns(['avatar', 'name', 'credits', 'role', 'usage', 'actions'])
|
->rawColumns(['avatar', 'name', 'credits', 'role', 'usage', 'actions'])
|
||||||
->make();
|
->make();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,6 @@ use App\Events\UserUpdateCreditsEvent;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Models\Voucher;
|
use App\Models\Voucher;
|
||||||
use App\Settings\GeneralSettings;
|
|
||||||
use App\Settings\LocaleSettings;
|
|
||||||
use Illuminate\Contracts\Foundation\Application;
|
use Illuminate\Contracts\Foundation\Application;
|
||||||
use Illuminate\Contracts\View\Factory;
|
use Illuminate\Contracts\View\Factory;
|
||||||
use Illuminate\Contracts\View\View;
|
use Illuminate\Contracts\View\View;
|
||||||
|
@ -19,21 +17,14 @@ use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
class VoucherController extends Controller
|
class VoucherController extends Controller
|
||||||
{
|
{
|
||||||
const READ_PERMISSION = "admin.voucher.read";
|
|
||||||
const WRITE_PERMISSION = "admin.voucher.write";
|
|
||||||
/**
|
/**
|
||||||
* Display a listing of the resource.
|
* Display a listing of the resource.
|
||||||
*
|
*
|
||||||
* @return Application|Factory|View
|
* @return Application|Factory|View
|
||||||
*/
|
*/
|
||||||
public function index(LocaleSettings $locale_settings, GeneralSettings $general_settings)
|
public function index()
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::READ_PERMISSION);
|
return view('admin.vouchers.index');
|
||||||
|
|
||||||
return view('admin.vouchers.index', [
|
|
||||||
'locale_datatables' => $locale_settings->datatables,
|
|
||||||
'credits_display_name' => $general_settings->credits_display_name
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -41,12 +32,9 @@ class VoucherController extends Controller
|
||||||
*
|
*
|
||||||
* @return Application|Factory|View
|
* @return Application|Factory|View
|
||||||
*/
|
*/
|
||||||
public function create(GeneralSettings $general_settings)
|
public function create()
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
return view('admin.vouchers.create');
|
||||||
return view('admin.vouchers.create', [
|
|
||||||
'credits_display_name' => $general_settings->credits_display_name
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -87,12 +75,10 @@ class VoucherController extends Controller
|
||||||
* @param Voucher $voucher
|
* @param Voucher $voucher
|
||||||
* @return Application|Factory|View
|
* @return Application|Factory|View
|
||||||
*/
|
*/
|
||||||
public function edit(Voucher $voucher, GeneralSettings $general_settings)
|
public function edit(Voucher $voucher)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
return view('admin.vouchers.edit', [
|
return view('admin.vouchers.edit', [
|
||||||
'voucher' => $voucher,
|
'voucher' => $voucher,
|
||||||
'credits_display_name' => $general_settings->credits_display_name
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,20 +112,15 @@ class VoucherController extends Controller
|
||||||
*/
|
*/
|
||||||
public function destroy(Voucher $voucher)
|
public function destroy(Voucher $voucher)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
$voucher->delete();
|
$voucher->delete();
|
||||||
|
|
||||||
return redirect()->back()->with('success', __('voucher has been removed!'));
|
return redirect()->back()->with('success', __('voucher has been removed!'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function users(Voucher $voucher, LocaleSettings $locale_settings, GeneralSettings $general_settings)
|
public function users(Voucher $voucher)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::READ_PERMISSION);
|
|
||||||
|
|
||||||
return view('admin.vouchers.users', [
|
return view('admin.vouchers.users', [
|
||||||
'voucher' => $voucher,
|
'voucher' => $voucher,
|
||||||
'locale_datatables' => $locale_settings->datatables,
|
|
||||||
'credits_display_name' => $general_settings->credits_display_name
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,7 +130,7 @@ class VoucherController extends Controller
|
||||||
*
|
*
|
||||||
* @throws ValidationException
|
* @throws ValidationException
|
||||||
*/
|
*/
|
||||||
public function redeem(Request $request, GeneralSettings $general_settings)
|
public function redeem(Request $request)
|
||||||
{
|
{
|
||||||
//general validations
|
//general validations
|
||||||
$request->validate([
|
$request->validate([
|
||||||
|
@ -180,7 +161,7 @@ class VoucherController extends Controller
|
||||||
|
|
||||||
if ($request->user()->credits + $voucher->credits >= 99999999) {
|
if ($request->user()->credits + $voucher->credits >= 99999999) {
|
||||||
throw ValidationException::withMessages([
|
throw ValidationException::withMessages([
|
||||||
'code' => "You can't redeem this voucher because you would exceed the limit of " . $general_settings->credits_display_name,
|
'code' => "You can't redeem this voucher because you would exceed the limit of ".CREDITS_DISPLAY_NAME,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +171,7 @@ class VoucherController extends Controller
|
||||||
event(new UserUpdateCreditsEvent($request->user()));
|
event(new UserUpdateCreditsEvent($request->user()));
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'success' => "{$voucher->credits} ". $general_settings->credits_display_name .' '.__('have been added to your balance!'),
|
'success' => "{$voucher->credits} ".CREDITS_DISPLAY_NAME.' '.__('have been added to your balance!'),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,7 +184,7 @@ class VoucherController extends Controller
|
||||||
return '<a class="text-info" target="_blank" href="'.route('admin.users.show', $user->id).'">'.$user->name.'</a>';
|
return '<a class="text-info" target="_blank" href="'.route('admin.users.show', $user->id).'">'.$user->name.'</a>';
|
||||||
})
|
})
|
||||||
->addColumn('credits', function (User $user) {
|
->addColumn('credits', function (User $user) {
|
||||||
return '<i class="mr-2 fas fa-coins"></i> '.$user->credits();
|
return '<i class="fas fa-coins mr-2"></i> '.$user->credits();
|
||||||
})
|
})
|
||||||
->addColumn('last_seen', function (User $user) {
|
->addColumn('last_seen', function (User $user) {
|
||||||
return $user->last_seen ? $user->last_seen->diffForHumans() : '';
|
return $user->last_seen ? $user->last_seen->diffForHumans() : '';
|
||||||
|
@ -214,33 +195,28 @@ class VoucherController extends Controller
|
||||||
|
|
||||||
public function dataTable()
|
public function dataTable()
|
||||||
{
|
{
|
||||||
$query = Voucher::selectRaw('
|
$query = Voucher::query();
|
||||||
vouchers.*,
|
|
||||||
CASE
|
|
||||||
WHEN (SELECT COUNT(*) FROM user_voucher WHERE user_voucher.voucher_id = vouchers.id) >= vouchers.uses THEN "USES_LIMIT_REACHED"
|
|
||||||
WHEN vouchers.expires_at IS NOT NULL AND vouchers.expires_at < NOW() THEN "EXPIRED"
|
|
||||||
ELSE "VALID"
|
|
||||||
END as derived_status
|
|
||||||
');
|
|
||||||
|
|
||||||
return datatables($query)
|
return datatables($query)
|
||||||
->addColumn('actions', function (Voucher $voucher) {
|
->addColumn('actions', function (Voucher $voucher) {
|
||||||
return '
|
return '
|
||||||
<a data-content="'.__('Users').'" data-toggle="popover" data-trigger="hover" data-placement="top" href="'.route('admin.vouchers.users', $voucher->id).'" class="mr-1 btn btn-sm btn-primary"><i class="fas fa-users"></i></a>
|
<a data-content="'.__('Users').'" data-toggle="popover" data-trigger="hover" data-placement="top" href="'.route('admin.vouchers.users', $voucher->id).'" class="btn btn-sm btn-primary mr-1"><i class="fas fa-users"></i></a>
|
||||||
<a data-content="'.__('Edit').'" data-toggle="popover" data-trigger="hover" data-placement="top" href="'.route('admin.vouchers.edit', $voucher->id).'" class="mr-1 btn btn-sm btn-info"><i class="fas fa-pen"></i></a>
|
<a data-content="'.__('Edit').'" data-toggle="popover" data-trigger="hover" data-placement="top" href="'.route('admin.vouchers.edit', $voucher->id).'" class="btn btn-sm btn-info mr-1"><i class="fas fa-pen"></i></a>
|
||||||
|
|
||||||
<form class="d-inline" onsubmit="return submitResult();" method="post" action="'.route('admin.vouchers.destroy', $voucher->id).'">
|
<form class="d-inline" onsubmit="return submitResult();" method="post" action="'.route('admin.vouchers.destroy', $voucher->id).'">
|
||||||
'.csrf_field().'
|
'.csrf_field().'
|
||||||
'.method_field('DELETE').'
|
'.method_field('DELETE').'
|
||||||
<button data-content="'.__('Delete').'" data-toggle="popover" data-trigger="hover" data-placement="top" class="mr-1 btn btn-sm btn-danger"><i class="fas fa-trash"></i></button>
|
<button data-content="'.__('Delete').'" data-toggle="popover" data-trigger="hover" data-placement="top" class="btn btn-sm btn-danger mr-1"><i class="fas fa-trash"></i></button>
|
||||||
</form>
|
</form>
|
||||||
';
|
';
|
||||||
})
|
})
|
||||||
->addColumn('status', function (Voucher $voucher) {
|
->addColumn('status', function (Voucher $voucher) {
|
||||||
$color = ($voucher->derived_status == 'VALID') ? 'success' : 'danger';
|
$color = 'success';
|
||||||
$status = str_replace('_', ' ', $voucher->derived_status);
|
if ($voucher->getStatus() != __('VALID')) {
|
||||||
|
$color = 'danger';
|
||||||
|
}
|
||||||
|
|
||||||
return '<span class="badge badge-'.$color.'">'.$status.'</span>';
|
return '<span class="badge badge-'.$color.'">'.$voucher->getStatus().'</span>';
|
||||||
})
|
})
|
||||||
->editColumn('uses', function (Voucher $voucher) {
|
->editColumn('uses', function (Voucher $voucher) {
|
||||||
return "{$voucher->used} / {$voucher->uses}";
|
return "{$voucher->used} / {$voucher->uses}";
|
||||||
|
@ -250,15 +226,14 @@ class VoucherController extends Controller
|
||||||
})
|
})
|
||||||
->editColumn('expires_at', function (Voucher $voucher) {
|
->editColumn('expires_at', function (Voucher $voucher) {
|
||||||
if (! $voucher->expires_at) {
|
if (! $voucher->expires_at) {
|
||||||
return __("Never");
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $voucher->expires_at ? $voucher->expires_at->diffForHumans() : __("Never");
|
return $voucher->expires_at ? $voucher->expires_at->diffForHumans() : '';
|
||||||
})
|
})
|
||||||
->editColumn('code', function (Voucher $voucher) {
|
->editColumn('code', function (Voucher $voucher) {
|
||||||
return "<code>{$voucher->code}</code>";
|
return "<code>{$voucher->code}</code>";
|
||||||
})
|
})
|
||||||
->orderColumn('status', 'derived_status $1')
|
|
||||||
->rawColumns(['actions', 'code', 'status'])
|
->rawColumns(['actions', 'code', 'status'])
|
||||||
->make();
|
->make();
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@ use Illuminate\Support\Facades\Notification;
|
||||||
use Illuminate\Support\HtmlString;
|
use Illuminate\Support\HtmlString;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
use Spatie\ValidationRules\Rules\Delimited;
|
use Spatie\ValidationRules\Rules\Delimited;
|
||||||
use Exception;
|
|
||||||
|
|
||||||
class NotificationController extends Controller
|
class NotificationController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -105,12 +104,8 @@ class NotificationController extends Controller
|
||||||
'users' => ['No users found!'],
|
'users' => ['No users found!'],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
Notification::send($users, new DynamicNotification($via, $database, $mail));
|
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()]);
|
return response()->json(['message' => 'Notification successfully sent.', 'user_count' => $users->count()]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,160 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Api;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Models\User;
|
|
||||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Http\Response;
|
|
||||||
use Illuminate\Validation\Rule;
|
|
||||||
use Spatie\Permission\Models\Role;
|
|
||||||
use Spatie\QueryBuilder\QueryBuilder;
|
|
||||||
|
|
||||||
class RoleController extends Controller
|
|
||||||
{
|
|
||||||
const ALLOWED_INCLUDES = ['permissions', 'users'];
|
|
||||||
|
|
||||||
const ALLOWED_FILTERS = ['name'];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display a listing of the resource.
|
|
||||||
*
|
|
||||||
* @return LengthAwarePaginator
|
|
||||||
*/
|
|
||||||
public function index(Request $request)
|
|
||||||
{
|
|
||||||
$query = QueryBuilder::for(Role::class)
|
|
||||||
->allowedIncludes(self::ALLOWED_INCLUDES)
|
|
||||||
->allowedFilters(self::ALLOWED_FILTERS);
|
|
||||||
|
|
||||||
return $query->paginate($request->input('per_page') ?? 50);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for creating a new resource.
|
|
||||||
*
|
|
||||||
* @return Response
|
|
||||||
*/
|
|
||||||
public function create()
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store a newly created resource in storage.
|
|
||||||
*
|
|
||||||
* @param Request $request
|
|
||||||
* @return Response
|
|
||||||
*/
|
|
||||||
public function store(Request $request)
|
|
||||||
{
|
|
||||||
$request->validate([
|
|
||||||
'name' => 'required|string|max:191',
|
|
||||||
'color' => [
|
|
||||||
'required',
|
|
||||||
'regex:/^#([a-f0-9]{6}|[a-f0-9]{3})$/i'
|
|
||||||
],
|
|
||||||
'power' => 'required',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$role = Role::create([
|
|
||||||
'name' => $request->name,
|
|
||||||
'color' => $request->color,
|
|
||||||
'power' => $request->power,
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($request->permissions) {
|
|
||||||
$permissions = explode(",",$request->permissions);
|
|
||||||
foreach($permissions as $permission){
|
|
||||||
$role->givePermissionTo($permission);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $role;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display the specified resource.
|
|
||||||
*
|
|
||||||
* @param int $id
|
|
||||||
* @return Role|Collection|Model
|
|
||||||
*/
|
|
||||||
public function show(int $id)
|
|
||||||
{
|
|
||||||
$query = QueryBuilder::for(Role::class)
|
|
||||||
->where('id', '=', $id)
|
|
||||||
->allowedIncludes(self::ALLOWED_INCLUDES);
|
|
||||||
|
|
||||||
return $query->firstOrFail();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for editing the specified resource.
|
|
||||||
*
|
|
||||||
* @param int $id
|
|
||||||
* @return Response
|
|
||||||
*/
|
|
||||||
public function edit($id)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the specified resource in storage.
|
|
||||||
*
|
|
||||||
* @param Request $request
|
|
||||||
* @param int $id
|
|
||||||
* @return Response
|
|
||||||
*/
|
|
||||||
public function update(Request $request, int $id)
|
|
||||||
{
|
|
||||||
$role = Role::findOrFail($id);
|
|
||||||
|
|
||||||
$request->validate([
|
|
||||||
'name' => 'sometimes|string|max:191',
|
|
||||||
'color' => [
|
|
||||||
'sometimes',
|
|
||||||
'regex:/^#([a-f0-9]{6}|[a-f0-9]{3})$/i'
|
|
||||||
],
|
|
||||||
'power' => 'sometimes',
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($request->permissions) {
|
|
||||||
$permissions = explode(",",$request->permissions);
|
|
||||||
$role->syncPermissions($permissions);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$role->update($request->except('permissions'));
|
|
||||||
|
|
||||||
return $role;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the specified resource from storage.
|
|
||||||
*
|
|
||||||
* @param int $id
|
|
||||||
* @return Response
|
|
||||||
*/
|
|
||||||
public function destroy(int $id)
|
|
||||||
{
|
|
||||||
$role = Role::findOrFail($id);
|
|
||||||
|
|
||||||
if($role->id == 1 || $role->id == 3|| $role->id == 4){ //cannot delete admin and User role
|
|
||||||
return response()->json([
|
|
||||||
'error' => 'Not allowed to delete Admin, Client or Member'], 400);
|
|
||||||
}
|
|
||||||
|
|
||||||
$users = User::role($role)->get();
|
|
||||||
|
|
||||||
foreach($users as $user){
|
|
||||||
$user->syncRoles([4]);
|
|
||||||
}
|
|
||||||
$role->delete();
|
|
||||||
|
|
||||||
return $role;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,7 +8,7 @@ use App\Http\Controllers\Controller;
|
||||||
use App\Models\DiscordUser;
|
use App\Models\DiscordUser;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Notifications\ReferralNotification;
|
use App\Notifications\ReferralNotification;
|
||||||
use App\Settings\UserSettings;
|
use App\Traits\Referral;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Contracts\Foundation\Application;
|
use Illuminate\Contracts\Foundation\Application;
|
||||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||||
|
@ -28,9 +28,11 @@ use Spatie\QueryBuilder\QueryBuilder;
|
||||||
|
|
||||||
class UserController extends Controller
|
class UserController extends Controller
|
||||||
{
|
{
|
||||||
const ALLOWED_INCLUDES = ['servers', 'notifications', 'payments', 'vouchers', 'roles', 'discordUser'];
|
use Referral;
|
||||||
|
|
||||||
const ALLOWED_FILTERS = ['name', 'server_limit', 'email', 'pterodactyl_id', 'suspended'];
|
const ALLOWED_INCLUDES = ['servers', 'notifications', 'payments', 'vouchers', 'discordUser'];
|
||||||
|
|
||||||
|
const ALLOWED_FILTERS = ['name', 'server_limit', 'email', 'pterodactyl_id', 'role', 'suspended'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display a listing of the resource.
|
* Display a listing of the resource.
|
||||||
|
@ -86,6 +88,7 @@ class UserController extends Controller
|
||||||
'email' => 'sometimes|string|email',
|
'email' => 'sometimes|string|email',
|
||||||
'credits' => 'sometimes|numeric|min:0|max:1000000',
|
'credits' => 'sometimes|numeric|min:0|max:1000000',
|
||||||
'server_limit' => 'sometimes|numeric|min:0|max:1000000',
|
'server_limit' => 'sometimes|numeric|min:0|max:1000000',
|
||||||
|
'role' => ['sometimes', Rule::in(['admin', 'moderator', 'client', 'member'])],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
event(new UserUpdateCreditsEvent($user));
|
event(new UserUpdateCreditsEvent($user));
|
||||||
|
@ -105,10 +108,7 @@ class UserController extends Controller
|
||||||
'pterodactyl_error_status' => $response->toException()->getCode(),
|
'pterodactyl_error_status' => $response->toException()->getCode(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
if($request->has("role")){
|
$user->update($request->all());
|
||||||
$user->syncRoles($request->role);
|
|
||||||
}
|
|
||||||
$user->update($request->except('role'));
|
|
||||||
|
|
||||||
return $user;
|
return $user;
|
||||||
}
|
}
|
||||||
|
@ -243,25 +243,10 @@ class UserController extends Controller
|
||||||
return $user;
|
return $user;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a unique Referral Code for User
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function createReferralCode()
|
|
||||||
{
|
|
||||||
$referralcode = STR::random(8);
|
|
||||||
if (User::where('referral_code', '=', $referralcode)->exists()) {
|
|
||||||
$this->createReferralCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $referralcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws ValidationException
|
* @throws ValidationException
|
||||||
*/
|
*/
|
||||||
public function store(Request $request, UserSettings $userSettings)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'name' => ['required', 'string', 'max:30', 'min:4', 'alpha_num', 'unique:users'],
|
'name' => ['required', 'string', 'max:30', 'min:4', 'alpha_num', 'unique:users'],
|
||||||
|
@ -270,7 +255,7 @@ class UserController extends Controller
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Prevent the creation of new users via API if this is enabled.
|
// Prevent the creation of new users via API if this is enabled.
|
||||||
if (! $userSettings->creation_enabled) {
|
if (!config('SETTINGS::SYSTEM:CREATION_OF_NEW_USERS', 'true')) {
|
||||||
throw ValidationException::withMessages([
|
throw ValidationException::withMessages([
|
||||||
'error' => 'The creation of new users has been blocked by the system administrator.',
|
'error' => 'The creation of new users has been blocked by the system administrator.',
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
namespace App\Http\Controllers\Auth;
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Settings\GeneralSettings;
|
|
||||||
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
@ -32,13 +31,13 @@ class ForgotPasswordController extends Controller
|
||||||
$this->middleware('guest');
|
$this->middleware('guest');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function validateEmail(Request $request, GeneralSettings $general_settings)
|
protected function validateEmail(Request $request)
|
||||||
{
|
{
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'email' => ['required', 'string', 'email', 'max:255'],
|
'email' => ['required', 'string', 'email', 'max:255'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($general_settings->recaptcha_enabled) {
|
if (config('SETTINGS::RECAPTCHA:ENABLED') == 'true') {
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'g-recaptcha-response' => 'required|recaptcha',
|
'g-recaptcha-response' => 'required|recaptcha',
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -4,7 +4,6 @@ namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Providers\RouteServiceProvider;
|
use App\Providers\RouteServiceProvider;
|
||||||
use App\Settings\GeneralSettings;
|
|
||||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
@ -54,13 +53,13 @@ class LoginController extends Controller
|
||||||
return $field;
|
return $field;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function login(Request $request, GeneralSettings $general_settings)
|
public function login(Request $request)
|
||||||
{
|
{
|
||||||
$validationRules = [
|
$validationRules = [
|
||||||
$this->username() => 'required|string',
|
$this->username() => 'required|string',
|
||||||
'password' => 'required|string',
|
'password' => 'required|string',
|
||||||
];
|
];
|
||||||
if ($general_settings->recaptcha_enabled) {
|
if (config('SETTINGS::RECAPTCHA:ENABLED') == 'true') {
|
||||||
$validationRules['g-recaptcha-response'] = ['required', 'recaptcha'];
|
$validationRules['g-recaptcha-response'] = ['required', 'recaptcha'];
|
||||||
}
|
}
|
||||||
$request->validate($validationRules);
|
$request->validate($validationRules);
|
||||||
|
|
|
@ -2,18 +2,13 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers\Auth;
|
namespace App\Http\Controllers\Auth;
|
||||||
|
|
||||||
|
use App\Classes\Pterodactyl;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Notifications\ReferralNotification;
|
use App\Notifications\ReferralNotification;
|
||||||
use App\Providers\RouteServiceProvider;
|
use App\Providers\RouteServiceProvider;
|
||||||
use App\Traits\Referral;
|
use App\Traits\Referral;
|
||||||
use Carbon\Carbon;
|
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\Foundation\Auth\RegistersUsers;
|
||||||
use Illuminate\Support\Facades\App;
|
use Illuminate\Support\Facades\App;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
@ -22,28 +17,9 @@ use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
use Spatie\Permission\Models\Role;
|
|
||||||
|
|
||||||
class RegisterController extends Controller
|
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
|
| Register Controller
|
||||||
|
@ -69,18 +45,9 @@ class RegisterController extends Controller
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function __construct(PterodactylSettings $ptero_settings, GeneralSettings $general_settings, WebsiteSettings $website_settings, UserSettings $user_settings, ReferralSettings $referral_settings)
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->middleware('guest');
|
$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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -96,14 +63,14 @@ class RegisterController extends Controller
|
||||||
'email' => ['required', 'string', 'email', 'max:64', 'unique:users'],
|
'email' => ['required', 'string', 'email', 'max:64', 'unique:users'],
|
||||||
'password' => ['required', 'string', 'min:8', 'confirmed'],
|
'password' => ['required', 'string', 'min:8', 'confirmed'],
|
||||||
];
|
];
|
||||||
if ($this->recaptcha_enabled) {
|
if (config('SETTINGS::RECAPTCHA:ENABLED') == 'true') {
|
||||||
$validationRules['g-recaptcha-response'] = ['required', 'recaptcha'];
|
$validationRules['g-recaptcha-response'] = ['required', 'recaptcha'];
|
||||||
}
|
}
|
||||||
if ($this->website_show_tos) {
|
if (config('SETTINGS::SYSTEM:SHOW_TOS') == 'true') {
|
||||||
$validationRules['terms'] = ['required'];
|
$validationRules['terms'] = ['required'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->register_ip_check) {
|
if (config('SETTINGS::SYSTEM:REGISTER_IP_CHECK', 'true') == 'true') {
|
||||||
|
|
||||||
//check if ip has already made an account
|
//check if ip has already made an account
|
||||||
$data['ip'] = session()->get('ip') ?? request()->ip();
|
$data['ip'] = session()->get('ip') ?? request()->ip();
|
||||||
|
@ -132,18 +99,15 @@ class RegisterController extends Controller
|
||||||
$user = User::create([
|
$user = User::create([
|
||||||
'name' => $data['name'],
|
'name' => $data['name'],
|
||||||
'email' => $data['email'],
|
'email' => $data['email'],
|
||||||
'credits' => $this->initial_credits,
|
'credits' => config('SETTINGS::USER:INITIAL_CREDITS', 150),
|
||||||
'server_limit' => $this->initial_server_limit,
|
'server_limit' => config('SETTINGS::USER:INITIAL_SERVER_LIMIT', 1),
|
||||||
'password' => Hash::make($data['password']),
|
'password' => Hash::make($data['password']),
|
||||||
'referral_code' => $this->createReferralCode(),
|
'referral_code' => $this->createReferralCode(),
|
||||||
'pterodactyl_id' => Str::uuid(),
|
|
||||||
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$user->syncRoles(Role::findByName('User'));
|
$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' => null,
|
|
||||||
'username' => $user->name,
|
'username' => $user->name,
|
||||||
'email' => $user->email,
|
'email' => $user->email,
|
||||||
'first_name' => $user->name,
|
'first_name' => $user->name,
|
||||||
|
@ -153,10 +117,6 @@ class RegisterController extends Controller
|
||||||
'language' => 'en',
|
'language' => 'en',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$user->update([
|
|
||||||
'pterodactyl_id' => $response->json()['attributes']['id'],
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($response->failed()) {
|
if ($response->failed()) {
|
||||||
$user->delete();
|
$user->delete();
|
||||||
Log::error('Pterodactyl Registration Error: ' . $response->json()['errors'][0]['detail']);
|
Log::error('Pterodactyl Registration Error: ' . $response->json()['errors'][0]['detail']);
|
||||||
|
@ -165,23 +125,24 @@ class RegisterController extends Controller
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete activity log for user creation where description = 'created' or 'deleted' and subject_id = user_id
|
$user->update([
|
||||||
DB::table('activity_log')->where('description', 'created')->orWhere('description', 'deleted')->where('subject_id', $user->id)->delete();
|
'pterodactyl_id' => $response->json()['attributes']['id'],
|
||||||
|
]);
|
||||||
|
|
||||||
//INCREMENT REFERRAL-USER CREDITS
|
//INCREMENT REFERRAL-USER CREDITS
|
||||||
if (!empty($data['referral_code'])) {
|
if (!empty($data['referral_code'])) {
|
||||||
$ref_code = $data['referral_code'];
|
$ref_code = $data['referral_code'];
|
||||||
$new_user = $user->id;
|
$new_user = $user->id;
|
||||||
if ($ref_user = User::query()->where('referral_code', '=', $ref_code)->first()) {
|
if ($ref_user = User::query()->where('referral_code', '=', $ref_code)->first()) {
|
||||||
if ($this->referral_mode === 'sign-up' || $this->referral_mode === 'both') {
|
if (config('SETTINGS::REFERRAL:MODE') == 'sign-up' || config('SETTINGS::REFERRAL:MODE') == 'both') {
|
||||||
$ref_user->increment('credits', $this->referral_reward);
|
$ref_user->increment('credits', config('SETTINGS::REFERRAL::REWARD'));
|
||||||
$ref_user->notify(new ReferralNotification($ref_user->id, $new_user));
|
$ref_user->notify(new ReferralNotification($ref_user->id, $new_user));
|
||||||
|
|
||||||
//LOGS REFERRALS IN THE ACTIVITY LOG
|
//LOGS REFERRALS IN THE ACTIVITY LOG
|
||||||
activity()
|
activity()
|
||||||
->performedOn($user)
|
->performedOn($user)
|
||||||
->causedBy($ref_user)
|
->causedBy($ref_user)
|
||||||
->log('gained ' . $this->referral_reward . ' ' . $this->credits_display_name . ' for sign-up-referral of ' . $user->name . ' (ID:' . $user->id . ')');
|
->log('gained ' . config('SETTINGS::REFERRAL::REWARD') . ' ' . config('SETTINGS::SYSTEM:CREDITS_DISPLAY_NAME') . ' for sign-up-referral of ' . $user->name . ' (ID:' . $user->id . ')');
|
||||||
}
|
}
|
||||||
//INSERT INTO USER_REFERRALS TABLE
|
//INSERT INTO USER_REFERRALS TABLE
|
||||||
DB::table('user_referrals')->insert([
|
DB::table('user_referrals')->insert([
|
||||||
|
|
|
@ -5,24 +5,22 @@ namespace App\Http\Controllers\Auth;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\DiscordUser;
|
use App\Models\DiscordUser;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Settings\DiscordSettings;
|
|
||||||
use App\Settings\UserSettings;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
use Laravel\Socialite\Facades\Socialite;
|
use Laravel\Socialite\Facades\Socialite;
|
||||||
|
|
||||||
class SocialiteController extends Controller
|
class SocialiteController extends Controller
|
||||||
{
|
{
|
||||||
public function redirect(DiscordSettings $discord_settings)
|
public function redirect()
|
||||||
{
|
{
|
||||||
$scopes = !empty($discord_settings->bot_token) && !empty($discord_settings->guild_id) ? ['guilds.join'] : [];
|
$scopes = ! empty(config('SETTINGS::DISCORD:BOT_TOKEN')) && ! empty(config('SETTINGS::DISCORD:GUILD_ID')) ? ['guilds.join'] : [];
|
||||||
|
|
||||||
return Socialite::driver('discord')
|
return Socialite::driver('discord')
|
||||||
->scopes($scopes)
|
->scopes($scopes)
|
||||||
->redirect();
|
->redirect();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function callback(DiscordSettings $discord_settings, UserSettings $user_settings)
|
public function callback()
|
||||||
{
|
{
|
||||||
if (Auth::guest()) {
|
if (Auth::guest()) {
|
||||||
return abort(500);
|
return abort(500);
|
||||||
|
@ -31,9 +29,9 @@ class SocialiteController extends Controller
|
||||||
/** @var User $user */
|
/** @var User $user */
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
$discord = Socialite::driver('discord')->user();
|
$discord = Socialite::driver('discord')->user();
|
||||||
$botToken = $discord_settings->bot_token;
|
$botToken = config('SETTINGS::DISCORD:BOT_TOKEN');
|
||||||
$guildId = $discord_settings->guild_id;
|
$guildId = config('SETTINGS::DISCORD:GUILD_ID');
|
||||||
$roleId = $discord_settings->role_id;
|
$roleId = config('SETTINGS::DISCORD:ROLE_ID');
|
||||||
|
|
||||||
//save / update discord_users
|
//save / update discord_users
|
||||||
|
|
||||||
|
@ -51,8 +49,8 @@ class SocialiteController extends Controller
|
||||||
DiscordUser::create(array_merge($discord->user, ['user_id' => Auth::user()->id]));
|
DiscordUser::create(array_merge($discord->user, ['user_id' => Auth::user()->id]));
|
||||||
|
|
||||||
//update user
|
//update user
|
||||||
Auth::user()->increment('credits', $user_settings->credits_reward_after_verify_discord);
|
Auth::user()->increment('credits', config('SETTINGS::USER:CREDITS_REWARD_AFTER_VERIFY_DISCORD'));
|
||||||
Auth::user()->increment('server_limit', $user_settings->server_limit_after_verify_discord);
|
Auth::user()->increment('server_limit', config('SETTINGS::USER:SERVER_LIMIT_REWARD_AFTER_VERIFY_DISCORD'));
|
||||||
Auth::user()->update(['discord_verified_at' => now()]);
|
Auth::user()->update(['discord_verified_at' => now()]);
|
||||||
} else {
|
} else {
|
||||||
$user->discordUser->update($discord->user);
|
$user->discordUser->update($discord->user);
|
||||||
|
|
|
@ -2,44 +2,12 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Models\User;
|
|
||||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||||
use Illuminate\Routing\Controller as BaseController;
|
use Illuminate\Routing\Controller as BaseController;
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
|
|
||||||
class Controller extends BaseController
|
class Controller extends BaseController
|
||||||
{
|
{
|
||||||
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
|
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
|
||||||
/**
|
|
||||||
* Check if user has permissions
|
|
||||||
* Abort 403 if the user doesn't have the required permission
|
|
||||||
*
|
|
||||||
* @param string $permission
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function checkPermission(string $permission)
|
|
||||||
{
|
|
||||||
/** @var User $user */
|
|
||||||
$user = Auth::user();
|
|
||||||
|
|
||||||
if (!$user->can($permission)) {
|
|
||||||
abort(403, __('User does not have the right permissions.'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if user has permissions
|
|
||||||
*
|
|
||||||
* @param string $permission
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function can(string $permission): bool
|
|
||||||
{
|
|
||||||
/** @var User $user */
|
|
||||||
$user = Auth::user();
|
|
||||||
|
|
||||||
return $user->can($permission);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,7 @@ namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Models\PartnerDiscount;
|
use App\Models\PartnerDiscount;
|
||||||
use App\Models\UsefulLink;
|
use App\Models\UsefulLink;
|
||||||
use App\Settings\GeneralSettings;
|
use Illuminate\Http\Request;
|
||||||
use App\Settings\WebsiteSettings;
|
|
||||||
use App\Settings\ReferralSettings;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Hash;
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
@ -34,7 +32,7 @@ class HomeController extends Controller
|
||||||
if (Storage::exists('callHome')) {
|
if (Storage::exists('callHome')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Http::asForm()->post('https://market.CtrlPanel.gg/callhome.php', [
|
Http::asForm()->post('https://market.ctrlpanel.gg/callhome.php', [
|
||||||
'id' => Hash::make(URL::current()),
|
'id' => Hash::make(URL::current()),
|
||||||
]);
|
]);
|
||||||
Storage::put('callHome', 'This is only used to count the installations of cpgg.');
|
Storage::put('callHome', 'This is only used to count the installations of cpgg.');
|
||||||
|
@ -91,7 +89,7 @@ class HomeController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Show the application dashboard. */
|
/** Show the application dashboard. */
|
||||||
public function index(GeneralSettings $general_settings, WebsiteSettings $website_settings, ReferralSettings $referral_settings)
|
public function index(Request $request)
|
||||||
{
|
{
|
||||||
$usage = Auth::user()->creditUsage();
|
$usage = Auth::user()->creditUsage();
|
||||||
$credits = Auth::user()->Credits();
|
$credits = Auth::user()->Credits();
|
||||||
|
@ -101,7 +99,7 @@ class HomeController extends Controller
|
||||||
|
|
||||||
/** Build our Time-Left-Box */
|
/** Build our Time-Left-Box */
|
||||||
if ($credits > 0.01 and $usage > 0) {
|
if ($credits > 0.01 and $usage > 0) {
|
||||||
$daysLeft = number_format($credits / ($usage / 30), 2, '.', '');
|
$daysLeft = number_format(($credits * 30) / $usage, 2, '.', '');
|
||||||
$hoursLeft = number_format($credits / ($usage / 30 / 24), 2, '.', '');
|
$hoursLeft = number_format($credits / ($usage / 30 / 24), 2, '.', '');
|
||||||
|
|
||||||
$bg = $this->getTimeLeftBoxBackground($daysLeft);
|
$bg = $this->getTimeLeftBoxBackground($daysLeft);
|
||||||
|
@ -122,9 +120,6 @@ class HomeController extends Controller
|
||||||
'numberOfReferrals' => DB::table('user_referrals')->where('referral_id', '=', Auth::user()->id)->count(),
|
'numberOfReferrals' => DB::table('user_referrals')->where('referral_id', '=', Auth::user()->id)->count(),
|
||||||
'partnerDiscount' => PartnerDiscount::where('user_id', Auth::user()->id)->first(),
|
'partnerDiscount' => PartnerDiscount::where('user_id', Auth::user()->id)->first(),
|
||||||
'myDiscount' => PartnerDiscount::getDiscount(),
|
'myDiscount' => PartnerDiscount::getDiscount(),
|
||||||
'general_settings' => $general_settings,
|
|
||||||
'website_settings' => $website_settings,
|
|
||||||
'referral_settings' => $referral_settings
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
namespace App\Http\Controllers\Moderation;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\Ticket;
|
use App\Models\Ticket;
|
||||||
|
@ -9,20 +9,15 @@ use Illuminate\Http\Request;
|
||||||
|
|
||||||
class TicketCategoryController extends Controller
|
class TicketCategoryController extends Controller
|
||||||
{
|
{
|
||||||
const READ_PERMISSION = "admin.tickets.category.read";
|
|
||||||
const WRITE_PERMISSION = "admin.tickets.category.write";
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* Display a listing of the resource.
|
* Display a listing of the resource.
|
||||||
*
|
*
|
||||||
* @return \Illuminate\Http\Response
|
* @return \Illuminate\Http\Response
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::READ_PERMISSION);
|
|
||||||
|
|
||||||
$categories = TicketCategory::all();
|
$categories = TicketCategory::all();
|
||||||
return view('admin.ticket.category')->with("categories",$categories);
|
return view('moderator.ticket.category')->with("categories",$categories);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,8 +28,6 @@ class TicketCategoryController extends Controller
|
||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
|
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'name' => 'required|string|max:191',
|
'name' => 'required|string|max:191',
|
||||||
]);
|
]);
|
||||||
|
@ -42,7 +35,7 @@ class TicketCategoryController extends Controller
|
||||||
TicketCategory::create($request->all());
|
TicketCategory::create($request->all());
|
||||||
|
|
||||||
|
|
||||||
return redirect(route("admin.ticket.category.index"))->with("success",__("Category created"));
|
return redirect(route("moderator.ticket.category.index"))->with("success",__("Category created"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -53,8 +46,6 @@ class TicketCategoryController extends Controller
|
||||||
*/
|
*/
|
||||||
public function update(Request $request)
|
public function update(Request $request)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
|
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'category' => 'required|int',
|
'category' => 'required|int',
|
||||||
'name' => 'required|string|max:191',
|
'name' => 'required|string|max:191',
|
||||||
|
@ -77,8 +68,6 @@ class TicketCategoryController extends Controller
|
||||||
*/
|
*/
|
||||||
public function destroy($id)
|
public function destroy($id)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
|
|
||||||
$category = TicketCategory::where("id",$id)->firstOrFail();
|
$category = TicketCategory::where("id",$id)->firstOrFail();
|
||||||
|
|
||||||
if($category->id == 5 ){ //cannot delete "other" category
|
if($category->id == 5 ){ //cannot delete "other" category
|
||||||
|
@ -95,7 +84,7 @@ class TicketCategoryController extends Controller
|
||||||
$category->delete();
|
$category->delete();
|
||||||
|
|
||||||
return redirect()
|
return redirect()
|
||||||
->route('admin.ticket.category.index')
|
->route('moderator.ticket.category.index')
|
||||||
->with('success', __('Category removed'));
|
->with('success', __('Category removed'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +101,7 @@ class TicketCategoryController extends Controller
|
||||||
})
|
})
|
||||||
->addColumn('actions', function (TicketCategory $category) {
|
->addColumn('actions', function (TicketCategory $category) {
|
||||||
return '
|
return '
|
||||||
<form class="d-inline" onsubmit="return submitResult();" method="post" action="'.route('admin.ticket.category.destroy', $category->id).'">
|
<form class="d-inline" onsubmit="return submitResult();" method="post" action="'.route('moderator.ticket.category.destroy', $category->id).'">
|
||||||
'.csrf_field().'
|
'.csrf_field().'
|
||||||
'.method_field('DELETE').'
|
'.method_field('DELETE').'
|
||||||
<button data-content="'.__('Delete').'" data-toggle="popover" data-trigger="hover" data-placement="top" class="btn btn-sm btn-danger mr-1"><i class="fas fa-trash"></i></button>
|
<button data-content="'.__('Delete').'" data-toggle="popover" data-trigger="hover" data-placement="top" class="btn btn-sm btn-danger mr-1"><i class="fas fa-trash"></i></button>
|
|
@ -1,9 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
namespace App\Http\Controllers\Moderation;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Controllers\Moderation\Exception;
|
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Models\Ticket;
|
use App\Models\Ticket;
|
||||||
use App\Models\TicketBlacklist;
|
use App\Models\TicketBlacklist;
|
||||||
|
@ -11,32 +10,21 @@ use App\Models\TicketCategory;
|
||||||
use App\Models\TicketComment;
|
use App\Models\TicketComment;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Notifications\Ticket\User\ReplyNotification;
|
use App\Notifications\Ticket\User\ReplyNotification;
|
||||||
use App\Settings\LocaleSettings;
|
|
||||||
use App\Settings\PterodactylSettings;
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
class TicketsController extends Controller
|
class TicketsController extends Controller
|
||||||
{
|
{
|
||||||
const READ_PERMISSION = "admin.tickets.read";
|
public function index()
|
||||||
const WRITE_PERMISSION = "admin.tickets.write";
|
|
||||||
|
|
||||||
const BLACKLIST_READ_PERMISSION ='admin.ticket_blacklist.read';
|
|
||||||
const BLACKLIST_WRITE_PERMISSION ='admin.ticket_blacklist.write';
|
|
||||||
public function index(LocaleSettings $locale_settings)
|
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::READ_PERMISSION);
|
$tickets = Ticket::orderBy('id', 'desc')->paginate(10);
|
||||||
|
$ticketcategories = TicketCategory::all();
|
||||||
|
|
||||||
return view('admin.ticket.index', [
|
return view('moderator.ticket.index', compact('tickets', 'ticketcategories'));
|
||||||
'tickets' => Ticket::orderBy('id', 'desc')->paginate(10),
|
|
||||||
'ticketcategories' => TicketCategory::all(),
|
|
||||||
'locale_datatables' => $locale_settings->datatables
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function show($ticket_id, PterodactylSettings $ptero_settings)
|
public function show($ticket_id)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::READ_PERMISSION);
|
|
||||||
try {
|
try {
|
||||||
$ticket = Ticket::where('ticket_id', $ticket_id)->firstOrFail();
|
$ticket = Ticket::where('ticket_id', $ticket_id)->firstOrFail();
|
||||||
} catch (Exception $e)
|
} catch (Exception $e)
|
||||||
|
@ -46,14 +34,12 @@ class TicketsController extends Controller
|
||||||
$ticketcomments = $ticket->ticketcomments;
|
$ticketcomments = $ticket->ticketcomments;
|
||||||
$ticketcategory = $ticket->ticketcategory;
|
$ticketcategory = $ticket->ticketcategory;
|
||||||
$server = Server::where('id', $ticket->server)->first();
|
$server = Server::where('id', $ticket->server)->first();
|
||||||
$pterodactyl_url = $ptero_settings->panel_url;
|
|
||||||
|
|
||||||
return view('admin.ticket.show', compact('ticket', 'ticketcategory', 'ticketcomments', 'server', 'pterodactyl_url'));
|
return view('moderator.ticket.show', compact('ticket', 'ticketcategory', 'ticketcomments', 'server'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function changeStatus($ticket_id)
|
public function changeStatus($ticket_id)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
try {
|
try {
|
||||||
$ticket = Ticket::where('ticket_id', $ticket_id)->firstOrFail();
|
$ticket = Ticket::where('ticket_id', $ticket_id)->firstOrFail();
|
||||||
} catch(Exception $e)
|
} catch(Exception $e)
|
||||||
|
@ -75,7 +61,6 @@ class TicketsController extends Controller
|
||||||
|
|
||||||
public function delete($ticket_id)
|
public function delete($ticket_id)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
try {
|
try {
|
||||||
$ticket = Ticket::where('ticket_id', $ticket_id)->firstOrFail();
|
$ticket = Ticket::where('ticket_id', $ticket_id)->firstOrFail();
|
||||||
} catch (Exception $e)
|
} catch (Exception $e)
|
||||||
|
@ -91,9 +76,6 @@ class TicketsController extends Controller
|
||||||
|
|
||||||
public function reply(Request $request)
|
public function reply(Request $request)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
|
|
||||||
|
|
||||||
$this->validate($request, ['ticketcomment' => 'required']);
|
$this->validate($request, ['ticketcomment' => 'required']);
|
||||||
try {
|
try {
|
||||||
$ticket = Ticket::where('id', $request->input('ticket_id'))->firstOrFail();
|
$ticket = Ticket::where('id', $request->input('ticket_id'))->firstOrFail();
|
||||||
|
@ -121,15 +103,14 @@ class TicketsController extends Controller
|
||||||
|
|
||||||
public function dataTable()
|
public function dataTable()
|
||||||
{
|
{
|
||||||
$query = Ticket::leftJoin('ticket_categories', 'tickets.ticketcategory_id', '=', 'ticket_categories.id')
|
$query = Ticket::query();
|
||||||
->select(['tickets.*', 'ticket_categories.name as category_name']);
|
|
||||||
|
|
||||||
return datatables($query)
|
return datatables($query)
|
||||||
->addColumn('category', function (Ticket $ticket) {
|
->addColumn('category', function (Ticket $tickets) {
|
||||||
return $ticket->category_name;
|
return $tickets->ticketcategory->name;
|
||||||
})
|
})
|
||||||
->editColumn('title', function (Ticket $tickets) {
|
->editColumn('title', function (Ticket $tickets) {
|
||||||
return '<a class="text-info" href="'.route('admin.ticket.show', ['ticket_id' => $tickets->ticket_id]).'">'.'#'.$tickets->ticket_id.' - '.htmlspecialchars($tickets->title).'</a>';
|
return '<a class="text-info" href="'.route('moderator.ticket.show', ['ticket_id' => $tickets->ticket_id]).'">'.'#'.$tickets->ticket_id.' - '.htmlspecialchars($tickets->title).'</a>';
|
||||||
})
|
})
|
||||||
->editColumn('user_id', function (Ticket $tickets) {
|
->editColumn('user_id', function (Ticket $tickets) {
|
||||||
return '<a href="'.route('admin.users.show', $tickets->user->id).'">'.$tickets->user->name.'</a>';
|
return '<a href="'.route('admin.users.show', $tickets->user->id).'">'.$tickets->user->name.'</a>';
|
||||||
|
@ -140,16 +121,16 @@ class TicketsController extends Controller
|
||||||
$statusButtonText = ($tickets->status == "Closed") ? __('Reopen') : __('Close');
|
$statusButtonText = ($tickets->status == "Closed") ? __('Reopen') : __('Close');
|
||||||
|
|
||||||
return '
|
return '
|
||||||
<a data-content="'.__('View').'" data-toggle="popover" data-trigger="hover" data-placement="top" href="'.route('admin.ticket.show', ['ticket_id' => $tickets->ticket_id]).'" class="mr-1 text-white btn btn-sm btn-info"><i class="fas fa-eye"></i></a>
|
<a data-content="'.__('View').'" data-toggle="popover" data-trigger="hover" data-placement="top" href="'.route('moderator.ticket.show', ['ticket_id' => $tickets->ticket_id]).'" class="btn btn-sm text-white btn-info mr-1"><i class="fas fa-eye"></i></a>
|
||||||
<form class="d-inline" method="post" action="'.route('admin.ticket.changeStatus', ['ticket_id' => $tickets->ticket_id]).'">
|
<form class="d-inline" method="post" action="'.route('moderator.ticket.changeStatus', ['ticket_id' => $tickets->ticket_id]).'">
|
||||||
'.csrf_field().'
|
'.csrf_field().'
|
||||||
'.method_field('POST').'
|
'.method_field('POST').'
|
||||||
<button data-content="'.__($statusButtonText).'" data-toggle="popover" data-trigger="hover" data-placement="top" class="text-white btn btn-sm '.$statusButtonColor.' mr-1"><i class="fas '.$statusButtonIcon.'"></i></button>
|
<button data-content="'.__($statusButtonText).'" data-toggle="popover" data-trigger="hover" data-placement="top" class="btn btn-sm text-white '.$statusButtonColor.' mr-1"><i class="fas '.$statusButtonIcon.'"></i></button>
|
||||||
</form>
|
</form>
|
||||||
<form class="d-inline" method="post" action="'.route('admin.ticket.delete', ['ticket_id' => $tickets->ticket_id]).'">
|
<form class="d-inline" method="post" action="'.route('moderator.ticket.delete', ['ticket_id' => $tickets->ticket_id]).'">
|
||||||
'.csrf_field().'
|
'.csrf_field().'
|
||||||
'.method_field('POST').'
|
'.method_field('POST').'
|
||||||
<button data-content="'.__('Delete').'" data-toggle="popover" data-trigger="hover" data-placement="top" class="mr-1 text-white btn btn-sm btn-danger"><i class="fas fa-trash"></i></button>
|
<button data-content="'.__('Delete').'" data-toggle="popover" data-trigger="hover" data-placement="top" class="btn btn-sm text-white btn-danger mr-1"><i class="fas fa-trash"></i></button>
|
||||||
</form>
|
</form>
|
||||||
';
|
';
|
||||||
})
|
})
|
||||||
|
@ -179,24 +160,17 @@ class TicketsController extends Controller
|
||||||
return ['display' => $tickets->updated_at ? $tickets->updated_at->diffForHumans() : '',
|
return ['display' => $tickets->updated_at ? $tickets->updated_at->diffForHumans() : '',
|
||||||
'raw' => $tickets->updated_at ? strtotime($tickets->updated_at) : ''];
|
'raw' => $tickets->updated_at ? strtotime($tickets->updated_at) : ''];
|
||||||
})
|
})
|
||||||
->orderColumn('category', 'category_name $1')
|
->rawColumns(['category', 'title', 'user_id', 'status', 'priority', 'updated_at', 'actions'])
|
||||||
->rawColumns(['title', 'user_id', 'status', 'priority', 'updated_at', 'actions'])
|
|
||||||
->make(true);
|
->make(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function blacklist(LocaleSettings $locale_settings)
|
public function blacklist()
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::BLACKLIST_READ_PERMISSION);
|
return view('moderator.ticket.blacklist');
|
||||||
|
|
||||||
return view('admin.ticket.blacklist', [
|
|
||||||
'locale_datatables' => $locale_settings->datatables
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function blacklistAdd(Request $request)
|
public function blacklistAdd(Request $request)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::BLACKLIST_WRITE_PERMISSION);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$user = User::where('id', $request->user_id)->firstOrFail();
|
$user = User::where('id', $request->user_id)->firstOrFail();
|
||||||
$check = TicketBlacklist::where('user_id', $user->id)->first();
|
$check = TicketBlacklist::where('user_id', $user->id)->first();
|
||||||
|
@ -222,8 +196,6 @@ class TicketsController extends Controller
|
||||||
|
|
||||||
public function blacklistDelete($id)
|
public function blacklistDelete($id)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::BLACKLIST_WRITE_PERMISSION);
|
|
||||||
|
|
||||||
$blacklist = TicketBlacklist::where('id', $id)->first();
|
$blacklist = TicketBlacklist::where('id', $id)->first();
|
||||||
$blacklist->delete();
|
$blacklist->delete();
|
||||||
|
|
||||||
|
@ -232,8 +204,6 @@ class TicketsController extends Controller
|
||||||
|
|
||||||
public function blacklistChange($id)
|
public function blacklistChange($id)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::BLACKLIST_WRITE_PERMISSION);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$blacklist = TicketBlacklist::where('id', $id)->first();
|
$blacklist = TicketBlacklist::where('id', $id)->first();
|
||||||
}
|
}
|
||||||
|
@ -278,15 +248,15 @@ class TicketsController extends Controller
|
||||||
})
|
})
|
||||||
->addColumn('actions', function (TicketBlacklist $blacklist) {
|
->addColumn('actions', function (TicketBlacklist $blacklist) {
|
||||||
return '
|
return '
|
||||||
<form class="d-inline" method="post" action="'.route('admin.ticket.blacklist.change', ['id' => $blacklist->id]).'">
|
<form class="d-inline" method="post" action="'.route('moderator.ticket.blacklist.change', ['id' => $blacklist->id]).'">
|
||||||
'.csrf_field().'
|
'.csrf_field().'
|
||||||
'.method_field('POST').'
|
'.method_field('POST').'
|
||||||
<button data-content="'.__('Change Status').'" data-toggle="popover" data-trigger="hover" data-placement="top" class="mr-1 text-white btn btn-sm btn-warning"><i class="fas fa-sync-alt"></i></button>
|
<button data-content="'.__('Change Status').'" data-toggle="popover" data-trigger="hover" data-placement="top" class="btn btn-sm text-white btn-warning mr-1"><i class="fas fa-sync-alt"></i></button>
|
||||||
</form>
|
</form>
|
||||||
<form class="d-inline" method="post" action="'.route('admin.ticket.blacklist.delete', ['id' => $blacklist->id]).'">
|
<form class="d-inline" method="post" action="'.route('moderator.ticket.blacklist.delete', ['id' => $blacklist->id]).'">
|
||||||
'.csrf_field().'
|
'.csrf_field().'
|
||||||
'.method_field('POST').'
|
'.method_field('POST').'
|
||||||
<button data-content="'.__('Delete').'" data-toggle="popover" data-trigger="hover" data-placement="top" class="mr-1 text-white btn btn-sm btn-danger"><i class="fas fa-trash"></i></button>
|
<button data-content="'.__('Delete').'" data-toggle="popover" data-trigger="hover" data-placement="top" class="btn btn-sm text-white btn-danger mr-1"><i class="fas fa-trash"></i></button>
|
||||||
</form>
|
</form>
|
||||||
';
|
';
|
||||||
})
|
})
|
|
@ -2,12 +2,11 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Classes\PterodactylClient;
|
use App\Classes\Pterodactyl;
|
||||||
use App\Models\Pterodactyl\Egg;
|
use App\Models\Egg;
|
||||||
use App\Models\Pterodactyl\Location;
|
use App\Models\Location;
|
||||||
use App\Models\Pterodactyl\Node;
|
use App\Models\Node;
|
||||||
use App\Models\Product;
|
use App\Models\Product;
|
||||||
use App\Settings\PterodactylSettings;
|
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
@ -15,13 +14,6 @@ use Illuminate\Support\Collection;
|
||||||
|
|
||||||
class ProductController extends Controller
|
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
|
* @description get product locations based on selected egg
|
||||||
*
|
*
|
||||||
|
@ -68,7 +60,7 @@ class ProductController extends Controller
|
||||||
{
|
{
|
||||||
$nodes = $this->getNodesBasedOnEgg($request, $egg);
|
$nodes = $this->getNodesBasedOnEgg($request, $egg);
|
||||||
foreach ($nodes as $key => $node) {
|
foreach ($nodes as $key => $node) {
|
||||||
$pteroNode = $this->pterodactyl->getNode($node->id);
|
$pteroNode = 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)) {
|
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);
|
$nodes->forget($key);
|
||||||
}
|
}
|
||||||
|
@ -117,7 +109,7 @@ class ProductController extends Controller
|
||||||
})
|
})
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
$pteroNode = $this->pterodactyl->getNode($node->id);
|
$pteroNode = Pterodactyl::getNode($node->id);
|
||||||
foreach ($products as $key => $product) {
|
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']) {
|
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;
|
$product->doesNotFit = true;
|
||||||
|
|
|
@ -2,12 +2,8 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Classes\Pterodactyl;
|
||||||
use App\Models\User;
|
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\RedirectResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
@ -16,32 +12,37 @@ use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
class ProfileController extends Controller
|
class ProfileController extends Controller
|
||||||
{
|
{
|
||||||
private $pterodactyl;
|
|
||||||
|
|
||||||
public function __construct(PterodactylSettings $ptero_settings)
|
|
||||||
{
|
|
||||||
$this->pterodactyl = new PterodactylClient($ptero_settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Display a listing of the resource. */
|
/** Display a listing of the resource. */
|
||||||
public function index(UserSettings $user_settings, DiscordSettings $discord_settings, ReferralSettings $referral_settings)
|
public function index()
|
||||||
{
|
{
|
||||||
|
switch (Auth::user()->role) {
|
||||||
|
case 'admin':
|
||||||
|
$badgeColor = 'badge-danger';
|
||||||
|
break;
|
||||||
|
case 'mod':
|
||||||
|
$badgeColor = 'badge-info';
|
||||||
|
break;
|
||||||
|
case 'client':
|
||||||
|
$badgeColor = 'badge-success';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$badgeColor = 'badge-secondary';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return view('profile.index')->with([
|
return view('profile.index')->with([
|
||||||
'user' => Auth::user(),
|
'user' => Auth::user(),
|
||||||
'credits_reward_after_verify_discord' => $user_settings->credits_reward_after_verify_discord,
|
'credits_reward_after_verify_discord' => config('SETTINGS::USER:CREDITS_REWARD_AFTER_VERIFY_DISCORD'),
|
||||||
'force_email_verification' => $user_settings->force_email_verification,
|
'force_email_verification' => config('SETTINGS::USER:FORCE_EMAIL_VERIFICATION'),
|
||||||
'force_discord_verification' => $user_settings->force_discord_verification,
|
'force_discord_verification' => config('SETTINGS::USER:FORCE_DISCORD_VERIFICATION'),
|
||||||
'discord_client_id' => $discord_settings->client_id,
|
'badgeColor' => $badgeColor,
|
||||||
'discord_client_secret' => $discord_settings->client_secret,
|
|
||||||
'referral_enabled' => $referral_settings->enabled
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function selfDestroyUser()
|
public function selfDestroyUser()
|
||||||
{
|
{
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
if ($user->hasRole("Admin")) return back()->with("error", "You cannot delete yourself as an admin!");
|
if ($user->role == "admin") return back()->with("error", "You cannot delete yourself as an admin!");
|
||||||
|
|
||||||
$user->delete();
|
$user->delete();
|
||||||
|
|
||||||
|
@ -80,7 +81,7 @@ class ProfileController extends Controller
|
||||||
|
|
||||||
//Update Users Password on Pterodactyl
|
//Update Users Password on Pterodactyl
|
||||||
//Username,Mail,First and Lastname are required aswell
|
//Username,Mail,First and Lastname are required aswell
|
||||||
$response = $this->pterodactyl->application->patch('/application/users/' . $user->pterodactyl_id, [
|
$response = Pterodactyl::client()->patch('/application/users/'.$user->pterodactyl_id, [
|
||||||
'password' => $request->input('new_password'),
|
'password' => $request->input('new_password'),
|
||||||
'username' => $request->input('name'),
|
'username' => $request->input('name'),
|
||||||
'first_name' => $request->input('name'),
|
'first_name' => $request->input('name'),
|
||||||
|
@ -124,7 +125,7 @@ class ProfileController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
//update name and email on Pterodactyl
|
//update name and email on Pterodactyl
|
||||||
$response = $this->pterodactyl->application->patch('/application/users/' . $user->pterodactyl_id, [
|
$response = Pterodactyl::client()->patch('/application/users/'.$user->pterodactyl_id, [
|
||||||
'username' => $request->input('name'),
|
'username' => $request->input('name'),
|
||||||
'first_name' => $request->input('name'),
|
'first_name' => $request->input('name'),
|
||||||
'last_name' => $request->input('name'),
|
'last_name' => $request->input('name'),
|
||||||
|
|
|
@ -2,19 +2,14 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Models\Pterodactyl\Egg;
|
use App\Classes\Pterodactyl;
|
||||||
use App\Models\Pterodactyl\Location;
|
use App\Models\Egg;
|
||||||
use App\Models\Pterodactyl\Nest;
|
use App\Models\Location;
|
||||||
use App\Models\Pterodactyl\Node;
|
use App\Models\Nest;
|
||||||
|
use App\Models\Node;
|
||||||
use App\Models\Product;
|
use App\Models\Product;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Notifications\ServerCreationError;
|
use App\Notifications\ServerCreationError;
|
||||||
use Carbon\Carbon;
|
|
||||||
use App\Settings\UserSettings;
|
|
||||||
use App\Settings\ServerSettings;
|
|
||||||
use App\Settings\PterodactylSettings;
|
|
||||||
use App\Classes\PterodactylClient;
|
|
||||||
use App\Settings\GeneralSettings;
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Http\Client\Response;
|
use Illuminate\Http\Client\Response;
|
||||||
|
@ -25,18 +20,8 @@ use Illuminate\Support\Facades\Request as FacadesRequest;
|
||||||
|
|
||||||
class ServerController extends Controller
|
class ServerController extends Controller
|
||||||
{
|
{
|
||||||
const CREATE_PERMISSION = 'user.server.create';
|
|
||||||
const UPGRADE_PERMISSION = 'user.server.upgrade';
|
|
||||||
|
|
||||||
private $pterodactyl;
|
|
||||||
|
|
||||||
public function __construct(PterodactylSettings $ptero_settings)
|
|
||||||
{
|
|
||||||
$this->pterodactyl = new PterodactylClient($ptero_settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Display a listing of the resource. */
|
/** Display a listing of the resource. */
|
||||||
public function index(GeneralSettings $general_settings, PterodactylSettings $ptero_settings)
|
public function index()
|
||||||
{
|
{
|
||||||
$servers = Auth::user()->servers;
|
$servers = Auth::user()->servers;
|
||||||
|
|
||||||
|
@ -44,7 +29,7 @@ class ServerController extends Controller
|
||||||
foreach ($servers as $server) {
|
foreach ($servers as $server) {
|
||||||
|
|
||||||
//Get server infos from ptero
|
//Get server infos from ptero
|
||||||
$serverAttributes = $this->pterodactyl->getServerAttributes($server->pterodactyl_id);
|
$serverAttributes = Pterodactyl::getServerAttributes($server->pterodactyl_id, true);
|
||||||
if (! $serverAttributes) {
|
if (! $serverAttributes) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -76,21 +61,14 @@ class ServerController extends Controller
|
||||||
|
|
||||||
return view('servers.index')->with([
|
return view('servers.index')->with([
|
||||||
'servers' => $servers,
|
'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. */
|
/** Show the form for creating a new resource. */
|
||||||
public function create(UserSettings $user_settings, ServerSettings $server_settings, GeneralSettings $general_settings)
|
public function create()
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::CREATE_PERMISSION);
|
if (! is_null($this->validateConfigurationRules())) {
|
||||||
|
return $this->validateConfigurationRules();
|
||||||
$validate_configuration = $this->validateConfigurationRules($user_settings, $server_settings, $general_settings);
|
|
||||||
|
|
||||||
if (!is_null($validate_configuration)) {
|
|
||||||
return $validate_configuration;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$productCount = Product::query()->where('disabled', '=', false)->count();
|
$productCount = Product::query()->where('disabled', '=', false)->count();
|
||||||
|
@ -120,16 +98,13 @@ class ServerController extends Controller
|
||||||
'locations' => $locations,
|
'locations' => $locations,
|
||||||
'eggs' => $eggs,
|
'eggs' => $eggs,
|
||||||
'user' => Auth::user(),
|
'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
|
* @return null|RedirectResponse
|
||||||
*/
|
*/
|
||||||
private function validateConfigurationRules(UserSettings $user_settings, ServerSettings $server_settings, GeneralSettings $generalSettings)
|
private function validateConfigurationRules()
|
||||||
{
|
{
|
||||||
//limit validation
|
//limit validation
|
||||||
if (Auth::user()->servers()->count() >= Auth::user()->server_limit) {
|
if (Auth::user()->servers()->count() >= Auth::user()->server_limit) {
|
||||||
|
@ -145,31 +120,35 @@ class ServerController extends Controller
|
||||||
$nodeName = $node->name;
|
$nodeName = $node->name;
|
||||||
|
|
||||||
// Check if node has enough memory and disk space
|
// Check if node has enough memory and disk space
|
||||||
$checkResponse = $this->pterodactyl->checkNodeResources($node, $product->memory, $product->disk);
|
$checkResponse = Pterodactyl::checkNodeResources($node, $product->memory, $product->disk);
|
||||||
if ($checkResponse == false) {
|
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."));
|
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
|
// Min. Credits
|
||||||
if (Auth::user()->credits < ($product->minimum_credits == -1
|
if (
|
||||||
? $user_settings->min_credits_to_make_server
|
Auth::user()->credits <
|
||||||
: $product->minimum_credits)) {
|
($product->minimum_credits == -1
|
||||||
return redirect()->route('servers.index')->with('error', 'You do not have the required amount of ' . $generalSettings->credits_display_name . ' to use this product!');
|
? config('SETTINGS::USER:MINIMUM_REQUIRED_CREDITS_TO_MAKE_SERVER', 50)
|
||||||
|
: $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
|
//Required Verification for creating an server
|
||||||
if ($user_settings->force_email_verification && !Auth::user()->hasVerifiedEmail()) {
|
if (config('SETTINGS::USER:FORCE_EMAIL_VERIFICATION', 'false') === 'true' && ! Auth::user()->hasVerifiedEmail()) {
|
||||||
return redirect()->route('profile.index')->with('error', __('You are required to verify your email address before you can create a server.'));
|
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
|
//Required Verification for creating an server
|
||||||
if (!$server_settings->creation_enabled && Auth::user()->cannot("admin.servers.bypass_creation_enabled")) {
|
|
||||||
|
if (! config('SETTINGS::SYSTEM:CREATION_OF_NEW_SERVERS', 'true') && Auth::user()->role != 'admin') {
|
||||||
return redirect()->route('servers.index')->with('error', __('The system administrator has blocked the creation of new servers.'));
|
return redirect()->route('servers.index')->with('error', __('The system administrator has blocked the creation of new servers.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
//Required Verification for creating an server
|
//Required Verification for creating an server
|
||||||
if ($user_settings->force_discord_verification && !Auth::user()->discordUser) {
|
if (config('SETTINGS::USER:FORCE_DISCORD_VERIFICATION', 'false') === 'true' && ! Auth::user()->discordUser) {
|
||||||
return redirect()->route('profile.index')->with('error', __('You are required to link your discord account before you can create a server.'));
|
return redirect()->route('profile.index')->with('error', __('You are required to link your discord account before you can create a server.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,15 +156,13 @@ class ServerController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Store a newly created resource in storage. */
|
/** Store a newly created resource in storage. */
|
||||||
public function store(Request $request, UserSettings $user_settings, ServerSettings $server_settings, GeneralSettings $generalSettings)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
/** @var Node $node */
|
/** @var Node $node */
|
||||||
/** @var Egg $egg */
|
/** @var Egg $egg */
|
||||||
/** @var Product $product */
|
/** @var Product $product */
|
||||||
$validate_configuration = $this->validateConfigurationRules($user_settings, $server_settings, $generalSettings);
|
if (! is_null($this->validateConfigurationRules())) {
|
||||||
|
return $this->validateConfigurationRules();
|
||||||
if (!is_null($validate_configuration)) {
|
|
||||||
return $validate_configuration;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$request->validate([
|
$request->validate([
|
||||||
|
@ -203,17 +180,16 @@ class ServerController extends Controller
|
||||||
$server = $request->user()->servers()->create([
|
$server = $request->user()->servers()->create([
|
||||||
'name' => $request->input('name'),
|
'name' => $request->input('name'),
|
||||||
'product_id' => $request->input('product'),
|
'product_id' => $request->input('product'),
|
||||||
'last_billed' => Carbon::now()->toDateTimeString(),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
//get free allocation ID
|
//get free allocation ID
|
||||||
$allocationId = $this->pterodactyl->getFreeAllocationId($node);
|
$allocationId = Pterodactyl::getFreeAllocationId($node);
|
||||||
if (! $allocationId) {
|
if (! $allocationId) {
|
||||||
return $this->noAllocationsError($server);
|
return $this->noAllocationsError($server);
|
||||||
}
|
}
|
||||||
|
|
||||||
//create server on pterodactyl
|
//create server on pterodactyl
|
||||||
$response = $this->pterodactyl->createServer($server, $egg, $allocationId);
|
$response = Pterodactyl::createServer($server, $egg, $allocationId);
|
||||||
if ($response->failed()) {
|
if ($response->failed()) {
|
||||||
return $this->serverCreationFailed($response, $server);
|
return $this->serverCreationFailed($response, $server);
|
||||||
}
|
}
|
||||||
|
@ -225,8 +201,11 @@ class ServerController extends Controller
|
||||||
'identifier' => $serverAttributes['identifier'],
|
'identifier' => $serverAttributes['identifier'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Charge first billing cycle
|
if (config('SETTINGS::SYSTEM:SERVER_CREATE_CHARGE_FIRST_HOUR', 'true') == 'true') {
|
||||||
$request->user()->decrement('credits', $server->product->price);
|
if ($request->user()->credits >= $server->product->getHourlyPrice()) {
|
||||||
|
$request->user()->decrement('credits', $server->product->getHourlyPrice());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return redirect()->route('servers.index')->with('success', __('Server created'));
|
return redirect()->route('servers.index')->with('success', __('Server created'));
|
||||||
}
|
}
|
||||||
|
@ -255,6 +234,8 @@ class ServerController extends Controller
|
||||||
*/
|
*/
|
||||||
private function serverCreationFailed(Response $response, Server $server)
|
private function serverCreationFailed(Response $response, Server $server)
|
||||||
{
|
{
|
||||||
|
$server->delete();
|
||||||
|
|
||||||
return redirect()->route('servers.index')->with('error', json_encode($response->json()));
|
return redirect()->route('servers.index')->with('error', json_encode($response->json()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,29 +251,13 @@ class ServerController extends Controller
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Cancel Server */
|
|
||||||
public function cancel(Server $server)
|
|
||||||
{
|
|
||||||
if ($server->user_id != Auth::user()->id) {
|
|
||||||
return back()->with('error', __('This is not your Server!'));
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
$server->update([
|
|
||||||
'canceled' => now(),
|
|
||||||
]);
|
|
||||||
return redirect()->route('servers.index')->with('success', __('Server canceled'));
|
|
||||||
} catch (Exception $e) {
|
|
||||||
return redirect()->route('servers.index')->with('error', __('An exception has occurred while trying to cancel the server"') . $e->getMessage() . '"');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Show Server Settings */
|
/** Show Server Settings */
|
||||||
public function show(Server $server, ServerSettings $server_settings, GeneralSettings $general_settings)
|
public function show(Server $server)
|
||||||
{
|
{
|
||||||
if ($server->user_id != Auth::user()->id) {
|
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 = $this->pterodactyl->getServerAttributes($server->pterodactyl_id);
|
$serverAttributes = Pterodactyl::getServerAttributes($server->pterodactyl_id);
|
||||||
$serverRelationships = $serverAttributes['relationships'];
|
$serverRelationships = $serverAttributes['relationships'];
|
||||||
$serverLocationAttributes = $serverRelationships['location']['attributes'];
|
$serverLocationAttributes = $serverRelationships['location']['attributes'];
|
||||||
|
|
||||||
|
@ -308,7 +273,7 @@ class ServerController extends Controller
|
||||||
$server->name = $serverAttributes['name'];
|
$server->name = $serverAttributes['name'];
|
||||||
$server->egg = $serverRelationships['egg']['attributes']['name'];
|
$server->egg = $serverRelationships['egg']['attributes']['name'];
|
||||||
|
|
||||||
$pteroNode = $this->pterodactyl->getNode($serverRelationships['node']['attributes']['id']);
|
$pteroNode = Pterodactyl::getNode($serverRelationships['node']['attributes']['id']);
|
||||||
|
|
||||||
$products = Product::orderBy('created_at')
|
$products = Product::orderBy('created_at')
|
||||||
->whereHas('nodes', function (Builder $builder) use ($serverRelationships) { //Only show products for that node
|
->whereHas('nodes', function (Builder $builder) use ($serverRelationships) { //Only show products for that node
|
||||||
|
@ -327,15 +292,11 @@ class ServerController extends Controller
|
||||||
return view('servers.settings')->with([
|
return view('servers.settings')->with([
|
||||||
'server' => $server,
|
'server' => $server,
|
||||||
'products' => $products,
|
'products' => $products,
|
||||||
'server_enable_upgrade' => $server_settings->enable_upgrade,
|
|
||||||
'credits_display_name' => $general_settings->credits_display_name
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function upgrade(Server $server, Request $request)
|
public function upgrade(Server $server, Request $request)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::UPGRADE_PERMISSION);
|
|
||||||
|
|
||||||
if ($server->user_id != Auth::user()->id) {
|
if ($server->user_id != Auth::user()->id) {
|
||||||
return redirect()->route('servers.index');
|
return redirect()->route('servers.index');
|
||||||
}
|
}
|
||||||
|
@ -345,7 +306,7 @@ class ServerController extends Controller
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
$oldProduct = Product::where('id', $server->product->id)->first();
|
$oldProduct = Product::where('id', $server->product->id)->first();
|
||||||
$newProduct = Product::where('id', $request->product_upgrade)->first();
|
$newProduct = Product::where('id', $request->product_upgrade)->first();
|
||||||
$serverAttributes = $this->pterodactyl->getServerAttributes($server->pterodactyl_id);
|
$serverAttributes = Pterodactyl::getServerAttributes($server->pterodactyl_id);
|
||||||
$serverRelationships = $serverAttributes['relationships'];
|
$serverRelationships = $serverAttributes['relationships'];
|
||||||
|
|
||||||
// Get node resource allocation info
|
// Get node resource allocation info
|
||||||
|
@ -356,56 +317,31 @@ class ServerController extends Controller
|
||||||
// Check if node has enough memory and disk space
|
// Check if node has enough memory and disk space
|
||||||
$requireMemory = $newProduct->memory - $oldProduct->memory;
|
$requireMemory = $newProduct->memory - $oldProduct->memory;
|
||||||
$requiredisk = $newProduct->disk - $oldProduct->disk;
|
$requiredisk = $newProduct->disk - $oldProduct->disk;
|
||||||
$checkResponse = $this->pterodactyl->checkNodeResources($node, $requireMemory, $requiredisk);
|
$checkResponse = Pterodactyl::checkNodeResources($node, $requireMemory, $requiredisk);
|
||||||
if ($checkResponse == false) {
|
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."));
|
return redirect()->route('servers.index')->with('error', __("The node '".$nodeName."' doesn't have the required memory or disk left to upgrade the server."));
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate the amount of credits that the user overpayed for the old product when canceling the server right now
|
$priceupgrade = $newProduct->getHourlyPrice();
|
||||||
// billing periods are hourly, daily, weekly, monthly, quarterly, half-annually, annually
|
|
||||||
$billingPeriod = $oldProduct->billing_period;
|
|
||||||
// seconds
|
|
||||||
$billingPeriods = [
|
|
||||||
'hourly' => 3600,
|
|
||||||
'daily' => 86400,
|
|
||||||
'weekly' => 604800,
|
|
||||||
'monthly' => 2592000,
|
|
||||||
'quarterly' => 7776000,
|
|
||||||
'half-annually' => 15552000,
|
|
||||||
'annually' => 31104000
|
|
||||||
];
|
|
||||||
// Get the amount of hours the user has been using the server
|
|
||||||
$billingPeriodMultiplier = $billingPeriods[$billingPeriod];
|
|
||||||
$timeDifference = now()->diffInSeconds($server->last_billed);
|
|
||||||
|
|
||||||
// Calculate the price for the time the user has been using the server
|
if ($priceupgrade < $oldProduct->getHourlyPrice()) {
|
||||||
$overpayedCredits = $oldProduct->price - $oldProduct->price * ($timeDifference / $billingPeriodMultiplier);
|
$priceupgrade = 0;
|
||||||
|
}
|
||||||
|
if ($user->credits >= $priceupgrade && $user->credits >= $newProduct->minimum_credits) {
|
||||||
if ($user->credits >= $newProduct->price && $user->credits >= $newProduct->minimum_credits) {
|
$server->product_id = $request->product_upgrade;
|
||||||
|
$server->update();
|
||||||
$server->allocation = $serverAttributes['allocation'];
|
$server->allocation = $serverAttributes['allocation'];
|
||||||
$response = $this->pterodactyl->updateServer($server, $newProduct);
|
$response = 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."));
|
if ($response->failed()) {
|
||||||
|
return $this->serverCreationFailed($response, $server);
|
||||||
|
}
|
||||||
|
//update user balance
|
||||||
|
$user->decrement('credits', $priceupgrade);
|
||||||
//restart the server
|
//restart the server
|
||||||
$response = $this->pterodactyl->powerAction($server, 'restart');
|
$response = Pterodactyl::powerAction($server, 'restart');
|
||||||
if ($response->failed()) return redirect()->route('servers.index')->with('error', 'Upgrade Failed! Could not restart the server: ' . $response->json()['errors'][0]['detail']);
|
if ($response->failed()) {
|
||||||
|
return redirect()->route('servers.index')->with('error', $response->json()['errors'][0]['detail']);
|
||||||
|
}
|
||||||
// Remove the allocation property from the server object as it is not a column in the database
|
|
||||||
unset($server->allocation);
|
|
||||||
// Update the server on controlpanel
|
|
||||||
$server->update([
|
|
||||||
'product_id' => $newProduct->id,
|
|
||||||
'updated_at' => now(),
|
|
||||||
'last_billed' => now(),
|
|
||||||
'canceled' => null,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Refund the user the overpayed credits
|
|
||||||
if ($overpayedCredits > 0) $user->increment('credits', $overpayedCredits);
|
|
||||||
|
|
||||||
// Withdraw the credits for the new product
|
|
||||||
$user->decrement('credits', $newProduct->price);
|
|
||||||
|
|
||||||
return redirect()->route('servers.show', ['server' => $server->id])->with('success', __('Server Successfully Upgraded'));
|
return redirect()->route('servers.show', ['server' => $server->id])->with('success', __('Server Successfully Upgraded'));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -3,31 +3,36 @@
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Models\ShopProduct;
|
use App\Models\ShopProduct;
|
||||||
use App\Settings\GeneralSettings;
|
|
||||||
use App\Settings\UserSettings;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
class StoreController extends Controller
|
class StoreController extends Controller
|
||||||
{
|
{
|
||||||
/** Display a listing of the resource. */
|
/** Display a listing of the resource. */
|
||||||
public function index(UserSettings $user_settings, GeneralSettings $general_settings)
|
public function index()
|
||||||
{
|
{
|
||||||
$isStoreEnabled = $general_settings->store_enabled;
|
$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;
|
||||||
|
}
|
||||||
|
|
||||||
//Required Verification for creating an server
|
//Required Verification for creating an server
|
||||||
if ($user_settings->force_email_verification && !Auth::user()->hasVerifiedEmail()) {
|
if (config('SETTINGS::USER:FORCE_EMAIL_VERIFICATION', false) === 'true' && ! Auth::user()->hasVerifiedEmail()) {
|
||||||
return redirect()->route('profile.index')->with('error', __('You are required to verify your email address before you can purchase credits.'));
|
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
|
//Required Verification for creating an server
|
||||||
if ($user_settings->force_discord_verification && !Auth::user()->discordUser) {
|
if (config('SETTINGS::USER:FORCE_DISCORD_VERIFICATION', false) === 'true' && ! Auth::user()->discordUser) {
|
||||||
return redirect()->route('profile.index')->with('error', __('You are required to link your discord account before you can purchase Credits'));
|
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([
|
return view('store.index')->with([
|
||||||
'products' => ShopProduct::where('disabled', '=', false)->orderBy('type', 'asc')->orderBy('price', 'asc')->get(),
|
'products' => ShopProduct::where('disabled', '=', false)->orderBy('type', 'asc')->orderBy('price', 'asc')->get(),
|
||||||
'isStoreEnabled' => $isStoreEnabled,
|
'isPaymentSetup' => $isPaymentSetup,
|
||||||
'credits_display_name' => $general_settings->credits_display_name
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,6 @@ use App\Models\User;
|
||||||
use App\Notifications\Ticket\Admin\AdminCreateNotification;
|
use App\Notifications\Ticket\Admin\AdminCreateNotification;
|
||||||
use App\Notifications\Ticket\Admin\AdminReplyNotification;
|
use App\Notifications\Ticket\Admin\AdminReplyNotification;
|
||||||
use App\Notifications\Ticket\User\CreateNotification;
|
use App\Notifications\Ticket\User\CreateNotification;
|
||||||
use App\Settings\LocaleSettings;
|
|
||||||
use App\Settings\PterodactylSettings;
|
|
||||||
use App\Settings\TicketSettings;
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Notification;
|
use Illuminate\Support\Facades\Notification;
|
||||||
|
@ -21,32 +18,23 @@ use Illuminate\Support\Str;
|
||||||
|
|
||||||
class TicketsController extends Controller
|
class TicketsController extends Controller
|
||||||
{
|
{
|
||||||
const READ_PERMISSION = 'user.ticket.read';
|
public function index()
|
||||||
const WRITE_PERMISSION = 'user.ticket.write';
|
|
||||||
public function index(LocaleSettings $locale_settings, TicketSettings $ticketSettings)
|
|
||||||
{
|
{
|
||||||
return view('ticket.index', [
|
$tickets = Ticket::where('user_id', Auth::user()->id)->paginate(10);
|
||||||
'ticketsettings' => $ticketSettings,
|
$ticketcategories = TicketCategory::all();
|
||||||
'tickets' => Ticket::where('user_id', Auth::user()->id)->paginate(10),
|
|
||||||
'ticketcategories' => TicketCategory::all(),
|
return view('ticket.index', compact('tickets', 'ticketcategories'));
|
||||||
'locale_datatables' => $locale_settings->datatables
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function store(Request $request, TicketSettings $ticket_settings)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
$this->validate(
|
$this->validate($request, [
|
||||||
$request,
|
|
||||||
[
|
|
||||||
'title' => 'required',
|
'title' => 'required',
|
||||||
'ticketcategory' => 'required',
|
'ticketcategory' => 'required',
|
||||||
'priority' => 'required',
|
'priority' => 'required',
|
||||||
'message' => 'required',
|
'message' => 'required',]
|
||||||
'g-recaptcha-response' => ['required', 'recaptcha'],
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
$ticket = new Ticket(
|
$ticket = new Ticket([
|
||||||
[
|
|
||||||
'title' => $request->input('title'),
|
'title' => $request->input('title'),
|
||||||
'user_id' => Auth::user()->id,
|
'user_id' => Auth::user()->id,
|
||||||
'ticket_id' => strtoupper(Str::random(8)),
|
'ticket_id' => strtoupper(Str::random(8)),
|
||||||
|
@ -54,26 +42,29 @@ class TicketsController extends Controller
|
||||||
'priority' => $request->input('priority'),
|
'priority' => $request->input('priority'),
|
||||||
'message' => $request->input('message'),
|
'message' => $request->input('message'),
|
||||||
'status' => 'Open',
|
'status' => 'Open',
|
||||||
'server' => $request->input('server'),
|
'server' => $request->input('server'),]
|
||||||
]
|
|
||||||
);
|
);
|
||||||
$ticket->save();
|
$ticket->save();
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
|
if (config('SETTINGS::TICKET:NOTIFY') == "all") {
|
||||||
$staffNotify = User::permission('admin.tickets.get_notification')->get();
|
$admin = User::where('role', 'admin')->orWhere('role', 'mod')->get();
|
||||||
foreach($staffNotify as $staff){
|
}
|
||||||
Notification::send($staff, new AdminCreateNotification($ticket, $user));
|
if (config('SETTINGS::TICKET:NOTIFY') == "admin") {
|
||||||
|
$admin = User::where('role', 'admin')->get();
|
||||||
|
}
|
||||||
|
if (config('SETTINGS::TICKET:NOTIFY') == "moderator") {
|
||||||
|
$admin = User::where('role', 'mod')->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$user->notify(new CreateNotification($ticket));
|
$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);
|
return redirect()->route('ticket.index')->with('success', __('A ticket has been opened, ID: #') . $ticket->ticket_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function show($ticket_id, PterodactylSettings $ptero_settings)
|
public function show($ticket_id)
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::READ_PERMISSION);
|
|
||||||
try {
|
try {
|
||||||
$ticket = Ticket::where('ticket_id', $ticket_id)->firstOrFail();
|
$ticket = Ticket::where('ticket_id', $ticket_id)->firstOrFail();
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
@ -82,9 +73,8 @@ class TicketsController extends Controller
|
||||||
$ticketcomments = $ticket->ticketcomments;
|
$ticketcomments = $ticket->ticketcomments;
|
||||||
$ticketcategory = $ticket->ticketcategory;
|
$ticketcategory = $ticket->ticketcategory;
|
||||||
$server = Server::where('id', $ticket->server)->first();
|
$server = Server::where('id', $ticket->server)->first();
|
||||||
$pterodactyl_url = $ptero_settings->panel_url;
|
|
||||||
|
|
||||||
return view('ticket.show', compact('ticket', 'ticketcategory', 'ticketcomments', 'server', 'pterodactyl_url'));
|
return view('ticket.show', compact('ticket', 'ticketcategory', 'ticketcomments', 'server'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function reply(Request $request)
|
public function reply(Request $request)
|
||||||
|
@ -109,19 +99,15 @@ class TicketsController extends Controller
|
||||||
'message' => $request->input('message'),
|
'message' => $request->input('message'),
|
||||||
]);
|
]);
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
|
$admin = User::where('role', 'admin')->orWhere('role', 'mod')->get();
|
||||||
$newmessage = $request->input('ticketcomment');
|
$newmessage = $request->input('ticketcomment');
|
||||||
|
Notification::send($admin, new AdminReplyNotification($ticket, $user, $newmessage));
|
||||||
$staffNotify = User::permission('admin.tickets.get_notification')->get();
|
|
||||||
foreach($staffNotify as $staff){
|
|
||||||
Notification::send($staff, new AdminReplyNotification($ticket, $user, $newmessage));
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirect()->back()->with('success', __('Your comment has been submitted'));
|
return redirect()->back()->with('success', __('Your comment has been submitted'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function create()
|
public function create()
|
||||||
{
|
{
|
||||||
$this->checkPermission(self::WRITE_PERMISSION);
|
|
||||||
//check in blacklist
|
//check in blacklist
|
||||||
$check = TicketBlacklist::where('user_id', Auth::user()->id)->first();
|
$check = TicketBlacklist::where('user_id', Auth::user()->id)->first();
|
||||||
if ($check && $check->status == 'True') {
|
if ($check && $check->status == 'True') {
|
||||||
|
@ -184,10 +170,8 @@ class TicketsController extends Controller
|
||||||
return __($tickets->priority);
|
return __($tickets->priority);
|
||||||
})
|
})
|
||||||
->editColumn('updated_at', function (Ticket $tickets) {
|
->editColumn('updated_at', function (Ticket $tickets) {
|
||||||
return [
|
return ['display' => $tickets->updated_at ? $tickets->updated_at->diffForHumans() : '',
|
||||||
'display' => $tickets->updated_at ? $tickets->updated_at->diffForHumans() : '',
|
'raw' => $tickets->updated_at ? strtotime($tickets->updated_at) : ''];
|
||||||
'raw' => $tickets->updated_at ? strtotime($tickets->updated_at) : ''
|
|
||||||
];
|
|
||||||
})
|
})
|
||||||
->addColumn('actions', function (Ticket $tickets) {
|
->addColumn('actions', function (Ticket $tickets) {
|
||||||
$statusButtonColor = ($tickets->status == "Closed") ? 'btn-success' : 'btn-warning';
|
$statusButtonColor = ($tickets->status == "Closed") ? 'btn-success' : 'btn-warning';
|
||||||
|
|
|
@ -4,6 +4,7 @@ namespace App\Http;
|
||||||
|
|
||||||
use App\Http\Middleware\ApiAuthToken;
|
use App\Http\Middleware\ApiAuthToken;
|
||||||
use App\Http\Middleware\CheckSuspended;
|
use App\Http\Middleware\CheckSuspended;
|
||||||
|
use App\Http\Middleware\GlobalNames;
|
||||||
use App\Http\Middleware\isAdmin;
|
use App\Http\Middleware\isAdmin;
|
||||||
use App\Http\Middleware\isMod;
|
use App\Http\Middleware\isMod;
|
||||||
use App\Http\Middleware\LastSeen;
|
use App\Http\Middleware\LastSeen;
|
||||||
|
@ -26,7 +27,6 @@ class Kernel extends HttpKernel
|
||||||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||||
\App\Http\Middleware\TrimStrings::class,
|
\App\Http\Middleware\TrimStrings::class,
|
||||||
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -43,12 +43,14 @@ class Kernel extends HttpKernel
|
||||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
LastSeen::class,
|
LastSeen::class,
|
||||||
|
GlobalNames::class,
|
||||||
\App\Http\Middleware\SetLocale::class,
|
\App\Http\Middleware\SetLocale::class,
|
||||||
],
|
],
|
||||||
|
|
||||||
'api' => [
|
'api' => [
|
||||||
'throttle:api',
|
'throttle:api',
|
||||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
|
GlobalNames::class,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -74,9 +76,5 @@ class Kernel extends HttpKernel
|
||||||
'moderator' => isMod::class,
|
'moderator' => isMod::class,
|
||||||
'api.token' => ApiAuthToken::class,
|
'api.token' => ApiAuthToken::class,
|
||||||
'checkSuspended' => CheckSuspended::class,
|
'checkSuspended' => CheckSuspended::class,
|
||||||
'role' => \Spatie\Permission\Middlewares\RoleMiddleware::class,
|
|
||||||
'permission' => \Spatie\Permission\Middlewares\PermissionMiddleware::class,
|
|
||||||
'role_or_permission' => \Spatie\Permission\Middlewares\RoleOrPermissionMiddleware::class,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
27
app/Http/Middleware/GlobalNames.php
Normal file
27
app/Http/Middleware/GlobalNames.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class GlobalNames
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @param Closure $next
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
namespace App\Http\Middleware;
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
use App\Settings\LocaleSettings;
|
|
||||||
use Closure;
|
use Closure;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\App;
|
use Illuminate\Support\Facades\App;
|
||||||
|
@ -10,12 +9,6 @@ use Illuminate\Support\Facades\Session;
|
||||||
|
|
||||||
class SetLocale
|
class SetLocale
|
||||||
{
|
{
|
||||||
private $locale_settings;
|
|
||||||
|
|
||||||
public function __construct(LocaleSettings $locale_settings)
|
|
||||||
{
|
|
||||||
$this->locale_settings = $locale_settings;
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Handle an incoming request.
|
* Handle an incoming request.
|
||||||
*
|
*
|
||||||
|
@ -26,15 +19,15 @@ class SetLocale
|
||||||
public function handle($request, Closure $next)
|
public function handle($request, Closure $next)
|
||||||
{
|
{
|
||||||
if (Session::has('locale')) {
|
if (Session::has('locale')) {
|
||||||
$locale = Session::get('locale', $this->locale_settings->default);
|
$locale = Session::get('locale', config('SETTINGS::LOCALE:DEFAULT'));
|
||||||
} else {
|
} else {
|
||||||
if (!$this->locale_settings->dynamic) {
|
if (config('SETTINGS::LOCALE:DYNAMIC') !== 'true') {
|
||||||
$locale = $this->locale_settings->default;
|
$locale = config('SETTINGS::LOCALE:DEFAULT');
|
||||||
} else {
|
} else {
|
||||||
$locale = substr($request->server('HTTP_ACCEPT_LANGUAGE'), 0, 2);
|
$locale = substr($request->server('HTTP_ACCEPT_LANGUAGE'), 0, 2);
|
||||||
|
|
||||||
if (! in_array($locale, explode(',', $this->locale_settings->available))) {
|
if (! in_array($locale, explode(',', config('SETTINGS::LOCALE:AVAILABLE')))) {
|
||||||
$locale = $this->locale_settings->default;
|
$locale = config('SETTINGS::LOCALE:DEFAULT');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
27
app/Http/Middleware/isAdmin.php
Normal file
27
app/Http/Middleware/isAdmin.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use App\Providers\RouteServiceProvider;
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class isAdmin
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @param Closure $next
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next)
|
||||||
|
{
|
||||||
|
if (Auth::user() && Auth::user()->role == 'admin') {
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect(RouteServiceProvider::HOME);
|
||||||
|
}
|
||||||
|
}
|
27
app/Http/Middleware/isMod.php
Normal file
27
app/Http/Middleware/isMod.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use App\Providers\RouteServiceProvider;
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class isMod
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @param Closure $next
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next)
|
||||||
|
{
|
||||||
|
if (Auth::user() && Auth::user()->role == 'moderator' || Auth::user() && Auth::user()->role == 'admin') {
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect(RouteServiceProvider::HOME);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,61 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Listeners;
|
|
||||||
|
|
||||||
use App\Events\CouponUsedEvent;
|
|
||||||
use App\Settings\CouponSettings;
|
|
||||||
use Carbon\Carbon;
|
|
||||||
|
|
||||||
class CouponUsed
|
|
||||||
{
|
|
||||||
private $delete_coupon_on_expires;
|
|
||||||
private $delete_coupon_on_uses_reached;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create the event listener.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __construct(CouponSettings $couponSettings)
|
|
||||||
{
|
|
||||||
$this->delete_coupon_on_expires = $couponSettings->delete_coupon_on_expires;
|
|
||||||
$this->delete_coupon_on_uses_reached = $couponSettings->delete_coupon_on_uses_reached;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle the event.
|
|
||||||
*
|
|
||||||
* @param \App\Events\CouponUsedEvent $event
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function handle(CouponUsedEvent $event)
|
|
||||||
{
|
|
||||||
// Automatically increments the coupon usage.
|
|
||||||
$this->incrementUses($event);
|
|
||||||
|
|
||||||
if ($this->delete_coupon_on_expires) {
|
|
||||||
if (!is_null($event->coupon->expired_at)) {
|
|
||||||
if ($event->coupon->expires_at <= Carbon::now()->timestamp) {
|
|
||||||
$event->coupon->delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->delete_coupon_on_uses_reached) {
|
|
||||||
if ($event->coupon->uses >= $event->coupon->max_uses) {
|
|
||||||
$event->coupon->delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Increments the use of a coupon.
|
|
||||||
*
|
|
||||||
* @param \App\Events\CouponUsedEvent $event
|
|
||||||
*/
|
|
||||||
private function incrementUses(CouponUsedEvent $event)
|
|
||||||
{
|
|
||||||
$event->coupon->increment('uses');
|
|
||||||
$event->coupon->save();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,27 +3,13 @@
|
||||||
namespace App\Listeners;
|
namespace App\Listeners;
|
||||||
|
|
||||||
use App\Events\PaymentEvent;
|
use App\Events\PaymentEvent;
|
||||||
use App\Settings\InvoiceSettings;
|
|
||||||
use App\Traits\Invoiceable;
|
use App\Traits\Invoiceable;
|
||||||
|
|
||||||
class CreateInvoice
|
class CreateInvoice
|
||||||
{
|
{
|
||||||
|
|
||||||
use Invoiceable;
|
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.
|
* Handle the event.
|
||||||
*
|
*
|
||||||
|
@ -32,9 +18,9 @@ class CreateInvoice
|
||||||
*/
|
*/
|
||||||
public function handle(PaymentEvent $event)
|
public function handle(PaymentEvent $event)
|
||||||
{
|
{
|
||||||
if ($this->invoice_enabled) {
|
if (config('SETTINGS::INVOICE:ENABLED') == 'true') {
|
||||||
// create invoice using the trait
|
// create invoice using the trait
|
||||||
$this->createInvoice($event->payment, $event->shopProduct, $this->invoice_settings);
|
$this->createInvoice($event->payment, $event->shopProduct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,24 +4,11 @@ namespace App\Listeners;
|
||||||
|
|
||||||
use App\Events\UserUpdateCreditsEvent;
|
use App\Events\UserUpdateCreditsEvent;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Settings\UserSettings;
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
|
||||||
class UnsuspendServers implements 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.
|
* Handle the event.
|
||||||
*
|
*
|
||||||
|
@ -32,7 +19,7 @@ class UnsuspendServers implements ShouldQueue
|
||||||
*/
|
*/
|
||||||
public function handle(UserUpdateCreditsEvent $event)
|
public function handle(UserUpdateCreditsEvent $event)
|
||||||
{
|
{
|
||||||
if ($event->user->credits > $this->min_credits_to_make_server) {
|
if ($event->user->credits > config('SETTINGS::USER:MINIMUM_REQUIRED_CREDITS_TO_MAKE_SERVER', 50)) {
|
||||||
/** @var Server $server */
|
/** @var Server $server */
|
||||||
foreach ($event->user->servers as $server) {
|
foreach ($event->user->servers as $server) {
|
||||||
if ($server->isSuspended()) {
|
if ($server->isSuspended()) {
|
||||||
|
|
|
@ -2,41 +2,15 @@
|
||||||
|
|
||||||
namespace App\Listeners;
|
namespace App\Listeners;
|
||||||
|
|
||||||
use App\Enums\PaymentStatus;
|
|
||||||
use App\Events\PaymentEvent;
|
use App\Events\PaymentEvent;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use App\Models\PartnerDiscount;
|
use App\Models\PartnerDiscount;
|
||||||
use App\Settings\GeneralSettings;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use App\Settings\ReferralSettings;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use App\Settings\UserSettings;
|
|
||||||
|
|
||||||
class UserPayment
|
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.
|
* Handle the event.
|
||||||
*
|
*
|
||||||
|
@ -49,13 +23,13 @@ class UserPayment
|
||||||
$shopProduct = $event->shopProduct;
|
$shopProduct = $event->shopProduct;
|
||||||
|
|
||||||
// only update user if payment is paid
|
// only update user if payment is paid
|
||||||
if ($event->payment->status != PaymentStatus::PAID->value) {
|
if ($event->payment->status != "paid") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//update server limit
|
//update server limit
|
||||||
if ($this->server_limit_after_irl_purchase !== 0 && $user->server_limit < $this->server_limit_after_irl_purchase) {
|
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' => $this->server_limit_after_irl_purchase]);
|
$user->update(['server_limit' => config('SETTINGS::USER:SERVER_LIMIT_AFTER_IRL_PURCHASE')]);
|
||||||
}
|
}
|
||||||
|
|
||||||
//update User with bought item
|
//update User with bought item
|
||||||
|
@ -66,35 +40,35 @@ class UserPayment
|
||||||
}
|
}
|
||||||
|
|
||||||
//give referral commission always
|
//give referral commission always
|
||||||
if (($this->referral_mode === "commission" || $this->referral_mode === "both") && $shopProduct->type == "Credits" && $this->referral_always_give_commission) {
|
if ((config("SETTINGS::REFERRAL:MODE") == "commission" || config("SETTINGS::REFERRAL:MODE") == "both") && $shopProduct->type == "Credits" && config("SETTINGS::REFERRAL::ALWAYS_GIVE_COMMISSION") == "true") {
|
||||||
if ($ref_user = DB::table("user_referrals")->where('registered_user_id', '=', $user->id)->first()) {
|
if ($ref_user = DB::table("user_referrals")->where('registered_user_id', '=', $user->id)->first()) {
|
||||||
$ref_user = User::findOrFail($ref_user->referral_id);
|
$ref_user = User::findOrFail($ref_user->referral_id);
|
||||||
$increment = number_format($shopProduct->quantity * (PartnerDiscount::getCommission($ref_user->id, $this->referral_percentage)) / 100, 0, "", "");
|
$increment = number_format($shopProduct->quantity * (PartnerDiscount::getCommission($ref_user->id)) / 100, 0, "", "");
|
||||||
$ref_user->increment('credits', $increment);
|
$ref_user->increment('credits', $increment);
|
||||||
|
|
||||||
//LOGS REFERRALS IN THE ACTIVITY LOG
|
//LOGS REFERRALS IN THE ACTIVITY LOG
|
||||||
activity()
|
activity()
|
||||||
->performedOn($user)
|
->performedOn($user)
|
||||||
->causedBy($ref_user)
|
->causedBy($ref_user)
|
||||||
->log('gained ' . $increment . ' ' . $this->credits_display_name . ' for commission-referral of ' . $user->name . ' (ID:' . $user->id . ')');
|
->log('gained ' . $increment . ' ' . config("SETTINGS::SYSTEM:CREDITS_DISPLAY_NAME") . ' for commission-referral of ' . $user->name . ' (ID:' . $user->id . ')');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//update role give Referral-reward
|
//update role give Referral-reward
|
||||||
if ($user->hasRole(4)) {
|
if ($user->role == 'member') {
|
||||||
$user->syncRoles(3);
|
$user->update(['role' => 'client']);
|
||||||
|
|
||||||
//give referral commission only on first purchase
|
//give referral commission only on first purchase
|
||||||
if (($this->referral_mode === "commission" || $this->referral_mode === "both") && $shopProduct->type == "Credits" && !$this->referral_always_give_commission) {
|
if ((config("SETTINGS::REFERRAL:MODE") == "commission" || config("SETTINGS::REFERRAL:MODE") == "both") && $shopProduct->type == "Credits" && config("SETTINGS::REFERRAL::ALWAYS_GIVE_COMMISSION") == "false") {
|
||||||
if ($ref_user = DB::table("user_referrals")->where('registered_user_id', '=', $user->id)->first()) {
|
if ($ref_user = DB::table("user_referrals")->where('registered_user_id', '=', $user->id)->first()) {
|
||||||
$ref_user = User::findOrFail($ref_user->referral_id);
|
$ref_user = User::findOrFail($ref_user->referral_id);
|
||||||
$increment = number_format($shopProduct->quantity * (PartnerDiscount::getCommission($ref_user->id, $this->referral_percentage)) / 100, 0, "", "");
|
$increment = number_format($shopProduct->quantity * (PartnerDiscount::getCommission($ref_user->id)) / 100, 0, "", "");
|
||||||
$ref_user->increment('credits', $increment);
|
$ref_user->increment('credits', $increment);
|
||||||
|
|
||||||
//LOGS REFERRALS IN THE ACTIVITY LOG
|
//LOGS REFERRALS IN THE ACTIVITY LOG
|
||||||
activity()
|
activity()
|
||||||
->performedOn($user)
|
->performedOn($user)
|
||||||
->causedBy($ref_user)
|
->causedBy($ref_user)
|
||||||
->log('gained ' . $increment . ' ' . $this->credits_display_name . ' for commission-referral of ' . $user->name . ' (ID:' . $user->id . ')');
|
->log('gained ' . $increment . ' ' . config("SETTINGS::SYSTEM:CREDITS_DISPLAY_NAME") . ' for commission-referral of ' . $user->name . ' (ID:' . $user->id . ')');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,22 +2,16 @@
|
||||||
|
|
||||||
namespace App\Listeners;
|
namespace App\Listeners;
|
||||||
|
|
||||||
use App\Settings\UserSettings;
|
|
||||||
|
|
||||||
class Verified
|
class Verified
|
||||||
{
|
{
|
||||||
private $server_limit_after_verify_email;
|
|
||||||
private $credits_reward_after_verify_email;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the event listener.
|
* Create the event listener.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function __construct(UserSettings $user_settings)
|
public function __construct()
|
||||||
{
|
{
|
||||||
$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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,8 +23,8 @@ class Verified
|
||||||
public function handle($event)
|
public function handle($event)
|
||||||
{
|
{
|
||||||
if (!$event->user->email_verified_reward) {
|
if (!$event->user->email_verified_reward) {
|
||||||
$event->user->increment('server_limit', $this->server_limit_after_verify_email);
|
$event->user->increment('server_limit', config('SETTINGS::USER:SERVER_LIMIT_REWARD_AFTER_VERIFY_EMAIL'));
|
||||||
$event->user->increment('credits', $this->credits_reward_after_verify_email);
|
$event->user->increment('credits', config('SETTINGS::USER:CREDITS_REWARD_AFTER_VERIFY_EMAIL'));
|
||||||
$event->user->update(['email_verified_reward' => true]);
|
$event->user->update(['email_verified_reward' => true]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,119 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use App\Settings\CouponSettings;
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
use Spatie\Activitylog\LogOptions;
|
|
||||||
use Spatie\Activitylog\Traits\LogsActivity;
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
|
||||||
|
|
||||||
class Coupon extends Model
|
|
||||||
{
|
|
||||||
use HasFactory, LogsActivity;
|
|
||||||
|
|
||||||
public function getActivitylogOptions(): LogOptions
|
|
||||||
{
|
|
||||||
return LogOptions::defaults()
|
|
||||||
->logOnlyDirty()
|
|
||||||
->logOnly(['*'])
|
|
||||||
->dontSubmitEmptyLogs();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string[]
|
|
||||||
*/
|
|
||||||
protected $fillable = [
|
|
||||||
'code',
|
|
||||||
'type',
|
|
||||||
'value',
|
|
||||||
'uses',
|
|
||||||
'max_uses',
|
|
||||||
'expires_at'
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string[]
|
|
||||||
*/
|
|
||||||
protected $casts = [
|
|
||||||
'value' => 'float',
|
|
||||||
'uses' => 'integer',
|
|
||||||
'max_uses' => 'integer',
|
|
||||||
'expires_at' => 'timestamp'
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the date format used by the coupons.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public static function formatDate(): string
|
|
||||||
{
|
|
||||||
return 'Y-MM-DD HH:mm:ss';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current state of the coupon.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getStatus()
|
|
||||||
{
|
|
||||||
if ($this->uses >= $this->max_uses) {
|
|
||||||
return 'USES_LIMIT_REACHED';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_null($this->expires_at)) {
|
|
||||||
if ($this->expires_at <= Carbon::now(config('app.timezone'))->timestamp) {
|
|
||||||
return __('EXPIRED');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return __('VALID');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a user has already exceeded the uses of a coupon.
|
|
||||||
*
|
|
||||||
* @param User $user The request being made.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function isMaxUsesReached($user): bool
|
|
||||||
{
|
|
||||||
$coupon_settings = new CouponSettings;
|
|
||||||
$coupon_uses = $user->coupons()->where('id', $this->id)->count();
|
|
||||||
|
|
||||||
return $coupon_uses >= $coupon_settings->max_uses_per_user;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a specified quantity of coupon codes.
|
|
||||||
*
|
|
||||||
* @param int $amount Amount of coupons to be generated.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public static function generateRandomCoupon(int $amount = 10): array
|
|
||||||
{
|
|
||||||
$coupons = [];
|
|
||||||
|
|
||||||
for ($i = 0; $i < $amount; $i++) {
|
|
||||||
$random_coupon = strtoupper(bin2hex(random_bytes(3)));
|
|
||||||
|
|
||||||
$coupons[] = $random_coupon;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $coupons;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return BelongsToMany
|
|
||||||
*/
|
|
||||||
public function users()
|
|
||||||
{
|
|
||||||
return $this->belongsToMany(User::class, 'user_coupons');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +1,12 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Models\Pterodactyl;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Classes\PterodactylClient;
|
use App\Classes\Pterodactyl;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
use App\Models\Pterodactyl\Nest;
|
|
||||||
use App\Models\Product;
|
|
||||||
|
|
||||||
class Egg extends Model
|
class Egg extends Model
|
||||||
{
|
{
|
||||||
|
@ -39,9 +37,9 @@ class Egg extends Model
|
||||||
public static function syncEggs()
|
public static function syncEggs()
|
||||||
{
|
{
|
||||||
Nest::syncNests();
|
Nest::syncNests();
|
||||||
$client = app(PterodactylClient::class);
|
|
||||||
Nest::all()->each(function (Nest $nest) use ($client) {
|
Nest::all()->each(function (Nest $nest) {
|
||||||
$eggs = $client->getEggs($nest);
|
$eggs = Pterodactyl::getEggs($nest);
|
||||||
|
|
||||||
foreach ($eggs as $egg) {
|
foreach ($eggs as $egg) {
|
||||||
$array = [];
|
$array = [];
|
|
@ -1,8 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Models\Pterodactyl;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Classes\PterodactylClient;
|
use App\Classes\Pterodactyl;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
@ -33,8 +33,7 @@ class Location extends Model
|
||||||
*/
|
*/
|
||||||
public static function syncLocations()
|
public static function syncLocations()
|
||||||
{
|
{
|
||||||
$client = app(PterodactylClient::class);
|
$locations = Pterodactyl::getLocations();
|
||||||
$locations = $client->getLocations();
|
|
||||||
|
|
||||||
//map response
|
//map response
|
||||||
$locations = array_map(function ($val) {
|
$locations = array_map(function ($val) {
|
|
@ -1,8 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Models\Pterodactyl;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Classes\PterodactylClient;
|
use App\Classes\Pterodactyl;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
@ -32,8 +32,7 @@ class Nest extends Model
|
||||||
|
|
||||||
public static function syncNests()
|
public static function syncNests()
|
||||||
{
|
{
|
||||||
$client = app(PterodactylClient::class);
|
$nests = Pterodactyl::getNests();
|
||||||
$nests = $client->getNests();
|
|
||||||
|
|
||||||
//map response
|
//map response
|
||||||
$nests = array_map(function ($nest) {
|
$nests = array_map(function ($nest) {
|
|
@ -1,14 +1,13 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Models\Pterodactyl;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Classes\PterodactylClient;
|
use App\Classes\Pterodactyl;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
use App\Models\Product;
|
|
||||||
|
|
||||||
class Node extends Model
|
class Node extends Model
|
||||||
{
|
{
|
||||||
|
@ -33,8 +32,7 @@ class Node extends Model
|
||||||
public static function syncNodes()
|
public static function syncNodes()
|
||||||
{
|
{
|
||||||
Location::syncLocations();
|
Location::syncLocations();
|
||||||
$client = app(PterodactylClient::class);
|
$nodes = Pterodactyl::getNodes();
|
||||||
$nodes = $client->getNodes();
|
|
||||||
|
|
||||||
//map response
|
//map response
|
||||||
$nodes = array_map(function ($node) {
|
$nodes = array_map(function ($node) {
|
|
@ -33,7 +33,7 @@ class PartnerDiscount extends Model
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getCommission($user_id, $percentage)
|
public static function getCommission($user_id)
|
||||||
{
|
{
|
||||||
if ($partnerDiscount = PartnerDiscount::where('user_id', $user_id)->first()) {
|
if ($partnerDiscount = PartnerDiscount::where('user_id', $user_id)->first()) {
|
||||||
if ($partnerDiscount->referral_system_commission >= 0) {
|
if ($partnerDiscount->referral_system_commission >= 0) {
|
||||||
|
@ -41,6 +41,6 @@ class PartnerDiscount extends Model
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $percentage;
|
return config('SETTINGS::REFERRAL:PERCENTAGE');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,6 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
use Spatie\Activitylog\LogOptions;
|
use Spatie\Activitylog\LogOptions;
|
||||||
use Spatie\Activitylog\Traits\LogsActivity;
|
use Spatie\Activitylog\Traits\LogsActivity;
|
||||||
use App\Models\Pterodactyl\Egg;
|
|
||||||
use App\Models\Pterodactyl\Node;
|
|
||||||
|
|
||||||
class Product extends Model
|
class Product extends Model
|
||||||
{
|
{
|
||||||
|
@ -45,46 +43,12 @@ class Product extends Model
|
||||||
|
|
||||||
public function getHourlyPrice()
|
public function getHourlyPrice()
|
||||||
{
|
{
|
||||||
// calculate the hourly price with the billing period
|
return ($this->price / 30) / 24;
|
||||||
switch($this->billing_period) {
|
|
||||||
case 'daily':
|
|
||||||
return $this->price / 24;
|
|
||||||
case 'weekly':
|
|
||||||
return $this->price / 24 / 7;
|
|
||||||
case 'monthly':
|
|
||||||
return $this->price / 24 / 30;
|
|
||||||
case 'quarterly':
|
|
||||||
return $this->price / 24 / 30 / 3;
|
|
||||||
case 'half-annually':
|
|
||||||
return $this->price / 24 / 30 / 6;
|
|
||||||
case 'annually':
|
|
||||||
return $this->price / 24 / 365;
|
|
||||||
default:
|
|
||||||
return $this->price;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMonthlyPrice()
|
public function getDailyPrice()
|
||||||
{
|
{
|
||||||
// calculate the hourly price with the billing period
|
return $this->price / 30;
|
||||||
switch($this->billing_period) {
|
|
||||||
case 'hourly':
|
|
||||||
return $this->price * 24 * 30;
|
|
||||||
case 'daily':
|
|
||||||
return $this->price * 30;
|
|
||||||
case 'weekly':
|
|
||||||
return $this->price * 4;
|
|
||||||
case 'monthly':
|
|
||||||
return $this->price;
|
|
||||||
case 'quarterly':
|
|
||||||
return $this->price / 3;
|
|
||||||
case 'half-annually':
|
|
||||||
return $this->price / 6;
|
|
||||||
case 'annually':
|
|
||||||
return $this->price / 12;
|
|
||||||
default:
|
|
||||||
return $this->price;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getWeeklyPrice()
|
public function getWeeklyPrice()
|
||||||
|
|
|
@ -2,9 +2,7 @@
|
||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use Carbon\Carbon;
|
use App\Classes\Pterodactyl;
|
||||||
use App\Classes\PterodactylClient;
|
|
||||||
use App\Settings\PterodactylSettings;
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use GuzzleHttp\Promise\PromiseInterface;
|
use GuzzleHttp\Promise\PromiseInterface;
|
||||||
use Hidehalo\Nanoid\Client;
|
use Hidehalo\Nanoid\Client;
|
||||||
|
@ -23,9 +21,6 @@ class Server extends Model
|
||||||
{
|
{
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
use LogsActivity;
|
use LogsActivity;
|
||||||
|
|
||||||
private PterodactylClient $pterodactyl;
|
|
||||||
|
|
||||||
public function getActivitylogOptions(): LogOptions
|
public function getActivitylogOptions(): LogOptions
|
||||||
{
|
{
|
||||||
return LogOptions::defaults()
|
return LogOptions::defaults()
|
||||||
|
@ -33,7 +28,6 @@ class Server extends Model
|
||||||
-> logOnly(['*'])
|
-> logOnly(['*'])
|
||||||
-> dontSubmitEmptyLogs();
|
-> dontSubmitEmptyLogs();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
|
@ -53,14 +47,12 @@ class Server extends Model
|
||||||
* @var string[]
|
* @var string[]
|
||||||
*/
|
*/
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
"name",
|
'name',
|
||||||
"description",
|
'description',
|
||||||
"suspended",
|
'suspended',
|
||||||
"identifier",
|
'identifier',
|
||||||
"product_id",
|
'product_id',
|
||||||
"pterodactyl_id",
|
'pterodactyl_id',
|
||||||
"last_billed",
|
|
||||||
"canceled"
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -70,14 +62,6 @@ class Server extends Model
|
||||||
'suspended' => 'datetime',
|
'suspended' => 'datetime',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
parent::__construct();
|
|
||||||
|
|
||||||
$ptero_settings = new PterodactylSettings();
|
|
||||||
$this->pterodactyl = new PterodactylClient($ptero_settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function boot()
|
public static function boot()
|
||||||
{
|
{
|
||||||
parent::boot();
|
parent::boot();
|
||||||
|
@ -89,7 +73,7 @@ class Server extends Model
|
||||||
});
|
});
|
||||||
|
|
||||||
static::deleting(function (Server $server) {
|
static::deleting(function (Server $server) {
|
||||||
$response = $server->pterodactyl->application->delete("/application/servers/{$server->pterodactyl_id}");
|
$response = Pterodactyl::client()->delete("/application/servers/{$server->pterodactyl_id}");
|
||||||
if ($response->failed() && ! is_null($server->pterodactyl_id)) {
|
if ($response->failed() && ! is_null($server->pterodactyl_id)) {
|
||||||
//only return error when it's not a 404 error
|
//only return error when it's not a 404 error
|
||||||
if ($response['errors'][0]['status'] != '404') {
|
if ($response['errors'][0]['status'] != '404') {
|
||||||
|
@ -112,7 +96,7 @@ class Server extends Model
|
||||||
*/
|
*/
|
||||||
public function getPterodactylServer()
|
public function getPterodactylServer()
|
||||||
{
|
{
|
||||||
return $this->pterodactyl->application->get("/application/servers/{$this->pterodactyl_id}");
|
return Pterodactyl::client()->get("/application/servers/{$this->pterodactyl_id}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -120,7 +104,7 @@ class Server extends Model
|
||||||
*/
|
*/
|
||||||
public function suspend()
|
public function suspend()
|
||||||
{
|
{
|
||||||
$response = $this->pterodactyl->suspendServer($this);
|
$response = Pterodactyl::suspendServer($this);
|
||||||
|
|
||||||
if ($response->successful()) {
|
if ($response->successful()) {
|
||||||
$this->update([
|
$this->update([
|
||||||
|
@ -136,16 +120,14 @@ class Server extends Model
|
||||||
*/
|
*/
|
||||||
public function unSuspend()
|
public function unSuspend()
|
||||||
{
|
{
|
||||||
$response = $this->pterodactyl->unSuspendServer($this);
|
$response = Pterodactyl::unSuspendServer($this);
|
||||||
|
|
||||||
if ($response->successful()) {
|
if ($response->successful()) {
|
||||||
$this->update([
|
$this->update([
|
||||||
'suspended' => null,
|
'suspended' => null,
|
||||||
'last_billed' => Carbon::now()->toDateTimeString(),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,48 @@ namespace App\Models;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
|
||||||
class Settings extends Model
|
class Settings extends Model
|
||||||
{
|
{
|
||||||
use HasFactory;
|
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;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,13 +36,6 @@ class ShopProduct extends Model
|
||||||
'disabled',
|
'disabled',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string[]
|
|
||||||
*/
|
|
||||||
protected $casts = [
|
|
||||||
'price' => 'float'
|
|
||||||
];
|
|
||||||
|
|
||||||
public static function boot()
|
public static function boot()
|
||||||
{
|
{
|
||||||
parent::boot();
|
parent::boot();
|
||||||
|
|
|
@ -2,10 +2,9 @@
|
||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Classes\Pterodactyl;
|
||||||
use App\Notifications\Auth\QueuedVerifyEmail;
|
use App\Notifications\Auth\QueuedVerifyEmail;
|
||||||
use App\Notifications\WelcomeMessage;
|
use App\Notifications\WelcomeMessage;
|
||||||
use App\Classes\PterodactylClient;
|
|
||||||
use App\Settings\PterodactylSettings;
|
|
||||||
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
|
@ -13,20 +12,16 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Illuminate\Notifications\Notifiable;
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Spatie\Activitylog\LogOptions;
|
use Spatie\Activitylog\LogOptions;
|
||||||
use Spatie\Activitylog\Traits\CausesActivity;
|
use Spatie\Activitylog\Traits\CausesActivity;
|
||||||
use Spatie\Activitylog\Traits\LogsActivity;
|
use Spatie\Activitylog\Traits\LogsActivity;
|
||||||
use Spatie\Permission\Traits\HasRoles;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class User
|
* Class User
|
||||||
*/
|
*/
|
||||||
class User extends Authenticatable implements MustVerifyEmail
|
class User extends Authenticatable implements MustVerifyEmail
|
||||||
{
|
{
|
||||||
use HasFactory, Notifiable, LogsActivity, CausesActivity, HasRoles;
|
use HasFactory, Notifiable, LogsActivity, CausesActivity;
|
||||||
|
|
||||||
private PterodactylClient $pterodactyl;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string[]
|
* @var string[]
|
||||||
|
@ -66,7 +61,7 @@ class User extends Authenticatable implements MustVerifyEmail
|
||||||
'avatar',
|
'avatar',
|
||||||
'suspended',
|
'suspended',
|
||||||
'referral_code',
|
'referral_code',
|
||||||
'email_verified_reward',
|
'email_verified_reward'
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -92,14 +87,6 @@ class User extends Authenticatable implements MustVerifyEmail
|
||||||
'email_verified_reward' => 'boolean'
|
'email_verified_reward' => 'boolean'
|
||||||
];
|
];
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
parent::__construct();
|
|
||||||
|
|
||||||
$ptero_settings = new PterodactylSettings();
|
|
||||||
$this->pterodactyl = new PterodactylClient($ptero_settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function boot()
|
public static function boot()
|
||||||
{
|
{
|
||||||
parent::boot();
|
parent::boot();
|
||||||
|
@ -126,7 +113,7 @@ class User extends Authenticatable implements MustVerifyEmail
|
||||||
|
|
||||||
$user->discordUser()->delete();
|
$user->discordUser()->delete();
|
||||||
|
|
||||||
$user->pterodactyl->application->delete("/application/users/{$user->pterodactyl_id}");
|
Pterodactyl::client()->delete("/application/users/{$user->pterodactyl_id}");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,14 +157,6 @@ class User extends Authenticatable implements MustVerifyEmail
|
||||||
return $this->belongsToMany(Voucher::class);
|
return $this->belongsToMany(Voucher::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return BelongsToMany
|
|
||||||
*/
|
|
||||||
public function coupons()
|
|
||||||
{
|
|
||||||
return $this->belongsToMany(Coupon::class, 'user_coupons');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return HasOne
|
* @return HasOne
|
||||||
*/
|
*/
|
||||||
|
@ -207,6 +186,9 @@ class User extends Authenticatable implements MustVerifyEmail
|
||||||
return $this->suspended;
|
return $this->suspended;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
public function suspend()
|
public function suspend()
|
||||||
{
|
{
|
||||||
foreach ($this->servers as $server) {
|
foreach ($this->servers as $server) {
|
||||||
|
@ -220,6 +202,9 @@ class User extends Authenticatable implements MustVerifyEmail
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
public function unSuspend()
|
public function unSuspend()
|
||||||
{
|
{
|
||||||
foreach ($this->getServersWithProduct() as $server) {
|
foreach ($this->getServersWithProduct() as $server) {
|
||||||
|
@ -235,34 +220,45 @@ class User extends Authenticatable implements MustVerifyEmail
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getServersWithProduct()
|
||||||
|
{
|
||||||
|
return $this->servers()
|
||||||
|
->with('product')
|
||||||
|
->get();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getAvatar()
|
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 'https://www.gravatar.com/avatar/' . md5(strtolower(trim($this->email)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
public function creditUsage()
|
public function creditUsage()
|
||||||
{
|
{
|
||||||
$usage = 0;
|
$usage = 0;
|
||||||
foreach ($this->getServersWithProduct() as $server) {
|
foreach ($this->getServersWithProduct() as $server) {
|
||||||
$usage += $server->product->getHourlyPrice() * 24 * 30;
|
$usage += $server->product->price;
|
||||||
}
|
}
|
||||||
|
|
||||||
return number_format($usage, 2, '.', '');
|
return number_format($usage, 2, '.', '');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getServersWithProduct()
|
|
||||||
{
|
|
||||||
return $this->servers()
|
|
||||||
->whereNull('suspended')
|
|
||||||
->whereNull('canceled')
|
|
||||||
->with('product')
|
|
||||||
->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array|string|string[]
|
* @return array|string|string[]
|
||||||
*/
|
*/
|
||||||
|
@ -283,7 +279,7 @@ class User extends Authenticatable implements MustVerifyEmail
|
||||||
public function verifyEmail()
|
public function verifyEmail()
|
||||||
{
|
{
|
||||||
$this->forceFill([
|
$this->forceFill([
|
||||||
'email_verified_at' => now()
|
'email_verified_at' => now(),
|
||||||
])->save();
|
])->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,17 +290,6 @@ class User extends Authenticatable implements MustVerifyEmail
|
||||||
])->save();
|
])->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function referredBy()
|
|
||||||
{
|
|
||||||
$referee = DB::table('user_referrals')->where("registered_user_id", $this->id)->first();
|
|
||||||
|
|
||||||
if ($referee) {
|
|
||||||
$referee = User::where("id", $referee->referral_id)->firstOrFail();
|
|
||||||
return $referee;
|
|
||||||
}
|
|
||||||
return Null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getActivitylogOptions(): LogOptions
|
public function getActivitylogOptions(): LogOptions
|
||||||
{
|
{
|
||||||
return LogOptions::defaults()
|
return LogOptions::defaults()
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
namespace App\Notifications;
|
namespace App\Notifications;
|
||||||
|
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Settings\GeneralSettings;
|
|
||||||
use App\Settings\ReferralSettings;
|
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Notifications\Notification;
|
use Illuminate\Notifications\Notification;
|
||||||
|
|
||||||
|
@ -17,12 +15,6 @@ class ReferralNotification extends Notification
|
||||||
*/
|
*/
|
||||||
private $user;
|
private $user;
|
||||||
|
|
||||||
private $ref_user;
|
|
||||||
|
|
||||||
private $reward;
|
|
||||||
|
|
||||||
private $credits_display_name;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new notification instance.
|
* Create a new notification instance.
|
||||||
*
|
*
|
||||||
|
@ -30,11 +22,6 @@ class ReferralNotification extends Notification
|
||||||
*/
|
*/
|
||||||
public function __construct(int $user, int $ref_user)
|
public function __construct(int $user, int $ref_user)
|
||||||
{
|
{
|
||||||
$general_settings= new GeneralSettings();
|
|
||||||
$referral_settings = new ReferralSettings();
|
|
||||||
|
|
||||||
$this->credits_display_name = $general_settings->credits_display_name;
|
|
||||||
$this->reward = $referral_settings->reward;
|
|
||||||
$this->user = User::findOrFail($user);
|
$this->user = User::findOrFail($user);
|
||||||
$this->ref_user = User::findOrFail($ref_user);
|
$this->ref_user = User::findOrFail($ref_user);
|
||||||
}
|
}
|
||||||
|
@ -61,7 +48,7 @@ class ReferralNotification extends Notification
|
||||||
return [
|
return [
|
||||||
'title' => __('Someone registered using your Code!'),
|
'title' => __('Someone registered using your Code!'),
|
||||||
'content' => '
|
'content' => '
|
||||||
<p>You received '. $this->reward . ' ' . $this->credits_display_name . '</p>
|
<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>because '.$this->ref_user->name.' registered with your Referral-Code!</p>
|
||||||
<p>Thank you very much for supporting us!.</p>
|
<p>Thank you very much for supporting us!.</p>
|
||||||
<p>'.config('app.name', 'Laravel').'</p>
|
<p>'.config('app.name', 'Laravel').'</p>
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
namespace App\Notifications;
|
namespace App\Notifications;
|
||||||
|
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Settings\GeneralSettings;
|
|
||||||
use App\Settings\UserSettings;
|
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Notifications\Notification;
|
use Illuminate\Notifications\Notification;
|
||||||
|
@ -18,16 +16,6 @@ class WelcomeMessage extends Notification implements ShouldQueue
|
||||||
*/
|
*/
|
||||||
private $user;
|
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.
|
* Create a new notification instance.
|
||||||
*
|
*
|
||||||
|
@ -35,15 +23,7 @@ class WelcomeMessage extends Notification implements ShouldQueue
|
||||||
*/
|
*/
|
||||||
public function __construct(User $user)
|
public function __construct(User $user)
|
||||||
{
|
{
|
||||||
$general_settings= new GeneralSettings();
|
|
||||||
$user_settings = new UserSettings();
|
|
||||||
|
|
||||||
$this->user = $user;
|
$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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -60,18 +40,18 @@ class WelcomeMessage extends Notification implements ShouldQueue
|
||||||
public function AdditionalLines()
|
public function AdditionalLines()
|
||||||
{
|
{
|
||||||
$AdditionalLine = '';
|
$AdditionalLine = '';
|
||||||
if ($this->credits_reward_after_verify_email != 0) {
|
if (config('SETTINGS::USER: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 />';
|
$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->server_limit_after_verify_email != 0) {
|
if (config('SETTINGS::USER:SERVER_LIMIT_REWARD_AFTER_VERIFY_EMAIL') != 0) {
|
||||||
$AdditionalLine .= __('Verifying your e-mail will also increase your Server Limit by ').$this->server_limit_after_verify_email.'. <br />';
|
$AdditionalLine .= __('Verifying your e-mail will also increase your Server Limit by ').config('SETTINGS::USER:SERVER_LIMIT_REWARD_AFTER_VERIFY_EMAIL').'. <br />';
|
||||||
}
|
}
|
||||||
$AdditionalLine .= '<br />';
|
$AdditionalLine .= '<br />';
|
||||||
if ($this->credits_reward_after_verify_discord != 0) {
|
if (config('SETTINGS::USER: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 />';
|
$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->server_limit_after_verify_discord != 0) {
|
if (config('SETTINGS::USER:SERVER_LIMIT_REWARD_AFTER_VERIFY_DISCORD') != 0) {
|
||||||
$AdditionalLine .= __('Verifying your Discord account will also increase your Server Limit by ').$this->server_limit_after_verify_discord.'. <br />';
|
$AdditionalLine .= __('Verifying your Discord account will also increase your Server Limit by ').config('SETTINGS::USER:SERVER_LIMIT_REWARD_AFTER_VERIFY_DISCORD').'. <br />';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $AdditionalLine;
|
return $AdditionalLine;
|
||||||
|
|
|
@ -2,19 +2,17 @@
|
||||||
|
|
||||||
namespace App\Providers;
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use App\Models\Settings;
|
||||||
use App\Models\UsefulLink;
|
use App\Models\UsefulLink;
|
||||||
use App\Settings\GeneralSettings;
|
|
||||||
use App\Settings\MailSettings;
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Pagination\Paginator;
|
use Illuminate\Pagination\Paginator;
|
||||||
|
use Illuminate\Support\Facades\Artisan;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Support\Facades\Schema;
|
use Illuminate\Support\Facades\Schema;
|
||||||
use Illuminate\Support\Facades\URL;
|
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
use Qirolab\Theme\Theme;
|
use Qirolab\Theme\Theme;
|
||||||
|
|
||||||
|
|
||||||
class AppServiceProvider extends ServiceProvider
|
class AppServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -56,12 +54,79 @@ class AppServiceProvider extends ServiceProvider
|
||||||
return $ok;
|
return $ok;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Force HTTPS if APP_URL is set to https
|
try {
|
||||||
if (config('app.url') && parse_url(config('app.url'), PHP_URL_SCHEME) === 'https') {
|
if (Schema::hasColumn('useful_links', 'position')) {
|
||||||
URL::forceScheme('https');
|
$useful_links = UsefulLink::where("position", "like", "%topbar%")->get()->sortby("id");
|
||||||
|
view()->share('useful_links', $useful_links);
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
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');
|
||||||
}
|
}
|
||||||
|
|
||||||
//get the Github Branch the panel is running on
|
|
||||||
try {
|
try {
|
||||||
$stringfromfile = file(base_path() . '/.git/HEAD');
|
$stringfromfile = file(base_path() . '/.git/HEAD');
|
||||||
|
|
||||||
|
@ -76,35 +141,14 @@ class AppServiceProvider extends ServiceProvider
|
||||||
}
|
}
|
||||||
config(['BRANCHNAME' => $branchname]);
|
config(['BRANCHNAME' => $branchname]);
|
||||||
|
|
||||||
// Do not run this code if no APP_KEY is set
|
// Set Discord-API Config
|
||||||
if (config('app.key') == null) return;
|
config(['services.discord.client_id' => config('SETTINGS::DISCORD:CLIENT_ID')]);
|
||||||
|
config(['services.discord.client_secret' => config('SETTINGS::DISCORD:CLIENT_SECRET')]);
|
||||||
try {
|
|
||||||
if (Schema::hasColumn('useful_links', 'position')) {
|
|
||||||
$useful_links = UsefulLink::where("position", "like", "%topbar%")->get()->sortby("id");
|
|
||||||
view()->share('useful_links', $useful_links);
|
|
||||||
}
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Log::error("Couldnt find useful_links. Probably the installation is not completet. " . $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);
|
||||||
try {
|
|
||||||
$generalSettings = $this->app->make(GeneralSettings::class);
|
|
||||||
if (!file_exists(base_path('themes') . "/" . $generalSettings->theme)) {
|
|
||||||
$generalSettings->theme = "default";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($generalSettings->theme && $generalSettings->theme !== config('theme.active')) {
|
|
||||||
Theme::set($generalSettings->theme, "default");
|
|
||||||
} else {
|
|
||||||
Theme::set("default", "default");
|
|
||||||
}
|
|
||||||
|
|
||||||
$settings = $this->app->make(MailSettings::class);
|
|
||||||
$settings->setConfig();
|
|
||||||
} catch (Exception $e) {
|
|
||||||
Log::error("Couldnt load Settings. Probably the installation is not completet. " . $e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,17 +4,15 @@ namespace App\Providers;
|
||||||
|
|
||||||
use App\Events\PaymentEvent;
|
use App\Events\PaymentEvent;
|
||||||
use App\Events\UserUpdateCreditsEvent;
|
use App\Events\UserUpdateCreditsEvent;
|
||||||
use App\Events\CouponUsedEvent;
|
|
||||||
use App\Listeners\CouponUsed;
|
|
||||||
use App\Listeners\CreateInvoice;
|
use App\Listeners\CreateInvoice;
|
||||||
use App\Listeners\UnsuspendServers;
|
use App\Listeners\UnsuspendServers;
|
||||||
use App\Listeners\UserPayment;
|
use App\Listeners\UserPayment;
|
||||||
use App\Listeners\Verified as ListenerVerified;
|
use App\Listeners\Verified as VerifiedListener;
|
||||||
use Illuminate\Auth\Events\Registered;
|
use Illuminate\Auth\Events\Registered;
|
||||||
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
|
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
|
||||||
use Illuminate\Auth\Events\Verified;
|
|
||||||
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
||||||
use SocialiteProviders\Manager\SocialiteWasCalled;
|
use SocialiteProviders\Manager\SocialiteWasCalled;
|
||||||
|
use Illuminate\Auth\Events\Verified;
|
||||||
|
|
||||||
class EventServiceProvider extends ServiceProvider
|
class EventServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
|
@ -34,15 +32,12 @@ class EventServiceProvider extends ServiceProvider
|
||||||
CreateInvoice::class,
|
CreateInvoice::class,
|
||||||
UserPayment::class,
|
UserPayment::class,
|
||||||
],
|
],
|
||||||
CouponUsedEvent::class => [
|
|
||||||
CouponUsed::class
|
|
||||||
],
|
|
||||||
SocialiteWasCalled::class => [
|
SocialiteWasCalled::class => [
|
||||||
// ... other providers
|
// ... other providers
|
||||||
'SocialiteProviders\\Discord\\DiscordExtendSocialite@handle',
|
'SocialiteProviders\\Discord\\DiscordExtendSocialite@handle',
|
||||||
],
|
],
|
||||||
Verified::class => [
|
Verified::class => [
|
||||||
ListenerVerified::class,
|
VerifiedListener::class,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -1,64 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Settings;
|
|
||||||
|
|
||||||
use Spatie\LaravelSettings\Settings;
|
|
||||||
|
|
||||||
class CouponSettings extends Settings
|
|
||||||
{
|
|
||||||
public bool $enabled;
|
|
||||||
public bool $delete_coupon_on_expires;
|
|
||||||
public bool $delete_coupon_on_uses_reached;
|
|
||||||
public ?int $max_uses_per_user;
|
|
||||||
|
|
||||||
public static function group(): string
|
|
||||||
{
|
|
||||||
return 'coupon';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Summary of validations array
|
|
||||||
* @return array<string, string>
|
|
||||||
*/
|
|
||||||
public static function getValidations()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'enabled' => "nullable|boolean",
|
|
||||||
'delete_coupon_on_expires' => 'nullable|boolean',
|
|
||||||
'delete_coupon_on_uses_reached' => 'nullable|boolean',
|
|
||||||
'max_uses_per_user' => 'nullable|integer',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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-ticket-alt",
|
|
||||||
'enabled' => [
|
|
||||||
'label' => 'Enable Coupons',
|
|
||||||
'type' => 'boolean',
|
|
||||||
'description' => 'Enables coupons to be used in the store.'
|
|
||||||
],
|
|
||||||
'delete_coupon_on_expires' => [
|
|
||||||
'label' => 'Auto Delete Expired Coupons',
|
|
||||||
'type' => 'boolean',
|
|
||||||
'description' => 'Automatically deletes the coupon if it expires.'
|
|
||||||
],
|
|
||||||
'delete_coupon_on_uses_reached' => [
|
|
||||||
'label' => 'Delete Coupon When Max Uses Reached',
|
|
||||||
'type' => 'boolean',
|
|
||||||
'description' => 'Delete a coupon as soon as its maximum usage is reached.'
|
|
||||||
],
|
|
||||||
'max_uses_per_user' => [
|
|
||||||
'label' => 'Max Uses Per User',
|
|
||||||
'type' => 'number',
|
|
||||||
'description' => 'Maximum number of uses that a user can make of the same coupon.'
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,78 +0,0 @@
|
||||||
<?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';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.',
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,132 +0,0 @@
|
||||||
<?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';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Summary of validations array
|
|
||||||
* @return array<string, string>
|
|
||||||
*/
|
|
||||||
public static function getValidations()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'store_enabled' => 'nullable|string',
|
|
||||||
'credits_display_name' => 'required|string',
|
|
||||||
'recaptcha_enabled' => 'nullable|string',
|
|
||||||
'recaptcha_site_key' => 'nullable|string',
|
|
||||||
'recaptcha_secret_key' => 'nullable|string',
|
|
||||||
'phpmyadmin_url' => 'nullable|string',
|
|
||||||
'alert_enabled' => 'nullable|string',
|
|
||||||
'alert_type' => 'required|in:primary,secondary,success,danger,warning,info',
|
|
||||||
'alert_message' => 'nullable|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' => 'textarea',
|
|
||||||
'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.'
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,92 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Settings;
|
|
||||||
|
|
||||||
use Spatie\LaravelSettings\Settings;
|
|
||||||
|
|
||||||
class InvoiceSettings extends Settings
|
|
||||||
{
|
|
||||||
public bool $enabled;
|
|
||||||
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 ?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|string',
|
|
||||||
'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.',
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
<?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' => 'array|required',
|
|
||||||
'clients_can_change' => 'nullable|string',
|
|
||||||
'datatables' => 'nullable|string',
|
|
||||||
'default' => 'required|in:' . implode(',', config('app.available_locales')),
|
|
||||||
'dynamic' => '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-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'),
|
|
||||||
'identifier' => 'display'
|
|
||||||
],
|
|
||||||
'dynamic' => [
|
|
||||||
'label' => 'Dynamic Locale',
|
|
||||||
'type' => 'boolean',
|
|
||||||
'description' => 'Whether to use the dynamic locale.',
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue