UserController.php 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. <?php
  2. namespace App\Http\Controllers\Api;
  3. use App\Classes\Pterodactyl;
  4. use App\Events\UserUpdateCreditsEvent;
  5. use App\Http\Controllers\Controller;
  6. use App\Models\DiscordUser;
  7. use App\Models\Settings;
  8. use App\Models\User;
  9. use Illuminate\Contracts\Foundation\Application;
  10. use Illuminate\Contracts\Pagination\LengthAwarePaginator;
  11. use Illuminate\Contracts\Routing\ResponseFactory;
  12. use Illuminate\Database\Eloquent\Builder;
  13. use Illuminate\Database\Eloquent\Collection;
  14. use Illuminate\Database\Eloquent\Model;
  15. use Illuminate\Http\Request;
  16. use Illuminate\Http\Response;
  17. use Illuminate\Support\Facades\App;
  18. use Illuminate\Support\Facades\Hash;
  19. use Illuminate\Support\Str;
  20. use Illuminate\Validation\Rule;
  21. use Illuminate\Validation\ValidationException;
  22. use Spatie\QueryBuilder\QueryBuilder;
  23. class UserController extends Controller
  24. {
  25. const ALLOWED_INCLUDES = ['servers', 'notifications', 'payments', 'vouchers', 'discordUser'];
  26. const ALLOWED_FILTERS = ['name', 'server_limit', 'email', 'pterodactyl_id', 'role', 'suspended'];
  27. /**
  28. * Display a listing of the resource.
  29. *
  30. * @param Request $request
  31. * @return LengthAwarePaginator
  32. */
  33. public function index(Request $request)
  34. {
  35. $query = QueryBuilder::for(User::class)
  36. ->allowedIncludes(self::ALLOWED_INCLUDES)
  37. ->allowedFilters(self::ALLOWED_FILTERS);
  38. return $query->paginate($request->input('per_page') ?? 50);
  39. }
  40. /**
  41. * Display the specified resource.
  42. *
  43. * @param int $id
  44. *
  45. * @return User|Builder|Collection|Model
  46. */
  47. public function show(int $id)
  48. {
  49. $discordUser = DiscordUser::find($id);
  50. $user = $discordUser ? $discordUser->user : User::findOrFail($id);
  51. $query = QueryBuilder::for($user)
  52. ->with('discordUser')
  53. ->allowedIncludes(self::ALLOWED_INCLUDES)
  54. ->where('users.id', '=', $id)
  55. ->orWhereHas('discordUser', function (Builder $builder) use ($id) {
  56. $builder->where('id', '=', $id);
  57. });
  58. return $query->firstOrFail();
  59. }
  60. /**
  61. * Update the specified resource in storage.
  62. *
  63. * @param Request $request
  64. * @param int $id
  65. * @return User
  66. */
  67. public function update(Request $request, int $id)
  68. {
  69. $discordUser = DiscordUser::find($id);
  70. $user = $discordUser ? $discordUser->user : User::findOrFail($id);
  71. $request->validate([
  72. "name" => "sometimes|string|min:4|max:30",
  73. "email" => "sometimes|string|email",
  74. "credits" => "sometimes|numeric|min:0|max:1000000",
  75. "server_limit" => "sometimes|numeric|min:0|max:1000000",
  76. "role" => ['sometimes', Rule::in(['admin', 'mod', 'client', 'member'])],
  77. ]);
  78. event(new UserUpdateCreditsEvent($user));
  79. //Update Users Password on Pterodactyl
  80. //Username,Mail,First and Lastname are required aswell
  81. $response = Pterodactyl::client()->patch('/application/users/' . $user->pterodactyl_id, [
  82. "username" => $request->name,
  83. "first_name" => $request->name,
  84. "last_name" => $request->name,
  85. "email" => $request->email,
  86. ]);
  87. if ($response->failed()) {
  88. throw ValidationException::withMessages([
  89. 'pterodactyl_error_message' => $response->toException()->getMessage(),
  90. 'pterodactyl_error_status' => $response->toException()->getCode()
  91. ]);
  92. }
  93. $user->update($request->all());
  94. return $user;
  95. }
  96. /**
  97. * increments the users credits or/and server_limit
  98. *
  99. * @param Request $request
  100. * @param int $id
  101. * @return User
  102. * @throws ValidationException
  103. */
  104. public function increment(Request $request, int $id)
  105. {
  106. $discordUser = DiscordUser::find($id);
  107. $user = $discordUser ? $discordUser->user : User::findOrFail($id);
  108. $request->validate([
  109. "credits" => "sometimes|numeric|min:0|max:1000000",
  110. "server_limit" => "sometimes|numeric|min:0|max:1000000",
  111. ]);
  112. if ($request->credits) {
  113. if ($user->credits + $request->credits >= 99999999) throw ValidationException::withMessages([
  114. 'credits' => "You can't add this amount of credits because you would exceed the credit limit"
  115. ]);
  116. event(new UserUpdateCreditsEvent($user));
  117. $user->increment('credits', $request->credits);
  118. }
  119. if ($request->server_limit) {
  120. if ($user->server_limit + $request->server_limit >= 2147483647) throw ValidationException::withMessages([
  121. 'server_limit' => "You cannot add this amount of servers because it would exceed the server limit."
  122. ]);
  123. $user->increment('server_limit', $request->server_limit);
  124. }
  125. return $user;
  126. }
  127. /**
  128. * decrements the users credits or/and server_limit
  129. *
  130. * @param Request $request
  131. * @param int $id
  132. * @return User
  133. * @throws ValidationException
  134. */
  135. public function decrement(Request $request, int $id)
  136. {
  137. $discordUser = DiscordUser::find($id);
  138. $user = $discordUser ? $discordUser->user : User::findOrFail($id);
  139. $request->validate([
  140. "credits" => "sometimes|numeric|min:0|max:1000000",
  141. "server_limit" => "sometimes|numeric|min:0|max:1000000",
  142. ]);
  143. if ($request->credits) {
  144. if ($user->credits - $request->credits < 0) throw ValidationException::withMessages([
  145. 'credits' => "You can't remove this amount of credits because you would exceed the minimum credit limit"
  146. ]);
  147. $user->decrement('credits', $request->credits);
  148. }
  149. if ($request->server_limit) {
  150. if ($user->server_limit - $request->server_limit < 0) throw ValidationException::withMessages([
  151. 'server_limit' => "You cannot remove this amount of servers because it would exceed the minimum server."
  152. ]);
  153. $user->decrement('server_limit', $request->server_limit);
  154. }
  155. return $user;
  156. }
  157. /**
  158. * Suspends the user
  159. *
  160. * @param Request $request
  161. * @param int $id
  162. * @return bool
  163. * @throws ValidationException
  164. */
  165. public function suspend(Request $request, int $id)
  166. {
  167. $discordUser = DiscordUser::find($id);
  168. $user = $discordUser ? $discordUser->user : User::findOrFail($id);
  169. if ($user->isSuspended()) {
  170. throw ValidationException::withMessages([
  171. 'error' => 'The user is already suspended',
  172. ]);
  173. }
  174. $user->suspend();
  175. return $user;
  176. }
  177. /**
  178. * Unsuspend the user
  179. *
  180. * @param Request $request
  181. * @param int $id
  182. * @return bool
  183. * @throws ValidationException
  184. */
  185. public function unsuspend(Request $request, int $id)
  186. {
  187. $discordUser = DiscordUser::find($id);
  188. $user = $discordUser ? $discordUser->user : User::findOrFail($id);
  189. if (!$user->isSuspended()) {
  190. throw ValidationException::withMessages([
  191. 'error' => "You cannot unsuspend an User who is not suspended."
  192. ]);
  193. }
  194. $user->unSuspend();
  195. return $user;
  196. }
  197. /**
  198. * @throws ValidationException
  199. */
  200. public function store(Request $request)
  201. {
  202. $request->validate([
  203. 'name' => ['required', 'string', 'max:30', 'min:4', 'alpha_num', 'unique:users'],
  204. 'email' => ['required', 'string', 'email', 'max:64', 'unique:users'],
  205. 'password' => ['required', 'string', 'min:8', 'max:191'],
  206. ]);
  207. $user = User::create([
  208. 'name' => $request->input('name'),
  209. 'email' => $request->input('email'),
  210. 'credits' => config('SETTINGS::USER:INITIAL_CREDITS', 150),
  211. 'server_limit' => config('SETTINGS::USER:INITIAL_SERVER_LIMIT', 1),
  212. 'password' => Hash::make($request->input('password')),
  213. ]);
  214. $response = Pterodactyl::client()->post('/application/users', [
  215. "external_id" => App::environment('local') ? Str::random(16) : (string)$user->id,
  216. "username" => $user->name,
  217. "email" => $user->email,
  218. "first_name" => $user->name,
  219. "last_name" => $user->name,
  220. "password" => $request->input('password'),
  221. "root_admin" => false,
  222. "language" => "en"
  223. ]);
  224. if ($response->failed()) {
  225. $user->delete();
  226. throw ValidationException::withMessages([
  227. 'pterodactyl_error_message' => $response->toException()->getMessage(),
  228. 'pterodactyl_error_status' => $response->toException()->getCode()
  229. ]);
  230. }
  231. $user->update([
  232. 'pterodactyl_id' => $response->json()['attributes']['id']
  233. ]);
  234. $user->sendEmailVerificationNotification();
  235. return $user;
  236. }
  237. /**
  238. * Remove the specified resource from storage.
  239. *
  240. * @param int $id
  241. * @return Application|Response|ResponseFactory
  242. */
  243. public function destroy(int $id)
  244. {
  245. $discordUser = DiscordUser::find($id);
  246. $user = $discordUser ? $discordUser->user : User::findOrFail($id);
  247. $user->delete();
  248. return response($user, 200);
  249. }
  250. }