Skip to content

Commit

Permalink
Merge branch '1.5' of github.com:benjaminjonard/koillection into 1.5
Browse files Browse the repository at this point in the history
  • Loading branch information
benjaminjonard committed Apr 30, 2024
2 parents 3c28432 + f925639 commit a5642b7
Show file tree
Hide file tree
Showing 28 changed files with 397 additions and 39 deletions.
131 changes: 131 additions & 0 deletions api/Controller/MetricsController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
<?php

declare(strict_types=1);

namespace Api\Controller;

use App\Enum\ConfigurationEnum;
use App\Repository\AlbumRepository;
use App\Repository\CollectionRepository;
use App\Repository\ConfigurationRepository;
use App\Repository\DatumRepository;
use App\Repository\ItemRepository;
use App\Repository\PhotoRepository;
use App\Repository\ScraperRepository;
use App\Repository\TagCategoryRepository;
use App\Repository\TagRepository;
use App\Repository\TemplateRepository;
use App\Repository\UserRepository;
use App\Repository\WishlistRepository;
use App\Repository\WishRepository;
use App\Service\DiskUsageCalculator;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\Routing\Annotation\Route;

class MetricsController extends AbstractController
{
private array $lines = [];

#[Route(
path: '/api/metrics',
name: 'api_metrics',
methods: ['GET']
)]
public function __invoke(
ConfigurationRepository $configurationRepository,
UserRepository $userRepository,
CollectionRepository $collectionRepository,
ItemRepository $itemRepository,
DatumRepository $datumRepository,
TagRepository $tagRepository,
TagCategoryRepository $tagCategoryRepository,
WishlistRepository $wishlistRepository,
WishRepository $wishRepository,
AlbumRepository $albumRepository,
PhotoRepository $photoRepository,
TemplateRepository $templateRepository,
ScraperRepository $scraperRepository,
DiskUsageCalculator $diskUsageCalculator
): Response
{
if ($configurationRepository->findOneBy(['label' => ConfigurationEnum::ENABLE_METRICS])->getValue() !== '1') {
throw new AccessDeniedHttpException();
}

$users = $userRepository->findAll();

$this->addCounter('user', [['label' => '', 'value' => $userRepository->count()]], 'number of registered users');

// Create global counters
$collectionValues[] = ['label' => null, 'value' => $collectionRepository->count()];
$itemValues[] = ['label' => null, 'value' => $itemRepository->count()];
$datumValues[] = ['label' => null, 'value' => $datumRepository->count()];
$tagValues[] = ['label' => null, 'value' => $tagRepository->count()];
$tagCategoryValues[] = ['label' => null, 'value' => $tagCategoryRepository->count()];
$wishlistValues[] = ['label' => null, 'value' => $wishlistRepository->count()];
$wishValues[] = ['label' => null, 'value' => $wishRepository->count()];
$albumValues[] = ['label' => null, 'value' => $albumRepository->count()];
$photoValues[] = ['label' => null, 'value' => $photoRepository->count()];
$templateValues[] = ['label' => null, 'value' => $templateRepository->count()];
$scraperValues[] = ['label' => null, 'value' => $scraperRepository->count()];
$diskUsedValues[] = ['label' => null, 'value' => $diskUsageCalculator->getSpaceUsedByUsers()];
$diskAvailableValues = [];

// Create counters per user
foreach ($users as $user) {
$label = "{user=\"{$user->getUsername()}\"}";
$collectionValues[] = ['label' => $label, 'value' => $collectionRepository->count(['owner' => $user])];
$itemValues[] = ['label' => $label, 'value' => $itemRepository->count(['owner' => $user])];
$datumValues[] = ['label' => $label, 'value' => $datumRepository->count(['owner' => $user])];
$tagValues[] = ['label' => $label, 'value' => $tagRepository->count(['owner' => $user])];
$tagCategoryValues[] = ['label' => $label, 'value' => $tagCategoryRepository->count(['owner' => $user])];
$wishlistValues[] = ['label' => $label, 'value' => $wishlistRepository->count(['owner' => $user])];
$wishValues[] = ['label' => $label, 'value' => $wishRepository->count(['owner' => $user])];
$albumValues[] = ['label' => $label, 'value' => $albumRepository->count(['owner' => $user])];
$photoValues[] = ['label' => $label, 'value' => $photoRepository->count(['owner' => $user])];
$templateValues[] = ['label' => $label, 'value' => $templateRepository->count(['owner' => $user])];
$scraperValues[] = ['label' => $label, 'value' => $scraperRepository->count(['owner' => $user])];
$diskUsedValues[] = ['label' => $label, 'value' => $diskUsageCalculator->getSpaceUsedByUser($user)];
$diskAvailableValues[] = ['label' => $label, 'value' => $user->getDiskSpaceAllowed()];
}

// Fill metrics
$this->addCounter('collection', $collectionValues, 'number of created collections');
$this->addCounter('item', $itemValues, 'number of created items');
$this->addCounter('datum', $datumValues, 'number of created data');
$this->addCounter('tag', $tagValues, 'number of created tags');
$this->addCounter('tag_category', $tagCategoryValues, 'number of created tag categories');
$this->addCounter('wishlist', $wishlistValues, 'number of created wishlists');
$this->addCounter('wish', $wishValues, 'number of created wishes');
$this->addCounter('album', $albumValues, 'number of created albums');
$this->addCounter('photo', $photoValues, 'number of created photos');
$this->addCounter('template', $templateValues, 'number of created templates');
$this->addCounter('scraper', $scraperValues, 'number of created scrapers');
$this->addCounter('used_disk_space_bytes', $diskUsedValues, 'used disk space by uploads (images, videos, files)', 'bytes');
$this->addCounter('available_disk_space_bytes', $diskAvailableValues, 'available disk space for uploads (images, videos, files)', 'bytes');

$metrics = implode(PHP_EOL, $this->lines);
$response = new Response();
$response->setContent($metrics);
$response->headers->set('Content-Type', 'text/plain');

return $response;
}

public function addCounter(string $name, array $values, string $help, string $unit = null): void
{
//$name = "koillection_{$name}";

$this->lines[] = "# HELP {$name} {$help}";
if ($unit !== null) {
$this->lines[] = "# UNIT {$name} {$unit}";
}
$this->lines[] = "# TYPE {$name} counter";

foreach ($values as $value) {
$this->lines[] = "{$name}_total{$value['label']} {$value['value']}";
}
}
}
2 changes: 2 additions & 0 deletions api/OpenApi/JwtDecorator.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
use ApiPlatform\OpenApi\Model\PathItem;
use ApiPlatform\OpenApi\Model\RequestBody;
use ApiPlatform\OpenApi\OpenApi;
use Symfony\Component\DependencyInjection\Attribute\AsDecorator;

#[AsDecorator(decorates: 'api_platform.openapi.factory')]
final readonly class JwtDecorator implements OpenApiFactoryInterface
{
public function __construct(
Expand Down
48 changes: 48 additions & 0 deletions api/OpenApi/MetricsDecorator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

declare(strict_types=1);

namespace Api\OpenApi;

use ApiPlatform\OpenApi\Factory\OpenApiFactoryInterface;
use ApiPlatform\OpenApi\Model\Operation;
use ApiPlatform\OpenApi\Model\PathItem;
use ApiPlatform\OpenApi\OpenApi;
use App\Enum\ConfigurationEnum;
use App\Repository\ConfigurationRepository;
use Symfony\Component\DependencyInjection\Attribute\AsDecorator;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;

#[AsDecorator(decorates: 'api_platform.openapi.factory')]
final readonly class MetricsDecorator implements OpenApiFactoryInterface
{
public function __construct(
private OpenApiFactoryInterface $decorated
) {
}

public function __invoke(array $context = []): OpenApi
{
$openApi = ($this->decorated)($context);

$pathItem = new PathItem(
ref: 'Metrics',
get: new Operation(
operationId: 'getMetrics',
tags: ['Metrics'],
responses: [
'200' => [
'description' => 'Get metrics',
'content' => [
'text/plain' => [],
],
],
],
summary: 'Get metrics.',
),
);
$openApi->getPaths()->addPath('/api/metrics', $pathItem);

return $openApi;
}
}
1 change: 1 addition & 0 deletions config/packages/security.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ security:
- { path: ^/translations, role: PUBLIC_ACCESS }
- { path: (?:^/api$)|(?:^/api/docs)|(?:^/api/index.(html|json|jsonld)$), roles: PUBLIC_ACCESS }
- { path: ^/api/authentication_token, roles: PUBLIC_ACCESS }
- { path: ^/api/metrics, roles: PUBLIC_ACCESS }
- { path: ^/$, role: PUBLIC_ACCESS }
- { path: ^/, role: ROLE_USER }

Expand Down
6 changes: 6 additions & 0 deletions config/routes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ controllers:
namespace: App\Controller
type: attribute

api_controllers:
resource:
path: ../api/Controller/
namespace: Api\Controller
type: attribute

kernel:
resource: ../src/Kernel.php
type: attribute
Expand Down
6 changes: 3 additions & 3 deletions config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ services:
resource: '../src/Controller'
tags: ['controller.service_arguments']

Api\OpenApi\JwtDecorator:
decorates: 'api_platform.openapi.factory'
arguments: [ '@.inner' ]
Api\Controller\:
resource: '../api/Controller'
tags: [ 'controller.service_arguments' ]

when@test:
services:
Expand Down
6 changes: 3 additions & 3 deletions migrations/Mysql/Version20220916162932.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public function up(Schema $schema): void

$collections = $this->connection->createQueryBuilder()->select('id, owner_id, children_title')->from('koi_collection')->executeQuery()->fetchAllAssociative();
foreach ($collections as $collection) {
$id = Uuid::v4()->toRfc4122();
$id = Uuid::v7()->toRfc4122();
$collectionId = $collection['id'];
$ownerId = $collection['owner_id'];
$label = !empty($collection['children_title']) ? "'" . $collection['children_title'] . "'" : 'NULL';
Expand All @@ -52,7 +52,7 @@ public function up(Schema $schema): void

$albums = $this->connection->createQueryBuilder()->select('id, owner_id')->from('koi_album')->executeQuery()->fetchAllAssociative();
foreach ($albums as $album) {
$id = Uuid::v4()->toRfc4122();
$id = Uuid::v7()->toRfc4122();
$albumId = $album['id'];
$ownerId = $album['owner_id'];

Expand All @@ -62,7 +62,7 @@ public function up(Schema $schema): void

$wishlists = $this->connection->createQueryBuilder()->select('id, owner_id')->from('koi_wishlist')->executeQuery()->fetchAllAssociative();
foreach ($wishlists as $wishlist) {
$id = Uuid::v4()->toRfc4122();
$id = Uuid::v7()->toRfc4122();
$wishlistId = $wishlist['id'];
$ownerId = $wishlist['owner_id'];

Expand Down
4 changes: 2 additions & 2 deletions migrations/Mysql/Version20220917151134.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public function up(Schema $schema): void

$collections = $this->connection->createQueryBuilder()->select('id, owner_id, items_title, items_display_mode, items_sorting_property, items_sorting_direction, items_sorting_type, items_list_columns, items_list_show_visibility, items_list_show_actions')->from('koi_collection')->executeQuery()->fetchAllAssociative();
foreach ($collections as $collection) {
$id = Uuid::v4()->toRfc4122();
$id = Uuid::v7()->toRfc4122();
$collectionId = $collection['id'];
$ownerId = $collection['owner_id'];
$label = !empty($collection['items_title']) ? "'" . $collection['items_title'] . "'" : 'NULL';
Expand All @@ -58,7 +58,7 @@ public function up(Schema $schema): void

$albums = $this->connection->createQueryBuilder()->select('id, owner_id, photos_display_mode')->from('koi_album')->executeQuery()->fetchAllAssociative();
foreach ($albums as $album) {
$id = Uuid::v4()->toRfc4122();
$id = Uuid::v7()->toRfc4122();
$albumId = $album['id'];
$ownerId = $album['owner_id'];
$displayMode = !empty($album['photos_display_mode']) ? "'" . $album['photos_display_mode'] . "'" : 'NULL';
Expand Down
2 changes: 1 addition & 1 deletion migrations/Mysql/Version20220918183100.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public function up(Schema $schema): void

$tags = $this->connection->createQueryBuilder()->select('id, owner_id, items_display_mode')->from('koi_tag')->executeQuery()->fetchAllAssociative();
foreach ($tags as $tag) {
$id = Uuid::v4()->toRfc4122();
$id = Uuid::v7()->toRfc4122();
$tagId = $tag['id'];
$ownerId = $tag['owner_id'];
$displayMode = !empty($tag['items_display_mode']) ? "'" . $tag['items_display_mode'] . "'" : 'NULL';
Expand Down
6 changes: 3 additions & 3 deletions migrations/Mysql/Version20220920150306.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,19 @@ public function up(Schema $schema): void

$users = $this->connection->createQueryBuilder()->select('id')->from('koi_user')->executeQuery()->fetchAllAssociative();
foreach ($users as $user) {
$id = Uuid::v4()->toRfc4122();
$id = Uuid::v7()->toRfc4122();
$userId = $user['id'];
$displayMode = "'" . DisplayModeEnum::DISPLAY_MODE_GRID . "'";
$sortingDirection = "'" . SortingDirectionEnum::ASCENDING . "'";

$this->addSql("INSERT INTO koi_display_configuration (id, owner_id, display_mode, sorting_direction, created_at) VALUES ('$id', '$userId', $displayMode, $sortingDirection, NOW())");
$this->addSql("UPDATE koi_user SET collections_display_configuration_id = '$id' WHERE id = '$userId'");

$id = Uuid::v4()->toRfc4122();
$id = Uuid::v7()->toRfc4122();
$this->addSql("INSERT INTO koi_display_configuration (id, owner_id, display_mode, sorting_direction, created_at) VALUES ('$id', '$userId', $displayMode, $sortingDirection, NOW())");
$this->addSql("UPDATE koi_user SET albums_display_configuration_id = '$id' WHERE id = '$userId'");

$id = Uuid::v4()->toRfc4122();
$id = Uuid::v7()->toRfc4122();
$this->addSql("INSERT INTO koi_display_configuration (id, owner_id, display_mode, sorting_direction, created_at) VALUES ('$id', '$userId', $displayMode, $sortingDirection, NOW())");
$this->addSql("UPDATE koi_user SET wishlists_display_configuration_id = '$id' WHERE id = '$userId'");
}
Expand Down
2 changes: 1 addition & 1 deletion migrations/Mysql/Version20230519201736.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public function up(Schema $schema): void

$this->addSql('CREATE TABLE koi_configuration (id CHAR(36) NOT NULL, label VARCHAR(255) NOT NULL, value VARCHAR(255) DEFAULT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', updated_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');

$id = Uuid::v4()->toRfc4122();
$id = Uuid::v7()->toRfc4122();
$label = ConfigurationEnum::THUMBNAILS_FORMAT;
$this->addSql("INSERT INTO koi_configuration (id, label, created_at) VALUES ('$id', '$label', NOW())");
}
Expand Down
4 changes: 2 additions & 2 deletions migrations/Mysql/Version20230525100104.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ public function up(Schema $schema): void
$this->addSql('ALTER TABLE koi_configuration CHANGE value value LONGTEXT DEFAULT NULL');
$this->addSql('CREATE UNIQUE INDEX UNIQ_576E96A6EA750E8 ON koi_configuration (label)');

$id = Uuid::v4()->toRfc4122();
$id = Uuid::v7()->toRfc4122();
$label = ConfigurationEnum::CUSTOM_LIGHT_THEME_CSS;
$this->addSql("INSERT INTO koi_configuration (id, label, created_at) VALUES ('$id', '$label', NOW())");

$id = Uuid::v4()->toRfc4122();
$id = Uuid::v7()->toRfc4122();
$label = ConfigurationEnum::CUSTOM_DARK_THEME_CSS;
$this->addSql("INSERT INTO koi_configuration (id, label, created_at) VALUES ('$id', '$label', NOW())");
}
Expand Down
33 changes: 33 additions & 0 deletions migrations/Mysql/Version20240411083658.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace App\Migrations\Mysql;

use App\Enum\ConfigurationEnum;
use Doctrine\DBAL\Platforms\MySQLPlatform;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
use Symfony\Component\Uid\Uuid;

final class Version20240411083658 extends AbstractMigration
{
public function getDescription(): string
{
return '[Mysql] Add enable_metrics to `koi_configuration`';
}

public function up(Schema $schema): void
{
$this->skipIf(!$this->connection->getDatabasePlatform() instanceof MySQLPlatform, 'Migration can only be executed safely on \'mysql\' or \'mariadb\'.');

$id = Uuid::v7()->toRfc4122();
$label = ConfigurationEnum::ENABLE_METRICS;
$this->addSql("INSERT INTO koi_configuration (id, label, created_at) VALUES ('$id', '$label', NOW())");
}

public function down(Schema $schema): void
{
$this->skipIf(true, 'Always move forward.');
}
}
6 changes: 3 additions & 3 deletions migrations/Postgresql/Version20220916154614.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public function up(Schema $schema): void

$collections = $this->connection->createQueryBuilder()->select('id, owner_id, children_title')->from('koi_collection')->executeQuery()->fetchAllAssociative();
foreach ($collections as $collection) {
$id = Uuid::v4()->toRfc4122();
$id = Uuid::v7()->toRfc4122();
$collectionId = $collection['id'];
$ownerId = $collection['owner_id'];
$label = !empty($collection['children_title']) ? "'" . $collection['children_title'] . "'" : 'NULL';
Expand All @@ -55,7 +55,7 @@ public function up(Schema $schema): void

$albums = $this->connection->createQueryBuilder()->select('id, owner_id')->from('koi_album')->executeQuery()->fetchAllAssociative();
foreach ($albums as $album) {
$id = Uuid::v4()->toRfc4122();
$id = Uuid::v7()->toRfc4122();
$albumId = $album['id'];
$ownerId = $album['owner_id'];

Expand All @@ -65,7 +65,7 @@ public function up(Schema $schema): void

$wishlists = $this->connection->createQueryBuilder()->select('id, owner_id')->from('koi_wishlist')->executeQuery()->fetchAllAssociative();
foreach ($wishlists as $wishlist) {
$id = Uuid::v4()->toRfc4122();
$id = Uuid::v7()->toRfc4122();
$wishlistId = $wishlist['id'];
$ownerId = $wishlist['owner_id'];

Expand Down
Loading

0 comments on commit a5642b7

Please sign in to comment.