Merge pull request #4668 from AngelFQC/BT20637

Calendar: Add agenda_event_subscriptions configuration setting
pull/4686/head
Nicolas Ducoulombier 3 years ago committed by GitHub
commit 9c92a5a70e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 18
      main/calendar/agenda.php
  2. 47
      main/calendar/agenda_js.php
  3. 32
      main/inc/ajax/agenda.ajax.php
  4. 375
      main/inc/lib/agenda.lib.php
  5. 4
      main/inc/lib/formvalidator/Element/SelectAjax.php
  6. 1
      main/inc/lib/template.lib.php
  7. 18
      main/install/configuration.dist.php
  8. 95
      main/template/default/agenda/month.tpl
  9. 42
      src/Chamilo/CoreBundle/Entity/AgendaEventInvitation.php
  10. 6
      src/Chamilo/CoreBundle/Entity/AgendaEventInvitee.php
  11. 14
      src/Chamilo/CoreBundle/Entity/AgendaEventSubscriber.php
  12. 36
      src/Chamilo/CoreBundle/Entity/AgendaEventSubscription.php
  13. 3
      src/Chamilo/CoreBundle/Entity/PersonalAgenda.php
  14. 11
      src/Chamilo/CoreBundle/Entity/Repository/PersonalAgendaRepository.php
  15. 48
      src/Chamilo/CoreBundle/Traits/EventSubscribableTrait.php

@ -174,6 +174,9 @@ if ($allowToEdit) {
$notificationPeriod = $_REQUEST['notification_period'] ?? [];
$careerId = $_REQUEST['career_id'] ?? 0;
$promotionId = $_REQUEST['promotion_id'] ?? 0;
$subscriptionVisibility = (int) ($_REQUEST['subscription_visibility'] ?? 0);
$subscriptionItemId = isset($_REQUEST['subscription_item']) ? (int) $_REQUEST['subscription_item'] : null;
$maxSubscriptions = (int) ($_REQUEST['max_subscriptions'] ?? 0);
$reminders = $notificationCount ? array_map(null, $notificationCount, $notificationPeriod) : [];
@ -194,7 +197,10 @@ if ($allowToEdit) {
$values['collective'] ?? false,
$reminders,
(int) $careerId,
(int) $promotionId
(int) $promotionId,
$subscriptionVisibility,
$subscriptionItemId,
$maxSubscriptions
);
if (!empty($values['repeat']) && !empty($eventId)) {
@ -254,6 +260,10 @@ if ($allowToEdit) {
$notificationPeriod = $_REQUEST['notification_period'] ?? [];
$careerId = $_REQUEST['career_id'] ?? 0;
$promotionId = $_REQUEST['promotion_id'] ?? 0;
$subscriptionVisibility = (int) ($_REQUEST['subscription_visibility'] ?? 0);
$subscriptionItemId = isset($_REQUEST['subscription_item']) ? (int) $_REQUEST['subscription_item'] : null;
$maxSubscriptions = (int) ($_REQUEST['max_subscriptions'] ?? 0);
$subscribers = $_REQUEST['subscribers'] ?? [];
$reminders = $notificationCount ? array_map(null, $notificationCount, $notificationPeriod) : [];
@ -307,7 +317,11 @@ if ($allowToEdit) {
$values['collective'] ?? false,
$reminders,
(int) $careerId,
(int) $promotionId
(int) $promotionId,
$subscriptionVisibility,
$subscriptionItemId,
$maxSubscriptions,
$subscribers
);
if (!empty($values['repeat']) && !empty($eventId)) {

@ -3,6 +3,8 @@
/* For licensing terms, see /license.txt */
// use anonymous mode when accessing this course tool
use Chamilo\CoreBundle\Entity\AgendaEventSubscription;
$use_anonymous = true;
$typeList = ['personal', 'course', 'admin', 'platform'];
// Calendar type
@ -237,6 +239,7 @@ $form = new FormValidator(
null,
['id' => 'add_event_form']
);
$form->addHeader(get_lang('Events'));
$form->addHtml('<span id="calendar_course_info"></span><div id="visible_to_input">');
@ -280,6 +283,7 @@ if ('course' === $agenda->type) {
}
if (api_get_configuration_value('agenda_collective_invitations') && 'personal' === $agenda->type) {
$form->addHeader(get_lang('Invitations'));
$form->addSelectAjax(
'invitees',
get_lang('Invitees'),
@ -292,6 +296,48 @@ if (api_get_configuration_value('agenda_collective_invitations') && 'personal' =
$form->addCheckBox('collective', '', get_lang('IsItEditableByTheInvitees'));
}
if (
api_is_platform_admin()
&& api_get_configuration_value('agenda_event_subscriptions') && 'personal' === $agenda->type
) {
$form->addHeader(get_lang('Subscriptions'));
$form->addHtml('<div id="form_subscriptions_container" style="position: relative;">');
$form->addSelect(
'subscription_visibility',
get_lang('AllowSubscriptions'),
[
AgendaEventSubscription::SUBSCRIPTION_NO => get_lang('No'),
AgendaEventSubscription::SUBSCRIPTION_ALL => get_lang('AllUsersOfThePlatform'),
AgendaEventSubscription::SUBSCRIPTION_CLASS => get_lang('UsersInsideClass'),
],
[
'onchange' => 'document.getElementById(\'max_subscriptions\').disabled = this.value == 0; document.getElementById(\'form_subscription_item\').disabled = this.value != 2',
]
);
$form->addSelectAjax(
'subscription_item',
get_lang('SocialGroup').' / '.get_lang('Class'),
[],
[
'url' => api_get_path(WEB_AJAX_PATH).'usergroup.ajax.php?a=get_class_by_keyword',
'disabled' => 'disabled',
'dropdownParent' => '#form_subscriptions_container',
]
);
$form->addNumeric(
'max_subscriptions',
['', get_lang('MaxSubscriptionsLeaveEmptyToNotLimit')],
[
'disabled' => 'disabled',
'step' => 1,
'min' => 0,
'value' => 0,
]
);
$form->addHtml('</div>');
$form->addHtml('<div id="form_subscriptions_edit" style="display: none;"></div>');
}
if (api_get_configuration_value('agenda_reminders')) {
$tpl->assign(
'agenda_reminders_js',
@ -309,6 +355,7 @@ if (api_get_configuration_value('allow_careers_in_global_agenda') && 'admin' ===
}
$form->addHtml('<div id="attachment_block" style="display: none">');
$form->addHeader(get_lang('FilesAttachment'));
$form->addLabel(get_lang('Attachment'), '<div id="attachment_text" style="display: none"></div>');
$form->addHtml('</div>');

@ -51,6 +51,8 @@ switch ($action) {
$notificationPeriod = $_REQUEST['notification_period'] ?? [];
$careerId = $_REQUEST['career_id'] ?? 0;
$promotionId = $_REQUEST['promotion_id'] ?? 0;
$subscriptionVisibility = (int) ($_REQUEST['subscription_visibility'] ?? 0);
$maxSubscriptions = (int) ($_REQUEST['max_subscriptions'] ?? 0);
$reminders = $notificationCount ? array_map(null, $notificationCount, $notificationPeriod) : [];
@ -71,7 +73,9 @@ switch ($action) {
$isCollective,
$reminders,
(int) $careerId,
(int) $promotionId
(int) $promotionId,
$subscriptionVisibility,
$maxSubscriptions
);
echo $eventId;
@ -224,6 +228,32 @@ switch ($action) {
);
}
break;
case 'event_subscribe':
if (!$agenda->getIsAllowedToEdit()) {
break;
}
if (false === Security::check_token('get')) {
exit;
}
$id = (int) explode('_', $_REQUEST['id'])[1];
$agenda->subscribeCurrentUserToEvent($id);
break;
case 'event_unsubscribe':
if (!$agenda->getIsAllowedToEdit()) {
break;
}
if (false === Security::check_token('get')) {
exit;
}
$id = (int) explode('_', $_REQUEST['id'])[1];
$agenda->unsubscribeCurrentUserToEvent($id);
break;
default:
echo '';
}

@ -4,7 +4,10 @@
use Chamilo\CoreBundle\Entity\AgendaEventInvitation;
use Chamilo\CoreBundle\Entity\AgendaEventInvitee;
use Chamilo\CoreBundle\Entity\AgendaEventSubscriber;
use Chamilo\CoreBundle\Entity\AgendaEventSubscription;
use Chamilo\CoreBundle\Entity\AgendaReminder;
use Chamilo\CoreBundle\Entity\PersonalAgenda;
use Chamilo\UserBundle\Entity\User;
/**
@ -254,13 +257,18 @@ class Agenda
bool $isCollective = false,
array $reminders = [],
int $careerId = 0,
int $promotionId = 0
int $promotionId = 0,
int $subscriptionVisibility = 0,
?int $subscriptionItemId = null,
int $maxSubscriptions = 0
) {
$start = api_get_utc_datetime($start);
$end = api_get_utc_datetime($end);
$allDay = isset($allDay) && ($allDay === 'true' || $allDay == 1) ? 1 : 0;
$id = null;
$em = Database::getManager();
switch ($this->type) {
case 'personal':
$attributes = [
@ -281,6 +289,26 @@ class Agenda
if (api_get_configuration_value('agenda_collective_invitations')) {
Agenda::saveCollectiveProperties($inviteesList, $isCollective, $id);
}
if (api_get_configuration_value('agenda_event_subscriptions') && api_is_platform_admin()) {
$personalEvent = $em->find(PersonalAgenda::class, $id);
$personalEvent
->setSubscriptionVisibility($subscriptionVisibility)
->setSubscriptionItemId($subscriptionItemId ?: null)
;
$subscription = (new AgendaEventSubscription())
->setCreator(api_get_user_entity(api_get_user_id()))
->setMaxAttendees($subscriptionVisibility > 0 ? $maxSubscriptions : 0)
;
$personalEvent
->setCollective(false)
->setInvitation($subscription)
;
$em->flush();
}
break;
case 'course':
$attributes = [
@ -865,7 +893,11 @@ class Agenda
bool $isCollective = false,
array $remindersList = [],
int $careerId = 0,
int $promotionId = 0
int $promotionId = 0,
int $subscriptionVisibility = 0,
?int $subscriptionItemId = null,
int $maxSubscriptions = 0,
array $subscribers = []
) {
$id = (int) $id;
$start = api_get_utc_datetime($start);
@ -874,6 +906,8 @@ class Agenda
$currentUserId = api_get_user_id();
$authorId = empty($authorId) ? $currentUserId : (int) $authorId;
$em = Database::getManager();
switch ($this->type) {
case 'personal':
$eventInfo = $this->get_event($id);
@ -909,6 +943,24 @@ class Agenda
if (api_get_configuration_value('agenda_collective_invitations')) {
Agenda::saveCollectiveProperties($inviteesList, $isCollective, $id);
}
if (api_get_configuration_value('agenda_event_subscriptions') && api_is_platform_admin()) {
$personalEvent = $em->find(PersonalAgenda::class, $id);
$personalEvent->setSubscriptionVisibility($subscriptionVisibility);
/** @var AgendaEventSubscription $subscription */
$subscription = $personalEvent->getInvitation();
$subscription->setMaxAttendees($subscriptionVisibility > 0 ? $maxSubscriptions : 0);
if ($personalEvent->getSubscriptionItemId() != $subscriptionItemId) {
$personalEvent->setSubscriptionItemId($subscriptionItemId ?: null);
$subscription->removeInvitees();
} else {
$subscription->removeInviteesNotInIdList($subscribers);
}
$em->flush();
}
break;
case 'course':
$eventInfo = $this->get_event($id);
@ -1306,6 +1358,80 @@ class Agenda
}
}
public function subscribeCurrentUserToEvent(int $id)
{
if (false === api_get_configuration_value('agenda_event_subscriptions')) {
return;
}
if ('personal' !== $this->type) {
return;
}
$em = Database::getManager();
$currentUser = api_get_user_entity(api_get_user_id());
$personalEvent = $em->find(PersonalAgenda::class, $id);
/** @var AgendaEventSubscription $subscription */
$subscription = $personalEvent ? $personalEvent->getInvitation() : null;
if (!$subscription) {
return;
}
if ($subscription->getInvitees()->count() >= $subscription->getMaxAttendees()
&& $subscription->getMaxAttendees() > 0
) {
return;
}
if (AgendaEventSubscription::SUBSCRIPTION_CLASS === $personalEvent->getSubscriptionVisibility()) {
$objGroup = new UserGroup();
$groupList = $objGroup->getUserGroupListByUser($currentUser->getId(), UserGroup::NORMAL_CLASS);
$groupIdList = array_column($groupList, 'id');
if (!in_array($personalEvent->getSubscriptionItemId(), $groupIdList)) {
return;
}
}
$subscriber = (new AgendaEventSubscriber())
->setUser($currentUser)
;
$subscription->addInvitee($subscriber);
$em->flush();
}
public function unsubscribeCurrentUserToEvent(int $id)
{
if (false === api_get_configuration_value('agenda_event_subscriptions')) {
return;
}
if ('personal' !== $this->type) {
return;
}
$em = Database::getManager();
$currentUser = api_get_user_entity(api_get_user_id());
$personalEvent = $em->find(PersonalAgenda::class, $id);
/** @var AgendaEventSubscription $subscription */
$subscription = $personalEvent ? $personalEvent->getInvitation() : null;
if (!$subscription) {
return;
}
$subscription->removeInviteeUser($currentUser);
$em->flush();
}
/**
* Get agenda events.
*
@ -1759,57 +1885,114 @@ class Agenda
$endCondition = '';
$agendaCollectiveInvitations = api_get_configuration_value('agenda_collective_invitations');
$agendaEventSubscriptions = api_get_configuration_value('agenda_event_subscriptions');
$userIsAdmin = api_is_platform_admin();
$queryParams = [];
if ($start !== 0) {
$startDate = api_get_utc_datetime($start, true, true);
$startCondition = "AND date >= '".$startDate->format('Y-m-d H:i:s')."'";
$queryParams['start_date'] = api_get_utc_datetime($start, true, true);
$startCondition = "AND pa.date >= :start_date";
}
if ($end !== 0) {
$endDate = api_get_utc_datetime($end, false, true);
$endCondition = "AND (enddate <= '".$endDate->format('Y-m-d H:i:s')."' OR enddate IS NULL)";
$queryParams['end_date'] = api_get_utc_datetime($end, false, true);
$endCondition = "AND (pa.enddate <= :end_date OR pa.enddate IS NULL)";
}
$user_id = api_get_user_id();
$sql = "SELECT * FROM ".$this->tbl_personal_agenda."
WHERE user = $user_id $startCondition $endCondition";
$queryParams['user_id'] = $user_id;
$userCondition = "pa.user = :user_id";
$objGroup = new UserGroup();
if ($agendaEventSubscriptions) {
$groupList = $objGroup->getUserGroupListByUser($user_id, UserGroup::NORMAL_CLASS);
$userCondition = "(
$userCondition
OR (
pa.subscriptionVisibility = ".AgendaEventSubscription::SUBSCRIPTION_ALL;
if ($groupList) {
$userCondition .= "
OR (
pa.subscriptionVisibility = ".AgendaEventSubscription::SUBSCRIPTION_CLASS."
AND pa.subscriptionItemId IN (".implode(', ', array_column($groupList, 'id')).")
)
";
}
$userCondition .= "
)
)
";
}
$sql = "SELECT pa FROM ChamiloCoreBundle:PersonalAgenda AS pa WHERE $userCondition $startCondition $endCondition";
$result = Database::getManager()
->createQuery($sql)
->setParameters($queryParams)
->getResult();
$result = Database::query($sql);
$my_events = [];
if (Database::num_rows($result)) {
while ($row = Database::fetch_array($result, 'ASSOC')) {
/** @var PersonalAgenda $row */
foreach ($result as $row) {
$event = [];
$event['id'] = 'personal_'.$row['id'];
$event['title'] = $row['title'];
$event['id'] = 'personal_'.$row->getId();
$event['title'] = $row->getTitle();
$event['className'] = 'personal';
$event['borderColor'] = $event['backgroundColor'] = $this->event_personal_color;
$event['editable'] = true;
$event['editable'] = $user_id === (int) $row->getUser();
$event['sent_to'] = get_lang('Me');
$event['type'] = 'personal';
if (!empty($row['date'])) {
$event['start'] = $this->formatEventDate($row['date']);
$event['start_date_localtime'] = api_get_local_time($row['date']);
if (!empty($row->getDate())) {
$event['start'] = $this->formatEventDate($row->getDate());
$event['start_date_localtime'] = api_get_local_time($row->getDate());
}
if (!empty($row['enddate'])) {
$event['end'] = $this->formatEventDate($row['enddate']);
$event['end_date_localtime'] = api_get_local_time($row['enddate']);
if (!empty($row->getEnddate())) {
$event['end'] = $this->formatEventDate($row->getEnddate());
$event['end_date_localtime'] = api_get_local_time($row->getEnddate());
}
$event['description'] = $row['text'];
$event['allDay'] = isset($row['all_day']) && $row['all_day'] == 1 ? $row['all_day'] : 0;
$event['description'] = $row->getText();
$event['allDay'] = $row->getAllDay();
$event['parent_event_id'] = 0;
$event['has_children'] = 0;
if ($agendaCollectiveInvitations) {
$event['collective'] = (bool) $row['collective'];
$event['invitees'] = self::getInviteesForPersonalEvent($row['id']);
if ($agendaCollectiveInvitations || $agendaEventSubscriptions) {
$subscription = $row->getInvitation();
if ($subscription instanceof AgendaEventSubscription) {
$subscribers = $subscription->getInvitees();
$event['subscription_visibility'] = $row->getSubscriptionVisibility();
$event['max_subscriptions'] = $subscription->getMaxAttendees();
$event['can_subscribe'] = $subscribers->count() < $subscription->getMaxAttendees()
|| $subscription->getMaxAttendees() === 0;
$event['user_is_subscribed'] = $subscription->hasUserAsInvitee(api_get_user_entity($user_id));
$event['count_subscribers'] = $subscribers->count();
if ($userIsAdmin) {
$event['subscribers'] = self::getInviteesForPersonalEvent($row->getId(), AgendaEventSubscriber::class);
}
if (AgendaEventSubscription::SUBSCRIPTION_CLASS === $row->getSubscriptionVisibility()) {
$groupInfo = $objGroup->get($row->getSubscriptionItemId());
$event['usergroup'] = $groupInfo['name'];
}
} else {
$event['collective'] = $row->isCollective();
$event['invitees'] = self::getInviteesForPersonalEvent($row->getId());
}
}
$my_events[] = $event;
$this->events[] = $event;
}
}
if ($agendaCollectiveInvitations) {
$this->loadEventsAsInvitee(
@ -1837,13 +2020,21 @@ class Agenda
return $my_events;
}
public static function getInviteesForPersonalEvent($eventId): array
public static function getInviteesForPersonalEvent($eventId, $type = AgendaEventInvitee::class): array
{
$em = Database::getManager();
$event = $em->find('ChamiloCoreBundle:PersonalAgenda', $eventId);
$inviteeRepo = $em->getRepository('ChamiloCoreBundle:AgendaEventInvitee');
$invitees = $inviteeRepo->findByInvitation($event->getInvitation());
$invitation = $event->getInvitation();
if ($invitation instanceof AgendaEventSubscription
&& AgendaEventInvitee::class === $type
) {
return [];
}
$inviteeRepo = $em->getRepository($type);
$invitees = $inviteeRepo->findByInvitation($invitation);
$inviteeList = [];
@ -2680,6 +2871,9 @@ class Agenda
$action = isset($params['action']) ? Security::remove_XSS($params['action']) : null;
$id = isset($params['id']) ? (int) $params['id'] : 0;
$em = Database::getManager();
$personalEvent = 'personal' === $this->type && $id ? $em->find('ChamiloCoreBundle:PersonalAgenda', $id) : null;
$url = api_get_self().'?action='.$action.'&id='.$id.'&type='.$this->type;
if ($this->type == 'course') {
$url = api_get_self().'?'.api_get_cidreq().'&action='.$action.'&id='.$id.'&type='.$this->type;
@ -2894,16 +3088,15 @@ class Agenda
$agendaCollectiveInvitations = api_get_configuration_value('agenda_collective_invitations');
if ($agendaCollectiveInvitations && 'personal' === $this->type) {
$em = Database::getManager();
$invitees = [];
$isCollective = false;
$allowInvitees = true;
if ($id) {
$event = $em->find('ChamiloCoreBundle:PersonalAgenda', $id);
$eventInvitation = $event->getInvitation();
if ($personalEvent) {
$eventInvitation = $personalEvent->getInvitation();
$allowInvitees = !$eventInvitation instanceof AgendaEventSubscription;
if ($eventInvitation) {
if ($eventInvitation && $allowInvitees) {
foreach ($eventInvitation->getInvitees() as $invitee) {
$inviteeUser = $invitee->getUser();
@ -2911,9 +3104,10 @@ class Agenda
}
}
$isCollective = $event->isCollective();
$isCollective = $personalEvent->isCollective();
}
if ($allowInvitees) {
$form->addSelectAjax(
'invitees',
get_lang('Invitees'),
@ -2924,13 +3118,15 @@ class Agenda
]
);
$form->addCheckBox('collective', '', get_lang('IsItEditableByTheInvitees'));
$form->addHtml('<hr>');
$params['invitees'] = array_keys($invitees);
$params['collective'] = $isCollective;
}
}
if (api_get_configuration_value('agenda_reminders')) {
$form->addHtml('<hr><div id="notification_list">');
$form->addHtml('<div id="notification_list">');
if ($id) {
$this->addFieldsForRemindersToForm($id, $form);
@ -2941,6 +3137,83 @@ class Agenda
$form->addHtml('<hr>');
}
if (api_is_platform_admin()
&& true === api_get_configuration_value('agenda_event_subscriptions')
) {
$form->addHtml('<hr>');
$form->addSelect(
'subscription_visibility',
get_lang('AllowSubscriptions'),
[
AgendaEventSubscription::SUBSCRIPTION_NO => get_lang('No'),
AgendaEventSubscription::SUBSCRIPTION_ALL => get_lang('AllUsersOfThePlatform'),
AgendaEventSubscription::SUBSCRIPTION_CLASS => get_lang('UsersInsideClass'),
]
);
$slctItem = $form->addSelectAjax(
'subscription_item',
get_lang('SocialGroup').' / '.get_lang('Class'),
[],
[
'url' => api_get_path(WEB_AJAX_PATH).'usergroup.ajax.php?a=get_class_by_keyword',
'disabled' => 'disabled',
]
);
$form->addNumeric(
'max_subscriptions',
['', get_lang('MaxSubscriptionsLeaveEmptyToNotLimit')],
[
'disabled' => 'disabled',
'step' => 1,
'min' => 0,
'value' => 0,
]
);
$form->addHtml("<script>
$(function () {
$('#add_event_subscription_visibility')
.on('change', function () {
$('#max_subscriptions').prop('disabled', this.value == 0);
$('#add_event_subscription_item').prop('disabled', this.value != 2);
})
.trigger('change');
})
</script>
");
if ($personalEvent) {
$subscribers = self::getInviteesForPersonalEvent($personalEvent->getId(), AgendaEventSubscriber::class);
$subscribers = array_combine(
array_column($subscribers, 'id'),
array_column($subscribers, 'name')
);
$params['subscribers'] = array_keys($subscribers);
$form->addSelect(
'subscribers',
get_lang('Subscribers'),
$subscribers,
['multiple' => 'multiple']
);
/** @var AgendaEventSubscription $subscription */
$subscription = $personalEvent->getInvitation();
$params['max_subscriptions'] = $subscription->getMaxAttendees();
$groupId = $personalEvent->getSubscriptionItemId();
if ($groupId) {
$objUserGroup = new UserGroup();
$groupInfo = $objUserGroup->get($groupId);
$slctItem->addOption($groupInfo['name'], $groupId);
}
}
}
if (api_get_configuration_value('allow_careers_in_global_agenda') && 'admin' === $this->type) {
Career::addCareerFieldsToForm($form);
$form->addHtml('<hr>');
@ -4589,10 +4862,15 @@ class Agenda
*/
public function formatEventDate($utcTime)
{
if ($utcTime instanceof DateTime) {
$eventDate = $utcTime;
} else {
$utcTimeZone = new DateTimeZone('UTC');
$eventDate = new DateTime($utcTime, $utcTimeZone);
}
$platformTimeZone = new DateTimeZone(api_get_timezone());
$eventDate = new DateTime($utcTime, $utcTimeZone);
$eventDate->setTimezone($platformTimeZone);
return $eventDate->format(DateTime::ISO8601);
@ -4609,25 +4887,34 @@ class Agenda
$event = $em->find('ChamiloCoreBundle:PersonalAgenda', $eventId);
$invitation = $event->getInvitation();
if ($invitation instanceof AgendaEventSubscription) {
return;
}
if (!$invitation) {
$invitation = new AgendaEventInvitation();
$invitation->setCreator(api_get_user_entity(api_get_user_id()));
$event
->setCollective($isCollective)
->setInvitation($invitation)
;
$event->setInvitation($invitation);
}
$em->persist($event);
$event->setCollective($isCollective);
foreach ($inviteeUserList as $inviteeId) {
$userInvitee = api_get_user_entity($inviteeId);
if (!$invitation->hasUserAsInvitee($userInvitee)) {
$invitee = new AgendaEventInvitee();
$invitee
->setUser(api_get_user_entity($inviteeId))
->setUser($userInvitee)
->setInvitation($invitation)
;
$em->persist($invitee);
}
}
$em->flush();
}

@ -23,6 +23,8 @@ class SelectAjax extends HTML_QuickForm_select
public function toHtml()
{
$iso = api_get_language_isocode(api_get_interface_language());
$dropdownParent = $this->getAttribute('dropdownParent');
$dropdownParentCondition = $dropdownParent ? "dropdownParent: '$dropdownParent'," : '';
$formatResult = $this->getAttribute('formatResult');
$formatSelection = $this->getAttribute('formatSelection');
$formatCondition = '';
@ -93,6 +95,7 @@ class SelectAjax extends HTML_QuickForm_select
width: '$width',
minimumInputLength: '$minimumInputLength',
tags: $tags,
$dropdownParentCondition
ajax: {
url: $url,
delay: $delay,
@ -130,6 +133,7 @@ JS;
$this->removeAttribute('class');
$this->removeAttribute('url');
$this->removeAttribute('url_function');
$this->removeAttribute('dropdownParent');
$this->setAttribute('style', 'width: 100%;');
return parent::toHtml().$html;

@ -200,6 +200,7 @@ class Template
$functions = [
['name' => 'get_tutors_names', 'callable' => 'Template::returnTutorsNames'],
['name' => 'get_teachers_names', 'callable' => 'Template::returnTeachersNames'],
['name' => 'api_is_platform_admin', 'callable' => 'api_is_platform_admin'],
];
foreach ($functions as $function) {

@ -462,6 +462,24 @@ CREATE UNIQUE INDEX UNIQ_D8612460AF68C6B ON personal_agenda (agenda_event_invita
// Then add the "@" symbol to AgendaEventInvitation and AgendaEventInvitee classes in the ORM\Entity() line.
// Then uncomment the "use EventCollectiveTrait;" line in the PersonalAgenda class.
//$_configuration['agenda_collective_invitations'] = false;
// It allows to other users to subscribe for events.
// Requires enable agenda_collective_invitations before.
// Requires DB changes:
/*
ALTER TABLE personal_agenda ADD subscription_visibility INT DEFAULT 0 NOT NULL, ADD subscription_item_id INT DEFAULT NULL;
ALTER TABLE agenda_event_invitee ADD type VARCHAR(255) NOT NULL;
ALTER TABLE agenda_event_invitation ADD type VARCHAR(255) NOT NULL, ADD max_attendees INT DEFAULT 0;
UPDATE agenda_event_invitation SET type = 'invitation';
UPDATE agenda_event_invitee SET type = 'invitee';
*/
// Then uncomment the "use EventSubscribableTrait;" line in the PersonalAgenda class.
// Then add the "@" symbol in ORM\InheritanceType, ORM\DiscriminatorColumn and ORM\DiscriminatorMap lines in the AgendaEventInvitation class.
// Then add the "@" symbol in @ORM\Entity line in the AgendaEventSubscription class.
// Then add the "@" symbol in ORM\InheritanceType, ORM\DiscriminatorColumn and ORM\DiscriminatorMap lines in the AgendaEventInvitee class.
// Then add the "@" symbol in @ORM\Entity line in the AgendaEventSubscriber class.
//$_configuration['agenda_event_subscriptions'] = false;
// Enable reminders for agenda events. Requires database changes:
/*
CREATE TABLE agenda_reminder (id BIGINT AUTO_INCREMENT NOT NULL, type VARCHAR(255) NOT NULL, event_id INT NOT NULL, date_interval VARCHAR(255) NOT NULL COMMENT '(DC2Type:dateinterval)', sent TINYINT(1) NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB;

@ -1,4 +1,5 @@
{% set agenda_collective_invitations = 'agenda_collective_invitations'|api_get_configuration_value %}
{% set agenda_event_subscriptions = 'agenda_event_subscriptions'|api_get_configuration_value %}
{% set agenda_reminders = 'agenda_reminders'|api_get_configuration_value %}
{% set career_in_global_events = 'allow_careers_in_global_agenda'|api_get_configuration_value %}
@ -340,6 +341,15 @@ $(function() {
//Reset the CKEditor content that persist in memory
CKEDITOR.instances['content'].setData('');
allFields.removeClass("ui-state-error");
$('#add_event_form').get(0).reset();
{% if agenda_event_subscriptions and 'personal' == type and api_is_platform_admin() %}
$('#form_subscription_visibility').trigger('change').selectpicker('refresh');
$('#form_subscriptions_container').show('');
$('#form_subscriptions_edit').hide().html('');
{% endif %}
$("#dialog-form").dialog("open");
$("#dialog-form").dialog({
buttons: {
@ -582,6 +592,13 @@ $(function() {
}
{% endif %}
{% if agenda_event_subscriptions and 'personal' == type and api_is_platform_admin() %}
$('#form_subscriptions_container').hide();
$('#form_subscriptions_edit')
.html(showSubcriptionsContainer(calEvent))
.show();
{% endif %}
{% if agenda_reminders %}
$('#notification_list').html('').next('.form-group').hide();
@ -941,6 +958,7 @@ $(function() {
};
{% if agenda_collective_invitations and 'personal' == type %}
if (!calEvent.subscription_visibility) {
buttons['{{ "Delete"|get_lang }}'] = function () {
$.ajax({
url: delete_url,
@ -954,6 +972,37 @@ $(function() {
}
});
};
}
{% endif %}
{% if agenda_event_subscriptions and 'personal' == type %}
$('#simple_subscriptions').html(showSubcriptionsContainer(calEvent));
if (calEvent.subscription_visibility > 0) {
if (calEvent.user_is_subscribed) {
buttons["{{ 'Unsubscribe'|get_lang }}"] = function () {
$.ajax({
url: '{{ web_agenda_ajax_url }}&a=event_unsubscribe&id=' + calEvent.id,
success:function() {
calendar.fullCalendar('refetchEvents');
//calendar.fullCalendar('rerenderEvents');
$("#simple-dialog-form").dialog('close');
}
});
};
} else if (calEvent.can_subscribe) {
buttons["{{ 'Subscribe'|get_lang }}"] = function () {
$.ajax({
url: '{{ web_agenda_ajax_url }}&a=event_subscribe&id=' + calEvent.id,
success:function() {
calendar.fullCalendar('refetchEvents');
//calendar.fullCalendar('rerenderEvents');
$("#simple-dialog-form").dialog('close');
}
});
}
}
}
{% endif %}
if ('session_subscription' === calEvent.type) {
@ -1004,6 +1053,48 @@ $(function() {
});
{{ agenda_reminders_js }}
function showSubcriptionsContainer (calEvent) {
if ((calEvent.invitees && calEvent.invitees.length)
|| !calEvent.subscription_visibility
) {
return '';
}
var html = '';
html += '<dl class="dl-horizontal">';
html += "<dt>{{ 'AllowSubscriptions'|get_lang }}</dt>";
html += '<dd>';
if (1 === calEvent.subscription_visibility) {
html += "{{ 'AllUsersOfThePlatform'|get_lang }}";
}
if (2 === calEvent.subscription_visibility) {
html += "{{ 'UsersInsideClass'|get_lang }}<br>" + calEvent.usergroup;
}
html += '</dd>';
if (calEvent.max_subscriptions) {
html += "<dt>{{ 'MaxSubscriptions'|get_lang }}</dt>";
html += '<dd>' + calEvent.max_subscriptions + '</dd>';
}
html += "<dt>{{ 'Subscriptions'|get_lang }}</dt><dd>" + calEvent.count_subscribers + "</dd>";
if (calEvent.subscribers) {
html += '<dt>{{ 'Subscribers'|get_lang }}</dt><dd>';
html += calEvent.subscribers
.map(function (invitee) { return invitee.name; })
.join('<br>');
html += '</dd>'
}
html += '</dl>';
return html;
}
});
</script>
{{ actions_div }}
@ -1090,6 +1181,10 @@ $(function() {
</div>
</div>
{% endif %}
{% if agenda_event_subscriptions and 'personal' == type %}
<div class="form-group" id="simple_subscriptions"></div>
{% endif %}
</form>
</div>

@ -14,6 +14,12 @@ use Doctrine\ORM\Mapping as ORM;
* @ORM\Table(name="agenda_event_invitation")
* Add @ to the next lineactivating the agenda_collective_invitations configuration setting.
* ORM\Entity()
* ORM\InheritanceType("SINGLE_TABLE")
* ORM\DiscriminatorColumn(name="type", type="string")
* ORM\DiscriminatorMap({
* "invitation" = "Chamilo\CoreBundle\Entity\AgendaEventInvitation",
* "subscription" = "Chamilo\CoreBundle\Entity\AgendaEventSubscription"
* })
*/
class AgendaEventInvitation
{
@ -91,15 +97,49 @@ class AgendaEventInvitation
return $this;
}
public function removeInvitees(): self
{
$this->invitees = new ArrayCollection();
return $this;
}
public function getCreator(): User
{
return $this->creator;
}
public function setCreator(User $creator): AgendaEventInvitation
public function setCreator(User $creator): self
{
$this->creator = $creator;
return $this;
}
public function hasUserAsInvitee(User $user): bool
{
return $this->invitees->exists(
function (int $key, AgendaEventInvitee $invitee) use ($user) {
return $invitee->getUser() === $user;
}
);
}
public function removeInviteesNotInIdList(array $idList): self
{
$toRemove = [];
/** @var AgendaEventInvitee $invitee */
foreach ($this->invitees as $key => $invitee) {
if (!in_array($invitee->getUser()->getId(), $idList)) {
$toRemove[] = $key;
}
}
foreach ($toRemove as $key) {
$this->invitees->remove($key);
}
return $this;
}
}

@ -12,6 +12,12 @@ use Doctrine\ORM\Mapping as ORM;
* @ORM\Table(name="agenda_event_invitee")
* Add @ to the next lineactivating the agenda_collective_invitations configuration setting.
* ORM\Entity()
* ORM\InheritanceType("SINGLE_TABLE")
* ORM\DiscriminatorColumn(name="type", type="string")
* ORM\DiscriminatorMap({
* "invitee" = "Chamilo\CoreBundle\Entity\AgendaEventInvitee",
* "subscriber" = "Chamilo\CoreBundle\Entity\AgendaEventSubscriber"
* })
*/
class AgendaEventInvitee
{

@ -0,0 +1,14 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\CoreBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* ORM\Entity()
*/
class AgendaEventSubscriber extends AgendaEventInvitee
{
}

@ -0,0 +1,36 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\CoreBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* ORM\Entity()
*/
class AgendaEventSubscription extends AgendaEventInvitation
{
public const SUBSCRIPTION_NO = 0;
public const SUBSCRIPTION_ALL = 1;
public const SUBSCRIPTION_CLASS = 2;
/**
* @var int
*
* @ORM\Column(name="max_attendees", type="integer", nullable=false, options={"default": 0})
*/
protected $maxAttendees = 0;
public function getMaxAttendees(): int
{
return $this->maxAttendees;
}
public function setMaxAttendees(int $maxAttendees): self
{
$this->maxAttendees = $maxAttendees;
return $this;
}
}

@ -4,6 +4,7 @@
namespace Chamilo\CoreBundle\Entity;
use Chamilo\CoreBundle\Traits\EventCollectiveTrait;
use Chamilo\CoreBundle\Traits\EventSubscribableTrait;
use Doctrine\ORM\Mapping as ORM;
/**
@ -17,6 +18,8 @@ class PersonalAgenda
{
// Uncomment next line when activating the agenda_collective_invitations configuration setting.
//use EventCollectiveTrait;
// Uncomment next line when activating the agenda_event_subscriptions configuration setting.
//use EventSubscribableTrait;
/**
* @var int

@ -4,6 +4,7 @@
namespace Chamilo\CoreBundle\Entity\Repository;
use Chamilo\CoreBundle\Entity\AgendaEventSubscription;
use Chamilo\CoreBundle\Entity\PersonalAgenda;
use Chamilo\UserBundle\Entity\User;
use Doctrine\ORM\EntityRepository;
@ -25,6 +26,16 @@ class PersonalAgendaRepository extends EntityRepository
)
;
if (api_get_configuration_value('agenda_event_subscriptions')) {
$qb
->andWhere(
$qb->expr()->not(
$qb->expr()->isInstanceOf('i', AgendaEventSubscription::class)
)
)
;
}
$params = [
'user' => $user,
];

@ -0,0 +1,48 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\CoreBundle\Traits;
use Doctrine\ORM\Mapping as ORM;
trait EventSubscribableTrait
{
/**
* @var int
*
* @ORM\Column(name="subscription_visibility", type="integer", options={"default": 0})
*/
protected $subscriptionVisibility = 0;
/**
* @var int
*
* @ORM\Column(name="subscription_item_id", type="integer", nullable=true)
*/
protected $subscriptionItemId = null;
public function getSubscriptionVisibility(): int
{
return $this->subscriptionVisibility;
}
public function setSubscriptionVisibility(int $subscriptionVisibility): self
{
$this->subscriptionVisibility = $subscriptionVisibility;
return $this;
}
public function getSubscriptionItemId(): ?int
{
return $this->subscriptionItemId;
}
public function setSubscriptionItemId(?int $subscriptionItemId): self
{
$this->subscriptionItemId = $subscriptionItemId;
return $this;
}
}
Loading…
Cancel
Save