From 2f5d61ca589b47c439347852d55bc59a435035d7 Mon Sep 17 00:00:00 2001 From: Lee Watson Date: Tue, 5 Jul 2016 13:34:54 +0100 Subject: [PATCH] Totally refactor caching so models pretty much handle their own caching with no outside interference --- .../Controllers/Account/AccountController.php | 22 +---- .../Controllers/Admin/AdminController.php | 42 ++------- app/Http/Controllers/Api/UploadController.php | 35 ++------ app/Http/Controllers/Auth/AuthController.php | 1 - .../Controllers/Auth/PasswordController.php | 3 +- app/Http/Controllers/Controller.php | 20 ----- app/Http/helpers.php | 10 ++- app/Models/Upload.php | 89 ++++++++++++------- app/Models/User.php | 60 ++++++++++++- resources/views/admin/uploads.blade.php | 6 +- resources/views/admin/users.blade.php | 2 +- resources/views/layouts/account.blade.php | 2 +- resources/views/layouts/master.blade.php | 2 +- 13 files changed, 143 insertions(+), 151 deletions(-) diff --git a/app/Http/Controllers/Account/AccountController.php b/app/Http/Controllers/Account/AccountController.php index 520e680..dc0c963 100644 --- a/app/Http/Controllers/Account/AccountController.php +++ b/app/Http/Controllers/Account/AccountController.php @@ -2,13 +2,12 @@ namespace App\Http\Controllers\Account; +use App\Helpers; use App\Http\Controllers\Controller; use App\Http\Requests; use App\Models\Upload; use App\Models\User; use Auth; -use Cache; -use App\Helpers; use Illuminate\Http\Request; use Illuminate\Mail\Message; use Mail; @@ -16,25 +15,6 @@ class AccountController extends Controller { - public function __construct() - { - parent::__construct(); - $userUploadCount = Cache::rememberForever('uploads_count:' . Auth::id(), function () { - return Auth::user()->uploads->count(); - }); - - $userUploadTotalSize = Cache::rememberForever('uploads_size:' . Auth::id(), function () { - return Auth::user()->uploads->sum('size'); - }); - - $userStorageQuota = Helpers::formatBytes(Cache::get('uploads_size:' . Auth::id())); - if (config('upste.user_storage_quota') > 0 && !Auth::user()->isPrivilegedUser()) { - $userStorageQuota = sprintf("%s / %s", $userStorageQuota, Helpers::formatBytes(config('upste.user_storage_quota'))); - } - - view()->share(compact('userUploadCount', 'userUploadTotalSize', 'userStorageQuota')); - } - public function getIndex() { return view('account.index'); diff --git a/app/Http/Controllers/Admin/AdminController.php b/app/Http/Controllers/Admin/AdminController.php index b47c002..3fb37cf 100644 --- a/app/Http/Controllers/Admin/AdminController.php +++ b/app/Http/Controllers/Admin/AdminController.php @@ -10,17 +10,14 @@ use App\Helpers; use Illuminate\Mail\Message; use Mail; -use Storage; -use View; class AdminController extends Controller { public function __construct() { - parent::__construct(); if (config('upste.require_user_approval')) { $requestCount = User::whereEnabled(false)->count(); - View::share('requestCount', $requestCount); + view()->share('requestCount', $requestCount); } } @@ -42,18 +39,7 @@ public function getRequests() public function getUsers() { - $users = User::whereEnabled(true)->with('uploads')->paginate(Auth::user()->preferences->pagination_items); - - foreach ($users as $user) { - Cache::rememberForever('uploads_count:' . $user->id, function () use ($user) { - return $user->uploads->count(); - }); - - Cache::rememberForever('uploads_size:' . $user->id, function () use ($user) { - return $user->uploads->sum('size'); - }); - } - + $users = User::whereEnabled(true)->paginate(Auth::user()->preferences->pagination_items); return view('admin.users', compact('users')); } @@ -79,17 +65,6 @@ public function postUserDelete(User $user) return redirect()->back(); } - // Reimplemented here to allow CASCADE to do it's job, as opposed to using $upload->forceDelete() - foreach ($user->uploads as $upload) { - if (Storage::exists("uploads/" . $upload->name)) { - Storage::delete("uploads/" . $upload->name); - } - - if (Storage::exists("thumbnails/" . $upload->name)) { - Storage::delete("thumbnails/" . $upload->name); - } - } - $user->forceDelete(); flash()->success(trans('messages.admin.deleted_user', ['name' => $user->name])); @@ -108,20 +83,14 @@ public function getUploads(User $user) { $allUploads = $user->uploads(); $uploads = $allUploads->orderBy('created_at', 'desc')->paginate(Auth::user()->preferences->pagination_items); - $uploadsTotalCount = Cache::rememberForever('uploads_count:' . $user->id, function () use ($allUploads) { - return $allUploads->count(); - }); - - $uploadsTotalSize = Helpers::formatBytes(Cache::rememberForever('uploads_size:' . $user->id, function () use ($allUploads) { - return $allUploads->sum('size'); - })); - return view('admin.uploads', compact('uploads', 'user', 'uploadsTotalCount', 'uploadsTotalSize')); + return view('admin.uploads', compact('uploads', 'user')); } public function postUserAccept(User $user) { - $user->fill(['enabled' => true])->save(); + $user->enabled = true; + $user->save(); $loginRoute = route('login'); Mail::queue(['text' => 'emails.user.account_accepted'], compact('user', 'loginRoute'), function (Message $message) use ($user) { @@ -130,7 +99,6 @@ public function postUserAccept(User $user) }); flash()->success(trans('messages.admin.account_accepted', ['name' => $user->name])); - Helpers::invalidateCache(); return redirect()->back(); } diff --git a/app/Http/Controllers/Api/UploadController.php b/app/Http/Controllers/Api/UploadController.php index 3390ca7..169da5d 100644 --- a/app/Http/Controllers/Api/UploadController.php +++ b/app/Http/Controllers/Api/UploadController.php @@ -32,19 +32,14 @@ public function post(Request $request) } if ($uploadedFile->getSize() >= config('upste.upload_limit')) { - return response()->json([trans( - 'messages.upload_too_large', - ['limit' => Helpers::formatBytes(config('upste.upload_limit'))] - )], StatusCode::REQUEST_ENTITY_TOO_LARGE); + $responseMsg = trans('messages.upload_too_large', ['limit' => Helpers::formatBytes(config('upste.upload_limit'))]); + return response()->json($responseMsg, StatusCode::REQUEST_ENTITY_TOO_LARGE); } // If this upload would hit the quota defined in .env, reject it. - if (config('upste.user_storage_quota') > 0 && !Auth::user()->isPrivilegedUser() && - (Cache::get('uploads_size:' . Auth::id()) + $uploadedFile->getSize()) >= config('upste.user_storage_quota')) { - return response()->json([trans( - 'messages.reached_upload_limit', - ['limit' => Helpers::formatBytes(config('upste.user_storage_quota'))] - )], StatusCode::FORBIDDEN); + if (config('upste.user_storage_quota') > 0 && !$request->user()->isPrivilegedUser() && ($request->user()->getUploadsSize() + $uploadedFile->getSize()) >= config('upste.user_storage_quota')) { + $responseMsg = trans('messages.reached_upload_limit', ['limit' => Helpers::formatBytes(config('upste.user_storage_quota'))]); + return response()->json($responseMsg, StatusCode::FORBIDDEN); } $ext = strtolower($uploadedFile->getClientOriginalExtension()); @@ -56,10 +51,11 @@ public function post(Request $request) $originalName = $uploadedFile->getClientOriginalName(); // Check to see if we already have this file for this user. - $existing = Upload::whereOriginalHash($originalHash)->whereUserId(Auth::id())->first(); + $existing = Upload::whereOriginalHash($originalHash)->whereUserId($request->user()->id)->first(); if ($existing) { $result = [ - 'url' => route('files.get', $existing) + 'url' => route('files.get', $existing), + 'delete_url' => route('account.uploads.delete', $existing), ]; $existing->original_name = $originalName; @@ -74,7 +70,7 @@ public function post(Request $request) } while (Upload::whereName($newName)->first() || $newName === 'index.php'); $upload = new Upload([ - 'user_id' => Auth::id(), + 'user_id' => $request->user()->id, 'name' => $newName, 'original_name' => $originalName, 'original_hash' => $originalHash @@ -129,17 +125,4 @@ public function post(Request $request) return response()->json($result, StatusCode::CREATED, [], JSON_UNESCAPED_SLASHES); } - - public function get(Request $request) - { - $user = Auth::user(); - - if (Cache::get('uploads_count:' . $user->id) !== 0) { - $uploads = $user->uploads->slice(0, $request->input('limit', Helpers::PAGINATION_DEFAULT_ITEMS)); - - return response()->json($uploads, StatusCode::CREATED, [], JSON_UNESCAPED_SLASHES); - } - - return response()->json([trans('messages.no_uploads_found')], StatusCode::NOT_FOUND, [], JSON_UNESCAPED_SLASHES); - } } diff --git a/app/Http/Controllers/Auth/AuthController.php b/app/Http/Controllers/Auth/AuthController.php index e199236..33cf8e0 100644 --- a/app/Http/Controllers/Auth/AuthController.php +++ b/app/Http/Controllers/Auth/AuthController.php @@ -38,7 +38,6 @@ class AuthController extends Controller */ public function __construct() { - parent::__construct(); $this->redirectPath = route('index'); } diff --git a/app/Http/Controllers/Auth/PasswordController.php b/app/Http/Controllers/Auth/PasswordController.php index 18fa532..6e578c8 100644 --- a/app/Http/Controllers/Auth/PasswordController.php +++ b/app/Http/Controllers/Auth/PasswordController.php @@ -30,7 +30,6 @@ class PasswordController extends Controller */ public function __construct() { - parent::__construct(); $this->redirectTo = route('account'); } @@ -55,7 +54,7 @@ public function sendResetLinkEmail(Request $request) $broker = $this->getBroker(); $passwordRoute = route('account.password.email'); - view()->composer('emails.user.password_reset', function($view) use ($passwordRoute) { + view()->composer('emails.user.password_reset', function ($view) use ($passwordRoute) { $view->with(compact('passwordRoute')); }); diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index fd25c06..af5cfb1 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -2,9 +2,6 @@ namespace App\Http\Controllers; -use Cache; -use DB; -use Helpers; use Illuminate\Foundation\Bus\DispatchesJobs; use Illuminate\Foundation\Validation\ValidatesRequests; use Illuminate\Routing\Controller as BaseController; @@ -12,21 +9,4 @@ class Controller extends BaseController { use DispatchesJobs, ValidatesRequests; - - public function __construct() - { - $userCount = Cache::rememberForever('users', function () { - return DB::table('users')->where('enabled', true)->count(); - }); - - $uploadCount = Cache::rememberForever('uploads', function () { - return DB::table('uploads')->count(); - }); - - $uploadTotalSize = Cache::rememberForever('uploads_total_size', function () { - return DB::table('uploads')->sum('size'); - }); - - view()->share(compact('userCount', 'uploadCount', 'uploadTotalSize')); - } } diff --git a/app/Http/helpers.php b/app/Http/helpers.php index 156db42..aeb8038 100644 --- a/app/Http/helpers.php +++ b/app/Http/helpers.php @@ -20,8 +20,7 @@ class Helpers public static function invalidateCache() { if (Auth::check()) { - Cache::forget('uploads_count:' . Auth::id()); - Cache::forget('uploads_size:' . Auth::id()); + Auth::user()->invalidateCache(); } Cache::forget('users'); @@ -127,4 +126,9 @@ public static function shouldThumbnail(UploadedFile $file) return false; } -} + + public static function properize($string) + { + return $string . ends_with($string, 's') ? '\'' : 's'; + } +} \ No newline at end of file diff --git a/app/Models/Upload.php b/app/Models/Upload.php index 11a6d04..f606d89 100644 --- a/app/Models/Upload.php +++ b/app/Models/Upload.php @@ -2,7 +2,8 @@ namespace App\Models; -use App\Helpers; +use Cache; +use DB; use Illuminate\Database\Eloquent\Model; use Storage; @@ -42,7 +43,6 @@ class Upload extends Model * @var array */ protected $fillable = ['name', 'hash', 'size', 'user_id', 'original_name', 'original_hash', 'downloads', 'views']; - /** * The attributes excluded from the model's JSON form. * @@ -50,12 +50,34 @@ class Upload extends Model */ protected $hidden = ['user_id', 'id', 'updated_at']; + public static function size() + { + return Cache::rememberForever('uploads_total_size', function () { + return DB::table('uploads')->sum('size'); + }); + } + + public static function count() + { + return Cache::rememberForever('uploads', function () { + return DB::table('uploads')->count(); + }); + } + public function save(array $options = []) { - Helpers::invalidateCache(); + static::invalidateCache(); + $this->user->invalidateCache(); + return parent::save($options); } + public static function invalidateCache() + { + Cache::forget('uploads'); + Cache::forget('uploads_total_size'); + } + /** * Get the user that owns the upload. */ @@ -64,15 +86,13 @@ public function user() return $this->belongsTo('App\Models\User'); } - public function createDirs() + public function forceDelete() { - if (!Storage::exists($this->getDir())) { - Storage::makeDirectory($this->getDir()); - } + $this->deleteDirs(); + $this->invalidateCache(); + $this->user->invalidateCache(); - if (!Storage::exists($this->getThumbnailDir())) { - Storage::makeDirectory($this->getThumbnailDir()); - } + return parent::forceDelete(); } public function deleteDirs() @@ -96,6 +116,11 @@ public function deleteDirs() } } + public function getPath($fullPath = false) + { + return $this->getDir($fullPath) . $this->name; + } + public function getDir($fullDir = false) { if ($fullDir) { @@ -105,6 +130,11 @@ public function getDir($fullDir = false) return sprintf('uploads/%s/%s/', md5($this->user_id), md5(mb_substr($this->name, 0, 1, 'utf-8'))); } + public function getThumbnailPath($fullPath = false) + { + return $this->getThumbnailDir($fullPath) . $this->name; + } + public function getThumbnailDir($fullDir = false) { if ($fullDir) { @@ -114,24 +144,6 @@ public function getThumbnailDir($fullDir = false) return sprintf('thumbnails/%s/%s/', md5($this->user_id), md5(mb_substr($this->name, 0, 1, 'utf-8'))); } - public function forceDelete() - { - $this->deleteDirs(); - Helpers::invalidateCache(); - - return parent::forceDelete(); - } - - public function getPath($fullPath = false) - { - return $this->getDir($fullPath) . $this->name; - } - - public function getThumbnailPath($fullPath = false) - { - return $this->getThumbnailDir($fullPath) . $this->name; - } - /** * Migrates files from the old uploads/$filename structure to a more efficient one. * Should only be called once from the command line. @@ -140,6 +152,7 @@ public function migrate() { if (php_sapi_name() !== 'cli') { trigger_error('CLI-only (Upload#migrate()) function called outside of CLI SAPI.', E_USER_ERROR); + return; } @@ -154,6 +167,22 @@ public function migrate() } } + public function createDirs() + { + if (!Storage::exists($this->getDir())) { + Storage::makeDirectory($this->getDir()); + } + + if (!Storage::exists($this->getThumbnailDir())) { + Storage::makeDirectory($this->getThumbnailDir()); + } + } + + public function hasPreview() + { + return $this->getThumbnailUrl() !== elixir('assets/img/thumbnail.png'); + } + public function getThumbnailUrl() { if (Storage::exists($this->getThumbnailDir() . $this->name)) { @@ -163,10 +192,6 @@ public function getThumbnailUrl() return elixir('assets/img/thumbnail.png'); } - public function hasPreview() { - return $this->getThumbnailUrl() !== elixir('assets/img/thumbnail.png'); - } - public function getRouteKeyName() { return 'name'; diff --git a/app/Models/User.php b/app/Models/User.php index ec9ab3f..306ade6 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -3,6 +3,8 @@ namespace App\Models; use App\Helpers; +use Cache; +use DB; use Illuminate\Auth\Authenticatable; use Illuminate\Auth\Passwords\CanResetPassword; use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; @@ -61,21 +63,32 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon */ protected $hidden = ['password', 'remember_token', 'apikey', 'enabled', 'banned', 'admin']; + public static function count() + { + return Cache::rememberForever('users', function () { + return DB::table('users')->where('enabled', true)->count(); + }); + } + /** * Get this user's uploads. */ public function uploads() { - return $this->hasMany('App\Models\Upload'); + return $this->hasMany(Upload::class); } public function preferences() { - return $this->hasOne('App\Models\UserPreferences'); + return $this->hasOne(UserPreferences::class); } public function forceDelete() { + foreach ($this->uploads as $upload) { + $upload->forceDelete(); + } + if (Storage::exists('uploads/' . md5($this->id))) { Storage::deleteDirectory('uploads/' . md5($this->id)); } @@ -84,11 +97,52 @@ public function forceDelete() Storage::deleteDirectory('thumbnails/' . md5($this->id)); } - Helpers::invalidateCache(); + $this->invalidateCache(); + $this->invalidateGlobalCache(); return parent::forceDelete(); } + public function invalidateCache() + { + Cache::forget('uploads_size:' . $this->id); + Cache::forget('uploads_count:' . $this->id); + } + + private function invalidateGlobalCache() { + Cache::forget('users'); + } + + public function setEnabledAttribute($value) + { + $this->attributes['enabled'] = $value; + $this->invalidateGlobalCache(); + } + + public function getUploadsCount() + { + return Cache::rememberForever('uploads_count:' . $this->id, function () { + return $this->uploads->count(); + }); + } + + public function getStorageQuota() + { + $userStorageQuota = Helpers::formatBytes($this->getUploadsSize()); + if (config('upste.user_storage_quota') > 0 && !$this->isPrivilegedUser()) { + $userStorageQuota = sprintf("%s / %s", $userStorageQuota, Helpers::formatBytes(config('upste.user_storage_quota'))); + } + + return $userStorageQuota; + } + + public function getUploadsSize() + { + return Cache::rememberForever('uploads_size:' . $this->id, function () { + return $this->uploads->sum('size'); + }); + } + public function isPrivilegedUser() { return $this->admin || $this->isSuperUser(); diff --git a/resources/views/admin/uploads.blade.php b/resources/views/admin/uploads.blade.php index b1ba395..4549e4e 100644 --- a/resources/views/admin/uploads.blade.php +++ b/resources/views/admin/uploads.blade.php @@ -9,8 +9,8 @@ @section('content') @if($uploads->count())
-

{{ $user->name }}'{{ ends_with($user->name, 's') ?: 's' }} Uploads

-

Total: {{ $uploadsTotalCount }} ({{ $uploadsTotalSize }})

+

{{ App\Helpers::properize($user->name) }} Uploads

+

Total: {{ $user->getUploadsCount() }} ({{ App\Helpers::formatBytes($user->getUploadsSize()) }})


@foreach ($uploads->chunk(2) as $chunk) @@ -63,4 +63,4 @@ @section('javascript') -@endsection \ No newline at end of file +@endsection diff --git a/resources/views/admin/users.blade.php b/resources/views/admin/users.blade.php index ed5647c..595f718 100644 --- a/resources/views/admin/users.blade.php +++ b/resources/views/admin/users.blade.php @@ -30,7 +30,7 @@ {{ $user->email }} {{ $user->created_at->copy()->tz(Auth::user()->preferences->timezone) }} - {{ Cache::get('uploads_count:' . $user->id) }} ({{ App\Helpers::formatBytes(Cache::get('uploads_size:' . $user->id)) }}) + {{ $user->getUploadsCount() }} ({{ App\Helpers::formatBytes($user->getUploadsSize()) }})