Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Internal: Fix HTML resource links for migrated OFAJ portal" - refs BT#22199 #6017

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 157 additions & 0 deletions src/CoreBundle/Migrations/Schema/V200/Version20250106151300.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
<?php

declare(strict_types=1);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a single space around assignment operators


/* For licensing terms, see /license.txt */

namespace Chamilo\CoreBundle\Migrations\Schema\V200;

use Chamilo\CoreBundle\Migrations\AbstractMigrationChamilo;
use Chamilo\CoreBundle\Repository\Node\CourseRepository;
use Chamilo\CoreBundle\Repository\ResourceNodeRepository;
use Chamilo\CourseBundle\Repository\CDocumentRepository;
use Doctrine\DBAL\Schema\Schema;
use Exception;

final class Version20250106151300 extends AbstractMigrationChamilo
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing class doc comment

{
public function getDescription(): string
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing function doc comment

{
return 'Fix incorrect resource links in HTML files already migrated.';
}

public function up(Schema $schema): void
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing function doc comment

{
$this->entityManager->clear();
$this->processHtmlFiles();
}

private function processHtmlFiles(): void
{
// Select only HTML files that are linked to resource links
$sql = "
SELECT rl.resource_node_id, rl.c_id
FROM resource_link rl
JOIN c_document cd ON rl.resource_node_id = cd.resource_node_id
WHERE cd.filetype = 'file'
";
$result = $this->connection->executeQuery($sql);
$items = $result->fetchAllAssociative();

$documentRepo = $this->container->get(CDocumentRepository::class);
$resourceNodeRepo = $this->container->get(ResourceNodeRepository::class);

foreach ($items as $item) {
try {
// Find the document by resource node ID
$document = $documentRepo->findOneBy(['resourceNode' => $item['resource_node_id']]);
if (!$document) {
error_log("Document not found for resource node ID {$item['resource_node_id']}");
continue;
}

// Retrieve the resource node
$resourceNode = $document->getResourceNode();
if (!$resourceNode || !$resourceNode->hasResourceFile()) {
error_log("Resource node or file not found for document ID {$document->getIid()}");
continue;
}

// Get the first resource file and validate MIME type
$resourceFile = $resourceNode->getResourceFiles()->first();
if (!$resourceFile || 'text/html' !== $resourceFile->getMimeType()) {
error_log("Invalid or missing HTML file for document ID {$document->getIid()}");
continue;
}

// Fetch content of the HTML file
$content = $resourceNodeRepo->getResourceNodeFileContent($resourceNode);
if (!is_string($content) || '' === trim($content)) {
error_log("Empty or invalid content for resource node ID {$item['resource_node_id']}");
continue;
}

// Update the content with fixed links
$updatedContent = $this->fixHtmlLinks($content, $document->getIid(), $item['resource_node_id'], $item['c_id']);
if ($content !== $updatedContent) {
// Save the updated content back
$documentRepo->updateResourceFileContent($document, $updatedContent);
$documentRepo->update($document);
error_log("Updated content for document ID {$document->getIid()}");
} else {
error_log("No changes required for document ID {$document->getIid()}");
}
} catch (Exception $e) {
// Log errors for debugging purposes
error_log("Error processing document with resource node ID {$item['resource_node_id']}: " . $e->getMessage());
}
}
}

private function fixHtmlLinks(string $content, int $documentId, int $resourceNodeId, int $currentCourseId): string
{
// Define the pattern to find resource links
$pattern = '/\/r\/document\/files\/([a-f0-9\-]+)\/view/';

return preg_replace_callback($pattern, function ($matches) use ($documentId, $resourceNodeId, $currentCourseId) {
$uuid = $matches[1];

// Normalize UUID by removing dashes and converting to binary
$cleanUuid = strtoupper(str_replace('-', '', $uuid));
$uuidBinary = pack('H*', $cleanUuid);

// Check the resource link for the given UUID and fetch title
$query = '
SELECT rl.resource_node_id, rl.c_id, rn.title
FROM resource_link rl
JOIN resource_node rn ON rl.resource_node_id = rn.id
WHERE rn.uuid = UNHEX(:uuid)
';
$resourceData = $this->connection->fetchAssociative($query, ['uuid' => $cleanUuid]);

if ($resourceData && $resourceData['c_id'] === $currentCourseId) {
// Log debugging information
error_log("Document ID $documentId, Resource Node $resourceNodeId: Valid resource found for UUID $uuid in the correct course $currentCourseId");

// Return the corrected link with original UUID format
return "/r/document/files/$uuid/view";
} elseif ($resourceData) {
// If the course ID doesn't match, find the correct file in the current course
error_log("Document ID $documentId, Resource Node $resourceNodeId: UUID $uuid does not belong to course $currentCourseId. Searching for the correct file...");

$documentRepo = $this->container->get(CDocumentRepository::class);
$courseRepo = $this->container->get(CourseRepository::class);
$title = $resourceData['title'];

// Load the Course object
$course = $courseRepo->find($currentCourseId);
if (!$course) {
error_log("Document ID $documentId, Resource Node $resourceNodeId: Course with ID $currentCourseId not found.");
return $matches[0]; // Return original link if course not found
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing blank line before return statement

}

// Search for a document in the current course by title
$correctDocument = $documentRepo->findResourceByTitleInCourse($title, $course);

if ($correctDocument) {
$newUrl = $documentRepo->getResourceFileUrl($correctDocument);
error_log("Document ID $documentId: Correct URL found: $newUrl");

return $newUrl;
} else {
error_log("Document ID $documentId, Resource Node $resourceNodeId: No document found for title $title in course $currentCourseId.");
}
}

// Log missing resource data
error_log("Document ID $documentId, Resource Node $resourceNodeId: Resource link for UUID $uuid not found.");
return $matches[0]; // Return original link if no match found
}, $content);
}


public function down(Schema $schema): void
{
$this->abortIf(true, 'This migration cannot be rolled back.');
}
}
Loading