diff --git a/assets/css/app.scss b/assets/css/app.scss index f3e5dde6b8..9139441c3d 100644 --- a/assets/css/app.scss +++ b/assets/css/app.scss @@ -742,6 +742,54 @@ form .field { } } +.files-info-page { + .form-control { + @apply w-48 p-1 border border-gray-300 rounded; + } + + .btn-primary { + @apply bg-primary text-primary-button-text p-1 rounded; + } + + .btn-primary:hover { + @apply bg-secondary-hover; + } + + .modal { + @apply hidden fixed z-10 left-0 top-0 w-full h-full overflow-auto bg-black bg-opacity-50 pt-16; + } + + .modal-content { + @apply bg-white m-auto p-5 border border-gray-300 w-1/3; + } + + .close-button { + @apply text-fontdisabled float-right text-2xl font-bold; + } + + .close-button:hover, + .close-button:focus { + @apply text-black no-underline cursor-pointer; + } + + .pagination { + @apply flex justify-center my-5; + } + + .pagination a, + .pagination span { + @apply mx-1 px-4 py-2 text-primary border border-gray-25; + } + + .pagination a:hover { + @apply bg-gray-15; + } + + .pagination span { + @apply bg-primary text-white border-primary; + } +} + //@import 'primevue-md-light-indigo/theme.css'; //@import '~primevue/resources/primevue.min.css'; //@import '~primeflex/primeflex.css'; diff --git a/src/CoreBundle/Controller/Admin/AdminController.php b/src/CoreBundle/Controller/Admin/AdminController.php index af73560622..d5360063a7 100644 --- a/src/CoreBundle/Controller/Admin/AdminController.php +++ b/src/CoreBundle/Controller/Admin/AdminController.php @@ -7,18 +7,27 @@ declare(strict_types=1); namespace Chamilo\CoreBundle\Controller\Admin; use Chamilo\CoreBundle\Controller\BaseController; +use Chamilo\CoreBundle\Entity\ResourceFile; +use Chamilo\CoreBundle\Repository\ResourceNodeRepository; use Chamilo\CoreBundle\ServiceHelper\AccessUrlHelper; use Chamilo\CoreBundle\Settings\SettingsManager; +use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Attribute\Route; +use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Security\Http\Attribute\IsGranted; +use Vich\UploaderBundle\Storage\StorageInterface; #[Route('/admin')] class AdminController extends BaseController { + private const ITEMS_PER_PAGE = 50; + public function __construct( - private readonly AccessUrlHelper $accessUrlHelper, + private EntityManagerInterface $entityManager, + private ResourceNodeRepository $resourceNodeRepository, + private StorageInterface $storage, + private AccessUrlHelper $accessUrlHelper ) {} #[IsGranted('ROLE_ADMIN')] @@ -38,4 +47,78 @@ class AdminController extends BaseController return new Response('', Response::HTTP_NO_CONTENT); } + + #[IsGranted('ROLE_ADMIN')] + #[Route('/files_info', name: 'admin_files_info', methods: ['GET'])] + public function listFilesInfo(Request $request): Response + { + $page = $request->query->getInt('page', 1); + $search = $request->query->get('search', ''); + $offset = ($page - 1) * self::ITEMS_PER_PAGE; + + $queryBuilder = $this->entityManager->getRepository(ResourceFile::class)->createQueryBuilder('rf') + ->leftJoin('rf.resourceNode', 'rn') + ->leftJoin('rn.resourceLinks', 'rl') + ->leftJoin('rl.course', 'c') + ->leftJoin('rl.user', 'u') + ->addSelect('rn', 'rl', 'c', 'u'); + + if ($search) { + $queryBuilder->where('rf.title LIKE :search') + ->orWhere('rf.originalName LIKE :search') + ->orWhere('c.title LIKE :search') + ->orWhere('u.username LIKE :search') + ->orWhere('rn.uuid LIKE :search') + ->setParameter('search', '%' . $search . '%'); + } + + $queryBuilder->orderBy('rf.id', 'DESC') + ->setFirstResult($offset) + ->setMaxResults(self::ITEMS_PER_PAGE); + + $files = $queryBuilder->getQuery()->getResult(); + + $totalItemsQuery = $this->entityManager->getRepository(ResourceFile::class) + ->createQueryBuilder('rf') + ->leftJoin('rf.resourceNode', 'rn') + ->leftJoin('rn.resourceLinks', 'rl') + ->leftJoin('rl.course', 'c') + ->leftJoin('rl.user', 'u') + ->select('COUNT(rf.id)'); + + if ($search) { + $totalItemsQuery->where('rf.title LIKE :search') + ->orWhere('rf.originalName LIKE :search') + ->orWhere('c.title LIKE :search') + ->orWhere('u.username LIKE :search') + ->orWhere('rn.uuid LIKE :search') + ->setParameter('search', '%' . $search . '%'); + } + + $totalItems = $totalItemsQuery->getQuery()->getSingleScalarResult(); + $totalPages = ceil($totalItems / self::ITEMS_PER_PAGE); + + $fileUrls = []; + $filePaths = []; + foreach ($files as $file) { + $resourceNode = $file->getResourceNode(); + if ($resourceNode) { + $fileUrls[$file->getId()] = $this->resourceNodeRepository->getResourceFileUrl($resourceNode); + $creator = $resourceNode->getCreator(); + } else { + $fileUrls[$file->getId()] = null; + $creator = null; + } + $filePaths[$file->getId()] = $this->resourceNodeRepository->getFilename($file); + } + + return $this->render('@ChamiloCore/Admin/files_info.html.twig', [ + 'files' => $files, + 'fileUrls' => $fileUrls, + 'filePaths' => $filePaths, + 'totalPages' => $totalPages, + 'currentPage' => $page, + 'search' => $search, + ]); + } } diff --git a/src/CoreBundle/Controller/Admin/IndexBlocksController.php b/src/CoreBundle/Controller/Admin/IndexBlocksController.php index ddb85383d7..6b914f91da 100644 --- a/src/CoreBundle/Controller/Admin/IndexBlocksController.php +++ b/src/CoreBundle/Controller/Admin/IndexBlocksController.php @@ -566,6 +566,12 @@ class IndexBlocksController extends BaseController 'label' => $this->translator->trans('Colors'), ]; + $items[] = [ + 'class' => 'item-file-info', + 'url' => '/admin/files_info', + 'label' => $this->translator->trans('File info'), + ]; + return $items; } diff --git a/src/CoreBundle/Resources/views/Admin/files_info.html.twig b/src/CoreBundle/Resources/views/Admin/files_info.html.twig new file mode 100644 index 0000000000..0e6ba2de22 --- /dev/null +++ b/src/CoreBundle/Resources/views/Admin/files_info.html.twig @@ -0,0 +1,152 @@ +{% extends "@ChamiloCore/Layout/layout_one_col.html.twig" %} + +{% block content %} +
| {{ 'Title'|trans }} | +{{ 'Original Name'|trans }} | +{{ 'Course'|trans }} | +{{ 'User'|trans }} | +{{ 'Actions'|trans }} | +
|---|---|---|---|---|
| {{ file.title }} | +{{ file.originalName }} | ++ {% if file.resourceNode and file.resourceNode.resourceLinks|length > 0 %} + {{ file.resourceNode.resourceLinks|first.course.title ?? 'N/A' }} + {% else %} + {{ 'N/A'|trans }} + {% endif %} + | ++ {% if file.resourceNode and file.resourceNode.resourceLinks|length > 0 %} + {{ file.resourceNode.resourceLinks|first.user.username ?? 'N/A' }} + {% elseif file.resourceNode and file.resourceNode.creator %} + {{ file.resourceNode.creator.username ?? 'N/A' }} + {% else %} + {{ 'N/A'|trans }} + {% endif %} + | ++ + {{ 'View'|trans }} + + | +