From 67bcfc65a58d19cd1d3fbca70b01f65549e6c0cf Mon Sep 17 00:00:00 2001 From: Pig Fang Date: Tue, 30 Jul 2019 14:29:02 +0800 Subject: [PATCH] Refactor user model --- app/Http/Controllers/AdminController.php | 3 +- app/Http/Controllers/ClosetController.php | 6 +- app/Http/Controllers/PlayerController.php | 7 +- app/Http/Controllers/SkinlibController.php | 9 +- app/Http/Controllers/UserController.php | 41 +++++-- app/Listeners/TextureRemoved.php | 6 +- app/Models/User.php | 132 +-------------------- tests/ClosetControllerTest.php | 6 +- tests/ModelsTest/UserTest.php | 9 -- 9 files changed, 59 insertions(+), 160 deletions(-) diff --git a/app/Http/Controllers/AdminController.php b/app/Http/Controllers/AdminController.php index f03592e1..630cca05 100644 --- a/app/Http/Controllers/AdminController.php +++ b/app/Http/Controllers/AdminController.php @@ -486,7 +486,8 @@ class AdminController extends Controller 'score' => 'required|integer', ]); - $user->setScore($request->input('score')); + $user->score = $request->input('score'); + $user->save(); return json(trans('admin.users.operations.score.success'), 0); } elseif ($action == 'permission') { diff --git a/app/Http/Controllers/ClosetController.php b/app/Http/Controllers/ClosetController.php index d4b01fab..ed0280d3 100644 --- a/app/Http/Controllers/ClosetController.php +++ b/app/Http/Controllers/ClosetController.php @@ -93,7 +93,8 @@ class ClosetController extends Controller } $user->closet()->attach($tid, ['item_name' => $request->name]); - $user->setScore(option('score_per_closet_item'), 'minus'); + $user->score -= option('score_per_closet_item'); + $user->save(); $texture->likes++; $texture->save(); @@ -132,7 +133,8 @@ class ClosetController extends Controller $user->closet()->detach($tid); if (option('return_score')) { - $user->setScore(option('score_per_closet_item'), 'plus'); + $user->score += option('score_per_closet_item'); + $user->save(); } $texture = Texture::find($tid); diff --git a/app/Http/Controllers/PlayerController.php b/app/Http/Controllers/PlayerController.php index 2b0e8d74..5103562e 100644 --- a/app/Http/Controllers/PlayerController.php +++ b/app/Http/Controllers/PlayerController.php @@ -86,7 +86,8 @@ class PlayerController extends Controller event(new PlayerWasAdded($player)); - $user->setScore(option('score_per_player'), 'minus'); + $user->score -= option('score_per_player'); + $user->save(); return json(trans('user.player.add.success', ['name' => $name]), 0, $player->toArray()); } @@ -105,7 +106,9 @@ class PlayerController extends Controller $player->delete(); if (option('return_score')) { - Auth::user()->setScore(Option::get('score_per_player'), 'plus'); + $user = auth()->user(); + $user->score += option('score_per_player'); + $user->save(); } event(new PlayerWasDeleted($playerName)); diff --git a/app/Http/Controllers/SkinlibController.php b/app/Http/Controllers/SkinlibController.php index d0b24117..0c624b43 100644 --- a/app/Http/Controllers/SkinlibController.php +++ b/app/Http/Controllers/SkinlibController.php @@ -230,8 +230,9 @@ class SkinlibController extends Controller $t->likes++; $t->save(); - $user->setScore($cost, 'minus'); + $user->score -= $cost; $user->closet()->attach($t->tid, ['item_name' => $t->name]); + $user->save(); return json(trans('skinlib.upload.success', ['name' => $request->input('name')]), 0, [ 'tid' => $t->tid, @@ -293,12 +294,14 @@ class SkinlibController extends Controller $t->likers()->get()->each(function ($user) use ($t) { $user->closet()->detach($t->tid); if (option('return_score')) { - $user->setScore(option('score_per_closet_item'), 'plus'); + $user->score += option('score_per_closet_item'); + $user->save(); } $t->likes--; }); - @$uploader->setScore($score_diff, 'plus'); + $uploader->score += $score_diff; + $uploader->save(); $t->public = ! $t->public; $t->save(); diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index c67461aa..00812de2 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -7,6 +7,7 @@ use URL; use Mail; use View; use Session; +use Carbon\Carbon; use App\Models\User; use App\Models\Texture; use Illuminate\Http\Request; @@ -39,7 +40,7 @@ class UserController extends Controller return view('user.index')->with([ 'statistics' => [ 'players' => $this->calculatePercentageUsed($user->players->count(), option('score_per_player')), - 'storage' => $this->calculatePercentageUsed($user->getStorageUsed(), option('score_per_storage')), + 'storage' => $this->calculatePercentageUsed($this->getStorageUsed($user), option('score_per_storage')), ], 'announcement' => app('parsedown')->text(option_localized('announcement')), 'extra' => ['unverified' => option('require_verification') && ! $user->verified], @@ -57,7 +58,7 @@ class UserController extends Controller ], 'stats' => [ 'players' => $this->calculatePercentageUsed($user->players->count(), option('score_per_player')), - 'storage' => $this->calculatePercentageUsed($user->getStorageUsed(), option('score_per_storage')), + 'storage' => $this->calculatePercentageUsed($this->getStorageUsed($user), option('score_per_storage')), ], 'signAfterZero' => option('sign_after_zero'), 'signGapTime' => option('sign_gap_time'), @@ -87,6 +88,11 @@ class UserController extends Controller return $result; } + protected function getStorageUsed(User $user) + { + return Texture::where('uploader', $user->uid)->select('size')->sum('size') ?: 0; + } + /** * Handle user signing. * @@ -95,17 +101,22 @@ class UserController extends Controller public function sign() { $user = Auth::user(); - if ($user->canSign()) { - $acquiredScore = $user->sign(); + if ($this->getSignRemainingTime($user) <= 0) { + $scoreLimits = explode(',', option('sign_score')); + $acquiredScore = rand($scoreLimits[0], $scoreLimits[1]); + + $user->score += $acquiredScore; + $user->last_sign_at = Carbon::now()->toDateTimeString(); + $user->save(); $gap = option('sign_gap_time'); return json(trans('user.sign-success', ['score' => $acquiredScore]), 0, [ 'score' => $user->score, - 'storage' => $this->calculatePercentageUsed($user->getStorageUsed(), option('score_per_storage')), + 'storage' => $this->calculatePercentageUsed($this->getStorageUsed($user), option('score_per_storage')), 'remaining_time' => $gap > 1 ? round($gap) : $gap, ]); } else { - $remaining_time = $this->getUserSignRemainingTimeWithPrecision(); + $remaining_time = $this->getUserSignRemainingTimeWithPrecision($user); return json(trans('user.cant-sign-until', [ 'time' => $remaining_time >= 1 @@ -116,13 +127,27 @@ class UserController extends Controller } } - public function getUserSignRemainingTimeWithPrecision($user = null) + protected function getUserSignRemainingTimeWithPrecision(User $user) { - $hours = ($user ?? Auth::user())->getSignRemainingTime() / 3600; + $hours = $this->getSignRemainingTime($user) / 3600; return $hours > 1 ? round($hours) : $hours; } + protected function getSignRemainingTime(User $user) + { + $lastSignTime = Carbon::parse($user->last_sign_at); + + if (option('sign_after_zero')) { + return Carbon::now()->diffInSeconds( + $lastSignTime <= Carbon::today() ? $lastSignTime : Carbon::tomorrow(), + false + ); + } + + return Carbon::now()->diffInSeconds($lastSignTime->addHours(option('sign_gap_time')), false); + } + public function sendVerificationEmail() { if (! option('require_verification')) { diff --git a/app/Listeners/TextureRemoved.php b/app/Listeners/TextureRemoved.php index a5a8cd2d..97e9611b 100644 --- a/app/Listeners/TextureRemoved.php +++ b/app/Listeners/TextureRemoved.php @@ -11,7 +11,8 @@ class TextureRemoved $texture->likers()->get()->each(function ($user) use ($texture) { $user->closet()->detach($texture->tid); if (option('return_score')) { - $user->setScore(option('score_per_closet_item'), 'plus'); + $user->score += option('score_per_closet_item'); + $user->save(); } }); @@ -29,7 +30,8 @@ class TextureRemoved $ret -= option('score_award_per_texture', 0); } - $uploader->setScore($ret, 'plus'); + $uploader->score += $ret; + $uploader->save(); } } } diff --git a/app/Models/User.php b/app/Models/User.php index 5fc6670c..f657f019 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -2,8 +2,6 @@ namespace App\Models; -use DB; -use Carbon\Carbon; use Illuminate\Support\Arr; use Laravel\Passport\HasApiTokens; use App\Events\EncryptUserPassword; @@ -16,26 +14,15 @@ class User extends Authenticatable implements JWTSubject use Notifiable; use HasApiTokens; - /** - * Permissions. - */ const BANNED = -1; const NORMAL = 0; const ADMIN = 1; const SUPER_ADMIN = 2; - /** - * Properties for Eloquent Model. - */ public $primaryKey = 'uid'; public $timestamps = false; protected $fillable = ['email', 'nickname', 'permission']; - /** - * The attributes that should be cast to native types. - * - * @var array - */ protected $casts = [ 'uid' => 'integer', 'score' => 'integer', @@ -46,18 +33,6 @@ class User extends Authenticatable implements JWTSubject protected $hidden = ['password', 'remember_token']; - /** - * Storage size used by user in KiB. - * - * @var int - */ - protected $storageUsed; - - /** - * Check if user is admin. - * - * @return bool - */ public function isAdmin() { return $this->permission >= static::ADMIN; @@ -68,9 +43,6 @@ class User extends Authenticatable implements JWTSubject return $this->belongsToMany(Texture::class, 'user_closet')->withPivot('item_name'); } - /** - * Retrieve the player name of first player. - */ public function getPlayerNameAttribute() { $player = $this->players->first(); @@ -78,9 +50,6 @@ class User extends Authenticatable implements JWTSubject return $player ? $player->name : ''; } - /** - * Update the player name of first player. - */ public function setPlayerNameAttribute($value) { $player = $this->players->first(); @@ -110,7 +79,6 @@ class User extends Authenticatable implements JWTSubject public static function getEncryptedPwdFromEvent($raw, User $user) { $responses = event(new EncryptUserPassword($raw, $user)); - return Arr::get($responses, 0); } @@ -123,108 +91,10 @@ class User extends Authenticatable implements JWTSubject public function changePassword($password) { $responses = event(new EncryptUserPassword($password, $this)); - - if (isset($responses[0])) { - $this->password = $responses[0]; // @codeCoverageIgnore - } else { - $this->password = app('cipher')->hash($password, config('secure.salt')); - } - + $this->password = Arr::get($responses, 0, app('cipher')->hash($password, config('secure.salt'))); return $this->save(); } - /** - * Set user score. - * - * @param int $score - * @param string $mode What operation should be done, set, plus or minus. - * @return bool - */ - public function setScore($score, $mode = 'set') - { - switch ($mode) { - case 'set': - $this->score = $score; - break; - - case 'plus': - $this->score += $score; - break; - - case 'minus': - $this->score -= $score; - break; - } - - return $this->save(); - } - - /** - * Get the size of storage units used by the user. - * - * @return int Size in KiloBytes. - */ - public function getStorageUsed() - { - if (is_null($this->storageUsed)) { - $this->storageUsed = 0; - - $result = DB::table('textures') - ->select(DB::raw('SUM(size) AS total_size')) - ->where('uploader', $this->uid) - ->first()->total_size; - - $this->storageUsed = $result ?: 0; - } - - return (int) $this->storageUsed; - } - - /** - * Sign for the user, return false if unavailable. - * - * @return int|bool - */ - public function sign() - { - if ($this->canSign()) { - $scoreLimits = explode(',', option('sign_score')); - $acquiredScore = rand($scoreLimits[0], $scoreLimits[1]); - - $this->setScore($acquiredScore, 'plus'); - $this->last_sign_at = get_datetime_string(); - $this->save(); - - return $acquiredScore; - } else { - return false; - } - } - - /** - * Get remaining time before next signing is available. - * - * @return int Time in seconds. - */ - public function getSignRemainingTime() - { - $lastSignTime = Carbon::parse($this->last_sign_at); - - if (option('sign_after_zero')) { - return Carbon::now()->diffInSeconds( - $lastSignTime <= Carbon::today() ? $lastSignTime : Carbon::tomorrow(), - false - ); - } - - return Carbon::now()->diffInSeconds($lastSignTime->addHours(option('sign_gap_time')), false); - } - - public function canSign() - { - return $this->getSignRemainingTime() <= 0; - } - public function delete() { Player::where('uid', $this->uid)->delete(); diff --git a/tests/ClosetControllerTest.php b/tests/ClosetControllerTest.php index 70f14956..7866a0be 100644 --- a/tests/ClosetControllerTest.php +++ b/tests/ClosetControllerTest.php @@ -110,7 +110,8 @@ class ClosetControllerTest extends TestCase )->assertJsonValidationErrors('name'); // The user doesn't have enough score to add a texture - $this->user->setScore(0); + $this->user->score = 0; + $this->user->save(); $this->postJson( '/user/closet/add', ['tid' => $texture->tid, 'name' => $name] @@ -120,7 +121,8 @@ class ClosetControllerTest extends TestCase ]); // Add a not-existed texture - $this->user->setScore(100); + $this->user->score = 100; + $this->user->save(); $this->postJson( '/user/closet/add', ['tid' => -1, 'name' => 'my'] diff --git a/tests/ModelsTest/UserTest.php b/tests/ModelsTest/UserTest.php index 2a8a044e..613f4499 100644 --- a/tests/ModelsTest/UserTest.php +++ b/tests/ModelsTest/UserTest.php @@ -10,15 +10,6 @@ class UserTest extends TestCase { use DatabaseTransactions; - public function testSign() - { - $user = factory(User::class)->make([ - 'last_sign_at' => get_datetime_string(time()), - ]); - $user->sign(); - $this->assertFalse($user->sign()); - } - public function testGetPlayerNameAttribute() { $user = factory(User::class)->create();