diff --git a/.env.example b/.env.example index 94676473..c7016a83 100644 --- a/.env.example +++ b/.env.example @@ -3,6 +3,8 @@ APP_ENV=production APP_KEY= APP_DEBUG=false APP_URL=http://localhost +#list with timezones https://www.php.net/manual/en/timezones.php +APP_TIMEZONE=UTC DB_CONNECTION=mysql DB_HOST=127.0.0.1 @@ -31,8 +33,8 @@ DISCORD_GUILD_ID= DISCORD_ROLE_ID= #nesseary URL's -PTERODACTYL_URL=https://panel.bitsec.dev -PHPMYADMIN_URL=https://mysql.bitsec.dev +PTERODACTYL_URL=https://panel.controlpanel.gg +PHPMYADMIN_URL=https://mysql.controlpanel.gg #optional. remove to remove database button DISCORD_INVITE_URL=https://discord.gg/vrUYdxG4wZ #GOOGLE RECAPTCHA diff --git a/app/Classes/Pterodactyl.php b/app/Classes/Pterodactyl.php index a48b569f..22bce864 100644 --- a/app/Classes/Pterodactyl.php +++ b/app/Classes/Pterodactyl.php @@ -11,6 +11,7 @@ use Exception; use Illuminate\Http\Client\PendingRequest; use Illuminate\Http\Client\Response; use Illuminate\Support\Facades\Http; +use Illuminate\Validation\Validator; class Pterodactyl { @@ -34,9 +35,8 @@ class Pterodactyl */ public function getUser(int $pterodactylId){ $response = self::client()->get("/application/users/{$pterodactylId}"); - if ($response->failed()) { - return []; - } + + if ($response->failed()) return $response->json(); return $response->json()['attributes']; } diff --git a/app/Console/Commands/MakeUserCommand.php b/app/Console/Commands/MakeUserCommand.php index ef3b1372..a06f0d18 100644 --- a/app/Console/Commands/MakeUserCommand.php +++ b/app/Console/Commands/MakeUserCommand.php @@ -6,6 +6,8 @@ use App\Classes\Pterodactyl; use App\Models\User; use Illuminate\Console\Command; use Illuminate\Support\Facades\Hash; +use Illuminate\Support\Facades\Validator; +use Illuminate\Validation\ValidationException; class MakeUserCommand extends Command { @@ -44,26 +46,37 @@ class MakeUserCommand extends Command public function handle() { $ptero_id = $this->option('ptero_id') ?? $this->ask('Please specify your Pterodactyl ID.'); - $password = $this->option('password') ?? $this->ask('Please specify your password.'); + $password = $this->secret('password') ?? $this->ask('Please specify your password.'); - if (strlen($password) < 8) { - $this->alert('Your password need to be at least 8 characters long'); + // Validate user input + $validator = Validator::make([ + 'ptero_id' => $ptero_id, + 'password' => $password, + ], [ + 'ptero_id' => 'required|numeric|integer|min:1|max:2147483647', + 'password' => 'required|string|min:8|max:60', + ]); + + if ($validator->fails()) { + $this->error($validator->errors()->first()); return 0; } //TODO: Do something with response (check for status code and give hints based upon that) $response = $this->pterodactyl->getUser($ptero_id); - if ($response === []) { - $this->alert('It seems that your Pterodactyl ID is not correct. Rerun the command and input an correct ID'); + if (isset($response['errors'])) { + if (isset($response['errors'][0]['code'])) $this->error("code: {$response['errors'][0]['code']}"); + if (isset($response['errors'][0]['status'])) $this->error("status: {$response['errors'][0]['status']}"); + if (isset($response['errors'][0]['detail'])) $this->error("detail: {$response['errors'][0]['detail']}"); return 0; } $user = User::create([ - 'name' => $response['first_name'], - 'email' => $response['email'], - 'role' => 'admin', - 'password' => Hash::make($password), + 'name' => $response['first_name'], + 'email' => $response['email'], + 'role' => 'admin', + 'password' => Hash::make($password), 'pterodactyl_id' => $response['id'] ]); diff --git a/app/Http/Controllers/Admin/ServerController.php b/app/Http/Controllers/Admin/ServerController.php index 0a1d98b6..6d333feb 100644 --- a/app/Http/Controllers/Admin/ServerController.php +++ b/app/Http/Controllers/Admin/ServerController.php @@ -90,8 +90,12 @@ class ServerController extends Controller */ public function destroy(Server $server) { - $server->delete(); - return redirect()->back()->with('success', 'server has been removed!'); + try { + $server->delete(); + return redirect()->route('admin.servers.index')->with('success', 'server removed'); + } catch (Exception $e) { + return redirect()->route('admin.servers.index')->with('error', 'An exception has occurred while trying to remove a resource "' . $e->getMessage() . '"'); + } } /** diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php index 88af1963..bc480aab 100644 --- a/app/Http/Controllers/Admin/UserController.php +++ b/app/Http/Controllers/Admin/UserController.php @@ -112,13 +112,12 @@ class UserController extends Controller "role" => Rule::in(['admin', 'mod', 'client', 'member']), ]); - if (empty($this->pterodactyl->getUser($request->input('pterodactyl_id')))) { + if (isset($this->pterodactyl->getUser($request->input('pterodactyl_id'))['errors'])) { throw ValidationException::withMessages([ 'pterodactyl_id' => ["User does not exists on pterodactyl's panel"] ]); } - if (!is_null($request->input('new_password'))) { $request->validate([ 'new_password' => 'required|string|min:8', diff --git a/app/Http/Controllers/Admin/VoucherController.php b/app/Http/Controllers/Admin/VoucherController.php index e1a71580..cf1b8600 100644 --- a/app/Http/Controllers/Admin/VoucherController.php +++ b/app/Http/Controllers/Admin/VoucherController.php @@ -45,10 +45,10 @@ class VoucherController extends Controller { $request->validate([ 'memo' => 'nullable|string|max:191', - 'code' => 'required|string|alpha_dash|max:36|min:4', + 'code' => 'required|string|alpha_dash|max:36|min:4|unique:vouchers', 'uses' => 'required|numeric|max:2147483647|min:1', 'credits' => 'required|numeric|between:0,99999999', - 'expires_at' => ['nullable','date_format:d-m-Y','after:today',"before:10 years"], + 'expires_at' => 'nullable|multiple_date_format:d-m-Y H:i:s,d-m-Y|after:now|before:10 years', ]); Voucher::create($request->except('_token')); @@ -75,7 +75,7 @@ class VoucherController extends Controller */ public function edit(Voucher $voucher) { - return view('admin.vouchers.edit' , [ + return view('admin.vouchers.edit', [ 'voucher' => $voucher ]); } @@ -91,10 +91,10 @@ class VoucherController extends Controller { $request->validate([ 'memo' => 'nullable|string|max:191', - 'code' => 'required|string|alpha_dash|max:36|min:4', + 'code' => "required|string|alpha_dash|max:36|min:4|unique:vouchers,code,{$voucher->id}", 'uses' => 'required|numeric|max:2147483647|min:1', 'credits' => 'required|numeric|between:0,99999999', - 'expires_at' => ['nullable','date_format:d-m-Y','after:today',"before:10 years"], + 'expires_at' => 'nullable|multiple_date_format:d-m-Y H:i:s,d-m-Y|after:now|before:10 years', ]); $voucher->update($request->except('_token')); @@ -127,7 +127,7 @@ class VoucherController extends Controller ]); #get voucher by code - $voucher = Voucher::where('code' , '=' , $request->input('code'))->firstOrFail(); + $voucher = Voucher::where('code', '=', $request->input('code'))->firstOrFail(); #extra validations if ($voucher->getStatus() == 'USES_LIMIT_REACHED') throw ValidationException::withMessages([ @@ -138,19 +138,19 @@ class VoucherController extends Controller 'code' => 'This voucher has expired' ]); - if (!$request->user()->vouchers()->where('id' , '=' , $voucher->id)->get()->isEmpty()) throw ValidationException::withMessages([ + if (!$request->user()->vouchers()->where('id', '=', $voucher->id)->get()->isEmpty()) throw ValidationException::withMessages([ 'code' => 'You already redeemed this voucher code' ]); if ($request->user()->credits + $voucher->credits >= 99999999) throw ValidationException::withMessages([ - 'code' => "You can't redeem this voucher because you would exceed the credit limit" + 'code' => "You can't redeem this voucher because you would exceed the ".CREDITS_DISPLAY_NAME." limit" ]); #redeem voucher $voucher->redeem($request->user()); return response()->json([ - 'success' => "{$voucher->credits} credits have been added to your balance!" + 'success' => "{$voucher->credits} ".CREDITS_DISPLAY_NAME." have been added to your balance!" ]); } @@ -191,5 +191,4 @@ class VoucherController extends Controller ->rawColumns(['actions', 'code', 'status']) ->make(); } - } diff --git a/app/Http/Controllers/Api/UserController.php b/app/Http/Controllers/Api/UserController.php index 7c905328..126a55b7 100644 --- a/app/Http/Controllers/Api/UserController.php +++ b/app/Http/Controllers/Api/UserController.php @@ -10,6 +10,7 @@ use Illuminate\Contracts\Routing\ResponseFactory; use Illuminate\Http\Request; use Illuminate\Http\Response; use Illuminate\Validation\Rule; +use Illuminate\Validation\ValidationException; class UserController extends Controller { @@ -63,11 +64,81 @@ class UserController extends Controller return $user; } + /** + * increments the users credits or/and server_limit + * + * @param Request $request + * @param int $id + * @return User + * @throws ValidationException + */ + public function increment(Request $request, int $id) + { + $discordUser = DiscordUser::find($id); + $user = $discordUser ? $discordUser->user : User::findOrFail($id); + + $request->validate([ + "credits" => "sometimes|numeric|min:0|max:1000000", + "server_limit" => "sometimes|numeric|min:0|max:1000000", + ]); + + if($request->credits){ + if ($user->credits + $request->credits >= 99999999) throw ValidationException::withMessages([ + 'credits' => "You can't add this amount of credits because you would exceed the credit limit" + ]); + $user->increment('credits', $request->credits); + } + + if($request->server_limit){ + if ($user->server_limit + $request->server_limit >= 2147483647) throw ValidationException::withMessages([ + 'server_limit' => "You cannot add this amount of servers because it would exceed the server limit." + ]); + $user->increment('server_limit', $request->server_limit); + } + + return $user; + } + + /** + * decrements the users credits or/and server_limit + * + * @param Request $request + * @param int $id + * @return User + * @throws ValidationException + */ + public function decrement(Request $request, int $id) + { + $discordUser = DiscordUser::find($id); + $user = $discordUser ? $discordUser->user : User::findOrFail($id); + + $request->validate([ + "credits" => "sometimes|numeric|min:0|max:1000000", + "server_limit" => "sometimes|numeric|min:0|max:1000000", + ]); + + if($request->credits){ + if($user->credits - $request->credits < 0) throw ValidationException::withMessages([ + 'credits' => "You can't remove this amount of credits because you would exceed the minimum credit limit" + ]); + $user->decrement('credits', $request->credits); + } + + if($request->server_limit){ + if($user->server_limit - $request->server_limit < 0) throw ValidationException::withMessages([ + 'server_limit' => "You cannot remove this amount of servers because it would exceed the minimum server." + ]); + $user->decrement('server_limit', $request->server_limit); + } + + return $user; + } + /** * Remove the specified resource from storage. * * @param int $id - * @return Application|ResponseFactory|Response|void + * @return Application|Response|ResponseFactory */ public function destroy(int $id) { diff --git a/app/Http/Controllers/Api/VoucherController.php b/app/Http/Controllers/Api/VoucherController.php index 99d9507a..f7acfdd5 100644 --- a/app/Http/Controllers/Api/VoucherController.php +++ b/app/Http/Controllers/Api/VoucherController.php @@ -41,10 +41,10 @@ class VoucherController extends Controller { $request->validate([ 'memo' => 'nullable|string|max:191', - 'code' => 'required|string|alpha_dash|max:36|min:4', + 'code' => 'required|string|alpha_dash|max:36|min:4|unique:vouchers', 'uses' => 'required|numeric|max:2147483647|min:1', 'credits' => 'required|numeric|between:0,99999999', - 'expires_at' => 'nullable|date_format:d-m-Y|after:today|before:10 years' + 'expires_at' => 'nullable|multiple_date_format:d-m-Y H:i:s,d-m-Y|after:now|before:10 years' ]); return Voucher::create($request->all()); @@ -85,10 +85,10 @@ class VoucherController extends Controller $request->validate([ 'memo' => 'nullable|string|max:191', - 'code' => 'required|string|alpha_dash|max:36|min:4', + 'code' => "required|string|alpha_dash|max:36|min:4|unique:vouchers,code,{$voucher->id}", 'uses' => 'required|numeric|max:2147483647|min:1', 'credits' => 'required|numeric|between:0,99999999', - 'expires_at' => 'nullable|date_format:d-m-Y|after:today|before:10 years' + 'expires_at' => 'nullable|multiple_date_format:d-m-Y H:i:s,d-m-Y|after:now|before:10 years' ]); $voucher->update($request->all()); diff --git a/app/Http/Controllers/ServerController.php b/app/Http/Controllers/ServerController.php index cf5db936..1ec74e14 100644 --- a/app/Http/Controllers/ServerController.php +++ b/app/Http/Controllers/ServerController.php @@ -88,7 +88,7 @@ class ServerController extends Controller //minimum credits if (Auth::user()->credits <= Configuration::getValueByKey('MINIMUM_REQUIRED_CREDITS_TO_MAKE_SERVER', 50)) { - return redirect()->route('servers.index')->with('error', "You do not have the required amount of credits to create a new server!"); + return redirect()->route('servers.index')->with('error', "You do not have the required amount of ".CREDITS_DISPLAY_NAME." to create a new server!"); } //Required Verification for creating an server @@ -111,7 +111,7 @@ class ServerController extends Controller $server->delete(); return redirect()->route('servers.index')->with('success', 'server removed'); } catch (Exception $e) { - return redirect()->route('servers.index')->with('error', 'An exception has occurred while trying to remove a resource'); + return redirect()->route('servers.index')->with('error', 'An exception has occurred while trying to remove a resource "' . $e->getMessage() . '"'); } } diff --git a/app/Http/Controllers/StoreController.php b/app/Http/Controllers/StoreController.php index 2aa0ed23..1b23d305 100644 --- a/app/Http/Controllers/StoreController.php +++ b/app/Http/Controllers/StoreController.php @@ -23,7 +23,7 @@ class StoreController extends Controller //Required Verification for creating an server if (Configuration::getValueByKey('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_DISPLAY_NAME."."); } return view('store.index')->with([ diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 5e7b9418..572a8656 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -3,6 +3,7 @@ namespace App\Http; use App\Http\Middleware\ApiAuthToken; +use App\Http\Middleware\CreditsDisplayName; use App\Http\Middleware\isAdmin; use App\Http\Middleware\LastSeen; use Illuminate\Foundation\Http\Kernel as HttpKernel; @@ -40,12 +41,14 @@ class Kernel extends HttpKernel \Illuminate\View\Middleware\ShareErrorsFromSession::class, \App\Http\Middleware\VerifyCsrfToken::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, - LastSeen::class + LastSeen::class, + CreditsDisplayName::class ], 'api' => [ 'throttle:api', \Illuminate\Routing\Middleware\SubstituteBindings::class, + CreditsDisplayName::class ], ]; diff --git a/app/Http/Middleware/CreditsDisplayName.php b/app/Http/Middleware/CreditsDisplayName.php new file mode 100644 index 00000000..a6962f41 --- /dev/null +++ b/app/Http/Middleware/CreditsDisplayName.php @@ -0,0 +1,23 @@ +role == 'admin') { + if (Auth::user() && Auth::user()->role == 'admin') { return $next($request); } diff --git a/app/Models/Server.php b/app/Models/Server.php index e48dc8a0..4d704cbe 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -70,7 +70,8 @@ class Server extends Model }); static::deleting(function (Server $server) { - Pterodactyl::client()->delete("/application/servers/{$server->pterodactyl_id}"); + $response = Pterodactyl::client()->delete("/application/servers/{$server->pterodactyl_id}"); + if ($response->failed() && !is_null($server->pterodactyl_id)) throw new Exception($response['errors'][0]['code']); }); } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 0224d58a..8aa705e0 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -4,6 +4,7 @@ namespace App\Providers; use Illuminate\Pagination\Paginator; use Illuminate\Support\Facades\Schema; +use Illuminate\Support\Facades\Validator; use Illuminate\Support\ServiceProvider; use Spatie\QueryBuilder\QueryBuilderRequest; @@ -29,5 +30,27 @@ class AppServiceProvider extends ServiceProvider Paginator::useBootstrap(); Schema::defaultStringLength(191); QueryBuilderRequest::setArrayValueDelimiter('|'); + + Validator::extend('multiple_date_format', function ($attribute, $value, $parameters, $validator) { + + $ok = true; + + $result = []; + + // iterate through all formats + foreach ($parameters as $parameter) { + + //validate with laravels standard date format validation + $result[] = $validator->validateDateFormat($attribute, $value, [$parameter]); + } + + //if none of result array is true. it sets ok to false + if (!in_array(true, $result)) { + $ok = false; + $validator->setCustomMessages(['multiple_date_format' => 'The format must be one of ' . join(",", $parameters)]); + } + + return $ok; + }); } } diff --git a/config/app.php b/config/app.php index d54c7e1d..11d8d417 100644 --- a/config/app.php +++ b/config/app.php @@ -67,7 +67,7 @@ return [ | */ - 'timezone' => 'UTC', + 'timezone' => env('APP_TIMEZONE', 'UTC'), /* |-------------------------------------------------------------------------- diff --git a/database/seeders/Seeds/ConfigurationSeeder.php b/database/seeders/Seeds/ConfigurationSeeder.php index 7dc5e46b..f84bdd26 100644 --- a/database/seeders/Seeds/ConfigurationSeeder.php +++ b/database/seeders/Seeds/ConfigurationSeeder.php @@ -119,6 +119,15 @@ class ConfigurationSeeder extends Seeder 'description' => 'The maximum amount of allocations to pull per node for automatic deployment, if more allocations are being used than this limit is set to, no new servers can be created!' ]); + //credits display name + Configuration::firstOrCreate([ + 'key' => 'CREDITS_DISPLAY_NAME', + ], [ + 'value' => 'Credits', + 'type' => 'string', + 'description' => 'Set the display name of your currency :)' + ]); + } } diff --git a/resources/views/admin/products/create.blade.php b/resources/views/admin/products/create.blade.php index 2a29bbe8..96935a55 100644 --- a/resources/views/admin/products/create.blade.php +++ b/resources/views/admin/products/create.blade.php @@ -53,7 +53,7 @@