User: Create "fallback" user role and account to attach orphan content to - refs #5221

Author: @christianbeeznest
pull/5254/head
christianbeeznest 8 months ago committed by GitHub
parent d578ca929a
commit a531dfc35e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      public/main/admin/user_list.php
  2. 7
      public/main/inc/lib/api.lib.php
  3. 184
      public/main/inc/lib/usermanager.lib.php
  4. 17
      public/main/install/install.lib.php
  5. 4
      src/CoreBundle/Entity/ResourceNode.php
  6. 3
      src/CoreBundle/Entity/TicketAssignedLog.php
  7. 5
      src/CoreBundle/Entity/TicketCategoryRelUser.php
  8. 2
      src/CoreBundle/Entity/TrackEAttempt.php
  9. 2
      src/CoreBundle/Entity/TrackEExercise.php
  10. 1
      src/CoreBundle/Entity/User.php
  11. 56
      src/CoreBundle/Migrations/Schema/V200/Version20240310160200.php
  12. 187
      src/CoreBundle/Repository/Node/UserRepository.php
  13. 18
      src/CourseBundle/Entity/CAttendanceResultComment.php
  14. 2
      src/CourseBundle/Entity/CForumPost.php

@ -388,6 +388,7 @@ function prepare_user_sql_query(bool $getCount, bool $showDeletedUsers = false):
} else {
$sql .= !str_contains($sql, 'WHERE') ? ' WHERE u.active <> '.USER_SOFT_DELETED : ' AND u.active <> '.USER_SOFT_DELETED;
}
$sql .= ' AND u.status <> '.ROLE_FALLBACK;
return $sql;
}

@ -51,6 +51,13 @@ define('ANONYMOUS', 6);
/** global status of a user: low security, necessary for inserting data from
* the teacher through HTMLPurifier */
define('COURSEMANAGERLOWSECURITY', 10);
/**
* Global status for the fallback user.
* This special status is used for a system user that acts as a placeholder
* or fallback for content ownership when regular users are deleted.
* This ensures data integrity and prevents orphaned content within the system.
*/
define('ROLE_FALLBACK', 99);
// Soft user status
define('PLATFORM_ADMIN', 11);
define('SESSION_COURSE_COACH', 12);

@ -657,178 +657,30 @@ class UserManager
/** @var User $user */
$user = $repository->find($user_id);
$repository->deleteUser($user, $destroy);
if (!$destroy) {
return true;
}
$usergroup_rel_user = Database::get_main_table(TABLE_USERGROUP_REL_USER);
$table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
$table_course = Database::get_main_table(TABLE_MAIN_COURSE);
$table_session = Database::get_main_table(TABLE_MAIN_SESSION);
$table_admin = Database::get_main_table(TABLE_MAIN_ADMIN);
$table_session_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
$table_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
$table_group = Database::get_course_table(TABLE_GROUP_USER);
$table_work = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
$userInfo = api_get_user_info($user_id);
// Unsubscribe the user from all groups in all his courses
$sql = "SELECT c.id
FROM $table_course c
INNER JOIN $table_course_user cu
ON (c.id = cu.c_id)
WHERE
cu.user_id = '".$user_id."' AND
relation_type<>".COURSE_RELATION_TYPE_RRHH."
";
$res = Database::query($sql);
while ($course = Database::fetch_object($res)) {
$sql = "DELETE FROM $table_group
WHERE c_id = {$course->id} AND user_id = $user_id";
Database::query($sql);
}
// Unsubscribe user from usergroup_rel_user
$sql = "DELETE FROM $usergroup_rel_user WHERE user_id = '".$user_id."'";
Database::query($sql);
// Unsubscribe user from all courses
$sql = "DELETE FROM $table_course_user WHERE user_id = '".$user_id."'";
Database::query($sql);
// Unsubscribe user from all courses in sessions
$sql = "DELETE FROM $table_session_course_user WHERE user_id = '".$user_id."'";
Database::query($sql);
// If the user was added as a general coach then set the current admin as general coach see BT#
$currentUserId = api_get_user_id();
$sql = "UPDATE session_rel_user
SET user_id = $currentUserId
WHERE user_id = $user_id AND relation_type = ".SessionEntity::GENERAL_COACH;
Database::query($sql);
$sql = "UPDATE session_rel_user
SET user_id = $currentUserId
WHERE user_id = $user_id AND relation_type = ".SessionEntity::SESSION_ADMIN;
Database::query($sql);
// Unsubscribe user from all sessions
$sql = "DELETE FROM $table_session_user
WHERE user_id = '".$user_id."'";
Database::query($sql);
if ('true' === api_get_setting('admin.plugin_redirection_enabled')) {
RedirectionPlugin::deleteUserRedirection($user_id);
}
// Delete user from the admin table
$sql = "DELETE FROM $table_admin WHERE user_id = '".$user_id."'";
Database::query($sql);
// Delete the personal agenda-items from this user
$agenda_table = Database::get_main_table(TABLE_PERSONAL_AGENDA);
$sql = "DELETE FROM $agenda_table WHERE user = '".$user_id."'";
Database::query($sql);
$gradebook_results_table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_RESULT);
$sql = 'DELETE FROM '.$gradebook_results_table.' WHERE user_id = '.$user_id;
Database::query($sql);
$extraFieldValue = new ExtraFieldValue('user');
$extraFieldValue->deleteValuesByItem($user_id);
UrlManager::deleteUserFromAllUrls($user_id);
//UrlManager::deleteUserFromAllUrls($user_id);
if ('true' === api_get_setting('allow_social_tool')) {
$userGroup = new UserGroupModel();
//Delete user from portal groups
$group_list = $userGroup->get_groups_by_user($user_id);
if (!empty($group_list)) {
foreach ($group_list as $group_id => $data) {
$userGroup->delete_user_rel_group($user_id, $group_id);
}
}
}
// Removing survey invitation
SurveyManager::delete_all_survey_invitations_by_user($user_id);
// Skills
$em = Database::getManager();
$criteria = ['user' => $user_id];
$skills = $em->getRepository(SkillRelUser::class)->findBy($criteria);
if ($skills) {
/** @var SkillRelUser $skill */
foreach ($skills as $skill) {
$comments = $skill->getComments();
if ($comments) {
/** @var SkillRelUserComment $comment */
foreach ($comments as $comment) {
$em->remove($comment);
}
}
$em->remove($skill);
}
}
// ExtraFieldSavedSearch
$criteria = ['user' => $user_id];
$searchList = $em->getRepository(ExtraFieldSavedSearch::class)->findBy($criteria);
if ($searchList) {
foreach ($searchList as $search) {
$em->remove($search);
}
if (!$user) {
return false;
}
$connection = Database::getManager()->getConnection();
$schemaManager = $connection->createSchemaManager();
$tableExists = $schemaManager->tablesExist(['plugin_bbb_room']);
if ($tableExists) {
// Delete user from database
$sql = "DELETE FROM plugin_bbb_room WHERE participant_id = $user_id";
Database::query($sql);
}
$repository->deleteUser($user, $destroy);
// Delete user/ticket relationships :(
$tableExists = $schemaManager->tablesExist(['ticket_ticket']);
if ($tableExists) {
TicketManager::deleteUserFromTicketSystem($user_id);
}
if ($destroy) {
Event::addEvent(
LOG_USER_DELETE,
LOG_USER_ID,
$user_id,
api_get_utc_datetime(),
api_get_user_id()
);
$tableExists = $schemaManager->tablesExist(['c_lp_category_user']);
if ($tableExists) {
$sql = "DELETE FROM c_lp_category_user WHERE user_id = $user_id";
Database::query($sql);
Event::addEvent(
LOG_USER_DELETE,
LOG_USER_OBJECT,
api_get_user_info($user_id),
api_get_utc_datetime(),
api_get_user_id()
);
}
$app_plugin = new AppPlugin();
$app_plugin->performActionsWhenDeletingItem('user', $user_id);
// Add event to system log
$authorId = api_get_user_id();
Event::addEvent(
LOG_USER_DELETE,
LOG_USER_ID,
$user_id,
api_get_utc_datetime(),
$authorId
);
Event::addEvent(
LOG_USER_DELETE,
LOG_USER_OBJECT,
$userInfo,
api_get_utc_datetime(),
$authorId
);
return true;
}

@ -1534,6 +1534,23 @@ function finishInstallationWithContainer(
['english_name = ?' => $languageForm]
);
$fallbackUser = new User();
$fallbackUser
->setUsername('fallback_user')
->setEmail('fallback@example.com')
->setPlainPassword($passForm)
->setStatus(ROLE_FALLBACK)
->setLastname('Fallback')
->setFirstname('User')
->setCreatorId(1)
->setOfficialCode('FALLBACK')
->setAuthSource(PLATFORM_AUTH_SOURCE)
->setPhone('0000000000')
->setLocale($languageForm)
->setTimezone($timezone)
->setActive(USER_SOFT_DELETED);
$repo->updateUser($fallbackUser);
// Install settings
installSettings(
$institutionForm,

@ -116,7 +116,7 @@ class ResourceNode implements Stringable
* ResourceFile available file for this node.
*/
#[Groups(['resource_node:read', 'resource_node:write', 'document:read', 'document:write', 'message:read'])]
#[ORM\OneToOne(inversedBy: 'resourceNode', targetEntity: ResourceFile::class, orphanRemoval: true)]
#[ORM\OneToOne(inversedBy: 'resourceNode', targetEntity: ResourceFile::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\JoinColumn(name: 'resource_file_id', referencedColumnName: 'id', onDelete: 'CASCADE')]
protected ?ResourceFile $resourceFile = null;
@ -129,7 +129,7 @@ class ResourceNode implements Stringable
#[Groups(['resource_node:read'])]
#[MaxDepth(1)]
#[ORM\JoinColumn(name: 'parent_id', onDelete: 'CASCADE')]
#[ORM\ManyToOne(targetEntity: self::class, inversedBy: 'children')]
#[ORM\ManyToOne(targetEntity: self::class, cascade: ['persist'], inversedBy: 'children')]
#[Gedmo\TreeParent]
protected ?ResourceNode $parent = null;

@ -6,6 +6,7 @@ declare(strict_types=1);
namespace Chamilo\CoreBundle\Entity;
use Chamilo\CoreBundle\Traits\UserTrait;
use DateTime;
use Doctrine\ORM\Mapping as ORM;
@ -13,6 +14,8 @@ use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
class TicketAssignedLog
{
use UserTrait;
#[ORM\Column(name: 'id', type: 'integer')]
#[ORM\Id]
#[ORM\GeneratedValue]

@ -6,6 +6,7 @@ declare(strict_types=1);
namespace Chamilo\CoreBundle\Entity;
use Chamilo\CoreBundle\Traits\UserTrait;
use Doctrine\ORM\Mapping as ORM;
/**
@ -15,6 +16,8 @@ use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
class TicketCategoryRelUser
{
use UserTrait;
#[ORM\Column(name: 'id', type: 'integer')]
#[ORM\Id]
#[ORM\GeneratedValue]
@ -26,5 +29,5 @@ class TicketCategoryRelUser
#[ORM\ManyToOne(targetEntity: User::class)]
#[ORM\JoinColumn(name: 'user_id', referencedColumnName: 'id', onDelete: 'CASCADE')]
protected TicketCategory $user;
protected User $user;
}

@ -57,7 +57,7 @@ class TrackEAttempt
protected ?int $id = null;
#[Assert\NotNull]
#[ORM\ManyToOne(targetEntity: TrackEExercise::class, inversedBy: 'attempts')]
#[ORM\ManyToOne(targetEntity: TrackEExercise::class, cascade: ['persist'], inversedBy: 'attempts')]
#[ORM\JoinColumn(name: 'exe_id', referencedColumnName: 'exe_id', nullable: false, onDelete: 'CASCADE')]
protected TrackEExercise $trackExercise;

@ -83,7 +83,7 @@ class TrackEExercise
#[Assert\NotNull]
#[Groups(['track_e_exercise:read'])]
#[ORM\ManyToOne(targetEntity: User::class)]
#[ORM\ManyToOne(targetEntity: User::class, cascade: ['persist'])]
#[ORM\JoinColumn(name: 'exe_user_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')]
protected User $user;

@ -86,6 +86,7 @@ class User implements UserInterface, EquatableInterface, ResourceInterface, Reso
public const USERNAME_MAX_LENGTH = 100;
public const ROLE_DEFAULT = 'ROLE_USER';
public const ANONYMOUS = 6;
public const ROLE_FALLBACK = 99;
/*public const COURSE_MANAGER = 1;
public const TEACHER = 1;
public const SESSION_ADMIN = 3;

@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
/* For licensing terms, see /license.txt */
namespace Chamilo\CoreBundle\Migrations\Schema\V200;
use Chamilo\CoreBundle\Entity\User;
use Chamilo\CoreBundle\Migrations\AbstractMigrationChamilo;
use Chamilo\CoreBundle\Repository\Node\UserRepository;
use Doctrine\DBAL\Schema\Schema;
class Version20240310160200 extends AbstractMigrationChamilo
{
public function getDescription(): string
{
return 'Adds a fallback user to the user table.';
}
public function up(Schema $schema): void
{
$container = $this->getContainer();
$doctrine = $container->get('doctrine');
$em = $doctrine->getManager();
/* @var UserRepository $repo*/
$repo = $container->get(UserRepository::class);
$plainPassword = 'fallback_user';
$encodedPassword = password_hash($plainPassword, PASSWORD_DEFAULT);
$fallbackUser = new User();
$fallbackUser
->setUsername('fallback_user')
->setEmail('fallback@example.com')
->setPassword($encodedPassword)
->setCreatorId(1)
->setStatus(User::ROLE_FALLBACK)
->setLastname('Fallback')
->setFirstname('User')
->setOfficialCode('FALLBACK')
->setAuthSource('platform')
->setPhone('0000000000')
->setLocale('en')
->setActive(User::SOFT_DELETED)
->setTimezone('UTC');
$em->flush();
error_log($fallbackUser->getFullname());
$repo->updateUser($fallbackUser);
}
}

@ -139,33 +139,192 @@ class UserRepository extends ResourceRepository implements PasswordUpgraderInter
public function deleteUser(User $user, bool $destroy = false): void
{
$em = $this->getEntityManager();
$em->getConnection()->beginTransaction();
if ($destroy) {
$type = $user->getResourceNode()->getResourceType();
$rootUser = $this->getRootUser();
try {
if ($destroy) {
$fallbackUser = $this->getFallbackUser();
$criteria = Criteria::create()->where(Criteria::expr()->eq('resourceType', $type));
$userNodeCreatedList = $user->getResourceNodes()->matching($criteria);
if ($fallbackUser) {
$this->reassignUserResourcesToFallback($user, $fallbackUser);
$em->flush();
}
foreach ($userNodeCreatedList as $userCreated) {
$userCreated->setCreator($rootUser);
foreach ($user->getGroups() as $group) {
$user->removeGroup($group);
}
if ($user->getResourceNode()) {
$em->remove($user->getResourceNode());
}
$em->remove($user);
} else {
$user->setActive(User::SOFT_DELETED);
$em->persist($user);
}
$em->remove($user->getResourceNode());
$em->flush();
$em->getConnection()->commit();
} catch (\Exception $e) {
$em->getConnection()->rollBack();
throw $e;
}
}
protected function reassignUserResourcesToFallback(User $userToDelete, User $fallbackUser): void
{
$em = $this->getEntityManager();
$userResourceNodes = $em->getRepository(ResourceNode::class)->findBy(['creator' => $userToDelete]);
foreach ($userResourceNodes as $resourceNode) {
$resourceNode->setCreator($fallbackUser);
$em->persist($resourceNode);
}
foreach ($user->getGroups() as $group) {
$user->removeGroup($group);
$childResourceNodes = $em->getRepository(ResourceNode::class)->findBy(['parent' => $userToDelete->getResourceNode()]);
foreach ($childResourceNodes as $childNode) {
$fallbackUserResourceNode = $fallbackUser->getResourceNode();
if ($fallbackUserResourceNode) {
$childNode->setParent($fallbackUserResourceNode);
} else {
$childNode->setParent(null);
}
$em->persist($childNode);
}
$em->remove($user);
} else {
$user->setActive(User::SOFT_DELETED);
$em->persist($user);
$relations = [
['bundle' => 'CoreBundle', 'entity' => 'AccessUrlRelUser', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'Admin', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'AgendaEventInvitee', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'AttemptFeedback', 'field' => 'user', 'type' => 'object', 'action' => 'convert'],
['bundle' => 'CoreBundle', 'entity' => 'Chat', 'field' => 'toUser', 'type' => 'int', 'action' => 'convert'],
['bundle' => 'CoreBundle', 'entity' => 'ChatVideo', 'field' => 'toUser', 'type' => 'int', 'action' => 'convert'],
['bundle' => 'CoreBundle', 'entity' => 'CourseRelUser', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'CourseRelUserCatalogue', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'CourseRequest', 'field' => 'user', 'type' => 'object', 'action' => 'convert'],
['bundle' => 'CourseBundle', 'entity' => 'CAttendanceResult', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CourseBundle', 'entity' => 'CAttendanceResultComment', 'field' => 'userId', 'type' => 'int', 'action' => 'convert'],
['bundle' => 'CourseBundle', 'entity' => 'CAttendanceSheet', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CourseBundle', 'entity' => 'CAttendanceSheetLog', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CourseBundle', 'entity' => 'CChatConnected', 'field' => 'userId', 'type' => 'int', 'action' => 'delete'],
['bundle' => 'CourseBundle', 'entity' => 'CDropboxCategory', 'field' => 'userId', 'type' => 'int', 'action' => 'convert'],
['bundle' => 'CourseBundle', 'entity' => 'CDropboxFeedback', 'field' => 'authorUserId', 'type' => 'int', 'action' => 'convert'],
['bundle' => 'CourseBundle', 'entity' => 'CDropboxPerson', 'field' => 'userId', 'type' => 'int', 'action' => 'convert'],
['bundle' => 'CourseBundle', 'entity' => 'CDropboxPost', 'field' => 'destUserId', 'type' => 'int', 'action' => 'convert'],
['bundle' => 'CourseBundle', 'entity' => 'CForumMailcue', 'field' => 'userId', 'type' => 'int', 'action' => 'delete'],
['bundle' => 'CourseBundle', 'entity' => 'CForumNotification', 'field' => 'userId', 'type' => 'int', 'action' => 'delete'],
['bundle' => 'CourseBundle', 'entity' => 'CForumPost', 'field' => 'user', 'type' => 'object', 'action' => 'convert'],
['bundle' => 'CourseBundle', 'entity' => 'CForumThread', 'field' => 'user', 'type' => 'object', 'action' => 'convert'],
['bundle' => 'CourseBundle', 'entity' => 'CForumThreadQualify', 'field' => 'user', 'type' => 'object', 'action' => 'convert'],
['bundle' => 'CourseBundle', 'entity' => 'CForumThreadQualifyLog', 'field' => 'userId', 'type' => 'int', 'action' => 'convert'],
['bundle' => 'CourseBundle', 'entity' => 'CGroupRelTutor', 'field' => 'user', 'type' => 'object', 'action' => 'convert'],
['bundle' => 'CourseBundle', 'entity' => 'CGroupRelUser', 'field' => 'user', 'type' => 'object', 'action' => 'convert'],
['bundle' => 'CourseBundle', 'entity' => 'CLpCategoryRelUser', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CourseBundle', 'entity' => 'CLpRelUser', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CourseBundle', 'entity' => 'CLpView', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CourseBundle', 'entity' => 'CStudentPublicationComment', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CourseBundle', 'entity' => 'CStudentPublicationRelUser', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CourseBundle', 'entity' => 'CSurveyInvitation', 'field' => 'user', 'type' => 'object', 'action' => 'convert'],
['bundle' => 'CourseBundle', 'entity' => 'CWiki', 'field' => 'userId', 'type' => 'int', 'action' => 'convert'],
['bundle' => 'CourseBundle', 'entity' => 'CWikiMailcue', 'field' => 'userId', 'type' => 'int', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'ExtraFieldSavedSearch', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'GradebookCategory', 'field' => 'user', 'type' => 'object', 'action' => 'convert'],
['bundle' => 'CoreBundle', 'entity' => 'GradebookCertificate', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'GradebookComment', 'field' => 'user', 'type' => 'object', 'action' => 'convert'],
['bundle' => 'CoreBundle', 'entity' => 'GradebookEvaluation', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'GradebookLink', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'GradebookLinkevalLog', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'GradebookResult', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'GradebookResultLog', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'GradebookScoreLog', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'Message', 'field' => 'sender', 'type' => 'object', 'action' => 'convert'],
['bundle' => 'CoreBundle', 'entity' => 'MessageFeedback', 'field' => 'user', 'type' => 'object', 'action' => 'convert'],
['bundle' => 'CoreBundle', 'entity' => 'MessageRelUser', 'field' => 'receiver', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'MessageTag', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'Notification', 'field' => 'destUserId', 'type' => 'int', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'PageCategory', 'field' => 'creator', 'type' => 'object', 'action' => 'convert'],
['bundle' => 'CoreBundle', 'entity' => 'PersonalAgenda', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'Portfolio', 'field' => 'user', 'type' => 'object', 'action' => 'convert'],
['bundle' => 'CoreBundle', 'entity' => 'PortfolioCategory', 'field' => 'user', 'type' => 'object', 'action' => 'convert'],
['bundle' => 'CoreBundle', 'entity' => 'PortfolioComment', 'field' => 'author', 'type' => 'object', 'action' => 'convert'],
['bundle' => 'CoreBundle', 'entity' => 'ResourceComment', 'field' => 'author', 'type' => 'object', 'action' => 'convert'],
['bundle' => 'CoreBundle', 'entity' => 'SequenceValue', 'field' => 'user', 'type' => 'object', 'action' => 'convert'],
['bundle' => 'CoreBundle', 'entity' => 'SessionRelCourseRelUser', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'SessionRelUser', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'SkillRelItemRelUser', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'SkillRelUser', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'SkillRelUserComment', 'field' => 'feedbackGiver', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'SocialPost', 'field' => 'sender', 'type' => 'object', 'action' => 'convert'],
['bundle' => 'CoreBundle', 'entity' => 'SocialPost', 'field' => 'userReceiver', 'type' => 'object', 'action' => 'convert'],
['bundle' => 'CoreBundle', 'entity' => 'SocialPostAttachment', 'field' => 'insertUserId', 'type' => 'int', 'action' => 'convert'],
['bundle' => 'CoreBundle', 'entity' => 'SocialPostFeedback', 'field' => 'user', 'type' => 'object', 'action' => 'convert'],
['bundle' => 'CoreBundle', 'entity' => 'Templates', 'field' => 'user', 'type' => 'object', 'action' => 'convert'],
['bundle' => 'CoreBundle', 'entity' => 'TicketAssignedLog', 'field' => 'user', 'type' => 'object', 'action' => 'convert'],
['bundle' => 'CoreBundle', 'entity' => 'TicketCategory', 'field' => 'insertUserId', 'type' => 'int', 'action' => 'convert'],
['bundle' => 'CoreBundle', 'entity' => 'TicketCategoryRelUser', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'TicketMessage', 'field' => 'insertUserId', 'type' => 'int', 'action' => 'convert'],
['bundle' => 'CoreBundle', 'entity' => 'TicketMessageAttachment', 'field' => 'lastEditUserId', 'type' => 'int', 'action' => 'convert'],
['bundle' => 'CoreBundle', 'entity' => 'TicketPriority', 'field' => 'insertUserId', 'type' => 'int', 'action' => 'convert'],
['bundle' => 'CoreBundle', 'entity' => 'TicketProject', 'field' => 'insertUserId', 'type' => 'int', 'action' => 'convert'],
['bundle' => 'CoreBundle', 'entity' => 'TicketProject', 'field' => 'lastEditUserId', 'type' => 'int', 'action' => 'convert'],
['bundle' => 'CoreBundle', 'entity' => 'TrackEAccess', 'field' => 'accessUserId', 'type' => 'int', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'TrackEAccessComplete', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'TrackEAttempt', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'TrackECourseAccess', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'TrackEDefault', 'field' => 'defaultUserId', 'type' => 'int', 'action' => 'convert'],
['bundle' => 'CoreBundle', 'entity' => 'TrackEDownloads', 'field' => 'downUserId', 'type' => 'int', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'TrackEExercise', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'TrackEExerciseConfirmation', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'TrackEHotpotatoes', 'field' => 'exeUserId', 'type' => 'int', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'TrackEHotspot', 'field' => 'hotspotUserId', 'type' => 'int', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'TrackELastaccess', 'field' => 'accessUserId', 'type' => 'int', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'TrackELinks', 'field' => 'linksUserId', 'type' => 'int', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'TrackELogin', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'TrackEOnline', 'field' => 'loginUserId', 'type' => 'int', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'TrackEUploads', 'field' => 'uploadUserId', 'type' => 'int', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'UsergroupRelUser', 'field' => 'user', 'type' => 'object', 'action' => 'convert'],
['bundle' => 'CoreBundle', 'entity' => 'UserRelTag', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
['bundle' => 'CoreBundle', 'entity' => 'UserRelUser', 'field' => 'user', 'type' => 'object', 'action' => 'delete'],
];
foreach ($relations as $relation) {
$entityClass = 'Chamilo\\' . $relation['bundle'] . '\\Entity\\' . $relation['entity'];
$repository = $em->getRepository($entityClass);
$records = $repository->findBy([$relation['field'] => $userToDelete]);
foreach ($records as $record) {
$setter = 'set' . ucfirst($relation['field']);
if ($relation['action'] === 'delete') {
$em->remove($record);
} elseif (method_exists($record, $setter)) {
$valueToSet = $relation['type'] === 'object' ? $fallbackUser : $fallbackUser->getId();
$record->$setter($valueToSet);
if (method_exists($record, 'getResourceFile') && $record->getResourceFile()) {
$resourceFile = $record->getResourceFile();
if (!$em->contains($resourceFile)) {
$em->persist($resourceFile);
}
}
$em->persist($record);
}
}
}
$em->flush();
}
public function getFallbackUser(): ?User
{
$fallbackUser = $this->findOneBy(['status' => User::ROLE_FALLBACK], ['id' => 'ASC']);
if (!$fallbackUser) {
throw new \Exception("User not found.");
}
return $fallbackUser;
}
public function addUserToResourceNode(int $userId, int $creatorId): ResourceNode
{
/** @var User $user */

@ -8,20 +8,10 @@ namespace Chamilo\CourseBundle\Entity;
use DateTime;
use Doctrine\ORM\Mapping as ORM;
/**
* CAttendanceResultComment.
*
* @ORM\Table(
* name="c_attendance_result_comment",
* indexes={
*
* @ORM\Index(name="attendance_sheet_id", columns={"attendance_sheet_id"}),
* @ORM\Index(name="user_id", columns={"user_id"})
* }
* )
*
* @ORM\Entity
*/
#[ORM\Entity]
#[ORM\Table(name: "c_attendance_result_comment")]
#[ORM\Index(columns: ["attendance_sheet_id"], name: "attendance_sheet_id")]
#[ORM\Index(columns: ["user_id"], name: "user_id")]
class CAttendanceResultComment
{
#[ORM\Column(name: 'iid', type: 'integer')]

@ -134,7 +134,7 @@ class CForumPost extends AbstractResource implements ResourceInterface, Stringab
return $this;
}
public function getThread(): CForumThread
public function getThread(): ?CForumThread
{
return $this->thread;
}

Loading…
Cancel
Save