Jelajahi Sumber

Merge branch 'development' into patch-1

AVMG 4 tahun lalu
induk
melakukan
131321b83f
35 mengubah file dengan 471 tambahan dan 98 penghapusan
  1. 2 1
      .gitignore
  2. 6 2
      app/Classes/Pterodactyl.php
  3. 0 1
      app/Console/Kernel.php
  4. 52 19
      app/Http/Controllers/Admin/PaymentController.php
  5. 2 2
      app/Http/Controllers/Admin/ProductController.php
  6. 1 8
      app/Http/Controllers/Auth/RegisterController.php
  7. 0 3
      app/Http/Controllers/HomeController.php
  8. 1 0
      app/Http/Controllers/StoreController.php
  9. 19 14
      app/Models/Payment.php
  10. 4 0
      app/Models/PaypalProduct.php
  11. 64 0
      app/Notifications/ConfirmPaymentNotification.php
  12. 1 0
      app/Notifications/ServerCreationError.php
  13. 2 1
      app/Notifications/WelcomeMessage.php
  14. 38 0
      database/factories/PaymentFactory.php
  15. 33 0
      database/factories/ProductFactory.php
  16. 34 0
      database/factories/ServerFactory.php
  17. 3 1
      database/factories/UserFactory.php
  18. 32 0
      database/migrations/2021_06_23_090026_update_price_to_payments_table.php
  19. 32 0
      database/migrations/2021_06_23_090806_add__currency_code_to_payments_table.php
  20. 1 0
      database/seeders/DatabaseSeeder.php
  21. 21 0
      database/seeders/DevelopmentSeeder.php
  22. 4 0
      database/seeders/ExampleItemsSeeder.php
  23. 1 1
      database/seeders/Seeds/ApplicationApiSeeder.php
  24. 17 1
      database/seeders/Seeds/ConfigurationSeeder.php
  25. 1 1
      database/seeders/Seeds/PaypalProductSeeder.php
  26. 1 1
      database/seeders/Seeds/ProductSeeder.php
  27. 1 1
      database/seeders/Seeds/UsefulLinksSeeder.php
  28. 23 0
      database/seeders/Seeds/UserSeeder.php
  29. 1 1
      resources/views/admin/configurations/index.blade.php
  30. 37 30
      resources/views/admin/payments/index.blade.php
  31. 18 0
      resources/views/mail/payment/confirmed.blade.php
  32. 4 2
      resources/views/servers/create.blade.php
  33. 6 6
      resources/views/servers/index.blade.php
  34. 2 2
      resources/views/store/index.blade.php
  35. 7 0
      routes/web.php

+ 2 - 1
.gitignore

@@ -5,8 +5,9 @@
 /vendor
 /vendor
 /storage/credit_deduction_log
 /storage/credit_deduction_log
 .env
 .env
-.idea
+.env.testing
 .env.backup
 .env.backup
+.idea
 .phpunit.result.cache
 .phpunit.result.cache
 docker-compose.override.yml
 docker-compose.override.yml
 Homestead.json
 Homestead.json

+ 6 - 2
app/Classes/Pterodactyl.php

@@ -49,8 +49,12 @@ class Pterodactyl
         $response = self::getAllocations($node);
         $response = self::getAllocations($node);
         $freeAllocations = [];
         $freeAllocations = [];
 
 
-        foreach ($response['data'] as $allocation) {
-            if (!$allocation['attributes']['assigned']) array_push($freeAllocations, $allocation);
+        if(isset($response['data'])){
+            if (!empty($response['data'])) {
+                foreach ($response['data'] as $allocation) {
+                    if (!$allocation['attributes']['assigned']) array_push($freeAllocations, $allocation);
+                }
+            }
         }
         }
 
 
         return $freeAllocations;
         return $freeAllocations;

+ 0 - 1
app/Console/Kernel.php

@@ -26,7 +26,6 @@ class Kernel extends ConsoleKernel
     protected function schedule(Schedule $schedule)
     protected function schedule(Schedule $schedule)
     {
     {
         $schedule->command('credits:charge')->hourly();
         $schedule->command('credits:charge')->hourly();
-        $schedule->command('queue:work --once')->everyMinute();
 
 
         //log cronjob activity
         //log cronjob activity
         $schedule->call(function () {
         $schedule->call(function () {

+ 52 - 19
app/Http/Controllers/Admin/PaymentController.php

@@ -3,11 +3,17 @@
 namespace App\Http\Controllers\Admin;
 namespace App\Http\Controllers\Admin;
 
 
 use App\Http\Controllers\Controller;
 use App\Http\Controllers\Controller;
+use App\Models\Configuration;
 use App\Models\Payment;
 use App\Models\Payment;
 use App\Models\PaypalProduct;
 use App\Models\PaypalProduct;
+use App\Models\Product;
+use App\Models\User;
+use App\Notifications\ConfirmPaymentNotification;
+use Exception;
 use Illuminate\Contracts\Foundation\Application;
 use Illuminate\Contracts\Foundation\Application;
 use Illuminate\Contracts\View\Factory;
 use Illuminate\Contracts\View\Factory;
 use Illuminate\Contracts\View\View;
 use Illuminate\Contracts\View\View;
+use Illuminate\Http\JsonResponse;
 use Illuminate\Http\RedirectResponse;
 use Illuminate\Http\RedirectResponse;
 use Illuminate\Http\Request;
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\Facades\Auth;
@@ -20,15 +26,11 @@ use PayPalHttp\HttpException;
 
 
 class PaymentController extends Controller
 class PaymentController extends Controller
 {
 {
-    protected $allowedAmounts = [
-        '87',
-        '350',
-        '1000',
-        '2000',
-        '4000'
-    ];
-
-    public function index(){
+    /**
+     * @return Application|Factory|View
+     */
+    public function index()
+    {
         return view('admin.payments.index')->with([
         return view('admin.payments.index')->with([
             'payments' => Payment::paginate(15)
             'payments' => Payment::paginate(15)
         ]);
         ]);
@@ -51,13 +53,13 @@ class PaymentController extends Controller
      * @param PaypalProduct $paypalProduct
      * @param PaypalProduct $paypalProduct
      * @return RedirectResponse
      * @return RedirectResponse
      */
      */
-    public function pay(Request $request , PaypalProduct $paypalProduct)
+    public function pay(Request $request, PaypalProduct $paypalProduct)
     {
     {
         $request = new OrdersCreateRequest();
         $request = new OrdersCreateRequest();
         $request->prefer('return=representation');
         $request->prefer('return=representation');
         $request->body = [
         $request->body = [
-            "intent"              => "CAPTURE",
-            "purchase_units"      => [
+            "intent" => "CAPTURE",
+            "purchase_units" => [
                 [
                 [
                     "reference_id" => uniqid(),
                     "reference_id" => uniqid(),
                     "description" => $paypalProduct->description,
                     "description" => $paypalProduct->description,
@@ -122,7 +124,10 @@ class PaymentController extends Controller
      */
      */
     public function success(Request $laravelRequest)
     public function success(Request $laravelRequest)
     {
     {
+        /** @var PaypalProduct $paypalProduct */
         $paypalProduct = PaypalProduct::findOrFail($laravelRequest->input('product'));
         $paypalProduct = PaypalProduct::findOrFail($laravelRequest->input('product'));
+        /** @var User $user */
+        $user = Auth::user();
 
 
         $request = new OrdersCaptureRequest($laravelRequest->input('token'));
         $request = new OrdersCaptureRequest($laravelRequest->input('token'));
         $request->prefer('return=representation');
         $request->prefer('return=representation');
@@ -132,30 +137,36 @@ class PaymentController extends Controller
             if ($response->statusCode == 201 || $response->statusCode == 200) {
             if ($response->statusCode == 201 || $response->statusCode == 200) {
 
 
                 //update credits
                 //update credits
-                Auth::user()->increment('credits', $paypalProduct->quantity);
+                $user->increment('credits', $paypalProduct->quantity);
 
 
                 //update server limit
                 //update server limit
-                if (Auth::user()->server_limit < 10) {
-                    Auth::user()->update(['server_limit' => 10]);
+                if (Configuration::getValueByKey('SERVER_LIMIT_AFTER_IRL_PURCHASE', 10) !== 0) {
+                    if ($user->server_limit < Configuration::getValueByKey('SERVER_LIMIT_AFTER_IRL_PURCHASE', 10)) {
+                        $user->update(['server_limit' => 10]);
+                    }
                 }
                 }
 
 
                 //update role
                 //update role
-                if (Auth::user()->role == 'member') {
-                    Auth::user()->update(['role' => 'client']);
+                if ($user->role == 'member') {
+                    $user->update(['role' => 'client']);
                 }
                 }
 
 
                 //store payment
                 //store payment
-                Payment::create([
-                    'user_id' => Auth::user()->id,
+                $payment = Payment::create([
+                    'user_id' => $user->id,
                     'payment_id' => $response->result->id,
                     'payment_id' => $response->result->id,
                     'payer_id' => $laravelRequest->input('PayerID'),
                     'payer_id' => $laravelRequest->input('PayerID'),
                     'type' => 'Credits',
                     'type' => 'Credits',
                     'status' => $response->result->status,
                     'status' => $response->result->status,
                     'amount' => $paypalProduct->quantity,
                     'amount' => $paypalProduct->quantity,
                     'price' => $paypalProduct->price,
                     'price' => $paypalProduct->price,
+                    'currency_code' => $paypalProduct->currency_code,
                     'payer' => json_encode($response->result->payer),
                     'payer' => json_encode($response->result->payer),
                 ]);
                 ]);
 
 
+                //payment notification
+                $user->notify(new ConfirmPaymentNotification($payment));
+
                 //redirect back to home
                 //redirect back to home
                 return redirect()->route('home')->with('success', 'Your credit balance has been increased!');
                 return redirect()->route('home')->with('success', 'Your credit balance has been increased!');
             }
             }
@@ -187,4 +198,26 @@ class PaymentController extends Controller
     {
     {
         return redirect()->route('store.index')->with('success', 'Payment was Cannceled');
         return redirect()->route('store.index')->with('success', 'Payment was Cannceled');
     }
     }
+
+
+    /**
+     * @return JsonResponse|mixed
+     * @throws Exception
+     */
+    public function dataTable()
+    {
+        $query = Payment::with('user');
+
+        return datatables($query)
+            ->editColumn('user', function (Payment $payment) {
+                return $payment->user->name;
+            })
+            ->editColumn('price', function (Payment $payment) {
+                return $payment->formatCurrency();
+            })
+            ->editColumn('created_at', function (Payment $payment) {
+                return $payment->created_at ? $payment->created_at->diffForHumans() : '';
+            })
+            ->make();
+    }
 }
 }

+ 2 - 2
app/Http/Controllers/Admin/ProductController.php

@@ -47,7 +47,7 @@ class ProductController extends Controller
             "name" => "required|max:30",
             "name" => "required|max:30",
             "price" => "required|numeric|max:1000000|min:0",
             "price" => "required|numeric|max:1000000|min:0",
             "memory" => "required|numeric|max:1000000|min:5",
             "memory" => "required|numeric|max:1000000|min:5",
-            "cpu" => "required|numeric|max:1000000|min:5",
+            "cpu" => "required|numeric|max:1000000|min:0",
             "swap" => "required|numeric|max:1000000|min:0",
             "swap" => "required|numeric|max:1000000|min:0",
             "description" => "required",
             "description" => "required",
             "disk" => "required|numeric|max:1000000|min:5",
             "disk" => "required|numeric|max:1000000|min:5",
@@ -103,7 +103,7 @@ class ProductController extends Controller
             "name" => "required|max:30",
             "name" => "required|max:30",
             "price" => "required|numeric|max:1000000|min:0",
             "price" => "required|numeric|max:1000000|min:0",
             "memory" => "required|numeric|max:1000000|min:5",
             "memory" => "required|numeric|max:1000000|min:5",
-            "cpu" => "required|numeric|max:1000000|min:5",
+            "cpu" => "required|numeric|max:1000000|min:0",
             "swap" => "required|numeric|max:1000000|min:0",
             "swap" => "required|numeric|max:1000000|min:0",
             "description" => "required",
             "description" => "required",
             "disk" => "required|numeric|max:1000000|min:5",
             "disk" => "required|numeric|max:1000000|min:5",

+ 1 - 8
app/Http/Controllers/Auth/RegisterController.php

@@ -56,21 +56,14 @@ class RegisterController extends Controller
         $data['ip'] = session()->get('ip') ?? request()->ip();
         $data['ip'] = session()->get('ip') ?? request()->ip();
         if (User::where('ip', '=', request()->ip())->exists()) session()->put('ip', request()->ip());
         if (User::where('ip', '=', request()->ip())->exists()) session()->put('ip', request()->ip());
 
 
-        //check if registered cookie exists as extra defense
-        if (isset($_COOKIE['4b3403665fea6'])) {
-            $data['registered'] = env('APP_ENV') == 'local' ? false : true;
-        }
-
         return Validator::make($data, [
         return Validator::make($data, [
             'name'                 => ['required', 'string', 'max:30', 'min:4', 'alpha_num', 'unique:users'],
             'name'                 => ['required', 'string', 'max:30', 'min:4', 'alpha_num', 'unique:users'],
             'email'                => ['required', 'string', 'email', 'max:64', 'unique:users'],
             'email'                => ['required', 'string', 'email', 'max:64', 'unique:users'],
             'password'             => ['required', 'string', 'min:8', 'confirmed'],
             'password'             => ['required', 'string', 'min:8', 'confirmed'],
             'g-recaptcha-response' => ['recaptcha'],
             'g-recaptcha-response' => ['recaptcha'],
             'ip'                   => ['unique:users'],
             'ip'                   => ['unique:users'],
-            'registered'           => ['nullable', 'boolean', 'in:true']
         ], [
         ], [
-            'ip.unique'  => "You have already made an account with us! Please contact support if you think this is incorrect.",
-            'registered.in' => "You have already made an account with us! Please contact support if you think this is incorrect."
+            'ip.unique'  => "You have already made an account with us! Please contact support if you think this is incorrect."
         ]);
         ]);
     }
     }
 
 

+ 0 - 3
app/Http/Controllers/HomeController.php

@@ -18,9 +18,6 @@ class HomeController extends Controller
     /** Show the application dashboard. */
     /** Show the application dashboard. */
     public function index(Request $request)
     public function index(Request $request)
     {
     {
-        //set cookie as extra layer of defense against users that make multiple accounts
-        setcookie('4b3403665fea6' , base64_encode(1) , time() + (20 * 365 * 24 * 60 * 60));
-
         $usage = 0;
         $usage = 0;
 
 
         foreach (Auth::user()->Servers as $server){
         foreach (Auth::user()->Servers as $server){

+ 1 - 0
app/Http/Controllers/StoreController.php

@@ -16,6 +16,7 @@ class StoreController extends Controller
     {
     {
         $isPaypalSetup = false;
         $isPaypalSetup = false;
         if (env('PAYPAL_SECRET') && env('PAYPAL_CLIENT_ID')) $isPaypalSetup = true;
         if (env('PAYPAL_SECRET') && env('PAYPAL_CLIENT_ID')) $isPaypalSetup = true;
+        if (env('APP_ENV' , 'local') == 'local') $isPaypalSetup = true;
 
 
         return view('store.index')->with([
         return view('store.index')->with([
             'products' => PaypalProduct::where('disabled' , '=' , false)->orderBy('price' , 'asc')->get(),
             'products' => PaypalProduct::where('disabled' , '=' , false)->orderBy('price' , 'asc')->get(),

+ 19 - 14
app/Models/Payment.php

@@ -6,6 +6,7 @@ use Hidehalo\Nanoid\Client;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
+use NumberFormatter;
 use Spatie\Activitylog\Traits\LogsActivity;
 use Spatie\Activitylog\Traits\LogsActivity;
 
 
 class Payment extends Model
 class Payment extends Model
@@ -19,21 +20,23 @@ class Payment extends Model
      * @var string[]
      * @var string[]
      */
      */
     protected $fillable = [
     protected $fillable = [
-       'id',
-      'user_id',
-      'payment_id',
-      'payer_id',
-      'payer',
-      'status',
-      'type',
-      'amount',
-      'price',
+        'id',
+        'user_id',
+        'payment_id',
+        'payer_id',
+        'payer',
+        'status',
+        'type',
+        'amount',
+        'price',
+        'currency_code',
     ];
     ];
 
 
-    public static function boot() {
+    public static function boot()
+    {
         parent::boot();
         parent::boot();
 
 
-        static::creating(function(Payment $payment) {
+        static::creating(function (Payment $payment) {
             $client = new Client();
             $client = new Client();
 
 
             $payment->{$payment->getKeyName()} = $client->generateId($size = 8);
             $payment->{$payment->getKeyName()} = $client->generateId($size = 8);
@@ -43,12 +46,14 @@ class Payment extends Model
     /**
     /**
      * @return BelongsTo
      * @return BelongsTo
      */
      */
-    public function User(){
+    public function user()
+    {
         return $this->belongsTo(User::class);
         return $this->belongsTo(User::class);
     }
     }
 
 
-    public function Price()
+    public function formatCurrency($locale = 'en_US')
     {
     {
-        return number_format($this->price, 2, '.', '');
+        $formatter = new NumberFormatter($locale, NumberFormatter::CURRENCY);
+        return $formatter->formatCurrency($this->price, $this->currency_code);
     }
     }
 }
 }

+ 4 - 0
app/Models/PaypalProduct.php

@@ -39,6 +39,10 @@ class PaypalProduct extends Model
         });
         });
     }
     }
 
 
+    /**
+     * @param string $locale
+     * @return string
+     */
     public function formatCurrency($locale = 'en_US')
     public function formatCurrency($locale = 'en_US')
     {
     {
         $formatter = new NumberFormatter($locale, NumberFormatter::CURRENCY);
         $formatter = new NumberFormatter($locale, NumberFormatter::CURRENCY);

+ 64 - 0
app/Notifications/ConfirmPaymentNotification.php

@@ -0,0 +1,64 @@
+<?php
+
+namespace App\Notifications;
+
+use App\Models\Payment;
+use Illuminate\Bus\Queueable;
+use Illuminate\Contracts\Queue\ShouldQueue;
+use Illuminate\Notifications\Messages\MailMessage;
+use Illuminate\Notifications\Notification;
+
+class ConfirmPaymentNotification extends Notification implements ShouldQueue
+{
+    use Queueable;
+
+    private Payment $payment;
+
+    /**
+     * Create a new notification instance.
+     *
+     * @return void
+     */
+    public function __construct(Payment $payment)
+    {
+        $this->payment = $payment;
+    }
+
+    /**
+     * Get the notification's delivery channels.
+     *
+     * @param  mixed  $notifiable
+     * @return array
+     */
+    public function via($notifiable)
+    {
+        return ['mail'];
+    }
+
+    /**
+     * Get the mail representation of the notification.
+     *
+     * @param  mixed  $notifiable
+     * @return MailMessage
+     */
+    public function toMail($notifiable)
+    {
+        return (new MailMessage)
+            ->subject('Payment Confirmation')
+            ->markdown('mail.payment.confirmed' , ['payment' => $this->payment]);
+    }
+
+    /**
+     * Get the array representation of the notification.
+     *
+     * @param mixed $notifiable
+     * @return array
+     */
+    public function toArray($notifiable)
+    {
+        return [
+            'title'   => "Payment Confirmed!",
+            'content' => "Payment Confirmed!",
+        ];
+    }
+}

+ 1 - 0
app/Notifications/ServerCreationError.php

@@ -8,6 +8,7 @@ use Illuminate\Bus\Queueable;
 use Illuminate\Notifications\Notification;
 use Illuminate\Notifications\Notification;
 
 
 class ServerCreationError extends Notification
 class ServerCreationError extends Notification
+
 {
 {
     use Queueable;
     use Queueable;
     /**
     /**

+ 2 - 1
app/Notifications/WelcomeMessage.php

@@ -5,9 +5,10 @@ namespace App\Notifications;
 use App\Models\Configuration;
 use App\Models\Configuration;
 use App\Models\User;
 use App\Models\User;
 use Illuminate\Bus\Queueable;
 use Illuminate\Bus\Queueable;
+use Illuminate\Contracts\Queue\ShouldQueue;
 use Illuminate\Notifications\Notification;
 use Illuminate\Notifications\Notification;
 
 
-class WelcomeMessage extends Notification
+class WelcomeMessage extends Notification implements ShouldQueue
 {
 {
     use Queueable;
     use Queueable;
 
 

+ 38 - 0
database/factories/PaymentFactory.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace Database\Factories;
+
+use App\Models\Payment;
+use App\Models\User;
+use Illuminate\Database\Eloquent\Factories\Factory;
+use Illuminate\Support\Str;
+
+class PaymentFactory extends Factory
+{
+    /**
+     * The name of the factory's corresponding model.
+     *
+     * @var string
+     */
+    protected $model = Payment::class;
+
+    /**
+     * Define the model's default state.
+     *
+     * @return array
+     */
+    public function definition()
+    {
+        return [
+            'payment_id' => Str::random(30),
+            'payer_id' => Str::random(30),
+            'user_id' => User::factory(),
+            'type' => "Credits",
+            'status' => "Completed",
+            'amount' => $this->faker->numberBetween(10, 10000),
+            'price' => $this->faker->numerify('##.##'),
+            'currency_code' => ['EUR', 'USD'][rand(0,1)],
+            'payer' => '{}',
+        ];
+    }
+}

+ 33 - 0
database/factories/ProductFactory.php

@@ -0,0 +1,33 @@
+<?php
+
+namespace Database\Factories;
+
+use App\Models\Product;
+use Illuminate\Database\Eloquent\Factories\Factory;
+
+class ProductFactory extends Factory
+{
+    /**
+     * The name of the factory's corresponding model.
+     *
+     * @var string
+     */
+    protected $model = Product::class;
+
+    /**
+     * Define the model's default state.
+     *
+     * @return array
+     */
+    public function definition()
+    {
+        return [
+            'name' => $this->faker->name,
+            'description' => $this->faker->text(60),
+            'price' => $this->faker->numberBetween(0 , 1000),
+            'memory' => $this->faker->numberBetween(32 , 1024),
+            'disk' => $this->faker->numberBetween(500 , 5000),
+            'databases' => $this->faker->numberBetween(1 , 10)
+        ];
+    }
+}

+ 34 - 0
database/factories/ServerFactory.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace Database\Factories;
+
+use App\Models\Product;
+use App\Models\Server;
+use Illuminate\Database\Eloquent\Factories\Factory;
+use Illuminate\Support\Str;
+
+class ServerFactory extends Factory
+{
+    /**
+     * The name of the factory's corresponding model.
+     *
+     * @var string
+     */
+    protected $model = Server::class;
+
+    /**
+     * Define the model's default state.
+     *
+     * @return array
+     */
+    public function definition()
+    {
+        return [
+            'name' => $this->faker->name,
+            'description' => $this->faker->text(60),
+            'identifier' => Str::random(30),
+            'pterodactyl_id' => $this->faker->numberBetween(1000000,1000000000),
+            'product_id' => Product::factory()
+        ];
+    }
+}

+ 3 - 1
database/factories/UserFactory.php

@@ -25,7 +25,9 @@ class UserFactory extends Factory
         return [
         return [
             'name' => $this->faker->name,
             'name' => $this->faker->name,
             'email' => $this->faker->unique()->safeEmail,
             'email' => $this->faker->unique()->safeEmail,
-            'email_verified_at' => now(),
+            'credits' => $this->faker->numberBetween(0,1500),
+            'last_seen' => $this->faker->dateTimeBetween(now(), '+30 days'),
+            'email_verified_at' => $this->faker->dateTimeBetween('-30 days', now()),
             'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
             'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
             'remember_token' => Str::random(10),
             'remember_token' => Str::random(10),
         ];
         ];

+ 32 - 0
database/migrations/2021_06_23_090026_update_price_to_payments_table.php

@@ -0,0 +1,32 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class UpdatePriceToPaymentsTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('payments', function (Blueprint $table) {
+            $table->decimal('price')->change();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('payments', function (Blueprint $table) {
+            $table->string('price')->change()->nullable();;
+        });
+    }
+}

+ 32 - 0
database/migrations/2021_06_23_090806_add__currency_code_to_payments_table.php

@@ -0,0 +1,32 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class AddCurrencyCodeToPaymentsTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('payments', function (Blueprint $table) {
+            $table->string('currency_code' , 3)->default('USD')->after('price');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('payments', function (Blueprint $table) {
+            $table->dropColumn('currency_code');
+        });
+    }
+}

+ 1 - 0
database/seeders/DatabaseSeeder.php

@@ -2,6 +2,7 @@
 
 
 namespace Database\Seeders;
 namespace Database\Seeders;
 
 
+use Database\Seeders\Seeds\ConfigurationSeeder;
 use Illuminate\Database\Seeder;
 use Illuminate\Database\Seeder;
 
 
 class DatabaseSeeder extends Seeder
 class DatabaseSeeder extends Seeder

+ 21 - 0
database/seeders/DevelopmentSeeder.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace Database\Seeders;
+
+use Database\Seeders\Seeds\UserSeeder;
+use Illuminate\Database\Seeder;
+
+class DevelopmentSeeder extends Seeder
+{
+    /**
+     * Run the database seeds.
+     *
+     * @return void
+     */
+    public function run()
+    {
+        $this->call([
+            UserSeeder::class,
+        ]);
+    }
+}

+ 4 - 0
database/seeders/ExampleItemsSeeder.php

@@ -2,6 +2,10 @@
 
 
 namespace Database\Seeders;
 namespace Database\Seeders;
 
 
+use Database\Seeders\Seeds\ProductSeeder;
+use Database\Seeders\Seeds\PaypalProductSeeder;
+use Database\Seeders\Seeds\ApplicationApiSeeder;
+use Database\Seeders\Seeds\UsefulLinksSeeder;
 use Illuminate\Database\Seeder;
 use Illuminate\Database\Seeder;
 
 
 class ExampleItemsSeeder extends Seeder
 class ExampleItemsSeeder extends Seeder

+ 1 - 1
database/seeders/ApplicationApiSeeder.php → database/seeders/Seeds/ApplicationApiSeeder.php

@@ -1,6 +1,6 @@
 <?php
 <?php
 
 
-namespace Database\Seeders;
+namespace Database\Seeders\Seeds;
 
 
 use App\Models\ApplicationApi;
 use App\Models\ApplicationApi;
 use Illuminate\Database\Seeder;
 use Illuminate\Database\Seeder;

+ 17 - 1
database/seeders/ConfigurationSeeder.php → database/seeders/Seeds/ConfigurationSeeder.php

@@ -1,6 +1,6 @@
 <?php
 <?php
 
 
-namespace Database\Seeders;
+namespace Database\Seeders\Seeds;
 
 
 use App\Models\Configuration;
 use App\Models\Configuration;
 use Illuminate\Database\Seeder;
 use Illuminate\Database\Seeder;
@@ -20,6 +20,7 @@ class ConfigurationSeeder extends Seeder
         ], [
         ], [
             'value' => '250',
             'value' => '250',
             'type'  => 'integer',
             'type'  => 'integer',
+            'description' => 'The initial amount of credits the user starts with.'
         ]);
         ]);
 
 
         Configuration::firstOrCreate([
         Configuration::firstOrCreate([
@@ -27,6 +28,7 @@ class ConfigurationSeeder extends Seeder
         ], [
         ], [
             'value' => '1',
             'value' => '1',
             'type'  => 'integer',
             'type'  => 'integer',
+            'description' => 'The initial server limit the user starts with.'
         ]);
         ]);
 
 
         //verify email event
         //verify email event
@@ -35,6 +37,7 @@ class ConfigurationSeeder extends Seeder
         ], [
         ], [
             'value' => '250',
             'value' => '250',
             'type'  => 'integer',
             'type'  => 'integer',
+            'description' => 'Increase in credits after the user has verified their email account.'
         ]);
         ]);
 
 
         Configuration::firstOrCreate([
         Configuration::firstOrCreate([
@@ -42,6 +45,7 @@ class ConfigurationSeeder extends Seeder
         ], [
         ], [
             'value' => '2',
             'value' => '2',
             'type'  => 'integer',
             'type'  => 'integer',
+            'description' => 'Increase in server limit after the user has verified their email account.'
         ]);
         ]);
 
 
         //verify discord event
         //verify discord event
@@ -50,6 +54,7 @@ class ConfigurationSeeder extends Seeder
         ] , [
         ] , [
             'value' => '375',
             'value' => '375',
             'type'  => 'integer',
             'type'  => 'integer',
+            'description' => 'Increase in credits after the user has verified their discord account.'
         ]);
         ]);
 
 
         Configuration::firstOrCreate([
         Configuration::firstOrCreate([
@@ -57,6 +62,7 @@ class ConfigurationSeeder extends Seeder
         ], [
         ], [
             'value' => '2',
             'value' => '2',
             'type'  => 'integer',
             'type'  => 'integer',
+            'description' => 'Increase in server limit after the user has verified their discord account.'
         ]);
         ]);
 
 
         //other
         //other
@@ -65,6 +71,16 @@ class ConfigurationSeeder extends Seeder
         ], [
         ], [
             'value' => '50',
             'value' => '50',
             'type'  => 'integer',
             'type'  => 'integer',
+            'description' => 'The minimum amount of credits the user would need to make a server.'
+        ]);
+
+        //purchasing
+        Configuration::firstOrCreate([
+            'key' => 'SERVER_LIMIT_AFTER_IRL_PURCHASE',
+        ], [
+            'value' => '10',
+            'type'  => 'integer',
+            'description' => 'updates the users server limit to this amount (unless the user already has a higher server limit) after making a purchase with real money, set to 0 to ignore this.',
         ]);
         ]);
     }
     }
 }
 }

+ 1 - 1
database/seeders/PaypalProductSeeder.php → database/seeders/Seeds/PaypalProductSeeder.php

@@ -1,6 +1,6 @@
 <?php
 <?php
 
 
-namespace Database\Seeders;
+namespace Database\Seeders\Seeds;
 
 
 use App\Models\PaypalProduct;
 use App\Models\PaypalProduct;
 use Illuminate\Database\Seeder;
 use Illuminate\Database\Seeder;

+ 1 - 1
database/seeders/ProductSeeder.php → database/seeders/Seeds/ProductSeeder.php

@@ -1,6 +1,6 @@
 <?php
 <?php
 
 
-namespace Database\Seeders;
+namespace Database\Seeders\Seeds;
 
 
 use App\Models\Product;
 use App\Models\Product;
 use Illuminate\Database\Seeder;
 use Illuminate\Database\Seeder;

+ 1 - 1
database/seeders/UsefulLinksSeeder.php → database/seeders/Seeds/UsefulLinksSeeder.php

@@ -1,6 +1,6 @@
 <?php
 <?php
 
 
-namespace Database\Seeders;
+namespace Database\Seeders\Seeds;
 
 
 use App\Models\UsefulLink;
 use App\Models\UsefulLink;
 use Illuminate\Database\Seeder;
 use Illuminate\Database\Seeder;

+ 23 - 0
database/seeders/Seeds/UserSeeder.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace Database\Seeders\Seeds;
+
+use App\Models\Server;
+use App\Models\User;
+use Illuminate\Database\Seeder;
+
+class UserSeeder extends Seeder
+{
+    /**
+     * Run the database seeds.
+     *
+     * @return void
+     */
+    public function run()
+    {
+        User::factory()
+            ->count(10)
+            ->has(Server::factory()->count(rand(1,3)) , 'servers')
+            ->create();
+    }
+}

+ 1 - 1
resources/views/admin/configurations/index.blade.php

@@ -40,7 +40,7 @@
                             <th>Key</th>
                             <th>Key</th>
                             <th>Value</th>
                             <th>Value</th>
                             <th>Type</th>
                             <th>Type</th>
-                            <th>Description</th>
+                            <th width="600">Description</th>
                             <th>Created at</th>
                             <th>Created at</th>
                             <th></th>
                             <th></th>
                         </tr>
                         </tr>

+ 37 - 30
resources/views/admin/payments/index.blade.php

@@ -28,48 +28,55 @@
                 <div class="card-header">
                 <div class="card-header">
                     <h5 class="card-title"><i class="fas fa-money-bill-wave mr-2"></i>Payments</h5>
                     <h5 class="card-title"><i class="fas fa-money-bill-wave mr-2"></i>Payments</h5>
                 </div>
                 </div>
-                <div class="card-body table-responsive">
 
 
-                    <table class="table table-striped">
+                <div class="card-body table-responsive">
+                    <table id="datatable" class="table table-striped">
                         <thead>
                         <thead>
-                            <tr>
-                                <th>ID</th>
-                                <th>User</th>
-                                <th>Type</th>
-                                <th>Amount</th>
-                                <th>Price</th>
-                                <th>Payment_ID</th>
-                                <th>Payer_ID</th>
-                                <th>Created at</th>
-                            </tr>
+                        <tr>
+                            <th>ID</th>
+                            <th>User</th>
+                            <th>Type</th>
+                            <th>Amount</th>
+                            <th>Price</th>
+                            <th>Payment_ID</th>
+                            <th>Payer_ID</th>
+                            <th>Created at</th>
+                        </tr>
                         </thead>
                         </thead>
                         <tbody>
                         <tbody>
-                            @foreach($payments as $payment)
-                                <tr>
-                                    <td>{{$payment->id}}</td>
-                                    <td>{{$payment->User->name}}</td>
-                                    <td>{{$payment->type}}</td>
-                                    <td><i class="fa fa-coins mr-2"></i>{{$payment->amount}}</td>
-                                    <td>€{{$payment->Price()}}</td>
-                                    <td>{{$payment->payment_id}}</td>
-                                    <td>{{$payment->payer_id}}</td>
-                                    <td>{{$payment->created_at->diffForHumans()}}</td>
-                                </tr>
-                            @endforeach
                         </tbody>
                         </tbody>
                     </table>
                     </table>
-
-                    <div class="float-right">
-                        {!!  $payments->links() !!}
-                    </div>
-
                 </div>
                 </div>
-            </div>
 
 
+            </div>
         </div>
         </div>
         <!-- END CUSTOM CONTENT -->
         <!-- END CUSTOM CONTENT -->
         </div>
         </div>
     </section>
     </section>
     <!-- END CONTENT -->
     <!-- END CONTENT -->
 
 
+    <script>
+        document.addEventListener("DOMContentLoaded", function () {
+            $('#datatable').DataTable({
+                processing: true,
+                serverSide: true,
+                stateSave: true,
+                ajax: "{{route('admin.payments.datatable')}}",
+                columns: [
+                    {data: 'id' , name : 'payments.id'},
+                    {data: 'user', sortable: false},
+                    {data: 'type'},
+                    {data: 'amount'},
+                    {data: 'price'},
+                    {data: 'payment_id'},
+                    {data: 'payer_id'},
+                    {data: 'created_at'},
+                ],
+                fnDrawCallback: function( oSettings ) {
+                    $('[data-toggle="popover"]').popover();
+                }
+            });
+        });
+    </script>
+
 @endsection
 @endsection

+ 18 - 0
resources/views/mail/payment/confirmed.blade.php

@@ -0,0 +1,18 @@
+@component('mail::message')
+# Thank you for your purchase!
+Your payment has been confirmed; Your credit balance has been updated.
+
+# Details
+___
+### Payment ID: **{{$payment->id}}**
+### Status:     **{{$payment->status}}**
+### Price:      **{{$payment->formatCurrency()}}**
+### Type:       **{{$payment->type}}**
+### Amount:     **{{$payment->amount}}**
+### Balance:    **{{$payment->user->credits}}**
+### User ID:    **{{$payment->user_id}}**
+
+<br>
+Thanks,<br>
+{{ config('app.name') }}
+@endcomponent

+ 4 - 2
resources/views/servers/create.blade.php

@@ -67,8 +67,10 @@
 
 
                                         @foreach($locations as $location)
                                         @foreach($locations as $location)
                                             <optgroup label="{{$location->name}}">
                                             <optgroup label="{{$location->name}}">
-                                                @foreach($location->nodes as $nodes)
-                                                    <option value="{{$nodes->id}}">{{$nodes->name}}</option>
+                                                @foreach($location->nodes as $node)
+                                                    @if(!$node->disabled)
+                                                        <option value="{{$node->id}}">{{$node->name}}</option>
+                                                    @endif
                                                 @endforeach
                                                 @endforeach
                                             </optgroup>
                                             </optgroup>
                                         @endforeach
                                         @endforeach

+ 6 - 6
resources/views/servers/index.blade.php

@@ -44,12 +44,12 @@
                                                 <i class="fas fa-ellipsis-v fa-sm fa-fw text-white-50"></i>
                                                 <i class="fas fa-ellipsis-v fa-sm fa-fw text-white-50"></i>
                                             </a>
                                             </a>
                                             <div class="dropdown-menu dropdown-menu-right shadow animated--fade-in" aria-labelledby="dropdownMenuLink">
                                             <div class="dropdown-menu dropdown-menu-right shadow animated--fade-in" aria-labelledby="dropdownMenuLink">
-                                                <a href="{{env('PTERODACTYL_URL' , 'http://localhost')}}/server/{{$server->identifier}}" class="dropdown-item text-info"><i title="manage" class="fas fa-tasks mr-2"></i><span>Manage</span></a>
-                                                <a href="{{env('PHPMYADMIN_URL' , 'http://localhost')}}" class="dropdown-item text-info"><i title="manage" class="fas fa-database mr-2"></i><span>Database</span></a>
+                                                <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>
+                                                <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>
                                                 <form method="post" onsubmit="return submitResult();" action="{{route('servers.destroy' , $server->id)}}">
                                                 <form method="post" onsubmit="return submitResult();" action="{{route('servers.destroy' , $server->id)}}">
                                                     @csrf
                                                     @csrf
                                                     @method('DELETE')
                                                     @method('DELETE')
-                                                    <button class="dropdown-item text-danger"><i title="delete" class="fas fa-trash mr-2"></i><span>Delete</span></button>
+                                                    <button class="dropdown-item text-danger"><i title="delete" class="fas fa-trash mr-2"></i><span>Delete server</span></button>
                                                 </form>
                                                 </form>
                                                 <div class="dropdown-divider"></div>
                                                 <div class="dropdown-divider"></div>
                                                 <span class="dropdown-item"><i title="Created at" class="fas fa-sync-alt mr-2"></i><span>{{$server->created_at->isoFormat('LL')}}</span></span>
                                                 <span class="dropdown-item"><i title="Created at" class="fas fa-sync-alt mr-2"></i><span>{{$server->created_at->isoFormat('LL')}}</span></span>
@@ -66,7 +66,7 @@
                                         <td>{{$server->product->cpu}} %</td>
                                         <td>{{$server->product->cpu}} %</td>
                                     </tr>
                                     </tr>
                                     <tr>
                                     <tr>
-                                        <td>Ram</td>
+                                        <td>RAM</td>
                                         <td>{{$server->product->memory}} MB</td>
                                         <td>{{$server->product->memory}} MB</td>
                                     </tr>
                                     </tr>
                                     <tr>
                                     <tr>
@@ -86,8 +86,8 @@
 
 
 
 
                             <div class="card-footer d-flex justify-content-between">
                             <div class="card-footer d-flex justify-content-between">
-                                <a href="{{env('PTERODACTYL_URL' , 'http://localhost')}}/server/{{$server->identifier}}" class="btn btn-info mx-3 w-100"><i class="fas fa-tasks mr-2"></i>Manage</a>
-                                <a href="{{env('PHPMYADMIN_URL' , 'http://localhost')}}" class="btn btn-info mx-3 w-100"><i class="fas fa-database mr-2"></i>Database</a>
+                                <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>
+                                <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>
                             </div>
                             </div>
 
 
                         </div>
                         </div>

+ 2 - 2
resources/views/store/index.blade.php

@@ -59,10 +59,10 @@
             @else
             @else
                 <div class="alert alert-danger alert-dismissible">
                 <div class="alert alert-danger alert-dismissible">
                     <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
                     <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
-                    <h4><i class="icon fa fa-ban"></i> @if($products->count() == 0) The store is temporarily
-                        disabled! @else The store is not correctly configured! @endif
+                    <h4><i class="icon fa fa-ban"></i> @if($products->count() == 0) There are no store products! @else The store is not correctly configured! @endif
                     </h4>
                     </h4>
                 </div>
                 </div>
+
             @endif
             @endif
 
 
 
 

+ 7 - 0
routes/web.php

@@ -88,6 +88,7 @@ Route::middleware('auth')->group(function () {
             'store' => 'paypalProduct',
             'store' => 'paypalProduct',
         ]);
         ]);
 
 
+        Route::get('payments/datatable', [PaymentController::class, 'datatable'])->name('payments.datatable');
         Route::get('payments', [PaymentController::class, 'index'])->name('payments.index');
         Route::get('payments', [PaymentController::class, 'index'])->name('payments.index');
 
 
         Route::get('nodes/datatable', [NodeController::class, 'datatable'])->name('nodes.datatable');
         Route::get('nodes/datatable', [NodeController::class, 'datatable'])->name('nodes.datatable');
@@ -101,6 +102,7 @@ Route::middleware('auth')->group(function () {
         Route::get('configurations/datatable', [ConfigurationController::class, 'datatable'])->name('configurations.datatable');
         Route::get('configurations/datatable', [ConfigurationController::class, 'datatable'])->name('configurations.datatable');
         Route::patch('configurations/updatevalue', [ConfigurationController::class, 'updatevalue'])->name('configurations.updatevalue');
         Route::patch('configurations/updatevalue', [ConfigurationController::class, 'updatevalue'])->name('configurations.updatevalue');
         Route::resource('configurations', ConfigurationController::class);
         Route::resource('configurations', ConfigurationController::class);
+        Route::resource('configurations', ConfigurationController::class);
 
 
         Route::patch('settings/update/icons', [SettingsController::class , 'updateIcons'])->name('settings.update.icons');
         Route::patch('settings/update/icons', [SettingsController::class , 'updateIcons'])->name('settings.update.icons');
         Route::resource('settings', SettingsController::class)->only('index');
         Route::resource('settings', SettingsController::class)->only('index');
@@ -112,6 +114,11 @@ Route::middleware('auth')->group(function () {
         Route::resource('api', ApplicationApiController::class)->parameters([
         Route::resource('api', ApplicationApiController::class)->parameters([
             'api' => 'applicationApi',
             'api' => 'applicationApi',
         ]);
         ]);
+
+        #Testing route to preview new ConfirmedPaymentNotification email
+        Route::get('test' , function(Request $request){
+            return (new \App\Notifications\ConfirmPaymentNotification(\App\Models\Payment::factory()->create()))->toMail($request->user());
+        });
     });
     });
 
 
     Route::get('/home', [HomeController::class, 'index'])->name('home');
     Route::get('/home', [HomeController::class, 'index'])->name('home');