diff --git a/public/plugin/justification/Justification.php b/public/plugin/justification/Justification.php new file mode 100644 index 0000000000..d9e648b26e --- /dev/null +++ b/public/plugin/justification/Justification.php @@ -0,0 +1,99 @@ + 'boolean', + 'default_course_id' => 'text', + ] + ); + } + + /** + * @return $this + */ + public static function create() + { + static $result = null; + + return $result ? $result : $result = new self(); + } + + public function getJustification($id) + { + $id = (int) $id; + + $sql = 'SELECT * FROM justification_document WHERE id = '.$id; + $query = Database::query($sql); + + return Database::fetch_array($query, 'ASSOC'); + } + + public function getUserJustificationList($userId) + { + $userId = (int) $userId; + + $sql = "SELECT * FROM justification_document_rel_users WHERE user_id = $userId "; + $query = Database::query($sql); + + return Database::store_result($query, 'ASSOC'); + } + + public function getUserJustification($id) + { + $id = (int) $id; + + $sql = "SELECT * FROM justification_document_rel_users WHERE id = $id "; + $query = Database::query($sql); + + return Database::fetch_array($query, 'ASSOC'); + } + + public function getList() + { + $sql = 'SELECT * FROM justification_document ORDER BY name '; + $query = Database::query($sql); + + return Database::store_result($query, 'ASSOC'); + } + + /** + * Install. + */ + public function install() + { + $sql = "CREATE TABLE IF NOT EXISTS justification_document ( + id INT unsigned NOT NULL auto_increment PRIMARY KEY, + code TEXT NULL, + name TEXT NULL, + validity_duration INT, + comment TEXT NULL, + date_manual_on INT + )"; + Database::query($sql); + + $sql = "CREATE TABLE IF NOT EXISTS justification_document_rel_users ( + id INT unsigned NOT NULL auto_increment PRIMARY KEY, + justification_document_id INT NOT NULL, + file_path VARCHAR(255), + user_id INT, + date_validity DATE + )"; + Database::query($sql); + } + + public function uninstall() + { + $sql = 'DROP TABLE IF EXISTS justification_document'; + Database::query($sql); + + $sql = 'DROP TABLE IF EXISTS justification_document_rel_users'; + Database::query($sql); + } +} diff --git a/public/plugin/justification/README.md b/public/plugin/justification/README.md new file mode 100644 index 0000000000..8eac4b4faf --- /dev/null +++ b/public/plugin/justification/README.md @@ -0,0 +1,5 @@ +Justification +============== + +1. Enable the plugin. +2. Create the justification files in plugin/justification/list.php \ No newline at end of file diff --git a/public/plugin/justification/add.php b/public/plugin/justification/add.php new file mode 100644 index 0000000000..ed5629b018 --- /dev/null +++ b/public/plugin/justification/add.php @@ -0,0 +1,68 @@ +addText('name', get_lang('Name')); +$form->addText('code', $plugin->get_lang('JustificationCode')); +$form->addNumeric('validity_duration', $plugin->get_lang('ValidityDuration')); +$form->addCheckBox('date_manual_on', $plugin->get_lang('DateManualOn')); +$form->addTextarea('comment', get_lang('Comment')); +$form->addButtonSave(get_lang('Save')); + +if ($form->validate()) { + $values = $form->getSubmitValues(); + $dateManual = isset($values['date_manual_on']) ? 1 : 0; + + $cleanedCode = api_replace_dangerous_char($values['code']); + $code = Database::escape_string($cleanedCode); + + $sql = "SELECT * FROM justification_document WHERE code = '$code' "; + $result = Database::query($sql); + $data = Database::fetch_array($result); + $message = Display::return_message(get_lang('ThisCodeAlradyExists'), 'warning'); + + if (empty($data)) { + $params = [ + 'name' => $values['name'], + 'code' => $cleanedCode, + 'validity_duration' => $values['validity_duration'], + 'date_manual_on' => $dateManual, + 'comment' => $values['comment'], + ]; + Database::insert('justification_document', $params); + $message = Display::return_message(get_lang('Saved')); + } + + Display::addFlash($message); + + $url = api_get_path(WEB_PLUGIN_PATH).'justification/list.php?'; + header('Location: '.$url); + exit; +} + +$actionLinks = Display::toolbarButton( + $plugin->get_lang('Back'), + api_get_path(WEB_PLUGIN_PATH).'justification/list.php', + 'arrow-left', + 'primary' +); + +$tpl->assign( + 'actions', + Display::toolbarAction('toolbar', [$actionLinks]) +); + +$content = $form->returnForm(); + +$tpl->assign('content', $content); +$tpl->display_one_col_template(); diff --git a/public/plugin/justification/cron.php b/public/plugin/justification/cron.php new file mode 100644 index 0000000000..d03992f3d9 --- /dev/null +++ b/public/plugin/justification/cron.php @@ -0,0 +1,88 @@ +getList(); +$totalFields = count($fieldList); + +if (empty($fieldList)) { + echo 'No fields to check. Please add them in the justification plugin'; + exit; +} + +$userList = UserManager::get_user_list(); +$count = count($userList); + +echo "#$count users found".PHP_EOL; +$currentDate = api_get_utc_datetime(); + +foreach ($userList as $user) { + $userId = $user['id']; + + echo "Checking user id #$userId".PHP_EOL; + + $userJustificationList = $plugin->getUserJustificationList($userId); + $userJustificationDocumentList = array_column($userJustificationList, 'date_validity', 'justification_document_id'); + + if (count($userJustificationList) < $totalFields) { + unsubscribeUser($userId, $courseInfo); + continue; + } + + if (count($userJustificationList) >= $totalFields) { + $successList = []; + foreach ($fieldList as $field) { + if (isset($userJustificationDocumentList[$field['id']])) { + $dateValidity = $userJustificationDocumentList[$field['id']]; + if ($dateValidity > $currentDate) { + $successList[] = true; + } + } + } + $countSuccess = count($successList); + if ($countSuccess === $totalFields) { + subscribeUser($userId, $courseInfo); + continue; + } else { + echo "User #$userId only got $countSuccess justification(s) out of $totalFields.".PHP_EOL; + } + } + + unsubscribeUser($userId, $courseInfo); +} + +function unsubscribeUser($userId, $courseInfo) +{ + $courseId = $courseInfo['real_id']; + CourseManager::unsubscribe_user($userId, $courseInfo['code']); + echo "Unsubscribe user id #$userId to course #$courseId".PHP_EOL; +} + +function subscribeUser($userId, $courseInfo) +{ + $courseId = $courseInfo['real_id']; + $isUserSubscribed = CourseManager::is_user_subscribed_in_course($userId, $courseInfo['code']); + if ($isUserSubscribed === false) { + CourseManager::subscribeUser($userId, $courseInfo['code'], STUDENT); + echo "Subscribe user id #$userId to course #$courseId".PHP_EOL; + } else { + echo "Nothing to do user id #$userId is already subscribed to #$courseId".PHP_EOL; + } +} diff --git a/public/plugin/justification/edit.php b/public/plugin/justification/edit.php new file mode 100644 index 0000000000..2852732eac --- /dev/null +++ b/public/plugin/justification/edit.php @@ -0,0 +1,76 @@ +getJustification($id); + +$tpl = new Template($tool); +$fields = []; + +$form = new FormValidator('add', 'post', api_get_self().'?id='.$id); +$form->addText('name', get_lang('Name')); +$form->addText('code', $plugin->get_lang('JustificationCode')); +$form->addNumeric('validity_duration', $plugin->get_lang('ValidityDuration')); +$form->addCheckBox('date_manual_on', $plugin->get_lang('DateManualOn')); +$form->addTextarea('comment', get_lang('Comment')); +$form->addButtonSave(get_lang('Update')); + +$form->setDefaults($justification); + +if ($form->validate()) { + $values = $form->getSubmitValues(); + $cleanedCode = api_replace_dangerous_char($values['code']); + $code = Database::escape_string($cleanedCode); + + $sql = "SELECT * FROM justification_document WHERE code = '$code' AND id <> $id"; + $result = Database::query($sql); + $data = Database::fetch_array($result); + $message = Display::return_message(get_lang('ThisCodeAlradyExists'), 'warning'); + if (empty($data)) { + $params = [ + 'name' => $values['name'], + 'code' => $cleanedCode, + 'validity_duration' => $values['validity_duration'], + 'date_manual_on' => (int) $values['date_manual_on'], + 'comment' => $values['comment'], + ]; + + Database::update('justification_document', $params, ['id = ?' => $id]); + $message = Display::return_message(get_lang('Saved')); + } + + Display::addFlash($message); + + $url = api_get_path(WEB_PLUGIN_PATH).'justification/list.php?'; + header('Location: '.$url); + exit; +} + +$actionLinks = Display::toolbarButton( + $plugin->get_lang('Back'), + api_get_path(WEB_PLUGIN_PATH).'justification/list.php', + 'arrow-left', + 'primary' +); + +$tpl->assign( + 'actions', + Display::toolbarAction('toolbar', [$actionLinks]) +); + +$content = $form->returnForm(); + +$tpl->assign('content', $content); +$tpl->display_one_col_template(); diff --git a/public/plugin/justification/index.php b/public/plugin/justification/index.php new file mode 100644 index 0000000000..e1533d2fe8 --- /dev/null +++ b/public/plugin/justification/index.php @@ -0,0 +1,4 @@ +install(); diff --git a/public/plugin/justification/justification_by_user.php b/public/plugin/justification/justification_by_user.php new file mode 100644 index 0000000000..ac900fec7c --- /dev/null +++ b/public/plugin/justification/justification_by_user.php @@ -0,0 +1,113 @@ +addHeader('Search'); +$form->addSelectAjax( + 'user_id', + get_lang('User'), + [], + [ + 'url' => api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_like', + ] +); +$form->addButtonSearch(get_lang('Search')); +$tpl->assign('form', $form->returnForm()); + +$userId = isset($_REQUEST['user_id']) ? (int) $_REQUEST['user_id'] : 0; + +if ($form->validate()) { + $userId = $form->getSubmitValue('user_id'); +} + +if ($userId) { + $tpl->assign('user_info', api_get_user_info($userId)); + $list = $plugin->getUserJustificationList($userId); + if ($list) { + foreach ($list as &$item) { + if ($item['date_validity'] < api_get_local_time()) { + $item['date_validity'] = Display::label($item['date_validity'], 'warning'); + } + $item['justification'] = $plugin->getJustification($item['justification_document_id']); + $item['file_path'] = Display::url( + $item['file_path'], + api_get_uploaded_web_url('justification', $item['id'], $item['file_path']), + ['target' => '_blank'] + ); + } + } + if (empty($list)) { + Display::addFlash(Display::return_message($plugin->get_lang('NoJustificationFound'))); + } + $tpl->assign('list', $list); +} + +$tpl->assign('user_id', $userId); +$content = $tpl->fetch('justification/view/justification_user_list.tpl'); + +$actionLinks = ''; + +$action = isset($_REQUEST['a']) ? $_REQUEST['a'] : ''; +$id = isset($_REQUEST['id']) ? (int) $_REQUEST['id'] : 0; + +switch ($action) { + case 'edit': + $userJustification = $plugin->getUserJustification($id); + $userInfo = api_get_user_info($userJustification['user_id']); + $form = new FormValidator('edit', 'post', api_get_self().'?a=edit&id='.$id.'&user_id='.$userId); + $form->addHeader($userInfo['complete_name']); + $element = $form->addDatePicker('date_validity', $plugin->get_lang('ValidityDate')); + $element->setValue($userJustification['date_validity']); + $form->addButtonUpdate(get_lang('Update')); + $form->setDefaults($userJustification); + $content = $form->returnForm(); + + if ($form->validate()) { + $values = $form->getSubmitValues(); + $date = Database::escape_string($values['date_validity']); + $sql = "UPDATE justification_document_rel_users SET date_validity = '$date' WHERE id = $id"; + Database::query($sql); + Display::addFlash(Display::return_message(get_lang('Updated'))); + header('Location: '.api_get_self().'?user_id='.$userId); + exit; + } + break; + case 'delete': + $userJustification = $plugin->getUserJustification($id); + if ($userJustification) { + api_remove_uploaded_file_by_id('justification', $id, $userJustification['file_path']); + + $sql = "DELETE FROM justification_document_rel_users WHERE id = $id"; + Database::query($sql); + + Display::addFlash(Display::return_message(get_lang('Deleted'))); + } + header('Location: '.api_get_self().'?user_id='.$userId); + exit; + break; +} + +$actionLinks .= Display::toolbarButton( + $plugin->get_lang('Back'), + api_get_path(WEB_PLUGIN_PATH).'justification/list.php', + 'arrow-left', + 'primary' +); + +$tpl->assign( + 'actions', + Display::toolbarAction('toolbar', [$actionLinks]) +); + +$tpl->assign('content', $content); +$tpl->display_one_col_template(); diff --git a/public/plugin/justification/lang/english.php b/public/plugin/justification/lang/english.php new file mode 100644 index 0000000000..8542a97dfe --- /dev/null +++ b/public/plugin/justification/lang/english.php @@ -0,0 +1,21 @@ +getList(); + +$tpl->assign('list', $list); + +$content = $tpl->fetch('justification/view/list.tpl'); +$actionLinks = ''; +$action = isset($_REQUEST['a']) ? $_REQUEST['a'] : ''; +$id = isset($_REQUEST['id']) ? (int) $_REQUEST['id'] : 0; + +switch ($action) { + case 'delete': + $sql = "DELETE FROM justification_document WHERE id = $id"; + Database::query($sql); + + Display::addFlash(Display::return_message(get_lang('Deleted'))); + header('Location: '.api_get_self()); + exit; + break; +} + +$actionLinks .= Display::toolbarButton( + $plugin->get_lang('Add'), + api_get_path(WEB_PLUGIN_PATH).'justification/add.php', + 'plus', + 'primary' +); +$actionLinks .= Display::toolbarButton( + $plugin->get_lang('Users'), + api_get_path(WEB_PLUGIN_PATH).'justification/justification_by_user.php', + 'user', + 'primary' +); + +$actionLinks .= Display::toolbarButton( + $plugin->get_lang('SetNewCourse'), + api_get_path(WEB_PLUGIN_PATH).'justification/set_course.php', + 'book', + 'primary' +); + +$tpl->assign( + 'actions', + Display::toolbarAction('toolbar', [$actionLinks]) +); + +$tpl->assign('content', $content); +$tpl->display_one_col_template(); diff --git a/public/plugin/justification/plugin.php b/public/plugin/justification/plugin.php new file mode 100644 index 0000000000..02126ea19e --- /dev/null +++ b/public/plugin/justification/plugin.php @@ -0,0 +1,6 @@ +get_info(); diff --git a/public/plugin/justification/set_course.php b/public/plugin/justification/set_course.php new file mode 100644 index 0000000000..1fdecfb6d6 --- /dev/null +++ b/public/plugin/justification/set_course.php @@ -0,0 +1,57 @@ +addHeader($plugin->get_lang('SetNewCourse')); +$currentCourse = api_get_setting('justification_default_course_id', 'justification'); + +if (!empty($currentCourse)) { + $courseInfo = api_get_course_info_by_id($currentCourse); + Display::addFlash(Display::return_message(get_lang('Course').': '.$courseInfo['title'])); +} + +$form->addSelectAjax( + 'course_id', + get_lang('Course'), + null, + [ + 'url' => api_get_path(WEB_AJAX_PATH).'course.ajax.php?a=search_course', + ] +); +$form->addButtonSave(get_lang('Save')); + +if ($form->validate()) { + $values = $form->getSubmitValues(); + api_set_setting('justification_default_course_id', $values['course_id']); + Display::addFlash(Display::return_message(get_lang('Saved'))); + $url = api_get_path(WEB_PLUGIN_PATH).'justification/list.php?'; + header('Location: '.$url); + exit; +} + +$actionLinks = Display::toolbarButton( + $plugin->get_lang('Back'), + api_get_path(WEB_PLUGIN_PATH).'justification/list.php', + 'arrow-left', + 'primary' +); + +$tpl->assign( + 'actions', + Display::toolbarAction('toolbar', [$actionLinks]) +); + +$content = $form->returnForm(); + +$tpl->assign('content', $content); +$tpl->display_one_col_template(); diff --git a/public/plugin/justification/uninstall.php b/public/plugin/justification/uninstall.php new file mode 100644 index 0000000000..a1e3b57a12 --- /dev/null +++ b/public/plugin/justification/uninstall.php @@ -0,0 +1,8 @@ +uninstall(); diff --git a/public/plugin/justification/view/add.tpl b/public/plugin/justification/view/add.tpl new file mode 100644 index 0000000000..078f032f1f --- /dev/null +++ b/public/plugin/justification/view/add.tpl @@ -0,0 +1,48 @@ +{{ search_form }} + + + + + + + + + + + + + + {% for meeting in meetings %} + + {% if meeting.visibility == 0 %} + + {% else %} + + {% endif %} + + + + + + + + {% endfor %} + +
{{ 'CreatedAt'|get_lang }}{{ 'Status'|get_lang }}{{ 'Records'|get_plugin_lang('BBBPlugin') }}{{ 'Course'|get_lang }}{{ 'Session'|get_lang }}{{ 'Participants'|get_lang }}{{ 'Actions'|get_lang }}
{{ meeting.created_at }}{{ meeting.created_at }} + {% if meeting.status == 1 %} + {{ 'MeetingOpened'|get_plugin_lang('BBBPlugin') }} + {% else %} + {{ 'MeetingClosed'|get_plugin_lang('BBBPlugin') }} + {% endif %} + + {% if meeting.record == 1 %} + {# Record list #} + {{ meeting.show_links }} + {% else %} + {{ 'NoRecording'|get_plugin_lang('BBBPlugin') }} + {% endif %} + {{ meeting.course ?: '-' }}{{ meeting.session ?: '-' }} + {{ meeting.participants ? meeting.participants|join('
') : '-' }} +
+ {{ meeting.action_links }} +
diff --git a/public/plugin/justification/view/justification_user_list.tpl b/public/plugin/justification/view/justification_user_list.tpl new file mode 100644 index 0000000000..35b88d286c --- /dev/null +++ b/public/plugin/justification/view/justification_user_list.tpl @@ -0,0 +1,38 @@ +{{ form }} + +{% if list %} +
+
+ + + + + + + + + {% for item in list %} + + + + + + + {% endfor %} +
{{ 'Justification'| get_plugin_lang('Justification') }}{{ 'File'| get_lang }}{{ 'Date'| get_lang('Date') }}{{ 'Actions'| get_lang }}
{{ item.justification.name }} {{ item.file_path }} + {{ item.date_validity }} + + + {{'Edit' | get_lang}} + + + {{'Delete' | get_lang}} + +
+
+
+{% endif %} diff --git a/public/plugin/justification/view/list.tpl b/public/plugin/justification/view/list.tpl new file mode 100644 index 0000000000..2147efa944 --- /dev/null +++ b/public/plugin/justification/view/list.tpl @@ -0,0 +1,33 @@ +
+
+ + + + + + + + + + {% for item in list %} + + + + + + + + {% endfor %} +
{{ 'Name'| get_lang }}{{ 'ValidityDuration'| get_plugin_lang('Justification') }}{{ 'DateManualOn'| get_plugin_lang('Justification') }}{{ 'Actions'| get_lang }}
{{ item.name }} ({{ item.code }}){{ item.validity_duration }}{{ item.date_manual_on }} + + {{'Edit' | get_lang}} + + + + {{'Delete' | get_lang}} + +
+
+