Merge branch 'master' of github.com:chamilo/chamilo-lms

pull/5292/head
Yannick Warnier 1 year ago
commit 90cb87c68b
  1. 60
      assets/vue/components/Login.vue
  2. 74
      assets/vue/composables/auth/login.js
  3. 3
      assets/vue/router/ccalendarevent.js
  4. 74
      assets/vue/views/ccalendarevent/CCalendarEventList.vue
  5. 20
      public/main/inc/ajax/agenda.ajax.php
  6. 85
      public/main/inc/lib/agenda.lib.php
  7. 77
      public/main/inc/lib/plugin.class.php
  8. 2
      public/plugin/positioning/src/Positioning.php
  9. 2
      public/plugin/surveyexportcsv/SurveyExportCsvPlugin.php
  10. 2
      public/plugin/surveyexporttxt/SurveyExportTxtPlugin.php
  11. 13
      src/CoreBundle/ApiResource/CalendarEvent.php
  12. 9
      src/CoreBundle/ApiResource/CourseTool.php
  13. 2
      src/CoreBundle/Controller/Admin/IndexBlocksController.php
  14. 9
      src/CoreBundle/DataProvider/Extension/CCalendarEventExtension.php
  15. 8
      src/CoreBundle/DataTransformer/CalendarEventTransformer.php
  16. 49
      src/CoreBundle/Entity/Listener/ResourceListener.php
  17. 166
      src/CoreBundle/Entity/SysCalendar.php
  18. 65
      src/CoreBundle/Filter/GlobalEventFilter.php
  19. 71
      src/CoreBundle/Migrations/Schema/V200/Version20180928172830.php
  20. 1
      src/CoreBundle/Migrations/Schema/V200/Version20201212114910.php
  21. 2
      src/CoreBundle/Migrations/Schema/V200/Version20201212195011.php
  22. 102
      src/CoreBundle/Migrations/Schema/V200/Version20240323181500.php
  23. 29
      src/CoreBundle/Migrations/Schema/V200/Version20240323222700.php
  24. 19
      src/CoreBundle/Repository/SysCalendarRepository.php
  25. 15
      src/CoreBundle/Tool/AbstractPlugin.php
  26. 52
      src/CoreBundle/Tool/AbstractTool.php
  27. 30
      src/CoreBundle/Tool/CustomCertificate.php
  28. 29
      src/CoreBundle/Tool/NotebookTeacher.php
  29. 25
      src/CoreBundle/Tool/Positioning.php
  30. 30
      src/CoreBundle/Tool/Test2Pdf.php
  31. 8
      src/CoreBundle/Tool/ToolChain.php
  32. 30
      src/CoreBundle/Tool/Zoom.php
  33. 2
      src/CourseBundle/Entity/CCalendarEvent.php
  34. 1
      src/CourseBundle/Entity/CTool.php
  35. 32
      src/CourseBundle/Repository/CCalendarEventRepository.php

@ -7,7 +7,7 @@
<form
class="login-section__form p-input-filled"
@submit.prevent="performLogin"
@submit.prevent="onSubmitLoginForm"
>
<div class="field">
<InputText
@ -72,19 +72,17 @@
<script setup>
import { useStore } from "vuex"
import { computed, ref } from "vue"
import { useRoute, useRouter } from "vue-router"
import Button from "primevue/button"
import InputText from "primevue/inputtext"
import Password from "primevue/password"
import InputSwitch from "primevue/inputswitch"
import { useI18n } from "vue-i18n"
import { useSecurityStore } from "../store/securityStore"
import { useLogin } from "../composables/auth/login"
const route = useRoute()
const router = useRouter()
const store = useStore()
const { t } = useI18n()
const securityStore = useSecurityStore()
const { redirectNotAuthenticated, performLogin } = useLogin()
const login = ref("")
const password = ref("")
@ -92,55 +90,13 @@ const remember = ref(false)
const isLoading = computed(() => store.getters["security/isLoading"])
let redirect = route.query.redirect
if (securityStore.isAuthenticated) {
if (typeof redirect !== "undefined") {
router.push({ path: redirect.toString() })
} else {
router.replace({ name: "Home" })
}
}
redirectNotAuthenticated()
async function performLogin() {
let payload = {
function onSubmitLoginForm() {
performLogin({
login: login.value,
password: password.value,
_remember_me: remember.value,
}
let redirect = route.query.redirect
const responseData = await store.dispatch("security/login", payload)
if (!store.getters["security/hasError"]) {
securityStore.user = store.state["security/user"]
// Check if 'redirect' is an absolute URL
if (typeof redirect !== "undefined" && isValidHttpUrl(redirect.toString())) {
// If it's an absolute URL, redirect directly
window.location.href = redirect.toString()
} else if (typeof redirect !== "undefined") {
// If 'redirect' is a relative path, use 'router.push' to navigate
await router.push({ path: redirect.toString() })
} else {
if (responseData.load_terms) {
window.location.href = responseData.redirect
} else {
window.location.href = "/home"
}
}
}
}
function isValidHttpUrl(string) {
let url
try {
url = new URL(string)
} catch (_) {
return false
}
return url.protocol === "http:" || url.protocol === "https:"
})
}
</script>

@ -0,0 +1,74 @@
import { usePlatformConfig } from "../../store/platformConfig"
import { useRoute, useRouter } from "vue-router"
import { useStore } from "vuex"
import { useSecurityStore } from "../../store/securityStore"
function isValidHttpUrl(string) {
let url
try {
url = new URL(string)
} catch (_) {
return false
}
return url.protocol === "http:" || url.protocol === "https:"
}
export function useLogin() {
const route = useRoute()
const router = useRouter()
const store = useStore()
const securityStore = useSecurityStore()
async function performLogin(payload) {
const responseData = await store.dispatch("security/login", payload)
if (store.getters["security/hasError"]) {
return
}
if (route.query.redirect) {
// Check if 'redirect' is an absolute URL
if (isValidHttpUrl(route.query.redirect.toString())) {
// If it's an absolute URL, redirect directly
window.location.href = route.query.redirect.toString()
return
}
securityStore.user = responseData
const platformConfigurationStore = usePlatformConfig()
await platformConfigurationStore.initialize()
// If 'redirect' is a relative path, use 'router.push' to navigate
await router.push({ path: route.query.redirect.toString() })
return
}
if (responseData.load_terms) {
window.location.href = responseData.redirect
} else {
window.location.href = "/home"
}
}
async function redirectNotAuthenticated() {
if (!securityStore.isAuthenticated) {
return
}
if (route.query.redirect) {
await router.push({ path: route.query.redirect.toString() })
} else {
await router.replace({ name: "Home" })
}
}
return {
performLogin,
redirectNotAuthenticated,
}
}

@ -18,7 +18,8 @@ export default {
{
name: 'CCalendarEventList',
path: '',
component: () => import('../views/ccalendarevent/CCalendarEventList.vue')
component: () => import('../views/ccalendarevent/CCalendarEventList.vue'),
props: (route) => ({ type: route.query.type })
}
]
};

@ -1,10 +1,10 @@
<template>
<div class="flex flex-col gap-4">
<CalendarSectionHeader
<!--CalendarSectionHeader
@add-click="showAddEventDialog"
@my-students-schedule-click="goToMyStudentsSchedule"
@session-planning-click="goToSessionPanning"
/>
/-->
<FullCalendar
ref="cal"
@ -23,6 +23,7 @@
v-if="dialog"
ref="createForm"
:values="item"
:is-global="isGlobal"
/>
<template #footer>
<BaseButton
@ -72,17 +73,18 @@
/>
<BaseButton
v-if="showDeleteButton"
:label="t('Delete')"
icon="delete"
type="danger"
@click="confirmDelete"
/>
<BaseButton
v-if="allowToEdit"
v-if="allowToEdit && showEditButton"
:label="t('Edit')"
type="secondary"
@click="dialog = true"
/>
icon="delete"/>
</template>
</Dialog>
@ -128,6 +130,7 @@ import { useStore } from "vuex"
import { useI18n } from "vue-i18n"
import { useConfirm } from "primevue/useconfirm"
import { useFormatDate } from "../../composables/formatDate"
import { useRoute } from "vue-router"
import Loading from "../../components/Loading.vue"
import FullCalendar from "@fullcalendar/vue3"
@ -171,6 +174,8 @@ const allowToUnsubscribe = ref(false)
const currentUser = computed(() => store.getters["security/getUser"])
const { t } = useI18n()
const { appLocale } = useLocale()
const route = useRoute()
const isGlobal = ref(route.query.type === 'global')
let currentEvent = null
@ -203,13 +208,29 @@ async function getCalendarEvents({ startStr, endStr }) {
params.gid = group.value.id
}
if (route.query?.type === 'global') {
params.type = 'global'
}
const calendarEvents = await cCalendarEventService.findAll({ params }).then((response) => response.json())
return calendarEvents["hydra:member"].map((event) => ({
...event,
start: event.startDate,
end: event.endDate,
}))
return calendarEvents["hydra:member"].map((event) => {
let color = '#007BFF'
if (event.type === 'global') {
color = '#FF0000'
} else if (event.type === 'course') {
color = '#28a745'
} else if (event.type === 'session') {
color = '#800080'
}
return {
...event,
start: event.startDate,
end: event.endDate,
color,
}
})
}
const calendarLocale = allLocales.find(
@ -291,6 +312,32 @@ const calendarOptions = ref({
},
})
const currentContext = computed(() => {
if (route.query.type === 'global') {
return 'global'
} else if (course.value) {
return 'course'
} else if (session.value) {
return 'session'
} else {
return 'personal'
}
});
const allowAction = (eventType) => {
const contextRules = {
global: ['global'],
course: ['course'],
session: ['session'],
personal: ['personal']
};
return contextRules[currentContext.value].includes(eventType);
};
const showEditButton = computed(() => allowAction(item.value.type));
const showDeleteButton = computed(() => allowAction(item.value.type));
const cal = ref(null)
function reFetch() {
@ -359,6 +406,10 @@ function onCreateEventForm() {
let itemModel = createForm.value.v$.item.$model
if (isGlobal.value) {
itemModel.isGlobal = true
}
if (itemModel["@id"]) {
store.dispatch("ccalendarevent/update", itemModel)
} else {
@ -380,6 +431,11 @@ function onCreateEventForm() {
const toast = useToast()
watch(() => route.query.type, (newType) => {
isGlobal.value = newType === 'global'
reFetch()
})
watch(
() => store.state.ccalendarevent.created,
(created) => {

@ -177,26 +177,6 @@ switch ($action) {
$month,
$year
);
$agendaitems = Agenda::get_global_agenda_items(
$agendaitems,
$day,
$month,
$year,
$week,
"month_view"
);
if ('true' === api_get_setting('allow_personal_agenda')) {
/*$agendaitems = Agenda::get_personal_agenda_items(
$user_id,
$agendaitems,
$day,
$month,
$year,
$week,
"month_view"
);*/
}
Agenda::display_mymonthcalendar(
$user_id,
$agendaitems,

@ -3,8 +3,6 @@
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Entity\Course;
//use Chamilo\CoreBundle\Entity\PersonalAgenda;
use Chamilo\CoreBundle\Entity\SysCalendar;
use Chamilo\CoreBundle\Framework\Container;
use Chamilo\CourseBundle\Entity\CCalendarEvent;
use Chamilo\CourseBundle\Entity\CCalendarEventAttachment;
@ -57,8 +55,6 @@ class Agenda
$sessionId = 0
) {
// Table definitions
$this->tbl_global_agenda = Database::get_main_table(TABLE_MAIN_SYSTEM_CALENDAR);
//$this->tbl_personal_agenda = Database::get_main_table(TABLE_PERSONAL_AGENDA);
$this->tbl_course_agenda = Database::get_course_table(TABLE_AGENDA);
$this->table_repeat = Database::get_course_table(TABLE_AGENDA_REPEAT);
@ -365,24 +361,6 @@ class Agenda
}
}
break;
case 'admin':
if (api_is_platform_admin()) {
$event = new SysCalendar();
$color = SysCalendar::COLOR_SYSTEM_EVENT;
$event
->setTitle($title)
->setContent($content)
->setStartDate($start)
->setEndDate($end)
->setAllDay($allDay)
->setUrl(api_get_url_entity())
->setColor($color)
;
$em->persist($event);
$em->flush();
$id = $event->getId();
}
break;
}
return $id;
@ -811,26 +789,6 @@ class Agenda
return false;
break;
case 'admin':
case 'platform':
if (api_is_platform_admin()) {
$attributes = [
'title' => $title,
'start_date' => $start,
'end_date' => $end,
'all_day' => $allDay,
];
if ($updateContent) {
$attributes['content'] = $content;
}
Database::update(
$this->tbl_global_agenda,
$attributes,
['id = ?' => $id]
);
}
break;
}
}
@ -925,14 +883,6 @@ class Agenda
}
}
break;
case 'admin':
if (api_is_platform_admin()) {
Database::delete(
$this->tbl_global_agenda,
['id = ?' => $id]
);
}
break;
}
}
@ -957,9 +907,6 @@ class Agenda
$format = 'json'
) {
switch ($this->type) {
case 'admin':
$this->getPlatformEvents($start, $end);
break;
case 'course':
$course = api_get_course_entity($courseId);
@ -1001,14 +948,6 @@ class Agenda
$sessionFilterActive = true;
}
if (false == $sessionFilterActive) {
// Getting personal events
//$this->getPersonalEvents($start, $end);
// Getting platform/admin events
$this->getPlatformEvents($start, $end);
}
$ignoreVisibility = ('true' === api_get_setting('agenda.personal_agenda_show_all_session_events'));
// Getting course events
@ -1171,12 +1110,6 @@ class Agenda
id = ".$id;
Database::query($sql);
break;
case 'admin':
$sql = "UPDATE $this->tbl_global_agenda SET
end_date = DATE_ADD(end_date, INTERVAL $delta MINUTE)
WHERE id = ".$id;
Database::query($sql);
break;
}
}
@ -1222,14 +1155,6 @@ class Agenda
id=".$id;
Database::query($sql);
break;
case 'admin':
$sql = "UPDATE $this->tbl_global_agenda SET
all_day = $allDay,
start_date = DATE_ADD(start_date,INTERVAL $delta MINUTE),
end_date = DATE_ADD(end_date, INTERVAL $delta MINUTE)
WHERE id=".$id;
Database::query($sql);
break;
}
}
@ -1291,16 +1216,6 @@ class Agenda
}
}
break;
case 'admin':
case 'platform':
$sql = "SELECT * FROM ".$this->tbl_global_agenda."
WHERE id = $id";
$result = Database::query($sql);
if (Database::num_rows($result)) {
$event = Database::fetch_array($result, 'ASSOC');
$event['description'] = $event['content'];
}
break;
}
return $event;

@ -1,8 +1,12 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Entity\ResourceLink;
use Chamilo\CoreBundle\Entity\Tool;
use Chamilo\CourseBundle\Entity\CTool;
use Doctrine\ORM\Exception\NotSupported;
use Doctrine\ORM\Exception\ORMException;
use Doctrine\ORM\OptimisticLockException;
/**
* Class Plugin
@ -507,7 +511,7 @@ class Plugin
*
* @return bool|null False on error, null otherwise
*/
public function install_course_fields($courseId, $add_tool_link = true, $iconName = '')
public function install_course_fields($courseId, $add_tool_link = true)
{
$plugin_name = $this->get_name();
$t_course = Database::get_course_table(TABLE_COURSE_SETTING);
@ -584,7 +588,7 @@ class Plugin
}
// Add an icon in the table tool list
$this->createLinkToCourseTool($plugin_name, $courseId, $iconName);
$this->createLinkToCourseTool($plugin_name, $courseId);
}
/**
@ -638,14 +642,14 @@ class Plugin
*
* @param bool $add_tool_link Whether we want to add a plugin link on the course homepage
*/
public function install_course_fields_in_all_courses($add_tool_link = true, $iconName = '')
public function install_course_fields_in_all_courses($add_tool_link = true)
{
// Update existing courses to add plugin settings
$table = Database::get_main_table(TABLE_MAIN_COURSE);
$sql = "SELECT id FROM $table ORDER BY id";
$res = Database::query($sql);
while ($row = Database::fetch_assoc($res)) {
$this->install_course_fields($row['id'], $add_tool_link, $iconName);
$this->install_course_fields($row['id'], $add_tool_link);
}
}
@ -1041,16 +1045,16 @@ class Plugin
}
/**
* Add an link for a course tool.
* Add a link for a course tool.
*
* @param string $name The tool name
* @param int $courseId The course ID
* @param string|null $iconName Optional. Icon file name
* @param string|null $link Optional. Link URL
* @param string $name The tool name
* @param int $courseId The course ID
*
* @return CTool|null
* @throws NotSupported
* @throws ORMException
* @throws OptimisticLockException
*/
protected function createLinkToCourseTool(string $name, int $courseId, string $iconName = null, string $link = null): ?CTool
protected function createLinkToCourseTool(string $name, int $courseId): ?CTool
{
if (!$this->addCourseTool) {
return null;
@ -1059,31 +1063,52 @@ class Plugin
$visibilityPerStatus = $this->getToolIconVisibilityPerUserStatus();
$visibility = $this->isIconVisibleByDefault();
$course = api_get_course_entity($courseId);
$user = api_get_user_entity();
$em = Database::getManager();
/** @var CTool $tool */
$tool = $em->getRepository(CTool::class)->findOneBy([
'title' => $name,
'course' => api_get_course_entity($courseId),
$toolRepo = $em->getRepository(Tool::class);
$cToolRepo = $em->getRepository(CTool::class);
/** @var CTool $cTool */
$cTool = $cToolRepo->findOneBy([
'title' => $name.$visibilityPerStatus,
'course' => $course,
]);
if (!$tool) {
$pluginName = $this->get_name();
if (!$cTool) {
$tool = $toolRepo->findOneBy(['title' => $name]);
$toolEntity = new Tool();
$toolEntity->setTitle($pluginName);
if (!$tool) {
$tool = new Tool();
$tool->setTitle($name);
$tool = new CTool();
$tool->setCourse(api_get_course_entity($courseId))
$em->persist($tool);
$em->flush();
}
$cTool = new CTool();
$cTool
->setTool($tool)
->setTitle($name.$visibilityPerStatus)
->setVisibility($visibility)
->setTool($toolEntity)
->setPosition(0);
$em->persist($tool);
->setParent($course)
->setCreator($user)
->addCourseLink(
$course,
null,
null,
$visibility ? ResourceLink::VISIBILITY_PUBLISHED : ResourceLink::VISIBILITY_DRAFT
)
;
$course->addTool($cTool);
$em->persist($cTool);
$em->flush();
}
return $tool;
return $cTool;
}
}

@ -47,7 +47,7 @@ class Positioning extends Plugin
Database::query($sql);
// Installing course settings
$this->install_course_fields_in_all_courses(true, 'positioning.png');
$this->install_course_fields_in_all_courses(true);
}
public function uninstall()

@ -82,7 +82,7 @@ class SurveyExportCsvPlugin extends Plugin
->getResult();
foreach ($result as $item) {
$this->createLinkToCourseTool($this->get_name().':teacher', $item['id'], 'survey.png');
$this->createLinkToCourseTool($this->get_name().':teacher', $item['id']);
}
}

@ -82,7 +82,7 @@ class SurveyExportTxtPlugin extends Plugin
->getResult();
foreach ($result as $item) {
$this->createLinkToCourseTool($this->get_name().':teacher', $item['id'], 'survey.png');
$this->createLinkToCourseTool($this->get_name().':teacher', $item['id']);
}
}

@ -43,7 +43,20 @@ class CalendarEvent extends AbstractResource
#[Groups(['calendar_event:read'])]
public ?ResourceNode $resourceNode = null,
?array $resourceLinkListFromEntity = null,
#[Groups(['calendar_event:read'])]
public ?string $type = null,
) {
$this->resourceLinkListFromEntity = $resourceLinkListFromEntity;
}
public function getType(): ?string
{
return $this->type;
}
public function setType(?string $type): self
{
$this->type = $type;
return $this;
}
}

@ -29,13 +29,4 @@ class CourseTool extends AbstractResource
#[Groups(['ctool:read'])]
public string $url;
#[Groups(['ctool:read'])]
public string $category = '';
#[Groups(['ctool:read'])]
public function getNameToTranslate(): string
{
return ucfirst(str_replace('_', ' ', $this->title));
}
}

@ -339,7 +339,7 @@ class IndexBlocksController extends BaseController
];
$items[] = [
'class' => 'item-global-agenda',
'url' => $this->generateUrl('legacy_main', ['name' => 'calendar/agenda_js.php', 'type' => 'admin']),
'url' => '/resources/ccalendarevent?type=global',
'label' => $this->translator->trans('Global agenda'),
];

@ -35,15 +35,20 @@ final class CCalendarEventExtension implements QueryCollectionExtensionInterface
?Operation $operation = null,
array $context = []
): void {
$this->addWhere($queryBuilder, $resourceClass);
$this->addWhere($queryBuilder, $resourceClass, $context);
}
private function addWhere(QueryBuilder $qb, string $resourceClass): void
private function addWhere(QueryBuilder $qb, string $resourceClass, array $context): void
{
if (CCalendarEvent::class !== $resourceClass) {
return;
}
$isGlobalType = isset($context['filters']['type']) && $context['filters']['type'] === 'global';
if ($isGlobalType) {
return;
}
$courseId = $this->cidReqHelper->getCourseId();
$sessionId = $this->cidReqHelper->getSessionId();
$groupId = $this->cidReqHelper->getGroupId();

@ -12,6 +12,7 @@ use Chamilo\CoreBundle\Entity\Session;
use Chamilo\CoreBundle\Entity\SessionRelCourse;
use Chamilo\CoreBundle\Repository\Node\UsergroupRepository;
use Chamilo\CourseBundle\Entity\CCalendarEvent;
use Chamilo\CourseBundle\Repository\CCalendarEventRepository;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\RouterInterface;
@ -20,6 +21,7 @@ class CalendarEventTransformer implements DataTransformerInterface
public function __construct(
private readonly RouterInterface $router,
private readonly UsergroupRepository $usergroupRepository,
private readonly CCalendarEventRepository $calendarEventRepository
) {}
public function transform($object, string $to, array $context = []): object
@ -48,7 +50,8 @@ class CalendarEventTransformer implements DataTransformerInterface
$subscriptionItemTitle = $this->usergroupRepository->find($object->getSubscriptionItemId())?->getTitle();
}
return new CalendarEvent(
$eventType = $this->calendarEventRepository->determineEventType($object);
$calendarEvent = new CalendarEvent(
'calendar_event_'.$object->getIid(),
$object->getTitle(),
$object->getContent(),
@ -65,6 +68,9 @@ class CalendarEventTransformer implements DataTransformerInterface
$object->getResourceNode(),
$object->getResourceLinkListFromEntity(),
);
$calendarEvent->setType($eventType);
return $calendarEvent;
}
private function mapSessionToDto(object $object): CalendarEvent

@ -13,6 +13,7 @@ use Chamilo\CoreBundle\Entity\EntityAccessUrlInterface;
use Chamilo\CoreBundle\Entity\PersonalFile;
use Chamilo\CoreBundle\Entity\ResourceFile;
use Chamilo\CoreBundle\Entity\ResourceFormat;
use Chamilo\CoreBundle\Entity\ResourceLink;
use Chamilo\CoreBundle\Entity\ResourceNode;
use Chamilo\CoreBundle\Entity\ResourceToRootInterface;
use Chamilo\CoreBundle\Entity\ResourceType;
@ -20,6 +21,7 @@ use Chamilo\CoreBundle\Entity\ResourceWithAccessUrlInterface;
use Chamilo\CoreBundle\Entity\User;
use Chamilo\CoreBundle\Tool\ToolChain;
use Chamilo\CoreBundle\Traits\AccessUrlListenerTrait;
use Chamilo\CourseBundle\Entity\CCalendarEvent;
use Cocur\Slugify\SlugifyInterface;
use Doctrine\ORM\Event\PostUpdateEventArgs;
use Doctrine\ORM\Event\PrePersistEventArgs;
@ -257,6 +259,10 @@ class ResourceListener
throw new InvalidArgumentException($message);
}
if ($resource instanceof CCalendarEvent) {
$this->addCCalendarEventGlobalLink($resource, $eventArgs);
}
}
/**
@ -299,4 +305,47 @@ class ResourceListener
$slug = sprintf('%s.%s', $this->slugify->slugify($originalBasename), $originalExtension);*/
$resource->getResourceNode()->setTitle($resourceName);
}
private function addCCalendarEventGlobalLink(CCalendarEvent $event, PrePersistEventArgs $eventArgs): void
{
$currentRequest = $this->request->getCurrentRequest();
if (null === $currentRequest) {
return;
}
$type = $currentRequest->query->get('type');
if (null === $type) {
$content = $currentRequest->getContent();
$params = json_decode($content, true);
if (isset($params['isGlobal']) && 1 === (int) $params['isGlobal']) {
$type = 'global';
}
}
if ('global' === $type) {
$em = $eventArgs->getObjectManager();
$resourceNode = $event->getResourceNode();
$globalLink = new ResourceLink();
$globalLink->setCourse(null)
->setSession(null)
->setGroup(null)
->setUser(null);
$alreadyHasGlobalLink = false;
foreach ($resourceNode->getResourceLinks() as $existingLink) {
if (null === $existingLink->getCourse() && null === $existingLink->getSession() &&
null === $existingLink->getGroup() && null === $existingLink->getUser()) {
$alreadyHasGlobalLink = true;
break;
}
}
if (!$alreadyHasGlobalLink) {
$resourceNode->addResourceLink($globalLink);
$em->persist($globalLink);
}
}
}
}

@ -1,166 +0,0 @@
<?php
declare(strict_types=1);
/* For licensing terms, see /license.txt */
namespace Chamilo\CoreBundle\Entity;
use DateTime;
use Doctrine\ORM\Mapping as ORM;
/**
* SysCalendar.
*/
#[ORM\Table(name: 'sys_calendar')]
#[ORM\Entity]
class SysCalendar
{
public const COLOR_SYSTEM_EVENT = '#FF0000';
#[ORM\Column(name: 'id', type: 'integer')]
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'IDENTITY')]
protected ?int $id = null;
#[ORM\Column(name: 'title', type: 'string', length: 255, nullable: false)]
protected string $title;
#[ORM\Column(name: 'content', type: 'text', nullable: true)]
protected ?string $content = null;
#[ORM\Column(name: 'start_date', type: 'datetime', nullable: true)]
protected ?DateTime $startDate = null;
#[ORM\Column(name: 'end_date', type: 'datetime', nullable: true)]
protected ?DateTime $endDate = null;
#[ORM\ManyToOne(targetEntity: AccessUrl::class)]
#[ORM\JoinColumn(name: 'access_url_id', referencedColumnName: 'id', onDelete: 'CASCADE')]
protected AccessUrl $url;
#[ORM\Column(name: 'all_day', type: 'integer', nullable: false)]
protected int $allDay;
#[ORM\Column(name: 'color', type: 'string', length: 20, nullable: true)]
protected ?string $color = null;
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
/**
* Get title.
*
* @return string
*/
public function getTitle()
{
return $this->title;
}
public function setContent(string $content): self
{
$this->content = $content;
return $this;
}
/**
* Get content.
*
* @return string
*/
public function getContent()
{
return $this->content;
}
public function setStartDate(DateTime $startDate): self
{
$this->startDate = $startDate;
return $this;
}
/**
* Get startDate.
*
* @return DateTime
*/
public function getStartDate()
{
return $this->startDate;
}
public function setEndDate(DateTime $endDate): self
{
$this->endDate = $endDate;
return $this;
}
/**
* Get endDate.
*
* @return DateTime
*/
public function getEndDate()
{
return $this->endDate;
}
public function setAllDay(int $allDay): self
{
$this->allDay = $allDay;
return $this;
}
/**
* Get allDay.
*
* @return int
*/
public function getAllDay()
{
return $this->allDay;
}
/**
* Get id.
*
* @return int
*/
public function getId()
{
return $this->id;
}
public function getColor(): ?string
{
return $this->color;
}
public function setColor(string $color): self
{
$this->color = $color;
return $this;
}
public function getUrl(): AccessUrl
{
return $this->url;
}
public function setUrl(AccessUrl $url): self
{
$this->url = $url;
return $this;
}
}

@ -0,0 +1,65 @@
<?php
/* For licensing terms, see /license.txt */
declare(strict_types=1);
namespace Chamilo\CoreBundle\Filter;
use ApiPlatform\Doctrine\Orm\Filter\AbstractFilter;
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use ApiPlatform\Metadata\Operation;
use Chamilo\CoreBundle\Entity\ResourceNode;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ManagerRegistry;
use Psr\Log\LoggerInterface;
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
class GlobalEventFilter extends AbstractFilter
{
public function __construct(
ManagerRegistry $managerRegistry,
?LoggerInterface $logger = null,
?array $properties = null,
?NameConverterInterface $nameConverter = null
) {
parent::__construct($managerRegistry, $logger, $properties, $nameConverter);
}
protected function filterProperty(
string $property,
$value,
QueryBuilder $queryBuilder,
QueryNameGeneratorInterface $queryNameGenerator,
string $resourceClass,
?Operation $operation = null,
array $context = []
): void {
$isGlobalType = isset($context['filters']['type']) && $context['filters']['type'] === 'global';
if (!$isGlobalType) {
return;
}
$rootAlias = $queryBuilder->getRootAliases()[0];
$resourceNodeAlias = $queryNameGenerator->generateJoinAlias('resourceNode');
$resourceLinkAlias = $queryNameGenerator->generateJoinAlias('resourceLink');
$queryBuilder
->innerJoin("$rootAlias.resourceNode", $resourceNodeAlias)
->innerJoin("$resourceNodeAlias.resourceLinks", $resourceLinkAlias)
->andWhere("$resourceLinkAlias.course IS NULL")
->andWhere("$resourceLinkAlias.session IS NULL")
->andWhere("$resourceLinkAlias.group IS NULL")
->andWhere("$resourceLinkAlias.user IS NULL");
}
public function getDescription(string $resourceClass): array
{
return [
'type' => [
'property' => 'type',
'type' => 'string',
'required' => false,
'description' => 'Filter events by type. Use "global" to get global events.',
],
];
}
}

@ -19,28 +19,12 @@ class Version20180928172830 extends AbstractMigrationChamilo
public function up(Schema $schema): void
{
$table = $schema->getTable('c_tool');
if (false === $table->hasForeignKey('FK_8456658091D79BD3')) {
$this->addSql(
'ALTER TABLE c_tool ADD CONSTRAINT FK_8456658091D79BD3 FOREIGN KEY (c_id) REFERENCES course (id)'
);
}
$this->addSql('ALTER TABLE c_tool CHANGE link link VARCHAR(255) DEFAULT NULL;');
$this->addSql('UPDATE c_tool SET title = "blog" WHERE title = "blog_management" ');
$this->addSql('UPDATE c_tool SET title = "agenda" WHERE title = "calendar_event" ');
$this->addSql('UPDATE c_tool SET title = "member" WHERE link = "user/user.php" ');
$this->addSql('UPDATE c_tool SET title = "course_description/index.php" WHERE link = "course_description/" ');
// $this->addSql('UPDATE c_tool SET title = "maintenance" WHERE title = "course_maintenance" ');
// $this->addSql('UPDATE c_tool SET title = "assignment" WHERE title = "student_publication" ');
// $this->addSql('UPDATE c_tool SET title = "settings" WHERE title = "course_setting" ');
if (!$table->hasColumn('tool_id')) {
$this->addSql('ALTER TABLE c_tool ADD tool_id INT NOT NULL');
}
if (!$table->hasColumn('position')) {
$this->addSql('ALTER TABLE c_tool ADD position INT NOT NULL');
}
if ($table->hasColumn('id')) {
$this->addSql('ALTER TABLE c_tool DROP id');
}
@ -63,18 +47,36 @@ class Version20180928172830 extends AbstractMigrationChamilo
$this->addSql('ALTER TABLE c_tool DROP custom_icon');
}
$this->addSql('UPDATE c_tool SET session_id = NULL WHERE session_id = 0');
if ($table->hasColumn('link')) {
$this->addSql('ALTER TABLE c_tool DROP link');
}
// Delete c_tool not registered in tool. @todo migrate BBB/LP/mobidico plugins
$this->addSql('DELETE FROM c_tool WHERE title NOT IN (SELECT title FROM tool)');
$this->addSql('UPDATE c_tool SET tool_id = (SELECT id FROM tool WHERE title = c_tool.title) WHERE tool_id IS NOT NULL');
if ($table->hasColumn('category')) {
$this->addSql('ALTER TABLE c_tool DROP category');
}
if (!$table->hasColumn('resource_node_id')) {
$this->addSql('ALTER TABLE c_tool ADD resource_node_id INT DEFAULT NULL');
if ($table->hasColumn('admin')) {
$this->addSql('ALTER TABLE c_tool DROP admin');
}
// @todo remove/move LP/Link shortcuts.
$this->addSql('DELETE FROM c_tool WHERE tool_id = 0 OR tool_id IS NULL');
if (!$table->hasColumn('tool_id')) {
$this->addSql('ALTER TABLE c_tool ADD tool_id INT NOT NULL');
}
if (!$table->hasColumn('position')) {
$this->addSql('ALTER TABLE c_tool ADD position INT NOT NULL');
}
$this->addSql('DELETE FROM c_tool WHERE c_id NOT IN (SELECT id FROM course)');
$this->addSql('ALTER TABLE c_tool CHANGE c_id c_id INT NOT NULL');
if (!$table->hasForeignKey('FK_8456658091D79BD3')) {
$this->addSql(
'ALTER TABLE c_tool ADD CONSTRAINT FK_8456658091D79BD3 FOREIGN KEY (c_id) REFERENCES course (id)'
);
}
$this->addSql('UPDATE c_tool SET session_id = NULL WHERE session_id = 0');
$this->addSql('DELETE FROM c_tool WHERE session_id IS NOT NULL AND session_id NOT IN (SELECT id FROM session)');
if (!$table->hasForeignKey('FK_84566580613FECDF')) {
@ -83,20 +85,31 @@ class Version20180928172830 extends AbstractMigrationChamilo
);
}
// Delete c_tool not registered in tool. @todo migrate BBB/LP/mobidico plugins
$this->addSql('DELETE FROM c_tool WHERE title NOT IN (SELECT title FROM tool)');
$this->addSql('UPDATE c_tool SET tool_id = (SELECT id FROM tool WHERE title = c_tool.title) WHERE tool_id IS NOT NULL');
// @todo remove/move LP/Link shortcuts.
$this->addSql('DELETE FROM c_tool WHERE tool_id = 0 OR tool_id IS NULL');
if (!$table->hasForeignKey('FK_845665808F7B22CC')) {
$this->addSql('ALTER TABLE c_tool ADD CONSTRAINT FK_845665808F7B22CC FOREIGN KEY (tool_id) REFERENCES tool (id)');
}
if (!$table->hasIndex('IDX_845665808F7B22CC')) {
$this->addSql('CREATE INDEX IDX_845665808F7B22CC ON c_tool (tool_id)');
}
if (!$table->hasColumn('resource_node_id')) {
$this->addSql('ALTER TABLE c_tool ADD resource_node_id INT DEFAULT NULL');
}
if (!$table->hasForeignKey('FK_845665801BAD783F')) {
$this->addSql(
'ALTER TABLE c_tool ADD CONSTRAINT FK_845665801BAD783F FOREIGN KEY (resource_node_id) REFERENCES resource_node (id) ON DELETE CASCADE'
);
}
if (!$table->hasIndex('IDX_845665808F7B22CC')) {
$this->addSql('CREATE INDEX IDX_845665808F7B22CC ON c_tool (tool_id)');
}
if (!$table->hasIndex('UNIQ_845665801BAD783F')) {
$this->addSql('CREATE UNIQUE INDEX UNIQ_845665801BAD783F ON c_tool (resource_node_id)');
}

@ -33,6 +33,7 @@ final class Version20201212114910 extends AbstractMigrationChamilo
$userList = [];
// Adding first admin as main creator also adding to the resource node tree.
$admin = $this->getAdmin();
$admin->addRole('ROLE_ADMIN');
$adminId = $admin->getId();
$userList[$adminId] = $admin;

@ -130,7 +130,7 @@ final class Version20201212195011 extends AbstractMigrationChamilo
$admin = $this->getAdmin();
$tool->setParent($course);
$toolRepo->addResourceNode($tool, $admin, $course);
$newVisibility = 1 === (int) $toolData['visibility'] ? ResourceLink::VISIBILITY_PUBLISHED : ResourceLink::VISIBILITY_PENDING;
$newVisibility = 1 === (int) $toolData['visibility'] ? ResourceLink::VISIBILITY_PUBLISHED : ResourceLink::VISIBILITY_DRAFT;
$tool->addCourseLink($course, $session, null, $newVisibility);
$em->persist($tool);
if (($counter % $batchSize) === 0) {

@ -0,0 +1,102 @@
<?php
/* For licensing terms, see /license.txt */
declare(strict_types=1);
namespace Chamilo\CoreBundle\Migrations\Schema\V200;
use Chamilo\CoreBundle\Entity\ResourceLink;
use Chamilo\CoreBundle\Entity\User;
use Chamilo\CoreBundle\Migrations\AbstractMigrationChamilo;
use Chamilo\CourseBundle\Entity\CCalendarEvent;
use DateTime;
use DateTimeZone;
use Doctrine\DBAL\Schema\Schema;
class Version20240323181500 extends AbstractMigrationChamilo
{
public function getDescription(): string
{
return 'Migrate sys_calendar to c_calendar_event';
}
public function up(Schema $schema): void
{
$em = $this->getEntityManager();
$sysCalendars = $this->connection->fetchAllAssociative('SELECT * FROM sys_calendar');
$utc = new DateTimeZone('UTC');
$admin = $this->getAdmin();
foreach ($sysCalendars as $sysCalendar) {
$calendarEvent = $this->createCCalendarEvent(
$sysCalendar['title'] ?: '-',
$sysCalendar['content'],
$sysCalendar['start_date'] ? new DateTime($sysCalendar['start_date'], $utc) : null,
$sysCalendar['end_date'] ? new DateTime($sysCalendar['end_date'], $utc) : null,
(bool) $sysCalendar['all_day'],
$sysCalendar['color'] ?? '',
$admin
);
$em->persist($calendarEvent);
$this->addGlobalResourceLinkToNode($em, $calendarEvent->getResourceNode());
}
$em->flush();
}
private function createCCalendarEvent(
string $title,
string $content,
?DateTime $startDate,
?DateTime $endDate,
bool $allDay,
string $color,
User $creator
): CCalendarEvent {
$calendarEvent = new CCalendarEvent();
$calendarEvent
->setTitle($title)
->setContent($content)
->setStartDate($startDate)
->setEndDate($endDate)
->setAllDay($allDay)
->setColor($color)
->setCreator($creator)
->setResourceName($title)
->setParentResourceNode($creator->getResourceNode()->getId())
;
return $calendarEvent;
}
private function addGlobalResourceLinkToNode($em, $resourceNode): void
{
$globalLink = new ResourceLink();
$globalLink->setCourse(null)
->setSession(null)
->setGroup(null)
->setUser(null);
$alreadyHasGlobalLink = false;
foreach ($resourceNode->getResourceLinks() as $existingLink) {
if (null === $existingLink->getCourse() && null === $existingLink->getSession() &&
null === $existingLink->getGroup() && null === $existingLink->getUser()) {
$alreadyHasGlobalLink = true;
break;
}
}
if (!$alreadyHasGlobalLink) {
$resourceNode->addResourceLink($globalLink);
$em->persist($globalLink);
}
}
public function down(Schema $schema): void
{
// Down migration is not defined, as data migration cannot be easily reverted
}
}

@ -0,0 +1,29 @@
<?php
/* For licensing terms, see /license.txt */
declare(strict_types=1);
namespace Chamilo\CoreBundle\Migrations\Schema\V200;
use Chamilo\CoreBundle\Migrations\AbstractMigrationChamilo;
use Doctrine\DBAL\Schema\Schema;
final class Version20240323222700 extends AbstractMigrationChamilo
{
public function getDescription(): string
{
return 'Remove the sys_calendar table';
}
public function up(Schema $schema): void
{
$this->addSql('DROP TABLE IF EXISTS sys_calendar');
}
public function down(Schema $schema): void
{
if (!$schema->hasTable('sys_calendar')) {
$this->addSql('CREATE TABLE sys_calendar (id INT AUTO_INCREMENT NOT NULL, title VARCHAR(255) NOT NULL, content LONGTEXT DEFAULT NULL, start_date DATETIME DEFAULT NULL, end_date DATETIME DEFAULT NULL, access_url_id INT DEFAULT NULL, all_day INT NOT NULL, color VARCHAR(20) DEFAULT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
}
}
}

@ -1,19 +0,0 @@
<?php
declare(strict_types=1);
/* For licensing terms, see /license.txt */
namespace Chamilo\CoreBundle\Repository;
use Chamilo\CoreBundle\Entity\SysCalendar;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
class SysCalendarRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, SysCalendar::class);
}
}

@ -0,0 +1,15 @@
<?php
/* For licensing terms, see /license.txt */
declare(strict_types=1);
namespace Chamilo\CoreBundle\Tool;
abstract class AbstractPlugin extends AbstractCourseTool implements ToolInterface
{
public function getCategory(): string
{
return 'plugin';
}
}

@ -6,7 +6,6 @@ declare(strict_types=1);
namespace Chamilo\CoreBundle\Tool;
use Sylius\Bundle\SettingsBundle\Schema\SchemaInterface;
use Symfony\Component\Serializer\Annotation\Groups;
abstract class AbstractTool
@ -15,17 +14,16 @@ abstract class AbstractTool
protected string $title;
#[Groups(['ctool:read'])]
protected string $titleToShow = '';
protected string $titleToShow;
#[Groups(['ctool:read'])]
protected string $icon = '';
#[Groups(['ctool:read'])]
protected string $category = '';
protected string $link;
protected string $image;
protected string $admin;
protected ?SchemaInterface $settings = null;
protected array $resourceTypes = [];
/**
@ -40,40 +38,12 @@ abstract class AbstractTool
*/
protected string $scope;
abstract public function getCategory(): string;
abstract public function getLink(): string;
/*public function __construct(
string $title,
string $category,
string $link,
?SchemaInterface $settings = null,
?array $resourceTypes = []
) {
$this->title = $title;
$this->titleToShow = $title;
$this->category = $category;
$this->link = $link;
$this->image = $title.'.png';
$this->settings = $settings;
$this->resourceTypes = $resourceTypes;
$this->icon = 'mdi-crop-square';
}*/
public function isCourseTool(): bool
{
return false;
}
public function isGlobal(): bool
{
return true;
}
public function getTitle(): string
{
return $this->title;
}
abstract public function getTitle(): string;
public function getTarget(): string
{
@ -110,23 +80,9 @@ abstract class AbstractTool
return $this->resourceTypes;
}
public function setResourceTypes(?array $resourceTypes): self
{
$this->resourceTypes = $resourceTypes;
return $this;
}
public function getTitleToShow(): string
{
// return $this->getTitle();
return ucfirst(str_replace('_', ' ', $this->getTitle()));
}
public function setTitleToShow(string $titleToShow): self
{
$this->titleToShow = $titleToShow;
return $this;
}
}

@ -0,0 +1,30 @@
<?php
/* For licensing terms, see /license.txt */
declare(strict_types=1);
namespace Chamilo\CoreBundle\Tool;
class CustomCertificate extends AbstractPlugin
{
public function getTitle(): string
{
return 'customcertificate';
}
public function getLink(): string
{
return '/plugin/customcertificate/start.php';
}
public function getIcon(): string
{
return 'mdi-certificate-outline';
}
public function getTitleToShow(): string
{
return 'Custom certificate';
}
}

@ -0,0 +1,29 @@
<?php
/* For licensing terms, see /license.txt */
declare(strict_types=1);
namespace Chamilo\CoreBundle\Tool;
class NotebookTeacher extends AbstractPlugin
{
public function getTitle(): string
{
return 'notebookteacher';
}
public function getLink(): string
{
return '/plugin/notebookteacher/start.php';
}
public function getIcon(): string
{
return 'mdi-note-edit';
}
public function getTitleToShow(): string
{
return 'Teacher notes';
}
}

@ -0,0 +1,25 @@
<?php
/* For licensing terms, see /license.txt */
declare(strict_types=1);
namespace Chamilo\CoreBundle\Tool;
class Positioning extends AbstractPlugin
{
public function getTitle(): string
{
return 'positioning';
}
public function getLink(): string
{
return '/plugin/positioning/start.php';
}
public function getIcon(): string
{
return 'mdi-radar';
}
}

@ -0,0 +1,30 @@
<?php
/* For licensing terms, see /license.txt */
declare(strict_types=1);
namespace Chamilo\CoreBundle\Tool;
class Test2Pdf extends AbstractPlugin
{
public function getTitle(): string
{
return 'test2pdf';
}
public function getLink(): string
{
return '/plugin/test2pdf/start.php';
}
public function getIcon(): string
{
return 'mdi-file-pdf-box';
}
public function getTitleToShow(): string
{
return 'Test to Pdf (Test2Pdf)';
}
}

@ -108,8 +108,9 @@ class ToolChain
$resourceType->setTool($toolEntity);
$manager->persist($resourceType);
}
$manager->flush();
}
$manager->flush();
}
}
@ -162,8 +163,6 @@ class ToolChain
'tracking',
'course_setting',
'course_maintenance',
'bbb',
'mobidico',
];
$toolList = array_flip($toolList);
@ -188,12 +187,9 @@ class ToolChain
/** @var Tool $toolEntity */
$toolEntity = $toolRepo->findOneBy($criteria);
if ($toolEntity) {
$position = $toolList[$tool->getTitle()] + 1;
$courseTool = (new CTool())
->setTool($toolEntity)
->setTitle($tool->getTitle())
->setPosition($position)
->setVisibility($visibility)
->setParent($course)
->setCreator($course->getCreator())

@ -0,0 +1,30 @@
<?php
/* For licensing terms, see /license.txt */
declare(strict_types=1);
namespace Chamilo\CoreBundle\Tool;
class Zoom extends AbstractPlugin
{
public function getTitle(): string
{
return 'zoom';
}
public function getLink(): string
{
return 'plugin/zoom/start.php';
}
public function getIcon(): string
{
return 'mdi-video-box';
}
public function getTitleToShow(): string
{
return 'Zoom Videoconference';
}
}

@ -21,6 +21,7 @@ use Chamilo\CoreBundle\Entity\AbstractResource;
use Chamilo\CoreBundle\Entity\ResourceInterface;
use Chamilo\CoreBundle\Entity\Room;
use Chamilo\CoreBundle\Filter\CidFilter;
use Chamilo\CoreBundle\Filter\GlobalEventFilter;
use Chamilo\CoreBundle\Filter\SidFilter;
use Chamilo\CoreBundle\State\CalendarEventProvider;
use Chamilo\CoreBundle\State\CCalendarEventProcessor;
@ -67,6 +68,7 @@ use Symfony\Component\Validator\Constraints as Assert;
#[ApiFilter(filterClass: DateFilter::class, strategy: 'exclude_null')]
#[ApiFilter(filterClass: CidFilter::class)]
#[ApiFilter(filterClass: SidFilter::class)]
#[ApiFilter(GlobalEventFilter::class, properties: ["type"])]
class CCalendarEvent extends AbstractResource implements ResourceInterface, Stringable
{
public const COLOR_STUDENT_PUBLICATION = '#FF8C00';

@ -77,7 +77,6 @@ class CTool extends AbstractResource implements ResourceInterface, ResourceShowC
public function __construct()
{
$this->visibility = true;
$this->position = 0;
}
public function __toString(): string

@ -8,6 +8,7 @@ namespace Chamilo\CourseBundle\Repository;
use Chamilo\CoreBundle\Entity\AbstractResource;
use Chamilo\CoreBundle\Entity\Course;
use Chamilo\CoreBundle\Entity\ResourceLink;
use Chamilo\CoreBundle\Entity\Session;
use Chamilo\CoreBundle\Entity\User;
use Chamilo\CoreBundle\Repository\ResourceRepository;
@ -76,4 +77,35 @@ final class CCalendarEventRepository extends ResourceRepository
return $event;
}
public function determineEventType(CCalendarEvent $event): string
{
$em = $this->getEntityManager();
$queryBuilder = $em->createQueryBuilder();
$queryBuilder
->select('rl')
->from(ResourceLink::class, 'rl')
->innerJoin('rl.resourceNode', 'rn')
->where('rn.id = :resourceNodeId')
->setParameter('resourceNodeId', $event->getResourceNode()->getId());
$resourceLinks = $queryBuilder->getQuery()->getResult();
foreach ($resourceLinks as $link) {
if (null === $link->getCourse() && null === $link->getSession() && null === $link->getGroup() && null === $link->getUser()) {
return 'global';
}
if (null !== $link->getCourse()) {
return 'course';
}
if (null !== $link->getSession()) {
return 'session';
}
}
return 'personal';
}
}

Loading…
Cancel
Save