From e2e2ac0c68ed453421f69204588020dc92a2b01b Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Sun, 19 Apr 2020 19:18:56 +0200 Subject: [PATCH] Metrics: Added configured locales and themes, refactoring/formatting --- config/config.default.php | 22 +++---- src/Controllers/Metrics/Controller.php | 44 +++++++++---- src/Controllers/Metrics/Stats.php | 33 ++++++++-- .../Controllers/Metrics/ControllerTest.php | 28 +++++++- tests/Unit/Controllers/Metrics/StatsTest.php | 64 ++++++++++++++++--- 5 files changed, 154 insertions(+), 37 deletions(-) diff --git a/config/config.default.php b/config/config.default.php index 3a03941e..e9bad153 100644 --- a/config/config.default.php +++ b/config/config.default.php @@ -70,17 +70,17 @@ return [ 'available_themes' => [ '12' => 'Engelsystem 36c3 (2019)', '10' => 'Engelsystem cccamp19 green (2019)', - '9' => 'Engelsystem cccamp19 yellow (2019)', - '8' => 'Engelsystem cccamp19 blue (2019)', - '7' => 'Engelsystem 35c3 dark (2018)', - '6' => 'Engelsystem 34c3 dark (2017)', - '5' => 'Engelsystem 34c3 light (2017)', - '4' => 'Engelsystem 33c3 (2016)', - '3' => 'Engelsystem 32c3 (2015)', - '2' => 'Engelsystem cccamp15', + '9' => 'Engelsystem cccamp19 yellow (2019)', + '8' => 'Engelsystem cccamp19 blue (2019)', + '7' => 'Engelsystem 35c3 dark (2018)', + '6' => 'Engelsystem 34c3 dark (2017)', + '5' => 'Engelsystem 34c3 light (2017)', + '4' => 'Engelsystem 33c3 (2016)', + '3' => 'Engelsystem 32c3 (2015)', + '2' => 'Engelsystem cccamp15', '11' => 'Engelsystem high contrast', - '0' => 'Engelsystem light', - '1' => 'Engelsystem dark', + '0' => 'Engelsystem light', + '1' => 'Engelsystem dark', ], // Redirect to this site after logging in or when pressing the top-left button @@ -152,7 +152,7 @@ return [ 'voucher_start' => null, ], - // Available locales in /locale/ + // Available locales in /resources/lang/ 'locales' => [ 'de_DE' => 'Deutsch', 'en_US' => 'English', diff --git a/src/Controllers/Metrics/Controller.php b/src/Controllers/Metrics/Controller.php index a47b8159..c1ba46ff 100644 --- a/src/Controllers/Metrics/Controller.php +++ b/src/Controllers/Metrics/Controller.php @@ -8,6 +8,7 @@ use Engelsystem\Helpers\Version; use Engelsystem\Http\Exceptions\HttpForbidden; use Engelsystem\Http\Request; use Engelsystem\Http\Response; +use Illuminate\Support\Collection; use Psr\Log\LogLevel; class Controller extends BaseController @@ -62,16 +63,9 @@ class Controller extends BaseController $now = microtime(true); $this->checkAuth(); - $tshirtSizes = []; - $userSizes = $this->stats->tshirtSizes(); - - foreach ($this->config->get('tshirt_sizes') as $name => $description) { - $size = $userSizes->where('shirt_size', '=', $name)->sum('count'); - $tshirtSizes[] = [ - 'labels' => ['size' => $name], - $size, - ]; - } + $userTshirtSizes = $this->formatStats($this->stats->tshirtSizes(), 'tshirt_sizes', 'shirt_size', 'size'); + $userLocales = $this->formatStats($this->stats->languages(), 'locales', 'language', 'locale'); + $userThemes = $this->formatStats($this->stats->themes(), 'available_themes', 'theme'); $data = [ $this->config->get('app_name') . ' stats', @@ -117,7 +111,12 @@ class Controller extends BaseController 'worklog_seconds' => ['type' => 'gauge', $this->stats->worklogSeconds()], 'vouchers' => ['type' => 'counter', $this->stats->vouchers()], 'tshirts_issued' => ['type' => 'counter', 'help' => 'Issued T-Shirts', $this->stats->tshirts()], - 'tshirt_sizes' => ['type' => 'gauge', 'help' => 'The sizes users have configured'] + $tshirtSizes, + 'tshirt_sizes' => [ + 'type' => 'gauge', + 'help' => 'The sizes users have configured' + ] + $userTshirtSizes, + 'locales' => ['type' => 'gauge', 'help' => 'The locales users have configured'] + $userLocales, + 'themes' => ['type' => 'gauge', 'help' => 'The themes users have configured'] + $userThemes, 'shifts' => ['type' => 'gauge', $this->stats->shifts()], 'announcements' => [ 'type' => 'gauge', @@ -212,4 +211,27 @@ class Controller extends BaseController throw new HttpForbidden($message, $headers); } + + /** + * Formats the stats collection as stats data + * + * @param Collection $data + * @param string $config + * @param string $dataField + * @param string|null $label + * @return array + */ + protected function formatStats(Collection $data, string $config, string $dataField, ?string $label = null): array + { + $return = []; + foreach ($this->config->get($config) as $name => $description) { + $count = $data->where($dataField, '=', $name)->sum('count'); + $return[] = [ + 'labels' => [($label ?: $dataField) => $name], + $count, + ]; + } + + return $return; + } } diff --git a/src/Controllers/Metrics/Stats.php b/src/Controllers/Metrics/Stats.php index 8129f27c..47e0d3e6 100644 --- a/src/Controllers/Metrics/Stats.php +++ b/src/Controllers/Metrics/Stats.php @@ -12,7 +12,10 @@ use Engelsystem\Models\Message; use Engelsystem\Models\News; use Engelsystem\Models\Question; use Engelsystem\Models\User\PasswordReset; +use Engelsystem\Models\User\PersonalData; +use Engelsystem\Models\User\Settings; use Engelsystem\Models\User\State; +use Engelsystem\Models\User\User; use Illuminate\Database\Query\Builder as QueryBuilder; use Illuminate\Database\Query\Expression as QueryExpression; use Illuminate\Support\Collection; @@ -94,8 +97,7 @@ class Stats */ public function currentlyWorkingUsers(bool $freeloaded = null): int { - $query = $this - ->getQuery('users') + $query = User::query() ->join('ShiftEntry', 'ShiftEntry.UID', '=', 'users.id') ->join('Shifts', 'Shifts.SID', '=', 'ShiftEntry.SID') ->where('Shifts.start', '<=', time()) @@ -129,11 +131,32 @@ class Stats */ public function tshirtSizes(): Collection { - return $this - ->getQuery('users_personal_data') + return PersonalData::query() ->select(['shirt_size', $this->raw('COUNT(shirt_size) AS count')]) ->whereNotNull('shirt_size') - ->groupBy('shirt_size') + ->groupBy(['shirt_size']) + ->get(); + } + + /** + * @return Collection + */ + public function languages(): Collection + { + return Settings::query() + ->select(['language', $this->raw('COUNT(language) AS count')]) + ->groupBy(['language']) + ->get(); + } + + /** + * @return Collection + */ + public function themes(): Collection + { + return Settings::query() + ->select(['theme', $this->raw('COUNT(theme) AS count')]) + ->groupBy(['theme']) ->get(); } diff --git a/tests/Unit/Controllers/Metrics/ControllerTest.php b/tests/Unit/Controllers/Metrics/ControllerTest.php index eefe96ad..f211ee8d 100644 --- a/tests/Unit/Controllers/Metrics/ControllerTest.php +++ b/tests/Unit/Controllers/Metrics/ControllerTest.php @@ -2,6 +2,7 @@ namespace Engelsystem\Test\Unit\Controllers\Metrics; +use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts; use Engelsystem\Config\Config; use Engelsystem\Controllers\Metrics\Controller; use Engelsystem\Controllers\Metrics\MetricsEngine; @@ -18,9 +19,12 @@ use Symfony\Component\HttpFoundation\ServerBag; class ControllerTest extends TestCase { + use ArraySubsetAsserts; + /** * @covers \Engelsystem\Controllers\Metrics\Controller::__construct * @covers \Engelsystem\Controllers\Metrics\Controller::metrics + * @covers \Engelsystem\Controllers\Metrics\Controller::formatStats */ public function testMetrics() { @@ -48,6 +52,8 @@ class ControllerTest extends TestCase $this->assertArrayHasKey('vouchers', $data); $this->assertArrayHasKey('tshirts_issued', $data); $this->assertArrayHasKey('tshirt_sizes', $data); + $this->assertArrayHasKey('locales', $data); + $this->assertArrayHasKey('themes', $data); $this->assertArrayHasKey('shifts', $data); $this->assertArrayHasKey('announcements', $data); $this->assertArrayHasKey('questions', $data); @@ -59,6 +65,12 @@ class ControllerTest extends TestCase $this->assertArrayHasKey('log_entries', $data); $this->assertArrayHasKey('scrape_duration_seconds', $data); + $this->assertArraySubset(['tshirt_sizes' => [ + 'type' => 'gauge', + ['labels' => ['size' => 'L'], 2], + ['labels' => ['size' => 'XL'], 0] + ]], $data); + return 'metrics return'; }); @@ -113,7 +125,13 @@ class ControllerTest extends TestCase $this->setExpects($stats, 'vouchers', null, 17); $this->setExpects($stats, 'tshirts', null, 3); $this->setExpects($stats, 'tshirtSizes', null, new Collection([ - (object)['shirt_size' => 'L', 'count' => 2], + ['shirt_size' => 'L', 'count' => 2], + ])); + $this->setExpects($stats, 'languages', null, new Collection([ + ['language' => 'en_US', 'count' => 5], + ])); + $this->setExpects($stats, 'themes', null, new Collection([ + ['theme' => '1', 'count' => 3], ])); $this->setExpects($stats, 'shifts', null, 142); $this->setExpects($stats, 'messages', null, 3); @@ -125,6 +143,14 @@ class ControllerTest extends TestCase 'L' => 'Large', 'XL' => 'X Large', ]); + $config->set('locales', [ + 'de_DE' => 'German', + 'en_US' => 'US English', + ]); + $config->set('available_themes', [ + '0' => 'Nothing', + '1' => 'Testing', + ]); $this->setExpects($version, 'getVersion', [], '0.42.42'); diff --git a/tests/Unit/Controllers/Metrics/StatsTest.php b/tests/Unit/Controllers/Metrics/StatsTest.php index 15447be8..a017dfee 100644 --- a/tests/Unit/Controllers/Metrics/StatsTest.php +++ b/tests/Unit/Controllers/Metrics/StatsTest.php @@ -10,6 +10,7 @@ use Engelsystem\Models\News; use Engelsystem\Models\Question; use Engelsystem\Models\User\PasswordReset; use Engelsystem\Models\User\PersonalData; +use Engelsystem\Models\User\Settings; use Engelsystem\Models\User\State; use Engelsystem\Models\User\User; use Engelsystem\Test\Unit\HasDatabase; @@ -58,7 +59,6 @@ class StatsTest extends TestCase /** * @covers \Engelsystem\Controllers\Metrics\Stats::tshirtSizes * @covers \Engelsystem\Controllers\Metrics\Stats::raw - * @covers \Engelsystem\Controllers\Metrics\Stats::getQuery */ public function testTshirtSizes() { @@ -68,11 +68,44 @@ class StatsTest extends TestCase $sizes = $stats->tshirtSizes(); $this->assertCount(2, $sizes); $this->assertEquals([ - (object)['shirt_size' => 'L', 'count' => 2], - (object)['shirt_size' => 'XXL', 'count' => 1], + ['shirt_size' => 'L', 'count' => 2], + ['shirt_size' => 'XXL', 'count' => 1], ], $sizes->toArray()); } + /** + * @covers \Engelsystem\Controllers\Metrics\Stats::languages + */ + public function testLanguages() + { + $this->addUsers(); + + $stats = new Stats($this->database); + $languages = $stats->languages(); + $this->assertCount(2, $languages); + $this->assertEquals([ + ['language' => 'lo_RM', 'count' => 2], + ['language' => 'te_ST', 'count' => 7], + ], $languages->toArray()); + } + + /** + * @covers \Engelsystem\Controllers\Metrics\Stats::themes + */ + public function testThemes() + { + $this->addUsers(); + + $stats = new Stats($this->database); + $themes = $stats->themes(); + $this->assertCount(3, $themes); + $this->assertEquals([ + ['theme' => 0, 'count' => 7], + ['theme' => 1, 'count' => 1], + ['theme' => 4, 'count' => 1], + ], $themes->toArray()); + } + /** * @covers \Engelsystem\Controllers\Metrics\Stats::announcements @@ -118,7 +151,7 @@ class StatsTest extends TestCase $this->addUsers(); $stats = new Stats($this->database); - $this->assertEquals(6, $stats->arrivedUsers()); + $this->assertEquals(7, $stats->arrivedUsers()); } /** @@ -149,6 +182,7 @@ class StatsTest extends TestCase /** * @covers \Engelsystem\Controllers\Metrics\Stats::sessions + * @covers \Engelsystem\Controllers\Metrics\Stats::getQuery */ public function testSessions() { @@ -223,18 +257,20 @@ class StatsTest extends TestCase $this->addUser(); $this->addUser([], ['shirt_size' => 'L']); $this->addUser(['arrived' => 1]); - $this->addUser(['arrived' => 1, 'got_voucher' => 2], ['shirt_size' => 'XXL']); - $this->addUser(['arrived' => 1, 'got_voucher' => 9]); - $this->addUser(['arrived' => 1, 'got_voucher' => 3, 'force_active' => true]); + $this->addUser(['arrived' => 1], [], ['language' => 'lo_RM']); + $this->addUser(['arrived' => 1, 'got_voucher' => 2], ['shirt_size' => 'XXL'], ['language' => 'lo_RM']); + $this->addUser(['arrived' => 1, 'got_voucher' => 9, 'force_active' => true], [], ['theme' => 1]); + $this->addUser(['arrived' => 1, 'got_voucher' => 3], ['theme' => 10]); $this->addUser(['arrived' => 1, 'active' => 1, 'got_shirt' => true, 'force_active' => true]); - $this->addUser(['arrived' => 1, 'active' => 1, 'got_shirt' => true], ['shirt_size' => 'L']); + $this->addUser(['arrived' => 1, 'active' => 1, 'got_shirt' => true], ['shirt_size' => 'L'], ['theme' => 4]); } /** * @param array $state * @param array $personalData + * @param array $settings */ - protected function addUser(array $state = [], $personalData = []) + protected function addUser(array $state = [], $personalData = [], $settings = []) { $name = 'user_' . Str::random(5); @@ -255,6 +291,16 @@ class StatsTest extends TestCase $personalData->user() ->associate($user) ->save(); + + $settings = new Settings(array_merge([ + 'language' => 'te_ST', + 'theme' => 0, + 'email_human' => '', + 'email_shiftinfo' => '', + ], $settings)); + $settings->user() + ->associate($user) + ->save(); } /**