Skip to content

Internal: Add tracking to all resource event - refs #6134 #6245

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

Merged
merged 5 commits into from
Jun 24, 2025
Merged
Show file tree
Hide file tree
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
4 changes: 2 additions & 2 deletions assets/vue/services/linkService.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ export default {
*/
toggleLinkVisibility: async (linkId, visible, cid, sid) => {
const endpoint = `${ENTRYPOINT}links/${linkId}/toggle_visibility?cid=${cid}&sid=${sid}`

return baseService.put(endpoint, { visible })
const response = await axios.put(endpoint, { visible })
return response.data
},

/**
Expand Down
28 changes: 20 additions & 8 deletions assets/vue/views/links/LinksList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ const categoryToDelete = ref(null)
const isLoading = ref(true)

const linkValidationResults = ref({})
const isToggling = ref({})

onMounted(async () => {
isAllowedToEdit.value = await checkIsAllowedToEdit(true, true, true)
Expand Down Expand Up @@ -266,17 +267,28 @@ async function checkLink(id, url) {
}

async function toggleVisibility(link) {
if (isToggling.value[link.iid]) return
isToggling.value = { ...isToggling.value, [link.iid]: true }

try {
const visibility = toggleVisibilityProperty(!link.linkVisible)
let newLink = await linkService.toggleLinkVisibility(link.iid, isVisible(visibility), cid, sid)
notifications.showSuccessNotification(t("Link visibility updated"))
Object.values(categories.value)
.map((c) => c.links)
.flat()
const newVisible = !isVisible(link.linkVisible)
const updatedLink = await linkService.toggleLinkVisibility(link.iid, newVisible, cid, sid)
const newFlagValue = visibilityFromBoolean(updatedLink.linkVisible)

linksWithoutCategory.value
.filter((l) => l.iid === link.iid)
.forEach((l) => (l.linkVisible = visibilityFromBoolean(newLink.linkVisible)))
} catch (error) {
.forEach((l) => (l.linkVisible = newFlagValue))

categories.value
.flatMap((c) => c.links || [])
.filter((l) => l.iid === link.iid)
.forEach((l) => (l.linkVisible = newFlagValue))

notifications.showSuccessNotification(t("Link visibility updated"))
} catch (err) {
notifications.showErrorNotification(t("Could not change visibility of link"))
} finally {
isToggling.value = { ...isToggling.value, [link.iid]: false }
}
}

Expand Down
16 changes: 16 additions & 0 deletions public/main/exercise/exercise.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Chamilo\CoreBundle\Entity\TrackEHotspot;
use Chamilo\CoreBundle\Framework\Container;
use Chamilo\CoreBundle\Repository\ResourceLinkRepository;
use Chamilo\CoreBundle\Repository\TrackEDefaultRepository;
use Chamilo\CourseBundle\Entity\CQuizCategory;
use Chamilo\CourseBundle\Entity\CQuiz;
use Chamilo\CourseBundle\Entity\CQuizRelQuestionCategory;
Expand Down Expand Up @@ -1851,6 +1852,21 @@ public function delete()
GradebookUtils::remove_resource_from_course_gradebook($linkInfo['id']);
}

// Register resource deletion manually because this is a soft delete (active = -1)
// and Doctrine does not trigger postRemove in this case.
/* @var TrackEDefaultRepository $trackRepo */
$trackRepo = Container::$container->get(TrackEDefaultRepository::class);
$resourceNode = $exercise->getResourceNode();
if ($resourceNode) {
$trackRepo->registerResourceEvent(
$resourceNode,
'deletion',
api_get_user_id(),
api_get_course_int_id(),
api_get_session_id()
);
}

return true;
}

Expand Down
63 changes: 50 additions & 13 deletions public/main/forum/forumfunction.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Chamilo\CoreBundle\Entity\Session as SessionEntity;
use Chamilo\CoreBundle\Entity\User;
use Chamilo\CoreBundle\Framework\Container;
use Chamilo\CoreBundle\Repository\TrackEDefaultRepository;
use Chamilo\CourseBundle\Entity\CForum;
use Chamilo\CourseBundle\Entity\CForumAttachment;
use Chamilo\CourseBundle\Entity\CForumCategory;
Expand Down Expand Up @@ -131,7 +132,7 @@ function handleForum($url)
if ('visible' === $action) {
$repo->setVisibilityPublished($resource, $course, $session);
} else {
$repo->setVisibilityPending($resource);
$repo->setVisibilityPending($resource, $course, $session);
}

if ('visible' === $action) {
Expand All @@ -149,6 +150,13 @@ function handleForum($url)
if ($resource) {
$linksRepo->removeByResourceInContext($resource, $course, $session);

// Manually register thread deletion event because the resource is not removed via Doctrine
$trackRepo = Container::$container->get(TrackEDefaultRepository::class);
$node = $resource->getResourceNode();
if ($node) {
$trackRepo->registerResourceEvent($node, 'deletion', api_get_user_id(), api_get_course_int_id(), api_get_session_id());
}

Display::addFlash(
Display::return_message(get_lang('Forum category deleted'), 'confirmation', false)
);
Expand All @@ -160,6 +168,13 @@ function handleForum($url)
if ($resource) {
$linksRepo->removeByResourceInContext($resource, $course, $session);

// Register forum deletion manually as it's not deleted via Doctrine
$trackRepo = Container::$container->get(TrackEDefaultRepository::class);
$node = $resource->getResourceNode();
if ($node) {
$trackRepo->registerResourceEvent($node, 'deletion', api_get_user_id(), api_get_course_int_id(), api_get_session_id());
}

Display::addFlash(Display::return_message(get_lang('Forum deleted'), 'confirmation', false));
}

Expand All @@ -183,6 +198,14 @@ function handleForum($url)
$link_id = $link_info['id'];
GradebookUtils::remove_resource_from_course_gradebook($link_id);
}

// Manually register thread deletion event because the resource is not removed via Doctrine
$trackRepo = Container::$container->get(TrackEDefaultRepository::class);
$node = $resource->getResourceNode();
if ($node) {
$trackRepo->registerResourceEvent($node, 'deletion', api_get_user_id(), api_get_course_int_id(), api_get_session_id());
}

Display::addFlash(Display::return_message(get_lang('Thread deleted'), 'confirmation', false));
}

Expand Down Expand Up @@ -856,22 +879,34 @@ function deletePost(CForumPost $post): void
$em->remove($post);
$em->flush();

$lastPostOfTheTread = getLastPostOfThread($post->getThread()->getIid());
$threadId = $post->getThread()->getIid();
$lastPostOfTheTread = getLastPostOfThread($threadId);

if (!empty($lastPostOfTheTread)) {
// Decreasing the number of replies for this thread and also changing the last post information.
$sql = "UPDATE $table_threads
SET
thread_replies = thread_replies - 1,
thread_last_post = ".$lastPostOfTheTread['iid'].",
thread_date = '".$lastPostOfTheTread['post_date']."'
WHERE iid = ".$post->getThread()->getIid();
// Decreasing the number of replies only if > 0
$threadReplies = Database::fetch_array(Database::query("SELECT thread_replies FROM $table_threads WHERE iid = $threadId"));
$replyCount = (int) $threadReplies['thread_replies'];

if ($replyCount > 0) {
$sql = "UPDATE $table_threads
SET
thread_replies = thread_replies - 1,
thread_last_post = ".$lastPostOfTheTread['iid'].",
thread_date = '".$lastPostOfTheTread['post_date']."'
WHERE iid = $threadId";
} else {
$sql = "UPDATE $table_threads
SET
thread_last_post = ".$lastPostOfTheTread['iid'].",
thread_date = '".$lastPostOfTheTread['post_date']."'
WHERE iid = $threadId";
}

Database::query($sql);
Display::addFlash(Display::return_message(get_lang('Post has been deleted')));
} else {
// We deleted the very last post of the thread, so we need to delete the thread as well.
$sql = "DELETE FROM $table_threads
WHERE iid = ".$post->getThread()->getIid();
$sql = "DELETE FROM $table_threads WHERE iid = $threadId";
Database::query($sql);

Display::addFlash(Display::return_message(get_lang('Thread deleted')));
Expand Down Expand Up @@ -3138,22 +3173,24 @@ function updateThreadInfo($threadId, $lastPostId, $post_date)
Database::query($sql);
}

function approvePost(CForumPost $post, $action)
function approvePost(CForumPost $post, $action): string
{
if ('invisible' === $action) {
$visibility = 0;
$message = 'PostMadeInvisible';
}

if ('visible' === $action) {
$visibility = 1;
handle_mail_cue('post', $post->getIid());
$message = 'PostMadeVisible';
}

$post->setVisible($visibility);
Database::getManager()->persist($post);
Database::getManager()->flush();

Display::addFlash(Display::return_message(get_lang('The visibility has been changed')));
return $message;
}

/**
Expand Down
42 changes: 12 additions & 30 deletions public/main/lp/learnpath.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Chamilo\CoreBundle\Entity\Session as SessionEntity;
use Chamilo\CoreBundle\Event\Events;
use Chamilo\CoreBundle\Event\LearningPathEndedEvent;
use Chamilo\CoreBundle\Repository\TrackEDefaultRepository;
use Chamilo\CoreBundle\ServiceHelper\ThemeHelper;
use Chamilo\CourseBundle\Entity\CLpRelUser;
use Chamilo\CoreBundle\Framework\Container;
Expand Down Expand Up @@ -793,33 +794,6 @@ public function delete($courseInfo = null, $id = null, $delete = 'keep')

$course = api_get_course_entity();
$session = api_get_session_entity();

//$lp_item = Database::get_course_table(TABLE_LP_ITEM);
//$lp_view = Database::get_course_table(TABLE_LP_VIEW);
//$lp_item_view = Database::get_course_table(TABLE_LP_ITEM_VIEW);

// Delete lp item id.
//foreach ($this->items as $lpItemId => $dummy) {
// $sql = "DELETE FROM $lp_item_view
// WHERE lp_item_id = '".$lpItemId."'";
// Database::query($sql);
//}

// Proposed by Christophe (nickname: clefevre)
//$sql = "DELETE FROM $lp_item
// WHERE lp_id = ".$this->lp_id;
//Database::query($sql);

//$sql = "DELETE FROM $lp_view
// WHERE lp_id = ".$this->lp_id;
//Database::query($sql);

//$table = Database::get_course_table(TABLE_LP_REL_USERGROUP);
//$sql = "DELETE FROM $table
// WHERE
// lp_id = {$this->lp_id}";
//Database::query($sql);

$lp = Container::getLpRepository()->find($this->lp_id);

Database::getManager()
Expand All @@ -837,9 +811,17 @@ public function delete($courseInfo = null, $id = null, $delete = 'keep')
GradebookUtils::remove_resource_from_course_gradebook($link_info['id']);
}

//if ('true' === api_get_setting('search_enabled')) {
// delete_all_values_for_item($this->cc, TOOL_LEARNPATH, $this->lp_id);
//}
$trackRepo = Container::$container->get(TrackEDefaultRepository::class);
$resourceNode = $lp->getResourceNode();
if ($resourceNode) {
$trackRepo->registerResourceEvent(
$resourceNode,
'deletion',
api_get_user_id(),
api_get_course_int_id(),
api_get_session_id()
);
}
}

/**
Expand Down
16 changes: 16 additions & 0 deletions src/CoreBundle/Controller/Api/UpdateDocumentFileAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,33 @@

namespace Chamilo\CoreBundle\Controller\Api;

use Chamilo\CoreBundle\Repository\TrackEDefaultRepository;
use Chamilo\CourseBundle\Entity\CDocument;
use Chamilo\CourseBundle\Repository\CDocumentRepository;
use Doctrine\ORM\EntityManager;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\HttpFoundation\Request;

class UpdateDocumentFileAction extends BaseResourceFileAction
{
public function __construct(
private TrackEDefaultRepository $trackRepo,
private Security $security
) {}

public function __invoke(CDocument $document, Request $request, CDocumentRepository $repo, EntityManager $em): CDocument
{
$this->handleUpdateRequest($document, $repo, $request, $em);

$node = $document->getResourceNode();
if ($node) {
$this->trackRepo->registerResourceEvent(
$node,
'edition',
$this->security->getUser()?->getId()
);
}

return $document;
}
}
21 changes: 16 additions & 5 deletions src/CoreBundle/Controller/Api/UpdateVisibilityDocument.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,37 @@

namespace Chamilo\CoreBundle\Controller\Api;

use Chamilo\CoreBundle\Entity\Course;
use Chamilo\CoreBundle\Entity\Session;
use Chamilo\CoreBundle\ServiceHelper\CidReqHelper;
use Chamilo\CourseBundle\Entity\CDocument;
use Chamilo\CourseBundle\Repository\CDocumentRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Doctrine\ORM\EntityManagerInterface;

#[AsController]
class UpdateVisibilityDocument extends AbstractController
{
public function __construct(
private readonly CidReqHelper $cidReqHelper,
private readonly EntityManagerInterface $em,
) {}

public function __invoke(CDocument $document, CDocumentRepository $repo): CDocument
{
$repo->toggleVisibilityPublishedDraft(
$document,
$this->cidReqHelper->getCourseEntity(),
$this->cidReqHelper->getSessionEntity()
);
$course = $this->cidReqHelper->getCourseEntity();
$session = $this->cidReqHelper->getSessionEntity();

if ($course) {
$course = $this->em->getRepository(Course::class)->find($course->getId());
}

if ($session) {
$session = $this->em->getRepository(Session::class)->find($session->getId());
}

$repo->toggleVisibilityPublishedDraft($document, $course, $session);

return $document;
}
Expand Down
4 changes: 2 additions & 2 deletions src/CoreBundle/Controller/Api/UpdateVisibilityLink.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ public function __invoke(CLink $link, CLinkRepository $repo): CLink
{
$repo->toggleVisibilityPublishedDraft(
$link,
$this->cidReqHelper->getCourseEntity(),
$this->cidReqHelper->getSessionEntity()
$this->cidReqHelper->getDoctrineCourseEntity(),
$this->cidReqHelper->getDoctrineSessionEntity()
);
$link->toggleVisibility();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ public function __invoke(CLinkCategory $linkCategory, CLinkCategoryRepository $r
{
$repo->toggleVisibilityPublishedDraft(
$linkCategory,
$this->cidReqHelper->getCourseEntity(),
$this->cidReqHelper->getSessionEntity()
$this->cidReqHelper->getDoctrineCourseEntity(),
$this->cidReqHelper->getDoctrineSessionEntity()
);
$linkCategory->toggleVisibility();

Expand Down
Loading
Loading