Metrics: Added configured locales and themes, refactoring/formatting

This commit is contained in:
Igor Scheller 2020-04-19 19:18:56 +02:00 committed by msquare
parent 4d8e568ff8
commit e2e2ac0c68
5 changed files with 154 additions and 37 deletions

View File

@ -152,7 +152,7 @@ return [
'voucher_start' => null, 'voucher_start' => null,
], ],
// Available locales in /locale/ // Available locales in /resources/lang/
'locales' => [ 'locales' => [
'de_DE' => 'Deutsch', 'de_DE' => 'Deutsch',
'en_US' => 'English', 'en_US' => 'English',

View File

@ -8,6 +8,7 @@ use Engelsystem\Helpers\Version;
use Engelsystem\Http\Exceptions\HttpForbidden; use Engelsystem\Http\Exceptions\HttpForbidden;
use Engelsystem\Http\Request; use Engelsystem\Http\Request;
use Engelsystem\Http\Response; use Engelsystem\Http\Response;
use Illuminate\Support\Collection;
use Psr\Log\LogLevel; use Psr\Log\LogLevel;
class Controller extends BaseController class Controller extends BaseController
@ -62,16 +63,9 @@ class Controller extends BaseController
$now = microtime(true); $now = microtime(true);
$this->checkAuth(); $this->checkAuth();
$tshirtSizes = []; $userTshirtSizes = $this->formatStats($this->stats->tshirtSizes(), 'tshirt_sizes', 'shirt_size', 'size');
$userSizes = $this->stats->tshirtSizes(); $userLocales = $this->formatStats($this->stats->languages(), 'locales', 'language', 'locale');
$userThemes = $this->formatStats($this->stats->themes(), 'available_themes', 'theme');
foreach ($this->config->get('tshirt_sizes') as $name => $description) {
$size = $userSizes->where('shirt_size', '=', $name)->sum('count');
$tshirtSizes[] = [
'labels' => ['size' => $name],
$size,
];
}
$data = [ $data = [
$this->config->get('app_name') . ' stats', $this->config->get('app_name') . ' stats',
@ -117,7 +111,12 @@ class Controller extends BaseController
'worklog_seconds' => ['type' => 'gauge', $this->stats->worklogSeconds()], 'worklog_seconds' => ['type' => 'gauge', $this->stats->worklogSeconds()],
'vouchers' => ['type' => 'counter', $this->stats->vouchers()], 'vouchers' => ['type' => 'counter', $this->stats->vouchers()],
'tshirts_issued' => ['type' => 'counter', 'help' => 'Issued T-Shirts', $this->stats->tshirts()], '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()], 'shifts' => ['type' => 'gauge', $this->stats->shifts()],
'announcements' => [ 'announcements' => [
'type' => 'gauge', 'type' => 'gauge',
@ -212,4 +211,27 @@ class Controller extends BaseController
throw new HttpForbidden($message, $headers); 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;
}
} }

View File

@ -12,7 +12,10 @@ use Engelsystem\Models\Message;
use Engelsystem\Models\News; use Engelsystem\Models\News;
use Engelsystem\Models\Question; use Engelsystem\Models\Question;
use Engelsystem\Models\User\PasswordReset; use Engelsystem\Models\User\PasswordReset;
use Engelsystem\Models\User\PersonalData;
use Engelsystem\Models\User\Settings;
use Engelsystem\Models\User\State; use Engelsystem\Models\User\State;
use Engelsystem\Models\User\User;
use Illuminate\Database\Query\Builder as QueryBuilder; use Illuminate\Database\Query\Builder as QueryBuilder;
use Illuminate\Database\Query\Expression as QueryExpression; use Illuminate\Database\Query\Expression as QueryExpression;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
@ -94,8 +97,7 @@ class Stats
*/ */
public function currentlyWorkingUsers(bool $freeloaded = null): int public function currentlyWorkingUsers(bool $freeloaded = null): int
{ {
$query = $this $query = User::query()
->getQuery('users')
->join('ShiftEntry', 'ShiftEntry.UID', '=', 'users.id') ->join('ShiftEntry', 'ShiftEntry.UID', '=', 'users.id')
->join('Shifts', 'Shifts.SID', '=', 'ShiftEntry.SID') ->join('Shifts', 'Shifts.SID', '=', 'ShiftEntry.SID')
->where('Shifts.start', '<=', time()) ->where('Shifts.start', '<=', time())
@ -129,11 +131,32 @@ class Stats
*/ */
public function tshirtSizes(): Collection public function tshirtSizes(): Collection
{ {
return $this return PersonalData::query()
->getQuery('users_personal_data')
->select(['shirt_size', $this->raw('COUNT(shirt_size) AS count')]) ->select(['shirt_size', $this->raw('COUNT(shirt_size) AS count')])
->whereNotNull('shirt_size') ->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(); ->get();
} }

View File

@ -2,6 +2,7 @@
namespace Engelsystem\Test\Unit\Controllers\Metrics; namespace Engelsystem\Test\Unit\Controllers\Metrics;
use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts;
use Engelsystem\Config\Config; use Engelsystem\Config\Config;
use Engelsystem\Controllers\Metrics\Controller; use Engelsystem\Controllers\Metrics\Controller;
use Engelsystem\Controllers\Metrics\MetricsEngine; use Engelsystem\Controllers\Metrics\MetricsEngine;
@ -18,9 +19,12 @@ use Symfony\Component\HttpFoundation\ServerBag;
class ControllerTest extends TestCase class ControllerTest extends TestCase
{ {
use ArraySubsetAsserts;
/** /**
* @covers \Engelsystem\Controllers\Metrics\Controller::__construct * @covers \Engelsystem\Controllers\Metrics\Controller::__construct
* @covers \Engelsystem\Controllers\Metrics\Controller::metrics * @covers \Engelsystem\Controllers\Metrics\Controller::metrics
* @covers \Engelsystem\Controllers\Metrics\Controller::formatStats
*/ */
public function testMetrics() public function testMetrics()
{ {
@ -48,6 +52,8 @@ class ControllerTest extends TestCase
$this->assertArrayHasKey('vouchers', $data); $this->assertArrayHasKey('vouchers', $data);
$this->assertArrayHasKey('tshirts_issued', $data); $this->assertArrayHasKey('tshirts_issued', $data);
$this->assertArrayHasKey('tshirt_sizes', $data); $this->assertArrayHasKey('tshirt_sizes', $data);
$this->assertArrayHasKey('locales', $data);
$this->assertArrayHasKey('themes', $data);
$this->assertArrayHasKey('shifts', $data); $this->assertArrayHasKey('shifts', $data);
$this->assertArrayHasKey('announcements', $data); $this->assertArrayHasKey('announcements', $data);
$this->assertArrayHasKey('questions', $data); $this->assertArrayHasKey('questions', $data);
@ -59,6 +65,12 @@ class ControllerTest extends TestCase
$this->assertArrayHasKey('log_entries', $data); $this->assertArrayHasKey('log_entries', $data);
$this->assertArrayHasKey('scrape_duration_seconds', $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'; return 'metrics return';
}); });
@ -113,7 +125,13 @@ class ControllerTest extends TestCase
$this->setExpects($stats, 'vouchers', null, 17); $this->setExpects($stats, 'vouchers', null, 17);
$this->setExpects($stats, 'tshirts', null, 3); $this->setExpects($stats, 'tshirts', null, 3);
$this->setExpects($stats, 'tshirtSizes', null, new Collection([ $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, 'shifts', null, 142);
$this->setExpects($stats, 'messages', null, 3); $this->setExpects($stats, 'messages', null, 3);
@ -125,6 +143,14 @@ class ControllerTest extends TestCase
'L' => 'Large', 'L' => 'Large',
'XL' => 'X 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'); $this->setExpects($version, 'getVersion', [], '0.42.42');

View File

@ -10,6 +10,7 @@ use Engelsystem\Models\News;
use Engelsystem\Models\Question; use Engelsystem\Models\Question;
use Engelsystem\Models\User\PasswordReset; use Engelsystem\Models\User\PasswordReset;
use Engelsystem\Models\User\PersonalData; use Engelsystem\Models\User\PersonalData;
use Engelsystem\Models\User\Settings;
use Engelsystem\Models\User\State; use Engelsystem\Models\User\State;
use Engelsystem\Models\User\User; use Engelsystem\Models\User\User;
use Engelsystem\Test\Unit\HasDatabase; use Engelsystem\Test\Unit\HasDatabase;
@ -58,7 +59,6 @@ class StatsTest extends TestCase
/** /**
* @covers \Engelsystem\Controllers\Metrics\Stats::tshirtSizes * @covers \Engelsystem\Controllers\Metrics\Stats::tshirtSizes
* @covers \Engelsystem\Controllers\Metrics\Stats::raw * @covers \Engelsystem\Controllers\Metrics\Stats::raw
* @covers \Engelsystem\Controllers\Metrics\Stats::getQuery
*/ */
public function testTshirtSizes() public function testTshirtSizes()
{ {
@ -68,11 +68,44 @@ class StatsTest extends TestCase
$sizes = $stats->tshirtSizes(); $sizes = $stats->tshirtSizes();
$this->assertCount(2, $sizes); $this->assertCount(2, $sizes);
$this->assertEquals([ $this->assertEquals([
(object)['shirt_size' => 'L', 'count' => 2], ['shirt_size' => 'L', 'count' => 2],
(object)['shirt_size' => 'XXL', 'count' => 1], ['shirt_size' => 'XXL', 'count' => 1],
], $sizes->toArray()); ], $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 * @covers \Engelsystem\Controllers\Metrics\Stats::announcements
@ -118,7 +151,7 @@ class StatsTest extends TestCase
$this->addUsers(); $this->addUsers();
$stats = new Stats($this->database); $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::sessions
* @covers \Engelsystem\Controllers\Metrics\Stats::getQuery
*/ */
public function testSessions() public function testSessions()
{ {
@ -223,18 +257,20 @@ class StatsTest extends TestCase
$this->addUser(); $this->addUser();
$this->addUser([], ['shirt_size' => 'L']); $this->addUser([], ['shirt_size' => 'L']);
$this->addUser(['arrived' => 1]); $this->addUser(['arrived' => 1]);
$this->addUser(['arrived' => 1, 'got_voucher' => 2], ['shirt_size' => 'XXL']); $this->addUser(['arrived' => 1], [], ['language' => 'lo_RM']);
$this->addUser(['arrived' => 1, 'got_voucher' => 9]); $this->addUser(['arrived' => 1, 'got_voucher' => 2], ['shirt_size' => 'XXL'], ['language' => 'lo_RM']);
$this->addUser(['arrived' => 1, 'got_voucher' => 3, 'force_active' => true]); $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, '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 $state
* @param array $personalData * @param array $personalData
* @param array $settings
*/ */
protected function addUser(array $state = [], $personalData = []) protected function addUser(array $state = [], $personalData = [], $settings = [])
{ {
$name = 'user_' . Str::random(5); $name = 'user_' . Str::random(5);
@ -255,6 +291,16 @@ class StatsTest extends TestCase
$personalData->user() $personalData->user()
->associate($user) ->associate($user)
->save(); ->save();
$settings = new Settings(array_merge([
'language' => 'te_ST',
'theme' => 0,
'email_human' => '',
'email_shiftinfo' => '',
], $settings));
$settings->user()
->associate($user)
->save();
} }
/** /**