Skip to content

Commit

Permalink
FilesMetadata
Browse files Browse the repository at this point in the history
Signed-off-by: Maxence Lange <[email protected]>
  • Loading branch information
ArtificialOwl committed Oct 3, 2023
1 parent 8f30f97 commit ea22334
Show file tree
Hide file tree
Showing 11 changed files with 482 additions and 0 deletions.
44 changes: 44 additions & 0 deletions core/Command/FilesMetadata/Get.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

namespace OC\Core\Command\FilesMetadata;

use OCP\FilesMetadata\IFilesMetadataManager;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class Get extends Command {
public function __construct(
private IFilesMetadataManager $filesMetadataManager,
) {
parent::__construct();
}

protected function configure() {
$this->setName('metadata:get')
->setDescription('update and returns up-to-date metadata')
->addArgument(
'fileId',
InputArgument::REQUIRED,
'id of the file document'
)
->addOption(
'background',
'',
InputOption::VALUE_NONE,
'emulate background jobs env'
);
}

protected function execute(InputInterface $input, OutputInterface $output): int {
$fileId = (int) $input->getArgument('fileId');
$metadata = $this->filesMetadataManager->refreshMetadata($fileId);
$output->writeln(json_encode($metadata, JSON_PRETTY_PRINT));

return 0;
}
}
2 changes: 2 additions & 0 deletions core/register_command.php
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,8 @@
$application->add(new OC\Core\Command\Security\RemoveCertificate(\OC::$server->getCertificateManager()));
$application->add(\OC::$server->get(\OC\Core\Command\Security\BruteforceAttempts::class));
$application->add(\OC::$server->get(\OC\Core\Command\Security\BruteforceResetAttempts::class));

$application->add(\OCP\Server::get(\OC\Core\Command\FilesMetadata\Get::class));
} else {
$application->add(\OC::$server->get(\OC\Core\Command\Maintenance\Install::class));
}
57 changes: 57 additions & 0 deletions lib/private/FilesMetadata/Event/FilesMetadataEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

declare(strict_types=1);

namespace OC\FilesMetadata\Event;

use OCP\EventDispatcher\Event;
use OCP\FilesMetadata\IFilesMetadata;

class FilesMetadataEvent extends Event {
private bool $runAsBackgroundJob = false;

public function __construct(
private int $fileId,
private IFilesMetadata $metadata,
) {
parent::__construct();
}

/**
* If an app prefer to update metadata on a background job, instead of
* live process, just call this method.
* A new event will be generated on next cron tick
*
* @return void
*/
public function requestBackgroundJob() {
$this->runAsBackgroundJob = true;
}

/**
* return fileId
*
* @return int
*/
public function getFileId(): int {
return $this->fileId;
}

/**
* return Metadata
*
* @return IFilesMetadata
*/
public function getMetadata(): IFilesMetadata {
return $this->metadata;
}

/**
* return true if any app that catch this event requested a re-run as background job
*
* @return bool
*/
public function isRunAsBackgroundJobRequested(): bool {
return $this->runAsBackgroundJob;
}
}
103 changes: 103 additions & 0 deletions lib/private/FilesMetadata/FilesMetadataManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?php

declare(strict_types=1);

namespace OC\FilesMetadata;

use OC\FilesMetadata\Event\FilesMetadataEvent;
use OC\FilesMetadata\Model\FilesMetadata;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\FilesMetadata\Exceptions\FilesMetadataNotFoundException;
use OCP\FilesMetadata\IFilesMetadata;
use OCP\FilesMetadata\IFilesMetadataManager;
use OCP\FilesMetadata\IFilesMetadataQueryHelper;

class FilesMetadataManager implements IFilesMetadataManager {

public function __construct(
private IEventDispatcher $eventDispatcher,
private FilesMetadataQueryHelper $filesMetadataQueryHelper,
) {
}

public function refreshMetadata(
int $fileId,
bool $asBackgroundJob = false,
bool $fromScratch = false
): IFilesMetadata {
$metadata = null;
if (!$fromScratch) {
try {
$metadata = $this->getMetadataFromDatabase($fileId);
} catch (FilesMetadataNotFoundException $e) {
}
}

if (is_null($metadata)) {
$metadata = new FilesMetadata($fileId);
}

$event = new FilesMetadataEvent($fileId, $metadata);
$this->eventDispatcher->dispatchTyped($event);
$this->saveMetadata($event->getMetadata());

return $metadata;
}

/**
* @param int $fileId
* @param bool $createIfNeeded
*
* @return IFilesMetadata
* @throws FilesMetadataNotFoundException
*/
public function getMetadata(int $fileId, bool $createIfNeeded = false): IFilesMetadata {
try {
return $this->getMetadataFromDatabase($fileId);
} catch (FilesMetadataNotFoundException $e) {
if ($createIfNeeded) {
return $this->refreshMetadata($fileId, true);
}

throw $e;
}
}

/**
* @param int $fileId
*
* @return IFilesMetadata
* @throws FilesMetadataNotFoundException
*/
public function getMetadataFromDatabase(int $fileId): IFilesMetadata {
$metadata = new FilesMetadata($fileId);
throw new FilesMetadataNotFoundException();

$json = '[]'; // get json from database;
// if entry exist in database.
$metadata->import($json);

return $metadata;
}


public function saveMetadata(IFilesMetadata $filesMetadata): void {
if ($filesMetadata->getFileId() === 0) {
return;
}

// database thing ...
// try to update first, if no update, insert as new

// remove indexes from metadata_index that are not in the list of indexes anymore.
foreach ($filesMetadata->listIndexes() as $index) {
// foreach index, update entry in table metadata_index
// if no update, insert as new row
// !! we might want to get the type of the value to be indexed at one point !!
}
}

public function getQueryHelper(): IFilesMetadataQueryHelper {
return $this->filesMetadataQueryHelper;
}
}
53 changes: 53 additions & 0 deletions lib/private/FilesMetadata/FilesMetadataQueryHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

declare(strict_types=1);

namespace OC\FilesMetadata;

use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\FilesMetadata\IFilesMetadata;
use OCP\FilesMetadata\IFilesMetadataQueryHelper;

class FilesMetadataQueryHelper implements IFilesMetadataQueryHelper {

public function __construct() {
}

public function linkedToFileId(
IQueryBuilder $queryBuilder,
string $fileTableAlias,
string $fileIdField
): void {
// leftJoin metadata in fileid=fileid
// add json to the select in specific templated alias
}

public function limitToSingleMetadata(
IQueryBuilder $queryBuilder,
string $fileTableAlias,
string $fileIdField,
string $metadataKey,
string $metadataValue,
bool $selectMetadata = false
): void {
// right join in fileId=fileId
// add json to the select in specific templated alias if $selectMetadata
// andWhere with metadataKey and metadataValue
}

/**
* @param array $data
*
* @return IFilesMetadata
*/
public function extractMetadata(array $data): IFilesMetadata {
$json = '[]'; // from $data, in an alias field generated by limitToSingleMetadata()
$fileId = 1; // from $data, in an alias field generated by limitToSingleMetadata()

$metadata = new FilesMetadata($fileId);
$metadata->import($json);

return $metadata;
}

}
106 changes: 106 additions & 0 deletions lib/private/FilesMetadata/Model/FilesMetadata.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php

declare(strict_types=1);

namespace OC\FilesMetadata\Model;

use OCP\FilesMetadata\IFilesMetadata;

class FilesMetadata implements IFilesMetadata {

private const INDEXES_KEY = '_indexes';

private int $fileId;
private array $metadata;
private bool $updated = false;

public function __construct(int $fileId = 0, array $metadata = []) {
$this->fileId = $fileId;
$this->metadata = $metadata;
}

public function getFileId(): int {
return $this->fileId;
}

public function import(string $json): IFilesMetadata {
$this->metadata = json_decode($json, true, JSON_THROW_ON_ERROR);
$this->updated = false;
return $this;
}

public function updated(): bool {
return $this->updated;
}

public function listIndexes(): array {
return $this->getArray(self::INDEXES_KEY, []);
}

public function addIndex(string $index): IFilesMetadata {
if (!array_key_exists('_indexes', $this->metadata)) {
$this->metadata[self::INDEXES_KEY] = [];
}

$this->metadata[self::INDEXES_KEY][] = $index;
return $this;
}

public function removeIndex(string $index): IFilesMetadata {
if (!array_key_exists(self::INDEXES_KEY, $this->metadata)) {
return $this;
}

$this->metadata[self::INDEXES_KEY] = array_diff($this->metadata[self::INDEXES_KEY], [$index]);
return $this;
}

public function get(string $key, string $default): string {
return $this->metadata[$key] ?? $default;
}

public function getInt(string $key, int $default): int {
return $this->metadata[$key] ?? $default;
}

public function getFloat(string $key, float $default): float {
return $this->metadata[$key] ?? $default;
}

public function getBool(string $key, bool $default): bool {
return $this->metadata[$key] ?? $default;
}

public function getArray(string $key, array $default): array {
return $this->metadata[$key] ?? $default;
}

public function set(string $key, string $value): IFilesMetadata {
$this->metadata[$key] = $value;
return $this;
}

public function setInt(string $key, int $value): IFilesMetadata {
$this->metadata[$key] = $value;
return $this;
}

public function setFloat(string $key, float $value): IFilesMetadata {
$this->metadata[$key] = $value;
return $this;
}

public function setBool(string $key, bool $value): IFilesMetadata {
$this->metadata[$key] = $value;
return $this;
}

public function setArray(string $key, array $value): IFilesMetadata {
$this->metadata[$key] = $value;
return $this;
}

public function jsonSerialize() {
return $this->metadata;
}
}
Loading

0 comments on commit ea22334

Please sign in to comment.