From 9275487cfaa3e1370f60fcd13b8ca3be5955a102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=8Carodej?= Date: Fri, 10 Dec 2021 16:37:00 +0100 Subject: [PATCH] record daily usage --- database/factories/TrafficFactory.php | 34 ++++++++++ src/App/Console/Kernel.php | 13 ++-- src/Domain/Files/Actions/UploadFileAction.php | 2 +- src/Domain/Files/Models/File.php | 4 +- src/Domain/Traffic/Models/Traffic.php | 6 ++ .../Scheduler/Actions/ReportUsageAction.php | 49 ++++++++++++++ tests/Domain/Traffic/TrafficTest.php | 39 ++++++----- tests/Support/Scheduler/SchedulerTest.php | 66 +++++++++++++++++++ 8 files changed, 186 insertions(+), 27 deletions(-) create mode 100644 database/factories/TrafficFactory.php create mode 100644 src/Support/Scheduler/Actions/ReportUsageAction.php diff --git a/database/factories/TrafficFactory.php b/database/factories/TrafficFactory.php new file mode 100644 index 00000000..fa8f4999 --- /dev/null +++ b/database/factories/TrafficFactory.php @@ -0,0 +1,34 @@ + $this->faker->uuid, + 'user_id' => $this->faker->uuid, + 'upload' => rand(11111111, 99999999), + 'download' => rand(11111111, 99999999), + 'created_at' => $this->faker->dateTimeBetween('-month'), + ]; + } +} diff --git a/src/App/Console/Kernel.php b/src/App/Console/Kernel.php index 244d05d3..9428efc5 100644 --- a/src/App/Console/Kernel.php +++ b/src/App/Console/Kernel.php @@ -8,6 +8,7 @@ use Support\Scheduler\Actions\DeleteFailedFilesAction; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; use Support\Scheduler\Actions\DeleteUnverifiedUsersAction; use Support\Scheduler\Actions\DeleteExpiredShareLinksAction; +use Support\Scheduler\Actions\ReportUsageAction; class Kernel extends ConsoleKernel { @@ -26,7 +27,7 @@ class Kernel extends ConsoleKernel */ protected function schedule(Schedule $schedule): void { - if (! is_storage_driver(['local'])) { + if (! is_storage_driver('local')) { $schedule->call( fn () => resolve(DeleteFailedFilesAction::class)() )->everySixHours(); @@ -38,7 +39,11 @@ class Kernel extends ConsoleKernel $schedule->call( fn () => resolve(DeleteUnverifiedUsersAction::class)() - )->daily(); + )->daily()->at('00:05'); + + $schedule->call( + fn () => resolve(ReportUsageAction::class)() + )->daily()->at('00:10'); // Run queue jobs every minute $schedule->command('queue:work --stop-when-empty') @@ -48,10 +53,10 @@ class Kernel extends ConsoleKernel // Backup app database daily $schedule->command('backup:clean') ->daily() - ->at('01:00'); + ->at('00:15'); $schedule->command('backup:run --only-db') ->daily() - ->at('01:30'); + ->at('00:20'); } /** diff --git a/src/Domain/Files/Actions/UploadFileAction.php b/src/Domain/Files/Actions/UploadFileAction.php index 4a8334bd..72e0ebdf 100644 --- a/src/Domain/Files/Actions/UploadFileAction.php +++ b/src/Domain/Files/Actions/UploadFileAction.php @@ -76,7 +76,7 @@ class UploadFileAction $disk_local->move("chunks/$chunkName", "files/$user_id/$fileName"); // Move files to external storage - if (! is_storage_driver(['local'])) { + if (! is_storage_driver('local')) { ($this->moveFileToExternalStorage)($fileName, $user_id); } diff --git a/src/Domain/Files/Models/File.php b/src/Domain/Files/Models/File.php index f7a72195..1fe95920 100644 --- a/src/Domain/Files/Models/File.php +++ b/src/Domain/Files/Models/File.php @@ -93,7 +93,7 @@ class File extends Model $links = []; // Generate thumbnail link for external storage service - if ($this->type === 'image' && ! is_storage_driver(['local'])) { + if ($this->type === 'image' && ! is_storage_driver('local')) { foreach (config('vuefilemanager.image_sizes') as $item) { $filePath = "files/{$this->user_id}/{$item['name']}-{$this->basename}"; @@ -127,7 +127,7 @@ class File extends Model public function getFileUrlAttribute(): string { // Get file from external storage - if (! is_storage_driver(['local'])) { + if (! is_storage_driver('local')) { $file_pretty_name = is_storage_driver('backblaze') ? Str::snake(mb_strtolower($this->attributes['name'])) : get_pretty_name($this->attributes['basename'], $this->attributes['name'], $this->attributes['mimetype']); diff --git a/src/Domain/Traffic/Models/Traffic.php b/src/Domain/Traffic/Models/Traffic.php index de3e59da..b67866bc 100644 --- a/src/Domain/Traffic/Models/Traffic.php +++ b/src/Domain/Traffic/Models/Traffic.php @@ -1,6 +1,7 @@ whereDate('created_at', today()); diff --git a/src/Support/Scheduler/Actions/ReportUsageAction.php b/src/Support/Scheduler/Actions/ReportUsageAction.php new file mode 100644 index 00000000..ff5e77e5 --- /dev/null +++ b/src/Support/Scheduler/Actions/ReportUsageAction.php @@ -0,0 +1,49 @@ +where('status', 'active') + ->cursor() + ->each(function($subscription) { + $this->recordBandwidth($subscription); + $this->recordStorageCapacity($subscription); + }); + } + + private function recordStorageCapacity(Subscription $subscription): void + { + // Sum all file size + $filesize = DB::table('files') + ->where('user_id', $subscription->user->id) + ->sum('filesize'); + + // We count storage size in GB, e.g. 0.15 is 150mb + $amount = $filesize / 1000000000; + + // Record storage capacity usage + $subscription->recordUsage('storage', $amount); + } + + private function recordBandwidth(Subscription $subscription): void + { + // We count storage size in GB, e.g. 0.15 is 150mb + $record = $subscription + ->user + ->traffics() + ->where('created_at', today()->subDay()) + ->first(); + + $amount = ($record->download ?? 0) / 1000000000; + + // Record storage capacity usage + $subscription->recordUsage('bandwidth', $amount); + } +} \ No newline at end of file diff --git a/tests/Domain/Traffic/TrafficTest.php b/tests/Domain/Traffic/TrafficTest.php index 7cf00fca..c80f30cf 100644 --- a/tests/Domain/Traffic/TrafficTest.php +++ b/tests/Domain/Traffic/TrafficTest.php @@ -1,6 +1,9 @@ assertStatus(201); $this->assertDatabaseHas('traffic', [ - 'user_id' => $this->user->id, - 'upload' => 991, - 'created_at' => now(), + 'user_id' => $this->user->id, + 'upload' => 991, + 'created_at' => now(), ]); $this->travel(1)->day(); @@ -82,9 +84,9 @@ class TrafficTest extends TestCase ])->assertStatus(201); $this->assertDatabaseHas('traffic', [ - 'user_id' => $this->user->id, - 'upload' => 991, - 'created_at' => now(), + 'user_id' => $this->user->id, + 'upload' => 991, + 'created_at' => now(), ]); $this->assertDatabaseCount('traffic', 2); @@ -193,21 +195,18 @@ class TrafficTest extends TestCase */ public function it_get_user_traffic_test() { - $user = User::factory() - ->create(); - foreach (range(0, 30) as $day) { - DB::table('traffic')->insert([ - 'id' => Str::uuid(), - 'user_id' => $user->id, - 'upload' => 10000 * $day, - 'download' => 1000000 * $day, - 'created_at' => now()->subDays($day), - 'updated_at' => now()->subDays($day), - ]); + Traffic::factory() + ->create([ + 'user_id' => $this->user->id, + 'upload' => 10000 * $day, + 'download' => 1000000 * $day, + 'created_at' => now()->subDays($day), + 'updated_at' => now()->subDays($day), + ]); } - $this->actingAs($user) + $this->actingAs($this->user) ->get('/api/user/storage') ->assertOk() ->assertJsonFragment([ diff --git a/tests/Support/Scheduler/SchedulerTest.php b/tests/Support/Scheduler/SchedulerTest.php index 4617de48..7b5d5f29 100644 --- a/tests/Support/Scheduler/SchedulerTest.php +++ b/tests/Support/Scheduler/SchedulerTest.php @@ -1,7 +1,11 @@ create(); + + $plan = Plan::factory() + ->create([ + 'type' => 'metered', + ]); + + PlanMeteredFeature::factory() + ->count(2) + ->sequence( + ['key' => 'storage'], + ['key' => 'bandwidth'], + ) + ->create([ + 'plan_id' => $plan->id, + ]); + + $subscription = Subscription::factory() + ->create([ + 'status' => 'active', + 'type' => 'pre-paid', + 'plan_id' => $plan->id, + 'user_id' => $user->id, + ]); + + File::factory() + ->create([ + 'user_id' => $user->id, + 'filesize' => 125000000, + ]); + + Traffic::factory() + ->create([ + 'user_id' => $user->id, + 'download' => 155000000, + 'created_at' => now()->subDay(), + ]); + + resolve(ReportUsageAction::class)(); + + $this + ->assertDatabaseHas('usages', [ + 'metered_feature_id' => $plan->meteredFeatures()->get()[0]->id, + 'subscription_id' => $subscription->id, + 'quantity' => 0.125, + ]) + ->assertDatabaseHas('usages', [ + 'metered_feature_id' => $plan->meteredFeatures()->get()[1]->id, + 'subscription_id' => $subscription->id, + 'quantity' => 0.155, + ]); + } + /** * @test */