diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php
index e49923ba..496c1bf3 100644
--- a/app/Http/Controllers/Admin/UserController.php
+++ b/app/Http/Controllers/Admin/UserController.php
@@ -78,7 +78,7 @@ class UserController extends Controller
"name" => "required|string|min:4|max:30",
"pterodactyl_id" => "required|numeric|unique:users,pterodactyl_id,{$user->id}",
"email" => "required|string|email",
- "credits" => "required|numeric|min:0|max:999999",
+ "credits" => "required|numeric|min:0|max:99999999",
"server_limit" => "required|numeric|min:0|max:1000000",
"role" => Rule::in(['admin', 'mod', 'client', 'member']),
]);
diff --git a/app/Http/Controllers/Admin/VoucherController.php b/app/Http/Controllers/Admin/VoucherController.php
index 9d439f4a..ec742092 100644
--- a/app/Http/Controllers/Admin/VoucherController.php
+++ b/app/Http/Controllers/Admin/VoucherController.php
@@ -7,9 +7,13 @@ use App\Models\Voucher;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\View\Factory;
use Illuminate\Contracts\View\View;
+use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
+use Illuminate\Support\Facades\Validator;
+use Illuminate\Validation\ValidationData;
+use Illuminate\Validation\ValidationException;
class VoucherController extends Controller
{
@@ -42,11 +46,11 @@ class VoucherController extends Controller
public function store(Request $request)
{
$request->validate([
- 'memo' => 'sometimes|string|max:191',
- 'code' => 'required|string|alpha_dash|max:36',
- 'uses' => 'required|numeric|max:2147483647',
- 'credits' => 'required|numeric|between:0,99999999',
- 'expires_at' => 'required|date|after:today',
+ 'memo' => 'sometimes|string|max:191',
+ 'code' => 'required|string|alpha_dash|max:36',
+ 'uses' => 'required|numeric|max:2147483647',
+ 'credits' => 'required|numeric|between:0,99999999',
+ 'expires_at' => 'nullable|date|after:1 hour',
]);
Voucher::create($request->except('_token'));
@@ -100,9 +104,49 @@ class VoucherController extends Controller
return redirect()->back()->with('success', 'voucher has been removed!');
}
+ /**
+ * @param Request $request
+ * @return JsonResponse
+ * @throws ValidationException
+ */
+ public function redeem(Request $request)
+ {
+ #general validations
+ $request->validate([
+ 'code' => 'required|exists:vouchers,code'
+ ]);
+
+ #get voucher by code
+ $voucher = Voucher::where('code' , '=' , $request->input('code'))->firstOrFail();
+
+ #extra validations
+ if ($voucher->getStatus() == 'USES_LIMIT_REACHED') throw ValidationException::withMessages([
+ 'code' => 'This voucher has reached the maximum amount of uses'
+ ]);
+
+ if ($voucher->getStatus() == 'EXPIRED') throw ValidationException::withMessages([
+ 'code' => 'This voucher has expired'
+ ]);
+
+ 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 a voucher with this many credits"
+ ]);
+
+ #redeem voucher
+ $voucher->redeem($request->user());
+
+ return response()->json([
+ 'success' => "{$voucher->credits} credits have been added to your balance!"
+ ]);
+ }
+
public function dataTable()
{
- $query = Voucher::with(['users']);
+ $query = Voucher::query();
return datatables($query)
->addColumn('actions', function (Voucher $voucher) {
@@ -120,7 +164,7 @@ class VoucherController extends Controller
->addColumn('status', function (Voucher $voucher) {
$color = 'success';
if ($voucher->getStatus() != 'VALID') $color = 'danger';
- return ''. $voucher->getStatus() .'';
+ return '' . $voucher->getStatus() . '';
})
->editColumn('uses', function (Voucher $voucher) {
$userCount = $voucher->users()->count();
@@ -130,12 +174,13 @@ class VoucherController extends Controller
return number_format($voucher->credits, 2, '.', '');
})
->editColumn('expires_at', function (Voucher $voucher) {
+ if (!$voucher->expires_at) return "";
return $voucher->expires_at ? $voucher->expires_at->diffForHumans() : '';
})
- ->editColumn('code' , function (Voucher $voucher) {
+ ->editColumn('code', function (Voucher $voucher) {
return "{$voucher->code}
";
})
- ->rawColumns(['actions' , 'code' , 'status'])
+ ->rawColumns(['actions', 'code', 'status'])
->make();
}
diff --git a/app/Models/User.php b/app/Models/User.php
index 61605aea..a6547099 100644
--- a/app/Models/User.php
+++ b/app/Models/User.php
@@ -7,17 +7,30 @@ use App\Notifications\Auth\QueuedVerifyEmail;
use App\Notifications\WelcomeMessage;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Relations\BelongsToMany;
+use Illuminate\Database\Eloquent\Relations\HasMany;
+use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Spatie\Activitylog\Traits\CausesActivity;
use Spatie\Activitylog\Traits\LogsActivity;
+/**
+ * Class User
+ * @package App\Models
+ */
class User extends Authenticatable implements MustVerifyEmail
{
use HasFactory, Notifiable, LogsActivity, CausesActivity;
+ /**
+ * @var string[]
+ */
protected static $logAttributes = ['name', 'email'];
+ /**
+ * @var string[]
+ */
protected static $ignoreChangedAttributes = [
'remember_token',
'credits',
@@ -68,6 +81,9 @@ class User extends Authenticatable implements MustVerifyEmail
'last_seen' => 'datetime',
];
+ /**
+ *
+ */
public static function boot()
{
parent::boot();
@@ -93,20 +109,32 @@ class User extends Authenticatable implements MustVerifyEmail
});
}
+ /**
+ *
+ */
public function sendEmailVerificationNotification()
{
$this->notify(new QueuedVerifyEmail);
}
+ /**
+ * @return string
+ */
public function credits()
{
return number_format($this->credits, 2, '.', '');
}
+ /**
+ * @return string
+ */
public function getAvatar(){
return "https://www.gravatar.com/avatar/" . md5(strtolower(trim($this->email)));
}
+ /**
+ * @return string
+ */
public function creditUsage()
{
$usage = 0;
@@ -118,6 +146,9 @@ class User extends Authenticatable implements MustVerifyEmail
return number_format($usage, 2, '.', '');
}
+ /**
+ * @return array|string|string[]
+ */
public function getVerifiedStatus(){
$status = '';
if ($this->hasVerifiedEmail()) $status .= 'email ';
@@ -126,15 +157,31 @@ class User extends Authenticatable implements MustVerifyEmail
return $status;
}
+ /**
+ * @return BelongsToMany
+ */
+ public function vouchers(){
+ return $this->belongsToMany(Voucher::class);
+ }
+
+ /**
+ * @return HasOne
+ */
public function discordUser(){
return $this->hasOne(DiscordUser::class);
}
+ /**
+ * @return HasMany
+ */
public function servers()
{
return $this->hasMany(Server::class);
}
+ /**
+ * @return HasMany
+ */
public function payments()
{
return $this->hasMany(Payment::class);
diff --git a/app/Models/Voucher.php b/app/Models/Voucher.php
index 9071a9a2..0315c8d9 100644
--- a/app/Models/Voucher.php
+++ b/app/Models/Voucher.php
@@ -41,14 +41,35 @@ class Voucher extends Model
});
}
+ /**
+ * @return string
+ */
public function getStatus(){
if ($this->users()->count() >= $this->uses) return 'USES_LIMIT_REACHED';
- if ($this->expires_at->isPast()) return 'EXPIRED';
+ if (!is_null($this->expires_at)){
+ if ($this->expires_at->isPast()) return 'EXPIRED';
+ }
+
return 'VALID';
}
/**
- * @return BelongsToMany
+ * @param User $user
+ * @return float
+ */
+ public function redeem(User $user){
+ try {
+ $user->increment('credits' , $this->credits);
+ $this->users()->attach($user);
+ }catch (\Exception $exception) {
+ throw $exception;
+ }
+
+ return $this->credits;
+ }
+
+ /**
+ * @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function users()
{
diff --git a/database/migrations/2021_07_10_062140_update_credits_to_users_table.php b/database/migrations/2021_07_10_062140_update_credits_to_users_table.php
new file mode 100644
index 00000000..bce7b344
--- /dev/null
+++ b/database/migrations/2021_07_10_062140_update_credits_to_users_table.php
@@ -0,0 +1,32 @@
+unsignedFloat('credits', 10)->change();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::table('users', function (Blueprint $table) {
+ $table->unsignedFloat('credits')->change();
+ });
+ }
+}
diff --git a/resources/views/admin/users/edit.blade.php b/resources/views/admin/users/edit.blade.php
index 0148cb9a..0358f189 100644
--- a/resources/views/admin/users/edit.blade.php
+++ b/resources/views/admin/users/edit.blade.php
@@ -72,7 +72,7 @@