Skip to content

Commit

Permalink
Merge branch 'main' into add-plex-watchlist-import
Browse files Browse the repository at this point in the history
  • Loading branch information
leepeuker committed Jun 27, 2023
2 parents e30c81f + 55fb364 commit cbdee83
Show file tree
Hide file tree
Showing 14 changed files with 275 additions and 151 deletions.
116 changes: 116 additions & 0 deletions public/js/job-modal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
const jobModal = new bootstrap.Modal('#jobModal')
const jobModalTypeInput = document.getElementById('jobModalType');

async function showJobModal(jobType) {
jobModalTypeInput.value = jobType
setJobModalTitle(jobModalTypeInput.value)

loadJobModal(true)
}

async function loadJobModal(showModal) {
setJobModalLoadingSpinner(true)
document.getElementById('jobModalEmptyMessage').classList.add('d-none')
document.getElementById('jobModalErrorAlert').classList.add('d-none')

if (showModal === true) {
jobModal.show();
}

let jobs = null

try {
jobs = await fetchJobs(jobModalTypeInput.value);
} catch (error) {
document.getElementById('jobModalErrorAlert').classList.remove('d-none')
}

setJobModalLoadingSpinner(false)

if (jobs !== null) {
renderJobModalTable(jobs)
}
}

function setJobModalTitle(jobType) {
let title

switch (jobType) {
case 'trakt_import_ratings':
title = 'Rating imports';
break;
case 'trakt_import_history':
title = 'History imports';
break;
case 'letterboxd_import_ratings':
title = 'Rating imports';
break;
case 'letterboxd_import_history':
title = 'History imports';
break;
default:
throw new Error('Not supported job type: ' + jobType);
}


document.getElementById('jobModalTitle').innerText = title;
}

async function fetchJobs(jobType) {

const response = await fetch('/jobs?type=' + jobType)

if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}

return await response.json()
}

function setJobModalLoadingSpinner(isActive = true) {
if (isActive === true) {
emptyJobModalTable()
document.getElementById('jobModalLoadingSpinner').classList.remove('d-none');
} else {
document.getElementById('jobModalLoadingSpinner').classList.add('d-none');
}
}

async function renderJobModalTable(jobs) {
const table = document.getElementById('jobModalTable');

let tbodyRef = table.getElementsByTagName('tbody')[0];

table.getElementsByTagName('tbody').innerHtml = 'ads'
if (jobs.length === 0) {
document.getElementById('jobModalEmptyMessage').classList.remove('d-none')
} else {
document.getElementById('jobModalEmptyMessage').classList.add('d-none')
}

jobs.forEach((job, index, jobs) => {
let newRow = tbodyRef.insertRow();

const createdAtCell = newRow.insertCell();
createdAtCell.appendChild(document.createTextNode(job.createdAt));

const statusCell = newRow.insertCell();
statusCell.appendChild(document.createTextNode(job.status));

const finishedAtCell = newRow.insertCell();
finishedAtCell.appendChild(document.createTextNode(job.status === 'done' || job.status === 'failed' ? job.updatedAt : '-'));

if (index === jobs.length - 1) {
statusCell.style.borderBottom = '0'
createdAtCell.style.borderBottom = '0'
finishedAtCell.style.borderBottom = '0'
}
});
}

async function emptyJobModalTable() {
const table = document.getElementById('jobModalTable');

let tbodyRef = table.getElementsByTagName('tbody')[0];
tbodyRef.innerHTML = '';
}
5 changes: 5 additions & 0 deletions settings/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@
#############
# Job Queue #
#############
$routeCollector->addRoute(
'GET',
'/jobs',
[\Movary\HttpController\JobController::class, 'getJobs'],
);
$routeCollector->addRoute(
'GET',
'/job-queue/purge-processed',
Expand Down
1 change: 0 additions & 1 deletion src/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,6 @@ public static function createSettingsController(ContainerInterface $container, C
{
return new SettingsController(
$container->get(Twig\Environment::class),
$container->get(JobQueueApi::class),
$container->get(Authentication::class),
$container->get(UserApi::class),
$container->get(MovieApi::class),
Expand Down
17 changes: 17 additions & 0 deletions src/HttpController/JobController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
use Movary\Domain\User\Service\Authentication;
use Movary\JobQueue\JobQueueApi;
use Movary\Service\Letterboxd\Service\LetterboxdCsvValidator;
use Movary\Util\Json;
use Movary\Util\SessionWrapper;
use Movary\ValueObject\Http\Header;
use Movary\ValueObject\Http\Request;
use Movary\ValueObject\Http\Response;
use Movary\ValueObject\Http\StatusCode;
use Movary\ValueObject\JobType;
use RuntimeException;

class JobController
Expand All @@ -23,6 +25,21 @@ public function __construct(
) {
}

public function getJobs(Request $request) : Response
{
if ($this->authenticationService->isUserAuthenticated() === false) {
return Response::createSeeOther('/');
}

$parameters = $request->getGetParameters();

$jobType = JobType::createFromString($parameters['type']);

$jobs = $this->jobQueueApi->find($this->authenticationService->getCurrentUserId(), $jobType);

return Response::createJson(Json::encode($jobs));
}

public function purgeAllJobs() : Response
{
if ($this->authenticationService->isUserAuthenticated() === false) {
Expand Down
3 changes: 0 additions & 3 deletions src/HttpController/SettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ class SettingsController
{
public function __construct(
private readonly Environment $twig,
private readonly JobQueueApi $workerService,
private readonly Authentication $authenticationService,
private readonly UserApi $userApi,
private readonly Movie\MovieApi $movieApi,
Expand Down Expand Up @@ -308,7 +307,6 @@ public function renderLetterboxdPage() : Response
'letterboxdRatingsSyncSuccessful' => $letterboxdRatingsSyncSuccessful,
'letterboxdRatingsImportFileInvalid' => $letterboxdRatingsImportFileInvalid,
'letterboxdDiaryImportFileInvalid' => $letterboxdDiaryImportFileInvalid,
'lastLetterboxdImportJobs' => $this->workerService->findLastLetterboxdImportsForUser($user->getId()),
]),
);
}
Expand Down Expand Up @@ -482,7 +480,6 @@ public function renderTraktPage() : Response
'traktCredentialsUpdated' => $traktCredentialsUpdated,
'traktScheduleHistorySyncSuccessful' => $scheduledTraktHistoryImport,
'traktScheduleRatingsSyncSuccessful' => $scheduledTraktRatingsImport,
'lastTraktImportJobs' => $this->workerService->findLastTraktImportsForUser($user->getId()),
]),
);
}
Expand Down
13 changes: 12 additions & 1 deletion src/JobQueue/JobEntity.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use Movary\ValueObject\JobStatus;
use Movary\ValueObject\JobType;

class JobEntity
class JobEntity implements \JsonSerializable
{
private function __construct(
private readonly int $id,
Expand Down Expand Up @@ -67,4 +67,15 @@ public function getUserId() : ?int
{
return $this->userId;
}

public function jsonSerialize() : array
{
return [
'type' => $this->type,
'status' => $this->getStatus(),
'userId' => $this->getUserId(),
'createdAt' => $this->getCreatedAt(),
'updatedAt' => $this->getUpdatedAt()
];
}
}
33 changes: 33 additions & 0 deletions src/JobQueue/JobEntityList.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php declare(strict_types=1);

namespace Movary\JobQueue;

use Movary\ValueObject\AbstractList;

/**
* @method JobEntity[] getIterator()
* @psalm-suppress ImplementedReturnTypeMismatch
*/
class JobEntityList extends AbstractList
{
public static function create() : self
{
return new self();
}

public static function createFromArray(array $data) : self
{
$list = new self();

foreach ($data as $historyEntry) {
$list->add(JobEntity::createFromArray($historyEntry));
}

return $list;
}

private function add(JobEntity $dto) : void
{
$this->data[] = $dto;
}
}
30 changes: 2 additions & 28 deletions src/JobQueue/JobQueueApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,35 +88,9 @@ public function fetchOldestWaitingJob() : ?JobEntity
return $this->repository->fetchOldestWaitingJob();
}

public function findLastImdbSync() : ?DateTime
public function find(int $userId, JobType $jobType) : ?JobEntityList
{
return $this->repository->findLastDateForJobByType(JobType::createImdbSync());
}

public function findLastLetterboxdImportsForUser(int $userId) : array
{
return $this->repository->findLastLetterboxdImportsForUser($userId);
}

public function findLastTmdbSync() : ?DateTime
{
$lastMovieSync = $this->repository->findLastDateForJobByType(JobType::createTmdbMovieSync());
$lastPersonSync = $this->repository->findLastDateForJobByType(JobType::createTmdbPersonSync());

if ($lastMovieSync === null) {
return $lastPersonSync;
}

if ($lastPersonSync === null) {
return $lastMovieSync;
}

return $lastMovieSync->isAfter($lastPersonSync) ? $lastMovieSync : $lastPersonSync;
}

public function findLastTraktImportsForUser(int $userId) : array
{
return $this->repository->findLastTraktImportsForUser($userId);
return $this->repository->find($userId, $jobType);
}

public function purgeAllJobs() : void
Expand Down
42 changes: 6 additions & 36 deletions src/JobQueue/JobQueueRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,47 +57,17 @@ public function fetchOldestWaitingJob() : ?JobEntity
return JobEntity::createFromArray($data);
}

public function findLastDateForJobByType(JobType $jobType) : ?DateTime
public function find(int $userId, JobType $jobType) : ?JobEntityList
{
$data = $this->dbConnection->fetchOne('SELECT created_at FROM `job_queue` WHERE job_type = ? AND job_status = ? ORDER BY created_at', [$jobType, JobStatus::createDone()]);

if ($data === false) {
return null;
}

return DateTime::createFromString($data);
}

public function findLastLetterboxdImportsForUser(int $userId) : array
{
return $this->dbConnection->fetchAllAssociative(
'SELECT *
FROM `job_queue`
WHERE job_type IN (?, ?) AND user_id = ?
ORDER BY created_at DESC
LIMIT 10',
$data = $this->dbConnection->fetchAllAssociative(
'SELECT * FROM `job_queue` WHERE job_type = ? and user_id = ? ORDER BY `created_at` DESC LIMIT 10',
[
JobType::createLetterboxdImportHistory(),
JobType::createLetterboxdImportRatings(),
$userId,
$jobType,
$userId
],
);
}

public function findLastTraktImportsForUser(int $userId) : array
{
return $this->dbConnection->fetchAllAssociative(
'SELECT *
FROM `job_queue`
WHERE job_type IN (?, ?) AND user_id = ?
ORDER BY created_at DESC
LIMIT 10',
[
JobType::createTraktImportHistory(),
JobType::createTraktImportRatings(),
$userId,
],
);
return JobEntityList::createFromArray($data);
}

public function purgeNotProcessedJobs() : void
Expand Down
7 changes: 6 additions & 1 deletion src/ValueObject/JobStatus.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use RuntimeException;

class JobStatus
class JobStatus implements \JsonSerializable
{
private const STATUS_DONE = 'done';

Expand Down Expand Up @@ -55,4 +55,9 @@ public function __toString() : string
{
return $this->status;
}

public function jsonSerialize() : string
{
return $this->status;
}
}
7 changes: 6 additions & 1 deletion src/ValueObject/JobType.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use RuntimeException;

class JobType
class JobType implements \JsonSerializable
{
private const TYPE_PLEX_IMPORT_WATCHLIST = 'plex_import_watchlist';

Expand Down Expand Up @@ -135,4 +135,9 @@ public function isOfTypeTraktImportRatings() : bool
{
return $this->type === self::TYPE_TRAKT_IMPORT_RATINGS;
}

public function jsonSerialize() : string
{
return $this->type;
}
}
Loading

0 comments on commit cbdee83

Please sign in to comment.