Merge pull request #183 from ControlPanel-gg/development
Notification System and fixes and improvements
This commit is contained in:
commit
0d8f3dd86a
|
@ -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
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
@ -32,11 +33,11 @@ class Pterodactyl
|
|||
* @param int $pterodactylId
|
||||
* @return mixed
|
||||
*/
|
||||
public function getUser(int $pterodactylId){
|
||||
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'];
|
||||
}
|
||||
|
||||
|
@ -50,7 +51,7 @@ class Pterodactyl
|
|||
$response = self::getAllocations($node);
|
||||
$freeAllocations = [];
|
||||
|
||||
if(isset($response['data'])){
|
||||
if (isset($response['data'])) {
|
||||
if (!empty($response['data'])) {
|
||||
foreach ($response['data'] as $allocation) {
|
||||
if (!$allocation['attributes']['assigned']) array_push($freeAllocations, $allocation);
|
||||
|
@ -125,7 +126,7 @@ class Pterodactyl
|
|||
*/
|
||||
public static function getAllocations(Node $node)
|
||||
{
|
||||
$per_page = Configuration::getValueByKey('ALLOCATION_LIMIT' , 200);
|
||||
$per_page = Configuration::getValueByKey('ALLOCATION_LIMIT', 200);
|
||||
$response = self::client()->get("/application/nodes/{$node->id}/allocations?per_page={$per_page}");
|
||||
if ($response->failed()) throw self::getException();
|
||||
return $response->json();
|
||||
|
@ -167,7 +168,7 @@ class Pterodactyl
|
|||
"feature_limits" => [
|
||||
"databases" => $server->product->databases,
|
||||
"backups" => $server->product->backups,
|
||||
"allocations" => 1
|
||||
"allocations" => $server->product->allocations,
|
||||
],
|
||||
"allocation" => [
|
||||
"default" => $allocationId
|
||||
|
|
|
@ -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,18 +46,29 @@ 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;
|
||||
}
|
||||
|
||||
|
|
32
app/Events/UserUpdateCreditsEvent.php
Normal file
32
app/Events/UserUpdateCreditsEvent.php
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Broadcasting\Channel;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PresenceChannel;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class UserUpdateCreditsEvent
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
/**
|
||||
* @var User
|
||||
*/
|
||||
public User $user;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param User $user
|
||||
*/
|
||||
public function __construct(User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Events\UserUpdateCreditsEvent;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Configuration;
|
||||
use App\Models\Payment;
|
||||
|
@ -167,6 +168,8 @@ class PaymentController extends Controller
|
|||
//payment notification
|
||||
$user->notify(new ConfirmPaymentNotification($payment));
|
||||
|
||||
event(new UserUpdateCreditsEvent($user));
|
||||
|
||||
//redirect back to home
|
||||
return redirect()->route('home')->with('success', 'Your credit balance has been increased!');
|
||||
}
|
||||
|
|
|
@ -90,8 +90,12 @@ class ServerController extends Controller
|
|||
*/
|
||||
public function destroy(Server $server)
|
||||
{
|
||||
try {
|
||||
$server->delete();
|
||||
return redirect()->back()->with('success', 'server has been removed!');
|
||||
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() . '"');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -3,8 +3,11 @@
|
|||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Classes\Pterodactyl;
|
||||
use App\Events\UserUpdateCreditsEvent;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
use App\Notifications\DynamicNotification;
|
||||
use Spatie\QueryBuilder\QueryBuilder;
|
||||
use Exception;
|
||||
use Illuminate\Contracts\Foundation\Application;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
|
@ -12,8 +15,11 @@ use Illuminate\Contracts\View\View;
|
|||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Illuminate\Support\HtmlString;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
|
@ -50,6 +56,30 @@ class UserController extends Controller
|
|||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a JSON response of users.
|
||||
*
|
||||
* @return \Illuminate\Support\Collection|\App\models\User
|
||||
*/
|
||||
public function json(Request $request)
|
||||
{
|
||||
$users = QueryBuilder::for(User::query())
|
||||
->allowedFilters(['id', 'name', 'pterodactyl_id', 'email'])
|
||||
->paginate(25);
|
||||
|
||||
if ($request->query('user_id')) {
|
||||
$user = User::query()->findOrFail($request->input('user_id'));
|
||||
$user->avatarUrl = $user->getAvatar();
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
return $users->map(function ($item) {
|
||||
$item->avatarUrl = $item->getAvatar();
|
||||
|
||||
return $item;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
|
@ -83,13 +113,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',
|
||||
|
@ -102,9 +131,9 @@ class UserController extends Controller
|
|||
}
|
||||
|
||||
$user->update($request->all());
|
||||
event(new UserUpdateCreditsEvent($user));
|
||||
|
||||
return redirect()->route('admin.users.index')->with('success', 'User updated!');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -142,6 +171,56 @@ class UserController extends Controller
|
|||
return redirect()->route('admin.users.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for seding notifications to the specified resource.
|
||||
*
|
||||
* @param User $user
|
||||
* @return Application|Factory|View|Response
|
||||
*/
|
||||
public function notifications(User $user)
|
||||
{
|
||||
return view('admin.users.notifications');
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the specified resource.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param User $user
|
||||
* @return RedirectResponse
|
||||
* @throws Exception
|
||||
*/
|
||||
public function notify(Request $request)
|
||||
{
|
||||
$data = $request->validate([
|
||||
"via" => "required|min:1|array",
|
||||
"via.*" => "required|string|in:mail,database",
|
||||
"all" => "required_without:users|boolean",
|
||||
"users" => "required_without:all|min:1|array",
|
||||
"users.*" => "exists:users,id",
|
||||
"title" => "required|string|min:1",
|
||||
"content" => "required|string|min:1"
|
||||
]);
|
||||
|
||||
$mail = null;
|
||||
$database = null;
|
||||
if (in_array('database', $data["via"])) {
|
||||
$database = [
|
||||
"title" => $data["title"],
|
||||
"content" => $data["content"]
|
||||
];
|
||||
}
|
||||
if (in_array('mail', $data["via"])) {
|
||||
$mail = (new MailMessage)
|
||||
->subject($data["title"])
|
||||
->line(new HtmlString($data["content"]));
|
||||
}
|
||||
$all = $data["all"] ?? false;
|
||||
$users = $all ? User::all() : User::whereIn("id", $data["users"])->get();
|
||||
Notification::send($users, new DynamicNotification($data["via"], $database, $mail));
|
||||
return redirect()->route('admin.users.notifications')->with('success', 'Notification sent!');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @throws Exception
|
||||
|
@ -186,16 +265,16 @@ class UserController extends Controller
|
|||
})
|
||||
->editColumn('role', function (User $user) {
|
||||
switch ($user->role) {
|
||||
case 'admin' :
|
||||
case 'admin':
|
||||
$badgeColor = 'badge-danger';
|
||||
break;
|
||||
case 'mod' :
|
||||
case 'mod':
|
||||
$badgeColor = 'badge-info';
|
||||
break;
|
||||
case 'client' :
|
||||
case 'client':
|
||||
$badgeColor = 'badge-success';
|
||||
break;
|
||||
default :
|
||||
default:
|
||||
$badgeColor = 'badge-secondary';
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Events\UserUpdateCreditsEvent;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Voucher;
|
||||
use Illuminate\Contracts\Foundation\Application;
|
||||
|
@ -45,10 +46,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 +76,7 @@ class VoucherController extends Controller
|
|||
*/
|
||||
public function edit(Voucher $voucher)
|
||||
{
|
||||
return view('admin.vouchers.edit' , [
|
||||
return view('admin.vouchers.edit', [
|
||||
'voucher' => $voucher
|
||||
]);
|
||||
}
|
||||
|
@ -91,10 +92,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 +128,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 +139,21 @@ 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());
|
||||
|
||||
event(new UserUpdateCreditsEvent($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 +194,4 @@ class VoucherController extends Controller
|
|||
->rawColumns(['actions', 'code', 'status'])
|
||||
->make();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
126
app/Http/Controllers/Api/NotificationController.php
Normal file
126
app/Http/Controllers/Api/NotificationController.php
Normal file
|
@ -0,0 +1,126 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\DiscordUser;
|
||||
use App\Models\User;
|
||||
use App\Notifications\DynamicNotification;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Illuminate\Support\HtmlString;
|
||||
use Spatie\ValidationRules\Rules\Delimited;
|
||||
|
||||
class NotificationController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display all notifications of an user.
|
||||
* @param Request $request
|
||||
* @param int $userId
|
||||
* @return Response
|
||||
*/
|
||||
public function index(Request $request, int $userId)
|
||||
{
|
||||
$discordUser = DiscordUser::find($userId);
|
||||
$user = $discordUser ? $discordUser->user : User::findOrFail($userId);
|
||||
|
||||
return $user->notifications()->paginate($request->query("per_page", 50));
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a specific notification
|
||||
*
|
||||
* @param int $userId
|
||||
* @param int $notificationId
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function view(int $userId, $notificationId)
|
||||
{
|
||||
$discordUser = DiscordUser::find($userId);
|
||||
$user = $discordUser ? $discordUser->user : User::findOrFail($userId);
|
||||
|
||||
$notification = $user->notifications()->where("id", $notificationId)->get()->first();
|
||||
|
||||
if (!$notification) {
|
||||
return response()->json(["message" => "Notification not found."], 404);
|
||||
}
|
||||
|
||||
return $notification;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a notification to an user.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function send(Request $request)
|
||||
{
|
||||
$data = $request->validate([
|
||||
"via" => ["required", new Delimited("in:mail,database")],
|
||||
"all" => "required_without:users|boolean",
|
||||
"users" => ["required_without:all", new Delimited("exists:users,id")],
|
||||
"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"],
|
||||
"content" => $data["content"]
|
||||
];
|
||||
}
|
||||
if (in_array("mail", $via)) {
|
||||
$mail = (new MailMessage)
|
||||
->subject($data["title"])
|
||||
->line(new HtmlString($data["content"]));
|
||||
}
|
||||
$all = $data["all"] ?? false;
|
||||
$users = $all ? User::all() : User::whereIn("id", explode(",", $data["users"]))->get();
|
||||
Notification::send($users, new DynamicNotification($via, $database, $mail));
|
||||
return response()->json(["message" => "Notification successfully sent."]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all notifications from an user
|
||||
*
|
||||
* @param int $userId
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function delete(int $userId)
|
||||
{
|
||||
$discordUser = DiscordUser::find($userId);
|
||||
$user = $discordUser ? $discordUser->user : User::findOrFail($userId);
|
||||
|
||||
$count = $user->notifications()->delete();
|
||||
|
||||
return response()->json(["message" => "All notifications have been successfully deleted.", "count" => $count]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delete a specific notification
|
||||
*
|
||||
* @param int $userId
|
||||
* @param int $notificationId
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function deleteOne(int $userId, $notificationid)
|
||||
{
|
||||
$discordUser = DiscordUser::find($userId);
|
||||
$user = $discordUser ? $discordUser->user : User::findOrFail($userId);
|
||||
|
||||
$notification = $user->notifications()->where("id", $notificationid)->get()->first();
|
||||
|
||||
if (!$notification) {
|
||||
return response()->json(["message" => "Notification not found."], 404);
|
||||
}
|
||||
|
||||
$notification->delete();
|
||||
return response()->json($notification);
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Events\UserUpdateCreditsEvent;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\DiscordUser;
|
||||
use App\Models\User;
|
||||
|
@ -10,6 +11,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
|
||||
{
|
||||
|
@ -60,6 +62,79 @@ class UserController extends Controller
|
|||
|
||||
$user->update($request->all());
|
||||
|
||||
event(new UserUpdateCreditsEvent($user));
|
||||
|
||||
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"
|
||||
]);
|
||||
event(new UserUpdateCreditsEvent($user));
|
||||
$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;
|
||||
}
|
||||
|
||||
|
@ -67,7 +142,7 @@ class UserController extends Controller
|
|||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return Application|ResponseFactory|Response|void
|
||||
* @return Application|Response|ResponseFactory
|
||||
*/
|
||||
public function destroy(int $id)
|
||||
{
|
||||
|
|
|
@ -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());
|
||||
|
@ -116,7 +116,8 @@ class VoucherController extends Controller
|
|||
* @param Voucher $voucher
|
||||
* @return LengthAwarePaginator
|
||||
*/
|
||||
public function users(Request $request, Voucher $voucher){
|
||||
public function users(Request $request, Voucher $voucher)
|
||||
{
|
||||
$request->validate([
|
||||
'include' => [
|
||||
'nullable',
|
||||
|
@ -125,7 +126,7 @@ class VoucherController extends Controller
|
|||
]
|
||||
]);
|
||||
|
||||
if($request->input('include') == 'discorduser'){
|
||||
if ($request->input('include') == 'discorduser') {
|
||||
return $voucher->users()->with('discordUser')->paginate($request->query('per_page') ?? 50);
|
||||
}
|
||||
|
||||
|
|
|
@ -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() . '"');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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([
|
||||
|
|
|
@ -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
|
||||
],
|
||||
];
|
||||
|
||||
|
|
23
app/Http/Middleware/CreditsDisplayName.php
Normal file
23
app/Http/Middleware/CreditsDisplayName.php
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Models\Configuration;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class CreditsDisplayName
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
define('CREDITS_DISPLAY_NAME' , Configuration::getValueByKey('CREDITS_DISPLAY_NAME' , 'Credits'));
|
||||
return $next($request);
|
||||
}
|
||||
}
|
30
app/Listeners/UnsuspendServers.php
Normal file
30
app/Listeners/UnsuspendServers.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Events\UserUpdateCreditsEvent;
|
||||
use App\Models\Configuration;
|
||||
use App\Models\Server;
|
||||
use Exception;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
|
||||
class UnsuspendServers implements ShouldQueue
|
||||
{
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param UserUpdateCreditsEvent $event
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function handle(UserUpdateCreditsEvent $event)
|
||||
{
|
||||
if ($event->user->credits > Configuration::getValueByKey('MINIMUM_REQUIRED_CREDITS_TO_MAKE_SERVER' , 50)){
|
||||
/** @var Server $server */
|
||||
foreach ($event->user->servers as $server){
|
||||
if ($server->isSuspended()) $server->unSuspend();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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']);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Models;
|
||||
|
||||
use App\Classes\Pterodactyl;
|
||||
use App\Events\UserUpdateCreditsEvent;
|
||||
use App\Notifications\Auth\QueuedVerifyEmail;
|
||||
use App\Notifications\WelcomeMessage;
|
||||
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
|
|
63
app/Notifications/DynamicNotification.php
Normal file
63
app/Notifications/DynamicNotification.php
Normal file
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
class DynamicNotification extends Notification
|
||||
|
||||
{
|
||||
use Queueable;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $via;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $database;
|
||||
/**
|
||||
* @var MailMessage
|
||||
*/
|
||||
private $mail;
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @param array $via
|
||||
* @param array $database
|
||||
* @param MailMessage $mail
|
||||
*/
|
||||
public function __construct($via, $database, $mail)
|
||||
{
|
||||
$this->via = $via;
|
||||
$this->database = $database;
|
||||
$this->mail = $mail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function via()
|
||||
{
|
||||
return $this->via;
|
||||
}
|
||||
|
||||
public function toMail()
|
||||
{
|
||||
return $this->mail;
|
||||
}
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return $this->database;
|
||||
}
|
||||
}
|
|
@ -4,7 +4,9 @@ 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;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
|
@ -27,5 +29,28 @@ 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;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Events\UserUpdateCreditsEvent;
|
||||
use App\Listeners\UnsuspendServers;
|
||||
use App\Listeners\Verified;
|
||||
use Illuminate\Auth\Events\Registered;
|
||||
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
|
||||
|
@ -20,6 +22,9 @@ class EventServiceProvider extends ServiceProvider
|
|||
Registered::class => [
|
||||
SendEmailVerificationNotification::class,
|
||||
],
|
||||
UserUpdateCreditsEvent::class => [
|
||||
UnsuspendServers::class
|
||||
],
|
||||
SocialiteWasCalled::class => [
|
||||
// ... other providers
|
||||
'SocialiteProviders\\Discord\\DiscordExtendSocialite@handle',
|
||||
|
|
0
bootstrap/cache/.gitignore
vendored
Normal file → Executable file
0
bootstrap/cache/.gitignore
vendored
Normal file → Executable file
|
@ -9,6 +9,7 @@
|
|||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^8.0|^7.4",
|
||||
"ext-intl": "*",
|
||||
"biscolab/laravel-recaptcha": "^5.0",
|
||||
"doctrine/dbal": "^3.1",
|
||||
"fideloper/proxy": "^4.4",
|
||||
|
@ -22,8 +23,9 @@
|
|||
"paypal/rest-api-sdk-php": "^1.14",
|
||||
"socialiteproviders/discord": "^4.1",
|
||||
"spatie/laravel-activitylog": "^3.16",
|
||||
"yajra/laravel-datatables-oracle": "~9.0",
|
||||
"ext-intl": "*"
|
||||
"spatie/laravel-query-builder": "^3.5",
|
||||
"spatie/laravel-validation-rules": "^3.0",
|
||||
"yajra/laravel-datatables-oracle": "~9.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"facade/ignition": "^2.5",
|
||||
|
|
143
composer.lock
generated
143
composer.lock
generated
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "dda32482531d11fdf6adc74fcba74715",
|
||||
"content-hash": "b3b61a46d5d4d6560d052cfda863d12c",
|
||||
"packages": [
|
||||
{
|
||||
"name": "asm89/stack-cors",
|
||||
|
@ -3460,6 +3460,147 @@
|
|||
],
|
||||
"time": "2021-03-02T16:49:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/laravel-query-builder",
|
||||
"version": "3.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/laravel-query-builder.git",
|
||||
"reference": "4e5257be24139836dc092f618d7c73bcb1c00302"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/laravel-query-builder/zipball/4e5257be24139836dc092f618d7c73bcb1c00302",
|
||||
"reference": "4e5257be24139836dc092f618d7c73bcb1c00302",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/database": "^6.20.13|^7.30.4|^8.22.2",
|
||||
"illuminate/http": "^6.20.13|7.30.4|^8.22.2",
|
||||
"illuminate/support": "^6.20.13|7.30.4|^8.22.2",
|
||||
"php": "^7.3|^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-json": "*",
|
||||
"laravel/legacy-factories": "^1.0.4",
|
||||
"mockery/mockery": "^1.4",
|
||||
"orchestra/testbench": "^4.9|^5.8|^6.3",
|
||||
"phpunit/phpunit": "^9.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Spatie\\QueryBuilder\\QueryBuilderServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Spatie\\QueryBuilder\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Alex Vanderbist",
|
||||
"email": "alex@spatie.be",
|
||||
"homepage": "https://spatie.be",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Easily build Eloquent queries from API requests",
|
||||
"homepage": "https://github.com/spatie/laravel-query-builder",
|
||||
"keywords": [
|
||||
"laravel-query-builder",
|
||||
"spatie"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/spatie/laravel-query-builder/issues",
|
||||
"source": "https://github.com/spatie/laravel-query-builder"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://spatie.be/open-source/support-us",
|
||||
"type": "custom"
|
||||
}
|
||||
],
|
||||
"time": "2021-07-05T14:17:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/laravel-validation-rules",
|
||||
"version": "3.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/laravel-validation-rules.git",
|
||||
"reference": "43e15a70fb6148b0128d7981b0c0f3e99463b9fb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/laravel-validation-rules/zipball/43e15a70fb6148b0128d7981b0c0f3e99463b9fb",
|
||||
"reference": "43e15a70fb6148b0128d7981b0c0f3e99463b9fb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/support": "^6.0|^7.0|^8.0",
|
||||
"php": "^7.3|^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/legacy-factories": "^1.0.4",
|
||||
"myclabs/php-enum": "^1.6",
|
||||
"orchestra/testbench": "^4.5|^5.0|^6.0",
|
||||
"phpunit/phpunit": "^9.3",
|
||||
"spatie/enum": "^2.2|^3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"league/iso3166": "Needed for the CountryCode rule"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Spatie\\ValidationRules\\ValidationRulesServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Spatie\\ValidationRules\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Freek Van der Herten",
|
||||
"email": "freek@spatie.be",
|
||||
"homepage": "https://spatie.be",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "A set of useful Laravel validation rules",
|
||||
"homepage": "https://github.com/spatie/laravel-validation-rules",
|
||||
"keywords": [
|
||||
"laravel-validation-rules",
|
||||
"spatie"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/spatie/laravel-validation-rules/issues",
|
||||
"source": "https://github.com/spatie/laravel-validation-rules/tree/3.0.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/spatie",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-11-30T15:23:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "swiftmailer/swiftmailer",
|
||||
"version": "v6.2.7",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
return [
|
||||
|
||||
'version' => '0.5',
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Name
|
||||
|
@ -67,7 +68,7 @@ return [
|
|||
|
|
||||
*/
|
||||
|
||||
'timezone' => 'UTC',
|
||||
'timezone' => env('APP_TIMEZONE', 'UTC'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
54
config/trustedproxy.php
Executable file
54
config/trustedproxy.php
Executable file
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
* Set trusted proxy IP addresses.
|
||||
*
|
||||
* Both IPv4 and IPv6 addresses are
|
||||
* supported, along with CIDR notation.
|
||||
*
|
||||
* The "*" character is syntactic sugar
|
||||
* within TrustedProxy to trust any proxy
|
||||
* that connects directly to your server,
|
||||
* a requirement when you cannot know the address
|
||||
* of your proxy (e.g. if using Rackspace balancers).
|
||||
*
|
||||
* The "**" character is syntactic sugar within
|
||||
* TrustedProxy to trust not just any proxy that
|
||||
* connects directly to your server, but also
|
||||
* proxies that connect to those proxies, and all
|
||||
* the way back until you reach the original source
|
||||
* IP. It will mean that $request->getClientIp()
|
||||
* always gets the originating client IP, no matter
|
||||
* how many proxies that client's request has
|
||||
* subsequently passed through.
|
||||
*/
|
||||
'proxies' => in_array(env('TRUSTED_PROXIES', []), ['*', '**']) ?
|
||||
env('TRUSTED_PROXIES') : explode(',', env('TRUSTED_PROXIES', null)),
|
||||
|
||||
/*
|
||||
* Or, to trust all proxies that connect
|
||||
* directly to your server, uncomment this:
|
||||
*/
|
||||
// 'proxies' => '*',
|
||||
|
||||
/*
|
||||
* Or, to trust ALL proxies, including those that
|
||||
* are in a chain of forwarding, uncomment this:
|
||||
*/
|
||||
// 'proxies' => '**',
|
||||
|
||||
/*
|
||||
* Default Header Names
|
||||
*
|
||||
* Change these if the proxy does
|
||||
* not send the default header names.
|
||||
*
|
||||
* Note that headers such as X-Forwarded-For
|
||||
* are transformed to HTTP_X_FORWARDED_FOR format.
|
||||
*
|
||||
* The following are Symfony defaults, found in
|
||||
* \Symfony\Component\HttpFoundation\Request::$trustedHeaders
|
||||
*/
|
||||
'headers' => \Illuminate\Http\Request::HEADER_X_FORWARDED_ALL,
|
||||
];
|
|
@ -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 :)'
|
||||
]);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="price">Price in credits</label>
|
||||
<label for="price">Price in {{CREDITS_DISPLAY_NAME}}</label>
|
||||
<input value="{{old('price')}}" id="price" name="price"
|
||||
type="number"
|
||||
class="form-control @error('price') is-invalid @enderror"
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="price">Price in credits</label>
|
||||
<label for="price">Price in {{CREDITS_DISPLAY_NAME}}</label>
|
||||
<input value="{{$product->price}}" id="price" name="price"
|
||||
type="number"
|
||||
class="form-control @error('price') is-invalid @enderror"
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="credits">Credits</label>
|
||||
<label for="credits">{{CREDITS_DISPLAY_NAME}}</label>
|
||||
<input value="{{$user->credits}}" id="credits" name="credits" step="any" min="0"
|
||||
max="99999999"
|
||||
type="number" class="form-control @error('credits') is-invalid @enderror"
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
<div class="card-header">
|
||||
<div class="d-flex justify-content-between">
|
||||
<h5 class="card-title"><i class="fas fa-users mr-2"></i>Users</h5>
|
||||
<a href="{{route('admin.users.notifications')}}" class="btn btn-sm btn-primary"><i
|
||||
class="fas fa-paper-plane mr-1"></i>Notify</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -43,7 +45,7 @@
|
|||
<th>Name</th>
|
||||
<th>Role</th>
|
||||
<th>Email</th>
|
||||
<th>Credits</th>
|
||||
<th>{{CREDITS_DISPLAY_NAME}}</th>
|
||||
<th>Usage</th>
|
||||
<th>Servers</th>
|
||||
<th>Verified</th>
|
||||
|
|
188
resources/views/admin/users/notifications.blade.php
Normal file
188
resources/views/admin/users/notifications.blade.php
Normal file
|
@ -0,0 +1,188 @@
|
|||
@extends('layouts.main')
|
||||
@section('content')
|
||||
<!-- CONTENT HEADER -->
|
||||
<section class="content-header">
|
||||
<div class="container-fluid">
|
||||
<div class="row mb-2">
|
||||
<div class="col-sm-6">
|
||||
<h1>Users</h1>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<ol class="breadcrumb float-sm-right">
|
||||
<li class="breadcrumb-item"><a href="{{route('home')}}">Dashboard</a></li>
|
||||
<li class="breadcrumb-item"><a href="{{route('admin.users.index')}}">Users</a></li>
|
||||
<li class="breadcrumb-item"><a class="text-muted"
|
||||
href="{{route('admin.users.notifications')}}">Notifications</a></li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- END CONTENT HEADER -->
|
||||
|
||||
<!-- MAIN CONTENT -->
|
||||
<section class="content">
|
||||
<div class="container-fluid">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form action="{{route('admin.users.notifications')}}" method="POST">
|
||||
@csrf
|
||||
@method('POST')
|
||||
|
||||
<div class="form-group">
|
||||
<label>Users</label><br>
|
||||
<input id="all" name="all"
|
||||
type="checkbox" value="1"
|
||||
onchange="toggleClass('users-form', 'd-none')">
|
||||
<label for="all">All</label>
|
||||
<div id="users-form">
|
||||
<select id="users" name="users[]" class="form-control" multiple></select>
|
||||
</div>
|
||||
@error('all')
|
||||
<div class="invalid-feedback d-block">
|
||||
{{$message}}
|
||||
</div>
|
||||
@enderror
|
||||
@error('users')
|
||||
<div class="invalid-feedback d-block">
|
||||
{{$message}}
|
||||
</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Send via</label><br>
|
||||
<input value="database" id="database" name="via[]"
|
||||
type="checkbox">
|
||||
<label for="database">Database</label>
|
||||
<br>
|
||||
<input value="mail" id="mail" name="via[]"
|
||||
type="checkbox">
|
||||
<label for="mail">Mail</label>
|
||||
@error('via')
|
||||
<div class="invalid-feedback d-block">
|
||||
{{$message}}
|
||||
</div>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="form-group" >
|
||||
<label for="title">Title</label>
|
||||
<input value="{{old('title')}}" id="title" name="title"
|
||||
type="text"
|
||||
class="form-control @error('title') is-invalid @enderror">
|
||||
@error('title')
|
||||
<div class="invalid-feedback">
|
||||
{{$message}}
|
||||
</div>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="content">Content</label>
|
||||
<textarea id="content"
|
||||
name="content"
|
||||
type="content"
|
||||
class="form-control @error('content') is-invalid @enderror">
|
||||
{{old('content')}}
|
||||
</textarea>
|
||||
@error('content')
|
||||
<div class="text-danger">
|
||||
{{$message}}
|
||||
</div>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="form-group text-right">
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</section>
|
||||
<!-- END CONTENT -->
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', (event) => {
|
||||
// Summernote
|
||||
$('#content').summernote({
|
||||
height: 100,
|
||||
toolbar: [
|
||||
[ 'style', [ 'style' ] ],
|
||||
[ 'font', [ 'bold', 'italic', 'underline', 'strikethrough', 'superscript', 'subscript', 'clear'] ],
|
||||
[ 'fontname', [ 'fontname' ] ],
|
||||
[ 'fontsize', [ 'fontsize' ] ],
|
||||
[ 'color', [ 'color' ] ],
|
||||
[ 'para', [ 'ol', 'ul', 'paragraph', 'height' ] ],
|
||||
[ 'table', [ 'table' ] ],
|
||||
[ 'insert', [ 'link'] ],
|
||||
[ 'view', [ 'undo', 'redo', 'fullscreen', 'codeview', 'help' ] ]
|
||||
]
|
||||
})
|
||||
|
||||
function initUserSelect(data) {
|
||||
$('#users').select2({
|
||||
ajax: {
|
||||
url: '/admin/users.json',
|
||||
dataType: 'json',
|
||||
delay: 250,
|
||||
|
||||
data: function (params) {
|
||||
return {
|
||||
filter: { email: params.term },
|
||||
page: params.page,
|
||||
};
|
||||
},
|
||||
|
||||
processResults: function (data, params) {
|
||||
return { results: data };
|
||||
},
|
||||
|
||||
cache: true,
|
||||
},
|
||||
data: data,
|
||||
minimumInputLength: 2,
|
||||
templateResult: function (data) {
|
||||
if (data.loading) return data.text;
|
||||
const $container = $(
|
||||
"<div class='select2-result-users clearfix' style='display:flex;'>" +
|
||||
"<div class='select2-result-users__avatar' style='display:flex;align-items:center;'><img class='img-circle img-bordered-s' src='" + data.avatarUrl + "?s=40' /></div>" +
|
||||
"<div class='select2-result-users__meta' style='margin-left:10px'>" +
|
||||
"<div class='select2-result-users__username' style='font-size:16px;'></div>" +
|
||||
"<div class='select2-result-users__email' style='font-size=13px;'></div>" +
|
||||
"</div>" +
|
||||
"</div>"
|
||||
);
|
||||
|
||||
$container.find(".select2-result-users__username").text(data.name);
|
||||
$container.find(".select2-result-users__email").text(data.email);
|
||||
|
||||
return $container;
|
||||
},
|
||||
templateSelection: function (data) {
|
||||
$container = $('<div> \
|
||||
<span> \
|
||||
<img class="img-rounded img-bordered-xs" src="' + data.avatarUrl + '?s=120" style="height:24px;margin-top:-4px;" alt="User Image"> \
|
||||
</span> \
|
||||
<span class="select2-selection-users__username" style="padding-left:10px;padding-right:10px;"></span> \
|
||||
</div>');
|
||||
$container.find(".select2-selection-users__username").text(data.name);
|
||||
return $container;
|
||||
}
|
||||
})
|
||||
}
|
||||
initUserSelect()
|
||||
})
|
||||
|
||||
function toggleClass(id, className) {
|
||||
document.getElementById(id).classList.toggle(className)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@endsection
|
|
@ -148,7 +148,7 @@
|
|||
<div class="col-lg-6">
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
<label>Credits</label>
|
||||
<label>{{CREDITS_DISPLAY_NAME}}</label>
|
||||
</div>
|
||||
<div class="col-lg-8">
|
||||
<span style="max-width: 250px;" class="d-inline-block text-truncate">
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
@extends('layouts.main')
|
||||
|
||||
@section('content')
|
||||
<!-- CONTENT HEADER -->
|
||||
<section class="content-header">
|
||||
<!-- CONTENT HEADER -->
|
||||
<section class="content-header">
|
||||
<div class="container-fluid">
|
||||
<div class="row mb-2">
|
||||
<div class="col-sm-6">
|
||||
|
@ -18,11 +18,11 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- END CONTENT HEADER -->
|
||||
</section>
|
||||
<!-- END CONTENT HEADER -->
|
||||
|
||||
<!-- MAIN CONTENT -->
|
||||
<section class="content">
|
||||
<!-- MAIN CONTENT -->
|
||||
<section class="content">
|
||||
<div class="container-fluid">
|
||||
|
||||
<div class="row">
|
||||
|
@ -39,9 +39,7 @@
|
|||
|
||||
<div class="form-group">
|
||||
<label for="memo">Memo <i data-toggle="popover" data-trigger="hover" data-content="Only admins can see this" class="fas fa-info-circle"></i></label>
|
||||
<input value="{{old('memo')}}" placeholder="Summer break voucher" id="memo"
|
||||
name="memo" type="text"
|
||||
class="form-control @error('memo') is-invalid @enderror">
|
||||
<input value="{{old('memo')}}" placeholder="Summer break voucher" id="memo" name="memo" type="text" class="form-control @error('memo') is-invalid @enderror">
|
||||
@error('memo')
|
||||
<div class="text-danger">
|
||||
{{$message}}
|
||||
|
@ -50,11 +48,8 @@
|
|||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="credits">* Credits</label>
|
||||
<input value="{{old('credits')}}" placeholder="500" id="credits"
|
||||
name="credits" type="number" step="any" min="0"
|
||||
max="99999999"
|
||||
class="form-control @error('credits') is-invalid @enderror">
|
||||
<label for="credits">* {{CREDITS_DISPLAY_NAME}}</label>
|
||||
<input value="{{old('credits')}}" placeholder="500" id="credits" name="credits" type="number" step="any" min="0" max="99999999" class="form-control @error('credits') is-invalid @enderror">
|
||||
@error('credits')
|
||||
<div class="text-danger">
|
||||
{{$message}}
|
||||
|
@ -66,10 +61,7 @@
|
|||
<div class="form-group">
|
||||
<label for="code">* Code</label>
|
||||
<div class="input-group">
|
||||
<input value="{{old('code')}}" placeholder="SUMMER" id="code" name="code"
|
||||
type="text"
|
||||
class="form-control @error('code') is-invalid @enderror"
|
||||
required="required">
|
||||
<input value="{{old('code')}}" placeholder="SUMMER" id="code" name="code" type="text" class="form-control @error('code') is-invalid @enderror" required="required">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-info" onclick="setRandomCode()" type="button">
|
||||
Random
|
||||
|
@ -84,12 +76,9 @@
|
|||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="uses">* Uses<i data-toggle="popover" data-trigger="hover" data-content="A voucher can only be used one time per user. Uses specifies the number of different users that can use this voucher." class="fas fa-info-circle"></i></label>
|
||||
<label for="uses">* Uses <i data-toggle="popover" data-trigger="hover" data-content="A voucher can only be used one time per user. Uses specifies the number of different users that can use this voucher." class="fas fa-info-circle"></i></label>
|
||||
<div class="input-group">
|
||||
<input value="{{old('uses') ?? 1}}" id="uses" min="1" max="2147483647"
|
||||
name="uses" type="number"
|
||||
class="form-control @error('uses') is-invalid @enderror"
|
||||
required="required">
|
||||
<input value="{{old('uses') ?? 1}}" id="uses" min="1" max="2147483647" name="uses" type="number" class="form-control @error('uses') is-invalid @enderror" required="required">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-info" onclick="setMaxUses()" type="button">Max
|
||||
</button>
|
||||
|
@ -103,9 +92,9 @@
|
|||
</div>
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<label for="expires_at">Expires at</label>
|
||||
<label for="expires_at">Expires at <i data-toggle="popover" data-trigger="hover" data-content="Timezone: {{ Config::get('app.timezone') }}" class="fas fa-info-circle"></i></label>
|
||||
<div class="input-group date" id="expires_at" data-target-input="nearest">
|
||||
<input value="{{old('expires_at')}}" name="expires_at" placeholder="dd-mm-yyyy" type="text" class="form-control @error('expires_at') is-invalid @enderror datetimepicker-input" data-target="#expires_at"/>
|
||||
<input value="{{old('expires_at')}}" name="expires_at" placeholder="dd-mm-yyyy hh:mm:ss" type="text" class="form-control @error('expires_at') is-invalid @enderror datetimepicker-input" data-target="#expires_at" />
|
||||
<div class="input-group-append" data-target="#expires_at" data-toggle="datetimepicker">
|
||||
<div class="input-group-text"><i class="fa fa-calendar"></i></div>
|
||||
</div>
|
||||
|
@ -131,14 +120,14 @@
|
|||
<i class="fas"></i>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
<!-- END CONTENT -->
|
||||
</section>
|
||||
<!-- END CONTENT -->
|
||||
|
||||
|
||||
<script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', (event) => {
|
||||
$('#expires_at').datetimepicker({
|
||||
format : 'DD-MM-yyyy',
|
||||
format: 'DD-MM-yyyy HH:mm:ss',
|
||||
icons: {
|
||||
time: 'far fa-clock',
|
||||
date: 'far fa-calendar',
|
||||
|
@ -175,7 +164,7 @@
|
|||
}
|
||||
return result;
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
|
||||
|
||||
@endsection
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
@extends('layouts.main')
|
||||
|
||||
@section('content')
|
||||
<!-- CONTENT HEADER -->
|
||||
<section class="content-header">
|
||||
<!-- CONTENT HEADER -->
|
||||
<section class="content-header">
|
||||
<div class="container-fluid">
|
||||
<div class="row mb-2">
|
||||
<div class="col-sm-6">
|
||||
|
@ -12,18 +12,17 @@
|
|||
<ol class="breadcrumb float-sm-right">
|
||||
<li class="breadcrumb-item"><a href="{{route('home')}}">Dashboard</a></li>
|
||||
<li class="breadcrumb-item"><a href="{{route('admin.vouchers.index')}}">Vouchers</a></li>
|
||||
<li class="breadcrumb-item"><a class="text-muted"
|
||||
href="{{route('admin.products.edit' , $voucher->id)}}">Edit</a>
|
||||
<li class="breadcrumb-item"><a class="text-muted" href="{{route('admin.products.edit' , $voucher->id)}}">Edit</a>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- END CONTENT HEADER -->
|
||||
</section>
|
||||
<!-- END CONTENT HEADER -->
|
||||
|
||||
<!-- MAIN CONTENT -->
|
||||
<section class="content">
|
||||
<!-- MAIN CONTENT -->
|
||||
<section class="content">
|
||||
<div class="container-fluid">
|
||||
|
||||
<div class="row">
|
||||
|
@ -40,12 +39,8 @@
|
|||
@method('PATCH')
|
||||
|
||||
<div class="form-group">
|
||||
<label for="memo">Memo <i data-toggle="popover" data-trigger="hover"
|
||||
data-content="Only admins can see this"
|
||||
class="fas fa-info-circle"></i></label>
|
||||
<input value="{{ $voucher->memo }}" placeholder="Summer break voucher" id="memo"
|
||||
name="memo" type="text"
|
||||
class="form-control @error('memo') is-invalid @enderror">
|
||||
<label for="memo">Memo <i data-toggle="popover" data-trigger="hover" data-content="Only admins can see this" class="fas fa-info-circle"></i></label>
|
||||
<input value="{{ $voucher->memo }}" placeholder="Summer break voucher" id="memo" name="memo" type="text" class="form-control @error('memo') is-invalid @enderror">
|
||||
@error('memo')
|
||||
<div class="text-danger">
|
||||
{{$message}}
|
||||
|
@ -54,11 +49,8 @@
|
|||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="credits">Credits *</label>
|
||||
<input value="{{$voucher->credits}}" placeholder="500" id="credits"
|
||||
name="credits" type="number" step="any" min="0"
|
||||
max="99999999"
|
||||
class="form-control @error('credits') is-invalid @enderror">
|
||||
<label for="credits">{{CREDITS_DISPLAY_NAME}} *</label>
|
||||
<input value="{{$voucher->credits}}" placeholder="500" id="credits" name="credits" type="number" step="any" min="0" max="99999999" class="form-control @error('credits') is-invalid @enderror">
|
||||
@error('credits')
|
||||
<div class="text-danger">
|
||||
{{$message}}
|
||||
|
@ -70,10 +62,7 @@
|
|||
<div class="form-group">
|
||||
<label for="code">Code *</label>
|
||||
<div class="input-group">
|
||||
<input value="{{$voucher->code}}" placeholder="SUMMER" id="code" name="code"
|
||||
type="text"
|
||||
class="form-control @error('code') is-invalid @enderror"
|
||||
required="required">
|
||||
<input value="{{$voucher->code}}" placeholder="SUMMER" id="code" name="code" type="text" class="form-control @error('code') is-invalid @enderror" required="required">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-info" onclick="setRandomCode()" type="button">
|
||||
Random
|
||||
|
@ -88,14 +77,9 @@
|
|||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="uses">Uses * <i data-toggle="popover" data-trigger="hover"
|
||||
data-content="A voucher can only be used one time per user. Uses specifies the number of different users that can use this voucher."
|
||||
class="fas fa-info-circle"></i></label>
|
||||
<label for="uses">Uses * <i data-toggle="popover" data-trigger="hover" data-content="A voucher can only be used one time per user. Uses specifies the number of different users that can use this voucher." class="fas fa-info-circle"></i></label>
|
||||
<div class="input-group">
|
||||
<input value="{{$voucher->uses}}" id="uses" min="1" max="2147483647"
|
||||
name="uses" type="number"
|
||||
class="form-control @error('uses') is-invalid @enderror"
|
||||
required="required">
|
||||
<input value="{{$voucher->uses}}" id="uses" min="1" max="2147483647" name="uses" type="number" class="form-control @error('uses') is-invalid @enderror" required="required">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-info" onclick="setMaxUses()" type="button">Max
|
||||
</button>
|
||||
|
@ -109,9 +93,9 @@
|
|||
</div>
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<label for="expires_at">Expires at</label>
|
||||
<label for="expires_at">Expires at <i data-toggle="popover" data-trigger="hover" data-content="Timezone: {{ Config::get('app.timezone') }}" class="fas fa-info-circle"></i></label>
|
||||
<div class="input-group date" id="expires_at" data-target-input="nearest">
|
||||
<input value="{{$voucher->expires_at ? $voucher->expires_at->format('d-m-Y') : ''}}" name="expires_at" placeholder="dd-mm-yyyy" type="text" class="form-control @error('expires_at') is-invalid @enderror datetimepicker-input" data-target="#expires_at"/>
|
||||
<input value="{{$voucher->expires_at ? $voucher->expires_at->format('d-m-Y H:i:s') : ''}}" name="expires_at" placeholder="dd-mm-yyyy hh:mm:ss" type="text" class="form-control @error('expires_at') is-invalid @enderror datetimepicker-input" data-target="#expires_at" />
|
||||
<div class="input-group-append" data-target="#expires_at" data-toggle="datetimepicker">
|
||||
<div class="input-group-text"><i class="fa fa-calendar"></i></div>
|
||||
</div>
|
||||
|
@ -136,14 +120,14 @@
|
|||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
<!-- END CONTENT -->
|
||||
</section>
|
||||
<!-- END CONTENT -->
|
||||
|
||||
|
||||
<script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', (event) => {
|
||||
$('#expires_at').datetimepicker({
|
||||
format : 'DD-MM-yyyy',
|
||||
format: 'DD-MM-yyyy HH:mm:ss',
|
||||
icons: {
|
||||
time: 'far fa-clock',
|
||||
date: 'far fa-calendar',
|
||||
|
@ -180,7 +164,7 @@
|
|||
}
|
||||
return result;
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
|
||||
|
||||
@endsection
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
<th>Status</th>
|
||||
<th>Code</th>
|
||||
<th>Memo</th>
|
||||
<th>Credits</th>
|
||||
<th>{{CREDITS_DISPLAY_NAME}}</th>
|
||||
<th>Used / Uses</th>
|
||||
<th>Expires</th>
|
||||
<th></th>
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
<span class="info-box-icon bg-danger elevation-1"><i class="fas fa-coins"></i></span>
|
||||
|
||||
<div class="info-box-content">
|
||||
<span class="info-box-text">Credits</span>
|
||||
<span class="info-box-text">{{CREDITS_DISPLAY_NAME}}</span>
|
||||
<span class="info-box-number">{{Auth::user()->Credits()}}</span>
|
||||
</div>
|
||||
<!-- /.info-box-content -->
|
||||
|
@ -58,7 +58,7 @@
|
|||
<span class="info-box-icon bg-warning elevation-1"><i class="fas fa-chart-line"></i></span>
|
||||
|
||||
<div class="info-box-content">
|
||||
<span class="info-box-text">Credit usage</span>
|
||||
<span class="info-box-text">{{CREDITS_DISPLAY_NAME}} usage</span>
|
||||
<span class="info-box-number">{{number_format($useage, 2, '.', '')}} <sup>per month</sup></span>
|
||||
</div>
|
||||
<!-- /.info-box-content -->
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
{{-- datetimepicker --}}
|
||||
<link rel="stylesheet" href="{{asset('plugins/tempusdominus-bootstrap-4/css/tempusdominus-bootstrap-4.min.css')}}">
|
||||
|
||||
{{-- select2 --}}
|
||||
<link rel="stylesheet" href="{{asset('plugins/select2/css/select2.min.css')}}">
|
||||
|
||||
<link rel="stylesheet" href="{{asset('css/app.css')}}">
|
||||
<link rel="preload" href="{{asset('plugins/fontawesome-free/css/all.min.css')}}" as="style"
|
||||
onload="this.onload=null;this.rel='stylesheet'">
|
||||
|
@ -316,7 +319,7 @@
|
|||
<footer class="main-footer">
|
||||
<strong>Copyright © 2021-{{date('Y')}} <a href="{{url('/')}}">{{env('APP_NAME' , 'Laravel')}}</a>.</strong>
|
||||
All rights
|
||||
reserved.
|
||||
reserved. Powered by <a href="https://controlpanel.gg">ControlPanel</a>. Version <b>{{config('app')['version']}}</b>
|
||||
</footer>
|
||||
|
||||
<!-- Control Sidebar -->
|
||||
|
@ -344,6 +347,9 @@
|
|||
<!-- Datetimepicker -->
|
||||
<script src="{{asset('plugins/tempusdominus-bootstrap-4/js/tempusdominus-bootstrap-4.min.js')}}"></script>
|
||||
|
||||
<!-- Select2 -->
|
||||
<script src={{asset('plugins/select2/js/select2.min.js')}}>
|
||||
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('[data-toggle="popover"]').popover();
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
url: form.action,
|
||||
dataType: 'json',
|
||||
data: {
|
||||
"_token": "{{ csrf_token() }}",
|
||||
code: input.value
|
||||
},
|
||||
success: function (response) {
|
||||
|
|
|
@ -198,7 +198,7 @@
|
|||
extra
|
||||
<b><i
|
||||
class="fa fa-coins mx-1"></i>{{$credits_reward_after_verify_discord}}
|
||||
</b> credits and increased server limit
|
||||
</b> {{CREDITS_DISPLAY_NAME}} and increased server limit
|
||||
</p>
|
||||
@endif
|
||||
</div>
|
||||
|
|
|
@ -45,7 +45,9 @@
|
|||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-right shadow animated--fade-in" aria-labelledby="dropdownMenuLink">
|
||||
<a href="{{env('PTERODACTYL_URL' , 'http://localhost')}}/server/{{$server->identifier}}" target="__blank" class="dropdown-item text-info"><i title="manage" class="fas fa-tasks mr-2"></i><span>Manage</span></a>
|
||||
@if(!empty(env('PHPMYADMIN_URL')))
|
||||
<a href="{{env('PHPMYADMIN_URL' , 'http://localhost')}}" class="dropdown-item text-info" target="__blank"><i title="manage" class="fas fa-database mr-2"></i><span>Database</span></a>
|
||||
@endif
|
||||
<form method="post" onsubmit="return submitResult();" action="{{route('servers.destroy' , $server->id)}}">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
|
@ -87,7 +89,9 @@
|
|||
|
||||
<div class="card-footer d-flex justify-content-between">
|
||||
<a href="{{env('PTERODACTYL_URL' , 'http://localhost')}}/server/{{$server->identifier}}" target="__blank" class="btn btn-info mx-3 w-100"><i class="fas fa-tasks mr-2"></i>Manage</a>
|
||||
@if(!empty(env('PHPMYADMIN_URL')))
|
||||
<a href="{{env('PHPMYADMIN_URL' , 'http://localhost')}}" target="__blank" class="btn btn-info mx-3 w-100" ><i class="fas fa-database mr-2"></i>Database</a>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -81,7 +81,7 @@
|
|||
<tbody>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td><i class="fa fa-coins mr-2"></i>{{$product->quantity}} {{$product->type}}</td>
|
||||
<td><i class="fa fa-coins mr-2"></i>{{$product->quantity}} {{strtolower($product->type) == 'credits' ? CREDITS_DISPLAY_NAME : $product->type}}</td>
|
||||
<td>{{$product->description}}</td>
|
||||
<td>{{$product->formatCurrency()}}</td>
|
||||
</tr>
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title"><i class="fa fa-coins mr-2"></i>Credits</h5>
|
||||
<h5 class="card-title"><i class="fa fa-coins mr-2"></i>{{CREDITS_DISPLAY_NAME}}</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-striped table-responsive-sm">
|
||||
|
@ -51,7 +51,7 @@
|
|||
@foreach($products as $product)
|
||||
<tr>
|
||||
<td>{{$product->formatCurrency()}}</td>
|
||||
<td>{{$product->type}}</td>
|
||||
<td>{{strtolower($product->type) == 'credits' ? CREDITS_DISPLAY_NAME : $product->type}}</td>
|
||||
<td><i class="fa fa-coins mr-2"></i>{{$product->display}}</td>
|
||||
<td><a href="{{route('checkout' , $product->id)}}" class="btn btn-info">Purchase</a>
|
||||
</td>
|
||||
|
|
|
@ -1,186 +0,0 @@
|
|||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<body>
|
||||
<div class="container py-3">
|
||||
<h1>Privacy Policy</h1>
|
||||
<p>Last updated: February 17, 2021</p>
|
||||
<p>This Privacy Policy describes Our policies and procedures on the collection, use and disclosure of Your information when You use the Service and tells You about Your privacy rights and how the law protects You.</p>
|
||||
<p>We use Your Personal data to provide and improve the Service. By using the Service, You agree to the collection and use of information in accordance with this Privacy Policy. This Privacy Policy has been created with the help of the <a href="https://www.freeprivacypolicy.com/free-privacy-policy-generator/" target="_blank">Privacy Policy Generator</a>.</p>
|
||||
<h1>Interpretation and Definitions</h1>
|
||||
<h2>Interpretation</h2>
|
||||
<p>The words of which the initial letter is capitalized have meanings defined under the following conditions. The following definitions shall have the same meaning regardless of whether they appear in singular or in plural.</p>
|
||||
<h2>Definitions</h2>
|
||||
<p>For the purposes of this Privacy Policy:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p><strong>Account</strong> means a unique account created for You to access our Service or parts of our Service.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Company</strong> (referred to as either "the Company", "We", "Us" or "Our" in this Agreement) refers to Bitsec Hosting.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Cookies</strong> are small files that are placed on Your computer, mobile device or any other device by a website, containing the details of Your browsing history on that website among its many uses.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Country</strong> refers to: Netherlands</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Device</strong> means any device that can access the Service such as a computer, a cellphone or a digital tablet.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Personal Data</strong> is any information that relates to an identified or identifiable individual.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Service</strong> refers to the Website.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Service Provider</strong> means any natural or legal person who processes the data on behalf of the Company. It refers to third-party companies or individuals employed by the Company to facilitate the Service, to provide the Service on behalf of the Company, to perform services related to the Service or to assist the Company in analyzing how the Service is used.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Third-party Social Media Service</strong> refers to any website or any social network website through which a User can log in or create an account to use the Service.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Usage Data</strong> refers to data collected automatically, either generated by the use of the Service or from the Service infrastructure itself (for example, the duration of a page visit).</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Website</strong> refers to Bitsec Hosting, accessible from <a href="https://bitsec.dev" rel="external nofollow noopener" target="_blank">https://bitsec.dev</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>You</strong> means the individual accessing or using the Service, or the company, or other legal entity on behalf of which such individual is accessing or using the Service, as applicable.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<h1>Collecting and Using Your Personal Data</h1>
|
||||
<h2>Types of Data Collected</h2>
|
||||
<h3>Personal Data</h3>
|
||||
<p>While using Our Service, We may ask You to provide Us with certain personally identifiable information that can be used to contact or identify You. Personally identifiable information may include, but is not limited to:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p>Email address</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>First name and last name</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Phone number</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Address, State, Province, ZIP/Postal code, City</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Usage Data</p>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Usage Data</h3>
|
||||
<p>Usage Data is collected automatically when using the Service.</p>
|
||||
<p>Usage Data may include information such as Your Device's Internet Protocol address (e.g. IP address), browser type, browser version, the pages of our Service that You visit, the time and date of Your visit, the time spent on those pages, unique device identifiers and other diagnostic data.</p>
|
||||
<p>When You access the Service by or through a mobile device, We may collect certain information automatically, including, but not limited to, the type of mobile device You use, Your mobile device unique ID, the IP address of Your mobile device, Your mobile operating system, the type of mobile Internet browser You use, unique device identifiers and other diagnostic data.</p>
|
||||
<p>We may also collect information that Your browser sends whenever You visit our Service or when You access the Service by or through a mobile device.</p>
|
||||
<h3>Tracking Technologies and Cookies</h3>
|
||||
<p>We use Cookies and similar tracking technologies to track the activity on Our Service and store certain information. Tracking technologies used are beacons, tags, and scripts to collect and track information and to improve and analyze Our Service. The technologies We use may include:</p>
|
||||
<ul>
|
||||
<li><strong>Cookies or Browser Cookies.</strong> A cookie is a small file placed on Your Device. You can instruct Your browser to refuse all Cookies or to indicate when a Cookie is being sent. However, if You do not accept Cookies, You may not be able to use some parts of our Service. Unless you have adjusted Your browser setting so that it will refuse Cookies, our Service may use Cookies.</li>
|
||||
<li><strong>Flash Cookies.</strong> Certain features of our Service may use local stored objects (or Flash Cookies) to collect and store information about Your preferences or Your activity on our Service. Flash Cookies are not managed by the same browser settings as those used for Browser Cookies. For more information on how You can delete Flash Cookies, please read "Where can I change the settings for disabling, or deleting local shared objects?" available at <a href="https://helpx.adobe.com/flash-player/kb/disable-local-shared-objects-flash.html#main_Where_can_I_change_the_settings_for_disabling__or_deleting_local_shared_objects_" rel="external nofollow noopener" target="_blank">https://helpx.adobe.com/flash-player/kb/disable-local-shared-objects-flash.html#main_Where_can_I_change_the_settings_for_disabling__or_deleting_local_shared_objects_</a></li>
|
||||
<li><strong>Web Beacons.</strong> Certain sections of our Service and our emails may contain small electronic files known as web beacons (also referred to as clear gifs, pixel tags, and single-pixel gifs) that permit the Company, for example, to count users who have visited those pages or opened an email and for other related website statistics (for example, recording the popularity of a certain section and verifying system and server integrity).</li>
|
||||
</ul>
|
||||
<p>Cookies can be "Persistent" or "Session" Cookies. Persistent Cookies remain on Your personal computer or mobile device when You go offline, while Session Cookies are deleted as soon as You close Your web browser. Learn more about cookies: <a href="https://www.freeprivacypolicy.com/blog/cookies/" target="_blank">Cookies: What Do They Do?</a>.</p>
|
||||
<p>We use both Session and Persistent Cookies for the purposes set out below:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p><strong>Necessary / Essential Cookies</strong></p>
|
||||
<p>Type: Session Cookies</p>
|
||||
<p>Administered by: Us</p>
|
||||
<p>Purpose: These Cookies are essential to provide You with services available through the Website and to enable You to use some of its features. They help to authenticate users and prevent fraudulent use of user accounts. Without these Cookies, the services that You have asked for cannot be provided, and We only use these Cookies to provide You with those services.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Cookies Policy / Notice Acceptance Cookies</strong></p>
|
||||
<p>Type: Persistent Cookies</p>
|
||||
<p>Administered by: Us</p>
|
||||
<p>Purpose: These Cookies identify if users have accepted the use of cookies on the Website.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Functionality Cookies</strong></p>
|
||||
<p>Type: Persistent Cookies</p>
|
||||
<p>Administered by: Us</p>
|
||||
<p>Purpose: These Cookies allow us to remember choices You make when You use the Website, such as remembering your login details or language preference. The purpose of these Cookies is to provide You with a more personal experience and to avoid You having to re-enter your preferences every time You use the Website.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<p>For more information about the cookies we use and your choices regarding cookies, please visit our Cookies Policy or the Cookies section of our Privacy Policy.</p>
|
||||
<h2>Use of Your Personal Data</h2>
|
||||
<p>The Company may use Personal Data for the following purposes:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p><strong>To provide and maintain our Service</strong>, including to monitor the usage of our Service.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>To manage Your Account:</strong> to manage Your registration as a user of the Service. The Personal Data You provide can give You access to different functionalities of the Service that are available to You as a registered user.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>For the performance of a contract:</strong> the development, compliance and undertaking of the purchase contract for the products, items or services You have purchased or of any other contract with Us through the Service.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>To contact You:</strong> To contact You by email, telephone calls, SMS, or other equivalent forms of electronic communication, such as a mobile application's push notifications regarding updates or informative communications related to the functionalities, products or contracted services, including the security updates, when necessary or reasonable for their implementation.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>To provide You</strong> with news, special offers and general information about other goods, services and events which we offer that are similar to those that you have already purchased or enquired about unless You have opted not to receive such information.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>To manage Your requests:</strong> To attend and manage Your requests to Us.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>For business transfers:</strong> We may use Your information to evaluate or conduct a merger, divestiture, restructuring, reorganization, dissolution, or other sale or transfer of some or all of Our assets, whether as a going concern or as part of bankruptcy, liquidation, or similar proceeding, in which Personal Data held by Us about our Service users is among the assets transferred.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>For other purposes</strong>: We may use Your information for other purposes, such as data analysis, identifying usage trends, determining the effectiveness of our promotional campaigns and to evaluate and improve our Service, products, services, marketing and your experience.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<p>We may share Your personal information in the following situations:</p>
|
||||
<ul>
|
||||
<li><strong>With Service Providers:</strong> We may share Your personal information with Service Providers to monitor and analyze the use of our Service, to contact You.</li>
|
||||
<li><strong>For business transfers:</strong> We may share or transfer Your personal information in connection with, or during negotiations of, any merger, sale of Company assets, financing, or acquisition of all or a portion of Our business to another company.</li>
|
||||
<li><strong>With Affiliates:</strong> We may share Your information with Our affiliates, in which case we will require those affiliates to honor this Privacy Policy. Affiliates include Our parent company and any other subsidiaries, joint venture partners or other companies that We control or that are under common control with Us.</li>
|
||||
<li><strong>With business partners:</strong> We may share Your information with Our business partners to offer You certain products, services or promotions.</li>
|
||||
<li><strong>With other users:</strong> when You share personal information or otherwise interact in the public areas with other users, such information may be viewed by all users and may be publicly distributed outside. If You interact with other users or register through a Third-Party Social Media Service, Your contacts on the Third-Party Social Media Service may see Your name, profile, pictures and description of Your activity. Similarly, other users will be able to view descriptions of Your activity, communicate with You and view Your profile.</li>
|
||||
<li><strong>With Your consent</strong>: We may disclose Your personal information for any other purpose with Your consent.</li>
|
||||
</ul>
|
||||
<h2>Retention of Your Personal Data</h2>
|
||||
<p>The Company will retain Your Personal Data only for as long as is necessary for the purposes set out in this Privacy Policy. We will retain and use Your Personal Data to the extent necessary to comply with our legal obligations (for example, if we are required to retain your data to comply with applicable laws), resolve disputes, and enforce our legal agreements and policies.</p>
|
||||
<p>The Company will also retain Usage Data for internal analysis purposes. Usage Data is generally retained for a shorter period of time, except when this data is used to strengthen the security or to improve the functionality of Our Service, or We are legally obligated to retain this data for longer time periods.</p>
|
||||
<h2>Transfer of Your Personal Data</h2>
|
||||
<p>Your information, including Personal Data, is processed at the Company's operating offices and in any other places where the parties involved in the processing are located. It means that this information may be transferred to — and maintained on — computers located outside of Your state, province, country or other governmental jurisdiction where the data protection laws may differ than those from Your jurisdiction.</p>
|
||||
<p>Your consent to this Privacy Policy followed by Your submission of such information represents Your agreement to that transfer.</p>
|
||||
<p>The Company will take all steps reasonably necessary to ensure that Your data is treated securely and in accordance with this Privacy Policy and no transfer of Your Personal Data will take place to an organization or a country unless there are adequate controls in place including the security of Your data and other personal information.</p>
|
||||
<h2>Disclosure of Your Personal Data</h2>
|
||||
<h3>Business Transactions</h3>
|
||||
<p>If the Company is involved in a merger, acquisition or asset sale, Your Personal Data may be transferred. We will provide notice before Your Personal Data is transferred and becomes subject to a different Privacy Policy.</p>
|
||||
<h3>Law enforcement</h3>
|
||||
<p>Under certain circumstances, the Company may be required to disclose Your Personal Data if required to do so by law or in response to valid requests by public authorities (e.g. a court or a government agency).</p>
|
||||
<h3>Other legal requirements</h3>
|
||||
<p>The Company may disclose Your Personal Data in the good faith belief that such action is necessary to:</p>
|
||||
<ul>
|
||||
<li>Comply with a legal obligation</li>
|
||||
<li>Protect and defend the rights or property of the Company</li>
|
||||
<li>Prevent or investigate possible wrongdoing in connection with the Service</li>
|
||||
<li>Protect the personal safety of Users of the Service or the public</li>
|
||||
<li>Protect against legal liability</li>
|
||||
</ul>
|
||||
<h2>Security of Your Personal Data</h2>
|
||||
<p>The security of Your Personal Data is important to Us, but remember that no method of transmission over the Internet, or method of electronic storage is 100% secure. While We strive to use commercially acceptable means to protect Your Personal Data, We cannot guarantee its absolute security.</p>
|
||||
<h1>Children's Privacy</h1>
|
||||
<p>Our Service does not address anyone under the age of 13. We do not knowingly collect personally identifiable information from anyone under the age of 13. If You are a parent or guardian and You are aware that Your child has provided Us with Personal Data, please contact Us. If We become aware that We have collected Personal Data from anyone under the age of 13 without verification of parental consent, We take steps to remove that information from Our servers.</p>
|
||||
<p>If We need to rely on consent as a legal basis for processing Your information and Your country requires consent from a parent, We may require Your parent's consent before We collect and use that information.</p>
|
||||
<h1>Links to Other Websites</h1>
|
||||
<p>Our Service may contain links to other websites that are not operated by Us. If You click on a third party link, You will be directed to that third party's site. We strongly advise You to review the Privacy Policy of every site You visit.</p>
|
||||
<p>We have no control over and assume no responsibility for the content, privacy policies or practices of any third party sites or services.</p>
|
||||
<h1>Changes to this Privacy Policy</h1>
|
||||
<p>We may update Our Privacy Policy from time to time. We will notify You of any changes by posting the new Privacy Policy on this page.</p>
|
||||
<p>We will let You know via email and/or a prominent notice on Our Service, prior to the change becoming effective and update the "Last updated" date at the top of this Privacy Policy.</p>
|
||||
<p>You are advised to review this Privacy Policy periodically for any changes. Changes to this Privacy Policy are effective when they are posted on this page.</p>
|
||||
<h1>Contact Us</h1>
|
||||
<p>If you have any questions about this Privacy Policy, You can contact us:</p>
|
||||
<ul>
|
||||
<li>By email: bitsechosting@gmail.com</li>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
@endsection
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
|
||||
use App\Http\Controllers\Api\NotificationController;
|
||||
use App\Http\Controllers\Api\ServerController;
|
||||
use App\Http\Controllers\Api\UserController;
|
||||
use App\Http\Controllers\Api\VoucherController;
|
||||
|
@ -17,15 +18,20 @@ 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::patch('/servers/{server}/suspend', [ServerController::class, 'suspend']);
|
||||
Route::patch('/servers/{server}/unsuspend', [ServerController::class, 'unSuspend']);
|
||||
Route::resource('servers', ServerController::class)->except(['store', 'create', 'edit', 'update']);
|
||||
|
||||
// Route::get('/vouchers/{voucher}/users' , [VoucherController::class , 'users']);
|
||||
Route::resource('vouchers', VoucherController::class)->except('create' , 'edit');
|
||||
// Route::get('/vouchers/{voucher}/users' , [VoucherController::class , 'users']);
|
||||
Route::resource('vouchers', VoucherController::class)->except('create', 'edit');
|
||||
|
||||
Route::get('/notifications/{user}', [NotificationController::class, 'index']);
|
||||
Route::get('/notifications/{user}/{notification}', [NotificationController::class, 'view']);
|
||||
Route::post('/notifications', [NotificationController::class, 'send']);
|
||||
Route::delete('/notifications/{user}', [NotificationController::class, 'delete']);
|
||||
Route::delete('/notifications/{user}/{notification}', [NotificationController::class, 'deleteOne']);
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -74,8 +74,11 @@ Route::middleware('auth')->group(function () {
|
|||
|
||||
Route::resource('activitylogs', ActivityLogController::class);
|
||||
|
||||
Route::get("users.json", [UserController::class, "json"])->name('users.json');
|
||||
Route::get('users/loginas/{user}', [UserController::class, 'loginAs'])->name('users.loginas');
|
||||
Route::get('users/datatable', [UserController::class, 'datatable'])->name('users.datatable');
|
||||
Route::get('users/notifications', [UserController::class, 'notifications'])->name('users.notifications');
|
||||
Route::post('users/notifications', [UserController::class, 'notify'])->name('users.notifications');
|
||||
Route::resource('users', UserController::class);
|
||||
|
||||
Route::get('servers/datatable', [AdminServerController::class, 'datatable'])->name('servers.datatable');
|
||||
|
|
0
storage/app/.gitignore
vendored
Normal file → Executable file
0
storage/app/.gitignore
vendored
Normal file → Executable file
0
storage/app/public/.gitignore
vendored
Normal file → Executable file
0
storage/app/public/.gitignore
vendored
Normal file → Executable file
0
storage/framework/.gitignore
vendored
Normal file → Executable file
0
storage/framework/.gitignore
vendored
Normal file → Executable file
0
storage/framework/cache/.gitignore
vendored
Normal file → Executable file
0
storage/framework/cache/.gitignore
vendored
Normal file → Executable file
0
storage/framework/cache/data/.gitignore
vendored
Normal file → Executable file
0
storage/framework/cache/data/.gitignore
vendored
Normal file → Executable file
0
storage/framework/sessions/.gitignore
vendored
Normal file → Executable file
0
storage/framework/sessions/.gitignore
vendored
Normal file → Executable file
0
storage/framework/testing/.gitignore
vendored
Normal file → Executable file
0
storage/framework/testing/.gitignore
vendored
Normal file → Executable file
0
storage/framework/views/.gitignore
vendored
Normal file → Executable file
0
storage/framework/views/.gitignore
vendored
Normal file → Executable file
0
storage/logs/.gitignore
vendored
Normal file → Executable file
0
storage/logs/.gitignore
vendored
Normal file → Executable file
Loading…
Reference in a new issue