diff --git a/app/Http/Controllers/Api/NotificationController.php b/app/Http/Controllers/Api/NotificationController.php index ceecbb24..9f187e9d 100644 --- a/app/Http/Controllers/Api/NotificationController.php +++ b/app/Http/Controllers/Api/NotificationController.php @@ -6,11 +6,13 @@ use App\Http\Controllers\Controller; use App\Models\DiscordUser; use App\Models\User; use App\Notifications\DynamicNotification; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Support\Facades\Notification; use Illuminate\Support\HtmlString; +use Illuminate\Validation\ValidationException; use Spatie\ValidationRules\Rules\Delimited; class NotificationController extends Controller @@ -61,13 +63,14 @@ class NotificationController extends Controller $data = $request->validate([ "via" => ["required", new Delimited("in:mail,database")], "all" => "required_without:users|boolean", - "users" => ["required_without:all", new Delimited("exists:users,id")], + "users" => ["required_without:all"], "title" => "required|string|min:1", "content" => "required|string|min:1" ]); $via = explode(",", $data["via"]); $mail = null; $database = null; + if (in_array("database", $via)) { $database = [ "title" => $data["title"], @@ -79,10 +82,28 @@ class NotificationController extends Controller ->subject($data["title"]) ->line(new HtmlString($data["content"])); } + $all = $data["all"] ?? false; - $users = $all ? User::all() : User::whereIn("id", explode(",", $data["users"]))->get(); + if ($all) { + $users = User::all(); + } else { + $userIds = explode(",", $data["users"]); + $users = User::query() + ->whereIn("id", $userIds) + ->orWhereHas('discordUser' , function (Builder $builder) use ($userIds) { + $builder->whereIn('id' , $userIds); + }) + ->get(); + } + + if ($users->count() == 0) { + throw ValidationException::withMessages([ + 'users' => ['No users found!'], + ]); + } + Notification::send($users, new DynamicNotification($via, $database, $mail)); - return response()->json(["message" => "Notification successfully sent."]); + return response()->json(["message" => "Notification successfully sent.", 'user_count' => $users->count()]); } /** diff --git a/app/Http/Controllers/Api/ServerController.php b/app/Http/Controllers/Api/ServerController.php index fcfa1b14..17e2be74 100644 --- a/app/Http/Controllers/Api/ServerController.php +++ b/app/Http/Controllers/Api/ServerController.php @@ -6,11 +6,16 @@ use App\Http\Controllers\Controller; use App\Models\Server; use Exception; use Illuminate\Contracts\Pagination\LengthAwarePaginator; +use Illuminate\Database\Eloquent\Collection; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; +use Spatie\QueryBuilder\QueryBuilder; class ServerController extends Controller { + const ALLOWED_INCLUDES = ['product', 'user']; + const ALLOWED_FILTERS = ['name', 'suspended', 'identifier', 'pterodactyl_id', 'user_id' , 'product_id']; + /** * Display a listing of the resource. * @@ -19,19 +24,29 @@ class ServerController extends Controller */ public function index(Request $request) { - return Server::with('product')->paginate($request->query('per_page') ?? 50); + $query = QueryBuilder::for(Server::class) + ->allowedIncludes(self::ALLOWED_INCLUDES) + ->allowedFilters(self::ALLOWED_FILTERS); + + return $query->paginate($request->input('per_page') ?? 50); } + + /** * Display the specified resource. * * @param Server $server - * @return Server + * @return Server|Collection */ public function show(Server $server) { - return $server->load('product'); + $query = QueryBuilder::for(Server::class) + ->where('id' ,'=' , $server->id) + ->allowedIncludes(self::ALLOWED_INCLUDES); + + return $query->get(); } diff --git a/app/Http/Controllers/Api/UserController.php b/app/Http/Controllers/Api/UserController.php index 0862950b..f01abf67 100644 --- a/app/Http/Controllers/Api/UserController.php +++ b/app/Http/Controllers/Api/UserController.php @@ -2,8 +2,10 @@ namespace App\Http\Controllers\Api; +use App\Classes\Pterodactyl; use App\Events\UserUpdateCreditsEvent; use App\Http\Controllers\Controller; +use App\Models\Configuration; use App\Models\DiscordUser; use App\Models\User; use Illuminate\Contracts\Foundation\Application; @@ -11,16 +13,21 @@ use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Contracts\Routing\ResponseFactory; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection; +use Illuminate\Http\Client\RequestException; use Illuminate\Http\Request; use Illuminate\Http\Response; +use Illuminate\Support\Facades\App; +use Illuminate\Support\Facades\Hash; +use Illuminate\Support\Str; use Illuminate\Validation\Rule; use Illuminate\Validation\ValidationException; use Spatie\QueryBuilder\QueryBuilder; class UserController extends Controller { - const ALLOWED_INCLUDES = ['servers', 'payments', 'vouchers', 'discordUser']; - const ALLOWED_FILTERS = ['email', 'pterodactyl_id', 'role', '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. * @@ -46,14 +53,14 @@ class UserController extends Controller public function show(int $id) { $discordUser = DiscordUser::find($id); - $user = $discordUser ? $discordUser->user : User::findOrFail($id); + $user = $discordUser ? $discordUser->user : User::findOrFail($id); $query = QueryBuilder::for($user) ->with('discordUser') ->allowedIncludes(self::ALLOWED_INCLUDES) - ->where('users.id' , '=' , $id) - ->orWhereHas('discordUser' , function (Builder $builder) use ($id) { - $builder->where('id' , '=' , $id); + ->where('users.id', '=', $id) + ->orWhereHas('discordUser', function (Builder $builder) use ($id) { + $builder->where('id', '=', $id); }); return $query->get(); @@ -158,6 +165,51 @@ class UserController extends Controller return $user; } + /** + * @throws RequestException + */ + public function store(Request $request) + { + $request->validate([ + 'name' => ['required', 'string', 'max:30', 'min:4', 'alpha_num', 'unique:users'], + 'email' => ['required', 'string', 'email', 'max:64', 'unique:users'], + 'password' => ['required', 'string', 'min:8', 'max:191'], + ]); + + $user = User::create([ + 'name' => $request->input('name'), + 'email' => $request->input('email'), + 'credits' => Configuration::getValueByKey('INITIAL_CREDITS', 150), + 'server_limit' => Configuration::getValueByKey('INITIAL_SERVER_LIMIT', 1), + 'password' => Hash::make($request->input('password')), + ]); + + $response = Pterodactyl::client()->post('/application/users', [ + "external_id" => App::environment('local') ? Str::random(16) : (string)$user->id, + "username" => $user->name, + "email" => $user->email, + "first_name" => $user->name, + "last_name" => $user->name, + "password" => $request->input('password'), + "root_admin" => false, + "language" => "en" + ]); + + if ($response->failed()) { + $user->delete(); + throw ValidationException::withMessages([ + 'pterodactyl_error_message' => $response->toException()->getMessage(), + 'pterodactyl_error_status' => $response->toException()->getCode() + ]); + } + + $user->update([ + 'pterodactyl_id' => $response->json()['attributes']['id'] + ]); + + return $user; + } + /** * Remove the specified resource from storage. * diff --git a/app/Http/Controllers/Api/VoucherController.php b/app/Http/Controllers/Api/VoucherController.php index f7acfdd5..3e005219 100644 --- a/app/Http/Controllers/Api/VoucherController.php +++ b/app/Http/Controllers/Api/VoucherController.php @@ -3,22 +3,32 @@ namespace App\Http\Controllers\Api; use App\Http\Controllers\Controller; +use App\Models\Server; use App\Models\Voucher; use Illuminate\Contracts\Pagination\LengthAwarePaginator; +use Illuminate\Database\Eloquent\Collection; use Illuminate\Http\Request; use Illuminate\Http\Response; use Illuminate\Validation\Rule; +use Spatie\QueryBuilder\QueryBuilder; class VoucherController extends Controller { + const ALLOWED_INCLUDES = ['users']; + const ALLOWED_FILTERS = ['code', 'memo', 'credits', 'uses']; + /** * Display a listing of the resource. * - * @return Response + * @return LengthAwarePaginator */ public function index(Request $request) { - return Voucher::paginate($request->query('per_page') ?? 50); + $query = QueryBuilder::for(Voucher::class) + ->allowedIncludes(self::ALLOWED_INCLUDES) + ->allowedFilters(self::ALLOWED_FILTERS); + + return $query->paginate($request->input('per_page') ?? 50); } /** @@ -40,10 +50,10 @@ class VoucherController extends Controller public function store(Request $request) { $request->validate([ - 'memo' => 'nullable|string|max:191', - 'code' => 'required|string|alpha_dash|max:36|min:4|unique:vouchers', - 'uses' => 'required|numeric|max:2147483647|min:1', - 'credits' => 'required|numeric|between:0,99999999', + 'memo' => 'nullable|string|max:191', + '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|multiple_date_format:d-m-Y H:i:s,d-m-Y|after:now|before:10 years' ]); @@ -54,11 +64,15 @@ class VoucherController extends Controller * Display the specified resource. * * @param int $id - * @return Response + * @return Collection|Voucher */ public function show(int $id) { - return Voucher::findOrFail($id); + $query = QueryBuilder::for(Voucher::class) + ->where('id' ,'=' , $id) + ->allowedIncludes(self::ALLOWED_INCLUDES); + + return $query->get(); } /** @@ -84,10 +98,10 @@ class VoucherController extends Controller $voucher = Voucher::findOrFail($id); $request->validate([ - 'memo' => 'nullable|string|max:191', - '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', + 'memo' => 'nullable|string|max:191', + '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|multiple_date_format:d-m-Y H:i:s,d-m-Y|after:now|before:10 years' ]); diff --git a/routes/api.php b/routes/api.php index c964be38..bf9bc7d0 100644 --- a/routes/api.php +++ b/routes/api.php @@ -20,7 +20,7 @@ use Illuminate\Support\Facades\Route; Route::middleware('api.token')->group(function () { Route::patch('/users/{user}/increment', [UserController::class, 'increment']); Route::patch('/users/{user}/decrement', [UserController::class, 'decrement']); - Route::resource('users', UserController::class)->except(['store', 'create']); + Route::resource('users', UserController::class)->except(['create']); Route::patch('/servers/{server}/suspend', [ServerController::class, 'suspend']); Route::patch('/servers/{server}/unsuspend', [ServerController::class, 'unSuspend']);