public/plugin/advanced_subscription/src/AdvancedSubscriptionPlugin.php
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Entity\Session;
use Chamilo\CoreBundle\Framework\Container;
use Chamilo\CoreBundle\Hook\HookAdminBlock;
use Chamilo\CoreBundle\Hook\HookNotificationContent;
use Chamilo\CoreBundle\Hook\HookNotificationTitle;
use Chamilo\CoreBundle\Hook\HookWSRegistration;
use Chamilo\CoreBundle\Hook\Interfaces\HookPluginInterface;
/**
* Class AdvancedSubscriptionPlugin
* This class is used to add an advanced subscription allowing the admin to
* create user queues requesting a subscribe to a session.
*/
class AdvancedSubscriptionPlugin extends Plugin implements HookPluginInterface
{
protected $strings;
private $errorMessages;
/**
* Constructor.
*/
public function __construct()
{
$parameters = [
'yearly_cost_limit' => 'text',
'yearly_hours_limit' => 'text',
'yearly_cost_unit_converter' => 'text',
'courses_count_limit' => 'text',
'course_session_credit_year_start_date' => 'text',
'ws_url' => 'text',
'min_profile_percentage' => 'text',
'check_induction' => 'boolean',
'secret_key' => 'text',
'terms_and_conditions' => 'wysiwyg',
];
parent::__construct('1.0', 'Imanol Losada, Daniel Barreto', $parameters);
$this->errorMessages = [];
}
/**
* Instance the plugin.
*
* @staticvar null $result
*
* @return AdvancedSubscriptionPlugin
*/
public static function create()
{
static $result = null;
return $result ?: $result = new self();
}
/**
* Install the plugin.
*/
public function install()
{
$this->installDatabase();
$this->addAreaField();
$this->installHook();
}
/**
* Uninstall the plugin.
*/
public function uninstall()
{
//$setting = api_get_setting('advanced_subscription');
$setting = false;
if (!empty($setting)) {
$this->uninstallHook();
// Note: Keeping area field data is intended so it will not be removed
$this->uninstallDatabase();
}
}
/**
* Get the error messages list.
*
* @return array The message list
*/
public function getErrorMessages()
{
return $this->errorMessages;
}
/**
* Check if is allowed subscribe to open session.
*
* @param array $params WS params
*
* @return bool
*/
public function isAllowedSubscribeToOpenSession($params)
{
$self = self::create();
$wsUrl = $self->get('ws_url');
$profileCompleted = 0;
if (!empty($wsUrl)) {
$client = new SoapClient(
null,
['location' => $wsUrl, 'uri' => $wsUrl]
);
$userInfo = api_get_user_info(
$params['user_id'],
false,
false,
true
);
try {
$profileCompleted = $client->__soapCall(
'getProfileCompletionPercentage',
$userInfo['extra']['drupal_user_id']
);
} catch (\Exception $e) {
$profileCompleted = 0;
}
} elseif (isset($params['profile_completed'])) {
$profileCompleted = (float) $params['profile_completed'];
}
$profileCompletedMin = (float) $self->get('min_profile_percentage');
if ($profileCompleted < $profileCompletedMin) {
$this->errorMessages[] = sprintf(
$this->get_lang('AdvancedSubscriptionProfileIncomplete'),
$profileCompletedMin,
$profileCompleted
);
}
$vacancy = $self->getVacancy($params['session_id']);
$sessionInfo = api_get_session_info($params['session_id']);
if ($sessionInfo['nbr_users'] >= $vacancy) {
$this->errorMessages[] = sprintf(
$this->get_lang('SessionXWithoutVacancies'),
$sessionInfo['name']
);
}
return empty($this->errorMessages);
}
/**
* Return true if user is allowed to be added to queue for session subscription.
*
* @param int $userId
* @param array $params MUST have keys:
* "is_connected" Indicate if the user is online on external web
* "profile_completed" Percentage of completed profile, given by WS
* @param bool $collectErrors Optional. Default is false. Whether collect all errors or throw exeptions
*
* @throws Exception
*
* @return bool
*/
public function isAllowedToDoRequest($userId, $params = [], $collectErrors = false)
{
$plugin = self::create();
$wsUrl = $plugin->get('ws_url');
// Student always is connected
$isConnected = true;
if (!$isConnected) {
$this->errorMessages[] = $this->get_lang('AdvancedSubscriptionNotConnected');
if (!$collectErrors) {
throw new \Exception($this->get_lang('AdvancedSubscriptionNotConnected'));
}
}
$profileCompletedMin = (float) $plugin->get('min_profile_percentage');
$profileCompleted = 0;
if (is_string($wsUrl) && !empty($wsUrl)) {
$options = [
'location' => $wsUrl,
'uri' => $wsUrl,
];
$client = new SoapClient(null, $options);
$userInfo = api_get_user_info($userId);
try {
$profileCompleted = $client->__soapCall('getProfileCompletionPercentage', $userInfo['extra']['drupal_user_id']);
} catch (\Exception $e) {
$profileCompleted = 0;
}
} elseif (isset($params['profile_completed'])) {
$profileCompleted = (float) $params['profile_completed'];
}
if ($profileCompleted < $profileCompletedMin) {
$errorMessage = sprintf(
$this->get_lang('AdvancedSubscriptionProfileIncomplete'),
$profileCompletedMin,
$profileCompleted
);
$this->errorMessages[] = $errorMessage;
if (!$collectErrors) {
throw new \Exception($errorMessage);
}
}
$yearlyCostLimit = $plugin->get('yearly_cost_limit');
$maxCost = $plugin->get('yearly_cost_unit_converter');
$maxCost *= $yearlyCostLimit;
$userCost = 0;
$now = new DateTime(api_get_utc_datetime());
$newYearDate = $plugin->get('course_session_credit_year_start_date');
$newYearDate = !empty($newYearDate) ?
new \DateTime($newYearDate.$now->format('/Y')) : $now;
$extra = new ExtraFieldValue('session');
$joinSessionTable = Database::get_main_table(TABLE_MAIN_SESSION_USER).' su INNER JOIN '.
Database::get_main_table(TABLE_MAIN_SESSION).' s ON s.id = su.session_id';
$whereSessionParams = 'su.relation_type = ? AND s.access_start_date >= ? AND su.user_id = ?';
$whereSessionParamsValues = [
Session::STUDENT,
$newYearDate->format('Y-m-d'),
$userId,
];
$whereSession = [
'where' => [
$whereSessionParams => $whereSessionParamsValues,
],
];
$selectSession = 's.id AS id';
$sessions = Database::select(
$selectSession,
$joinSessionTable,
$whereSession
);
$expendedTimeMax = $plugin->get('yearly_hours_limit');
$expendedTime = 0;
if (is_array($sessions) && count($sessions) > 0) {
foreach ($sessions as $session) {
$costField = $extra->get_values_by_handler_and_field_variable($session['id'], 'cost');
$userCost += $costField['value'];
$teachingHoursField = $extra->get_values_by_handler_and_field_variable($session['id'], 'teaching_hours');
$expendedTime += $teachingHoursField['value'];
}
}
if (isset($params['sessionId'])) {
$costField = $extra->get_values_by_handler_and_field_variable($params['sessionId'], 'cost');
$userCost += $costField['value'];
$teachingHoursField = $extra->get_values_by_handler_and_field_variable($params['sessionId'], 'teaching_hours');
$expendedTime += $teachingHoursField['value'];
}
if ($maxCost <= $userCost) {
$errorMessage = sprintf(
$this->get_lang('AdvancedSubscriptionCostXLimitReached'),
$yearlyCostLimit
);
$this->errorMessages[] = $errorMessage;
if (!$collectErrors) {
throw new \Exception($errorMessage);
}
}
if ($expendedTimeMax <= $expendedTime) {
$errorMessage = sprintf(
$this->get_lang('AdvancedSubscriptionTimeXLimitReached'),
$expendedTimeMax
);
$this->errorMessages[] = $errorMessage;
if (!$collectErrors) {
throw new \Exception($errorMessage);
}
}
$expendedNumMax = $plugin->get('courses_count_limit');
$expendedNum = count($sessions);
if ($expendedNumMax <= $expendedNum) {
$errorMessage = sprintf(
$this->get_lang('AdvancedSubscriptionCourseXLimitReached'),
$expendedNumMax
);
$this->errorMessages[] = $errorMessage;
if (!$collectErrors) {
throw new \Exception($errorMessage);
}
}
$checkInduction = $plugin->get('check_induction');
$numberOfApprovedInductionSessions = $this->getApprovedInductionSessions($userId);
$completedInduction = $numberOfApprovedInductionSessions > 0;
if ('true' == $checkInduction && !$completedInduction) {
$this->errorMessages[] = $this->get_lang('AdvancedSubscriptionIncompleteInduction');
if (!$collectErrors) {
throw new \Exception($this->get_lang('AdvancedSubscriptionIncompleteInduction'));
}
}
return empty($this->errorMessages);
}
/**
* Register a user into a queue for a session.
*
* @param $userId
* @param $sessionId
*
* @return bool|int
*/
public function addToQueue($userId, $sessionId)
{
// Filter input variables
$userId = (int) $userId;
$sessionId = (int) $sessionId;
$now = api_get_utc_datetime();
$advancedSubscriptionQueueTable = Database::get_main_table(TABLE_ADVANCED_SUBSCRIPTION_QUEUE);
$attributes = [
'session_id' => $sessionId,
'user_id' => $userId,
'status' => 0,
'created_at' => $now,
'updated_at' => null,
];
return Database::insert($advancedSubscriptionQueueTable, $attributes);
}
/**
* Register message with type and status.
*
* @param $mailId
* @param $userId
* @param $sessionId
*
* @return bool|int
*/
public function saveLastMessage($mailId, $userId, $sessionId)
{
// Filter variables
$mailId = (int) $mailId;
$userId = (int) $userId;
$sessionId = (int) $sessionId;
$queueTable = Database::get_main_table(TABLE_ADVANCED_SUBSCRIPTION_QUEUE);
$attributes = [
'last_message_id' => $mailId,
'updated_at' => api_get_utc_datetime(),
];
return Database::update(
$queueTable,
$attributes,
['user_id = ? AND session_id = ?' => [$userId, $sessionId]]
);
}
/**
* Check for requirements and register user into queue.
*
* @param $userId
* @param $sessionId
* @param $params
*
* @return bool|string
*/
public function startSubscription($userId, $sessionId, $params)
{
$result = 'Params not found';
if (!empty($sessionId) && !empty($userId)) {
$plugin = self::create();
try {
if ($plugin->isAllowedToDoRequest($userId, $params)) {
$result = (bool) $plugin->addToQueue($userId, $sessionId);
} else {
throw new \Exception($this->get_lang('AdvancedSubscriptionNotMoreAble'));
}
} catch (Exception $e) {
$result = $e->getMessage();
}
}
return $result;
}
/**
* Send message for the student subscription approval to a specific session.
*
* @param int|array $studentId
* @param int $receiverId
* @param string $subject
* @param string $content
* @param int $sessionId
* @param bool $save
* @param array $fileAttachments
*
* @return bool|int
*/
public function sendMailMessage(
$studentId,
$receiverId,
$subject,
$content,
$sessionId,
$save = false,
$fileAttachments = []
) {
if (!empty($fileAttachments) &&
is_array($fileAttachments) &&
isset($fileAttachments['files']) &&
isset($fileAttachments['comments'])
) {
$mailId = MessageManager::send_message(
$receiverId,
$subject,
$content,
$fileAttachments['files'],
$fileAttachments['comments']
);
} else {
$mailId = MessageManager::send_message(
$receiverId,
$subject,
$content
);
}
if ($save && !empty($mailId)) {
// Save as sent message
if (is_array($studentId) && !empty($studentId)) {
foreach ($studentId as $student) {
$this->saveLastMessage($mailId, $student['user_id'], $sessionId);
}
} else {
$studentId = (int) $studentId;
$this->saveLastMessage($mailId, $studentId, $sessionId);
}
} elseif (!empty($mailId)) {
// Update queue row, updated_at
Database::update(
Database::get_main_table(TABLE_ADVANCED_SUBSCRIPTION_QUEUE),
[
'updated_at' => api_get_utc_datetime(),
],
[
'user_id = ? AND session_id = ?' => [$studentId, $sessionId],
]
);
}
return $mailId;
}
/**
* Check if session is open for subscription.
*
* @param $sessionId
* @param string $fieldVariable
*
* @return bool
*/
public function isSessionOpen($sessionId, $fieldVariable = 'is_open_session')
{
$extraFieldValue = new ExtraFieldValue('session');
$result = $extraFieldValue->get_values_by_handler_and_field_variable(
$sessionId,
$fieldVariable
);
$isOpen = false;
if (!empty($result)) {
$isOpen = (bool) $result['value'];
}
return $isOpen;
}
/**
* Check if user is in the session's target group based on its area.
*
* @param $userId
* @param $sessionId
* @param string $userFieldVariable
* @param string $sessionFieldVariable
*
* @return bool
*/
public function isUserInTargetGroup(
$userId,
$sessionId,
$userFieldVariable = 'area',
$sessionFieldVariable = 'target'
) {
$extraSessionFieldValue = new ExtraFieldValue('session');
$sessionTarget = $extraSessionFieldValue->get_values_by_handler_and_field_variable(
$sessionId,
$sessionFieldVariable
);
$extraUserFieldValue = new ExtraFieldValue('user');
$userArea = $extraUserFieldValue->get_values_by_handler_and_field_variable(
$userId,
$userFieldVariable
);
$isInTargetGroup = false;
if (isset($sessionTarget) && (!empty($sessionTarget)) && 'minedu' == $sessionTarget['value']) {
if ('MINEDU' == substr($userArea['value'], 0, 6)) {
$isInTargetGroup = true;
}
}
if (isset($sessionTarget) && (!empty($sessionTarget)) && 'regiones' == $sessionTarget['value']) {
if (('UGEL' == substr($userArea['value'], 0, 4)) || ('DRE' == substr($userArea['value'], 0, 3))) {
$isInTargetGroup = true;
}
}
return $isInTargetGroup;
}
/**
* Update the queue status for subscription approval rejected or accepted.
*
* @param $params
* @param $newStatus
*
* @return bool
*/
public function updateQueueStatus($params, $newStatus)
{
$newStatus = (int) $newStatus;
$res = false;
if (isset($params['queue']['id'])) {
$where = [
'id = ?' => (int) ($params['queue']['id']),
];
} elseif (isset($params['studentUserId']) && isset($params['sessionId'])) {
$where = [
'user_id = ? AND session_id = ? AND status <> ? AND status <> ?' => [
(int) ($params['studentUserId']),
(int) ($params['sessionId']),
$newStatus,
ADVANCED_SUBSCRIPTION_QUEUE_STATUS_ADMIN_APPROVED,
],
];
}
if (isset($where)) {
$res = (bool) Database::update(
Database::get_main_table(TABLE_ADVANCED_SUBSCRIPTION_QUEUE),
[
'status' => $newStatus,
'updated_at' => api_get_utc_datetime(),
],
$where
);
}
return $res;
}
/**
* Render and send mail by defined advanced subscription action.
*
* @param $data
* @param $actionType
*
* @return array
*/
public function sendMail($data, $actionType)
{
$template = new Template($this->get_lang('plugin_title'));
$template->assign('data', $data);
$templateParams = [
'user',
'student',
'students',
'superior',
'admins',
'session',
'signature',
'admin_view_url',
'acceptUrl',
'rejectUrl',
];
foreach ($templateParams as $templateParam) {
$template->assign($templateParam, $data[$templateParam]);
}
$mailIds = [];
switch ($actionType) {
case ADVANCED_SUBSCRIPTION_ACTION_STUDENT_REQUEST:
// Mail to student
$mailIds['render'] = $this->sendMailMessage(
$data['studentUserId'],
$data['student']['user_id'],
$this->get_lang('MailStudentRequest'),
$template->fetch('/advanced_subscription/views/student_notice_student.tpl'),
$data['sessionId'],
true
);
// Mail to superior
$mailIds[] = $this->sendMailMessage(
$data['studentUserId'],
$data['superior']['user_id'],
$this->get_lang('MailStudentRequest'),
$template->fetch('/advanced_subscription/views/student_notice_superior.tpl'),
$data['sessionId']
);
break;
case ADVANCED_SUBSCRIPTION_ACTION_SUPERIOR_APPROVE:
// Mail to student
$mailIds[] = $this->sendMailMessage(
$data['studentUserId'],
$data['student']['user_id'],
$this->get_lang('MailBossAccept'),
$template->fetch('/advanced_subscription/views/superior_accepted_notice_student.tpl'),
$data['sessionId'],
true
);
// Mail to superior
$mailIds['render'] = $this->sendMailMessage(
$data['studentUserId'],
$data['superior']['user_id'],
$this->get_lang('MailBossAccept'),
$template->fetch('/advanced_subscription/views/superior_accepted_notice_superior.tpl'),
$data['sessionId']
);
// Mail to admin
foreach ($data['admins'] as $adminId => $admin) {
$template->assign('admin', $admin);
$mailIds[] = $this->sendMailMessage(
$data['studentUserId'],
$adminId,
$this->get_lang('MailBossAccept'),
$template->fetch('/advanced_subscription/views/superior_accepted_notice_admin.tpl'),
$data['sessionId']
);
}
break;
case ADVANCED_SUBSCRIPTION_ACTION_SUPERIOR_DISAPPROVE:
// Mail to student
$mailIds[] = $this->sendMailMessage(
$data['studentUserId'],
$data['student']['user_id'],
$this->get_lang('MailBossReject'),
$template->fetch('/advanced_subscription/views/superior_rejected_notice_student.tpl'),
$data['sessionId'],
true
);
// Mail to superior
$mailIds['render'] = $this->sendMailMessage(
$data['studentUserId'],
$data['superior']['user_id'],
$this->get_lang('MailBossReject'),
$template->fetch('/advanced_subscription/views/superior_rejected_notice_superior.tpl'),
$data['sessionId']
);
break;
case ADVANCED_SUBSCRIPTION_ACTION_SUPERIOR_SELECT:
// Mail to student
$mailIds[] = $this->sendMailMessage(
$data['studentUserId'],
$data['student']['user_id'],
$this->get_lang('MailStudentRequestSelect'),
$template->fetch('/advanced_subscription/views/student_notice_student.tpl'),
$data['sessionId'],
true
);
// Mail to superior
$mailIds['render'] = $this->sendMailMessage(
$data['studentUserId'],
$data['superior']['user_id'],
$this->get_lang('MailStudentRequestSelect'),
$template->fetch('/advanced_subscription/views/student_notice_superior.tpl'),
$data['sessionId']
);
break;
case ADVANCED_SUBSCRIPTION_ACTION_ADMIN_APPROVE:
$fileAttachments = [];
if (api_get_plugin_setting('courselegal', 'tool_enable')) {
$courseLegal = CourseLegalPlugin::create();
$courses = SessionManager::get_course_list_by_session_id($data['sessionId']);
$course = current($courses);
$data['courseId'] = $course['id'];
$data['course'] = api_get_course_info_by_id($data['courseId']);
$termsAndConditions = $courseLegal->getData($data['courseId'], $data['sessionId']);
$termsAndConditions = $termsAndConditions['content'];
$termsAndConditions = $this->renderTemplateString($termsAndConditions, $data);
$tpl = new Template(get_lang('Terms and Conditions'));
$tpl->assign('session', $data['session']);
$tpl->assign('student', $data['student']);
$tpl->assign('sessionId', $data['sessionId']);
$tpl->assign('termsContent', $termsAndConditions);
$termsAndConditions = $tpl->fetch('/advanced_subscription/views/terms_and_conditions_to_pdf.tpl');
$pdf = new PDF();
$filename = 'terms'.sha1(rand(0, 99999));
$pdf->content_to_pdf($termsAndConditions, null, $filename, null, 'F');
$fileAttachments['file'][] = [
'name' => $filename.'.pdf',
'application/pdf' => $filename.'.pdf',
'tmp_name' => api_get_path(SYS_ARCHIVE_PATH).$filename.'.pdf',
'error' => UPLOAD_ERR_OK,
'size' => filesize(api_get_path(SYS_ARCHIVE_PATH).$filename.'.pdf'),
];
$fileAttachments['comments'][] = get_lang('Terms and Conditions');
}
// Mail to student
$mailIds[] = $this->sendMailMessage(
$data['studentUserId'],
$data['student']['user_id'],
$this->get_lang('MailAdminAccept'),
$template->fetch('/advanced_subscription/views/admin_accepted_notice_student.tpl'),
$data['sessionId'],
true,
$fileAttachments
);
// Mail to superior
$mailIds[] = $this->sendMailMessage(
$data['studentUserId'],
$data['superior']['user_id'],
$this->get_lang('MailAdminAccept'),
$template->fetch('/advanced_subscription/views/admin_accepted_notice_superior.tpl'),
$data['sessionId']
);
// Mail to admin
$adminId = $data['currentUserId'];
$template->assign('admin', $data['admins'][$adminId]);
$mailIds['render'] = $this->sendMailMessage(
$data['studentUserId'],
$adminId,
$this->get_lang('MailAdminAccept'),
$template->fetch('/advanced_subscription/views/admin_accepted_notice_admin.tpl'),
$data['sessionId']
);
break;
case ADVANCED_SUBSCRIPTION_ACTION_ADMIN_DISAPPROVE:
// Mail to student
$mailIds[] = $this->sendMailMessage(
$data['studentUserId'],
$data['student']['user_id'],
$this->get_lang('MailAdminReject'),
$template->fetch('/advanced_subscription/views/admin_rejected_notice_student.tpl'),
$data['sessionId'],
true
);
// Mail to superior
$mailIds[] = $this->sendMailMessage(
$data['studentUserId'],
$data['superior']['user_id'],
$this->get_lang('MailAdminReject'),
$template->fetch('/advanced_subscription/views/admin_rejected_notice_superior.tpl'),
$data['sessionId']
);
// Mail to admin
$adminId = $data['currentUserId'];
$template->assign('admin', $data['admins'][$adminId]);
$mailIds['render'] = $this->sendMailMessage(
$data['studentUserId'],
$adminId,
$this->get_lang('MailAdminReject'),
$template->fetch('/advanced_subscription/views/admin_rejected_notice_admin.tpl'),
$data['sessionId']
);
break;
case ADVANCED_SUBSCRIPTION_ACTION_STUDENT_REQUEST_NO_BOSS:
// Mail to student
$mailIds['render'] = $this->sendMailMessage(
$data['studentUserId'],
$data['student']['user_id'],
$this->get_lang('MailStudentRequestNoBoss'),
$template->fetch('/advanced_subscription/views/student_no_superior_notice_student.tpl'),
$data['sessionId'],
true
);
// Mail to admin
foreach ($data['admins'] as $adminId => $admin) {
$template->assign('admin', $admin);
$mailIds[] = $this->sendMailMessage(
$data['studentUserId'],
$adminId,
$this->get_lang('MailStudentRequestNoBoss'),
$template->fetch('/advanced_subscription/views/student_no_superior_notice_admin.tpl'),
$data['sessionId']
);
}
break;
case ADVANCED_SUBSCRIPTION_ACTION_REMINDER_STUDENT:
$mailIds['render'] = $this->sendMailMessage(
$data['student']['user_id'],
$data['student']['user_id'],
$this->get_lang('MailRemindStudent'),
$template->fetch('/advanced_subscription/views/reminder_notice_student.tpl'),
$data['sessionId'],
true
);
break;
case ADVANCED_SUBSCRIPTION_ACTION_REMINDER_SUPERIOR:
$mailIds['render'] = $this->sendMailMessage(
$data['students'],
$data['superior']['user_id'],
$this->get_lang('MailRemindSuperior'),
$template->fetch('/advanced_subscription/views/reminder_notice_superior.tpl'),
$data['sessionId']
);
break;
case ADVANCED_SUBSCRIPTION_ACTION_REMINDER_SUPERIOR_MAX:
$mailIds['render'] = $this->sendMailMessage(
$data['students'],
$data['superior']['user_id'],
$this->get_lang('MailRemindSuperior'),
$template->fetch('/advanced_subscription/views/reminder_notice_superior_max.tpl'),
$data['sessionId']
);
break;
case ADVANCED_SUBSCRIPTION_ACTION_REMINDER_ADMIN:
// Mail to admin
foreach ($data['admins'] as $adminId => $admin) {
$template->assign('admin', $admin);
$mailIds[] = $this->sendMailMessage(
$data['students'],
$adminId,
$this->get_lang('MailRemindAdmin'),
$template->fetch('/advanced_subscription/views/reminder_notice_admin.tpl'),
$data['sessionId']
);
}
break;
default:
break;
}
return $mailIds;
}
/**
* Count the users in queue filtered by params (sessions, status).
*
* @param array $params Input array containing the set of
* session and status to count from queue
* e.g:
* array('sessions' => array(215, 218, 345, 502),
* 'status' => array(0, 1, 2))
*
* @return int
*/
public function countQueueByParams($params)
{
$count = 0;
if (!empty($params) && is_array($params)) {
$advancedSubscriptionQueueTable = Database::get_main_table(TABLE_ADVANCED_SUBSCRIPTION_QUEUE);
$where['1 = ? '] = 1;
if (isset($params['sessions']) && is_array($params['sessions'])) {
foreach ($params['sessions'] as &$sessionId) {
$sessionId = (int) $sessionId;
}
$where['AND session_id IN ( ? ) '] = implode($params['sessions']);
}
if (isset($params['status']) && is_array($params['status'])) {
foreach ($params['status'] as &$status) {
$status = (int) $status;
}
$where['AND status IN ( ? ) '] = implode($params['status']);
}
$where['where'] = $where;
$count = Database::select('COUNT(*)', $advancedSubscriptionQueueTable, $where);
$count = $count[0]['COUNT(*)'];
}
return $count;
}
/**
* This method will call the Hook management insertHook to add Hook observer from this plugin.
*/
public function installHook()
{
$hookObserver = HookAdvancedSubscription::create();
$hookFactory = Container::$container->get('chamilo_core.hook_factory');
$hookFactory->build(HookAdminBlock::class)->attach($hookObserver);
$hookFactory->build(HookWSRegistration::class)->attach($hookObserver);
$hookFactory->build(HookNotificationContent::class)->attach($hookObserver);
$hookFactory->build(HookNotificationTitle::class)->attach($hookObserver);
}
/**
* This method will call the Hook management deleteHook to disable Hook observer from this plugin.
*/
public function uninstallHook()
{
$hookObserver = HookAdvancedSubscription::create();
$hookFactory = Container::$container->get('chamilo_core.hook_factory');
$hookFactory->build(HookAdminBlock::class)->detach($hookObserver);
$hookFactory->build(HookWSRegistration::class)->detach($hookObserver);
$hookFactory->build(HookNotificationContent::class)->detach($hookObserver);
$hookFactory->build(HookNotificationTitle::class)->detach($hookObserver);
}
/**
* Return the status from user in queue to session subscription.
*
* @param int $userId
* @param int $sessionId
*
* @return bool|int
*/
public function getQueueStatus($userId, $sessionId)
{
$userId = (int) $userId;
$sessionId = (int) $sessionId;
if (!empty($userId) && !empty($sessionId)) {
$queueTable = Database::get_main_table(TABLE_ADVANCED_SUBSCRIPTION_QUEUE);
$row = Database::select(
'status',
$queueTable,
[
'where' => [
'user_id = ? AND session_id = ?' => [$userId, $sessionId],
],
]
);
if (1 == count($row)) {
return $row[0]['status'];
} else {
return ADVANCED_SUBSCRIPTION_QUEUE_STATUS_NO_QUEUE;
}
}
return false;
}
/**
* Return the remaining vacancy.
*
* @param $sessionId
*
* @return bool|int
*/
public function getVacancy($sessionId)
{
if (!empty($sessionId)) {
$extra = new ExtraFieldValue('session');
$var = $extra->get_values_by_handler_and_field_variable(
$sessionId,
'vacancies'
);
$vacancy = (int) ($var['value']);
if (!empty($vacancy)) {
$vacancy -= $this->countQueueByParams(
[
'sessions' => [$sessionId],
'status' => [ADVANCED_SUBSCRIPTION_QUEUE_STATUS_ADMIN_APPROVED],
]
);
if ($vacancy >= 0) {
return $vacancy;
} else {
return 0;
}
}
}
return false;
}
/**
* Return the session details data from a session ID (including the extra
* fields used for the advanced subscription mechanism).
*
* @param $sessionId
*
* @return bool|mixed
*/
public function getSessionDetails($sessionId)
{
if (!empty($sessionId)) {
// Assign variables
$fieldsArray = [
'code',
'cost',
'place',
'allow_visitors',
'teaching_hours',
'brochure',
'banner',
];
$extraField = new ExtraField('session');
// Get session fields
$fieldList = $extraField->get_all([
'variable IN ( ?, ?, ?, ?, ?, ?, ? )' => $fieldsArray,
]);
// Index session fields
$fields = [];
foreach ($fieldList as $field) {
$fields[$field['id']] = $field['variable'];
}
$mergedArray = array_merge([$sessionId], array_keys($fields));
$sql = 'SELECT * FROM '.Database::get_main_table(TABLE_EXTRA_FIELD_VALUES).'
WHERE item_id = %d AND field_id IN (%d, %d, %d, %d, %d, %d, %d)';
$sql = vsprintf($sql, $mergedArray);
$sessionFieldValueList = Database::query($sql);
while ($sessionFieldValue = Database::fetch_assoc($sessionFieldValueList)) {
// Check if session field value is set in session field list
if (isset($fields[$sessionFieldValue['field_id']])) {
$var = $fields[$sessionFieldValue['field_id']];
$val = $sessionFieldValue['value'];
// Assign session field value to session
$sessionArray[$var] = $val;
}
}
$sessionArray['description'] = SessionManager::getDescriptionFromSessionId($sessionId);
if (isset($sessionArray['brochure'])) {
$sessionArray['brochure'] = api_get_path(WEB_UPLOAD_PATH).$sessionArray['brochure'];
}
if (isset($sessionArray['banner'])) {
$sessionArray['banner'] = api_get_path(WEB_UPLOAD_PATH).$sessionArray['banner'];
}
return $sessionArray;
}
return false;
}
/**
* Get status message.
*
* @param int $status
* @param bool $isAble
*
* @return string
*/
public function getStatusMessage($status, $isAble = true)
{
switch ($status) {
case ADVANCED_SUBSCRIPTION_QUEUE_STATUS_NO_QUEUE:
$message = $this->get_lang('AdvancedSubscriptionNoQueue');
if ($isAble) {
$message = $this->get_lang('AdvancedSubscriptionNoQueueIsAble');
}
break;
case ADVANCED_SUBSCRIPTION_QUEUE_STATUS_START:
$message = $this->get_lang('AdvancedSubscriptionQueueStart');
break;
case ADVANCED_SUBSCRIPTION_QUEUE_STATUS_BOSS_DISAPPROVED:
$message = $this->get_lang('AdvancedSubscriptionQueueBossDisapproved');
break;
case ADVANCED_SUBSCRIPTION_QUEUE_STATUS_BOSS_APPROVED:
$message = $this->get_lang('AdvancedSubscriptionQueueBossApproved');
break;
case ADVANCED_SUBSCRIPTION_QUEUE_STATUS_ADMIN_DISAPPROVED:
$message = $this->get_lang('AdvancedSubscriptionQueueAdminDisapproved');
break;
case ADVANCED_SUBSCRIPTION_QUEUE_STATUS_ADMIN_APPROVED:
$message = $this->get_lang('AdvancedSubscriptionQueueAdminApproved');
break;
default:
$message = sprintf($this->get_lang('AdvancedSubscriptionQueueDefault'), $status);
}
return $message;
}
/**
* Return the url to go to session.
*
* @param $sessionId
*
* @return string
*/
public function getSessionUrl($sessionId)
{
return api_get_path(WEB_CODE_PATH).'session/?session_id='.(int) $sessionId;
}
/**
* Get a url for subscribe a user in session.
*
* @param int $userId The user ID
* @param array $params Params from WS
*
* @return string
*/
public function getOpenSessionUrl($userId, $params)
{
$userIsSubscribed = SessionManager::isUserSubscribedAsStudent(
$params['session_id'],
$userId
);
if ($userIsSubscribed) {
return api_get_path(WEB_CODE_PATH)
.'session/index.php?session_id='
.(int) ($params['session_id']);
}
$params['secret_key'] = null;
$params['user_id'] = null;
$params['user_field'] = null;
$params['is_connected'] = null;
$urlParams = array_merge($params, ['user_id' => $userId]);
$url = api_get_path(WEB_PLUGIN_PATH);
$url .= 'advanced_subscription/src/open_session.php?';
$url .= http_build_query($urlParams);
return 'javascript:void(window.open(\''
.$url
.'\',\'AdvancedSubscriptionTerms\', \'toolbar=no,location=no,'
.'status=no,menubar=no,scrollbars=yes,resizable=yes,width=700px,'
.'height=600px\', \'100\' ))';
}
/**
* Return the url to enter to subscription queue to session.
*
* @param $params
*
* @return string
*/
public function getQueueUrl($params)
{
return api_get_path(WEB_PLUGIN_PATH).'advanced_subscription/ajax/advanced_subscription.ajax.php?'.
'a='.Security::remove_XSS($params['action']).'&'.
's='.(int) ($params['sessionId']).'&'.
'current_user_id='.(int) ($params['currentUserId']).'&'.
'e='.(int) ($params['newStatus']).'&'.
'u='.(int) ($params['studentUserId']).'&'.
'q='.(int) ($params['queueId']).'&'.
'is_connected=1&'.
'profile_completed='.(int) ($params['profile_completed']).'&'.
'v='.$this->generateHash($params);
}
/**
* Return the list of student, in queue used by admin view.
*
* @param int $sessionId
*
* @return array
*/
public function listAllStudentsInQueueBySession($sessionId)
{
// Filter input variable
$sessionId = (int) $sessionId;
// Assign variables
$fieldsArray = [
'target',
'publication_end_date',
'mode',
'recommended_number_of_participants',
'vacancies',
];
$sessionArray = api_get_session_info($sessionId);
$extraSession = new ExtraFieldValue('session');
$extraField = new ExtraField('session');
// Get session fields
$fieldList = $extraField->get_all([
'variable IN ( ?, ?, ?, ?, ?)' => $fieldsArray,
]);
// Index session fields
$fields = [];
foreach ($fieldList as $field) {
$fields[$field['id']] = $field['variable'];
}
$mergedArray = array_merge([$sessionId], array_keys($fields));
$sessionFieldValueList = $extraSession->get_all(
[
'item_id = ? field_id IN ( ?, ?, ?, ?, ?, ?, ? )' => $mergedArray,
]
);
foreach ($sessionFieldValueList as $sessionFieldValue) {
// Check if session field value is set in session field list
if (isset($fields[$sessionFieldValue['field_id']])) {
$var = $fields[$sessionFieldValue['field_id']];
$val = $sessionFieldValue['value'];
// Assign session field value to session
$sessionArray[$var] = $val;
}
}
$queueTable = Database::get_main_table(TABLE_ADVANCED_SUBSCRIPTION_QUEUE);
$userTable = Database::get_main_table(TABLE_MAIN_USER);
$userJoinTable = $queueTable.' q INNER JOIN '.$userTable.' u ON q.user_id = u.id';
$where = [
'where' => [
'q.session_id = ?' => [
$sessionId,
],
],
'order' => 'q.status DESC, u.lastname ASC',
];
$select = 'u.user_id, u.firstname, u.lastname, q.created_at, q.updated_at, q.status, q.id as queue_id';
$students = Database::select($select, $userJoinTable, $where);
foreach ($students as &$student) {
$status = (int) ($student['status']);
switch ($status) {
case ADVANCED_SUBSCRIPTION_QUEUE_STATUS_NO_QUEUE:
case ADVANCED_SUBSCRIPTION_QUEUE_STATUS_START:
$student['validation'] = '';
break;
case ADVANCED_SUBSCRIPTION_QUEUE_STATUS_BOSS_DISAPPROVED:
case ADVANCED_SUBSCRIPTION_QUEUE_STATUS_ADMIN_DISAPPROVED:
$student['validation'] = 'No';
break;
case ADVANCED_SUBSCRIPTION_QUEUE_STATUS_BOSS_APPROVED:
case ADVANCED_SUBSCRIPTION_QUEUE_STATUS_ADMIN_APPROVED:
$student['validation'] = 'Yes';
break;
default:
error_log(__FILE__.' '.__FUNCTION__.' Student status no detected');
}
}
$return = [
'session' => $sessionArray,
'students' => $students,
];
return $return;
}
/**
* List all session (id, title) for select input.
*
* @param int $limit
*
* @return array
*/
public function listAllSessions($limit = 100)
{
$limit = (int) $limit;
$sessionTable = Database::get_main_table(TABLE_MAIN_SESSION);
$columns = 'id, title';
$conditions = [];
if ($limit > 0) {
$conditions = [
'order' => 'title',
'limit' => $limit,
];
}
return Database::select($columns, $sessionTable, $conditions);
}
/**
* Generate security hash to check data send by url params.
*
* @param string $data
*
* @return string
*/
public function generateHash($data)
{
$key = hash('sha512', $this->get('secret_key'));
// Prepare array to have specific type variables
$dataPrepared['action'] = (string) ($data['action']);
$dataPrepared['sessionId'] = (int) ($data['sessionId']);
$dataPrepared['currentUserId'] = (int) ($data['currentUserId']);
$dataPrepared['studentUserId'] = (int) ($data['studentUserId']);
$dataPrepared['queueId'] = (int) ($data['queueId']);
$dataPrepared['newStatus'] = (int) ($data['newStatus']);
$dataPrepared = serialize($dataPrepared);
return hash('sha512', $dataPrepared.$key);
}
/**
* Verify hash from data.
*
* @param string $data
* @param string $hash
*
* @return bool
*/
public function checkHash($data, $hash)
{
return $this->generateHash($data) == $hash;
}
/**
* Copied and fixed from plugin.class.php
* Returns the "system" name of the plugin in lowercase letters.
*
* @return string
*/
public function get_name()
{
return 'advanced_subscription';
}
/**
* Return the url to show subscription terms.
*
* @param array $params
* @param int $mode
*
* @return string
*/
public function getTermsUrl($params, $mode = ADVANCED_SUBSCRIPTION_TERMS_MODE_POPUP)
{
$urlParams = [
'a' => Security::remove_XSS($params['action']),
's' => (int) ($params['sessionId']),
'current_user_id' => (int) ($params['currentUserId']),
'e' => (int) ($params['newStatus']),
'u' => (int) ($params['studentUserId']),
'q' => (int) ($params['queueId']),
'is_connected' => 1,
'profile_completed' => (int) ($params['profile_completed']),
'v' => $this->generateHash($params),
];
switch ($mode) {
case ADVANCED_SUBSCRIPTION_TERMS_MODE_POPUP:
case ADVANCED_SUBSCRIPTION_TERMS_MODE_FINAL:
$urlParams['r'] = 0;
break;
case ADVANCED_SUBSCRIPTION_TERMS_MODE_REJECT:
$urlParams['r'] = 1;
break;
}
$url = api_get_path(WEB_PLUGIN_PATH).'advanced_subscription/src/terms_and_conditions.php?';
$url .= http_build_query($urlParams);
// Launch popup
if (ADVANCED_SUBSCRIPTION_TERMS_MODE_POPUP == $mode) {
$url = 'javascript:void(window.open(\''.$url.'\',\'AdvancedSubscriptionTerms\', \'toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=700px,height=600px\', \'100\' ))';
}
return $url;
}
/**
* Return the url to get mail rendered.
*
* @param array $params
*
* @return string
*/
public function getRenderMailUrl($params)
{
return api_get_path(WEB_PLUGIN_PATH).'advanced_subscription/src/render_mail.php?'.
'q='.$params['queueId'].'&'.
'v='.$this->generateHash($params);
}
/**
* Return the last message id from queue row.
*
* @param int $studentUserId
* @param int $sessionId
*
* @return int|bool
*/
public function getLastMessageId($studentUserId, $sessionId)
{
$studentUserId = (int) $studentUserId;
$sessionId = (int) $sessionId;
if (!empty($sessionId) && !empty($studentUserId)) {
$row = Database::select(
'last_message_id',
Database::get_main_table(TABLE_ADVANCED_SUBSCRIPTION_QUEUE),
[
'where' => [
'user_id = ? AND session_id = ?' => [$studentUserId, $sessionId],
],
]
);
if (count($row) > 0) {
return $row[0]['last_message_id'];
}
}
return false;
}
/**
* Return string replacing tags "{{}}"with variables assigned in $data.
*
* @param string $templateContent
* @param array $data
*
* @return string
*/
public function renderTemplateString($templateContent, $data = [])
{
$twigString = new \Twig_Environment(new \Twig_Loader_String());
return $twigString->render(
$templateContent,
$data
);
}
/**
* addAreaField() (adds an area field if it is not already created).
*/
private function addAreaField()
{
$extraField = new ExtraField('user');
$extraFieldHandler = $extraField->get_handler_field_info_by_field_variable('area');
$areaExists = false !== $extraFieldHandler;
if (!$areaExists) {
$extraField = new ExtraField('user');
$extraField->save([
'value_type' => 1,
'variable' => 'area',
'display_text' => get_plugin_lang('Area', 'AdvancedSubscriptionPlugin'),
'default_value' => null,
'field_order' => null,
'visible_to_self' => 1,
'changeable' => 1,
'filter' => null,
]);
}
}
/**
* Create the database tables for the plugin.
*/
private function installDatabase()
{
$advancedSubscriptionQueueTable = Database::get_main_table(TABLE_ADVANCED_SUBSCRIPTION_QUEUE);
$sql = "CREATE TABLE IF NOT EXISTS $advancedSubscriptionQueueTable (".
'id int UNSIGNED NOT NULL AUTO_INCREMENT, '.
'session_id int UNSIGNED NOT NULL, '.
'user_id int UNSIGNED NOT NULL, '.
'status int UNSIGNED NOT NULL, '.
'last_message_id int UNSIGNED NOT NULL, '.
'created_at datetime NOT NULL, '.
'updated_at datetime NULL, '.
'PRIMARY KEY PK_advanced_subscription_queue (id), '.
'UNIQUE KEY UK_advanced_subscription_queue (user_id, session_id)); ';
Database::query($sql);
}
/**
* Drop the database tables for the plugin.
*/
private function uninstallDatabase()
{
/* Drop plugin tables */
$advancedSubscriptionQueueTable = Database::get_main_table(TABLE_ADVANCED_SUBSCRIPTION_QUEUE);
$sql = "DROP TABLE IF EXISTS $advancedSubscriptionQueueTable; ";
Database::query($sql);
/* Delete settings */
$settingsTable = Database::get_main_table(TABLE_MAIN_SETTINGS);
Database::query("DELETE FROM $settingsTable WHERE subkey = 'advanced_subscription'");
}
/**
* Get the count of approved induction sessions by a user.
*
* @param int $userId The user id
*
* @return int The count of approved sessions
*/
private function getApprovedInductionSessions($userId)
{
$tSession = Database::get_main_table(TABLE_MAIN_SESSION);
$tSessionField = Database::get_main_table(TABLE_EXTRA_FIELD);
$tSessionFieldValues = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
$tSessionUser = Database::get_main_table(TABLE_MAIN_SESSION_USER);
$extraFieldType = \Chamilo\CoreBundle\Entity\ExtraField::SESSION_FIELD_TYPE;
$sql = "SELECT s.id FROM $tSession AS s
INNER JOIN $tSessionFieldValues AS sfv ON s.id = sfv.item_id
INNER JOIN $tSessionField AS sf ON sfv.field_id = sf.id
INNER JOIN $tSessionUser AS su ON s.id = su.session_id
WHERE
sf.item_type = $extraFieldType AND
sf.variable = 'is_induction_session' AND
su.relation_type = ".Session::STUDENT." AND
su.user_id = ".(int) $userId;
$result = Database::query($sql);
if (false === $result) {
return 0;
}
$numberOfApproved = 0;
while ($session = Database::fetch_assoc($result)) {
$numberOfApprovedCourses = 0;
$courses = SessionManager::get_course_list_by_session_id($session['id']);
foreach ($courses as $course) {
$courseCategories = Category::load(
null,
null,
$course['real_id'],
null,
null,
$session['id'],
null
);
if (count($courseCategories) > 0 &&
Category::userFinishedCourse($userId, $courseCategories[0])
) {
$numberOfApprovedCourses++;
}
}
if ($numberOfApprovedCourses === count($courses)) {
$numberOfApproved++;
}
}
return $numberOfApproved;
}
}