OOM killer & Roles / Permissions API

This commit is contained in:
Dennis 2023-05-05 14:07:25 +02:00 committed by GitHub
commit ea554bf288
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 265 additions and 55 deletions

View file

@ -266,6 +266,7 @@ class PterodactylClient
'docker_image' => $egg->docker_image,
'startup' => $egg->startup,
'environment' => $egg->getEnvironmentVariables(),
'oom_disabled' => !$server->product->oom_killer,
'limits' => [
'memory' => $server->product->memory,
'swap' => $server->product->swap,
@ -378,6 +379,7 @@ class PterodactylClient
'io' => $product->io,
'cpu' => $product->cpu,
'threads' => null,
'oom_disabled' => !$server->product->oom_killer,
'feature_limits' => [
'databases' => $product->databases,
'backups' => $product->backups,

View file

@ -87,6 +87,7 @@ class ProductController extends Controller
'nodes.*' => 'required|exists:nodes,id',
'eggs.*' => 'required|exists:eggs,id',
'disabled' => 'nullable',
'oom_killer' => 'nullable',
]);
$disabled = ! is_null($request->input('disabled'));
@ -159,6 +160,7 @@ class ProductController extends Controller
'nodes.*' => 'required|exists:nodes,id',
'eggs.*' => 'required|exists:eggs,id',
'disabled' => 'nullable',
'oom_killer' => 'nullable',
]);
$disabled = ! is_null($request->input('disabled'));
@ -256,6 +258,9 @@ class ProductController extends Controller
->editColumn('minimum_credits', function (Product $product, UserSettings $user_settings) {
return $product->minimum_credits==-1 ? $user_settings->min_credits_to_make_server : $product->minimum_credits;
})
->editColumn('oom_killer', function (Product $product, UserSettings $user_settings) {
return $product->oom_killer ? __("enabled") : __("disabled");
})
->editColumn('created_at', function (Product $product) {
return $product->created_at ? $product->created_at->diffForHumans() : '';
})

View file

@ -0,0 +1,155 @@
<?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' => 'nullable|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) {
$role->givePermissionTo($request->permissions);
}
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' => 'nullable|string|max:191',
'color' => [
'required',
'regex:/^#([a-f0-9]{6}|[a-f0-9]{3})$/i'
],
'power' => 'required',
]);
if ($request->permissions) {
$role->givePermissionTo($request->permissions);
}
$role->update($request->all());
//TODO 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;
}
}

View file

@ -2,16 +2,12 @@
namespace App\Http\Controllers\Api;
use App\Classes\Pterodactyl;
use App\Events\UserUpdateCreditsEvent;
use App\Http\Controllers\Controller;
use App\Models\DiscordUser;
use App\Models\User;
use App\Notifications\ReferralNotification;
use App\Traits\Referral;
use App\Settings\PterodactylSettings;
use App\Classes\PterodactylClient;
use App\Settings\ReferralSettings;
use App\Settings\UserSettings;
use Carbon\Carbon;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
@ -31,18 +27,9 @@ use Spatie\QueryBuilder\QueryBuilder;
class UserController extends Controller
{
use Referral;
const ALLOWED_INCLUDES = ['servers', 'notifications', 'payments', 'vouchers', 'roles', 'discordUser'];
const ALLOWED_INCLUDES = ['servers', 'notifications', 'payments', 'vouchers', 'discordUser'];
const ALLOWED_FILTERS = ['name', 'server_limit', 'email', 'pterodactyl_id', 'role', 'suspended'];
private $pterodactyl;
public function __construct(PterodactylSettings $ptero_settings)
{
$this->pterodactyl = new PterodactylClient($ptero_settings);
}
const ALLOWED_FILTERS = ['name', 'server_limit', 'email', 'pterodactyl_id', 'suspended'];
/**
* Display a listing of the resource.
@ -98,14 +85,13 @@ class UserController extends Controller
'email' => 'sometimes|string|email',
'credits' => '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));
//Update Users Password on Pterodactyl
//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, [
'username' => $request->name,
'first_name' => $request->name,
'last_name' => $request->name,
@ -213,7 +199,7 @@ class UserController extends Controller
*
* @throws ValidationException
*/
public function suspend(int $id)
public function suspend(Request $request, int $id)
{
$discordUser = DiscordUser::find($id);
$user = $discordUser ? $discordUser->user : User::findOrFail($id);
@ -237,12 +223,12 @@ class UserController extends Controller
*
* @throws ValidationException
*/
public function unsuspend(int $id)
public function unsuspend(Request $request, int $id)
{
$discordUser = DiscordUser::find($id);
$user = $discordUser ? $discordUser->user : User::findOrFail($id);
if (!$user->isSuspended()) {
if (! $user->isSuspended()) {
throw ValidationException::withMessages([
'error' => 'You cannot unsuspend an User who is not suspended.',
]);
@ -253,10 +239,25 @@ class UserController extends Controller
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
*/
public function store(Request $request, UserSettings $user_settings, ReferralSettings $referral_settings)
public function store(Request $request)
{
$request->validate([
'name' => ['required', 'string', 'max:30', 'min:4', 'alpha_num', 'unique:users'],
@ -265,7 +266,7 @@ class UserController extends Controller
]);
// Prevent the creation of new users via API if this is enabled.
if (!$user_settings->creation_enabled) {
if (! config('SETTINGS::SYSTEM:CREATION_OF_NEW_USERS', 'true')) {
throw ValidationException::withMessages([
'error' => 'The creation of new users has been blocked by the system administrator.',
]);
@ -274,13 +275,13 @@ class UserController extends Controller
$user = User::create([
'name' => $request->input('name'),
'email' => $request->input('email'),
'credits' => $user_settings->initial_credits,
'server_limit' => $user_settings->initial_server_limit,
'credits' => config('SETTINGS::USER:INITIAL_CREDITS', 150),
'server_limit' => config('SETTINGS::USER:INITIAL_SERVER_LIMIT', 1),
'password' => Hash::make($request->input('password')),
'referral_code' => $this->createReferralCode(),
]);
$response = $this->pterodactyl->application->post('/application/users', [
$response = Pterodactyl::client()->post('/application/users', [
'external_id' => App::environment('local') ? Str::random(16) : (string) $user->id,
'username' => $user->name,
'email' => $user->email,
@ -303,12 +304,12 @@ class UserController extends Controller
'pterodactyl_id' => $response->json()['attributes']['id'],
]);
//INCREMENT REFERRAL-USER CREDITS
if (!empty($request->input('referral_code'))) {
if (! empty($request->input('referral_code'))) {
$ref_code = $request->input('referral_code');
$new_user = $user->id;
if ($ref_user = User::query()->where('referral_code', '=', $ref_code)->first()) {
if ($referral_settings->mode === 'register' || $referral_settings->mode === 'both') {
$ref_user->increment('credits', $referral_settings->reward);
if (config('SETTINGS::REFERRAL:MODE') == 'register' || config('SETTINGS::REFERRAL:MODE') == 'both') {
$ref_user->increment('credits', config('SETTINGS::REFERRAL::REWARD'));
$ref_user->notify(new ReferralNotification($ref_user->id, $new_user));
}
//INSERT INTO USER_REFERRALS TABLE

View file

@ -58,17 +58,13 @@ class TicketsController extends Controller
);
$ticket->save();
$user = Auth::user();
switch ($ticket_settings->notify) {
case 'all':
$admin = User::where('role', 'admin')->orWhere('role', 'mod')->get();
Notification::send($admin, new AdminCreateNotification($ticket, $user));
case 'admin':
$admin = User::where('role', 'admin')->get();
Notification::send($admin, new AdminCreateNotification($ticket, $user));
case 'moderator':
$admin = User::where('role', 'mod')->get();
Notification::send($admin, new AdminCreateNotification($ticket, $user));
$staffNotify = User::permission('admin.tickets.get_notification')->get();
foreach($staffNotify as $staff){
Notification::send($staff, new AdminCreateNotification($ticket, $user));
}
$user->notify(new CreateNotification($ticket));
return redirect()->route('ticket.index')->with('success', __('A ticket has been opened, ID: #') . $ticket->ticket_id);
@ -112,9 +108,12 @@ class TicketsController extends Controller
'message' => $request->input('message'),
]);
$user = Auth::user();
$admin = User::where('role', 'admin')->orWhere('role', 'mod')->get();
$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'));
}

View file

@ -7,7 +7,6 @@ use Spatie\LaravelSettings\Settings;
class TicketSettings extends Settings
{
public bool $enabled;
public string $notify;
public static function group(): string
{
@ -22,7 +21,6 @@ class TicketSettings extends Settings
{
return [
'enabled' => 'nullable|boolean',
'notify' => 'nullable|string',
];
}
@ -40,17 +38,6 @@ class TicketSettings extends Settings
'type' => 'boolean',
'description' => 'Enable or disable the ticket system.',
],
'notify' => [
'label' => 'Notify',
'type' => 'select',
'description' => 'Who will receive an E-Mail when a new Ticket is created.',
'options' => [
'admin' => 'Admins',
'moderator' => 'Moderators',
'all' => 'Admins and Moderators',
'none' => 'Nobody',
],
],
];
}
}

View file

@ -15,6 +15,7 @@ return [
'admin.ticket.read',
'admin.tickets.write',
'admin.tickets.get_notification',
'admin.ticket_blacklist.read',
'admin.ticket_blacklist.write',

View file

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('products', function (Blueprint $table) {
$table->boolean('oom_killer')->after("allocations")->default(false);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('products', function (Blueprint $table) {
$table->dropColumn('oom_killer');
});
}
};

View file

@ -131,7 +131,15 @@
</div>
@enderror
</div>
<div class="form-group">
<input type="checkbox" value="1" id="oom" name="oom_killer"
class="">
<label for="oom_killer">{{__('OOM Killer')}} <i
data-toggle="popover" data-trigger="hover"
data-content="{{__('Enable or Disable the OOM Killer for this Product.')}}"
class="fas fa-info-circle"></i></label>
</div>
</div>
<div class="col-lg-6">
<div class="form-group">

View file

@ -139,6 +139,16 @@
@enderror
</div>
<div class="form-group">
<input type="checkbox" @if($product->oom_killer) checked @endif value="1" id="oom" name="oom_killer"
class="">
<label for="oom_killer">{{__('OOM Killer')}} <i
data-toggle="popover" data-trigger="hover"
data-content="{{__('Enable or Disable the OOM Killer for this Product.')}}"
class="fas fa-info-circle"></i></label>
</div>
</div>
<div class="col-lg-6">
<div class="form-group">

View file

@ -53,6 +53,7 @@
<th>{{__('Nodes')}}</th>
<th>{{__('Eggs')}}</th>
<th>{{__('Min Credits')}}</th>
<th>{{__('OOM Killer')}}</th>
<th>{{__('Servers')}}</th>
<th>{{__('Created at')}}</th>
<th>{{ __('Actions') }}</th>
@ -101,6 +102,7 @@
{data: "nodes", sortable: false},
{data: "eggs", sortable: false},
{data: "minimum_credits"},
{data: "oom_killer"},
{data: "servers", sortable: false},
{data: "created_at"},
{data: "actions", sortable: false}

View file

@ -18,7 +18,7 @@
href="{{ \Illuminate\Support\Facades\Storage::disk('public')->exists('favicon.ico') ? asset('storage/favicon.ico') : asset('favicon.ico') }}"
type="image/x-icon">
<script src="{{ asset('plugins/alpinejs/3.12.0_cdn.min.js') }}"></script>
<script src="{{ asset('plugins/alpinejs/3.12.0_cdn.min.js') }}" defer></script>
{{-- <link rel="stylesheet" href="{{asset('css/adminlte.min.css')}}"> --}}
<link rel="stylesheet" href="{{ asset('plugins/datatables/jquery.dataTables.min.css') }}">
@ -507,6 +507,7 @@
<div class="content-wrapper">
<!--
@if (!Auth::user()->hasVerifiedEmail())
@if (Auth::user()->created_at->diffInHours(now(), false) > 1)
<div class="alert alert-warning p-2 m-2">
@ -518,6 +519,7 @@
</div>
@endif
@endif
-->
@yield('content')

View file

@ -201,6 +201,12 @@
{{ __('Databases') }}</span>
<span class="d-inline-block" x-text="product.databases"></span>
</li>
<li class="d-flex justify-content-between">
<span class="d-inline-block"><i class="fas fa-skull-crossbones"></i>
{{ __('OOM Killer') }}</span>
<span class="d-inline-block"
x-text="product.oom_killer == 1 ? 'enabled' : 'disabled'"></span>
</li>
<li class="d-flex justify-content-between">
<span class="d-inline-block"><i class="fas fa-network-wired"></i>
{{ __('Allocations') }}