diff --git a/assets/css/app.scss b/assets/css/app.scss index 394756bed9..190c948d92 100644 --- a/assets/css/app.scss +++ b/assets/css/app.scss @@ -708,6 +708,54 @@ form .field { background-color: #dc3545; } +.permissions-table { + width: 100%; + border-collapse: collapse; + th, td { + border: 1px solid #ccc; + padding: 8px; + text-align: center; + } + th { + background-color: #f9f9f9; + } + tr:nth-child(even) { + background-color: #f2f2f2; + } + tr:hover { + background-color: #e9e9e9; + } + th, td { + border: 1px solid #ddd; + padding: 8px; + } + th { + padding-top: 12px; + padding-bottom: 12px; + text-align: center; + background-color: #999; + color: white; + } + td { + padding: 12px; + } + input[type="checkbox"] { + transform: scale(1.2); + } + .save-button { + background-color: #4CAF50; + color: white; + padding: 10px 20px; + margin: 20px 0; + border: none; + cursor: pointer; + text-align: center; + } + .save-button:hover { + background-color: #45a049; + } +} + //@import 'primevue-md-light-indigo/theme.css'; //@import '~primevue/resources/primevue.min.css'; //@import '~primeflex/primeflex.css'; diff --git a/public/main/inc/lib/api.lib.php b/public/main/inc/lib/api.lib.php index 1813d97349..f9d17ba102 100644 --- a/public/main/inc/lib/api.lib.php +++ b/public/main/inc/lib/api.lib.php @@ -11,6 +11,7 @@ use Chamilo\CoreBundle\Entity\User; use Chamilo\CoreBundle\Entity\UserCourseCategory; use Chamilo\CoreBundle\Exception\NotAllowedException; use Chamilo\CoreBundle\Framework\Container; +use Chamilo\CoreBundle\Service\PermissionService; use Chamilo\CoreBundle\ServiceHelper\MailHelper; use Chamilo\CoreBundle\ServiceHelper\ThemeHelper; use Chamilo\CourseBundle\Entity\CGroup; @@ -7473,3 +7474,17 @@ function api_protect_webservices() exit; } } + +/** + * Checks if a set of roles have a specific permission. + * + * @param string $permissionSlug The slug of the permission to check. + * @param array $roles An array of role codes to check against. + * @return bool True if any of the roles have the permission, false otherwise. + */ +function api_get_permission(string $permissionSlug, array $roles): bool +{ + $permissionService = Container::$container->get(PermissionService::class); + + return $permissionService->hasPermission($permissionSlug, $roles); +} diff --git a/src/CoreBundle/Controller/PermissionController.php b/src/CoreBundle/Controller/PermissionController.php new file mode 100644 index 0000000000..b8e5ee9371 --- /dev/null +++ b/src/CoreBundle/Controller/PermissionController.php @@ -0,0 +1,103 @@ +Permission check result: ' . ($hasPermission ? 'true' : 'false') . ''); + } + + #[IsGranted('ROLE_ADMIN')] + #[Route('/permissions', name: 'permissions')] + public function index( + PermissionRepository $permissionRepo, + PermissionRelRoleRepository $permissionRelRoleRepo, + Request $request, + EntityManagerInterface $em + ): Response { + $permissions = $permissionRepo->findAll(); + $roles = ['ROLE_INVITEE', 'ROLE_STUDENT', 'ROLE_TEACHER', 'ROLE_ADMIN', 'ROLE_SUPER_ADMIN', 'ROLE_GLOBAL_ADMIN', 'ROLE_RRHH', 'ROLE_QUESTION_MANAGER', 'ROLE_SESSION_MANAGER', 'ROLE_STUDENT_BOSS']; + + if ($request->isMethod('POST')) { + $data = $request->request->all('permissions'); + foreach ($permissions as $permission) { + foreach ($roles as $role) { + $checkboxValue = isset($data[$permission->getSlug()][$role]); + error_log('Processing role: ' . $role . ' with value: ' . ($checkboxValue ? 'true' : 'false')); + $permRelRole = $permissionRelRoleRepo->findOneBy(['permission' => $permission, 'roleCode' => $role]); + + if ($checkboxValue) { + if (!$permRelRole) { + $permRelRole = new PermissionRelRole(); + $permRelRole->setPermission($permission); + $permRelRole->setRoleCode($role); + } + $permRelRole->setChangeable(true); + $permRelRole->setUpdatedAt(new \DateTime()); + $em->persist($permRelRole); + error_log('Persisting PermissionRelRole for permission: ' . $permission->getSlug() . ' and role: ' . $role); + } else { + if ($permRelRole) { + $em->remove($permRelRole); + error_log('Removing PermissionRelRole for permission: ' . $permission->getSlug() . ' and role: ' . $role); + } + } + } + } + $em->flush(); + error_log('Flush complete'); + + return $this->redirectToRoute('permissions'); + } + + $forms = []; + foreach ($permissions as $permission) { + $defaultData = []; + foreach ($roles as $role) { + $permRelRole = $permissionRelRoleRepo->findOneBy(['permission' => $permission, 'roleCode' => $role]); + $defaultData[$role] = $permRelRole ? $permRelRole->isChangeable() : false; + } + + $form = $this->createForm(PermissionType::class, $defaultData, ['roles' => $roles]); + $forms[$permission->getSlug()] = $form->createView(); + } + + return $this->render('@ChamiloCore/Permission/index.html.twig', [ + 'permissions' => $permissions, + 'forms' => $forms, + 'roles' => $roles + ]); + } +} diff --git a/src/CoreBundle/DataFixtures/PermissionFixtures.php b/src/CoreBundle/DataFixtures/PermissionFixtures.php new file mode 100644 index 0000000000..976f52adc2 --- /dev/null +++ b/src/CoreBundle/DataFixtures/PermissionFixtures.php @@ -0,0 +1,262 @@ +getRepository(Permission::class)->findOneBy(['slug' => $permData['slug']]); + if ($existingPermission) { + continue; + } + + $permission = new Permission(); + $permission->setTitle($permData['title']); + $permission->setSlug($permData['slug']); + $permission->setDescription($permData['description']); + $manager->persist($permission); + + $manager->flush(); + + foreach ($roles as $roleName => $roleCode) { + if (in_array($roleCode, $permissionsMapping[$permData['slug']])) { + $permRelRole = new PermissionRelRole(); + $permRelRole->setPermission($permission); + $permRelRole->setRoleCode($roleName); + $permRelRole->setChangeable(true); + $permRelRole->setUpdatedAt(new \DateTime()); + $manager->persist($permRelRole); + } + } + } + + $manager->flush(); + } + + public static function getPermissions(): array + { + return [ + ['title' => 'View Analytics', 'slug' => 'analytics:view', 'description' => 'View analytics data'], + ['title' => 'View Assigned Analytics', 'slug' => 'analytics:viewassigned', 'description' => 'View results of users assigned to me'], + ['title' => 'View All Analytics', 'slug' => 'analytics:viewall', 'description' => 'View results of all users'], + ['title' => 'Create Assignment', 'slug' => 'assignment:create', 'description' => 'Create assignments'], + ['title' => 'Delete Assignment', 'slug' => 'assignment:delete', 'description' => 'Delete assignments'], + ['title' => 'Edit Assignment', 'slug' => 'assignment:edit', 'description' => 'Edit assignments'], + ['title' => 'Grade Assignment', 'slug' => 'assignment:grade', 'description' => 'Grade assignments'], + ['title' => 'Submit Assignment', 'slug' => 'assignment:submit', 'description' => 'Submit assignments'], + ['title' => 'View Assignment', 'slug' => 'assignment:view', 'description' => 'View assignments'], + ['title' => 'Backup', 'slug' => 'backup:backup', 'description' => 'Backup'], + ['title' => 'Copy Backup', 'slug' => 'backup:copy', 'description' => 'Copy backup'], + ['title' => 'Restore Backup', 'slug' => 'backup:restore', 'description' => 'Restore backup'], + ['title' => 'Configure Badge Criteria', 'slug' => 'badge:configurecriteria', 'description' => 'Configure badge criteria'], + ['title' => 'Create Badge', 'slug' => 'badge:create', 'description' => 'Create badges'], + ['title' => 'Edit Badge', 'slug' => 'badge:edit', 'description' => 'Edit badges'], + ['title' => 'Delete Badge', 'slug' => 'badge:delete', 'description' => 'Delete badges'], + ['title' => 'View Badge', 'slug' => 'badge:view', 'description' => 'View badges'], + ['title' => 'Create Calendar Event', 'slug' => 'calendar:create', 'description' => 'Create calendar events'], + ['title' => 'Edit Calendar Event', 'slug' => 'calendar:edit', 'description' => 'Edit calendar events'], + ['title' => 'Delete Calendar Event', 'slug' => 'calendar:delete', 'description' => 'Delete calendar events'], + ['title' => 'View Courses Catalogue', 'slug' => 'catalogue:view', 'description' => 'View courses catalogue'], + ['title' => 'Create Certificate Template', 'slug' => 'certificate:create', 'description' => 'Create certificate templates'], + ['title' => 'Delete Certificate Template', 'slug' => 'certificate:delete', 'description' => 'Delete certificate templates'], + ['title' => 'Edit Certificate Template', 'slug' => 'certificate:edit', 'description' => 'Edit certificate templates'], + ['title' => 'Generate Certificate', 'slug' => 'certificate:generate', 'description' => 'Generate certificates'], + ['title' => 'Generate All Certificates', 'slug' => 'certificate:generateall', 'description' => 'Generate all certificates in a gradebook'], + ['title' => 'View All Certificates', 'slug' => 'certificate:viewall', 'description' => 'View all instances of one certificate issued to all users'], + ['title' => 'Assign Course to Class', 'slug' => 'class:assigncourse', 'description' => 'Assign a course to a class'], + ['title' => 'Assign Session to Class', 'slug' => 'class:assignsession', 'description' => 'Assign a session to a class'], + ['title' => 'Assign User to Class', 'slug' => 'class:assignuser', 'description' => 'Assign a user to a class'], + ['title' => 'Create Class', 'slug' => 'class:create', 'description' => 'Manage global classes of users'], + ['title' => 'Delete Class', 'slug' => 'class:delete', 'description' => 'Delete classes'], + ['title' => 'Edit Class', 'slug' => 'class:edit', 'description' => 'Edit classes'], + ['title' => 'View Class', 'slug' => 'class:view', 'description' => 'View classes'], + ['title' => 'Create CMS Page', 'slug' => 'cms:create', 'description' => 'Create CMS pages'], + ['title' => 'Delete CMS Page', 'slug' => 'cms:delete', 'description' => 'Delete CMS pages'], + ['title' => 'Edit CMS Page', 'slug' => 'cms:edit', 'description' => 'Edit CMS pages'], + ['title' => 'Create Course Space', 'slug' => 'course:create', 'description' => 'Create course spaces'], + ['title' => 'Delete Course Space', 'slug' => 'course:delete', 'description' => 'Delete course spaces'], + ['title' => 'Download Course Content', 'slug' => 'course:downloadcoursecontent', 'description' => 'Download all course content'], + ['title' => 'Edit Own Course Properties', 'slug' => 'course:edit', 'description' => 'Edit own course\'s properties'], + ['title' => 'Edit All Course Properties', 'slug' => 'course:editall', 'description' => 'Edit all course\'s properties'], + ['title' => 'Manage Plugins', 'slug' => 'plugin:manage', 'description' => 'Enable/disable/configure plugins'], + ['title' => 'Create Quiz', 'slug' => 'quiz:create', 'description' => 'Create quizzes'], + ['title' => 'Delete Quiz', 'slug' => 'quiz:delete', 'description' => 'Delete quizzes'], + ['title' => 'Edit Quiz', 'slug' => 'quiz:edit', 'description' => 'Edit quizzes'], + ['title' => 'Grade Quiz', 'slug' => 'quiz:grade', 'description' => 'Grade quizzes'], + ['title' => 'View Live Quiz Results', 'slug' => 'quiz:viewliveresults', 'description' => 'View live quiz results'], + ['title' => 'Manage Question Bank', 'slug' => 'quiz:managequestionbank', 'description' => 'Manage question bank'], + ['title' => 'Create Role', 'slug' => 'role:create', 'description' => 'Create roles'], + ['title' => 'Manage Role Permissions', 'slug' => 'role:managepermissions', 'description' => 'Assign or remove permissions from roles'], + ['title' => 'Create Session', 'slug' => 'session:create', 'description' => 'Create sessions'], + ['title' => 'Delete Session', 'slug' => 'session:delete', 'description' => 'Delete sessions'], + ['title' => 'Edit Own Session Properties', 'slug' => 'session:edit', 'description' => 'Edit own session\'s properties'], + ['title' => 'Edit All Session Properties', 'slug' => 'session:editall', 'description' => 'Edit all session\'s properties'], + ['title' => 'Assign Course to Session', 'slug' => 'session:assigncourse', 'description' => 'Assign a course to a session'], + ['title' => 'Edit Site Settings', 'slug' => 'site:editsettings', 'description' => 'Manage settings of the platform'], + ['title' => 'Access Site Maintenance', 'slug' => 'site:maintenanceaccess', 'description' => 'Access site maintenance'], + ['title' => 'Manage Course Competency', 'slug' => 'skill:coursecompetencymanage', 'description' => 'Assign skills through course gradebooks'], + ['title' => 'Review User Competency', 'slug' => 'skill:usercompetencyreview', 'description' => 'Add comments on other user\'s acquired skills'], + ['title' => 'Assign Skill', 'slug' => 'skill:assign', 'description' => 'Assign a skill to a user'], + ['title' => 'Create Skill', 'slug' => 'skill:create', 'description' => 'Create skills'], + ['title' => 'Delete Skill', 'slug' => 'skill:delete', 'description' => 'Delete skills'], + ['title' => 'Edit Skill', 'slug' => 'skill:edit', 'description' => 'Edit skills'], + ['title' => 'View Skill', 'slug' => 'skill:view', 'description' => 'View all skills acquired by users in my context'], + ['title' => 'View All Skills', 'slug' => 'skill:viewall', 'description' => 'View all skills acquired by users of the platform'], + ['title' => 'Create Survey', 'slug' => 'survey:create', 'description' => 'Add a survey (global or inside own course)'], + ['title' => 'Delete Survey', 'slug' => 'survey:delete', 'description' => 'Delete surveys'], + ['title' => 'Edit Survey', 'slug' => 'survey:edit', 'description' => 'Edit surveys'], + ['title' => 'Submit Survey', 'slug' => 'survey:submit', 'description' => 'Submit surveys'], + ['title' => 'View Survey Results', 'slug' => 'survey:viewresults', 'description' => 'View survey results'], + ['title' => 'Comment on Ticket', 'slug' => 'ticket:comment', 'description' => 'Comment on tickets'], + ['title' => 'Manage Tickets', 'slug' => 'ticket:manage', 'description' => 'Manage the tickets system'], + ['title' => 'Report Ticket', 'slug' => 'ticket:report', 'description' => 'Report tickets'], + ['title' => 'See Ticket Issues', 'slug' => 'ticket:seeissues', 'description' => 'See issue details for issues where they are involved'], + ['title' => 'View All Ticket Issues', 'slug' => 'ticket:viewallissues', 'description' => 'View all issues'], + ['title' => 'Edit Tool Visibility', 'slug' => 'tool:editvisibility', 'description' => 'Allow setting the visibility of a tool in a course'], + ['title' => 'Manage URL', 'slug' => 'url:manage', 'description' => 'Manage Multi-URL configuration'], + ['title' => 'Assign Classes to URL', 'slug' => 'url:assignclass', 'description' => 'Assign classes to URL'], + ['title' => 'Assign Courses to URL', 'slug' => 'url:assigncourse', 'description' => 'Assign courses to URL'], + ['title' => 'Assign Users to URL', 'slug' => 'url:assignuser', 'description' => 'Assign users to URL'], + ['title' => 'Assign User to Class', 'slug' => 'user:assignclass', 'description' => 'Assign a user to a class'], + ['title' => 'Assign User to Course', 'slug' => 'user:assigncourse', 'description' => 'Assign a user to a course'], + ['title' => 'Assign User to Session', 'slug' => 'user:assignsession', 'description' => 'Assign a user to a session'], + ['title' => 'Create User', 'slug' => 'user:create', 'description' => 'Create users'], + ['title' => 'Delete User', 'slug' => 'user:delete', 'description' => 'Delete users'], + ['title' => 'Edit User', 'slug' => 'user:edit', 'description' => 'Edit users'], + ['title' => 'Edit User Role', 'slug' => 'user:editrole', 'description' => 'Edit user roles'], + ['title' => 'Login As User', 'slug' => 'user:loginas', 'description' => 'Login as another user'], + ]; + } + + public static function getRoles(): array + { + return [ + 'ROLE_INVITEE' => 'INV', + 'ROLE_STUDENT' => 'STU', + 'ROLE_TEACHER' => 'TEA', + 'ROLE_ADMIN' => 'ADM', + 'ROLE_SUPER_ADMIN' => 'SUA', + 'ROLE_GLOBAL_ADMIN' => 'GLO', + 'ROLE_RRHH' => 'HRM', + 'ROLE_QUESTION_MANAGER' => 'QBM', + 'ROLE_SESSION_MANAGER' => 'SSM', + 'ROLE_STUDENT_BOSS' => 'STB', + ]; + } + + public static function getPermissionsMapping(): array + { + return [ + 'analytics:view' => ['INV', 'STU', 'TEA', 'ADM', 'SUA', 'GLO', 'HRM', 'QBM', 'SSM', 'STB'], + 'analytics:viewassigned' => ['TEA', 'ADM', 'SUA', 'GLO', 'HRM', 'SSM', 'STB'], + 'analytics:viewall' => ['ADM', 'SUA', 'GLO', 'SSM', 'STB'], + 'assignment:create' => ['TEA'], + 'assignment:delete' => ['TEA', 'ADM', 'SUA', 'GLO'], + 'assignment:edit' => ['TEA', 'ADM', 'SUA', 'GLO'], + 'assignment:grade' => ['TEA'], + 'assignment:submit' => ['STU'], + 'assignment:view' => ['INV', 'STU', 'TEA', 'ADM', 'SUA', 'GLO', 'HRM', 'SSM', 'STB'], + 'backup:backup' => ['TEA', 'ADM', 'SUA', 'GLO', 'SSM'], + 'backup:copy' => ['TEA', 'ADM', 'SUA', 'GLO', 'SSM'], + 'backup:restore' => ['TEA', 'ADM', 'SUA', 'GLO', 'SSM'], + 'badge:configurecriteria' => ['ADM', 'SUA', 'GLO', 'SSM'], + 'badge:create' => ['ADM', 'SUA', 'GLO', 'SSM'], + 'badge:edit' => ['ADM', 'SUA', 'GLO', 'SSM'], + 'badge:delete' => ['ADM', 'SUA', 'GLO', 'SSM'], + 'badge:view' => ['INV', 'STU', 'TEA', 'ADM', 'SUA', 'GLO', 'SSM', 'STB'], + 'calendar:create' => ['ADM', 'SUA', 'GLO'], + 'calendar:edit' => ['ADM', 'SUA', 'GLO'], + 'calendar:delete' => ['ADM', 'SUA', 'GLO'], + 'catalogue:view' => ['INV', 'STU', 'TEA', 'ADM', 'SUA', 'GLO', 'HRM', 'QBM', 'SSM', 'STB'], + 'certificate:create' => ['TEA', 'SSM'], + 'certificate:delete' => ['TEA', 'SSM'], + 'certificate:edit' => ['TEA', 'SSM'], + 'certificate:generate' => ['STU', 'TEA', 'SSM'], + 'certificate:generateall' => ['TEA', 'HRM', 'SSM'], + 'certificate:viewall' => ['TEA', 'HRM', 'SSM', 'STB'], + 'class:assigncourse' => ['TEA', 'ADM', 'SUA', 'GLO'], + 'class:assignsession' => ['ADM', 'SUA', 'GLO', 'SSM'], + 'class:assignuser' => ['ADM', 'SUA', 'GLO', 'SSM'], + 'class:create' => ['ADM', 'SUA', 'GLO', 'SSM'], + 'class:delete' => ['ADM', 'SUA', 'GLO', 'SSM'], + 'class:edit' => ['ADM', 'SUA', 'GLO', 'SSM'], + 'class:view' => ['STU', 'TEA', 'ADM', 'SUA', 'GLO', 'SSM'], + 'cms:create' => ['ADM', 'SUA', 'GLO'], + 'cms:delete' => ['ADM', 'SUA', 'GLO'], + 'cms:edit' => ['ADM', 'SUA', 'GLO'], + 'course:create' => ['TEA', 'ADM', 'SUA', 'GLO', 'SSM'], + 'course:delete' => ['TEA', 'ADM', 'SUA', 'GLO'], + 'course:downloadcoursecontent' => ['TEA', 'ADM', 'SUA', 'GLO', 'SSM'], + 'course:edit' => ['TEA', 'SSM'], + 'course:editall' => ['ADM', 'SUA', 'GLO'], + 'plugin:manage' => ['ADM', 'SUA', 'GLO'], + 'quiz:create' => ['TEA', 'QBM'], + 'quiz:delete' => ['TEA', 'QBM'], + 'quiz:edit' => ['TEA', 'QBM'], + 'quiz:grade' => ['TEA'], + 'quiz:viewliveresults' => ['TEA', 'SSM'], + 'quiz:managequestionbank' => ['ADM', 'SUA', 'GLO', 'QBM'], + 'role:create' => ['ADM', 'SUA', 'GLO'], + 'role:managepermissions' => ['ADM', 'SUA', 'GLO'], + 'session:create' => ['ADM', 'SUA', 'GLO', 'SSM'], + 'session:delete' => ['ADM', 'SUA', 'GLO', 'SSM'], + 'session:edit' => ['ADM', 'SUA', 'GLO', 'SSM'], + 'session:editall' => ['ADM', 'SUA', 'GLO', 'SSM'], + 'session:assigncourse' => ['ADM', 'SUA', 'GLO', 'SSM'], + 'site:editsettings' => ['ADM', 'SUA', 'GLO'], + 'site:maintenanceaccess' => ['ADM', 'SUA', 'GLO'], + 'skill:coursecompetencymanage' => ['TEA', 'ADM', 'SUA', 'GLO', 'HRM'], + 'skill:usercompetencyreview' => ['STU', 'TEA', 'ADM', 'SUA', 'GLO'], + 'skill:assign' => ['ADM', 'SUA', 'GLO'], + 'skill:create' => ['GLO'], + 'skill:delete' => ['GLO'], + 'skill:edit' => ['GLO'], + 'skill:view' => ['ADM', 'SUA', 'GLO', 'SSM', 'STB'], + 'skill:viewall' => ['ADM', 'SUA', 'GLO', 'SSM', 'STB'], + 'survey:create' => ['TEA'], + 'survey:delete' => ['TEA'], + 'survey:edit' => ['TEA'], + 'survey:submit' => ['INV', 'STU', 'TEA', 'ADM', 'SUA', 'GLO', 'SSM', 'STB'], + 'survey:viewresults' => ['TEA', 'HRM', 'SSM', 'STB'], + 'ticket:comment' => ['STU', 'TEA', 'ADM', 'SUA', 'GLO', 'HRM', 'QBM', 'SSM', 'STB'], + 'ticket:manage' => ['ADM', 'SUA', 'GLO'], + 'ticket:report' => ['STU', 'TEA', 'ADM', 'SUA', 'GLO', 'HRM', 'QBM', 'SSM', 'STB'], + 'ticket:seeissues' => ['STU', 'TEA', 'ADM', 'SUA', 'GLO', 'SSM', 'STB'], + 'ticket:viewallissues' => ['ADM', 'SUA', 'GLO', 'SSM', 'STB'], + 'tool:editvisibility' => ['TEA', 'ADM', 'SUA', 'GLO', 'SSM'], + 'url:manage' => ['GLO'], + 'url:assignclass' => ['GLO'], + 'url:assigncourse' => ['GLO'], + 'url:assignuser' => ['GLO'], + 'user:assignclass' => ['ADM', 'SUA', 'GLO', 'SSM'], + 'user:assigncourse' => ['TEA', 'ADM', 'SUA', 'GLO'], + 'user:assignsession' => ['ADM', 'SUA', 'GLO', 'SSM'], + 'user:create' => ['ADM', 'SUA', 'GLO'], + 'user:delete' => ['ADM', 'SUA', 'GLO'], + 'user:edit' => ['ADM', 'SUA', 'GLO'], + 'user:editrole' => ['ADM', 'SUA', 'GLO'], + 'user:loginas' => ['SUA', 'GLO'], + ]; + } +} diff --git a/src/CoreBundle/Entity/Permission.php b/src/CoreBundle/Entity/Permission.php new file mode 100644 index 0000000000..62ec07990c --- /dev/null +++ b/src/CoreBundle/Entity/Permission.php @@ -0,0 +1,81 @@ +id; + } + + public function getTitle(): string + { + return $this->title; + } + + public function setTitle(string $title): self + { + $this->title = $title; + return $this; + } + + public function getSlug(): string + { + return $this->slug; + } + + public function setSlug(string $slug): self + { + $this->slug = $slug; + return $this; + } + + public function getDescription(): ?string + { + return $this->description; + } + + public function setDescription(?string $description): self + { + $this->description = $description; + return $this; + } + + public function __toString(): string + { + return $this->title; + } +} diff --git a/src/CoreBundle/Entity/PermissionRelRole.php b/src/CoreBundle/Entity/PermissionRelRole.php new file mode 100644 index 0000000000..08e598e60f --- /dev/null +++ b/src/CoreBundle/Entity/PermissionRelRole.php @@ -0,0 +1,89 @@ +id; + } + + public function getPermission(): Permission + { + return $this->permission; + } + + public function setPermission(Permission $permission): self + { + $this->permission = $permission; + return $this; + } + + public function getRoleCode(): string + { + return $this->roleCode; + } + + public function setRoleCode(string $roleCode): self + { + $this->roleCode = $roleCode; + return $this; + } + + public function isChangeable(): bool + { + return $this->changeable; + } + + public function setChangeable(bool $changeable): self + { + $this->changeable = $changeable; + return $this; + } + + public function getUpdatedAt(): \DateTime + { + return $this->updatedAt; + } + + public function setUpdatedAt(\DateTime $updatedAt): self + { + $this->updatedAt = $updatedAt; + return $this; + } +} diff --git a/src/CoreBundle/Form/PermissionType.php b/src/CoreBundle/Form/PermissionType.php new file mode 100644 index 0000000000..c07a7f9b1a --- /dev/null +++ b/src/CoreBundle/Form/PermissionType.php @@ -0,0 +1,33 @@ +add($role, CheckboxType::class, [ + 'required' => false, + ]); + } + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'roles' => [], + ]); + } +} diff --git a/src/CoreBundle/Migrations/Schema/V200/Version20240709222600.php b/src/CoreBundle/Migrations/Schema/V200/Version20240709222600.php new file mode 100644 index 0000000000..e685bcb7ad --- /dev/null +++ b/src/CoreBundle/Migrations/Schema/V200/Version20240709222600.php @@ -0,0 +1,51 @@ +addSql(' + CREATE TABLE IF NOT EXISTS permission ( + id INT AUTO_INCREMENT NOT NULL, + title VARCHAR(255) NOT NULL, + slug VARCHAR(255) NOT NULL, + description LONGTEXT DEFAULT NULL, + UNIQUE INDEX UNIQ_2DEDCC6F989D9B62 (slug), + PRIMARY KEY(id) + ) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB ROW_FORMAT = DYNAMIC + '); + + $this->addSql(' + CREATE TABLE IF NOT EXISTS permission_rel_role ( + id INT AUTO_INCREMENT NOT NULL, + permission_id INT NOT NULL, + role_code VARCHAR(50) NOT NULL, + changeable TINYINT(1) NOT NULL, + updated_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime)\', + INDEX IDX_43723A27FED90CCA (permission_id), + PRIMARY KEY(id), + CONSTRAINT FK_43723A27FED90CCA FOREIGN KEY (permission_id) REFERENCES permission (id) + ) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB ROW_FORMAT = DYNAMIC + '); + } + + public function down(Schema $schema): void + { + $this->addSql('DROP TABLE IF EXISTS permission_rel_role'); + $this->addSql('DROP TABLE IF EXISTS permission'); + } +} diff --git a/src/CoreBundle/Migrations/Schema/V200/Version20240709222700.php b/src/CoreBundle/Migrations/Schema/V200/Version20240709222700.php new file mode 100644 index 0000000000..ec0d3e30a3 --- /dev/null +++ b/src/CoreBundle/Migrations/Schema/V200/Version20240709222700.php @@ -0,0 +1,74 @@ +entityManager->getRepository(Permission::class); + $existingPermission = $permissionRepository->findOneBy(['slug' => $permData['slug']]); + + if ($existingPermission) { + $permission = $existingPermission; + } else { + $permission = new Permission(); + $permission->setTitle($permData['title']); + $permission->setSlug($permData['slug']); + $permission->setDescription($permData['description']); + + $this->entityManager->persist($permission); + $this->entityManager->flush(); + } + + foreach ($roles as $roleName => $roleCode) { + if (in_array($roleCode, $permissionsMapping[$permData['slug']])) { + $permissionRelRoleRepository = $this->entityManager->getRepository(PermissionRelRole::class); + $existingRelation = $permissionRelRoleRepository->findOneBy([ + 'permission' => $permission, + 'roleCode' => $roleName + ]); + + if ($existingRelation) { + continue; + } + + $permissionRelRole = new PermissionRelRole(); + $permissionRelRole->setPermission($permission); + $permissionRelRole->setRoleCode($roleName); + $permissionRelRole->setChangeable(true); + $permissionRelRole->setUpdatedAt(new \DateTime()); + + $this->entityManager->persist($permissionRelRole); + $this->entityManager->flush(); + } + } + } + } + + public function down(Schema $schema): void + { + $this->addSql('DELETE FROM permission_rel_role'); + $this->addSql('DELETE FROM permission'); + } +} diff --git a/src/CoreBundle/Repository/PermissionRelRoleRepository.php b/src/CoreBundle/Repository/PermissionRelRoleRepository.php new file mode 100644 index 0000000000..75ef3828b2 --- /dev/null +++ b/src/CoreBundle/Repository/PermissionRelRoleRepository.php @@ -0,0 +1,23 @@ + + */ +class PermissionRelRoleRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, PermissionRelRole::class); + } + +} diff --git a/src/CoreBundle/Repository/PermissionRepository.php b/src/CoreBundle/Repository/PermissionRepository.php new file mode 100644 index 0000000000..0f559138ff --- /dev/null +++ b/src/CoreBundle/Repository/PermissionRepository.php @@ -0,0 +1,23 @@ + + */ +class PermissionRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Permission::class); + } + +} diff --git a/src/CoreBundle/Resources/config/services.yml b/src/CoreBundle/Resources/config/services.yml index 00540aeb2b..d65a41cd4e 100644 --- a/src/CoreBundle/Resources/config/services.yml +++ b/src/CoreBundle/Resources/config/services.yml @@ -103,3 +103,7 @@ services: Chamilo\CoreBundle\Filter\SocialWallFilter: tags: [ 'api_platform.filter' ] + + Chamilo\CoreBundle\Service\PermissionService: + arguments: + $permissionRelRoleRepository: '@Chamilo\CoreBundle\Repository\PermissionRelRoleRepository' diff --git a/src/CoreBundle/Resources/views/Permission/index.html.twig b/src/CoreBundle/Resources/views/Permission/index.html.twig new file mode 100644 index 0000000000..8f7aca0f09 --- /dev/null +++ b/src/CoreBundle/Resources/views/Permission/index.html.twig @@ -0,0 +1,49 @@ +{% extends "@ChamiloCore/Layout/layout_one_col.html.twig" %} + +{% block content %} +

{{ 'Permissions Management'|trans }}

+
+ + + + + + {% for role in roles %} + + {% endfor %} + + + + {% for permission in permissions %} + + + {% for role in roles %} + + {% endfor %} + + {% endfor %} + +
{{ 'Permission '|trans }}
({{ 'slug'|trans }})
+ {{ role|trans }}
+ +
{{ permission.title|trans }}
({{ permission.slug }})
+ +
+ +
+ +{% endblock %} diff --git a/src/CoreBundle/Service/PermissionService.php b/src/CoreBundle/Service/PermissionService.php new file mode 100644 index 0000000000..0d2d9903fc --- /dev/null +++ b/src/CoreBundle/Service/PermissionService.php @@ -0,0 +1,35 @@ +permissionRelRoleRepository = $permissionRelRoleRepository; + } + + public function hasPermission(string $permissionSlug, array $roles): bool + { + $queryBuilder = $this->permissionRelRoleRepository->createQueryBuilder('prr') + ->innerJoin('prr.permission', 'p') + ->where('p.slug = :permissionSlug') + ->andWhere('prr.roleCode IN (:roles)') + ->andWhere('prr.changeable = :changeable') + ->setParameter('permissionSlug', $permissionSlug) + ->setParameter('roles', $roles) + ->setParameter('changeable', true); + + $results = $queryBuilder->getQuery()->getResult(); + + return count($results) > 0; + } +}