Merge remote-tracking branch 'chamilo/1.11.x' into 18214

* chamilo/1.11.x: (246 commits)
  Student publications: Teacher can upload corrections BT#18352
  Exercises: Fix overload page if allow record audio is activated.
  Exercises: Fix notification URL
  Update lang var + format code
  Student Publication: Pending list - fix access for teachers BT#18352
  Student Publication: Pending list - fix access for teachers BT#18352
  Admin: Add config lp_start_and_end_date_visible_in_student_view
  Exercises - Replace QuestionsToReview to VerificationOfAnsweredQuestions
  Minor - behat decrease wait time
  Minor - format code
  LPs: Hide category for student if hidden in course session BT#17744
  LPs: Fix category link visibility, dont add cidreq already added
  LPs: Allow invisible LP category in course home for students BT#17744
  LPs: Fix categoiry link visibility BT#17744
  Minor - format code, update doc
  Course category: Add $checkHidePrivate parameter BT#18434
  LPs: Fix course home LP link visibility BT#17744
  LPs: Fix course home LP link visibility BT#17744
  LPs: Fix course home LP link visibility BT#17744
  LPs: Fix course home LP link visibility BT#17744
  ...
pull/3743/head
Carlos Alvarado 5 years ago
commit 922aa797d0
No known key found for this signature in database
GPG Key ID: B612DB1EE6658FBB
  1. 191
      .github/workflows/php.yml
  2. 2
      .yamllint_config
  3. 3
      README.md
  4. 24
      app/Resources/public/css/base.css
  5. 4
      documentation/security.html
  6. 16
      main/admin/course_category.php
  7. 7
      main/admin/user_export.php
  8. 4
      main/admin/user_information.php
  9. 27
      main/announcements/announcements.php
  10. 1
      main/auth/courses.php
  11. 2
      main/auth/okn/start.php
  12. 8
      main/badge/issued.php
  13. 9
      main/badge/issued_all.php
  14. 3
      main/calendar/agenda.php
  15. 3
      main/calendar/agenda_list.php
  16. 1
      main/calendar/planification.php
  17. 31
      main/course_home/course_home.php
  18. 113
      main/course_info/delete_course.php
  19. 23
      main/course_info/infocours.php
  20. 1
      main/coursecopy/import_moodle.php
  21. 60
      main/coursecopy/recycle_course.php
  22. 3
      main/cron/update_ldap_users.php
  23. 2
      main/document/download_uploaded_files.php
  24. 154
      main/document/showinframes.php
  25. 94
      main/exercise/exercise.class.php
  26. 98
      main/exercise/exercise_question_reminder.php
  27. 5
      main/exercise/exercise_reminder.php
  28. 94
      main/exercise/exercise_report.php
  29. 6
      main/exercise/exercise_result.class.php
  30. 33
      main/exercise/exercise_result.php
  31. 10
      main/exercise/exercise_show.php
  32. 149
      main/exercise/exercise_submit.php
  33. 16
      main/exercise/export/aiken/aiken_import.inc.php
  34. 2
      main/exercise/result.php
  35. 44
      main/exercise/stats.php
  36. 13
      main/gradebook/certificate_report.php
  37. 31
      main/gradebook/cli/export_all_certificates.php
  38. 58
      main/gradebook/gradebook_display_certificate.php
  39. 47
      main/gradebook/gradebook_flatview.php
  40. 6
      main/gradebook/index.php
  41. 81
      main/gradebook/lib/GradebookUtils.php
  42. 33
      main/gradebook/lib/be/category.class.php
  43. 37
      main/gradebook/lib/fe/displaygradebook.php
  44. 2
      main/gradebook/lib/fe/evalform.class.php
  45. 27
      main/gradebook/lib/fe/flatviewtable.class.php
  46. 106
      main/gradebook/lib/flatview_data_generator.class.php
  47. 33
      main/gradebook/lib/gradebook_data_generator.class.php
  48. 35
      main/gradebook/lib/gradebook_result.class.php
  49. 76
      main/gradebook/lib/scoredisplay.class.php
  50. 5
      main/group/group.php
  51. BIN
      main/img/icons/32/file_html_na.png
  52. 3
      main/inc/ajax/announcement.ajax.php
  53. 16
      main/inc/ajax/course.ajax.php
  54. 17
      main/inc/ajax/course_home.ajax.php
  55. 669
      main/inc/ajax/exercise.ajax.php
  56. 14
      main/inc/ajax/extra_field.ajax.php
  57. 38
      main/inc/ajax/gradebook.ajax.php
  58. 56
      main/inc/ajax/model.ajax.php
  59. 9
      main/inc/ajax/work.ajax.php
  60. 25
      main/inc/lib/AnnouncementManager.php
  61. 10
      main/inc/lib/CoursesAndSessionsCatalog.class.php
  62. 45
      main/inc/lib/MoodleImport.php
  63. 1538
      main/inc/lib/PortfolioController.php
  64. 2
      main/inc/lib/SortableTableFromArrayConfig.php
  65. 4
      main/inc/lib/agenda.lib.php
  66. 3
      main/inc/lib/api.lib.php
  67. 10
      main/inc/lib/auth.lib.php
  68. 11
      main/inc/lib/career.lib.php
  69. 92
      main/inc/lib/course.lib.php
  70. 23
      main/inc/lib/course_category.lib.php
  71. 224
      main/inc/lib/course_home.lib.php
  72. 33
      main/inc/lib/display.lib.php
  73. 39
      main/inc/lib/document.lib.php
  74. 211
      main/inc/lib/exercise.lib.php
  75. 3
      main/inc/lib/extra_field.lib.php
  76. 2
      main/inc/lib/groupmanager.lib.php
  77. 30
      main/inc/lib/hook/HookPortfolioItemAdded.php
  78. 27
      main/inc/lib/hook/HookPortfolioItemCommented.php
  79. 14
      main/inc/lib/hook/interfaces/HookPortfolioItemAddedEventInterface.php
  80. 16
      main/inc/lib/hook/interfaces/HookPortfolioItemAddedObserverInterface.php
  81. 14
      main/inc/lib/hook/interfaces/HookPortfolioItemCommentedEventInterface.php
  82. 16
      main/inc/lib/hook/interfaces/HookPortfolioItemCommentedObserverInterface.php
  83. 4
      main/inc/lib/hook/interfaces/HookQuizEndObserverInterface.php
  84. 14
      main/inc/lib/javascript/ckeditor/plugins/oembed/lang/fr.js
  85. 11
      main/inc/lib/javascript/record_audio/record_audio.js
  86. 19
      main/inc/lib/pdf.lib.php
  87. 2
      main/inc/lib/security.lib.php
  88. 4
      main/inc/lib/template.lib.php
  89. 17
      main/inc/lib/usermanager.lib.php
  90. 26
      main/install/configuration.dist.php
  91. 47
      main/lang/english/trad4all.inc.php
  92. 179
      main/lang/french/trad4all.inc.php
  93. 47
      main/lang/spanish/trad4all.inc.php
  94. 233
      main/lp/learnpath.class.php
  95. 31
      main/lp/learnpathList.class.php
  96. 1
      main/lp/lp_add.php
  97. 35
      main/lp/lp_controller.php
  98. 21
      main/lp/lp_list.php
  99. 30
      main/lp/lp_view.php
  100. 66
      main/mySpace/myStudents.php
  101. Some files were not shown because too many files have changed in this diff Show More

@ -0,0 +1,191 @@
name: PHP Composer
on: [push, pull_request]
jobs:
build:
name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }}
runs-on: ubuntu-18.04
strategy:
fail-fast: false
matrix:
operating-system: [ubuntu-latest]
php-versions: ['7.1', '7.2', '7.3', '7.4']
# services:
# mysql:
# image: mysql:5.7
# env:
# MYSQL_ALLOW_EMPTY_PASSWORD: false
# MYSQL_ROOT_PASSWORD: chamilo
# MYSQL_DATABASE: chamilo
# ports:
# - 3306/tcp
# options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup apache
run: |
sudo apt update
sudo apt install apache2 php${{ matrix.php-versions }} php${{ matrix.php-versions }}-common php${{ matrix.php-versions }}-cli libapache2-mod-php${{ matrix.php-versions }}
sudo a2enmod rewrite actions
sudo cp -f tests/travis/gh-apache /etc/apache2/sites-available/000-default.conf
sudo chmod 777 -R $HOME
cat /etc/apache2/sites-available/000-default.conf
sudo service apache2 restart
sudo systemctl restart apache2
- name: Setup PHP, with composer and extensions
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}
extensions: mbstring, xml, ctype, iconv, intl, pdo, pdo_mysql, dom, gd, json, soap, zip, bcmath
ini-values: post_max_size=256M, max_execution_time=600, memory_limit=4096M
- name: Get composer cache directory
id: composer-cache-v1
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: Cache composer dependencies
uses: actions/cache@v2
with:
path: ${{ steps.composer-cache-v1.outputs.dir }}
# Use composer.json for key, if composer.lock is not committed.
# key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
key: v1-${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: v1-${{ runner.os }}-composer-
- name: Install dependencies with composer
run: composer install --prefer-dist --no-progress
# - name: Install assets
# run: php bin/console assets:install
#
# - name: Generate fos_js_routes.json
# run: php bin/console fos:js-routing:dump --format=json --target=public/js/fos_js_routes.json
# - name: Get yarn cache directory
# id: yarn-cache
# run: echo "::set-output name=dir::$(yarn cache dir)"
#
# - name: Cache yarn dependencies
# uses: actions/cache@v2
# with:
# path: ${{ steps.yarn-cache.outputs.dir }}
# # Use composer.json for key, if composer.lock is not committed.
# # key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
# key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
# restore-keys: ${{ runner.os }}-yarn-
#
# - name: Yarn install
# uses: borales/actions-yarn@v2.3.0
# with:
# cmd: install # will run `yarn install` command
#
# - name: Yarn run encore dev
# uses: borales/actions-yarn@v2.3.0
# with:
# cmd: run encore dev
- name: Start chrome
run: |
sudo apt install google-chrome-stable
google-chrome --version
google-chrome-stable --version
google-chrome-stable --headless --disable-gpu --remote-debugging-port=9222 http://localhost &
whereis google-chrome-stable
# https://github.com/marketplace/actions/setup-chromedriver
- name: Start chromedriver
uses: nanasess/setup-chromedriver@master
with:
# Optional: do not specify to match Chrome's version
chromedriver-version: '88.0.4324.96'
- run: |
export DISPLAY=:99
chromedriver --url-base=/wd/hub &
sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 & # optional
# wget https://chromedriver.storage.googleapis.com/88.0.4324.96/chromedriver_linux64.zip --quiet && unzip chromedriver_linux64.zip
# sudo mv chromedriver /usr/bin
# sudo chmod +x /usr/bin/chromedriver
# chromedriver --version
# - run: |
# export DISPLAY=:99
# chromedriver --url-base=/wd/hub &
# sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 & # optional
# chromedriver --version
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Get Selenium
run: |
wget http://selenium-release.storage.googleapis.com/3.141/selenium-server-standalone-3.141.59.jar --quiet
- name: Run Selenium
run: |
java -version
export DISPLAY=:99.0
sudo xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 &
java -Dwebdriver.chrome.driver=/usr/bin/chromedriver -jar selenium-server-standalone-3.141.59.jar -log selenium.log > /dev/null &
- name: Start mysql service
run: |
sudo /etc/init.d/mysql start
sudo systemctl restart apache2
#
# - name: Install database
# run: |
# bin/console doctrine:database:create || echo "Error while creating the DB"
# env:
# DATABASE_URL: mysql://root:root@127.0.0.1:${{ job.services.mysql.ports['3306'] }}/chamilo
# DATABASE_HOST: 127.0.0.1
# DATABASE_PORT: ${{ job.services.mysql.ports['3306'] }}
# DATABASE_NAME: chamilo
# DATABASE_USER: root
# DATABASE_PASSWORD: root
# APP_INSTALLED: 1
- name: Check settings
run: |
php -ini
php -v
php -m
# - name: Check chamilo
# run: |
# sudo chmod 777 -R ${{ github.workspace }}
# curl http://localhost/main/install/index.php
- name: Install chash
run: |
git clone https://github.com/chamilo/chash
cd chash
git checkout 0.2.x
composer install
php -d phar.readonly=0 createPhar.php
chmod +x chash.phar
sudo mv chash.phar /usr/local/bin/chash
- name: Install chamilo
run: |
php ${{ github.workspace }}/chash/chash.php chash:chamilo_install 1.11.x ${{ github.workspace }} --no-interaction --sitename="Chamilo" --site_url="http://localhost/" --institution="Chamilo" --institution_url="https://chamilo.org" --encrypt_method="sha1" --firstname="John" --lastname="Doe" --language="english" --driver="pdo_mysql" --host="localhost" --port="3306" --dbname="chamilo" --dbuser="root" --dbpassword="root" --permissions_for_new_directories="0777" --permissions_for_new_files="0666" --linux-user="www-data" --linux-group="www-data" --username="admin" --password="admin" --email="admin@example.com" --phone="555-5555"
sudo chmod -R 777 app/cache app/logs app/courses app/upload web
php ${{ github.workspace }}/chash/chash.php chash:chamilo_status
ls -la
bash tests/travis/post_installation.sh
curl http://localhost/index.php
ls -la web/build
- name: Behat tests
run: |
cd ${{ github.workspace }}/tests/behat
../../vendor/behat/behat/bin/behat -vvv

@ -8,4 +8,4 @@ ignore: |
rules:
line-length:
max: 500
max: 800

@ -1,8 +1,7 @@
# Chamilo 1.11.x
[![Build Status](https://travis-ci.org/chamilo/chamilo-lms.svg?branch=1.11.x)](https://travis-ci.org/chamilo/chamilo-lms)
![PHP Composer](https://github.com/chamilo/chamilo-lms/workflows/PHP%20Composer/badge.svg?branch=1.11.x)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/chamilo/chamilo-lms/badges/quality-score.png?b=1.11.x)](https://scrutinizer-ci.com/g/chamilo/chamilo-lms/?branch=1.11.x)
[![Code Coverage](https://scrutinizer-ci.com/g/chamilo/chamilo-lms/badges/coverage.png?b=1.11.x)](https://scrutinizer-ci.com/g/chamilo/chamilo-lms/?branch=1.11.x)
[![Bountysource](https://www.bountysource.com/badge/team?team_id=12439&style=raised)](https://www.bountysource.com/teams/chamilo?utm_source=chamilo&utm_medium=shield&utm_campaign=raised)
[![Code Consistency](https://squizlabs.github.io/PHP_CodeSniffer/analysis/chamilo/chamilo-lms/grade.svg)](http://squizlabs.github.io/PHP_CodeSniffer/analysis/chamilo/chamilo-lms/)
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/166/badge)](https://bestpractices.coreinfrastructure.org/projects/166)

@ -6111,6 +6111,10 @@ div#chat-remote-video video {
border-color: #0077b5;
}
.txt-linkedin {
color: #0a66c2;
}
/**** END SOCIAL MEDIA ****/
/**** ABOUT SESSION ****/
@ -6576,23 +6580,6 @@ div#chat-remote-video video {
text-align: center;
}
.grid-courses .items .image .black-shadow {
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
box-sizing: border-box;
position: absolute;
background: rgba(0, 0, 0, 0.7) none repeat scroll 0 0;
padding: 40px 10px 10px;
}
.grid-courses .items .image .hovered-course {
opacity: 1;
transition: all 0.3s ease 0s;
}
.grid-courses .items .toolbar .info {
float: left;
font-size: 12px;
@ -10542,7 +10529,7 @@ ul.dropdown-menu.inner > li > a {
#registration input.register-profile[value='5']:after,
#registration input.register-profile[value='1']:after
{
top:-5px;
top: -5px;
left: -2px;
}
@ -10555,4 +10542,3 @@ ul.dropdown-menu.inner > li > a {
.form-inline .bootstrap-select.form-control:not([class*="col-"]) {
width: 100%;
}

@ -43,9 +43,7 @@ It is considered a safer behaviour not to disclose server information from your
<p>
Make sure you check <a href="http://support.chamilo.org/projects/chamilo-18/wiki/Security_issues">our security
issues page</a> from time to time.
Subscribe to our free security alerts mailing-list:
<a href="http://lists.chamilo.org/listinfo/security">http://lists.chamilo.org/listinfo/security</a> or that you
follow our security Twitter feed: <a href="http://twitter.com/chamilosecurity">http://twitter.com/chamilosecurity</a>.
You can also follow our security Twitter feed: <a href="http://twitter.com/chamilosecurity">http://twitter.com/chamilosecurity</a>.
</p>
<h2><a name="3.Using-safe-browsers"></a>3. Using safe browsers</h2>

@ -23,13 +23,13 @@ $action = isset($_GET['action']) ? $_GET['action'] : null;
$myCourseListAsCategory = api_get_configuration_value('my_courses_list_as_category');
if (!empty($action)) {
if ($action == 'delete') {
if ($action === 'delete') {
CourseCategory::deleteNode($categoryId);
Display::addFlash(Display::return_message(get_lang('Deleted')));
header('Location: '.api_get_self().'?category='.Security::remove_XSS($category));
exit();
} elseif (($action == 'add' || $action == 'edit') && isset($_POST['formSent']) && $_POST['formSent']) {
if ($action == 'add') {
} elseif (($action === 'add' || $action === 'edit') && isset($_POST['formSent']) && $_POST['formSent']) {
if ($action === 'add') {
$ret = CourseCategory::addNode(
$_POST['code'],
$_POST['name'],
@ -63,7 +63,7 @@ if (!empty($action)) {
Display::addFlash($errorMsg);
header('Location: '.api_get_path(WEB_CODE_PATH).'admin/course_category.php');
exit;
} elseif ($action == 'moveUp') {
} elseif ($action === 'moveUp') {
CourseCategory::moveNodeUp($categoryId, $_GET['tree_pos'], $category);
header('Location: '.api_get_self().'?category='.Security::remove_XSS($category));
Display::addFlash(Display::return_message(get_lang('Updated')));
@ -80,7 +80,7 @@ $interbreadcrumb[] = [
Display::display_header($tool_name);
$urlId = api_get_current_access_url_id();
if ($action == 'add' || $action == 'edit') {
if ($action === 'add' || $action === 'edit') {
echo '<div class="actions">';
echo Display::url(
Display::return_icon('folder_up.png', get_lang('Back'), '', ICON_SIZE_MEDIUM),
@ -88,7 +88,7 @@ if ($action == 'add' || $action == 'edit') {
);
echo '</div>';
$form_title = ($action == 'add') ? get_lang('AddACategory') : get_lang('EditNode');
$form_title = $action === 'add' ? get_lang('AddACategory') : get_lang('EditNode');
if (!empty($category)) {
$form_title .= ' '.get_lang('Into').' '.Security::remove_XSS($category);
}
@ -139,7 +139,7 @@ if ($action == 'add' || $action == 'edit') {
['ToolbarSet' => 'Minimal']
);
$form->addFile('image', get_lang('Image'), ['accept' => 'image/*']);
if ($action == 'edit' && !empty($categoryInfo['image'])) {
if ($action === 'edit' && !empty($categoryInfo['image'])) {
$form->addHtml('
<div class="form-group">
<div class="col-sm-offset-2 col-sm-8">'.
@ -180,7 +180,7 @@ if ($action == 'add' || $action == 'edit') {
);
}
if (empty($parentInfo) || $parentInfo['auth_cat_child'] == 'TRUE') {
if (empty($parentInfo) || $parentInfo['auth_cat_child'] === 'TRUE') {
$newCategoryLink = Display::url(
Display::return_icon('new_folder.png', get_lang('AddACategory'), '', ICON_SIZE_MEDIUM),
api_get_path(WEB_CODE_PATH).'admin/course_category.php?action=add&category='.Security::remove_XSS($category)

@ -88,7 +88,8 @@ if ($form->validate()) {
u.status AS Status,
u.official_code AS OfficialCode,
u.phone AS Phone,
u.registration_date AS RegistrationDate";
u.registration_date AS RegistrationDate,
u.active AS Active";
if (strlen($course_code) > 0) {
$sql .= " FROM $user_table u, $course_user_table cu
WHERE
@ -102,7 +103,7 @@ if ($form->validate()) {
WHERE
u.user_id = scu.user_id AND
scu.c_id = $courseSessionId AND
scu.session_id = $sessionId
scu.session_id = $sessionId
ORDER BY lastname,firstname";
$filename = 'export_users_'.$courseSessionCode.'_'.$sessionInfo['name'].'_'.api_get_local_time();
} else {
@ -138,6 +139,7 @@ if ($form->validate()) {
'OfficialCode',
'PhoneNumber',
'RegistrationDate',
'Active',
];
} else {
$data[] = [
@ -152,6 +154,7 @@ if ($form->validate()) {
'OfficialCode',
'PhoneNumber',
'RegistrationDate',
'Active',
];
}

@ -718,8 +718,8 @@ if (api_get_configuration_value('allow_career_users')) {
$table = new HTML_Table(['class' => 'table table-hover table-striped data_table']);
$table->setHeaderContents(0, 0, get_lang('Career'));
$row = 1;
foreach ($careers as $carerData) {
$table->setCellContents($row, 0, $carerData['name']);
foreach ($careers as $careerData) {
$table->setCellContents($row, 0, $careerData['name']);
$row++;
}
echo $table->toHtml();

@ -23,17 +23,18 @@ $token = Security::get_existing_token();
$courseId = api_get_course_int_id();
$_course = api_get_course_info_by_id($courseId);
$group_id = api_get_group_id();
$sessionId = api_get_session_id();
$current_course_tool = TOOL_ANNOUNCEMENT;
$this_section = SECTION_COURSES;
$nameTools = get_lang('ToolAnnouncement');
$allowToEdit = (
api_is_allowed_to_edit(false, true) ||
(api_get_course_setting('allow_user_edit_announcement') && !api_is_anonymous())
(api_get_course_setting('allow_user_edit_announcement') && !api_is_anonymous()) ||
($sessionId && api_is_coach() && api_get_configuration_value('allow_coach_to_edit_announcements'))
);
$allowStudentInGroupToSend = false;
$sessionId = api_get_session_id();
$drhHasAccessToSessionContent = api_drh_can_access_all_session_content();
if (!empty($sessionId) && $drhHasAccessToSessionContent) {
$allowToEdit = $allowToEdit || api_is_drh();
@ -344,12 +345,18 @@ switch ($action) {
exit;
break;
case 'showhide':
if (!isset($_GET['isStudentView']) || $_GET['isStudentView'] != 'false') {
if (!isset($_GET['isStudentView']) || $_GET['isStudentView'] !== 'false') {
if (isset($_GET['id']) && $_GET['id']) {
if ($sessionId != 0 &&
api_is_allowed_to_session_edit(false, true) == false
) {
api_not_allowed();
$block = true;
if (api_get_configuration_value('allow_coach_to_edit_announcements') && api_is_coach()) {
$block = false;
}
if ($block) {
api_not_allowed();
}
}
if (!$allowToEdit) {
@ -372,10 +379,14 @@ switch ($action) {
break;
case 'add':
case 'modify':
if ($sessionId != 0 &&
api_is_allowed_to_session_edit(false, true) == false
) {
api_not_allowed(true);
if ($sessionId != 0 && api_is_allowed_to_session_edit(false, true) === false) {
$block = true;
if (api_get_configuration_value('allow_coach_to_edit_announcements') && api_is_coach()) {
$block = false;
}
if ($block) {
api_not_allowed();
}
}
if ($allowStudentInGroupToSend === false) {

@ -284,6 +284,7 @@ switch ($action) {
$categoryCode,
$searchTerm,
true,
true,
$conditions
);
}

@ -25,7 +25,7 @@ $auth = new Auth($settingsInfo);
$settings = new Settings($settingsInfo);
$authRequest = new AuthnRequest($settings);
$samlRequest = $authRequest->getRequest();
$samlRequest = $authRequest->getRequest(true);
$idpData = $settings->getIdPData();
if (isset($_GET['email']) || isset($_GET['email_bis'])) {

@ -88,10 +88,18 @@ if ($skillIssue->getAcquiredLevel()) {
}
$author = api_get_user_info($skillIssue->getArgumentationAuthorId());
$tempDate = DateTime::createFromFormat('Y-m-d H:i:s', $skillIssueDate);
$linkedinOrganizationId = api_get_configuration_value('linkedin_organization_id');
if (($linkedinOrganizationId === false)) {
$linkedinOrganizationId = null;
}
$skillIssueInfo = [
'id' => $skillIssue->getId(),
'datetime' => api_format_date($skillIssueDate, DATE_TIME_FORMAT_SHORT),
'year' => $tempDate->format('Y'),
'month' => $tempDate->format('m'),
'linkedin_organization_id' => $linkedinOrganizationId,
'acquired_level' => $currentSkillLevel,
'argumentation_author_id' => $skillIssue->getArgumentationAuthorId(),
'argumentation_author_name' => $author['complete_name'],

@ -72,9 +72,18 @@ foreach ($userSkills as $index => $skillIssue) {
}
$argumentationAuthor = api_get_user_info($skillIssue->getArgumentationAuthorId());
$tempDate = DateTime::createFromFormat('Y-m-d H:i:s', $skillIssueDate);
$linkedinOrganizationId = api_get_configuration_value('linkedin_organization_id');
if (($linkedinOrganizationId === false)) {
$linkedinOrganizationId = null;
}
$skillIssueInfo = [
'id' => $skillIssue->getId(),
'datetime' => api_format_date($skillIssueDate, DATE_TIME_FORMAT_SHORT),
'year' => $tempDate->format('Y'),
'month' => $tempDate->format('m'),
'linkedin_organization_id' => $linkedinOrganizationId,
'acquired_level' => $currentSkillLevel,
'argumentation_author_id' => $skillIssue->getArgumentationAuthorId(),
'argumentation_author_name' => api_get_person_name(

@ -1,4 +1,5 @@
<?php
/* For licensing terms, see /license.txt */
// use anonymous mode when accessing this course tool
@ -16,7 +17,7 @@ $action = isset($_GET['action']) ? Security::remove_XSS($_GET['action']) : null;
$url = null;
if (empty($action)) {
if (!empty($course_info)) {
$url = api_get_path(WEB_CODE_PATH).'calendar/agenda_js.php?type=course'.'&'.api_get_cidreq();
$url = api_get_path(WEB_CODE_PATH).'calendar/agenda_js.php?type=course&'.api_get_cidreq();
} else {
$url = api_get_path(WEB_CODE_PATH).'calendar/agenda_js.php?';
}

@ -12,7 +12,8 @@ $logInfo = [
];
Event::registerLog($logInfo);
$type = isset($_REQUEST['type']) ? $_REQUEST['type'] : null;
$typeList = ['personal', 'course', 'admin', 'platform'];
$type = isset($_REQUEST['type']) && in_array($_REQUEST['type'], $typeList, true) ? $_REQUEST['type'] : null;
$interbreadcrumb[] = [
'url' => api_get_path(WEB_CODE_PATH).'calendar/agenda_js.php?type='.Security::remove_XSS($type),

@ -1,4 +1,5 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Component\Utils\ChamiloApi;

@ -34,8 +34,7 @@ require_once __DIR__.'/../inc/global.inc.php';
$js = '<script>'.api_get_language_translate_html().'</script>';
$htmlHeadXtra[] = $js;
$htmlHeadXtra[] = '<script type="text/javascript">
$htmlHeadXtra[] = '<script>
/* show eye for all show/hide*/
function buttonForAllShowHide()
{
@ -53,7 +52,6 @@ $htmlHeadXtra[] = '<script type="text/javascript">
// if the image has the eye-slash icon, prepare to make visible
tools_visibles.push(image_id)
}
});
if (tools_visibles.length == 0) {
$(".visible-all").addClass("hidden");
@ -62,7 +60,8 @@ $htmlHeadXtra[] = '<script type="text/javascript">
$(".visible-all").removeClass("hidden");
$(".invisible-all").addClass("hidden");
}
};
}
/* option show/hide thematic-block */
$(function() {
buttonForAllShowHide();
@ -81,11 +80,11 @@ $htmlHeadXtra[] = '<script type="text/javascript">
tools_visibles.push(image_id)
}
});
message_invisible = "'.get_lang('ToolIsNowHidden', '').'";
message_invisible = "'.get_lang('ToolIsNowHidden').'";
ids = tools_invisibles;
if (tools_invisibles.length == 0) {
ids = tools_visibles;
message_invisible = "'.get_lang('ToolIsNowVisible', '').'";
message_invisible = "'.get_lang('ToolIsNowVisible').'";
}
$.ajax({
@ -100,7 +99,7 @@ $htmlHeadXtra[] = '<script type="text/javascript">
success: function (data) {
data = JSON.parse(data);
$.each(data,function(index,item){
new_current_view = "'.api_get_path(WEB_IMG_PATH).'" + item.view;
new_current_view = "'.api_get_path(WEB_IMG_PATH).'" + item.view;
//eyes
$("#linktool_"+item.id).attr("class", item.fclass);
//tool
@ -122,6 +121,7 @@ $htmlHeadXtra[] = '<script type="text/javascript">
}
});
});
$("#thematic-show").click(function(){
$(".btn-hide-thematic").hide();
$(".btn-show-thematic").show(); //show using class
@ -158,10 +158,12 @@ $htmlHeadXtra[] = '<script type="text/javascript">
success: function(data) {
eval("var info=" + data);
new_current_tool_image = info.image;
new_current_view = "'.api_get_path(WEB_IMG_PATH).'" + info.view;
new_current_view = "'.api_get_path(WEB_IMG_PATH).'" + info.view;
//eyes
//$("#" + tool_id).attr("src", new_current_view);
$("#linktool_"+my_tool_id).attr("class", info.fclass);
$("#linktool_"+my_tool_id).attr("title", info.label);
//tool
$("#toolimage_" + my_tool_id).attr("src", new_current_tool_image);
//clase
@ -169,15 +171,15 @@ $htmlHeadXtra[] = '<script type="text/javascript">
$("#istooldesc_" + my_tool_id).attr("class", info.tclass);
if (info.message == "is_active") {
message = "'.get_lang('ToolIsNowVisible', '').'";
message = "'.get_lang('ToolIsNowVisible').'";
$("#" + tool_id)
.attr("alt", "'.get_lang('Activate', '').'")
.attr("title", "'.get_lang('Activate', '').'");
.attr("alt", "'.get_lang('Deactivate').'")
.attr("title", "'.get_lang('Deactivate').'");
} else {
message = "'.get_lang('ToolIsNowHidden', '').'";
message = "'.get_lang('ToolIsNowHidden').'";
$("#" + tool_id)
.attr("alt", "'.get_lang('Deactivate', '').'")
.attr("title", "'.get_lang('Deactivate', '').'");
.attr("alt", "'.get_lang('Activate').'")
.attr("title", "'.get_lang('Activate').'");
}
$(".normal-message").hide();
$("#id_confirmation_message").html(message);
@ -186,7 +188,6 @@ $htmlHeadXtra[] = '<script type="text/javascript">
});
});
});
</script>';
// The section for the tabs

@ -15,71 +15,76 @@ $current_course_tool = TOOL_COURSE_MAINTENANCE;
api_protect_course_script(true);
$_course = api_get_course_info();
$current_course_code = $_course['official_code'];
$current_course_name = $_course['name'];
$courseInfo = api_get_course_info();
if (empty($courseInfo)) {
api_not_allowed(true);
}
$courseCode = $courseInfo['code'];
$courseName = $courseInfo['name'];
if (!api_is_allowed_to_edit()) {
api_not_allowed(true);
}
$tool_name = get_lang('DelCourse');
$type_info_message = 'warning';
if (isset($_GET['delete']) && $_GET['delete'] === 'yes' && $_GET['course_code'] && !empty($_GET['course_code'])) {
if ($current_course_code == $_GET['course_code']) {
CourseManager::delete_course($_course['sysCode']);
// DELETE CONFIRMATION MESSAGE
Session::erase('_cid');
Session::erase('_real_cid');
$message = '<h3>'.get_lang('CourseTitle').' : '.$current_course_name.'</h3>';
$message .= '<h3>'.get_lang('CourseCode').' : '.$current_course_code.'</h3>';
$message .= get_lang('HasDel');
$message .= '<br /><br /><a href="../../index.php">'.get_lang('BackHome').'</a>';
} else {
/* message if code course is incorrect */
$message = '<h3>'.get_lang('CourseTitle').' : '.$current_course_name.'</h3>';
$message .= '<h3>'.get_lang('CourseCode').' : '.$current_course_code.'</h3>';
$message .= '<p>'.get_lang('CourseRegistrationCodeIncorrect').'</p>';
$message .= '<p><a class="btn btn-primary" href="'
.api_get_path(WEB_CODE_PATH)
.'course_info/delete_course.php?'
.api_get_cidreq()
.'">'.get_lang('BackToPreviousPage').'</a>';
$message .= '<br /><br /><a href="../../index.php">'.get_lang('BackHome').'</a>';
$type_info_message = 'error';
$content = Display::page_subheader(get_lang('CourseTitle').' : '.$courseName);
$message = '';
$message .= Display::return_message(
'<strong>'.get_lang('ByDel').'<strong>',
'error',
false
);
$form = new FormValidator('delete', 'get');
$form->addLabel(null, sprintf(get_lang('CourseCodeToEnteredCapitalLettersToConfirmDeletionX'), $courseCode));
$form->addText('course_code', get_lang('CourseCode'));
$form->addLabel(null, get_lang('AreYouSureToDeleteJS'));
$buttonGroup[] = $form->addButton('yes', get_lang('Yes'), '', 'danger', '', '', [], true);
$buttonGroup[] = $form->addButton('no', get_lang('No'), '', 'primary', '', '', ['id' => 'no_delete'], true);
$form->addGroup($buttonGroup);
$returnUrl = api_get_path(WEB_CODE_PATH).'course_info/maintenance.php?'.api_get_cidreq();
if ($form->validate()) {
$values = $form->getSubmitValues();
$courseCodeFromGet = $values['course_code'];
if (isset($values['no'])) {
api_location($returnUrl);
}
if (isset($values['yes'])) {
if ($courseCode === $courseCodeFromGet) {
CourseManager::delete_course($courseInfo['code']);
// DELETE CONFIRMATION MESSAGE
Session::erase('_cid');
Session::erase('_real_cid');
Display::addFlash(Display::return_message($courseCode.' '.get_lang('HasDel'), 'error', false));
api_location(api_get_path(WEB_PATH));
} else {
Display::addFlash(Display::return_message(get_lang('CourseRegistrationCodeIncorrect'), 'warning'));
}
}
} else {
$message = '<h3>'.get_lang('CourseTitle').' : '.$current_course_name.'</h3>';
$message .= '<h3>'.get_lang('CourseCode').' : '.$current_course_code.'</h3>';
$message .= '<p>'.get_lang('ByDel').'</p>';
$message .= '<p><span class="form_required">*</span>'
.get_lang('CourseCodeConfirmation')
.'&nbsp;<input type="text" name="course_code" id="course_code"></p>';
$message .= '<p>';
$message .= '<button class="btn btn-danger delete-course">'.get_lang('ValidateChanges').'</button>';
$message .= '&nbsp;';
$message .= '<a class="btn btn-primary"href="'
.api_get_path(WEB_CODE_PATH)
.'course_info/maintenance.php?'
.api_get_cidreq().'">'
.get_lang('No')
.'</a>';
$message .= '</p>';
$interbreadcrumb[] = [
'url' => 'maintenance.php',
'name' => get_lang('Maintenance'),
];
}
$htmlHeadXtra[] = '<script>
$message .= $form->returnForm();
$interbreadcrumb[] = [
'url' => 'maintenance.php',
'name' => get_lang('Maintenance'),
];
$htmlHeadXtra[] = '<script>
$(function(){
/* Asking by course code to confirm recycling*/
$(".delete-course").on("click",function(){
window.location ="'.api_get_self().'?delete=yes&'.api_get_cidreq().'&course_code=" + $("#course_code").val();
})
$("#no_delete").on("click", function(e) {
e.preventDefault();
window.location = "'.$returnUrl.'";
});
})
</script>';
$tpl = new Template($tool_name);
$tpl->assign('content', Display::return_message($message, $type_info_message, false));
$tpl->assign('content', $content.$message);
$tpl->display_one_col_template();

@ -922,6 +922,29 @@ $form->addPanelOption(
$globalGroup
);
if (api_get_configuration_value('allow_portfolio_tool')) {
$globalGroup = [
get_lang('QualifyPortfolioItems') => [
$form->createElement('radio', 'qualify_portfolio_item', null, get_lang('Yes'), 1),
$form->createElement('radio', 'qualify_portfolio_item', null, get_lang('No'), 2),
],
get_lang('QualifyPortfolioComments') => [
$form->createElement('radio', 'qualify_portfolio_comment', null, get_lang('Yes'), 1),
$form->createElement('radio', 'qualify_portfolio_comment', null, get_lang('No'), 2),
],
get_lang('MaxScore') => [
$form->createElement('number', 'portfolio_max_score', get_lang('MaxScore'), ['step' => 'any', 'min' => 0]),
],
$form->addButtonSave(get_lang('SaveSettings'), 'submit_save', true),
];
$form->addPanelOption(
'portfolio',
Display::return_icon('wiki_task.png', get_lang('Portfolio')).PHP_EOL.get_lang('Portfolio'),
$globalGroup
);
}
// Plugin course settings
$appPlugin = new AppPlugin();
$appPlugin->add_course_settings_form($form);

@ -6,6 +6,7 @@
* Import a backup from moodle system.
*
* @author José Loguercio <jose.loguercio@beeznest.com>
* @author Julio Montoya
*/
require_once __DIR__.'/../inc/global.inc.php';

@ -1,4 +1,5 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CourseBundle\Component\CourseCopy\CourseBuilder;
@ -9,8 +10,6 @@ use Chamilo\CourseBundle\Component\CourseCopy\CourseSelectForm;
* Delete resources from a course.
*
* @author Bart Mollet <bart.mollet@hogent.be>
*
* @package chamilo.backup
*/
require_once __DIR__.'/../inc/global.inc.php';
$current_course_tool = TOOL_COURSE_MAINTENANCE;
@ -70,20 +69,18 @@ if (Security::check_token('post') && (
$recycle_type = 'select_items';
}
$cr = new CourseRecycler($course);
if ($recycle_type == 'full_backup') {
if ($recycle_type === 'full_backup') {
/* to delete, course code confirmation must be equal that current course code */
if ($current_course_code == $courseCodeConfirmation) {
$cr->recycle($recycle_type);
echo Display::return_message(get_lang('RecycleFinished'), 'confirm');
} else {
$messageFailCourseCode = '<p>'.get_lang('CourseRegistrationCodeIncorrect').'</p>';
$messageFailCourseCode .= '<p><a class="btn btn-primary" href="'.api_get_self().'?'.api_get_cidreq().'">'.
echo Display::return_message(get_lang('CourseRegistrationCodeIncorrect'), 'error', false);
echo '<p><a class="btn btn-primary" href="'.api_get_self().'?'.api_get_cidreq().'">'.
get_lang('BackToPreviousPage').
'</a></p>';
echo Display::return_message($messageFailCourseCode, 'error', false);
}
} elseif ($recycle_type == 'select_items') {
} elseif ($recycle_type === 'select_items') {
$cr->recycle($recycle_type);
echo Display::return_message(get_lang('RecycleFinished'), 'confirm');
}
@ -108,25 +105,13 @@ if (Security::check_token('post') && (
} else {
echo Display::return_message(get_lang('RecycleWarning'), 'warning', false);
$form = new FormValidator('recycle_course', 'post', api_get_self().'?'.api_get_cidreq());
$form->addElement('header', get_lang('SelectOptionForBackup'));
$form->addHeader(get_lang('SelectOptionForBackup'));
$form->addElement('radio', 'recycle_option', null, get_lang('FullRecycle'), 'full_backup');
$form->addElement('radio', 'recycle_option', null, get_lang('LetMeSelectItems'), 'select_items');
//Confirmation input code
$form->addElement(
'label',
'',
'<span class="hidden course-full-delete">'.get_lang('CourseCodeConfirmation').'</span>',
null,
null
);
$form->addElement(
'input',
'course_code_confirmation',
null,
'class="hidden course-full-delete"',
'course_code'
);
$form->addHtml('<div class="course-full-delete hidden">');
$form->addText('course_code_confirmation', get_lang('CourseCodeConfirmation'));
$form->addHtml('</div>');
$form->addButtonSave(get_lang('RecycleCourse'));
$form->setDefaults(['recycle_option' => 'select_items']);
@ -137,20 +122,19 @@ if (Security::check_token('post') && (
$form->display();
/* make recycle_course_course_code_confirmation required to put code course */
echo '
<script>
$(function(){
$ (`[type="radio"]`).on (`change`, function (e) {
if ($ (this).val () === `full_backup`) {
$ (`#recycle_course_course_code_confirmation`).prop (`required`, `required`);
$ (`.course-full-delete`).removeClass(`hidden`);
} else {
$ (`#recycle_course_course_code_confirmation`).prop (`required`, ``);
$ (`.course-full-delete`).addClass(`hidden`);
}
});
})
</script>';
<script>
$(function(){
$(`[type="radio"]`).on(`change`, function (e) {
if ($(this).val() === `full_backup`) {
$(`#recycle_course_course_code_confirmation`).prop(`required`, `required`);
$(`.course-full-delete`).removeClass(`hidden`);
} else {
$(`#recycle_course_course_code_confirmation`).prop(`required`, ``);
$(`.course-full-delete`).addClass(`hidden`);
}
});
})
</script>';
}
}

@ -50,7 +50,7 @@ while ($user = Database::fetch_array($result, 'ASSOC')) {
Database::update($table, $params, ['id = ?' => $userId]);
$extraFields = [
'company' => $ldapUser['company'][0],
'company' => $ldapUser['department'][0],
];
foreach ($extraFields as $variable => $value) {
$params = [
@ -61,7 +61,6 @@ while ($user = Database::fetch_array($result, 'ASSOC')) {
print_r($params).PHP_EOL;
$extraFieldUser->save($params);
}
exit;
}
}
}

@ -16,6 +16,8 @@ $courseInfo = api_get_course_info($courseCode);
if (empty($courseInfo)) {
$courseInfo = api_get_course_info();
}
$type = preg_replace("/[^a-zA-Z_]+/", '', $type);
if (empty($courseInfo) || empty($type) || empty($file)) {
api_not_allowed(true);
}

@ -99,7 +99,8 @@ $is_visible = DocumentManager::check_visibility_tree(
);
if (!$is_allowed_to_edit && !$is_visible) {
api_not_allowed(true);
echo Display::return_message(get_lang('ProtectedDocument'), 'warning');
api_not_allowed(false, '&nbsp;');
}
$pathinfo = pathinfo($header_file);
@ -116,7 +117,6 @@ if (isset($group_id) && $group_id != '') {
if ($current_group) {
$current_group_name = $current_group['name'];
}
$interbreadcrumb[] = [
'url' => api_get_path(WEB_CODE_PATH).'group/group.php?'.api_get_cidreq(),
'name' => get_lang('Groups'),
@ -176,14 +176,14 @@ $frameheight = 135;
if (api_is_course_admin()) {
$frameheight = 165;
}
$execute_iframe = true;
$frameReady = Display::getFrameReadyBlock('#mainFrame');
$web_odf_supported_files = DocumentManager::get_web_odf_extension_list();
// PDF should be displayed with viewerJS
$web_odf_supported_files[] = 'pdf';
if (in_array(strtolower($pathinfo['extension']), $web_odf_supported_files)) {
$show_web_odf = true;
$execute_iframe = false;
$htmlHeadXtra[] = '
<script>
resizeIframe = function() {
@ -194,15 +194,14 @@ if (in_array(strtolower($pathinfo['extension']), $web_odf_supported_files)) {
$(function() {
$(window).resize(resizeIframe());
});
</script>'
;
</script>';
}
// Activate code highlight.
$isChatFolder = false;
if (isset($document_data['parents']) && isset($document_data['parents'][0])) {
$chatFolder = $document_data['parents'][0];
if (isset($chatFolder['path']) && $chatFolder['path'] == '/chat_files') {
if (isset($chatFolder['path']) && $chatFolder['path'] === '/chat_files') {
$isChatFolder = true;
}
}
@ -217,17 +216,12 @@ if ($isChatFolder) {
</script>';
}
$execute_iframe = true;
if ($playerSupported) {
$extension = api_strtolower($pathinfo['extension']);
$execute_iframe = false;
}
if ($show_web_odf) {
$execute_iframe = false;
}
$is_freemind_available = $pathinfo['extension'] == 'mm' && api_get_setting('enable_freemind') == 'true';
$is_freemind_available = $pathinfo['extension'] === 'mm' && api_get_setting('enable_freemind') === 'true';
if ($is_freemind_available) {
$execute_iframe = false;
}
@ -259,22 +253,6 @@ if ($originIsLearnpath) {
$file_url = api_get_path(WEB_COURSE_PATH).$courseInfo['path'].'/document'.$header_file;
$file_url_web = $file_url.'?'.api_get_cidreq();
if ($show_web_odf) {
echo '<div class="text-center">';
$browser = api_get_navigator();
$pdfUrl = api_get_path(WEB_LIBRARY_PATH).'javascript/ViewerJS/index.html#'.$file_url;
if ($browser['name'] == 'Mozilla' && preg_match('|.*\.pdf|i', $header_file)) {
$pdfUrl = $file_url;
}
echo '<div id="viewerJS">';
echo '<iframe id="viewerJSContent" frameborder="0" allowfullscreen="allowfullscreen" webkitallowfullscreen style="width:100%;"
src="'.$pdfUrl.'">
</iframe>';
echo '</div>';
echo '</div>';
}
if ($playerSupported) {
echo DocumentManager::generateMediaPreview($file_url_web, $extension);
}
@ -337,42 +315,37 @@ if ($is_freemind_available) {
//fo.addVariable("toolTipsBgColor","0xaaeeaa");: bgcolor for tooltips ej;"0xaaeeaa"
//fo.addVariable("defaultWordWrap","300"); //default 600
//
fo.write("flashcontent");
// ]]>
</script>
<?php
}
if ($execute_iframe) {
if ($isChatFolder) {
$content = Security::remove_XSS(file_get_contents($file_url_sys));
echo $content;
} else {
$parentId = $document_data['parent_id'];
$url = api_get_path(WEB_CODE_PATH).'document/document.php?'.api_get_cidreq().'&id='.$parentId;
$actionsLeft = Display::url(
Display::return_icon('back.png', get_lang('Back'), '', ICON_SIZE_MEDIUM),
$url
);
if (($execute_iframe || $show_web_odf) && !$isChatFolder) {
$parentId = $document_data['parent_id'];
$url = api_get_path(WEB_CODE_PATH).'document/document.php?'.api_get_cidreq().'&id='.$parentId;
$actionsLeft = Display::url(
Display::return_icon('back.png', get_lang('Back'), '', ICON_SIZE_MEDIUM),
$url
);
$groupMemberWithEditRights = false;
$groupId = api_get_group_id();
if (!empty($groupId)) {
$groupInfo = GroupManager::get_group_properties($groupId);
if ($groupInfo) {
$groupMemberWithEditRights = GroupManager::allowUploadEditDocument(
api_get_user_id(),
api_get_course_int_id(),
$groupInfo,
$document_data
);
}
$groupMemberWithEditRights = false;
$groupId = api_get_group_id();
if (!empty($groupId)) {
$groupInfo = GroupManager::get_group_properties($groupId);
if ($groupInfo) {
$groupMemberWithEditRights = GroupManager::allowUploadEditDocument(
api_get_user_id(),
api_get_course_int_id(),
$groupInfo,
$document_data
);
}
}
$allowToEdit = api_is_allowed_to_edit(null, true) || $groupMemberWithEditRights;
if ($allowToEdit) {
$allowToEdit = api_is_allowed_to_edit(null, true) || $groupMemberWithEditRights;
if ($allowToEdit) {
if (false === $show_web_odf) {
$actionsLeft .= Display::url(
Display::return_icon(
'edit.png',
@ -382,36 +355,65 @@ if ($execute_iframe) {
),
api_get_path(WEB_CODE_PATH).'document/edit_document.php?'.api_get_cidreq().'&id='.$document_id
);
}
$titleToShow = addslashes(basename($document_data['title']));
$titleToShow = addslashes(basename($document_data['title']));
$urlDeleteParams = http_build_query(
[
'action' => 'delete_item',
'id' => $parentId,
'deleteid' => $document_data['id'],
]
);
$urlDeleteParams = http_build_query(
[
'action' => 'delete_item',
'id' => $parentId,
'deleteid' => $document_data['id'],
]
);
$actionsLeft .= Display::url(
Display::return_icon('delete.png', get_lang('Delete'), '', ICON_SIZE_MEDIUM),
'#',
[
'data-item-title' => $titleToShow,
'data-href' => api_get_path(WEB_CODE_PATH).'document/document.php?'.api_get_cidreq(
).'&'.$urlDeleteParams,
'data-toggle' => 'modal',
'data-target' => '#confirm-delete',
]
);
$actionsLeft .= Display::url(
Display::return_icon('delete.png', get_lang('Delete'), '', ICON_SIZE_MEDIUM),
'#',
[
'data-item-title' => $titleToShow,
'data-href' => api_get_path(WEB_CODE_PATH).'document/document.php?'.api_get_cidreq().'&'.$urlDeleteParams,
'data-toggle' => 'modal',
'data-target' => '#confirm-delete',
]
);
if (false === $show_web_odf) {
$actionsLeft .= Display::url(
Display::return_icon('pdf.png', get_lang('Export2PDF'), [], ICON_SIZE_MEDIUM),
api_get_path(WEB_CODE_PATH).'document/document.php?'.api_get_cidreq(
).'&action=export_to_pdf&id='.$document_id
);
}
}
echo $toolbar = Display::toolbarAction('actions-documents', [$actionsLeft]);
}
echo $toolbar = Display::toolbarAction('actions-documents', [$actionsLeft]);
if ($show_web_odf) {
$execute_iframe = false;
echo '<div class="text-center">';
$browser = api_get_navigator();
$pdfUrl = api_get_path(WEB_LIBRARY_PATH).'javascript/ViewerJS/index.html?zoom=page-width#'.$file_url;
if ($browser['name'] === 'Mozilla' && preg_match('|.*\.pdf|i', $header_file)) {
$pdfUrl = $file_url;
}
echo '<div id="viewerJS">';
echo '<iframe
id="viewerJSContent"
frameborder="0"
allowfullscreen="allowfullscreen"
webkitallowfullscreen
style="width:100%;height:600px;"
src="'.$pdfUrl.'">
</iframe>';
echo '</div>';
echo '</div>';
}
if ($execute_iframe) {
if ($isChatFolder) {
$content = Security::remove_XSS(file_get_contents($file_url_sys));
echo $content;
} else {
echo '<iframe
id="mainFrame"
name="mainFrame"

@ -95,6 +95,8 @@ class Exercise
public $hideComment;
public $hideNoAnswer;
public $hideExpectedAnswer;
public $forceShowExpectedChoiceColumn;
public $disableHideCorrectAnsweredQuestions;
/**
* Constructor of the class.
@ -139,6 +141,7 @@ class Exercise
$this->hideComment = false;
$this->hideNoAnswer = false;
$this->hideExpectedAnswer = false;
$this->disableHideCorrectAnsweredQuestions = false;
if (!empty($courseId)) {
$courseInfo = api_get_course_info_by_id($courseId);
@ -2205,6 +2208,12 @@ class Exercise
null,
get_lang('HideCategoryTable')
),
$form->createElement(
'checkbox',
'hide_correct_answered_questions',
null,
get_lang('HideCorrectAnsweredQuestions')
),
];
$form->addGroup($group, null, get_lang('ResultsConfigurationPage'));
}
@ -2616,6 +2625,11 @@ class Exercise
{
// Feedback type.
$feedback = [];
$warning = sprintf(
get_lang('TheSettingXWillChangeToX'),
get_lang('ShowResultsToStudents'),
get_lang('ShowScoreAndRightAnswer')
);
$endTest = $form->createElement(
'radio',
'exerciseFeedbackType',
@ -2624,7 +2638,8 @@ class Exercise
EXERCISE_FEEDBACK_TYPE_END,
[
'id' => 'exerciseType_'.EXERCISE_FEEDBACK_TYPE_END,
'onclick' => 'check_feedback()',
//'onclick' => 'if confirm() check_feedback()',
'onclick' => 'javascript:if(confirm('."'".addslashes($warning)."'".')) { check_feedback(); } else { return false;} ',
]
);
@ -3320,8 +3335,6 @@ class Exercise
}
$isReviewingAnswers = isset($_REQUEST['reminder']) && 2 === (int) $_REQUEST['reminder'];
// User
$endReminderValue = false;
if (!empty($myRemindList) && $isReviewingAnswers) {
$endValue = end($myRemindList);
@ -3329,11 +3342,13 @@ class Exercise
$endReminderValue = true;
}
}
$endTest = false;
if ($this->type == ALL_ON_ONE_PAGE || $nbrQuestions == $questionNum || $endReminderValue) {
if ($this->review_answers) {
$label = get_lang('ReviewQuestions');
$class = 'btn btn-success';
} else {
$endTest = true;
$label = get_lang('EndTest');
$class = 'btn btn-warning';
}
@ -3396,10 +3411,15 @@ class Exercise
]
);
} else {
$attributes = ['type' => 'button', 'class' => $class, 'data-question' => $question_id];
$name = 'save_now';
if ($endTest && api_get_configuration_value('quiz_check_all_answers_before_end_test')) {
$name = 'check_answers';
}
$buttonList[] = Display::button(
'save_now',
$name,
$label,
['type' => 'button', 'class' => $class, 'data-question' => $question_id]
$attributes
);
}
$buttonList[] = '<span id="save_for_now_'.$question_id.'" class="exercise_save_mini_message"></span>';
@ -3713,7 +3733,6 @@ class Exercise
if ($answerType == ORAL_EXPRESSION) {
$exe_info = Event::get_exercise_results_by_attempt($exeId);
$exe_info = isset($exe_info[$exeId]) ? $exe_info[$exeId] : null;
$objQuestionTmp->initFile(
api_get_session_id(),
isset($exe_info['exe_user_id']) ? $exe_info['exe_user_id'] : api_get_user_id(),
@ -3843,7 +3862,6 @@ class Exercise
$option = isset($values[1]) ? $values[1] : '';
$choice[$my_answer_id] = $option;
}
$userAnsweredQuestion = !empty($choice);
}
@ -4451,14 +4469,13 @@ class Exercise
$result = Database::query($sql);
$data = Database::fetch_array($result);
$choice = '';
$questionScore = 0;
if ($data) {
$choice = $data['answer'];
$questionScore = $data['marks'];
}
$choice = str_replace('\r\n', '', $choice);
$choice = stripslashes($choice);
$questionScore = $data['marks'];
if (-1 == $questionScore) {
$totalScore += 0;
} else {
@ -4924,7 +4941,7 @@ class Exercise
$coords = array_filter($coords);
$user_array = '';
foreach ($coords as $coord) {
list($x, $y) = explode(';', $coord);
[$x, $y] = explode(';', $coord);
$user_array .= round($x).';'.round($y).'/';
}
$user_array = substr($user_array, 0, -1) ?: '';
@ -7749,7 +7766,7 @@ class Exercise
}
}
$attributes = ['id' => 'remind_list['.$questionId.']'];
$attributes = ['id' => 'remind_list['.$questionId.']', 'data-question-id' => $questionId];
// Showing the question
$exercise_actions = null;
@ -8323,10 +8340,11 @@ class Exercise
$pageConfig = api_get_configuration_value('allow_quiz_results_page_config');
if ($pageConfig) {
$params = [
'hide_expected_answer' => isset($values['hide_expected_answer']) ? $values['hide_expected_answer'] : '',
'hide_question_score' => isset($values['hide_question_score']) ? $values['hide_question_score'] : '',
'hide_total_score' => isset($values['hide_total_score']) ? $values['hide_total_score'] : '',
'hide_category_table' => isset($values['hide_category_table']) ? $values['hide_category_table'] : '',
'hide_expected_answer' => $values['hide_expected_answer'] ?? '',
'hide_question_score' => $values['hide_question_score'] ?? '',
'hide_total_score' => $values['hide_total_score'] ?? '',
'hide_category_table' => $values['hide_category_table'] ?? '',
'hide_correct_answered_questions' => $values['hide_correct_answered_questions'] ?? '',
];
$type = Type::getType('array');
$platform = Database::getManager()->getConnection()->getDatabasePlatform();
@ -8418,6 +8436,10 @@ class Exercise
*/
public function showExpectedChoiceColumn()
{
if (true === $this->forceShowExpectedChoiceColumn) {
return true;
}
if ($this->hideExpectedAnswer) {
return false;
}
@ -10361,11 +10383,12 @@ class Exercise
return $lpList;
}
public function getReminderTable($questionList, $exercise_stat_info)
public function getReminderTable($questionList, $exercise_stat_info, $disableCheckBoxes = false)
{
$learnpath_id = isset($_REQUEST['learnpath_id']) ? (int) $_REQUEST['learnpath_id'] : 0;
$learnpath_item_id = isset($_REQUEST['learnpath_item_id']) ? (int) $_REQUEST['learnpath_item_id'] : 0;
$learnpath_item_view_id = isset($_REQUEST['learnpath_item_view_id']) ? (int) $_REQUEST['learnpath_item_view_id'] : 0;
$categoryId = isset($_REQUEST['category_id']) ? (int) $_REQUEST['category_id'] : 0;
if (empty($exercise_stat_info)) {
return '';
@ -10373,7 +10396,6 @@ class Exercise
$remindList = $exercise_stat_info['questions_to_check'];
$remindList = explode(',', $remindList);
$exeId = $exercise_stat_info['exe_id'];
$exerciseId = $exercise_stat_info['exe_exo_id'];
$exercise_result = $this->getUserAnswersSavedInExercise($exeId);
@ -10386,7 +10408,11 @@ class Exercise
foreach ($questionList as $questionId) {
$objQuestionTmp = Question::read($questionId);
$check_id = 'remind_list['.$questionId.']';
$attributes = ['id' => $check_id, 'onclick' => "save_remind_item(this, '$questionId');"];
$attributes = [
'id' => $check_id,
'onclick' => "save_remind_item(this, '$questionId');",
'data-question-id' => $questionId,
];
if (in_array($questionId, $remindList)) {
$attributes['checked'] = 1;
}
@ -10407,10 +10433,11 @@ class Exercise
if (!in_array($questionId, $exercise_result)) {
$questionTitle = Display::label($questionTitle, 'danger');
}
$label_attributes = [];
$label_attributes['for'] = $check_id;
$questionTitle = Display::tag('label', $checkbox.$questionTitle, $label_attributes);
if (false === $disableCheckBoxes) {
$questionTitle = Display::tag('label', $checkbox.$questionTitle, $label_attributes);
}
$table .= Display::div($questionTitle, ['class' => 'exercise_reminder_item ']);
}
@ -10429,26 +10456,39 @@ class Exercise
window.location = "'.api_get_path(WEB_CODE_PATH).'exercise/exercise_result.php?'.api_get_cidreq().'&exe_id='.$exeId.'&" + lp_data;
}
function selectAll() {
$("input[type=checkbox]").each(function () {
$(this).prop("checked", 1);
var question_id = $(this).data("question-id");
var action = "add";
$.ajax({
url: "'.api_get_path(WEB_AJAX_PATH).'exercise.ajax.php?'.api_get_cidreq().'&a=add_question_to_reminder",
data: "question_id="+question_id+"&exe_id='.$exeId.'&action="+action,
success: function(returnValue) {
}
});
});
}
function changeOptionStatus(status)
{
$("input[type=checkbox]").each(function () {
$(this).prop("checked", status);
});
var action = "";
var extraOption = "remove_all";
var option = "remove_all";
if (status == 1) {
extraOption = "add_all";
option = "add_all";
}
$.ajax({
url: "'.api_get_path(WEB_AJAX_PATH).'exercise.ajax.php?'.api_get_cidreq().'&a=add_question_to_reminder",
data: "option="+extraOption+"&exe_id='.$exeId.'&action="+action,
data: "option="+option+"&exe_id='.$exeId.'&action="+action,
success: function(returnValue) {
}
});
}
function review_questions() {
function reviewQuestions() {
var isChecked = 1;
$("input[type=checkbox]").each(function () {
if ($(this).prop("checked")) {
@ -10461,7 +10501,7 @@ class Exercise
$("#message").addClass("warning-message");
$("#message").html("'.addslashes(get_lang('SelectAQuestionToReview')).'");
} else {
window.location = "exercise_submit.php?'.api_get_cidreq().'&exerciseId='.$exerciseId.'&reminder=2&" + lp_data;
window.location = "exercise_submit.php?'.api_get_cidreq().'&category_id='.$categoryId.'&exerciseId='.$exerciseId.'&reminder=2&" + lp_data;
}
}

@ -14,7 +14,6 @@ if (false === api_get_configuration_value('block_category_questions')) {
$this_section = SECTION_COURSES;
api_protect_course_script(true);
$origin = api_get_origin();
$learnpath_id = isset($_REQUEST['learnpath_id']) ? (int) $_REQUEST['learnpath_id'] : 0;
$learnpath_item_id = isset($_REQUEST['learnpath_item_id']) ? (int) $_REQUEST['learnpath_item_id'] : 0;
$learnpath_item_view_id = isset($_REQUEST['learnpath_item_view_id']) ? (int) $_REQUEST['learnpath_item_view_id'] : 0;
@ -38,10 +37,11 @@ if (empty($objExercise) || empty($questionCategoryId) || empty($exeId) || empty(
api_not_allowed(true);
}
$categoryId = $categoryObj->id;
$categoryId = (int) $categoryObj->id;
$params = "exe_id=$exeId&exerciseId=$exerciseId&learnpath_id=$learnpath_id&learnpath_item_id=$learnpath_item_id&learnpath_item_view_id=$learnpath_item_view_id&".api_get_cidreq();
$url = api_get_path(WEB_CODE_PATH).'exercise/exercise_submit.php?'.$params;
$validateUrl = api_get_self().'?'.$params.'&category_id='.$categoryId.'&validate=1';
$validateUrl = api_get_path(WEB_CODE_PATH).'exercise/exercise_question_reminder.php?'.
$params.'&category_id='.$categoryId.'&validate=1';
$time_control = false;
$clock_expired_time = ExerciseLib::get_session_time_control_key(
@ -88,7 +88,6 @@ if ($validateCategory) {
// Cleaning old remind list.
$objExercise->removeAllQuestionToRemind($exeId);
api_location($url.'&num='.$currentQuestion);
}
@ -103,11 +102,11 @@ if (!$hideHeaderAndFooter) {
}
// I'm in a preview mode as course admin. Display the action menu.
if (api_is_course_admin() && !$hideHeaderAndFooter) {
if (!$hideHeaderAndFooter && api_is_course_admin()) {
echo '<div class="actions">';
echo '<a href="admin.php?'.api_get_cidreq().'&exerciseId='.$objExercise->id.'">'.
echo '<a href="admin.php?'.api_get_cidreq().'&exerciseId='.$objExercise->iId.'">'.
Display::return_icon('back.png', get_lang('GoBackToQuestionList'), [], 32).'</a>';
echo '<a href="exercise_admin.php?'.api_get_cidreq().'&modifyExercise=yes&exerciseId='.$objExercise->id.'">'.
echo '<a href="exercise_admin.php?'.api_get_cidreq().'&modifyExercise=yes&exerciseId='.$objExercise->iId.'">'.
Display::return_icon('edit.png', get_lang('ModifyExercise'), [], 32).'</a>';
echo '</div>';
}
@ -115,12 +114,14 @@ echo Display::page_header($categoryObj->name);
echo '<p>'.Security::remove_XSS($categoryObj->description).'</p>';
echo '<p>'.get_lang('BlockCategoryExplanation').'</p>';
$categoryList = Session::read('categoryList');
$disableAllQuestions = '';
$questionList = [];
if (isset($categoryList[$categoryId])) {
$questionList = $categoryList[$categoryId];
}
if ($objExercise->review_answers) {
$questionList = [];
$categoryList = Session::read('categoryList');
if (isset($categoryList[$categoryId])) {
$questionList = $categoryList[$categoryId];
}
$disableAllQuestions = 'changeOptionStatus(0);';
echo $objExercise->getReminderTable($questionList, $trackInfo);
}
@ -130,19 +131,28 @@ if ($time_control) {
echo Display::div('', ['id' => 'message']);
$previousQuestion = $currentQuestion - 1;
echo '<script>
var lp_data = $.param({
"learnpath_id": '.$learnpath_id.',
"learnpath_item_id" : '.$learnpath_item_id.',
"learnpath_item_view_id": '.$learnpath_item_view_id.'
});
$nextQuestion = $currentQuestion + 1;
if (!empty($questionList)) {
$firstQuestionOfCategory = end($questionList);
$dataTracking = explode(',', $trackInfo['data_tracking']);
$index = 0;
foreach ($dataTracking as $index => $question) {
if ($firstQuestionOfCategory == $question) {
break;
}
}
$nextQuestion = $index + 1;
}
echo '<script>
function goBack() {
window.location = "'.$url.'&num='.$previousQuestion.'&" + lp_data;
window.location = "'.$url.'&num='.$previousQuestion.'";
}
function continueExercise() {
window.location = "'.$validateUrl.'&num='.$currentQuestion.'&" + lp_data;
'.$disableAllQuestions.'
window.location = "'.$validateUrl.'&num='.$nextQuestion.'";
}
function final_submit() {
@ -164,17 +174,43 @@ if (!in_array($categoryId, $blockedCategories)) {
['onclick' => 'goBack();', 'class' => 'btn btn-default']
);
}
$exerciseActions .= '&nbsp;'.Display::url(
get_lang('ContinueTest'),
'javascript://',
['onclick' => 'continueExercise();', 'class' => 'btn btn-primary']
);
/*
$exerciseActions .= '&nbsp;'.Display::url(
get_lang('EndTest'),
'javascript://',
['onclick' => 'final_submit();', 'class' => 'btn btn-warning']
);*/
if ($objExercise->review_answers) {
$exerciseActions .= Display::url(
get_lang('ReviewQuestions'),
'javascript://',
['onclick' => 'reviewQuestions();', 'class' => 'btn btn-primary']
);
$exerciseActions .= '&nbsp;'.Display::url(
get_lang('SelectAll'),
'javascript://',
['onclick' => 'selectAll();', 'class' => 'btn btn-default']
);
$exerciseActions .= '&nbsp;'.Display::url(
get_lang('UnSelectAll'),
'javascript://',
['onclick' => 'changeOptionStatus(0);', 'class' => 'btn btn-default']
);
}
end($categoryList);
// This is the last category
if (key($categoryList) === $categoryId) {
$exerciseActions .= '&nbsp;'.Display::url(
get_lang('EndTest'),
'javascript://',
['onclick' => 'final_submit();', 'class' => 'btn btn-warning']
);
} else {
$exerciseActions .= '&nbsp;'.Display::url(
get_lang('ContinueTest'),
'javascript://',
['onclick' => 'continueExercise();', 'class' => 'btn btn-primary']
);
}
echo Display::div('', ['class' => 'clear']);
echo Display::div($exerciseActions, ['class' => 'form-actions']);

@ -82,14 +82,13 @@ $interbreadcrumb[] = ['url' => 'exercise.php?'.api_get_cidreq(), 'name' => get_l
$hideHeaderAndFooter = in_array($origin, ['learnpath', 'embeddable']);
if (!$hideHeaderAndFooter) {
//so we are not in learnpath tool
Display::display_header($nameTools, get_lang('Exercise'));
} else {
Display::display_reduced_header();
}
// I'm in a preview mode as course admin. Display the action menu.
if (api_is_course_admin() && !$hideHeaderAndFooter) {
if (!$hideHeaderAndFooter && api_is_course_admin()) {
echo '<div class="actions">';
echo '<a href="admin.php?'.api_get_cidreq().'&exerciseId='.$objExercise->id.'">'.
Display::return_icon('back.png', get_lang('GoBackToQuestionList'), [], 32).'</a>';
@ -122,7 +121,7 @@ echo $objExercise->getReminderTable($question_list, $exercise_stat_info);
$exerciseActions = Display::url(
get_lang('ReviewQuestions'),
'javascript://',
['onclick' => 'review_questions();', 'class' => 'btn btn-primary']
['onclick' => 'reviewQuestions();', 'class' => 'btn btn-primary']
);
$exerciseActions .= '&nbsp;'.Display::url(

@ -18,7 +18,7 @@ $htmlHeadXtra[] = api_get_jqgrid_js();
$filter_user = isset($_REQUEST['filter_by_user']) ? (int) $_REQUEST['filter_by_user'] : null;
$isBossOfStudent = false;
if (api_is_student_boss() && !empty($filter_user)) {
if (!empty($filter_user) && api_is_student_boss()) {
// Check if boss has access to user info.
if (UserManager::userIsBossOfStudent(api_get_user_id(), $filter_user)) {
$isBossOfStudent = true;
@ -157,7 +157,6 @@ if (isset($_REQUEST['comments']) &&
// Filtered by post-condition
$id = (int) $_GET['exeid'];
$track_exercise_info = ExerciseLib::get_exercise_track_exercise_info($id);
if (empty($track_exercise_info)) {
api_not_allowed();
}
@ -168,54 +167,73 @@ if (isset($_REQUEST['comments']) &&
$lp_item_view_id = (int) $track_exercise_info['orig_lp_item_view_id'];
$exerciseId = $track_exercise_info['exe_exo_id'];
$exeWeighting = $track_exercise_info['exe_weighting'];
$attemptData = Event::get_exercise_results_by_attempt($id);
$questionListData = [];
if ($attemptData && $attemptData[$id] && $attemptData[$id]['question_list']) {
$questionListData = $attemptData[$id]['question_list'];
}
$post_content_id = [];
$comments_exist = false;
$questionListInPost = [];
foreach ($_POST as $key_index => $key_value) {
$my_post_info = explode('_', $key_index);
$post_content_id[] = isset($my_post_info[1]) ? $my_post_info[1] : null;
if ($my_post_info[0] === 'comments') {
$comments_exist = true;
$questionListInPost[] = $my_post_info[1];
}
}
$loop_in_track = $comments_exist === true ? (count($_POST) / 2) : count($_POST);
if ($comments_exist === true) {
$array_content_id_exe = array_slice($post_content_id, $loop_in_track);
} else {
$array_content_id_exe = $post_content_id;
}
for ($i = 0; $i < $loop_in_track; $i++) {
$my_marks = isset($_POST['marks_'.$array_content_id_exe[$i]]) ? $_POST['marks_'.$array_content_id_exe[$i]] : '';
$my_comments = '';
if (isset($_POST['comments_'.$array_content_id_exe[$i]])) {
$my_comments = $_POST['comments_'.$array_content_id_exe[$i]];
}
$my_questionid = (int) $array_content_id_exe[$i];
foreach ($questionListInPost as $questionId) {
$marks = $_POST['marks_'.$questionId] ?? 0;
$my_comments = $_POST['comments_'.$questionId] ?? '';
$params = [
'marks' => $my_marks,
'teacher_comment' => $my_comments,
];
$question = Question::read($questionId);
if (false === $question) {
continue;
}
// From the database.
$marksFromDatabase = $questionListData[$questionId]['marks'];
if (in_array($question->type, [FREE_ANSWER, ORAL_EXPRESSION, ANNOTATION])) {
// From the form.
$params['marks'] = $marks;
if ($marksFromDatabase != $marks) {
Event::addEvent(
LOG_QUESTION_SCORE_UPDATE,
LOG_EXERCISE_ATTEMPT_QUESTION_ID,
[
'exe_id' => $id,
'question_id' => $questionId,
'old_marks' => $marksFromDatabase,
'new_marks' => $marks,
]
);
}
} else {
$marks = $marksFromDatabase;
}
Database::update(
$TBL_TRACK_ATTEMPT,
$params,
['question_id = ? AND exe_id = ?' => [$my_questionid, $id]]
['question_id = ? AND exe_id = ?' => [$questionId, $id]]
);
$params = [
'exe_id' => $id,
'question_id' => $my_questionid,
'marks' => $my_marks,
'question_id' => $questionId,
'marks' => $marks,
'insert_date' => api_get_utc_datetime(),
'author' => api_get_user_id(),
'teacher_comment' => $my_comments,
];
Database::insert($TBL_TRACK_ATTEMPT_RECORDING, $params);
}
$useEvaluationPlugin = false;
$pluginEvaluation = QuestionOptionsEvaluationPlugin::create();
@ -251,14 +269,12 @@ if (isset($_REQUEST['comments']) &&
//@todo move this somewhere else
$subject = get_lang('ExamSheetVCC');
$message = isset($_POST['notification_content']) ? $_POST['notification_content'] : '';
MessageManager::send_message_simple(
$student_id,
$subject,
$message,
api_get_user_id()
);
if ($allowCoachFeedbackExercises) {
Display::addFlash(
Display::return_message(get_lang('MessageSent'))
@ -268,6 +284,9 @@ if (isset($_REQUEST['comments']) &&
$notifications = api_get_configuration_value('exercise_finished_notification_settings');
if ($notifications) {
$oldResultDisabled = $objExerciseTmp->results_disabled;
$objExerciseTmp->results_disabled = RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS;
ob_start();
$stats = ExerciseLib::displayQuestionListByAttempt(
$objExerciseTmp,
@ -278,7 +297,27 @@ if (isset($_REQUEST['comments']) &&
api_get_configuration_value('quiz_results_answers_report'),
false
);
$objExerciseTmp->results_disabled = $oldResultDisabled;
ob_end_clean();
// Show all for teachers.
$oldResultDisabled = $objExerciseTmp->results_disabled;
$objExerciseTmp->results_disabled = RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS;
$objExerciseTmp->forceShowExpectedChoiceColumn = true;
ob_start();
$statsTeacher = ExerciseLib::displayQuestionListByAttempt(
$objExerciseTmp,
$track_exercise_info['exe_id'],
false,
false,
false,
api_get_configuration_value('quiz_results_answers_report'),
false
);
ob_end_clean();
$objExerciseTmp->forceShowExpectedChoiceColumn = false;
$objExerciseTmp->results_disabled = $oldResultDisabled;
$attemptCount = Event::getAttemptPosition(
$track_exercise_info['exe_id'],
@ -295,7 +334,8 @@ if (isset($_REQUEST['comments']) &&
$track_exercise_info,
api_get_course_info(),
$attemptCount,
$stats
$stats,
$statsTeacher
);
}

@ -60,6 +60,12 @@ class ExerciseResult
$session_id_and = ' AND te.session_id = '.$sessionId.' ';
$exercise_id = (int) $exercise_id;
if (empty($sessionId) &&
api_get_configuration_value('show_exercise_session_attempts_in_base_course')
) {
$session_id_and = '';
}
if (!empty($exercise_id)) {
$session_id_and .= " AND exe_exo_id = $exercise_id ";
}

@ -82,6 +82,7 @@ if (!empty($objExercise->getResultAccess())) {
$showHeader = false;
$showFooter = false;
$showLearnPath = true;
$pageActions = '';
$pageTop = '';
$pageBottom = '';
@ -90,6 +91,7 @@ $courseInfo = api_get_course_info();
if (!in_array($origin, ['learnpath', 'embeddable', 'mobileapp'])) {
// So we are not in learnpath tool
$showHeader = true;
$showLearnPath = false;
}
// I'm in a preview mode as course admin. Display the action menu.
@ -202,7 +204,7 @@ if (!empty($exercise_stat_info)) {
$max_score = $objExercise->get_max_score();
if ($origin === 'embeddable') {
if ('embeddable' === $origin) {
$pageTop .= showEmbeddableFinishButton();
} else {
Display::addFlash(
@ -224,6 +226,30 @@ $stats = ExerciseLib::displayQuestionListByAttempt(
);
$pageContent .= ob_get_contents();
ob_end_clean();
// Change settings for teacher access.
$oldResultDisabled = $objExercise->results_disabled;
$objExercise->results_disabled = RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS;
$objExercise->forceShowExpectedChoiceColumn = true;
$objExercise->disableHideCorrectAnsweredQuestions = true;
ob_start();
$statsTeacher = ExerciseLib::displayQuestionListByAttempt(
$objExercise,
$exeId,
false,
$remainingMessage,
$allowSignature,
api_get_configuration_value('quiz_results_answers_report'),
false
);
ob_end_clean();
// Restore settings.
$objExercise->results_disabled = $oldResultDisabled;
$objExercise->forceShowExpectedChoiceColumn = false;
$objExercise->disableHideCorrectAnsweredQuestions = false;
// Save here LP status
if (!empty($learnpath_id) && $saveResults) {
// Save attempt in lp
@ -236,7 +262,8 @@ ExerciseLib::sendNotification(
$exercise_stat_info,
$courseInfo,
$attempt_count++,
$stats
$stats,
$statsTeacher
);
$hookQuizEnd = HookQuizEnd::create();
@ -289,7 +316,7 @@ if (!in_array($origin, ['learnpath', 'embeddable', 'mobileapp'])) {
$showFooter = false;
}
$template = new Template($nameTools, $showHeader, $showFooter);
$template = new Template($nameTools, $showHeader, $showFooter, $showLearnPath);
$template->assign('page_top', $pageTop);
$template->assign('page_content', $pageContent);
$template->assign('page_bottom', $pageBottom);

@ -402,6 +402,11 @@ $arrmarks = [];
$strids = '';
$marksid = '';
$countPendingQuestions = 0;
$audioTemplate = null;
if ($allowRecordAudio && $allowTeacherCommentAudio) {
$audioTemplate = new Template('', false, false, false, false, false, false);
}
foreach ($questionList as $questionId) {
$choice = isset($exerciseResult[$questionId]) ? $exerciseResult[$questionId] : '';
// destruction of the Question object
@ -635,8 +640,6 @@ foreach ($questionList as $questionId) {
$renderer = &$feedback_form->defaultRenderer();
$renderer->setFormTemplate('<form{attributes}><div>{content}</div></form>');
$renderer->setCustomElementTemplate('<div>{element}</div>');
$comnt = Event::get_comments($id, $questionId);
$textareaId = 'comments_'.$questionId;
$default = [$textareaId => $comnt];
@ -657,12 +660,11 @@ foreach ($questionList as $questionId) {
}
$feedback_form->setDefaults($default);
$feedback_form->display();
echo '</div>';
if ($allowRecordAudio && $allowTeacherCommentAudio) {
echo '<div class="col-sm-5">';
echo ExerciseLib::getOralFeedbackForm($id, $questionId, $student_id);
echo ExerciseLib::getOralFeedbackForm($audioTemplate, $id, $questionId, $student_id);
echo '</div>';
}
echo '</div>';

@ -127,10 +127,8 @@ $exerciseResult = isset($_REQUEST['exerciseResult']) ? $_REQUEST['exerciseResult
$exerciseResultCoordinates = isset($_REQUEST['exerciseResultCoordinates']) ? $_REQUEST['exerciseResultCoordinates'] : null;
$choice = isset($_REQUEST['choice']) ? $_REQUEST['choice'] : null;
$choice = empty($choice) ? isset($_REQUEST['choice2']) ? $_REQUEST['choice2'] : null : null;
$questionCategoryId = isset($_REQUEST['category_id']) ? (int) $_REQUEST['category_id'] : 0;
$current_question = $currentQuestionFromUrl = isset($_REQUEST['num']) ? (int) $_REQUEST['num'] : null;
$currentAnswer = isset($_REQUEST['num_answer']) ? (int) $_REQUEST['num_answer'] : null;
$logInfo = [
'tool' => TOOL_QUIZ,
'tool_id' => $exerciseId,
@ -176,7 +174,7 @@ if (empty($exerciseInSession) || (!empty($exerciseInSession) && $exerciseInSessi
} else {
Session::write('firstTime', false);
}
//2. Checking if $objExercise is set.
// 2. Checking if $objExercise is set.
/** @var |Exercise $objExercise */
if (!isset($objExercise) && isset($exerciseInSession)) {
if ($debug) {
@ -434,12 +432,13 @@ if (empty($exercise_stat_info)) {
$exe_id = $exercise_stat_info['exe_id'];
// Remember last question id position.
$isFirstTime = Session::read('firstTime');
//$isFirstTime = true;
if ($isFirstTime && ONE_PER_PAGE == $objExercise->type) {
$resolvedQuestions = Event::getAllExerciseEventByExeId($exe_id);
if (!empty($resolvedQuestions) &&
!empty($exercise_stat_info['data_tracking'])
) {
$last = current(end($resolvedQuestions));
/*$last = current(end($resolvedQuestions));
$attemptQuestionList = explode(',', $exercise_stat_info['data_tracking']);
$count = 1;
foreach ($attemptQuestionList as $question) {
@ -449,10 +448,26 @@ if (empty($exercise_stat_info)) {
$count++;
}
$current_question = $count;
*/
// Get current question based in data_tracking question list, instead of track_e_attempt order BT#17789.
$resolvedQuestionsQuestionIds = array_keys($resolvedQuestions);
$count = 0;
$attemptQuestionList = explode(',', $exercise_stat_info['data_tracking']);
//var_dump($attemptQuestionList, $resolvedQuestionsQuestionIds);
foreach ($attemptQuestionList as $index => $question) {
if (in_array($question, $resolvedQuestionsQuestionIds)) {
$count = $index;
continue;
}
}
$current_question = $count;
//var_dump($current_question, $index);exit;
}
}
}
Session::write('exe_id', $exe_id);
$checkAnswersUrl = api_get_path(WEB_AJAX_PATH).'exercise.ajax.php?a=check_answers&exe_id='.$exe_id.'&'.api_get_cidreq();
$saveDurationUrl = api_get_path(WEB_AJAX_PATH).'exercise.ajax.php?a=update_duration&exe_id='.$exe_id.'&'.api_get_cidreq();
$questionListInSession = Session::read('questionList');
$selectionType = $objExercise->getQuestionSelectionType();
@ -508,7 +523,7 @@ if (!empty($exercise_stat_info['questions_to_check'])) {
}
$params = "exe_id=$exe_id&exerciseId=$exerciseId&learnpath_id=$learnpath_id&learnpath_item_id=$learnpath_item_id&learnpath_item_view_id=$learnpath_item_view_id&".api_get_cidreq().'&reminder='.$reminder;
if (2 == $reminder && empty($myRemindList)) {
if (2 === $reminder && empty($myRemindList)) {
if ($debug) {
error_log('6.2 calling the exercise_reminder.php');
}
@ -598,7 +613,6 @@ if ($time_control) {
//Sends the exercise form when the expired time is finished.
$htmlHeadXtra[] = $objExercise->showTimeControlJS($time_left);
}
// in LP's is enabled the "remember question" feature?
if (!isset($_SESSION['questionList'])) {
// selects the list of question ID
@ -657,35 +671,43 @@ if ($allowBlockCategory &&
}
$count++;
}
//var_dump($questionCheck);exit;
// Use reminder list to get the current question.
if (2 === $reminder && !empty($myRemindList)) {
/*if (2 === $reminder && !empty($myRemindList)) {
$remindQuestionId = current($myRemindList);
$questionCheck = Question::read($remindQuestionId);
}
}*/
$categoryId = 0;
if (null !== $questionCheck) {
$categoryId = $questionCheck->category;
}
if ($objExercise->review_answers && isset($_GET['category_id'])) {
$categoryId = $_GET['category_id'] ?? 0;
}
//var_dump($categoryId, $categoryList);
if (!empty($categoryId)) {
$categoryInfo = $categoryList[$categoryId];
$count = 1;
$total = count($categoryList[$categoryId]);
//var_dump($questionCheck);
foreach ($categoryList[$categoryId] as $checkQuestionId) {
if ((int) $checkQuestionId === $questionCheck->iid) {
if ((int) $checkQuestionId === (int) $questionCheck->iid) {
break;
}
$count++;
}
//var_dump($count , $total);
if ($count === $total) {
$isLastQuestionInCategory = $categoryId;
if ($isLastQuestionInCategory) {
// This is the last question
if ((int) $current_question + 1 === count($questionList)) {
$isLastQuestionInCategory = 0;
if (false === $objExercise->review_answers) {
$isLastQuestionInCategory = 0;
}
}
}
}
@ -693,7 +715,11 @@ if ($allowBlockCategory &&
if (0 === $isLastQuestionInCategory) {
$showPreviousButton = false;
}
if (0 === $isLastQuestionInCategory && 2 === $reminder) {
// $isLastQuestionInCategory = $categoryId;
}
}
//var_dump($categoryId, $blockedCategories, $isLastQuestionInCategory);
// Blocked if category was already answered.
if ($categoryId && in_array($categoryId, $blockedCategories)) {
@ -703,7 +729,8 @@ if ($allowBlockCategory &&
api_location($url);
}
}
//exit;
//var_dump($isLastQuestionInCategory);
if ($debug) {
error_log('8. Question list loaded '.print_r($questionList, 1));
}
@ -713,7 +740,7 @@ $question_count = 0;
if (!empty($questionList)) {
$question_count = count($questionList);
}
//var_dump($current_question);
if ($current_question > $question_count) {
// If time control then don't change the current question, otherwise there will be a loop.
// @todo
@ -757,7 +784,7 @@ if ($formSent && isset($_POST)) {
$exerciseResult = $choice;
} else {
// gets the question ID from $choice. It is the key of the array
list($key) = array_keys($choice);
[$key] = array_keys($choice);
// if the user didn't already answer this question
if (!isset($exerciseResult[$key])) {
// stores the user answer into the array
@ -964,7 +991,6 @@ if ($allowTimePerQuestion && $objExercise->type == ONE_PER_PAGE) {
$previousQuestion = $objQuestionTmp;
}
}
$extraFieldValue = new ExtraFieldValue('question');
$value = $extraFieldValue->get_values_by_handler_and_field_variable($objQuestionTmp->iid, 'time');
if (!empty($value) && isset($value['value']) && !empty($value['value'])) {
@ -1128,10 +1154,10 @@ if ($showQuestionClock) {
if (!in_array($origin, ['learnpath', 'embeddable'])) {
echo '<div id="highlight-plugin" class="glossary-content">';
}
if ($reminder == 2) {
if (2 === $reminder) {
$data_tracking = $exercise_stat_info['data_tracking'];
$data_tracking = explode(',', $data_tracking);
$current_question = 1; //set by default the 1st question
$current_question = 1; // Set by default the 1st question
if (!empty($myRemindList)) {
// Checking which questions we are going to call from the remind list
@ -1221,6 +1247,24 @@ if (!empty($questionList)) {
}
}
if ($allowBlockCategory &&
ONE_PER_PAGE == $objExercise->type &&
EX_Q_SELECTION_CATEGORIES_ORDERED_QUESTIONS_RANDOM == $selectionType
) {
if (0 === $isLastQuestionInCategory && 2 === $reminder) {
$endReminderValue = false;
if (!empty($myRemindList)) {
$endValue = end($myRemindList);
if ($endValue == $questionId) {
$endReminderValue = true;
}
}
if ($endReminderValue) {
$isLastQuestionInCategory = $categoryId;
}
}
}
$saveIcon = Display::return_icon(
'save.png',
get_lang('Saved'),
@ -1229,6 +1273,7 @@ $saveIcon = Display::return_icon(
false,
true
);
$loading = Display::returnFontAwesomeIcon('spinner', null, true, 'fa-spin');
echo '<script>
function addExerciseEvent(elm, evType, fn, useCapture) {
@ -1280,25 +1325,11 @@ echo '<script>
}
});
$(".main_question").mouseover(function() {
//$(this).find(".exercise_save_now_button").show();
//$(this).addClass("question_highlight");
});
$(".main_question").mouseout(function() {
//$(this).find(".exercise_save_now_button").hide();
$(this).removeClass("question_highlight");
});
$(".no_remind_highlight").hide();
// if the users validates the form using return key,
// prevent form action and simulates click on validation button
/*$("#exercise_form").submit(function(){
$(".question-validate-btn").first().trigger("click");
return false;
});*/
$("form#exercise_form").prepend($("#exercise-description"));
$(\'button[name="previous_question_and_save"]\').on("touchstart click", function (e) {
@ -1321,10 +1352,52 @@ echo '<script>
save_question_list(questionList);
});
$(\'button[name="save_now"]\').on(\'touchstart click\', function (e) {
$(\'button[name="check_answers"]\').on(\'touchstart click\', function (e) {
e.preventDefault();
e.stopPropagation();
var $this = $(this);
var urlExtra = $this.data(\'url\') || null;
var questionId = parseInt($this.data(\'question\')) || 0;
save_now(questionId, "check_answers");
var checkUrl = "'.$checkAnswersUrl.'";
$("#global-modal").attr("data-keyboard", "false");
$("#global-modal").attr("data-backdrop", "static");
$("#global-modal").find(".close").hide();
$("#global-modal .modal-body").load(checkUrl, function() {
$("#global-modal .modal-body").append("<div class=\"btn-group\"></div>");
var continueTest = $("<a>",{
text: "'.addslashes(get_lang('ContinueTest')).'",
title: "'.addslashes(get_lang('ContinueTest')).'",
href: "javascript:void(0);",
click: function(){
$(this).attr("disabled", "disabled");
$("#global-modal").modal("hide");
$("#global-modal .modal-body").html("");
}
}).addClass("btn btn-default").appendTo("#global-modal .modal-body .btn-group");
$("<a>",{
text: "'.addslashes(get_lang('EndTest')).'",
title: "'.addslashes(get_lang('EndTest')).'",
href: "javascript:void(0);",
click: function() {
$(this).attr("disabled", "disabled");
continueTest.attr("disabled", "disabled");
save_now(questionId, urlExtra);
$("#global-modal .modal-body").html("<span style=\"text-align:center\">'.addslashes($loading).addslashes(get_lang('Loading')).'</span>");
}
}).addClass("btn btn-primary").appendTo("#global-modal .modal-body .btn-group");
});
$("#global-modal").modal("show");
});
$(\'button[name="save_now"]\').on(\'touchstart click\', function (e) {
e.preventDefault();
e.stopPropagation();
var
$this = $(this),
questionId = parseInt($this.data(\'question\')) || 0,
@ -1413,8 +1486,7 @@ echo '<script>
dataparam += remind_list ? ("&" + remind_list) : "";
dataparam += my_choiceDc ? ("&" + my_choiceDc) : "";
$("#save_for_now_"+question_id).html(\''.
Display::returnFontAwesomeIcon('spinner', null, true, 'fa-spin').'\');
$("#save_for_now_"+question_id).html(\''.$loading.'\');
$.ajax({
type:"post",
url: "'.api_get_path(WEB_AJAX_PATH).'exercise.ajax.php?'.api_get_cidreq().'&a=save_exercise_by_now",
@ -1440,8 +1512,7 @@ echo '<script>
// If last question in category send to exercise_question_reminder.php
if ('.$isLastQuestionInCategory.' > 0 ) {
url = "exercise_question_reminder.php?'.$params.'&num='.$current_question.
'&category_id='.$isLastQuestionInCategory.'";
url = "exercise_question_reminder.php?'.$params.'&num='.($current_question - 1).'&category_id='.$isLastQuestionInCategory.'";
}
if (url_extra) {
@ -1450,6 +1521,10 @@ echo '<script>
$("#save_for_now_"+question_id).html(\''.
Display::return_icon('save.png', get_lang('Saved'), [], ICON_SIZE_SMALL).'\');
if ("check_answers" === url_extra) {
return true;
}
// window.quizTimeEnding will be reset in exercise.class.php
if (window.quizTimeEnding) {
redirectExerciseToResult();
@ -1489,7 +1564,7 @@ echo '<script>
});
free_answers = $.param(free_answers);
$("#save_all_response").html(\''.Display::returnFontAwesomeIcon('spinner', null, true, 'fa-spin').'\');
$("#save_all_response").html(\''.$loading.'\');
var requestData = "'.$params.'&type=all";
requestData += "&" + my_choice;

@ -338,6 +338,10 @@ function aiken_parse_file(&$exercise_info, $exercisePath, $file, $questionFile)
continue;
}
if (false !== strpos($data[$next], 'DESCRIPTION:')) {
continue;
}
// Check if next has score, otherwise loop too next question.
if (false === strpos($data[$next], 'SCORE:')) {
$answers_array = [];
@ -351,11 +355,21 @@ function aiken_parse_file(&$exercise_info, $exercisePath, $file, $questionFile)
continue;
} elseif (preg_match('/^DESCRIPTION:\s?(.*)/', $info, $matches)) {
$exercise_info['question'][$question_index]['description'] = $matches[1];
$next = $line + 1;
if (false !== strpos($data[$next], 'ANSWER_EXPLANATION:')) {
continue;
}
// Check if next has score, otherwise loop too next question.
if (false === strpos($data[$next], 'SCORE:')) {
$answers_array = [];
$question_index++;
continue;
}
} elseif (preg_match('/^ANSWER_EXPLANATION:\s?(.*)/', $info, $matches)) {
// Comment of correct answer
$correct_answer_index = array_search($matches[1], $answers_array);
$exercise_info['question'][$question_index]['feedback'] = $matches[1];
$next = $line + 1;
// Check if next has score, otherwise loop too next question.
if (false === strpos($data[$next], 'SCORE:')) {

@ -27,7 +27,7 @@ if (empty($id)) {
api_not_allowed($show_headers);
}
$is_allowedToEdit = api_is_allowed_to_edit(null, true) || $is_courseTutor;
$is_allowedToEdit = api_is_allowed_to_edit(null, true) || api_is_course_tutor();
// Getting results from the exe_id. This variable also contain all the information about the exercise
$track_exercise_info = ExerciseLib::get_exercise_track_exercise_info($id);

@ -30,23 +30,15 @@ if (!$result) {
$sessionId = api_get_session_id();
$courseCode = api_get_course_id();
$courseId = api_get_course_int_id();
if (empty($sessionId)) {
$students = CourseManager:: get_student_list_from_course_code(
$courseCode,
false
);
$students = CourseManager::get_student_list_from_course_code($courseCode, false);
} else {
$students = CourseManager:: get_student_list_from_course_code(
$courseCode,
true,
$sessionId
);
$students = CourseManager::get_student_list_from_course_code($courseCode, true, $sessionId);
}
$count_students = count($students);
//$question_list = $objExercise->get_validated_question_list();
$totalQuestions = $objExercise->getQuestionCount(); //Get total of questions
$question_list = $objExercise->getQuestionForTeacher(0, $totalQuestions); // get questions from 0 to total
$questionList = $objExercise->getQuestionForTeacher(0, $objExercise->getQuestionCount());
$data = [];
// Question title # of students who tool it Lowest score Average Highest score Maximum score
@ -60,14 +52,13 @@ $headers = [
get_lang('Weighting'),
];
if (!empty($question_list)) {
foreach ($question_list as $question_id) {
if (!empty($questionList)) {
foreach ($questionList as $question_id) {
$questionObj = Question::read($question_id);
$exercise_stats = ExerciseLib::get_student_stats_by_question(
$exerciseStats = ExerciseLib::get_student_stats_by_question(
$question_id,
$exerciseId,
$courseCode,
$courseId,
$sessionId,
true
);
@ -92,14 +83,13 @@ if (!empty($question_list)) {
false,
$count_users.' / '.$count_students
);
$data[$question_id]['lowest_score'] = round($exercise_stats['min'], 2);
$data[$question_id]['average_score'] = round($exercise_stats['average'], 2);
$data[$question_id]['highest_score'] = round($exercise_stats['max'], 2);
$data[$question_id]['lowest_score'] = round($exerciseStats['min'], 2);
$data[$question_id]['average_score'] = round($exerciseStats['average'], 2);
$data[$question_id]['highest_score'] = round($exerciseStats['max'], 2);
$data[$question_id]['max_score'] = round($questionObj->weighting, 2);
}
}
// Format A table
$table = new HTML_Table(['class' => 'table table-hover table-striped data_table']);
$row = 0;
$column = 0;
@ -130,14 +120,14 @@ $headers = [
$data = [];
if (!empty($question_list)) {
if (!empty($questionList)) {
$id = 0;
foreach ($question_list as $question_id) {
foreach ($questionList as $question_id) {
$questionObj = Question::read($question_id);
$exercise_stats = ExerciseLib::get_student_stats_by_question(
$exerciseStats = ExerciseLib::get_student_stats_by_question(
$question_id,
$exerciseId,
$courseCode,
$courseId,
$sessionId,
true
);
@ -212,7 +202,7 @@ if (!empty($question_list)) {
$answer_id,
$question_id,
$exerciseId,
$courseCode,
$courseId,
$sessionId,
MATCHING
);
@ -266,7 +256,7 @@ if (!empty($question_list)) {
$real_answer_id,
$question_id,
$exerciseId,
$courseCode,
$courseId,
$sessionId
);
$percentage = 0;

@ -129,14 +129,11 @@ if ($searchSessionAndCourse || $searchCourseOnly) {
}
if (!is_null($gradebook)) {
$exportAllLink = api_get_path(WEB_CODE_PATH)."gradebook/gradebook_display_certificate.php?";
$exportAllLink .= http_build_query([
"action" => "export_all_certificates",
"cidReq" => $selectedCourseInfo['code'],
"id_session" => 0,
"gidReq" => 0,
"cat_id" => $gradebook->get_id(),
]);
$exportAllLink = GradebookUtils::returnJsExportAllCertificates(
'#btn-export-all',
$gradebook->get_id(),
$selectedCourseInfo['code']
);
$sessionName = api_get_session_name($selectedSession);
$courseName = api_get_course_info($selectedCourseInfo['code'])['title'];

@ -0,0 +1,31 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Command to export certificates for a gradebook categori in course (or course session).
*
* <code>php main/gradebook/cli/export_all_certificated.php COURSE_CODE SESSION_ID CATEGORY_ID [USER_IDS]</code>
*/
require_once __DIR__.'/../../inc/global.inc.php';
if (PHP_SAPI !== 'cli') {
exit(get_lang('NotAllowed'));
}
$courseCode = $argv[1];
$sessionId = $argv[2];
$categoryId = $argv[3];
$userList = isset($argv[4]) ? explode(',', $argv[4]) : [];
$date = api_get_utc_datetime(null, false, true);
$pdfName = 'certs_'.$courseCode.'_'.$sessionId.'_'.$categoryId.'_'.$date->format('Y-m-d');
$finalFile = api_get_path(SYS_ARCHIVE_PATH)."$pdfName.pdf";
if (file_exists($finalFile)) {
unlink(api_get_path(SYS_ARCHIVE_PATH)."$pdfName.pdf");
}
Category::exportAllCertificates($categoryId, $userList, $courseCode, true, $pdfName);

@ -125,31 +125,6 @@ switch ($action) {
);
$content = $form->returnForm();
break;
case 'export_all_certificates':
if ($allowCustomCertificate) {
$params = 'course_code='.api_get_course_id().
'&session_id='.api_get_session_id().
'&'.api_get_cidreq().
'&cat_id='.$categoryId;
$url = api_get_path(WEB_PLUGIN_PATH).
'customcertificate/src/print_certificate.php?export_all_in_one=1&'.$params;
} else {
if (api_is_student_boss()) {
$userGroup = new UserGroup();
$userList = $userGroup->getGroupUsersByUser(api_get_user_id());
} else {
$userList = [];
if (!empty($filterOfficialCodeGet)) {
$userList = UserManager::getUsersByOfficialCode($filterOfficialCodeGet);
}
}
Category::exportAllCertificates($categoryId, $userList);
}
header('Location: '.$url);
exit;
break;
case 'export_all_certificates_zip':
if ($allowCustomCertificate) {
$params = 'course_code='.api_get_course_id().
@ -280,10 +255,27 @@ $actions .= Display::url(
$hideCertificateExport = api_get_setting('hide_certificate_export_link');
if (count($certificate_list) > 0 && $hideCertificateExport !== 'true') {
$actions .= Display::url(
Display::return_icon('pdf.png', get_lang('ExportAllCertificatesToPDF'), [], ICON_SIZE_MEDIUM),
$url.'&action=export_all_certificates'
);
if ($allowCustomCertificate) {
$actions = Display::url(
Display::return_icon('pdf.png', get_lang('ExportAllCertificatesToPDF'), [], ICON_SIZE_MEDIUM),
api_get_path(WEB_PLUGIN_PATH)
.'customcertificate/src/print_certificate.php?'.api_get_cidreq().'&'
.http_build_query(
[
'export_all_in_one' => 1,
'course_code' => api_get_course_id(),
'session_id' => api_get_session_id(),
'cat_id' => $categoryId,
]
)
);
} else {
$actions .= Display::url(
Display::return_icon('pdf.png', get_lang('ExportAllCertificatesToPDF'), [], ICON_SIZE_MEDIUM),
'#',
['id' => 'btn-export-all']
);
}
if ($allowCustomCertificate) {
$actions .= Display::url(
@ -350,5 +342,13 @@ if (count($certificate_list) == 0) {
}
echo '</tbody>';
echo '</table>';
echo GradebookUtils::returnJsExportAllCertificates(
'#btn-export-all',
$categoryId,
api_get_course_id(),
api_get_session_id(),
$filterOfficialCodeGet
);
}
Display::display_footer();

@ -211,29 +211,31 @@ if (!empty($_GET['export_report']) &&
) {
if (api_is_platform_admin() || api_is_course_admin() || api_is_session_general_coach() || $isDrhOfCourse) {
$user_id = null;
if (empty($_SESSION['export_user_fields'])) {
$_SESSION['export_user_fields'] = false;
}
if (!api_is_allowed_to_edit(false, false) && !api_is_course_tutor()) {
if (!api_is_allowed_to_edit() && !api_is_course_tutor()) {
$user_id = api_get_user_id();
}
$params['show_official_code'] = true;
$printable_data = GradebookUtils::get_printable_data(
$onlyScore = isset($_GET['only_score']) && 1 === (int) $_GET['only_score'];
$printableData = GradebookUtils::get_printable_data(
$cat[0],
$users,
$alleval,
$alllinks,
$params,
$mainCourseCategory[0]
$mainCourseCategory[0],
$onlyScore
);
switch ($_GET['export_format']) {
case 'xls':
ob_start();
$export = new GradeBookResult();
$export->exportCompleteReportXLS($printable_data);
$export->exportCompleteReportXLS($printableData);
$content = ob_get_contents();
ob_end_clean();
echo $content;
@ -241,7 +243,7 @@ if (!empty($_GET['export_report']) &&
case 'doc':
ob_start();
$export = new GradeBookResult();
$export->exportCompleteReportDOC($printable_data);
$export->exportCompleteReportDOC($printableData);
$content = ob_get_contents();
ob_end_clean();
echo $content;
@ -250,7 +252,7 @@ if (!empty($_GET['export_report']) &&
default:
ob_start();
$export = new GradeBookResult();
$export->exportCompleteReportCSV($printable_data);
$export->exportCompleteReportCSV($printableData);
$content = ob_get_contents();
ob_end_clean();
echo $content;
@ -263,6 +265,37 @@ if (!empty($_GET['export_report']) &&
}
$this_section = SECTION_COURSES;
if (isset($_GET['selectcat']) && ($_SESSION['studentview'] === 'teacherview')) {
$htmlHeadXtra[] = '<script>
$(function() {
$("#dialog:ui-dialog").dialog("destroy");
$("#dialog-confirm").dialog({
autoOpen: false,
show: "blind",
resizable: false,
height:300,
modal: true
});
$(".export_opener").click(function() {
var targetUrl = $(this).attr("href");
$("#dialog-confirm").dialog({
width:400,
height:300,
buttons: {
"'.addslashes(get_lang('Download')).'": function() {
let onlyScore = $("input[name=only_score]").prop("checked") ? 1 : 0;
location.href = targetUrl+"&only_score="+onlyScore;
$(this).dialog("close");
}
}
});
$("#dialog-confirm").dialog("open");
return false;
});
});
</script>';
}
if (isset($_GET['exportpdf'])) {
$export_pdf_form->display();

@ -906,7 +906,6 @@ if (isset($first_time) && $first_time == 1 && api_is_allowed_to_edit(null, true)
foreach ($components as $component) {
$gradebook = new Gradebook();
$params = [];
$params['name'] = $component['acronym'];
$params['description'] = $component['title'];
$params['user_id'] = api_get_user_id();
@ -918,8 +917,9 @@ if (isset($first_time) && $first_time == 1 && api_is_allowed_to_edit(null, true)
$gradebook->save($params);
}
// Reloading cats
$cats = Category:: load(
$cats = Category::load(
null,
null,
$course_code,
@ -1052,9 +1052,7 @@ if (isset($first_time) && $first_time == 1 && api_is_allowed_to_edit(null, true)
}
api_set_in_gradebook();
$contents = ob_get_contents();
ob_end_clean();
$view = new Template($viewTitle);

@ -604,6 +604,7 @@ class GradebookUtils
* @param $alllinks
* @param $params
* @param null $mainCourseCategory
* @param bool $onlyScore
*
* @return array
*/
@ -613,7 +614,8 @@ class GradebookUtils
$alleval,
$alllinks,
$params,
$mainCourseCategory = null
$mainCourseCategory = null,
$onlyScore = false
) {
$datagen = new FlatViewDataGenerator(
$users,
@ -624,29 +626,28 @@ class GradebookUtils
);
$offset = isset($_GET['offset']) ? (int) $_GET['offset'] : 0;
// step 2: generate rows: students
$datagen->category = $cat;
$count = (($offset + 10) > $datagen->get_total_items_count()) ? ($datagen->get_total_items_count() - $offset) : GRADEBOOK_ITEM_LIMIT;
$header_names = $datagen->get_header_names($offset, $count, true);
$data_array = $datagen->get_data(
$totalItems = $datagen->get_total_items_count();
$count = (($offset + 10) > $totalItems) ? ($totalItems - $offset) : GRADEBOOK_ITEM_LIMIT;
$headers = $datagen->get_header_names($offset, $count, true);
$list = $datagen->get_data(
FlatViewDataGenerator::FVDG_SORT_LASTNAME,
0,
null,
$offset,
$count,
$onlyScore,
true,
true
$onlyScore
);
$result = [];
foreach ($data_array as $data) {
foreach ($list as $data) {
$result[] = array_slice($data, 1);
}
$return = [$header_names, $result];
return $return;
return [$headers, $result];
}
/**
@ -1704,4 +1705,64 @@ class GradebookUtils
Database::update($table, $params, ['id = ?' => $commentInfo['id']]);
}
}
public static function returnJsExportAllCertificates(
$buttonSelector,
$categoryId,
$courseCode,
$sessionId = 0,
$filterOfficialCodeGet = null
) {
$params = [
'a' => 'export_all_certificates',
'cat_id' => $categoryId,
'cidReq' => $courseCode,
'id_session' => $sessionId,
'filter' => $filterOfficialCodeGet,
];
$urlExportAll = 'gradebook.ajax.php?'.http_build_query($params);
$params['a'] = 'verify_export_all_certificates';
$urlVerifyExportAll = 'gradebook.ajax.php?'.http_build_query($params);
$imgSrcLoading = api_get_path(WEB_LIBRARY_JS_PATH).'loading.gif';
$imgSrcPdf = Display::return_icon('pdf.png', '', [], ICON_SIZE_MEDIUM, false, true);
return "<script>
$(function () {
var \$btnExport = $('$buttonSelector'),
interval = 0;
function verifyExportSuccess (response) {
if (response.length > 0) {
\$btnExport.find('img').prop('src', '$imgSrcPdf');
window.clearInterval(interval);
window.removeEventListener('beforeunload', onbeforeunloadListener);
window.location.href = response;
}
}
function exportAllSuccess () {
interval = window.setInterval(
function () {
$.ajax(_p.web_ajax + '$urlVerifyExportAll').then(verifyExportSuccess);
},
15000
);
}
function onbeforeunloadListener (e) {
e.preventDefault();
e.returnValue = '';
}
\$btnExport.on('click', function (e) {
e.preventDefault();
\$btnExport.find('img').prop({src: '$imgSrcLoading', width: 40, height: 40});
window.addEventListener('beforeunload', onbeforeunloadListener);
$.ajax(_p.web_ajax + '$urlExportAll').then(exportAllSuccess);
});
});
</script>";
}
}

@ -2265,11 +2265,21 @@ class Category implements GradebookItem
}
/**
* @param int $catId
* @param array $userList
*/
public static function exportAllCertificates($catId, $userList = [])
{
* @param int $catId
* @param array $userList
* @param string|null $courseCode
* @param bool $generateToFile
* @param string $pdfName
*
* @throws \MpdfException
*/
public static function exportAllCertificates(
$catId,
$userList = [],
$courseCode = null,
$generateToFile = false,
$pdfName = ''
) {
$orientation = api_get_configuration_value('certificate_pdf_orientation');
$params['orientation'] = 'landscape';
@ -2281,8 +2291,8 @@ class Category implements GradebookItem
$params['right'] = 0;
$params['top'] = 0;
$params['bottom'] = 0;
$page_format = $params['orientation'] === 'landscape' ? 'A4-L' : 'A4';
$pdf = new PDF($page_format, $params['orientation'], $params);
$pageFormat = $params['orientation'] === 'landscape' ? 'A4-L' : 'A4';
$pdf = new PDF($pageFormat, $params['orientation'], $params);
if (api_get_configuration_value('add_certificate_pdf_footer')) {
$pdf->setCertificateFooter();
}
@ -2310,10 +2320,13 @@ class Category implements GradebookItem
// stuff) and return as one multiple-pages PDF
$pdf->html_to_pdf(
$certificate_path_list,
get_lang('Certificates'),
null,
empty($pdfName) ? get_lang('Certificates') : $pdfName,
$courseCode,
false,
false,
false
true,
'',
$generateToFile
);
}
}

@ -162,6 +162,12 @@ class DisplayGradebook
'selectcat' => $catobj->get_id(),
]);
$scoreRanking = ScoreDisplay::instance()->get_custom_score_display_settings();
$attributes = [];
if (!empty($scoreRanking)) {
$attributes = ['class' => 'export_opener'];
}
$header .= Display::url(
Display::return_icon(
'export_csv.png',
@ -169,7 +175,8 @@ class DisplayGradebook
'',
ICON_SIZE_MEDIUM
),
$exportCsvUrl
$exportCsvUrl,
$attributes
);
$exportXlsUrl = api_get_self().'?'.api_get_cidreq().'&'.http_build_query([
@ -185,7 +192,8 @@ class DisplayGradebook
'',
ICON_SIZE_MEDIUM
),
$exportXlsUrl
$exportXlsUrl,
$attributes
);
$exportDocUrl = api_get_self().'?'.api_get_cidreq().'&'.http_build_query([
@ -201,7 +209,8 @@ class DisplayGradebook
'',
ICON_SIZE_MEDIUM
),
$exportDocUrl
$exportDocUrl,
$attributes
);
$exportPrintUrl = api_get_self().'?'.api_get_cidreq().'&'.http_build_query([
@ -239,7 +248,27 @@ class DisplayGradebook
);
$header .= '</div>';
echo $header;
$dialog = '';
if (!empty($scoreRanking)) {
$dialog = '<div id="dialog-confirm" style="display:none" title="'.get_lang('ConfirmYourChoice').'">';
$form = new FormValidator(
'report',
'post',
null,
null,
['class' => 'form-vertical']
);
$form->addCheckBox(
'only_score',
null,
get_lang('OnlyNumbers')
);
$dialog .= $form->returnForm();
$dialog .= '</div>';
}
echo $header.$dialog;
}
/**

@ -523,7 +523,7 @@ class EvalForm extends FormValidator
private function build_basic_form($edit = 0)
{
$form_title = get_lang('NewEvaluation');
if (!empty($_GET['editeval']) && $_GET['editeval'] == 1) {
if (!empty($_GET['editeval'])) {
$form_title = get_lang('EditEvaluation');
}

@ -348,16 +348,15 @@ class FlatViewTable extends SortableTable
$header = null;
if ($this->limit_enabled && $totalitems > GRADEBOOK_ITEM_LIMIT) {
$header .= '<table style="width: 100%; text-align: right; margin-left: auto; margin-right: auto;" border="0" cellpadding="2">'
.'<tbody>'
.'<tr>';
$header .= '<table
style="width: 100%; text-align: right; margin-left: auto; margin-right: auto;"
border="0" cellpadding="2"><tbody>
<tr>';
// previous X
$header .= '<td style="width:100%;">';
if ($this->offset >= GRADEBOOK_ITEM_LIMIT) {
$header .= '<a href="'.api_get_self()
.'?selectcat='.Security::remove_XSS($_GET['selectcat'])
.'&offset='.(($this->offset) - GRADEBOOK_ITEM_LIMIT)
$header .= '<a
href="'.api_get_self().'?selectcat='.(int) $_GET['selectcat'].'&offset='.(($this->offset) - GRADEBOOK_ITEM_LIMIT)
.(isset($_GET['search']) ? '&search='.Security::remove_XSS($_GET['search']) : '').'">'
.Display::return_icon(
'action_prev.png',
@ -434,10 +433,8 @@ class FlatViewTable extends SortableTable
$firstHeader = [];
while ($column < count($header_names)) {
$headerData = $header_names[$column];
if (is_array($headerData)) {
$countItems = count($headerData['items']);
$this->set_header(
$column,
$headerData['header'],
@ -445,8 +442,12 @@ class FlatViewTable extends SortableTable
'colspan="'.$countItems.'"'
);
foreach ($headerData['items'] as $item) {
$firstHeader[] = '<span class="text-center">'.$item.'</span>';
if (count($headerData['items']) > 0) {
foreach ($headerData['items'] as $item) {
$firstHeader[] = '<span class="text-center">'.$item.'</span>';
}
} else {
$firstHeader[] = '&mdash;';
}
} else {
$this->set_header($column, $headerData, false, $thAttributes);
@ -509,6 +510,8 @@ class FlatViewTable extends SortableTable
*/
private function build_name_link($userId, $name)
{
return '<a href="user_stats.php?userid='.$userId.'&selectcat='.$this->selectcat->get_id().'&'.api_get_cidreq().'">'.$name.'</a>';
return '<a
href="user_stats.php?userid='.$userId.'&selectcat='.$this->selectcat->get_id().'&'.api_get_cidreq().'">'.
$name.'</a>';
}
}

@ -306,8 +306,9 @@ class FlatViewDataGenerator
$users_count = null,
$items_start = 0,
$items_count = null,
$ignore_score_color = false,
$show_all = false
$ignoreScoreColor = false,
$show_all = false,
$onlyScore = false
) {
// Do some checks on users/items counts, redefine if invalid values
if (!isset($users_count)) {
@ -371,7 +372,6 @@ class FlatViewDataGenerator
}
$parent_id = $this->category->get_parent_id();
if (0 == $parent_id ||
(isset($this->params['only_subcat']) && $this->params['only_subcat'] == $this->category->get_id())
) {
@ -440,12 +440,9 @@ class FlatViewDataGenerator
}
$row[] = $user[1];
$this->addExtraFieldColumnsData($row, $user[0]);
$item_value_total = 0;
$item_total = 0;
$allcat = $this->category->get_subcategories(
null,
$course_code,
@ -461,11 +458,14 @@ class FlatViewDataGenerator
$defaultStyle = (int) $style;
}
if ($onlyScore) {
$defaultStyle = SCORE_PERCENT;
}
if (0 == $parent_id && !empty($allcat)) {
/** @var Category $sub_cat */
foreach ($allcat as $sub_cat) {
$score = $sub_cat->calc_score($user_id);
if ('true' === $detailAdminView) {
$links = $sub_cat->get_links();
/** @var ExerciseLink $link */
@ -474,7 +474,9 @@ class FlatViewDataGenerator
$linkScore = $link->calc_score($user_id);
$linkScoreList[] = $scoreDisplay->display_score(
$linkScore,
SCORE_SIMPLE
$defaultStyle,
null,
$ignoreScoreColor
);
}
@ -485,7 +487,9 @@ class FlatViewDataGenerator
$evalScore = $evaluation->calc_score($user_id);
$evalScoreList[] = $scoreDisplay->display_score(
$evalScore,
SCORE_SIMPLE
$defaultStyle,
null,
$ignoreScoreColor
);
}
}
@ -505,27 +509,34 @@ class FlatViewDataGenerator
if (!empty($style)) {
$defaultShowPercentageValue = $style;
}
if ($onlyScore) {
$defaultShowPercentageValue = SCORE_PERCENT;
}
$real_score = $scoreDisplay->display_score(
$real_score,
$defaultShowPercentageValue,
true
true,
$ignoreScoreColor
);
$temp_score = $scoreDisplay->display_score(
$score,
SCORE_DIV_SIMPLE_WITH_CUSTOM,
null
null,
$ignoreScoreColor
);
$temp_score = Display::tip($real_score, $temp_score);
} else {
$real_score = $scoreDisplay->display_score(
$real_score,
SCORE_DIV_PERCENT,
SCORE_ONLY_SCORE
SCORE_ONLY_SCORE,
$ignoreScoreColor
);
$temp_score = $scoreDisplay->display_score(
$score,
$defaultStyle,
null
null,
$ignoreScoreColor
);
$temp_score = Display::tip($temp_score, $real_score);
}
@ -563,7 +574,11 @@ class FlatViewDataGenerator
$items_count,
$items_start,
$show_all,
$row
$row,
null,
[],
$ignoreScoreColor,
$onlyScore
);
$item_value_total += $result['item_value_total'];
$evaluationsAdded = $result['evaluations_added'];
@ -579,19 +594,22 @@ class FlatViewDataGenerator
$show_all,
$row,
$mainCategoryId,
$evaluationsAdded
$evaluationsAdded,
$ignoreScoreColor,
$onlyScore
);
$item_total += $result['item_total'];
$item_value_total += $result['item_value_total'];
$total_score = [$item_value_total, $item_total];
$style = api_get_configuration_value('gradebook_report_score_style');
$customDisplayIsStandalone = api_get_configuration_value('gradebook_score_display_custom_standalone')
&& $scoreDisplay->is_custom();
$customDisplayIsStandalone =
api_get_configuration_value('gradebook_score_display_custom_standalone') &&
$scoreDisplay->is_custom();
if (!$show_all) {
$defaultStyle = empty($style) ? SCORE_DIV_PERCENT : (int) $style;
$displayScore = $scoreDisplay->display_score($total_score, $defaultStyle);
//$defaultStyle = empty($style) ? SCORE_DIV_PERCENT : (int) $style;
$displayScore = $scoreDisplay->display_score($total_score, $defaultStyle, null, $ignoreScoreColor);
if (!empty($model)) {
$displayScore = ExerciseLib::show_score($total_score[0], $total_score[1]);
}
@ -601,8 +619,11 @@ class FlatViewDataGenerator
$row[] = $displayScore;
}
} else {
$defaultStyle = empty($style) ? SCORE_DIV_SIMPLE_WITH_CUSTOM_LETTERS : (int) $style;
$displayScore = $scoreDisplay->display_score($total_score, $defaultStyle);
/*$defaultStyle = empty($style) ? SCORE_DIV_SIMPLE_WITH_CUSTOM_LETTERS : (int) $style;
if ($ignoreScoreColor) {
$defaultStyle = SCORE_DIV_PERCENT;
}*/
$displayScore = $scoreDisplay->display_score($total_score, $defaultStyle, null, $ignoreScoreColor);
if (!empty($model)) {
$displayScore = ExerciseLib::show_score($total_score[0], $total_score[1]);
}
@ -648,7 +669,9 @@ class FlatViewDataGenerator
$show_all,
&$row,
$parentCategoryIdFilter = null,
$evaluationsAlreadyAdded = []
$evaluationsAlreadyAdded = [],
$ignoreScoreDecorations = false,
$onlyScore = false
) {
// Generate actual data array
$scoreDisplay = ScoreDisplay::instance();
@ -662,6 +685,10 @@ class FlatViewDataGenerator
if (!empty($style)) {
$defaultStyle = (int) $style;
}
if ($onlyScore) {
$defaultStyle = SCORE_PERCENT;
}
$showPercentage = api_get_setting('gradebook_show_percentage_in_reports');
for ($count = 0; $count < $items_count && ($items_start + $count < count($this->evals_links)); $count++) {
/** @var AbstractLink $item */
@ -681,13 +708,10 @@ class FlatViewDataGenerator
$evaluationsAdded[] = $item->get_id();
$score = $item->calc_score($user_id);
$real_score = $score;
$divide = isset($score[1]) && !empty($score[1]) && $score[1] > 0 ? $score[1] : 1;
// Sub cat weight
$item_value = isset($score[0]) ? $score[0] / $divide : null;
// Fixing total when using one or multiple gradebooks.
if (empty($parentCategoryIdFilter)) {
if (0 == $this->category->get_parent_id()) {
@ -708,11 +732,15 @@ class FlatViewDataGenerator
}
$item_total += $item->get_weight();
$totalType = SCORE_DIV_PERCENT;
if ($onlyScore) {
$totalType = SCORE_PERCENT;
}
$complete_score = $scoreDisplay->display_score(
$score,
SCORE_DIV_PERCENT,
SCORE_ONLY_SCORE
$totalType,
SCORE_ONLY_SCORE,
$ignoreScoreDecorations
);
if ('false' === $showPercentage) {
@ -720,19 +748,29 @@ class FlatViewDataGenerator
if (!empty($style)) {
$defaultShowPercentageValue = $style;
}
if ($onlyScore) {
$defaultShowPercentageValue = SCORE_PERCENT;
}
$real_score = $scoreDisplay->display_score(
$real_score,
$defaultShowPercentageValue
$defaultShowPercentageValue,
null,
$ignoreScoreDecorations
);
$temp_score = $scoreDisplay->display_score(
[$item_value, null],
SCORE_DIV_SIMPLE_WITH_CUSTOM
$defaultStyle,
null,
$ignoreScoreDecorations
);
$temp_score = Display::tip($real_score, $temp_score);
} else {
$temp_score = $scoreDisplay->display_score(
$real_score,
$defaultStyle
$defaultStyle,
null,
$ignoreScoreDecorations
);
$temp_score = Display::tip($temp_score, $complete_score);
}
@ -985,7 +1023,6 @@ class FlatViewDataGenerator
$item_total += $item->get_weight();
$score_denom = (0 == $score[1]) ? 1 : $score[1];
$score_final = ($score[0] / $score_denom) * 100;
$displayScore = trim(
$scoreDisplay->display_score(
$score,
@ -1002,7 +1039,10 @@ class FlatViewDataGenerator
];
}
$total_score = [$item_value, $item_total];
$score_final = ($item_value / $item_total) * 100;
$score_final = 0;
if (!empty($item_total)) {
$score_final = ($item_value / $item_total) * 100;
}
if ($displayWarning) {
echo Display::return_message($total_score[1], 'warning');
}

@ -684,7 +684,7 @@ class GradebookDataGenerator
$score,
SCORE_DIV,
SCORE_BOTH,
false,
true,
true,
true
);
@ -774,22 +774,21 @@ class GradebookDataGenerator
false,
true
);
$type = $item->get_item_type();
if ('L' === $type && 'ExerciseLink' === get_class($item)) {
$display = ExerciseLib::show_score(
$score[0],
$score[1],
false,
true,
false,
false,
null,
null,
false,
true
);
}
/*$type = $item->get_item_type();
if ('L' === $type && 'ExerciseLink' === get_class($item)) {
$display = ExerciseLib::show_score(
$score[0],
$score[1],
false,
true,
false,
false,
null,
null,
false,
true
);
}*/
} else {
$display = ExerciseLib::show_score(
$score[0],

@ -28,16 +28,16 @@ class GradeBookResult
public function exportCompleteReportCSV($dato)
{
$filename = 'gradebook_results_'.gmdate('YmdGis').'.csv';
$data = '';
//build the results
//titles
foreach ($dato[0] as $header_col) {
if (!empty($header_col)) {
if (is_array($header_col)) {
if (isset($header_col['header'])) {
$data .= str_replace("\r\n", ' ', api_html_entity_decode(strip_tags($header_col['header']))).';';
$data .= str_replace(
"\r\n",
' ',
api_html_entity_decode(strip_tags($header_col['header']))
).';';
}
} else {
$data .= str_replace("\r\n", ' ', api_html_entity_decode(strip_tags($header_col))).';';
@ -47,9 +47,7 @@ class GradeBookResult
$data .= "\r\n";
$cant_students = count($dato[1]);
for ($i = 0; $i < $cant_students; $i++) {
$column = 0;
foreach ($dato[1][$i] as $col_name) {
$data .= str_replace("\r\n", ' ', api_html_entity_decode(strip_tags($col_name))).';';
}
@ -93,23 +91,24 @@ class GradeBookResult
$spreadsheet = new PHPExcel();
$spreadsheet->setActiveSheetIndex(0);
$worksheet = $spreadsheet->getActiveSheet();
$line = 1;
$column = 0;
//headers
foreach ($data[0] as $header_col) {
// headers.
foreach ($data[0] as $headerData) {
$title = $headerData;
if (isset($headerData['header'])) {
$title = $headerData['header'];
}
$title = html_entity_decode(strip_tags($title));
$worksheet->SetCellValueByColumnAndRow(
$column,
$line,
html_entity_decode(strip_tags($header_col))
$title
);
$column++;
}
$line++;
$cant_students = count($data[1]);
for ($i = 0; $i < $cant_students; $i++) {
$column = 0;
foreach ($data[1][$i] as $col_name) {
@ -147,12 +146,16 @@ class GradeBookResult
$table->addRow();
for ($i = 0; $i < count($data[0]); $i++) {
$table->addCell(1750)->addText(strip_tags($data[0][$i]));
$title = $data[0][$i];
if (isset($data[0][$i]['header'])) {
$title = $data[0][$i]['header'];
}
$title = strip_tags($title);
$table->addCell(1750)->addText($title);
}
foreach ($data[1] as $dataLine) {
$table->addRow();
for ($i = 0; $i < count($dataLine); $i++) {
$table->addCell(1750)->addText(strip_tags($dataLine[$i]));
}

@ -336,6 +336,11 @@ class ScoreDisplay
$ignoreDecimals = false,
$removeEmptyDecimals = false
) {
// No score available.
if (!is_array($score)) {
return '-';
}
$my_score = $score == 0 ? [] : $score;
switch ($type) {
case SCORE_BAR:
@ -348,22 +353,16 @@ class ScoreDisplay
return round($percentage);
break;
case SCORE_SIMPLE:
if (!isset($my_score[0])) {
$my_score[0] = 0;
}
return $this->format_score($my_score[0], $ignoreDecimals);
break;
}
if ($this->custom_enabled && isset($this->custom_display_conv)) {
$display = $this->displayDefault($my_score, $type, $ignoreDecimals, $removeEmptyDecimals);
if (false === $disableColor && $this->custom_enabled && isset($this->custom_display_conv)) {
$display = $this->displayDefault($my_score, $type, $ignoreDecimals, $removeEmptyDecimals, true);
} else {
// if no custom display set, use default display
$display = $this->displayDefault($my_score, $type, $ignoreDecimals, $removeEmptyDecimals);
}
if ($this->coloring_enabled && $disableColor == false) {
if ($this->coloring_enabled && false === $disableColor) {
$denom = isset($score[1]) && !empty($score[1]) && $score[1] > 0 ? $score[1] : 1;
$scoreCleaned = isset($score[0]) ? $score[0] : 0;
if (($scoreCleaned / $denom) < ($this->color_split_value / 100)) {
@ -440,53 +439,45 @@ class ScoreDisplay
* @param int $type
* @param bool $ignoreDecimals
* @param bool $removeEmptyDecimals
* @param bool $addScoreLabel
*
* @return string
*/
private function displayDefault($score, $type, $ignoreDecimals = false, $removeEmptyDecimals = false)
private function displayDefault($score, $type, $ignoreDecimals = false, $removeEmptyDecimals = false, $addScoreLabel = false)
{
$scoreLabel = '';
if ($addScoreLabel) {
$scoreLabel = $this->display_custom($score);
if (!empty($scoreLabel)) {
$scoreLabel = ' - '.$scoreLabel;
}
}
switch ($type) {
case SCORE_DIV: // X / Y
return $this->display_as_div($score, $ignoreDecimals, $removeEmptyDecimals);
return $this->display_as_div($score, $ignoreDecimals, $removeEmptyDecimals).$scoreLabel;
case SCORE_PERCENT: // XX %
return $this->display_as_percent($score);
return $this->display_as_percent($score).$scoreLabel;
case SCORE_DIV_PERCENT: // X / Y (XX %)
//return $this->display_as_div($score).' ('.$this->display_as_percent($score).')';
// 2020-10 Changed to XX % (X / Y)
return $this->display_as_percent($score).' ('.$this->display_as_div($score).')';
return $this->display_as_percent($score).' ('.$this->display_as_div($score).')'.$scoreLabel;
case SCORE_AVERAGE: // XX %
return $this->display_as_percent($score);
return $this->display_as_percent($score).$scoreLabel;
case SCORE_DECIMAL: // 0.50 (X/Y)
return $this->display_as_decimal($score);
return $this->display_as_decimal($score).$scoreLabel;
case SCORE_DIV_PERCENT_WITH_CUSTOM: // X / Y (XX %) - Good!
$custom = $this->display_custom($score);
if (!empty($custom)) {
$custom = ' - '.$custom;
}
$div = $this->display_as_div($score, false, $removeEmptyDecimals);
/*return
$div.
' ('.$this->display_as_percent($score).')'.$custom;*/
return
$this->display_as_percent($score).
' ('.$div.')'.$custom;
' ('.$div.')'.$scoreLabel;
case SCORE_DIV_SIMPLE_WITH_CUSTOM: // X - Good!
$custom = $this->display_custom($score);
if (!empty($custom)) {
$custom = ' - '.$custom;
}
return $this->display_simple_score($score).$custom;
return $this->display_simple_score($score).$scoreLabel;
break;
case SCORE_DIV_SIMPLE_WITH_CUSTOM_LETTERS:
$custom = $this->display_custom($score);
if (!empty($custom)) {
$custom = ' - '.$custom;
}
$score = $this->display_simple_score($score);
//needs sudo apt-get install php5-intl
// Needs sudo apt-get install php5-intl
if (class_exists('NumberFormatter')) {
$iso = api_get_language_isocode();
$f = new NumberFormatter($iso, NumberFormatter::SPELLOUT);
@ -495,10 +486,15 @@ class ScoreDisplay
$letters = " ($letters) ";
}
return $score.$letters.$custom;
break;
case SCORE_CUSTOM: // Good!
return $score.$letters.$scoreLabel;
case SCORE_CUSTOM: // Good!
return $this->display_custom($score);
case SCORE_SIMPLE:
if (!isset($score[0])) {
$score[0] = 0;
}
return $this->format_score($score[0], $ignoreDecimals).$scoreLabel;
}
}

@ -219,16 +219,11 @@ if (api_get_setting('allow_group_categories') === 'true') {
'title' => get_lang('DefaultGroupCategory'),
];
$group_cats = array_merge([$defaultCategory], $group_cats);
foreach ($group_cats as $index => $category) {
$categoryId = $category['id'];
$group_list = GroupManager::get_group_list($categoryId);
$groupToShow = GroupManager::process_groups($group_list, $categoryId);
if (empty($groupToShow)) {
continue;
}
if (empty($categoryId) && empty($group_list)) {
continue;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

@ -27,7 +27,8 @@ switch ($action) {
case 'preview':
$allowToEdit = (
api_is_allowed_to_edit(false, true) ||
(api_get_course_setting('allow_user_edit_announcement') && !api_is_anonymous())
(api_get_course_setting('allow_user_edit_announcement') && !api_is_anonymous()) ||
($sessionId && api_is_coach() && api_get_configuration_value('allow_coach_to_edit_announcements'))
);
$drhHasAccessToSessionContent = api_drh_can_access_all_session_content();

@ -258,12 +258,18 @@ switch ($action) {
}
break;
case 'search_user_by_course':
if (api_is_platform_admin()) {
$user = Database::get_main_table(TABLE_MAIN_USER);
$session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
$sessionId = $_GET['session_id'];
$course = api_get_course_info_by_id($_GET['course_id']);
$sessionId = $_GET['session_id'];
$course = api_get_course_info_by_id($_GET['course_id']);
$isPlatformAdmin = api_is_platform_admin();
$userIsSubscribedInCourse = CourseManager::is_user_subscribed_in_course(
api_get_user_id(),
$course['code'],
!empty($sessionId),
$sessionId
);
if ($isPlatformAdmin || $userIsSubscribedInCourse) {
$json = [
'items' => [],
];

@ -22,18 +22,20 @@ switch ($action) {
if (api_is_allowed_to_edit(null, true)) {
$criteria = [
'cId' => $course_id,
'sessionId' => 0,
//'sessionId' => 0,
'iid' => (int) $_GET['id'],
];
/** @var CTool $tool */
$tool = $repository->findOneBy($criteria);
$visibility = $tool->getVisibility();
$visibility = 0;
if ($allowEditionInSession && !empty($sessionId)) {
$newLink = str_replace('id_session=0', 'id_session='.$sessionId, $tool->getLink());
$criteria = [
'cId' => $course_id,
'sessionId' => $sessionId,
'name' => $tool->getName(),
//'iid' => (int) $_GET['id'],
'link' => $newLink,
];
/** @var CTool $tool */
@ -45,10 +47,11 @@ switch ($action) {
} else {
// Creates new row in c_tool
$toolInSession = clone $tool;
$toolInSession->setLink($newLink);
$toolInSession->setIid(0);
$toolInSession->setId(0);
$toolInSession->setVisibility(0);
$toolInSession->setSessionId($session_id);
$toolInSession->setSessionId($sessionId);
$em->persist($toolInSession);
$em->flush();
// Update id with iid
@ -58,12 +61,14 @@ switch ($action) {
// $tool will be updated later
$tool = $toolInSession;
}
} else {
$visibility = $tool->getVisibility();
}
$toolImage = $tool->getImage();
$customIcon = $tool->getCustomIcon();
if (api_get_setting('homepage_view') != 'activity_big') {
if (api_get_setting('homepage_view') !== 'activity_big') {
$toolImage = Display::return_icon(
$toolImage,
null,

@ -160,7 +160,6 @@ switch ($action) {
}
// 1. Setting variables needed by jqgrid
$action = $_GET['a'];
$exercise_id = (int) $_GET['exercise_id'];
$page = (int) $_REQUEST['page']; //page
$limit = (int) $_REQUEST['rows']; //quantity of rows
@ -395,399 +394,419 @@ switch ($action) {
echo 1;
exit;
break;
case 'check_answers':
if (false === api_is_allowed_to_session_edit()) {
echo 'error';
exit;
}
/** @var Exercise $objExercise */
$objExercise = Session::read('objExercise');
$questionList = Session::read('questionList');
$exeId = Session::read('exe_id');
// If exercise or question is not set then exit.
if (empty($questionList) || empty($objExercise)) {
echo 'error';
exit;
}
$statInfo = $objExercise->get_stat_track_exercise_info_by_exe_id($exeId);
echo Display::page_subheader(get_lang('VerificationOfAnsweredQuestions'));
echo $objExercise->getReminderTable($questionList, $statInfo, true);
break;
case 'save_exercise_by_now':
$course_info = api_get_course_info_by_id($course_id);
$course_id = $course_info['real_id'];
// Use have permissions to edit exercises results now?
if (api_is_allowed_to_session_edit()) {
// "all" or "simple" strings means that there's one or all questions exercise type
$type = isset($_REQUEST['type']) ? $_REQUEST['type'] : null;
if (false === api_is_allowed_to_session_edit()) {
echo 'error';
if ($debug) {
error_log(
'Exercises attempt '.$exeId.': Failed saving question(s) in course/session '.
$course_id.'/'.$session_id.
': The user ('.api_get_user_id().') does not have the permission to access this session now'
);
}
exit;
}
// Questions choices.
$choice = isset($_REQUEST['choice']) ? $_REQUEST['choice'] : [];
// "all" or "simple" strings means that there's one or all questions exercise type
$type = isset($_REQUEST['type']) ? $_REQUEST['type'] : null;
// certainty degree choice
$choiceDegreeCertainty = isset($_REQUEST['choiceDegreeCertainty']) ? $_REQUEST['choiceDegreeCertainty'] : [];
// Questions choices.
$choice = isset($_REQUEST['choice']) ? $_REQUEST['choice'] : [];
// Hot spot coordinates from all questions.
$hot_spot_coordinates = isset($_REQUEST['hotspot']) ? $_REQUEST['hotspot'] : [];
// certainty degree choice
$choiceDegreeCertainty = isset($_REQUEST['choiceDegreeCertainty']) ? $_REQUEST['choiceDegreeCertainty'] : [];
// There is a reminder?
$remind_list = isset($_REQUEST['remind_list']) && !empty($_REQUEST['remind_list'])
? array_keys($_REQUEST['remind_list']) : [];
// Hot spot coordinates from all questions.
$hot_spot_coordinates = isset($_REQUEST['hotspot']) ? $_REQUEST['hotspot'] : [];
// Needed in manage_answer.
$learnpath_id = isset($_REQUEST['learnpath_id']) ? (int) $_REQUEST['learnpath_id'] : 0;
$learnpath_item_id = isset($_REQUEST['learnpath_item_id']) ? (int) $_REQUEST['learnpath_item_id'] : 0;
// There is a reminder?
$remind_list = isset($_REQUEST['remind_list']) && !empty($_REQUEST['remind_list'])
? array_keys($_REQUEST['remind_list']) : [];
if ($debug) {
error_log("exe_id = $exeId");
error_log("type = $type");
error_log("choice = ".print_r($choice, 1)." ");
error_log("hot_spot_coordinates = ".print_r($hot_spot_coordinates, 1));
error_log("remind_list = ".print_r($remind_list, 1));
error_log("--------------------------------");
}
// Needed in manage_answer.
$learnpath_id = isset($_REQUEST['learnpath_id']) ? (int) $_REQUEST['learnpath_id'] : 0;
$learnpath_item_id = isset($_REQUEST['learnpath_item_id']) ? (int) $_REQUEST['learnpath_item_id'] : 0;
// Exercise information.
/** @var Exercise $objExercise */
$objExercise = Session::read('objExercise');
if ($debug) {
error_log("exe_id = $exeId");
error_log("type = $type");
error_log("choice = ".print_r($choice, 1)." ");
error_log("hot_spot_coordinates = ".print_r($hot_spot_coordinates, 1));
error_log("remind_list = ".print_r($remind_list, 1));
error_log("--------------------------------");
}
// Question info.
$question_id = isset($_REQUEST['question_id']) ? (int) $_REQUEST['question_id'] : null;
$question_list = Session::read('questionList');
/** @var Exercise $objExercise */
$objExercise = Session::read('objExercise');
// If exercise or question is not set then exit.
if (empty($question_list) || empty($objExercise)) {
echo 'error';
if ($debug) {
if (empty($question_list)) {
error_log("question_list is empty");
}
if (empty($objExercise)) {
error_log("objExercise is empty");
}
}
exit;
}
// Question info.
$question_id = isset($_REQUEST['question_id']) ? (int) $_REQUEST['question_id'] : null;
$question_list = Session::read('questionList');
if (WhispeakAuthPlugin::questionRequireAuthentify($question_id)) {
if ($objExercise->type == ONE_PER_PAGE) {
echo 'one_per_page';
break;
// If exercise or question is not set then exit.
if (empty($question_list) || empty($objExercise)) {
echo 'error';
if ($debug) {
if (empty($question_list)) {
error_log("question_list is empty");
}
echo 'ok';
break;
} else {
ChamiloSession::erase(WhispeakAuthPlugin::SESSION_QUIZ_QUESTION);
}
// Getting information of the current exercise.
$exercise_stat_info = $objExercise->get_stat_track_exercise_info_by_exe_id($exeId);
$exercise_id = $exercise_stat_info['exe_exo_id'];
$attemptList = [];
// First time here we create an attempt (getting the exe_id).
if (!empty($exercise_stat_info)) {
// We know the user we get the exe_id.
$exeId = $exercise_stat_info['exe_id'];
$total_score = $exercise_stat_info['exe_result'];
// Getting the list of attempts
$attemptList = Event::getAllExerciseEventByExeId($exeId);
}
// No exe id? Can't save answer.
if (empty($exeId)) {
// Fires an error.
echo 'error';
if ($debug) {
error_log('exe_id is empty');
if (empty($objExercise)) {
error_log("objExercise is empty");
}
exit;
}
exit;
}
Session::write('exe_id', $exeId);
// Updating Reminder algorithm.
if (WhispeakAuthPlugin::questionRequireAuthentify($question_id)) {
if ($objExercise->type == ONE_PER_PAGE) {
$bd_reminder_list = explode(',', $exercise_stat_info['questions_to_check']);
if (empty($remind_list)) {
$remind_list = $bd_reminder_list;
$new_list = [];
foreach ($bd_reminder_list as $item) {
if ($item != $question_id) {
$new_list[] = $item;
}
}
$remind_list = $new_list;
} else {
if (isset($remind_list[0])) {
if (!in_array($remind_list[0], $bd_reminder_list)) {
array_push($bd_reminder_list, $remind_list[0]);
}
$remind_list = $bd_reminder_list;
}
}
echo 'one_per_page';
break;
}
// Getting the total weight if the request is simple.
$total_weight = 0;
if ($type === 'simple') {
foreach ($question_list as $my_question_id) {
$objQuestionTmp = Question::read($my_question_id, $objExercise->course);
$total_weight += $objQuestionTmp->selectWeighting();
}
}
unset($objQuestionTmp);
echo 'ok';
break;
} else {
ChamiloSession::erase(WhispeakAuthPlugin::SESSION_QUIZ_QUESTION);
}
// Getting information of the current exercise.
$exercise_stat_info = $objExercise->get_stat_track_exercise_info_by_exe_id($exeId);
$exercise_id = $exercise_stat_info['exe_exo_id'];
$attemptList = [];
// First time here we create an attempt (getting the exe_id).
if (!empty($exercise_stat_info)) {
// We know the user we get the exe_id.
$exeId = $exercise_stat_info['exe_id'];
$total_score = $exercise_stat_info['exe_result'];
// Getting the list of attempts
$attemptList = Event::getAllExerciseEventByExeId($exeId);
}
// No exe id? Can't save answer.
if (empty($exeId)) {
// Fires an error.
echo 'error';
if ($debug) {
error_log('Starting questions loop in save_exercise_by_now');
error_log('exe_id is empty');
}
exit;
}
Session::write('exe_id', $exeId);
// Check we have at least one non-empty answer in the array
// provided by the user's click on the "Finish test" button.
if ('all' === $type) {
$atLeastOneAnswer = false;
foreach ($question_list as $my_question_id) {
if (!empty($choice[$my_question_id])) {
$atLeastOneAnswer = true;
break;
// Updating Reminder algorithm.
if ($objExercise->type == ONE_PER_PAGE) {
$bd_reminder_list = explode(',', $exercise_stat_info['questions_to_check']);
if (empty($remind_list)) {
$remind_list = $bd_reminder_list;
$new_list = [];
foreach ($bd_reminder_list as $item) {
if ($item != $question_id) {
$new_list[] = $item;
}
}
if (!$atLeastOneAnswer) {
error_log(
'In '.__FILE__.'::action save_exercise_by_now,'.
' from user '.api_get_user_id().
' for track_e_exercises.exe_id = '.$exeId.
', we received an empty set of answers.'.
'Preventing submission to avoid overwriting w/ null.');
echo 'error';
exit;
$remind_list = $new_list;
} else {
if (isset($remind_list[0])) {
if (!in_array($remind_list[0], $bd_reminder_list)) {
array_push($bd_reminder_list, $remind_list[0]);
}
$remind_list = $bd_reminder_list;
}
}
}
// Looping the question list from database (not from the user answer)
// Getting the total weight if the request is simple.
$total_weight = 0;
if ($type === 'simple') {
foreach ($question_list as $my_question_id) {
if ($type === 'simple' && $question_id != $my_question_id) {
continue;
}
$my_choice = isset($choice[$my_question_id]) ? $choice[$my_question_id] : null;
$objQuestionTmp = Question::read($my_question_id, $objExercise->course);
$myChoiceDegreeCertainty = null;
if ($objQuestionTmp->type === MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY) {
if (isset($choiceDegreeCertainty[$my_question_id])) {
$myChoiceDegreeCertainty = $choiceDegreeCertainty[$my_question_id];
}
}
$total_weight += $objQuestionTmp->selectWeighting();
}
}
unset($objQuestionTmp);
// Getting free choice data.
if (in_array($objQuestionTmp->type, [FREE_ANSWER, ORAL_EXPRESSION]) && $type === 'all') {
$my_choice = isset($_REQUEST['free_choice'][$my_question_id]) && !empty($_REQUEST['free_choice'][$my_question_id])
? $_REQUEST['free_choice'][$my_question_id]
: null;
}
if ($debug) {
error_log('Starting questions loop in save_exercise_by_now');
}
if ($type === 'all') {
// If saving the whole exercise (not only one question),
// record the sum of individual max scores (called
// "exe_weighting" in track_e_exercises)
$total_weight += $objQuestionTmp->selectWeighting();
// Check we have at least one non-empty answer in the array
// provided by the user's click on the "Finish test" button.
if ('all' === $type) {
$atLeastOneAnswer = false;
foreach ($question_list as $my_question_id) {
if (!empty($choice[$my_question_id])) {
$atLeastOneAnswer = true;
break;
}
}
if (!$atLeastOneAnswer) {
error_log(
'In '.__FILE__.'::action save_exercise_by_now,'.
' from user '.api_get_user_id().
' for track_e_exercises.exe_id = '.$exeId.
', we received an empty set of answers.'.
'Preventing submission to avoid overwriting w/ null.');
echo 'error';
exit;
}
}
// This variable came from exercise_submit_modal.php.
$hotspot_delineation_result = null;
if (isset($_SESSION['hotspot_delineation_result']) &&
isset($_SESSION['hotspot_delineation_result'][$objExercise->selectId()])
) {
$hotspot_delineation_result = $_SESSION['hotspot_delineation_result'][$objExercise->selectId()][$my_question_id];
// Looping the question list from database (not from the user answer)
foreach ($question_list as $my_question_id) {
if ($type === 'simple' && $question_id != $my_question_id) {
continue;
}
$my_choice = isset($choice[$my_question_id]) ? $choice[$my_question_id] : null;
$objQuestionTmp = Question::read($my_question_id, $objExercise->course);
$myChoiceDegreeCertainty = null;
if ($objQuestionTmp->type === MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY) {
if (isset($choiceDegreeCertainty[$my_question_id])) {
$myChoiceDegreeCertainty = $choiceDegreeCertainty[$my_question_id];
}
}
if ('simple' === $type) {
// Getting old attempt in order to decrease the total score.
$old_result = $objExercise->manage_answer(
$exeId,
$my_question_id,
null,
'exercise_show',
[],
false,
true,
false,
$objExercise->selectPropagateNeg()
);
// Removing old score.
$total_score = $total_score - $old_result['score'];
}
// Getting free choice data.
if ('all' === $type && in_array($objQuestionTmp->type, [FREE_ANSWER, ORAL_EXPRESSION])) {
$my_choice = isset($_REQUEST['free_choice'][$my_question_id]) && !empty($_REQUEST['free_choice'][$my_question_id])
? $_REQUEST['free_choice'][$my_question_id]
: null;
}
$questionDuration = 0;
if (api_get_configuration_value('allow_time_per_question')) {
$extraFieldValue = new ExtraFieldValue('question');
$value = $extraFieldValue->get_values_by_handler_and_field_variable($objQuestionTmp->iid, 'time');
if (!empty($value) && isset($value['value']) && !empty($value['value'])) {
$questionDuration = Event::getAttemptQuestionDuration($exeId, $objQuestionTmp->iid);
if (empty($questionDuration)) {
echo 'error';
if ($debug) {
error_log("Question duration = 0, in exeId: $exeId, question_id: $my_question_id");
}
exit;
if ($type === 'all') {
// If saving the whole exercise (not only one question),
// record the sum of individual max scores (called
// "exe_weighting" in track_e_exercises)
$total_weight += $objQuestionTmp->selectWeighting();
}
// This variable came from exercise_submit_modal.php.
$hotspot_delineation_result = null;
if (isset($_SESSION['hotspot_delineation_result']) &&
isset($_SESSION['hotspot_delineation_result'][$objExercise->selectId()])
) {
$hotspot_delineation_result = $_SESSION['hotspot_delineation_result'][$objExercise->selectId()][$my_question_id];
}
if ('simple' === $type) {
// Getting old attempt in order to decrease the total score.
$old_result = $objExercise->manage_answer(
$exeId,
$my_question_id,
null,
'exercise_show',
[],
false,
true,
false,
$objExercise->selectPropagateNeg()
);
// Removing old score.
$total_score = $total_score - $old_result['score'];
}
$questionDuration = 0;
if (api_get_configuration_value('allow_time_per_question')) {
$extraFieldValue = new ExtraFieldValue('question');
$value = $extraFieldValue->get_values_by_handler_and_field_variable($objQuestionTmp->iid, 'time');
if (!empty($value) && isset($value['value']) && !empty($value['value'])) {
$questionDuration = Event::getAttemptQuestionDuration($exeId, $objQuestionTmp->iid);
if (empty($questionDuration)) {
echo 'error';
if ($debug) {
error_log("Question duration = 0, in exeId: $exeId, question_id: $my_question_id");
}
exit;
}
}
}
// Deleting old attempt
if (isset($attemptList) && !empty($attemptList[$my_question_id])) {
if ($debug) {
error_log("delete_attempt exe_id : $exeId, my_question_id: $my_question_id");
}
Event::delete_attempt(
// Deleting old attempt.
if (isset($attemptList) && !empty($attemptList[$my_question_id])) {
if ($debug) {
error_log("delete_attempt exe_id : $exeId, my_question_id: $my_question_id");
}
Event::delete_attempt(
$exeId,
api_get_user_id(),
$course_id,
$session_id,
$my_question_id
);
if ($objQuestionTmp->type === HOT_SPOT) {
Event::delete_attempt_hotspot(
$exeId,
api_get_user_id(),
$course_id,
$session_id,
$my_question_id
);
if ($objQuestionTmp->type === HOT_SPOT) {
Event::delete_attempt_hotspot(
$exeId,
api_get_user_id(),
$course_id,
$session_id,
$my_question_id
);
}
if (isset($attemptList[$my_question_id]) &&
isset($attemptList[$my_question_id]['marks'])
) {
$total_score -= $attemptList[$my_question_id]['marks'];
}
}
// We're inside *one* question. Go through each possible answer for this question
if ($objQuestionTmp->type === MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY) {
$myChoiceTmp = [];
$myChoiceTmp['choice'] = $my_choice;
$myChoiceTmp['choiceDegreeCertainty'] = $myChoiceDegreeCertainty;
$result = $objExercise->manage_answer(
$exeId,
$my_question_id,
$myChoiceTmp,
'exercise_result',
$hot_spot_coordinates,
true,
false,
false,
$objExercise->selectPropagateNeg(),
$hotspot_delineation_result,
true,
false,
false,
$questionDuration
);
} else {
$result = $objExercise->manage_answer(
$exeId,
$my_question_id,
$my_choice,
'exercise_result',
$hot_spot_coordinates,
true,
false,
false,
$objExercise->selectPropagateNeg(),
$hotspot_delineation_result,
true,
false,
false,
$questionDuration
);
if (isset($attemptList[$my_question_id]) &&
isset($attemptList[$my_question_id]['marks'])
) {
$total_score -= $attemptList[$my_question_id]['marks'];
}
}
// Adding the new score.
$total_score += $result['score'];
// We're inside *one* question. Go through each possible answer for this question
if ($objQuestionTmp->type === MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY) {
$myChoiceTmp = [];
$myChoiceTmp['choice'] = $my_choice;
$myChoiceTmp['choiceDegreeCertainty'] = $myChoiceDegreeCertainty;
$result = $objExercise->manage_answer(
$exeId,
$my_question_id,
$myChoiceTmp,
'exercise_result',
$hot_spot_coordinates,
true,
false,
false,
$objExercise->selectPropagateNeg(),
$hotspot_delineation_result,
true,
false,
false,
$questionDuration
);
} else {
$result = $objExercise->manage_answer(
$exeId,
$my_question_id,
$my_choice,
'exercise_result',
$hot_spot_coordinates,
true,
false,
false,
$objExercise->selectPropagateNeg(),
$hotspot_delineation_result,
true,
false,
false,
$questionDuration
);
}
if ($debug) {
error_log("total_score: $total_score ");
error_log("total_weight: $total_weight ");
}
// Adding the new score.
$total_score += $result['score'];
$duration = 0;
$now = time();
if ($type === 'all') {
$exercise_stat_info = $objExercise->get_stat_track_exercise_info_by_exe_id($exeId);
}
if ($debug) {
error_log("total_score: $total_score ");
error_log("total_weight: $total_weight ");
}
$key = ExerciseLib::get_time_control_key(
$exercise_id,
$exercise_stat_info['orig_lp_id'],
$exercise_stat_info['orig_lp_item_id']
);
$duration = 0;
$now = time();
if ($type === 'all') {
$exercise_stat_info = $objExercise->get_stat_track_exercise_info_by_exe_id($exeId);
}
$durationTime = Session::read('duration_time');
if (isset($durationTime[$key]) && !empty($durationTime[$key])) {
if ($debug) {
error_log('Session time: '.$durationTime[$key]);
}
$duration = $now - $durationTime[$key];
if (!empty($exercise_stat_info['exe_duration'])) {
$duration += $exercise_stat_info['exe_duration'];
}
$duration = (int) $duration;
} else {
if (!empty($exercise_stat_info['exe_duration'])) {
$duration = $exercise_stat_info['exe_duration'];
}
}
$key = ExerciseLib::get_time_control_key(
$exercise_id,
$exercise_stat_info['orig_lp_id'],
$exercise_stat_info['orig_lp_item_id']
);
$durationTime = Session::read('duration_time');
if (isset($durationTime[$key]) && !empty($durationTime[$key])) {
if ($debug) {
error_log('duration to save in DB:'.$duration);
error_log('Session time: '.$durationTime[$key]);
}
Session::write('duration_time', [$key => $now]);
Event::updateEventExercise(
$exeId,
$objExercise->selectId(),
$total_score,
$total_weight,
$session_id,
$exercise_stat_info['orig_lp_id'],
$exercise_stat_info['orig_lp_item_id'],
$exercise_stat_info['orig_lp_item_view_id'],
$duration,
$question_list,
'incomplete',
$remind_list
);
if (api_get_configuration_value('allow_time_per_question')) {
$questionStart = Session::read('question_start', []);
if (!empty($questionStart)) {
if (isset($questionStart[$my_question_id])) {
unset($questionStart[$my_question_id]);
}
array_filter($questionStart);
Session::write('question_start', $questionStart);
}
$duration = $now - $durationTime[$key];
if (!empty($exercise_stat_info['exe_duration'])) {
$duration += $exercise_stat_info['exe_duration'];
}
HookQuizQuestionAnswered::create()
->setEventData(
[
'exe_id' => (int) $exeId,
'quiz' => [
'id' => (int) $objExercise->id,
'title' => $objExercise->selectTitle(true),
],
'question' => [
'id' => (int) $my_question_id,
'weight' => (float) $result['weight'],
],
]
)
->notifyQuizQuestionAnswered();
// Destruction of the Question object
unset($objQuestionTmp);
if ($debug) {
error_log("---------- end question ------------");
$duration = (int) $duration;
} else {
if (!empty($exercise_stat_info['exe_duration'])) {
$duration = $exercise_stat_info['exe_duration'];
}
}
if ($debug) {
error_log('Finished questions loop in save_exercise_by_now');
error_log('duration to save in DB:'.$duration);
}
Session::write('duration_time', [$key => $now]);
Event::updateEventExercise(
$exeId,
$objExercise->selectId(),
$total_score,
$total_weight,
$session_id,
$exercise_stat_info['orig_lp_id'],
$exercise_stat_info['orig_lp_item_id'],
$exercise_stat_info['orig_lp_item_view_id'],
$duration,
$question_list,
'incomplete',
$remind_list
);
if (api_get_configuration_value('allow_time_per_question')) {
$questionStart = Session::read('question_start', []);
if (!empty($questionStart)) {
if (isset($questionStart[$my_question_id])) {
unset($questionStart[$my_question_id]);
}
array_filter($questionStart);
Session::write('question_start', $questionStart);
}
}
} else {
HookQuizQuestionAnswered::create()
->setEventData(
[
'exe_id' => (int) $exeId,
'quiz' => [
'id' => (int) $objExercise->id,
'title' => $objExercise->selectTitle(true),
],
'question' => [
'id' => (int) $my_question_id,
'weight' => (float) $result['weight'],
],
]
)
->notifyQuizQuestionAnswered();
// Destruction of the Question object
unset($objQuestionTmp);
if ($debug) {
error_log(
'Exercises attempt '.$exeId.': Failed saving question(s) in course/session '.
$course_id.'/'.$session_id.
': The user ('.
api_get_user_id().
') does not have the permission to access this session now');
error_log("---------- end question ------------");
}
echo 'error';
exit;
}
if ($debug) {
error_log('Finished questions loop in save_exercise_by_now');
}
if ($type === 'all') {

@ -1,4 +1,5 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Entity\Tag;
@ -138,29 +139,26 @@ switch ($action) {
$(function() {
$( "#sortable" ).sortable();
$( "#sortable" ).disableSelection();
$( "#link_'.$variable.'" ).on("click", function() {
var newList = [];
$("#sortable").find("li").each(function(){
newList.push($(this).text());
});
var save = JSON.stringify(newList);
var save = JSON.stringify(newList);
$.ajax({
url: "'.$url.'",
dataType: "json",
data: "values="+save,
success: function(data) {
console.log(data);
}
});
alert("'.get_lang('Saved').'");
location.reload();
return false;
});
});
</script>';

@ -55,6 +55,44 @@ switch ($action) {
$form->display();
}
break;*/
case 'export_all_certificates':
$categoryId = (int) $_GET['cat_id'];
$filterOfficialCodeGet = isset($_GET['filter']) ? Security::remove_XSS($_GET['filter']) : null;
if (api_is_student_boss()) {
$userGroup = new UserGroup();
$userList = $userGroup->getGroupUsersByUser(api_get_user_id());
} else {
$userList = [];
if (!empty($filterOfficialCodeGet)) {
$userList = UserManager::getUsersByOfficialCode($filterOfficialCodeGet);
}
}
$courseCode = api_get_course_id();
$sessionId = api_get_session_id();
$commandScript = api_get_path(SYS_CODE_PATH).'gradebook/cli/export_all_certificates.php';
$userList = implode(',', $userList);
shell_exec("php $commandScript $courseCode $sessionId $categoryId $userList > /dev/null &");
break;
case 'verify_export_all_certificates':
$categoryId = (int) $_GET['cat_id'];
$courseCode = isset($_GET['cidReq']) ? Security::remove_XSS($_GET['cidReq']) : api_get_course_id();
$sessionId = isset($_GET['id_session']) ? (int) $_GET['id_session'] : api_get_session_id();
$date = api_get_utc_datetime(null, false, true);
$pdfName = 'certs_'.$courseCode.'_'.$sessionId.'_'.$categoryId.'_'.$date->format('Y-m-d');
$sysFinalFile = api_get_path(SYS_ARCHIVE_PATH)."$pdfName.pdf";
$webFinalFile = api_get_path(WEB_ARCHIVE_PATH)."$pdfName.pdf";
if (file_exists($sysFinalFile)) {
echo $webFinalFile;
}
break;
default:
echo '';
break;

@ -53,6 +53,7 @@ if (!in_array(
'get_work_user_list',
'get_work_user_list_others',
'get_work_user_list_all',
'get_work_pending_list',
'get_timelines',
'get_user_skill_ranking',
'get_usergroups',
@ -557,6 +558,21 @@ switch ($action) {
$work_id = $_REQUEST['work_id'];
$count = get_count_work($work_id);
break;
case 'get_work_pending_list':
require_once api_get_path(SYS_CODE_PATH).'work/work.lib.php';
$courseId = $_REQUEST['course'] ?? 0;
$status = $_REQUEST['status'] ?? 0;
$count = getAllWork(
null,
null,
null,
null,
$whereCondition,
true,
$courseId,
$status
);
break;
case 'get_work_user_list_others':
require_once api_get_path(SYS_CODE_PATH).'work/work.lib.php';
$work_id = $_REQUEST['work_id'];
@ -642,10 +658,7 @@ switch ($action) {
$whereCondition = " AND $whereCondition";
}
$count = ExerciseLib::get_count_exam_results(
$exercise_id,
$whereCondition
);
$count = ExerciseLib::get_count_exam_results($exercise_id, $whereCondition);
break;
case 'get_exercise_results_report':
api_protect_admin_script();
@ -1371,6 +1384,38 @@ switch ($action) {
$whereCondition
);
break;
case 'get_work_pending_list':
api_block_anonymous_users();
if (false === api_is_teacher()) {
exit;
}
$plagiarismColumns = [];
if (api_get_configuration_value('allow_compilatio_tool')) {
$plagiarismColumns = ['compilatio'];
}
$columns = [
'course',
'work_name',
'fullname',
'title',
'qualification',
'sent_date',
'qualificator_id',
'correction',
];
$columns = array_merge($columns, $plagiarismColumns);
$columns[] = 'actions';
$result = getAllWork(
$start,
$limit,
$sidx,
$sord,
$whereCondition,
false,
$courseId,
$status
);
break;
case 'get_work_user_list_others':
$plagiarismColumns = [];
if (api_get_configuration_value('allow_compilatio_tool')) {
@ -1539,7 +1584,7 @@ switch ($action) {
if (!empty($categoryList)) {
foreach ($categoryList as $categoryInfo) {
$label = 'category_'.$categoryInfo['id'];
if ($operation == 'excel') {
if ($operation === 'excel') {
$columns[] = $label.'_score_percentage';
$columns[] = $label.'_only_score';
$columns[] = $label.'_total';
@ -2474,6 +2519,7 @@ $allowed_actions = [
'get_work_user_list',
'get_work_user_list_others',
'get_work_user_list_all',
'get_work_pending_list',
'get_timelines',
'get_grade_models',
'get_event_email_template',

@ -151,13 +151,10 @@ switch ($action) {
api_protect_course_script(true);
// User access same as upload.php
$is_allowed_to_edit = api_is_allowed_to_edit(null, true);
$itemId = isset($_GET['item_id']) ? intval($_GET['item_id']) : '';
$itemId = isset($_GET['item_id']) ? (int) $_GET['item_id'] : '';
$result = [];
if (!empty($_FILES) && !empty($itemId)) {
$file = $_FILES['file'];
$courseInfo = api_get_course_info();
$workInfo = get_work_data_by_id($itemId);
$workInfoParent = get_work_data_by_id($workInfo['parent_id']);
@ -166,9 +163,7 @@ switch ($action) {
echo 'false';
break;
}
$work_table = Database::get_course_table(
TABLE_STUDENT_PUBLICATION
);
$work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
if (isset($resultUpload['url']) && !empty($resultUpload['url'])) {
$title = isset($resultUpload['filename']) && !empty($resultUpload['filename']) ? $resultUpload['filename'] : get_lang('Untitled');

@ -1649,7 +1649,8 @@ class AnnouncementManager
if (api_is_allowed_to_edit(false, true) ||
($allowUserEditSetting && !api_is_anonymous()) ||
($allowDrhAccess && api_is_drh())
($allowDrhAccess && api_is_drh()) ||
($session_id && api_is_coach() && api_get_configuration_value('allow_coach_to_edit_announcements'))
) {
// A.1. you are a course admin with a USER filter
// => see only the messages of this specific user + the messages of the group (s)he is member of.
@ -1867,7 +1868,6 @@ class AnnouncementManager
$results = [];
$emailIcon = '<i class="fa fa-envelope-o" title="'.get_lang('AnnounceSentByEmail').'"></i>';
$attachmentIcon = '<i class="fa fa-paperclip" title="'.get_lang('Attachment').'"></i>';
$editIcon = Display::return_icon(
'edit.png',
get_lang('Edit'),
@ -1909,7 +1909,6 @@ class AnnouncementManager
if (!in_array($row['id'], $displayed)) {
$actionUrl = api_get_path(WEB_CODE_PATH).'announcements/announcements.php?'
.api_get_cidreq_params($courseInfo['code'], $session_id, $row['to_group_id']);
$sent_to_icon = '';
// the email icon
if ($row['email_sent'] == '1') {
@ -1957,10 +1956,8 @@ class AnnouncementManager
$attachment_icon = ' '.$attachmentIcon;
}
/* TITLE */
$user_info = api_get_user_info($row['insert_user_id']);
$username = sprintf(get_lang('LoginX'), $user_info['username']);
$username_span = Display::tag(
'span',
$user_info['complete_name'],
@ -1977,7 +1974,8 @@ class AnnouncementManager
if (api_is_allowed_to_edit(false, true) ||
(api_is_session_general_coach() && api_is_element_in_the_session(TOOL_ANNOUNCEMENT, $row['id'])) ||
(api_get_course_setting('allow_user_edit_announcement') && !api_is_anonymous()) ||
($row['to_group_id'] == $group_id && $isTutor)
($row['to_group_id'] == $group_id && $isTutor) ||
($session_id && api_is_coach() && api_get_configuration_value('allow_coach_to_edit_announcements'))
) {
if ($disableEdit === true) {
$modify_icons = "<a href='#'>".$editIconDisable."</a>";
@ -1985,16 +1983,17 @@ class AnnouncementManager
$modify_icons = "<a href=\"".$actionUrl."&action=modify&id=".$row['id']."\">".$editIcon."</a>";
}
$image_visibility = 'invisible';
$alt_visibility = get_lang('Visible');
if ($row['visibility'] == 1) {
$image_visibility = "visible";
$image_visibility = 'visible';
$alt_visibility = get_lang('Hide');
} else {
$image_visibility = "invisible";
$alt_visibility = get_lang('Visible');
}
$modify_icons .= "<a href=\"".$actionUrl."&action=showhide&id=".$row['id']."&sec_token=".$stok."\">".
Display::return_icon($image_visibility.'.png', $alt_visibility, '', ICON_SIZE_SMALL)."</a>";
$modify_icons .= "<a
href=\"".$actionUrl."&action=showhide&id=".$row['id']."&sec_token=".$stok."\">".
Display::return_icon($image_visibility.'.png', $alt_visibility, '', ICON_SIZE_SMALL).
"</a>";
// DISPLAY MOVE UP COMMAND only if it is not the top announcement
if ($iterator != 1) {
@ -2003,12 +2002,14 @@ class AnnouncementManager
} else {
$modify_icons .= Display::return_icon('up_na.gif', get_lang('Up'));
}
if ($iterator < $bottomAnnouncement) {
$modify_icons .= "<a href=\"".$actionUrl."&action=move&down=".$row["id"]."&sec_token=".$stok."\">".
Display::return_icon('down.gif', get_lang('Down'))."</a>";
} else {
$modify_icons .= Display::return_icon('down_na.gif', get_lang('Down'));
}
if (api_is_allowed_to_edit(false, true)) {
if ($disableEdit === true) {
$modify_icons .= Display::url($deleteIconDisable, '#');

@ -82,6 +82,16 @@ class CoursesAndSessionsCatalog
// Check special courses
$courseListToAvoid = CourseManager::get_special_course_list();
$categoryToAvoid = api_get_configuration_value('course_category_code_to_use_as_model');
if (!empty($categoryToAvoid) && api_is_student()) {
$coursesInCategoryToAvoid = CourseCategory::getCoursesInCategory($categoryToAvoid, '', false);
if (!empty($coursesInCategoryToAvoid)) {
foreach ($coursesInCategoryToAvoid as $courseToAvoid) {
$courseListToAvoid[] = $courseToAvoid['id'];
}
}
}
// Checks "hide_from_catalog" extra field
$extraFieldType = ExtraField::COURSE_FIELD_TYPE;

@ -267,14 +267,9 @@ class MoodleImport
$questionsValues = $this->readMainQuestionsXml($questionsXml, $question['questionid']);
$moduleValues['question_instances'][$index] = $questionsValues;
// Set Question Type from Moodle XML element <qtype>
$qType = $moduleValues['question_instances'][$index]['qtype'];
// Add the matched chamilo question type to the array
$moduleValues['question_instances'][$index]['chamilo_qtype'] =
$this->matchMoodleChamiloQuestionTypes($qType);
$questionInstance = Question::getInstance(
$moduleValues['question_instances'][$index]['chamilo_qtype']
);
$qType = $questionsValues['qtype'];
$questionType = $this->matchMoodleChamiloQuestionTypes($questionsValues);
$questionInstance = Question::getInstance($questionType);
if (empty($questionInstance)) {
continue;
}
@ -282,8 +277,8 @@ class MoodleImport
error_log('question: '.$question['questionid']);
}
$questionInstance->updateTitle($moduleValues['question_instances'][$index]['name']);
$questionText = $moduleValues['question_instances'][$index]['questiontext'];
$questionInstance->updateTitle($questionsValues['name']);
$questionText = $questionsValues['questiontext'];
// Replace the path from @@PLUGINFILE@@ to a correct chamilo path
$questionText = str_replace(
@ -608,7 +603,7 @@ class MoodleImport
$questionType = '';
foreach ($question->childNodes as $item) {
$currentItem[$item->nodeName] = $item->nodeValue;
if ($item->nodeName == 'qtype') {
if ('qtype' === $item->nodeName) {
$questionType = $item->nodeValue;
}
@ -619,11 +614,10 @@ class MoodleImport
$answer = $item->getElementsByTagName($this->getQuestionTypeAnswersTag($questionType));
$currentItem['plugin_qtype_'.$questionType.'_question'] = [];
for ($i = 0; $i <= $answer->length - 1; $i++) {
$currentItem['plugin_qtype_'.$questionType.'_question'][$i]['answerid'] =
$answer->item($i)->getAttribute('id');
$label = 'plugin_qtype_'.$questionType.'_question';
$currentItem[$label][$i]['answerid'] = $answer->item($i)->getAttribute('id');
foreach ($answer->item($i)->childNodes as $properties) {
$currentItem['plugin_qtype_'.$questionType.'_question'][$i][$properties->nodeName] =
$properties->nodeValue;
$currentItem[$label][$i][$properties->nodeName] = $properties->nodeValue;
}
}
@ -631,8 +625,7 @@ class MoodleImport
for ($i = 0; $i <= $typeValues->length - 1; $i++) {
foreach ($typeValues->item($i)->childNodes as $properties) {
$currentItem[$questionType.'_values'][$properties->nodeName] = $properties->nodeValue;
if ($properties->nodeName != 'sequence') {
if ($properties->nodeName !== 'sequence') {
continue;
}
@ -689,12 +682,24 @@ class MoodleImport
}
/**
* @param string $moodleQuestionType
* @param array Result of readMainQuestionsXml
*
* @return int Chamilo question type
*/
public function matchMoodleChamiloQuestionTypes($moodleQuestionType)
public function matchMoodleChamiloQuestionTypes($questionsValues)
{
$moodleQuestionType = $questionsValues['qtype'];
$questionOptions = $moodleQuestionType.'_values';
// Check <single> located in <plugin_qtype_multichoice_question><multichoice><single><single>
if (
'multichoice' === $moodleQuestionType &&
isset($questionsValues[$questionOptions]) &&
isset($questionsValues[$questionOptions]['single']) &&
1 === (int) $questionsValues[$questionOptions]['single']
) {
return UNIQUE_ANSWER;
}
switch ($moodleQuestionType) {
case 'multichoice':
return MULTIPLE_ANSWER;
@ -705,7 +710,7 @@ class MoodleImport
case 'essay':
return FREE_ANSWER;
case 'truefalse':
return UNIQUE_ANSWER_NO_OPTION;
return UNIQUE_ANSWER;
}
}

File diff suppressed because it is too large Load Diff

@ -97,7 +97,7 @@ class SortableTableFromArrayConfig extends SortableTable
*/
public function get_total_number_of_items()
{
if (isset($this->total_number_of_items) && !empty($this->total_number_of_items)) {
if (!empty($this->total_number_of_items) && $this->total_number_of_items !== -1) {
return $this->total_number_of_items;
} else {
if (!empty($this->table_data)) {

@ -1,4 +1,5 @@
<?php
/* For licensing terms, see /license.txt */
/**
@ -154,8 +155,9 @@ class Agenda
*/
public function setType($type)
{
$type = (string) trim($type);
$typeList = $this->getTypes();
if (in_array($type, $typeList)) {
if (in_array($type, $typeList, true)) {
$this->type = $type;
}
}

@ -229,6 +229,7 @@ define('LOG_EXERCISE_RESULT_DELETE', 'exe_result_deleted');
define('LOG_EXERCISE_ATTEMPT_DELETE', 'exe_attempt_deleted');
define('LOG_LP_ATTEMPT_DELETE', 'lp_attempt_deleted');
define('LOG_QUESTION_RESULT_DELETE', 'qst_attempt_deleted');
define('LOG_QUESTION_SCORE_UPDATE', 'score_attempt_updated');
define('LOG_MY_FOLDER_CREATE', 'my_folder_created');
define('LOG_MY_FOLDER_CHANGE', 'my_folder_changed');
@ -3786,7 +3787,7 @@ function api_is_allowed($tool, $action, $task_id = 0)
// Getting the permissions of the task.
if ($task_id != 0) {
$task_permissions = get_permissions('task', $task_id);
/* !!! */$_SESSION['total_permissions'][$_course['code']] = $task_permissions;
$_SESSION['total_permissions'][$_course['code']] = $task_permissions;
}
//print_r($_SESSION['total_permissions']);

@ -309,14 +309,18 @@ class Auth
// protect variables
$current_user_id = api_get_user_id();
$course_code = Database::escape_string($course_code);
$result = true;
$courseInfo = api_get_course_info($course_code);
// Check if course can be unsubscribe
if (empty($courseInfo) || empty($current_user_id)) {
return false;
}
// Check if course can be unsubscribe.
if ('1' !== $courseInfo['unsubscribe']) {
return false;
}
$courseId = $courseInfo['real_id'];
// we check (once again) if the user is not course administrator
@ -329,6 +333,8 @@ class Auth
status='1' ";
$result_check = Database::query($sql);
$number_of_rows = Database::num_rows($result_check);
$result = true;
if ($number_of_rows > 0) {
$result = false;
}

@ -1,4 +1,5 @@
<?php
/* For licensing terms, see /license.txt */
use Fhaculty\Graph\Graph;
@ -650,6 +651,10 @@ class Career extends Model
font-size: 11px;
height: 40px;
}
.panel-body{
min-height: 55px;
}
</style>';
// Create groups
@ -919,6 +924,10 @@ class Career extends Model
$iconData['Description'] = 'Result Id = '.$resultId;
}
if ('Joe Anonymous' === $iconData['TeacherUsername']) {
$iconData['TeacherUsername'] = '';
}
if (!empty($icon)) {
$params = [
'id' => 'course_'.$id.'_'.$resultId,
@ -942,7 +951,7 @@ class Career extends Model
}
if (!empty($results)) {
$content .= '<div class="row"></div><div class="pull-right">'.$results.'</div>';
$content .= '<div class="row"></div><div class="pull-left">'.$results.'</div>';
}
}

@ -151,9 +151,11 @@ class CourseManager
* @param int $orderby The column we want to order it by. Optional, defaults to first column.
* @param string $orderdirection The direction of the order (ASC or DESC). Optional, defaults to ASC.
* @param int $visibility the visibility of the course, or all by default
* @param string $startwith If defined, only return results for which the course *title* begins with this string
* @param string $startwith If defined, only return results for which the course *title* begins with this
* string
* @param string $urlId The Access URL ID, if using multiple URLs
* @param bool $alsoSearchCode An extension option to indicate that we also want to search for course codes (not *only* titles)
* @param bool $alsoSearchCode An extension option to indicate that we also want to search for course codes
* (not *only* titles)
* @param array $conditionsLike
* @param array $onlyThisCourseList
*
@ -530,13 +532,57 @@ class CourseManager
);
}
}
$subscriptionSettings = learnpath::getSubscriptionSettings();
if ($subscriptionSettings['allow_add_users_to_lp_category']) {
$em = Database::getManager();
$repo = $em->getRepository('ChamiloCourseBundle:CLpCategory');
if (api_get_configuration_value('allow_session_lp_category')) {
//$criteria = ['cId' => $course_id, 'sessionId' => $session_id];
$table = Database::get_course_table('lp_category');
$conditionSession = api_get_session_condition($session_id, true);
$sql = "SELECT * FROM $table WHERE c_id = $course_id $conditionSession";
$result = Database::query($sql);
$categories = [];
if (Database::num_rows($result)) {
while ($row = Database::fetch_array($result)) {
$categories[] = $repo->find($row['iid']);
}
}
} else {
$criteria = ['cId' => $course_id];
$categories = $repo->findBy($criteria);
}
if (!empty($categories)) {
/** @var \Chamilo\CourseBundle\Entity\CLpCategory $category */
foreach ($categories as $category) {
if ($category->getUsers()->count() > 0) {
foreach ($userList as $uid) {
$user = api_get_user_entity($uid);
$criteria = Criteria::create()->where(
Criteria::expr()->eq('user', $user)
);
$userCategory = $category->getUsers()->matching($criteria)->first();
if ($userCategory) {
$category->removeUsers($userCategory);
}
}
$em->persist($category);
$em->flush();
}
}
}
}
if (api_get_configuration_value('catalog_course_subscription_in_user_s_session')) {
// Also unlink the course from the users' currently accessible sessions
/** @var Course $course */
$course = Database::getManager()->getRepository('ChamiloCoreBundle:Course')->findOneBy([
'code' => $course_code,
]);
if (is_null($course)) {
if (null === $course) {
return false;
}
/** @var Chamilo\UserBundle\Entity\User $user */
@ -1432,8 +1478,8 @@ class CourseManager
* @param int $sessionId
* @param string $limit
* @param string $order_by the field to order the users by.
* Valid values are 'lastname', 'firstname', 'username', 'email', 'official_code' OR a part of a SQL statement
* that starts with ORDER BY ...
* Valid values are 'lastname', 'firstname', 'username', 'email',
* 'official_code' OR a part of a SQL statement that starts with ORDER BY ...
* @param int|null $filter_by_status if using the session_id: 0 or 2 (student, coach),
* if using session_id = 0 STUDENT or COURSEMANAGER
* @param bool|null $return_count
@ -2959,7 +3005,6 @@ class CourseManager
*/
public static function get_special_course_list()
{
$courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
$tbl_course_field = Database::get_main_table(TABLE_EXTRA_FIELD);
$tbl_course_field_value = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
$tbl_url_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
@ -2970,8 +3015,7 @@ class CourseManager
// Get special course field
$sql = "SELECT id FROM $tbl_course_field
WHERE extra_field_type = $extraFieldType AND
variable = 'special_course'";
WHERE extra_field_type = $extraFieldType AND variable = 'special_course'";
$result = Database::query($sql);
if (Database::num_rows($result) > 0) {
@ -2980,28 +3024,27 @@ class CourseManager
// Note: The value is better indexed as string, so
// using '1' instead of integer is more efficient
$sql = "SELECT DISTINCT(item_id) as cid
FROM $tbl_course_field_value
WHERE field_id = ".$row['id']." AND value = '1'";
FROM $tbl_course_field_value
WHERE field_id = ".$row['id']." AND value = '1'";
$result = Database::query($sql);
while ($row = Database::fetch_assoc($result)) {
$courseList[] = $row['cid'];
}
if (count($courseList) < 1) {
return $courseList;
if (empty($courseList)) {
return [];
}
if (api_get_multiple_access_url()) {
//we filter the courses by the active URL
$coursesSelect = '';
if (count($courseList) == 1) {
if (count($courseList) === 1) {
$coursesSelect = $courseList[0];
} else {
$coursesSelect = implode(',', $courseList);
}
$access_url_id = api_get_current_access_url_id();
if ($access_url_id != -1) {
$urlId = api_get_current_access_url_id();
if ($urlId != -1) {
$courseList = [];
$sql = "SELECT c_id FROM $tbl_url_course
WHERE access_url_id = $access_url_id
AND c_id IN ($coursesSelect)";
WHERE access_url_id = $urlId AND c_id IN ($coursesSelect)";
$result = Database::query($sql);
while ($row = Database::fetch_assoc($result)) {
$courseList[] = $row['c_id'];
@ -3073,7 +3116,8 @@ class CourseManager
* @param int $user_id
* @param bool $include_sessions Whether to include courses from session or not
* @param bool $adminGetsAllCourses If the user is platform admin,
* whether he gets all the courses or just his. Note: This does *not* include all sessions
* whether he gets all the courses or just his. Note: This does
* *not* include all sessions
* @param bool $loadSpecialCourses
* @param array $skipCourseList List of course ids to skip
* @param bool $useUserLanguageFilterIfAvailable
@ -4758,8 +4802,8 @@ class CourseManager
* Creates a new course code based in a given code.
*
* @param string wanted code
* <code> $wanted_code = 'curse' if there are in the DB codes like curse1 curse2 the function will return: course3</code>
* if the course code doest not exist in the DB the same course code will be returned
* <code> $wanted_code = 'curse' if there are in the DB codes like curse1 curse2 the function will return:
* course3</code> if the course code doest not exist in the DB the same course code will be returned
*
* @return string wanted unused code
*/
@ -5854,6 +5898,12 @@ class CourseManager
$courseSettings[] = 'lp_return_link';
}
if (api_get_configuration_value('allow_portfolio_tool')) {
$courseSettings[] = 'qualify_portfolio_item';
$courseSettings[] = 'qualify_portfolio_comment';
$courseSettings[] = 'portfolio_max_score';
}
if (!empty($pluginCourseSettings)) {
$courseSettings = array_merge(
$courseSettings,

@ -503,7 +503,6 @@ class CourseCategory
$deleteUrl = $mainUrl.'&id='.$category['code'].'&action=delete';
$actions = [];
if ($urlId == $category['access_url_id']) {
$actions[] = Display::url($editIcon, $editUrl);
$actions[] = Display::url($moveIcon, $moveUrl);
@ -521,7 +520,7 @@ class CourseCategory
$url
);
$countCourses = self::countCoursesInCategory($category['code'], null, false);
$countCourses = self::countCoursesInCategory($category['code'], null, false, false);
$content = [
$title,
@ -597,8 +596,9 @@ class CourseCategory
/**
* @param string $category_code
* @param string $keyword
* @paran bool $avoidCourses
* @paran array $conditions
* @param bool $avoidCourses
* @param bool $checkHidePrivate
* @param array $conditions
*
* @return int
*/
@ -606,12 +606,20 @@ class CourseCategory
$category_code = '',
$keyword = '',
$avoidCourses = true,
$checkHidePrivate = true,
$conditions = []
) {
return self::getCoursesInCategory($category_code, $keyword, $avoidCourses, $conditions, true);
return self::getCoursesInCategory(
$category_code,
$keyword,
$avoidCourses,
$checkHidePrivate,
$conditions,
true
);
}
public static function getCoursesInCategory($category_code = '', $keyword = '', $avoidCourses = true, $conditions = [], $getCount = false)
public static function getCoursesInCategory($category_code = '', $keyword = '', $avoidCourses = true, $checkHidePrivate = true, $conditions = [], $getCount = false)
{
$tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
$categoryCode = Database::escape_string($category_code);
@ -621,8 +629,7 @@ class CourseCategory
if ($avoidCourses) {
$avoidCoursesCondition = CoursesAndSessionsCatalog::getAvoidCourseCondition();
}
$visibilityCondition = CourseManager::getCourseVisibilitySQLCondition('course', true);
$visibilityCondition = CourseManager::getCourseVisibilitySQLCondition('course', true, $checkHidePrivate);
$sqlInjectJoins = '';
$where = ' AND 1 = 1 ';

@ -1,4 +1,5 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CourseBundle\Entity\CLpCategory;
@ -529,7 +530,11 @@ class CourseHome
category = "authoring" OR
category = "interaction" OR
category = "plugin"
) OR (t.name = "'.TOOL_TRACKING.'")
) OR
(t.name = "'.TOOL_TRACKING.'")
OR (
image = "scormbuilder.gif"
)
)';
}
@ -561,7 +566,6 @@ class CourseHome
ON (t.c_id = lc.c_id AND l.category_id = lc.iid)
$conditions AND
t.c_id = $course_id $condition_session
ORDER BY
CASE WHEN l.category_id IS NULL THEN 0 ELSE 1 END,
CASE WHEN l.display_order IS NULL THEN 0 ELSE 1 END,
@ -655,6 +659,7 @@ class CourseHome
});
$isAllowToEdit = api_is_allowed_to_edit(null, true);
$showInvisibleLpsForStudents = api_get_configuration_value('show_invisible_lp_in_course_home');
foreach ($tools as $temp_row) {
$add = false;
if ($check) {
@ -665,7 +670,10 @@ class CourseHome
$add = true;
}
if ($allowEditionInSession && !empty($sessionId)) {
if (false === $showInvisibleLpsForStudents &&
false === $isAllowToEdit &&
$allowEditionInSession && !empty($sessionId)
) {
// Checking if exist row in session
$criteria = [
'cId' => $course_id,
@ -674,10 +682,8 @@ class CourseHome
];
/** @var CTool $toolObj */
$toolObj = Database::getManager()->getRepository('ChamiloCourseBundle:CTool')->findOneBy($criteria);
if ($toolObj) {
if ($isAllowToEdit == false && $toolObj->getVisibility() == false) {
continue;
}
if ($toolObj && $toolObj->getVisibility() == false) {
continue;
}
}
@ -694,25 +700,34 @@ class CourseHome
if ($isAllowToEdit) {
$add = true;
} else {
$add = learnpath::is_lp_visible_for_student(
$lpId,
$userId,
$courseInfo,
$sessionId
);
if ($showInvisibleLpsForStudents) {
$add = true;
} else {
$add = learnpath::is_lp_visible_for_student(
$lpId,
$userId,
$courseInfo,
$sessionId
);
// Check if LP is visible.
$visibility = api_get_item_visibility($courseInfo, TOOL_LEARNPATH, $lpId, $sessionId);
if (1 !== $visibility) {
$add = false;
}
}
}
if ($path) {
$temp_row['custom_image'] = $path;
}
break;
case 'lp_category.gif':
$lpCategory = self::getPublishedLpCategoryFromLink(
$temp_row['link']
);
$add = learnpath::categoryIsVisibleForStudent(
$lpCategory,
$user
);
$lpCategory = self::getPublishedLpCategoryFromLink($temp_row['link']);
if ($showInvisibleLpsForStudents) {
$add = true;
} else {
$add = learnpath::categoryIsVisibleForStudent($lpCategory, $user);
}
break;
}
@ -802,6 +817,15 @@ class CourseHome
$properties['name'] = $links_row['title'];
$properties['session_id'] = $links_row['session_id'];
$properties['link'] = $links_row['url'];
// For students, check if link is visible in the session.
if ($sessionId && !($is_platform_admin || api_is_course_admin())) {
$visibility = api_get_item_visibility($courseInfo, TOOL_LINK, $links_row['iid'], $sessionId);
if (1 !== $visibility) {
continue;
}
}
$properties['visibility'] = $links_row['visibility'];
$properties['image'] = $links_row['visibility'] == '0' ? 'file_html.png' : 'file_html.png';
$properties['adminlink'] = $linkUrl.'&id='.$links_row['id'].'&cidReq='.$courseInfo['code'];
@ -892,6 +916,7 @@ class CourseHome
$items = [];
$app_plugin = new AppPlugin();
$toolRepo = Database::getManager()->getRepository('ChamiloCourseBundle:CTool');
if (isset($all_tools_list)) {
$lnk = '';
foreach ($all_tools_list as &$tool) {
@ -905,9 +930,56 @@ class CourseHome
$item = [];
$studentview = false;
$tool['original_link'] = $tool['link'];
if ($tool['image'] === 'lp_category.gif') {
if ($session_id) {
if (api_is_coach() || api_is_allowed_to_edit()) {
$lpCategory = self::getPublishedLpCategoryFromLink($tool['link']);
$itemInfo = api_get_item_property_info(
$courseId,
TOOL_LEARNPATH_CATEGORY,
$lpCategory->getId(),
$session_id
);
if ($itemInfo && 0 === (int) $itemInfo['visibility']) {
$tool['image'] = 'lp_category_na.gif';
}
} else {
$categoryInSessionName = str_replace('id_session', $session_id, $tool['name']);
$criteria = [
'cId' => $courseId,
'name' => $categoryInSessionName,
'sessionId' => $session_id,
];
/** @var CTool $tool */
$toolObj = $toolRepo->findOneBy($criteria);
if ($toolObj) {
$visibility = (int) $toolObj->getVisibility();
if (0 === $visibility) {
continue;
}
}
}
}
}
if ($tool['image'] === 'scormbuilder.gif') {
// Check if the published learnpath is visible for student
$lpId = self::getPublishedLpIdFromLink($tool['link']);
if ($session_id && api_is_coach()) {
$itemInfo = api_get_item_property_info(
$courseId,
TOOL_LEARNPATH,
$lpId,
$session_id
);
if ($itemInfo && 0 === (int) $itemInfo['visibility']) {
$tool['image'] = 'scormbuilder_na.gif';
}
}
if (api_is_allowed_to_edit(null, true)) {
$studentview = true;
}
@ -937,18 +1009,13 @@ class CourseHome
$item['extra'] = null;
$toolAdmin = isset($tool['admin']) ? $tool['admin'] : '';
$extraClass = '';
$isSessionToolVisible = false;
if ($is_allowed_to_edit && $allowChangeVisibility) {
if (empty($session_id)) {
if (isset($tool['id'])) {
if ($tool['visibility'] == '1' && $toolAdmin != '1') {
$link['name'] = Display::return_icon(
'visible.png',
get_lang('Deactivate'),
['id' => 'linktool_'.$tool['iid']],
ICON_SIZE_SMALL,
false
);
$isSessionToolVisible = true;
$link['name'] = '<em
id="'.'linktool_'.$tool['iid'].'"
class="fa fa-eye"
@ -957,18 +1024,13 @@ class CourseHome
$lnk[] = $link;
}
if ($tool['visibility'] == '0' && $toolAdmin != '1') {
$link['name'] = Display::return_icon(
'invisible.png',
get_lang('Activate'),
['id' => 'linktool_'.$tool['iid']],
ICON_SIZE_SMALL,
false
);
$isSessionToolVisible = false;
$link['name'] = '<em
id="'.'linktool_'.$tool['iid'].'"
class="fa fa-eye-slash text-muted"
title="'.get_lang('Activate').'"></em>';
$link['cmd'] = 'restore=yes';
$extraClass = 'text-muted';
$lnk[] = $link;
}
}
@ -978,58 +1040,42 @@ class CourseHome
'name' => $tool['name'],
'sessionId' => $session_id,
];
/** @var CTool $tool */
$toolObj = Database::getManager()->getRepository('ChamiloCourseBundle:CTool')->findOneBy($criteria);
$toolObj = $toolRepo->findOneBy($criteria);
if ($toolObj) {
$visibility = (int) $toolObj->getVisibility();
switch ($visibility) {
case 0:
$info = pathinfo($tool['image']);
$basename = basename($tool['image'], '.'.$info['extension']);
$tool['image'] = $basename.'_na.'.$info['extension'];
$link['name'] = Display::return_icon(
'invisible.png',
get_lang('Activate'),
['id' => 'linktool_'.$tool['iid']],
ICON_SIZE_SMALL,
false
);
$isSessionToolVisible = false;
if (in_array($tool['image'], ['scormbuilder.png', 'scormbuilder.gif'])) {
$info = pathinfo($tool['image']);
$basename = basename($tool['image'], '.'.$info['extension']);
$tool['image'] = $basename.'_na.'.$info['extension'];
}
$link['name'] = '<em
id="'.'linktool_'.$tool['iid'].'"
class="fa fa-eye-slash text-muted"
title="'.get_lang('Deactivate').'"></em>';
title="'.get_lang('Activate').'"></em>';
$link['cmd'] = 'restore=yes';
$extraClass = 'text-muted';
$lnk[] = $link;
break;
case 1:
$link['name'] = Display::return_icon(
'visible.png',
get_lang('Deactivate'),
['id' => 'linktool_'.$tool['iid']],
ICON_SIZE_SMALL,
false
);
$isSessionToolVisible = true;
$link['name'] = '<em
id="'.'linktool_'.$tool['iid'].'"
class="fa fa-eye"
title="'.get_lang('Activate').'"></em>';
title="'.get_lang('Deactivate').'"></em>';
$link['cmd'] = 'hide=yes';
$lnk[] = $link;
break;
}
} else {
$link['name'] = Display::return_icon(
'visible.png',
get_lang('Deactivate'),
['id' => 'linktool_'.$tool['iid']],
ICON_SIZE_SMALL,
false
);
$isSessionToolVisible = true;
$link['name'] = '<em
id="'.'linktool_'.$tool['iid'].'"
class="fa fa-eye"
title="'.get_lang('Activate').'"></em>';
title="'.get_lang('Deactivate').'"></em>';
$link['cmd'] = 'hide=yes';
$lnk[] = $link;
}
@ -1069,11 +1115,34 @@ class CourseHome
}
$class = '';
$info = pathinfo($tool['image']);
$basename = basename($tool['image'], '.'.$info['extension']);
if ($tool['visibility'] == '0' && $toolAdmin != '1') {
$class = 'text-muted';
$info = pathinfo($tool['image']);
$basename = basename($tool['image'], '.'.$info['extension']);
$tool['image'] = $basename.'_na.'.$info['extension'];
if (!strpos($tool['image'], '_na')) {
$tool['image'] = $basename.'_na.'.$info['extension'];
}
}
if ($is_allowed_to_edit && $allowChangeVisibility &&
($tool['image'] === 'scormbuilder.gif' || $tool['image'] === 'scormbuilder_na.gif')
) {
if (false === $isSessionToolVisible) {
$tool['image'] = 'scormbuilder_na.gif';
} else {
$tool['image'] = 'scormbuilder.gif';
}
}
if ($is_allowed_to_edit && $allowChangeVisibility &&
($tool['image'] === 'lp_category.gif' || $tool['image'] === 'lp_category_na.gif')
) {
if (false === $isSessionToolVisible) {
$tool['image'] = 'lp_category_na.gif';
} else {
$tool['image'] = 'lp_category.gif';
}
}
$qm_or_amp = strpos($tool['link'], '?') === false ? '?' : '&';
@ -1082,7 +1151,9 @@ class CourseHome
if ($tool['image'] === 'file_html.png' || $tool['image'] === 'file_html_na.png') {
$tool['link'] = $tool['link'];
} else {
$tool['link'] = $tool['link'].$qm_or_amp.api_get_cidreq(true, false).'&gidReq=0';
if (!in_array($tool['image'], ['lp_category.gif', 'lp_category_na.gif'])) {
$tool['link'] = $tool['link'].$qm_or_amp.api_get_cidreq(true, false).'&gidReq=0';
}
}
$toolIid = isset($tool['iid']) ? $tool['iid'] : null;
@ -1110,7 +1181,7 @@ class CourseHome
$tool_link_params = [
'id' => 'tooldesc_'.$toolIid,
'href' => $tool['link'],
'class' => $class,
'class' => "$class $extraClass ",
'target' => $tool['target'],
];
}
@ -1160,18 +1231,6 @@ class CourseHome
false
);
/*if (!empty($tool['custom_icon'])) {
$image = self::getCustomWebIconPath().$tool['custom_icon'];
$icon = Display::img(
$image,
$tool['description'],
array(
'class' => 'tool-icon',
'id' => 'toolimage_'.$tool['id']
)
);
}*/
// Validation when belongs to a session
$session_img = api_get_session_image(
$tool['session_id'],
@ -1202,7 +1261,6 @@ class CourseHome
$originalImage = self::getToolIcon($item, ICON_SIZE_BIG);
$item['tool']['only_icon_medium'] = self::getToolIcon($item, ICON_SIZE_MEDIUM, false);
$item['tool']['only_icon_small'] = self::getToolIcon($item, ICON_SIZE_SMALL, false);
if ($theme === 'activity_big') {
$item['tool']['image'] = Display::url(
$originalImage,
@ -1698,11 +1756,9 @@ class CourseHome
// Adding only maintenance for coaches.
$myList = self::get_tools_category(TOOL_ADMIN_PLATFORM);
$onlyMaintenanceList = [];
foreach ($myList as $item) {
if ($item['name'] === 'course_maintenance') {
$item['link'] = 'course_info/maintenance_coach.php';
$onlyMaintenanceList[] = $item;
}
}

@ -2529,6 +2529,11 @@ class Display
}
$title = !empty($title) ? '<div class="panel-heading" '.$headerStyle.' ><h3 class="panel-title">'.$title.'</h3>'.$extra.'</div>' : '';
if (empty($title) && !empty($extra)) {
$title = '<div class="panel-heading" '.$headerStyle.' >'.$extra.'</div>';
}
$footer = !empty($footer) ? '<div class="panel-footer">'.$footer.'</div>' : '';
$typeList = ['primary', 'success', 'info', 'warning', 'danger'];
$style = !in_array($type, $typeList) ? 'default' : $type;
@ -2865,7 +2870,7 @@ HTML;
*
* @return string
*/
public static function getFrameReadyBlock($frameName)
public static function getFrameReadyBlock($frameName, $itemType = '')
{
$webPublicPath = api_get_path(WEB_PUBLIC_PATH);
$webJsPath = api_get_path(WEB_LIBRARY_JS_PATH);
@ -2932,9 +2937,24 @@ HTML;
});
},
"'.$frameName.'",
[
{type:"script", src:"'.api_get_jquery_web_path().'", deps: [
';
if ('quiz' === $itemType) {
$jquery = '
'.$fixLink.'
{type:"script", src:"'.api_get_path(WEB_LIBRARY_PATH).'javascript/jquery.highlight.js"},
{type:"script", src:"'.api_get_path(WEB_CODE_PATH).'glossary/glossary.js.php?'.api_get_cidreq().'"},
{type:"script", src: "'.$webPublicPath.'assets/mediaelement/build/mediaelement-and-player.min.js",
deps: [
{type:"script", src: "'.$webJsPath.'mediaelement/plugins/vrview/vrview.js"},
{type:"script", src: "'.$webJsPath.'mediaelement/plugins/markersrolls/markersrolls.min.js"},
'.$videoPluginFiles.'
]},
'.$translateHtml.'
';
} else {
$jquery = '
{type:"script", src:"'.api_get_jquery_web_path().'", deps: [
'.$fixLink.'
{type:"script", src:"'.api_get_path(WEB_LIBRARY_PATH).'javascript/jquery.highlight.js"},
{type:"script", src:"'.api_get_path(WEB_CODE_PATH).'glossary/glossary.js.php?'.api_get_cidreq().'"},
@ -2946,7 +2966,12 @@ HTML;
'.$videoPluginFiles.'
]},
'.$translateHtml.'
]},
]},';
}
$frameReady .= '
[
'.$jquery.'
'.$videoPluginCssFiles.'
{type:"script", src:"'.$webPublicPath.'assets/MathJax/MathJax.js?config=AM_HTMLorMML"},
{type:"stylesheet", src:"'.$webPublicPath.'assets/jquery-ui/themes/smoothness/jquery-ui.min.css"},

@ -3531,10 +3531,16 @@ class DocumentManager
// If you want to debug it, I advise you to do "echo" on the eval statements.
$newResources = [];
$added = [];
if (!empty($resources) && $user_in_course) {
foreach ($resources as $resource) {
$docId = $resource['id'];
if (in_array($docId, $added)) {
continue;
}
$is_visible = self::is_visible_by_id(
$resource['id'],
$docId,
$course_info,
$session_id,
api_get_user_id()
@ -3545,7 +3551,7 @@ class DocumentManager
continue;
}
}
$added[] = $docId;
$newResources[] = $resource;
}
}
@ -5158,7 +5164,6 @@ class DocumentManager
$filetype = $document_data['filetype'];
$path = $document_data['path'];
$url_path = urlencode($document_data['path']);
$basePageUrl = api_get_path(WEB_CODE_PATH).'document/';
$pageUrl = $basePageUrl.'document.php';
@ -5171,19 +5176,19 @@ class DocumentManager
if (!$show_as_icon) {
// Build download link (icon)
$forcedownload_link = $filetype == 'folder'
$forcedownload_link = $filetype === 'folder'
? $pageUrl.'?'.$courseParams.'&action=downloadfolder&id='.$document_data['id']
: $pageUrl.'?'.$courseParams.'&amp;action=download&amp;id='.$document_data['id'];
// Folder download or file download?
$forcedownload_icon = $filetype == 'folder' ? 'save_pack.png' : 'save.png';
$forcedownload_icon = $filetype === 'folder' ? 'save_pack.png' : 'save.png';
// Prevent multiple clicks on zipped folder download
$prevent_multiple_click = $filetype == 'folder' ? " onclick=\"javascript: if(typeof clic_$dbl_click_id == 'undefined' || !clic_$dbl_click_id) { clic_$dbl_click_id=true; window.setTimeout('clic_".($dbl_click_id++)."=false;',10000); } else { return false; }\"" : '';
$prevent_multiple_click = $filetype === 'folder' ? " onclick=\"javascript: if(typeof clic_$dbl_click_id == 'undefined' || !clic_$dbl_click_id) { clic_$dbl_click_id=true; window.setTimeout('clic_".($dbl_click_id++)."=false;',10000); } else { return false; }\"" : '';
}
$target = '_self';
$is_browser_viewable_file = false;
if ($filetype == 'file') {
if ($filetype === 'file') {
// Check the extension
$ext = explode('.', $path);
$ext = strtolower($ext[count($ext) - 1]);
@ -5191,11 +5196,7 @@ class DocumentManager
// HTML-files an some other types are shown in a frameset by default.
$is_browser_viewable_file = self::isBrowserViewable($ext);
if ($is_browser_viewable_file) {
if ($ext == 'pdf' || in_array($ext, $webODFList)) {
$url = $pageUrl.'?'.$courseParams.'&amp;action=download&amp;id='.$document_data['id'];
} else {
$url = $basePageUrl.'showinframes.php?'.$courseParams.'&id='.$document_data['id'];
}
$url = $basePageUrl.'showinframes.php?'.$courseParams.'&id='.$document_data['id'];
} else {
// url-encode for problematic characters (we may not call them dangerous characters...)
//$path = str_replace('%2F', '/', $url_path).'?'.$courseParams;
@ -5213,12 +5214,12 @@ class DocumentManager
$tooltip_title = $title;
$tooltip_title_alt = $tooltip_title;
if ($filetype == 'link') {
if ($filetype === 'link') {
$tooltip_title_alt = $title;
$url = $document_data['comment'].'" target="_blank';
}
if ($path == '/shared_folder') {
if ($path === '/shared_folder') {
$tooltip_title_alt = get_lang('UserFolders');
} elseif (strstr($path, 'shared_folder_session_')) {
$tooltip_title_alt = get_lang('UserFolders').' ('.api_get_session_name(api_get_session_id()).')';
@ -5633,7 +5634,7 @@ class DocumentManager
$parent_id
);
if (!$is_read_only /* or ($session_id!=api_get_session_id()) */) {
if (!$is_read_only) {
// Add action to covert to PDF, will create a new document whit same filename but .pdf extension
// @TODO: add prompt to select a format target
if (!in_array($path, self::get_system_folders())) {
@ -6553,7 +6554,7 @@ class DocumentManager
// checking
$table = Database::get_course_table(TABLE_DOCUMENT);
$courseId = $courseInfo['real_id'];
echo $sql = "SELECT * FROM $table WHERE id = $documentId AND c_id = $courseId";
$sql = "SELECT * FROM $table WHERE id = $documentId AND c_id = $courseId";
$result = Database::query($sql);
$exists = Database::num_rows($result) > 0;
$fileDeletedFromDb = !$exists;
@ -6647,6 +6648,12 @@ class DocumentManager
*/
public static function getFileHostingWhiteList()
{
$links = api_get_configuration_value('documents_custom_cloud_link_list');
if (!empty($links) && isset($links['links'])) {
return $links['links'];
}
return [
'asuswebstorage.com',
'box.com',

@ -532,7 +532,13 @@ class ExerciseLib
}
if ($answerType != UNIQUE_ANSWER_IMAGE) {
$answer = Security::remove_XSS($answer, STUDENT);
$userStatus = STUDENT;
// Allows to do a remove_XSS in question of exersice with user status COURSEMANAGER
// see BT#18242
if (api_get_configuration_value('question_exercise_html_strict_filtering')) {
$userStatus = COURSEMANAGERLOWSECURITY;
}
$answer = Security::remove_XSS($answer, $userStatus);
}
$s .= Display::input(
'hidden',
@ -578,7 +584,13 @@ class ExerciseLib
case GLOBAL_MULTIPLE_ANSWER:
case MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY:
$input_id = 'choice-'.$questionId.'-'.$answerId;
$answer = Security::remove_XSS($answer, STUDENT);
$userStatus = STUDENT;
// Allows to do a remove_XSS in question of exersice with user status COURSEMANAGER
// see BT#18242
if (api_get_configuration_value('question_exercise_html_strict_filtering')) {
$userStatus = COURSEMANAGERLOWSECURITY;
}
$answer = Security::remove_XSS($answer, $userStatus);
if (in_array($numAnswer, $userChoiceList)) {
$attributes = [
@ -775,7 +787,13 @@ class ExerciseLib
}
}
$answer = Security::remove_XSS($answer, STUDENT);
$userStatus = STUDENT;
// Allows to do a remove_XSS in question of exersice with user status COURSEMANAGER
// see BT#18242
if (api_get_configuration_value('question_exercise_html_strict_filtering')) {
$userStatus = COURSEMANAGERLOWSECURITY;
}
$answer = Security::remove_XSS($answer, $userStatus);
$answer_input = '<input type="hidden" name="choice2['.$questionId.']" value="0" />';
$answer_input .= '<label class="checkbox">';
$answer_input .= Display::input(
@ -811,7 +829,13 @@ class ExerciseLib
}
}
}
$answer = Security::remove_XSS($answer, STUDENT);
$userStatus = STUDENT;
// Allows to do a remove_XSS in question of exersice with user status COURSEMANAGER
// see BT#18242
if (api_get_configuration_value('question_exercise_html_strict_filtering')) {
$userStatus = COURSEMANAGERLOWSECURITY;
}
$answer = Security::remove_XSS($answer, $userStatus);
$s .= '<tr>';
$s .= Display::tag('td', $answer);
foreach ($objQuestionTmp->options as $key => $item) {
@ -1890,7 +1914,7 @@ HOTSPOT;
*/
public static function get_count_exam_results($exerciseId, $conditions, $courseCode = '', $showSession = false)
{
$count = self::get_exam_results_data(
return self::get_exam_results_data(
null,
null,
null,
@ -1901,8 +1925,6 @@ HOTSPOT;
$courseCode,
$showSession
);
return $count;
}
/**
@ -2048,7 +2070,7 @@ HOTSPOT;
}
/**
* Gets the exam'data results.
* Gets exercise results.
*
* @todo this function should be moved in a library + no global calls
*
@ -2095,7 +2117,6 @@ HOTSPOT;
}
$documentPath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document';
$course_id = $courseInfo['real_id'];
$sessionId = api_get_session_id();
$exercise_id = (int) $exercise_id;
@ -2121,9 +2142,16 @@ HOTSPOT;
$sessionCondition = " AND ttte.session_id = $sessionId";
}
if (empty($sessionId) &&
api_get_configuration_value('show_exercise_session_attempts_in_base_course')
) {
$session_id_and = '';
$sessionCondition = '';
}
$exercise_where = '';
if (!empty($exercise_id)) {
$exercise_where .= ' AND te.exe_exo_id = '.$exercise_id.' ';
$exercise_where .= ' AND te.exe_exo_id = '.$exercise_id.' ';
}
$hotpotatoe_where = '';
@ -2383,20 +2411,19 @@ HOTSPOT;
if (is_array($results)) {
$users_array_id = [];
$from_gradebook = false;
if (isset($_GET['gradebook']) && $_GET['gradebook'] == 'view') {
if (isset($_GET['gradebook']) && $_GET['gradebook'] === 'view') {
$from_gradebook = true;
}
$sizeof = count($results);
$locked = api_resource_is_locked_by_gradebook(
$exercise_id,
LINK_EXERCISE
);
$locked = api_resource_is_locked_by_gradebook($exercise_id, LINK_EXERCISE);
$timeNow = strtotime(api_get_utc_datetime());
// Looping results
for ($i = 0; $i < $sizeof; $i++) {
$revised = $results[$i]['revised'];
if ($results[$i]['completion_status'] == 'incomplete') {
$attemptSessionId = (int) $results[$i]['session_id'];
$cidReq = api_get_cidreq(false).'&id_session='.$attemptSessionId;
if ('incomplete' === $results[$i]['completion_status']) {
// If the exercise was incomplete, we need to determine
// if it is still into the time allowed, or if its
// allowed time has expired and it can be closed
@ -2430,17 +2457,20 @@ HOTSPOT;
$users_array_id[] = $results[$i]['username'].$results[$i]['firstname'].$results[$i]['lastname'];
}
$lp_obj = isset($results[$i]['orig_lp_id']) && isset($lp_list[$results[$i]['orig_lp_id']]) ? $lp_list[$results[$i]['orig_lp_id']] : null;
$lp_obj = isset($results[$i]['orig_lp_id']) &&
isset($lp_list[$results[$i]['orig_lp_id']]) ? $lp_list[$results[$i]['orig_lp_id']] : null;
if (empty($lp_obj)) {
// Try to get the old id (id instead of iid)
$lpNewId = isset($results[$i]['orig_lp_id']) && isset($oldIds[$results[$i]['orig_lp_id']]) ? $oldIds[$results[$i]['orig_lp_id']] : null;
$lpNewId = isset($results[$i]['orig_lp_id']) &&
isset($oldIds[$results[$i]['orig_lp_id']]) ? $oldIds[$results[$i]['orig_lp_id']] : null;
if ($lpNewId) {
$lp_obj = isset($lp_list[$lpNewId]) ? $lp_list[$lpNewId] : null;
}
}
$lp_name = null;
if ($lp_obj) {
$url = api_get_path(WEB_CODE_PATH).'lp/lp_controller.php?'.api_get_cidreq().'&action=view&lp_id='.$results[$i]['orig_lp_id'];
$url = api_get_path(WEB_CODE_PATH).
'lp/lp_controller.php?'.$cidReq.'&action=view&lp_id='.$results[$i]['orig_lp_id'];
$lp_name = Display::url(
$lp_obj['lp_name'],
$url,
@ -2508,7 +2538,7 @@ HOTSPOT;
$revisedLabel = '';
switch ($revised) {
case 0:
$actions .= "<a href='exercise_show.php?".api_get_cidreq()."&action=qualify&id=$id'>".
$actions .= "<a href='exercise_show.php?".$cidReq."&action=qualify&id=$id'>".
Display:: return_icon(
'quiz.png',
get_lang('Qualify')
@ -2520,7 +2550,7 @@ HOTSPOT;
);
break;
case 1:
$actions .= "<a href='exercise_show.php?".api_get_cidreq()."&action=edit&id=$id'>".
$actions .= "<a href='exercise_show.php?".$cidReq."&action=edit&id=$id'>".
Display:: return_icon(
'edit.png',
get_lang('Edit'),
@ -2535,11 +2565,9 @@ HOTSPOT;
break;
case 2: //finished but not marked as such
$actions .= '<a href="exercise_report.php?'
.api_get_cidreq()
.'&exerciseId='
.$exercise_id
.'&a=close&id='
.$id
.$cidReq
.'&exerciseId='.$exercise_id
.'&a=close&id='.$id
.'">'.
Display:: return_icon(
'lock.png',
@ -2569,7 +2597,7 @@ HOTSPOT;
}
if ($filter == 2) {
$actions .= ' <a href="exercise_history.php?'.api_get_cidreq().'&exe_id='.$id.'">'.
$actions .= ' <a href="exercise_history.php?'.$cidReq.'&exe_id='.$id.'">'.
Display:: return_icon(
'history.png',
get_lang('ViewHistoryChange')
@ -2588,7 +2616,7 @@ HOTSPOT;
.'</a>';
$recalculateUrl = api_get_path(WEB_CODE_PATH).'exercise/recalculate.php?'.
api_get_cidreq().'&'.
$cidReq.'&'.
http_build_query([
'id' => $id,
'exercise' => $exercise_id,
@ -2606,8 +2634,9 @@ HOTSPOT;
);
$filterByUser = isset($_GET['filter_by_user']) ? (int) $_GET['filter_by_user'] : 0;
$delete_link = '<a href="exercise_report.php?'.api_get_cidreq().'&filter_by_user='.$filterByUser.'&filter='.$filter.'&exerciseId='.$exercise_id.'&delete=delete&did='.$id.'"
onclick="javascript:if(!confirm(\''.sprintf(
$delete_link = '<a
href="exercise_report.php?'.$cidReq.'&filter_by_user='.$filterByUser.'&filter='.$filter.'&exerciseId='.$exercise_id.'&delete=delete&did='.$id.'"
onclick="javascript:if(!confirm(\''.sprintf(
addslashes(get_lang('DeleteAttempt')),
$results[$i]['username'],
$dt
@ -2629,7 +2658,7 @@ HOTSPOT;
$actions .= $delete_link;
}
} else {
$attempt_url = api_get_path(WEB_CODE_PATH).'exercise/result.php?'.api_get_cidreq().'&id='.$results[$i]['exe_id'].'&id_session='.$sessionId;
$attempt_url = api_get_path(WEB_CODE_PATH).'exercise/result.php?'.$cidReq.'&id='.$results[$i]['exe_id'];
$attempt_link = Display::url(
get_lang('Show'),
$attempt_url,
@ -2661,8 +2690,8 @@ HOTSPOT;
if ($is_allowedToEdit) {
$sessionName = '';
$sessionStartAccessDate = '';
if (!empty($results[$i]['session_id'])) {
$sessionInfo = api_get_session_info($results[$i]['session_id']);
if (!empty($attemptSessionId)) {
$sessionInfo = api_get_session_info($attemptSessionId);
if (!empty($sessionInfo)) {
$sessionName = $sessionInfo['name'];
$sessionStartAccessDate = api_get_local_time($sessionInfo['access_start_date']);
@ -2678,7 +2707,8 @@ HOTSPOT;
if (!empty($question_list)) {
foreach ($question_list as $questionId) {
$objQuestionTmp = Question::read($questionId, $objExercise->course);
// We're inside *one* question. Go through each possible answer for this question
// We're inside *one* question.
// Go through each possible answer for this question.
$result = $objExercise->manage_answer(
$exeId,
$questionId,
@ -2755,8 +2785,8 @@ HOTSPOT;
$result['total'],
true,
true,
true, // $show_only_percentage = false
true, // hide % sign
true,
true,
$decimalSeparator,
$thousandSeparator,
$roundValues
@ -3878,18 +3908,18 @@ EOT;
/**
* Get student results (only in completed exercises) stats by question.
*
* @param int $question_id
* @param int $exercise_id
* @param string $course_code
* @param int $session_id
* @param bool $onlyStudent Filter only enrolled students
* @param int $question_id
* @param int $exercise_id
* @param int $courseId
* @param int $session_id
* @param bool $onlyStudent Filter only enrolled students
*
* @return array
*/
public static function get_student_stats_by_question(
$question_id,
$exercise_id,
$course_code,
$courseId,
$session_id,
$onlyStudent = false
) {
@ -3899,35 +3929,35 @@ EOT;
$question_id = (int) $question_id;
$exercise_id = (int) $exercise_id;
$course_code = Database::escape_string($course_code);
$session_id = (int) $session_id;
$courseId = api_get_course_int_id($course_code);
$courseId = (int) $courseId;
$sql = "SELECT MAX(marks) as max, MIN(marks) as min, AVG(marks) as average
FROM $track_exercises e
";
if (true == $onlyStudent) {
$courseCondition = '';
FROM $track_exercises e ";
if ($onlyStudent) {
if (empty($session_id)) {
$courseCondition = "
INNER JOIN $courseUser c
ON (
INNER JOIN $courseUser c
ON (
e.exe_user_id = c.user_id AND
e.c_id = c.c_id AND
c.status = ".STUDENT."
AND relation_type <> 2
)";
)";
} else {
$sessionRelCourse = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
$courseCondition = "
INNER JOIN $courseUser c
ON (
e.exe_user_id = c.user_id AND
e.c_id = c.c_id AND
c.status = 0
)";
INNER JOIN $sessionRelCourse sc
ON (
e.exe_user_id = sc.user_id AND
e.c_id = sc.c_id AND
e.session_id = sc.session_id AND
sc.status = 0
) ";
}
$sql .= $courseCondition;
}
$sql .= "
INNER JOIN $track_attempt a
ON (
@ -4163,7 +4193,7 @@ EOT;
* @param int $answer_id
* @param int $question_id
* @param int $exercise_id
* @param string $course_code
* @param int $courseId
* @param int $session_id
* @param string $question_type
* @param string $correct_answer
@ -4175,7 +4205,7 @@ EOT;
$answer_id,
$question_id,
$exercise_id,
$course_code,
$courseId,
$session_id,
$question_type = null,
$correct_answer = null,
@ -4190,7 +4220,7 @@ EOT;
$question_id = (int) $question_id;
$answer_id = (int) $answer_id;
$exercise_id = (int) $exercise_id;
$courseId = api_get_course_int_id($course_code);
$courseId = (int) $courseId;
$session_id = (int) $session_id;
switch ($question_type) {
@ -4660,7 +4690,7 @@ EOT;
}
// Check if the current attempt is the last.
if (false === $save_user_result && !empty($attempts)) {
/*if (false === $save_user_result && !empty($attempts)) {
$showTotalScoreAndUserChoicesInLastAttempt = false;
$position = 1;
foreach ($attempts as $attempt) {
@ -4673,7 +4703,7 @@ EOT;
if ($position == $objExercise->attempts) {
$showTotalScoreAndUserChoicesInLastAttempt = true;
}
}
}*/
}
}
@ -4911,6 +4941,16 @@ EOT;
}
$contents = ob_get_clean();
// Hide correct answers.
if ($scorePassed && false === $objExercise->disableHideCorrectAnsweredQuestions) {
// Skip correct answers.
$hide = (int) $objExercise->getPageConfigurationAttribute('hide_correct_answered_questions');
if (1 === $hide) {
continue;
}
}
$question_content = '';
if ($show_results) {
$question_content = '<div class="question_row_answer">';
@ -5465,22 +5505,21 @@ EOT;
/**
* Get the recorder audio component for save a teacher audio feedback.
*
* @param int $attemptId
* @param int $questionId
* @param int $userId
* @param Template $template
* @param int $attemptId
* @param int $questionId
* @param int $userId
*
* @return string
*/
public static function getOralFeedbackForm($attemptId, $questionId, $userId)
public static function getOralFeedbackForm($template, $attemptId, $questionId, $userId)
{
$view = new Template('', false, false, false, false, false, false);
$view->assign('user_id', $userId);
$view->assign('question_id', $questionId);
$view->assign('directory', "/../exercises/teacher_audio/$attemptId/");
$view->assign('file_name', "{$questionId}_{$userId}");
$template = $view->get_template('exercise/oral_expression.tpl');
$template->assign('user_id', $userId);
$template->assign('question_id', $questionId);
$template->assign('directory', "/../exercises/teacher_audio/$attemptId/");
$template->assign('file_name', "{$questionId}_{$userId}");
return $view->fetch($template);
return $template->fetch($template->get_template('exercise/oral_expression.tpl'));
}
/**
@ -5960,23 +5999,34 @@ EOT;
return $total;
}
public static function parseContent($content, $stats, $exercise, $trackInfo, $currentUserId = 0)
public static function parseContent($content, $stats, Exercise $exercise, $trackInfo, $currentUserId = 0)
{
$wrongAnswersCount = $stats['failed_answers_count'];
$attemptDate = substr($trackInfo['exe_date'], 0, 10);
$exeId = $trackInfo['exe_id'];
$resultsStudentUrl = api_get_path(WEB_CODE_PATH).
'exercise/result.php?id='.$exeId.'&'.api_get_cidreq();
$resultsTeacherUrl = api_get_path(WEB_CODE_PATH).
'exercise/exercise_show.php?action=edit&id='.$exeId.'&'.api_get_cidreq();
$content = str_replace(
[
'((exercise_error_count))',
'((all_answers_html))',
'((all_answers_teacher_html))',
'((exercise_title))',
'((exercise_attempt_date))',
'((link_to_test_result_page_student))',
'((link_to_test_result_page_teacher))',
],
[
$wrongAnswersCount,
$stats['all_answers_html'],
$stats['all_answers_teacher_html'],
$exercise->get_formated_title(),
$attemptDate,
$resultsStudentUrl,
$resultsTeacherUrl,
],
$content
);
@ -5999,7 +6049,8 @@ EOT;
$exercise_stat_info,
$courseInfo,
$attemptCountToSend,
$stats
$stats,
$statsTeacher
) {
$notifications = api_get_configuration_value('exercise_finished_notification_settings');
if (empty($notifications)) {
@ -6011,6 +6062,7 @@ EOT;
$wrongAnswersCount = $stats['failed_answers_count'];
$exercisePassed = $stats['exercise_passed'];
$countPendingQuestions = $stats['count_pending_questions'];
$stats['all_answers_teacher_html'] = $statsTeacher['all_answers_html'];
// If there are no pending questions (Open questions).
if (0 === $countPendingQuestions) {
@ -6079,10 +6131,9 @@ EOT;
if ($extraFieldData && isset($extraFieldData['value'])) {
$content = $extraFieldData['value'];
$content = self::parseContent($content, $stats, $objExercise, $exercise_stat_info, $studentId);
if (false === $exercisePassed) {
if (0 !== $wrongAnswersCount) {
$content .= $stats['failed_answers_html'];
}
//if (false === $exercisePassed) {
if (0 !== $wrongAnswersCount) {
$content .= $stats['failed_answers_html'];
}
$sendMessage = true;

@ -3117,6 +3117,7 @@ JAVASCRIPT;
$tagRelExtraTable = Database::get_main_table(TABLE_MAIN_EXTRA_FIELD_REL_TAG);
$tagTable = Database::get_main_table(TABLE_MAIN_TAG);
$optionsTable = Database::get_main_table(TABLE_EXTRA_FIELD_OPTIONS);
$value = Database::escape_string(implode("','", $options));
$sql = "SELECT DISTINCT t.*, v.value, o.display_text
FROM $tagRelExtraTable te
@ -3126,7 +3127,7 @@ JAVASCRIPT;
ON (te.item_id = v.item_id AND v.field_id = $id)
INNER JOIN $optionsTable o
ON (o.option_value = v.value)
WHERE v.value IN ('".implode("','", $options)."')
WHERE v.value IN ('".$value."')
ORDER BY o.option_order, t.tag
";

@ -2474,7 +2474,7 @@ class GroupManager
);
$table->set_additional_parameters(['category' => $category_id]);
$column = 0;
if (api_is_allowed_to_edit(false, true) and count($group_list) > 1) {
if (api_is_allowed_to_edit(false, true) && count($group_list) > 1) {
$table->set_header($column++, '', false);
}
$table->set_header($column++, get_lang('Groups'));

@ -0,0 +1,30 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Class HookPortfolioItemAdded.
*/
class HookPortfolioItemAdded extends HookEvent implements HookPortfolioItemAddedEventInterface
{
/**
* HookPortfolioItemAdded constructor.
*
* @throws \Exception
*/
public function __construct()
{
parent::__construct('HookPortfolioItemAdded');
}
/**
* {@inheritDoc}
*/
public function notifyItemAdded()
{
/** @var \HookPortfolioItemAddedObserverInterface $observer */
foreach ($this->observers as $observer) {
$observer->hookItemAdded($this);
}
}
}

@ -0,0 +1,27 @@
<?php
/* For licensing terms, see /license.txt */
class HookPortfolioItemCommented extends HookEvent implements HookPortfolioItemCommentedEventInterface
{
/**
* HookPortfolioItemCommented constructor.
*
* @throws \Exception
*/
protected function __construct()
{
parent::__construct('HookPortfolioItemCommented');
}
/**
* {@inheritDoc}
*/
public function notifyItemCommented()
{
/** @var \HookPortfolioItemCommentedObserverInterface $observer */
foreach ($this->observers as $observer) {
$observer->hookItemCommented($this);
}
}
}

@ -0,0 +1,14 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Interface HookPortfolioItemAddedEventInterface.
*/
interface HookPortfolioItemAddedEventInterface extends HookEventInterface
{
/**
* @return void
*/
public function notifyItemAdded();
}

@ -0,0 +1,16 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Interface HookPortfolioItemAddedObserverInterface.
*/
interface HookPortfolioItemAddedObserverInterface extends HookObserverInterface
{
/**
* @param \HookPortfolioItemAddedEventInterface $hookEvent
*
* @return mixed
*/
public function hookItemAdded(HookPortfolioItemAddedEventInterface $hookEvent);
}

@ -0,0 +1,14 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Interface HookPortfolioItemCommentedEventInterface.
*/
interface HookPortfolioItemCommentedEventInterface extends HookEventInterface
{
/**
* @return void
*/
public function notifyItemCommented();
}

@ -0,0 +1,16 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Interface HookPortfolioItemCommentedObserverInterface.
*/
interface HookPortfolioItemCommentedObserverInterface extends HookObserverInterface
{
/**
* @param \HookPortfolioItemCommentedEventInterface $hookEvent
*
* @return mixed
*/
public function hookItemCommented(HookPortfolioItemCommentedEventInterface $hookEvent);
}

@ -7,7 +7,9 @@
interface HookQuizEndObserverInterface
{
/**
* @param \HookQuizEndEventInterface $hookEvent
*
* @return mixed
*/
public function hookQuizEnd(HookQuizEndEventInterface $hookvent);
public function hookQuizEnd(HookQuizEndEventInterface $hookEvent);
}

@ -15,11 +15,11 @@ CKEDITOR.plugins.setLang('oembed', 'fr', {
maxHeight: "Max. Hauteur:",
maxWidthTitle: "Largeur maximale du conteneur.",
maxHeightTitle: "Hauteur maximale du conteneur.",
resizeType: "Resize Type (Only Video's):",
noresize: "No Resize (use default)",
responsive: "Responsive Resize",
custom: "Specific Resize",
autoClose: "Automatically Close Dialog after Code is Embeded",
noVimeo: "The owner of this video has set domain restrictions and you will not be able to embed it on your website.",
Error: "Media Content could not been retrieved, please try a different URL."
resizeType: "Type de redimensionnement (uniquement les vidéos):",
noresize: "Pas de redimensionnement (par défaut)",
responsive: "Redimensionnement réactif",
custom: "Redimensionnement spécifique",
autoClose: "Fermer automatiquement la boîte de dialogue une fois le code incorporé",
noVimeo: "Le propriétaire de cette vidéo a défini des restrictions de domaine et vous ne pourrez pas l'intégrer à votre site Web.",
Error: "Impossible de récupérer le contenu multimédia, veuillez essayer une autre URL."
});

@ -1,8 +1,6 @@
/* For licensing terms, see /license.txt */
window.RecordAudio = (function () {
var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
function startTimer() {
$("#timer").show();
var timerData = {
@ -126,8 +124,10 @@ window.RecordAudio = (function () {
stopTimer();
startTimer();
recordRTC = RecordRTC(stream, {
recorderType: isSafari ? RecordRTC.StereoAudioRecorder : RecordRTC.MediaStreamRecorder,
type: 'audio'
recorderType: RecordRTC.StereoAudioRecorder,
type: 'audio',
mimeType: 'audio/wav',
numberOfAudioChannels: 2
});
recordRTC.startRecording();
@ -185,7 +185,6 @@ window.RecordAudio = (function () {
if (!recordRTC) {
return;
}
stopTimer();
recordRTC.stopRecording(function (audioURL) {
btnStart.prop('disabled', false).removeClass('hidden');
@ -280,4 +279,4 @@ window.RecordAudio = (function () {
useWami(wamiInfo, fileName);
}
}
})();
})();

@ -186,12 +186,15 @@ class PDF
* 1 => array('title'=>'Bye','path'=>'file2.html')
* );
* @param string $pdf_name pdf name
* @param string $course_code (if you are using html that are located
* @param null $course_code (if you are using html that are located
* in the document tool you must provide this)
* @param bool $print_title add title
* @param bool $complete_style show header and footer if true
* @param bool $addStyle
* @param string $mainTitle
* @param bool $generateToFile Optional. When it is TRUE, then the output file is move to app/cache
*
* @throws \MpdfException
*
* @return false|null
*/
@ -202,7 +205,8 @@ class PDF
$print_title = false,
$complete_style = true,
$addStyle = true,
$mainTitle = ''
$mainTitle = '',
$generateToFile = false
) {
if (empty($html_file_array)) {
return false;
@ -365,7 +369,15 @@ class PDF
$output_file = $pdf_name.'.pdf';
}
// F to save the pdf in a file
@$this->pdf->Output($output_file, 'D');
if ($generateToFile) {
@$this->pdf->Output(
api_get_path(SYS_ARCHIVE_PATH).$output_file,
'F'
);
} else {
@$this->pdf->Output($output_file, 'D');
}
exit;
}
@ -490,6 +502,7 @@ class PDF
$document_html
);
$document_html = str_replace(api_get_path(WEB_UPLOAD_PATH), api_get_path(SYS_UPLOAD_PATH), $document_html);
$document_html = str_replace(api_get_path(WEB_ARCHIVE_PATH), api_get_path(SYS_ARCHIVE_PATH), $document_html);
// The library mPDF expects UTF-8 encoded input data.

@ -58,6 +58,8 @@ class Security
return false;
}
// Clean $abs_path.
$abs_path = str_replace(['//', '../', './'], ['/', '', ''], $abs_path);
$true_path = str_replace("\\", '/', realpath($abs_path));
$checker_path = str_replace("\\", '/', realpath($checker_path));

@ -149,6 +149,7 @@ class Template
'api_get_user_info',
'api_get_configuration_value',
'api_get_setting',
'api_get_course_setting',
'api_get_plugin_setting',
[
'name' => 'return_message',
@ -446,9 +447,10 @@ class Template
// Only if course is available
$courseToolBar = '';
$origin = api_get_origin();
$show_course_navigation_menu = '';
if (!empty($this->course_id) && $this->user_is_logged_in) {
if (api_get_setting('show_toolshortcuts') != 'false') {
if ($origin !== 'embeddable' && api_get_setting('show_toolshortcuts') !== 'false') {
// Course toolbar
$courseToolBar = CourseHome::show_navigation_tool_shortcuts();
}

@ -3575,6 +3575,7 @@ class UserManager
$categoryStart = $row['session_category_date_start'] ? $row['session_category_date_start']->format('Y-m-d') : '';
$categoryEnd = $row['session_category_date_end'] ? $row['session_category_date_end']->format('Y-m-d') : '';
$courseList = self::get_courses_list_by_session($user_id, $session_id);
$daysLeft = SessionManager::getDayLeftInSession($row, $user_id);
// User portal filters:
@ -4077,9 +4078,19 @@ class UserManager
$checkPosition = array_filter(array_column($myCourseList, 'position'));
if (empty($checkPosition)) {
// The session course list doesn't have any position,
// then order the course list by course code
$list = array_column($myCourseList, 'course_code');
array_multisort($myCourseList, SORT_ASC, $list);
// then order the course list by course code.
$orderByCode = array_column($myCourseList, 'course_code');
sort($orderByCode, SORT_NATURAL);
$newCourseList = [];
foreach ($orderByCode as $code) {
foreach ($myCourseList as $course) {
if ($code === $course['course_code']) {
$newCourseList[] = $course;
break;
}
}
}
$myCourseList = $newCourseList;
}
}

@ -302,6 +302,8 @@ $_configuration['system_stable'] = NEW_VERSION_STABLE;
// Allows to do a remove_XSS in course introduction with user status COURSEMANAGERLOWSECURITY
// in order to accept all embed type videos (like vimeo, wistia, etc)
// $_configuration['course_introduction_html_strict_filtering'] = true;
// Allows to do a remove_XSS in question of exersice with user status COURSEMANAGER
// $_configuration['question_exercise_html_strict_filtering'] = true;
// Prevents the duplicate upload in assignments
// $_configuration['assignment_prevent_duplicate_upload'] = false;
//Show student progress in My courses page
@ -920,13 +922,15 @@ ALTER TABLE portfolio ADD CONSTRAINT FK_A9ED1062613FECDF FOREIGN KEY (session_id
ALTER TABLE portfolio ADD CONSTRAINT FK_A9ED106212469DE2 FOREIGN KEY (category_id) REFERENCES portfolio_category (id) ON DELETE SET NULL;
ALTER TABLE portfolio_category ADD CONSTRAINT FK_7AC64359A76ED395 FOREIGN KEY (user_id) REFERENCES user (id);
INSERT INTO settings_current(variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable) VALUES('course_create_active_tools','portfolio','checkbox','Tools','true','CourseCreateActiveToolsTitle','CourseCreateActiveToolsComment',NULL,'Portfolio', 0);
CREATE TABLE portfolio_comment (id INT AUTO_INCREMENT NOT NULL, author_id INT NOT NULL, item_id INT NOT NULL, tree_root INT DEFAULT NULL, parent_id INT DEFAULT NULL, content LONGTEXT NOT NULL, date DATETIME NOT NULL, is_important TINYINT(1) DEFAULT '0' NOT NULL, lft INT NOT NULL, lvl INT NOT NULL, rgt INT NOT NULL, INDEX IDX_C2C17DA2F675F31B (author_id), INDEX IDX_C2C17DA2126F525E (item_id), INDEX IDX_C2C17DA2A977936C (tree_root), INDEX IDX_C2C17DA2727ACA70 (parent_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB;
CREATE TABLE portfolio_comment (id INT AUTO_INCREMENT NOT NULL, author_id INT NOT NULL, item_id INT NOT NULL, tree_root INT DEFAULT NULL, parent_id INT DEFAULT NULL, content LONGTEXT NOT NULL, date DATETIME NOT NULL, is_important TINYINT(1) DEFAULT '0' NOT NULL, lft INT NOT NULL, lvl INT NOT NULL, rgt INT NOT NULL, score DOUBLE PRECISION DEFAULT NULL, INDEX IDX_C2C17DA2F675F31B (author_id), INDEX IDX_C2C17DA2126F525E (item_id), INDEX IDX_C2C17DA2A977936C (tree_root), INDEX IDX_C2C17DA2727ACA70 (parent_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB;
ALTER TABLE portfolio_comment ADD CONSTRAINT FK_C2C17DA2F675F31B FOREIGN KEY (author_id) REFERENCES user (id);
ALTER TABLE portfolio_comment ADD CONSTRAINT FK_C2C17DA2126F525E FOREIGN KEY (item_id) REFERENCES portfolio (id);
ALTER TABLE portfolio_comment ADD CONSTRAINT FK_C2C17DA2A977936C FOREIGN KEY (tree_root) REFERENCES portfolio_comment (id) ON DELETE CASCADE;
ALTER TABLE portfolio_comment ADD CONSTRAINT FK_C2C17DA2727ACA70 FOREIGN KEY (parent_id) REFERENCES portfolio_comment (id) ON DELETE CASCADE;
ALTER TABLE portfolio ADD origin INT DEFAULT NULL, ADD origin_type INT DEFAULT NULL;
ALTER TABLE portfolio ADD score DOUBLE PRECISION DEFAULT NULL;
INSERT INTO extra_field (extra_field_type, field_type, variable, display_text, visible_to_self, visible_to_others, changeable, created_at) VALUES (19, 10, 'tags', 'tags', 1, 1, 1, NOW());
CREATE TABLE portfolio_attachment (id INT AUTO_INCREMENT NOT NULL, path VARCHAR(255) NOT NULL, comment LONGTEXT DEFAULT NULL, size INT NOT NULL, filename VARCHAR(255) NOT NULL, origin_id INT NOT NULL, origin_type INT NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB;
*/
// In 1.11.8, before enabling this feature, you also need to:
// - edit src/Chamilo/CoreBundle/Entity/Portfolio.php and PortfolioCategory.php
@ -990,6 +994,8 @@ VALUES (2, 13, 'session_courses_read_only_mode', 'Lock Course In Session', 1, 1,
// Set to true to disable the new personal data page inside the social network
// menu
// $_configuration['disable_gdpr'] = true;
// Set the LinkedIn organization id BT#17468
//$_configuration['linkedin_organization_id'] = false;
// GDPR requires users to be informed of the Data Protection Officer name and
// contact point. These can only be defined here for now, but will be moved to
@ -1820,6 +1826,24 @@ ALTER TABLE gradebook_comment ADD CONSTRAINT FK_C3B70763AD3ED51C FOREIGN KEY (gr
// Add certificate footer. Add your template main/template/default/export/pdf_certificate_footer.tpl
// $_configuration['add_certificate_pdf_footer'] = true;
// Shows a popup with the list of answered/unanswered questions before sending a test.
// $_configuration['quiz_check_all_answers_before_end_test'] = true;
// Custom cloud link URLS, this requires enable_add_file_link = true
// $_configuration['documents_custom_cloud_link_list'] = ['links' => ['example.com', 'example2.com']];
// Shows exercise session attempts in the base course.
// $_configuration['show_exercise_session_attempts_in_base_course'] = false;
// Allow coach users to always edit announcements inside active/past sessions.
// $_configuration['allow_coach_to_edit_announcements'] = false;
// Show invisible LP in the course home for students. BT#17744
//$_configuration['show_invisible_lp_in_course_home'] = true;
// Show start/end date in LP list for students.
//$_configuration['lp_start_and_end_date_visible_in_student_view'] = true;
// KEEP THIS AT THE END
// -------- Custom DB changes
// Add user activation by confirmation email

@ -615,7 +615,7 @@ $Stats = "Statistics";
$UplPage = "Upload page and link to Home Page";
$LinkSite = "Add link to page on Home Page";
$HasDel = "has been deleted";
$ByDel = "Deleting this area will permanently delete all the content (documents, links...) it contains and unregister all its members (not remove them from other courses). <p>Do you really want to delete the course?";
$ByDel = "Deleting this area will permanently delete all the content (documents, links...) it contains and unregister all its members (not remove them from other courses).";
$Y = "YES";
$N = "NO";
$DepartmentUrl = "Department URL";
@ -6675,7 +6675,7 @@ $NewExercises = "New exercises";
$MyAverage = "My average";
$AllAttempts = "All attempts";
$QuestionsToReview = "Questions to be reviewed";
$QuestionWithNoAnswer = "Questions without answer";
$QuestionWithNoAnswer = "Questions without answer will be highlighted in Red below";
$ValidateAnswers = "Validate answers";
$ReviewQuestions = "Review selected questions";
$YouTriedToResolveThisExerciseEarlier = "You have tried to resolve this exercise earlier";
@ -7574,7 +7574,7 @@ $Convert = "Convert";
$PortalLimitType = "Portal's limit type";
$PortalName = "Portal name";
$BestScore = "Best score";
$AreYouSureToDeleteJS = "Are you sure to delete";
$AreYouSureToDeleteJS = "Are you sure to delete?";
$ConversionToSameFileFormat = "Conversion to same file format. Please choose another.";
$FileFormatNotSupported = "File format not supported";
$FileConvertedFromXToY = "File converted from %s to %s";
@ -8720,4 +8720,45 @@ $ShowScoreEveryAttemptShowAnswersLastAttemptNoFeedback = "Show the result to the
$AddGradebookComment = "Comment";
$LatestLoginInAnyCourse = "Latest login in a course";
$The = "The";
$MultiplicateQuestionsByClass = "Multiplicate questions by class";
$MultiplicateQuestionsByUser = "Multiplicate questions by user";
$QuestionForNextUser = "Questions about next user";
$CourseCodeToEnteredCapitalLettersToConfirmDeletionX = "Course code to be entered in capital letters to confirm the deletion: %s";
$BadgeXTitle = "Badge: %s";
$PortfolioCommentFromXUser = "Comment by %s";
$PortfolioItemFromXUser = "Portfolio item by %s";
$CopyToMyPortfolio = "Copy to my portfolio";
$CopyToStudentPortfolio = "Copy to student portfolio";
$OriginallyPublishedAsXTitleByYUser = "Originally published as \"%s\" by %s";
$OriginallyCommentedByXUserInYItem = "Originally commented by %s in \"%s\"";
$PortfolioItemAddedToStudents = "Item added to students own portfolio";
$MarkCommentAsImportant = "Mark comment as important";
$UnmarkCommentAsImportant = "Unmark comment as important";
$CommentMarkedAsImportant = "Portfolio item marked as important";
$SelectLearnerPortfolio = "Select a learner portfolio";
$SeeMyPortfolio = "See my portfolio in this course";
$PortfolioDetails = "Portfolio details";
$PortfolioItemTitle = "Item title";
$CreationDateXDate = "Creation date: %s";
$UpdateDateXDate = "Update date: %s";
$CategoryXName = "Category: %s";
$DateXDate = "Date: %s";
$PortfolioItemTitleXName = "Item title: %s";
$NoItemsInYourPortfolio = "No items in your portfolio";
$YouHaveNotCommented = "You have not commented";
$PortfolioItems = "Portfolio items";
$PortfolioComments = "Portfolio comments";
$PortfolioCommentsMade = "Comments made";
$QualifyThisPortfolioItem = "Grade this item";
$PortfolioItemGraded = "Portfolio item was graded";
$ContextForCommentToBeGrade = "Context for the comment to be grade";
$QualifyThisPortfolioComment = "Grade this comment";
$PortfolioCommentGraded = "Portfolio comment was graded";
$QualifyPortfolioItems = "Grade items";
$QualifyPortfolioComments = "Grade comments";
$HideCorrectAnsweredQuestions = "Hide correct answered questions";
$TheSettingXWillChangeToX = "The setting \"%s\" will change to \"%s\"";
$VerificationOfAnsweredQuestions = "Verification of answered questions";
$StudentPublicationToCorrect = "Student's assignments to be corrected";
$StudentPublicationCorrectionWarning = "You will find below all the work that have been submitted by students in one of your course (it could be in the base course or in a course in a session). You can filter the list selecting a specific course or a work status.";
?>

@ -239,7 +239,7 @@ $WithoutCategory = "Sans catégorie";
$IncorrectScore = "Score réponse incorrecte";
$CorrectScore = "Score réponse correcte";
$UseCustomScoreForAllQuestions = "Utiliser le score sur mesure pour toutes les questions";
$YouShouldAddItemsBeforeAttachAudio = "
$YouShouldAddItemsBeforeAttachAudio = "
Vous devez ajouter des étapes à votre parcours avant de pouvoir leur affecter des fichiers audio";
$InactiveDays = "Jours inactifs";
$FollowedHumanResources = "DRH suivis";
@ -326,23 +326,23 @@ $DeleteUsersNotInList = "Désinscrite les apprenants qui ne sont pas dans la lis
$IfSessionExistsUpdate = "Si une session existe, la mettre à jour";
$CreatedByXYOnZ = "Créé(e) par <a href=\"%s\">%s</a>, le %s";
$LoginWithExternalAccount = "S'authentifier avec un compte extérieur à l'établissement";
$ImportAikenQuizExplanationExample = "Ceci est le texte de la question 1
A. Réponse 1
B. Réponse 2
C. Réponse 3
ANSWER: B
Ceci est le texte de la question 2
A. Réponse 1
B. Réponse 2
C. Réponse 3
D. Réponse 4
ANSWER: D
ANSWER_EXPLANATION: C'est un commentaire facultatif de retour qui apparaîtra à côté de la bonne réponse.
$ImportAikenQuizExplanationExample = "Ceci est le texte de la question 1
A. Réponse 1
B. Réponse 2
C. Réponse 3
ANSWER: B
Ceci est le texte de la question 2
A. Réponse 1
B. Réponse 2
C. Réponse 3
D. Réponse 4
ANSWER: D
ANSWER_EXPLANATION: C'est un commentaire facultatif de retour qui apparaîtra à côté de la bonne réponse.
SCORE: 20";
$ImportAikenQuizExplanation = "Le format Aiken est un fichier (.txt) avec un texte simple, avec plusieurs blocs de questions, chacune séparée par une ligne blanche. La première ligne est la question, les lignes de réponse sont préfixés par une lettre et un point, et la bonne réponse vient avec le préfixe 'ANSWER'.
$ImportAikenQuizExplanation = "Le format Aiken est un fichier (.txt) avec un texte simple, avec plusieurs blocs de questions, chacune séparée par une ligne blanche. La première ligne est la question, les lignes de réponse sont préfixés par une lettre et un point, et la bonne réponse vient avec le préfixe 'ANSWER'.
Voir l'exemple ci-dessous.";
$ExerciseAikenErrorNoAnswerOptionGiven = "Le fichier importé comporte au moins une question sans réponse (ou les réponses ne comprennent pas la lettre de préfixe requis). Assurez-vous que chaque question a au moins une réponse et qu'elle est précédée par une lettre et un point ou une parenthèse, comme ceci:
$ExerciseAikenErrorNoAnswerOptionGiven = "Le fichier importé comporte au moins une question sans réponse (ou les réponses ne comprennent pas la lettre de préfixe requis). Assurez-vous que chaque question a au moins une réponse et qu'elle est précédée par une lettre et un point ou une parenthèse, comme ceci:
A. Réponse 1";
$ExerciseAikenErrorNoCorrectAnswerDefined = "Le fichier importé comporte au moins une question sans réponse correcte définie. Assurez-vous que toutes les questions comprennent la réponse: [Lettre] ligne.";
$SearchCourseBySession = "Recherche de cours par session";
@ -607,7 +607,7 @@ $Stats = "Suivi";
$UplPage = "Déposer page et lier à l'accueil";
$LinkSite = "Ajouter un lien sur la page d'accueil";
$HasDel = "a été supprimé";
$ByDel = "En supprimant ce cours, vous supprimerez tous les documents qu'il contient et désinscrirez tous les membres qui y sont inscrits. <p>Voulez-vous réellement supprimer ce cours ?";
$ByDel = "En supprimant ce cours, vous supprimerez tous les documents qu'il contient et désinscrirez tous les membres qui y sont inscrits.";
$Y = "OUI";
$N = "NON";
$DepartmentUrl = "URL du département";
@ -837,10 +837,10 @@ $AllowVisitors = "Permettre des visiteurs externes";
$EnableIframeInclusionComment = "Autoriser les balises iframe dans l'éditeur HTML améliore l'édition de documents mais peut représenter un risque pour la sécurité.";
$AddedToLPCannotBeAccessed = "Cet exercice fait partie d'un parcours d'apprentissage, il n'est donc pas accessible par les étudiants depuis cette page. Si vous voulez rendre cet exercice disponible depuis l'outil exercice, vous devez en faire une copie en utilisant l'icône \"Copie\"";
$EnableIframeInclusionTitle = "Autoriser les balises iframe dans l'éditeur HTML.";
$MailTemplateRegistrationMessage = "Cher(ère) ((firstname)) ((lastname)), Vous êtes inscrit(e) sur
((sitename) avec les paramètres suivants: Nom d'utilisateur :
((username)) Mot de passe : ((password)) L'adresse de ((sitename)) est :
((url)) En cas de problème, n'hésitez pas à prendre contact avec nous
$MailTemplateRegistrationMessage = "Cher(ère) ((firstname)) ((lastname)), Vous êtes inscrit(e) sur
((sitename) avec les paramètres suivants: Nom d'utilisateur :
((username)) Mot de passe : ((password)) L'adresse de ((sitename)) est :
((url)) En cas de problème, n'hésitez pas à prendre contact avec nous
Cordialement, le responsable ((admin_name)) ((admin_surname)).";
$Explanation = "Une fois que vous aurez cliqué sur OK, un cours contenant Tests, Documents, Parcours d'Apprentissage SCORM... sera créé. Grâce à votre identifiant de responsable du cours vous pourrez en modifier le contenu";
$CodeTaken = "Ce code est déjà pris.<br />Utilisez le bouton de retour en arrière de votre navigateur et recommencez";
@ -2633,14 +2633,14 @@ $NoPosts = "Aucune publication";
$WithoutAchievedSkills = "Aucune compétence acquise";
$TypeMessage = "Veuillez introduire votre message !";
$ConfirmReset = "Êtes-vous sûr de vouloir supprimer tous les messages ?";
$MailCronCourseExpirationReminderBody = "Cher/Chère %s,
Nous avons remarqué que vous n'avez pas terminé le cours %s alors que sa date de fin a été établie au %s, vous laissant %s jour(s) pour le terminer. Nous vous rappelons que vous ne disposez de la possibilité de suivre ce cours qu'une fois par an. Nous vous invitons donc avec insistance à le compléter dans le délai qu'il vous reste. Vous pouvez retrouver le cours en vous connectant à la plate-forme à cette adresse: %s
--
Cordialement,
$MailCronCourseExpirationReminderBody = "Cher/Chère %s,
Nous avons remarqué que vous n'avez pas terminé le cours %s alors que sa date de fin a été établie au %s, vous laissant %s jour(s) pour le terminer. Nous vous rappelons que vous ne disposez de la possibilité de suivre ce cours qu'une fois par an. Nous vous invitons donc avec insistance à le compléter dans le délai qu'il vous reste. Vous pouvez retrouver le cours en vous connectant à la plate-forme à cette adresse: %s
--
Cordialement,
L'équipe de support de %s";
$MailCronCourseExpirationReminderSubject = "Urgent: Rappel d'expiration prochaine du cours %s";
$ExerciseAndLearningPath = "Exercices et parcours";
@ -5547,7 +5547,7 @@ $AssignCoursesToHumanResourcesManager = "Assigner des cours au directeur RH";
$TimezoneValueTitle = "Fuseau horaire";
$TimezoneValueComment = "Le fuseau horaire de ce portail devrait être réglé sur celui du siège de l'organisation. Si vous ne configurez pas de fuseau horaire, celui du serveur sera utilisé. Si vous en configurez un, toutes les heures de cette plateforme seront affichées sur base de ce fuseau. Ce paramètre a une priorité inférieure à celui de l'utilisateur, s'il en a activé et sélectionné personnellement dans son profil étendu.";
$UseUsersTimezoneTitle = "Utiliser les fuseaux horaires utilisateurs";
$UseUsersTimezoneComment = "Activer la possibilité pour les utilisateurs de sélectionner leur fuseau horaire. Le champ de fuseau horaire doit être rendu visible et modifiable dans les options de profiling du panneau d'administration avant que les utilisateurs ne puissent choisir leur propre fuseau.
$UseUsersTimezoneComment = "Activer la possibilité pour les utilisateurs de sélectionner leur fuseau horaire. Le champ de fuseau horaire doit être rendu visible et modifiable dans les options de profiling du panneau d'administration avant que les utilisateurs ne puissent choisir leur propre fuseau.
Une fois configuré, les utilisateurs pourront voir toutes les heures du portail (heure de remise des travaux, événements, etc) converties dans leur fuseau horaire personnel.";
$FieldTypeTimezone = "Fuseau horaire";
$Timezone = "Fuseaux horaires";
@ -5821,8 +5821,8 @@ $Item = "Élément";
$ConfigureDashboardPlugin = "Configurer le plugin de tableau de bord";
$EditBlocks = "Éditer les blocs";
$Never = "Jamais";
$YourAccountIsActiveYouCanLoginAndCheckYourCourses = "Cher utilisateur,
$YourAccountIsActiveYouCanLoginAndCheckYourCourses = "Cher utilisateur,
Votre compte a été activé. Vous pouvez à présent vous connecter et consulter vos cours.";
$SessionFields = "Champs de session";
$CopyLabelSuffix = "Copie";
@ -5884,7 +5884,7 @@ $CourseSettingsRegisterDirectLink = "Si votre cours est public ou ouvert, utilis
$DirectLink = "Lien direct";
$here = "ici";
$GoAheadAndBrowseOurCourseCatalogXOnceRegisteredYouWillSeeTheCourseHereX = "Révisez notre catalogue de cours %s pour vous inscrire à votre cours préféré. Une fois inscrit(e), votre cours apparaîtra %s, à la place de ce message.";
$HelloXAsYouCanSeeYourCourseListIsEmpty = "Bonjour %s, nous vous souhaitons la bienvenue,<br />
$HelloXAsYouCanSeeYourCourseListIsEmpty = "Bonjour %s, nous vous souhaitons la bienvenue,<br />
Comme vous pouvez le voir, votre liste de cours est vide. C'est parce que vous ne vous êtes pas encore inscrit à un cours!";
$UnsubscribeUsersAlreadyAddedInCourse = "Désinscrire les utilisateurs actuellement inscrits";
$ImportUsers = "Importer des utilisateurs";
@ -5966,11 +5966,11 @@ $ContactInformationHasBeenSent = "L'information de contact a été envoyée. Mer
$EditExtraFieldOptions = "Modifier les options de champs";
$ExerciseDescriptionLabel = "Description";
$UserInactivedSinceX = "Utilisateur inactif depuis %s";
$ContactInformationDescription = "Cher utilisateur,<br />
<br />
Vous êtes sur le point de commencer à utiliser l'une des meilleures plateformes e-learning de logiciel libre du marché. Comme beaucoup d'autres projets de logiciel libre, celui-ci est supporté par une grande communauté d'étudiants, d'enseignants, de développeurs et de créateurs de contenu qui aimeraient pouvoir promouvoir le projet dans les meilleures conditions.<br /><br />
Au travers d'une meilleure connaissance de notre public et de l'un de nos plus importants utilisateurs, vous, qui gèrerez ce système e-learning, nous pourrons nous assurer de faire savoir au plus grand nombre que notre logiciel est utilisé, et nous pourrons vous informer directement sur les événements importants à vos yeux.<br /><br />
En complétant ce formulaire, vous acceptez que l'Association Chamilo ou ses membres puissent vous envoyer des informations par courriel au sujet d'événements importants ou de mises à jours du logiciel ou de la communauté. Ceci aidera la communauté à croître comme une entité organisée au sein de laquelle l'information se propage, au travers d'un respect permanent de votre temps et de votre vie privée.<br /><br />
$ContactInformationDescription = "Cher utilisateur,<br />
<br />
Vous êtes sur le point de commencer à utiliser l'une des meilleures plateformes e-learning de logiciel libre du marché. Comme beaucoup d'autres projets de logiciel libre, celui-ci est supporté par une grande communauté d'étudiants, d'enseignants, de développeurs et de créateurs de contenu qui aimeraient pouvoir promouvoir le projet dans les meilleures conditions.<br /><br />
Au travers d'une meilleure connaissance de notre public et de l'un de nos plus importants utilisateurs, vous, qui gèrerez ce système e-learning, nous pourrons nous assurer de faire savoir au plus grand nombre que notre logiciel est utilisé, et nous pourrons vous informer directement sur les événements importants à vos yeux.<br /><br />
En complétant ce formulaire, vous acceptez que l'Association Chamilo ou ses membres puissent vous envoyer des informations par courriel au sujet d'événements importants ou de mises à jours du logiciel ou de la communauté. Ceci aidera la communauté à croître comme une entité organisée au sein de laquelle l'information se propage, au travers d'un respect permanent de votre temps et de votre vie privée.<br /><br />
Veuillez prendre en considération que vous n'êtes <b>pas obligé</b> de compléter ce formulaire. Si vous désirez rester anonyme, nous perdrons la possibilité de vous offrir les privilèges d'être un administrateur de portail enregistré, mais nous respecterons votre décision. Laissez simplement ce formulaire vide et cliquez sur \"Suivant\". De même, une fois l'envoi de l'information du formulaire ci-dessous confirmé, vous devrez cliquer sur \"Suivant\".";
$CompanyActivity = "Activité de votre entreprise";
$PleaseAllowUsALittleTimeToSubscribeYouToOneOfOurCourses = "Merci de nous donner un moment pour vous inscrire à l'un de nos cours. Si vous pensez avoir été oublié, merci de contacter les administrateurs du site. Vous pouvez généralement trouver leurs informations de contact dans le pied de page.";
@ -6127,7 +6127,7 @@ $SSOServerUnAuthURIComment = "L'adresse de la page qui se charge de la déconnex
$SSOServerProtocolTitle = "Protocole du serveur Single Sign On";
$SSOServerProtocolComment = "Le protocole à préfixer au domaine du serveur Single Sign On (nous recommandons l'usage de https:// si votre serveur le permet, car tout protocole non sécurisé engendre des risques au niveau du mécanisme d'authentification).";
$EnabledWirisTitle = "Éditeur mathématique WIRIS";
$EnabledWirisComment = "Activer l'éditeur mathématique WIRIS. En installant ce plugin, vous obtenez l'éditeur WIRIS et WIRIS CAS.<br/>Cette activation n'est totalement réalisée que si le <a href=\"http://www.wiris.com/es/plugins3/ckeditor/download\">plugin PHP pour CKeditor WIRIS</a> a été préalablement téléchargé et décompressé dans le répertoire de Chamilo main/inc/lib/javascript/ckeditor/plugins/.<br/>
$EnabledWirisComment = "Activer l'éditeur mathématique WIRIS. En installant ce plugin, vous obtenez l'éditeur WIRIS et WIRIS CAS.<br/>Cette activation n'est totalement réalisée que si le <a href=\"http://www.wiris.com/es/plugins3/ckeditor/download\">plugin PHP pour CKeditor WIRIS</a> a été préalablement téléchargé et décompressé dans le répertoire de Chamilo main/inc/lib/javascript/ckeditor/plugins/.<br/>
Cela est nécessaire car Wiris est un logiciel propriétaire et ses services sont de nature <a href=\"http://www.wiris.com/store/who-pays\">commerciale</a>. Pour faire des ajustements pour le plug-in, éditer le fichier configuration.ini ou remplacer son contenu par le fichier configuration.ini.default de Chamilo.";
$FileSavedAs = "Le fichier a été enregistré sous";
$FileExportAs = "Le fichier a été exporté sous";
@ -6152,9 +6152,9 @@ $AverageScore = "Score moyen";
$LastConnexionDate = "Date de dernière connexion";
$ToolVideoconference = "Vidéoconférence";
$BigBlueButtonEnableTitle = "Outil de vidéoconférence BigBlueButton";
$BigBlueButtonEnableComment = "Choisissez si vous désirez activer l'outil de vidéoconférence BigBlueButton. Une fois activé, il apparaît comme un outil de cours additionnel sur toutes les pages d'accueil de cours, et les enseignants peuvent lancer une conférence à tout moment. Les étudiants ne peuvent pas lancer de conférence, seulement en rejoindre.
Si vous n'avez pas de serveur BigBlueButton fonctionnel, veuillez <a target=\"_blank\" href=\"http://bigbluebutton.org/\">en installer un</a> ou vous adresser aux <a target=\"_blank\" href=\"http://www.chamilo.org/en/providers\">fournisseurs officiels de Chamilo</a> pour pouvoir bénéficier de cette fonctionnalité.
BigBlueButton est un logiciel libre et gratuit. Son installation requiert des compétences techniques particulières, ce qui demande un travail considérable et peut résulter coûteux si vous ne disposez pas desdites compétences.
$BigBlueButtonEnableComment = "Choisissez si vous désirez activer l'outil de vidéoconférence BigBlueButton. Une fois activé, il apparaît comme un outil de cours additionnel sur toutes les pages d'accueil de cours, et les enseignants peuvent lancer une conférence à tout moment. Les étudiants ne peuvent pas lancer de conférence, seulement en rejoindre.
Si vous n'avez pas de serveur BigBlueButton fonctionnel, veuillez <a target=\"_blank\" href=\"http://bigbluebutton.org/\">en installer un</a> ou vous adresser aux <a target=\"_blank\" href=\"http://www.chamilo.org/en/providers\">fournisseurs officiels de Chamilo</a> pour pouvoir bénéficier de cette fonctionnalité.
BigBlueButton est un logiciel libre et gratuit. Son installation requiert des compétences techniques particulières, ce qui demande un travail considérable et peut résulter coûteux si vous ne disposez pas desdites compétences.
Dans la logique du développement durable de notre projet, nous vous offrons la possibilité d'installer vous-même la solution ou de vous faire aider par des professionnels à l'expérience démontrée.";
$BigBlueButtonHostTitle = "Adresse du serveur BigBlueButton";
$BigBlueButtonHostComment = "Veuillez indiquer l'adresse du serveur BigBlueButton. Ceci peut être <i>localhost</i>, une adresse IP (par exemple <i>192.168.13.54</i> ou un nom de domaine (par exemple <i>my.video.com</i>).";
@ -6644,7 +6644,7 @@ $DisableEndDate = "Désactiver date de fin";
$ForumCategories = "Catégories de forums";
$Copy = "Copie";
$ArchiveDirCleanup = "Vidange du cache et des fichiers temporaires";
$ArchiveDirCleanupDescr = "Chamilo garde une copie de la plupart des fichiers temporaires qu'il génère (pour les exports, copies et sauvegardes diverses) dans son répertoire app/cache/. Après un certain temps, ces fichiers peuvent s'accumuler et occuper un espace disque assez important et sans intérêt particulier. Cliquez sur le bouton ci-dessous pour vider ce répertoire immédiatement. Idéalement, cette opération devrait être exécutée automatiquement sur base régulière (cron), mais si cela représente une difficulté importante dans votre contexte, vous pouvez visiter cette page de temps en temps pour éliminer tous les fichiers temporaires du répertoire.
$ArchiveDirCleanupDescr = "Chamilo garde une copie de la plupart des fichiers temporaires qu'il génère (pour les exports, copies et sauvegardes diverses) dans son répertoire app/cache/. Après un certain temps, ces fichiers peuvent s'accumuler et occuper un espace disque assez important et sans intérêt particulier. Cliquez sur le bouton ci-dessous pour vider ce répertoire immédiatement. Idéalement, cette opération devrait être exécutée automatiquement sur base régulière (cron), mais si cela représente une difficulté importante dans votre contexte, vous pouvez visiter cette page de temps en temps pour éliminer tous les fichiers temporaires du répertoire.
Cette fonctionnalité nettoie également le cache des thèmes graphiques.";
$ArchiveDirCleanupProceedButton = "Vidanger";
$ArchiveDirCleanupSucceeded = "Le répertoire app/cache/ a été vidangé.";
@ -6662,7 +6662,7 @@ $NewExercises = "Nouveaux exercices";
$MyAverage = "Ma moyenne";
$AllAttempts = "Toutes les tentatives";
$QuestionsToReview = "Questions à revoir";
$QuestionWithNoAnswer = "Questions sans réponses";
$QuestionWithNoAnswer = "Questions sans réponses surlignées en rouge ci-dessous";
$ValidateAnswers = "Finaliser l'exercice";
$ReviewQuestions = "Revoir les questions sélectionnées";
$YouTriedToResolveThisExerciseEarlier = "Vous avez essayé de résoudre cet exercice plus tôt";
@ -6929,7 +6929,7 @@ $DatabaseXWillBeCreated = "La base de donnée %s va être créée";
$ADatabaseWithTheSameNameAlreadyExists = "Une base de donnée du même nom existe déjà. Si vous utilisez cette base, son contenu actuel sera écrasé.";
$UserXCantHaveAccessInTheDatabaseX = "L'utilisateur %s n'a pas accès à la base de donnée %s";
$DatabaseXCantBeCreatedUserXDoestHaveEnoughPermissions = "La base de donnée %s ne peut pas être crée, l'utilisateur %s n'a pas suffisamment de permissions.";
$CopyOnlySessionItems = "Copier seulement les élémenents de la session";
$CopyOnlySessionItems = "Copier seulement les éléments de la session";
$FirstLetterCourseTitle = "Première lettre (title)";
$NumberOfPublishedExercises = "# d'exerices publiés";
$NumberOfPublishedLps = "# de parcours publiés";
@ -6998,10 +6998,10 @@ $ShibbolethMainActivateTitle = "<h3>Configuration de l'authentification Shibbole
$ShibbolethMainActivateComment = "<p>Vous devez, en premier lieu, configurer Shibboleth pour votre serveur web. Pour le configurer pour Chamilo.</p><h5>éditez le fichier main/auth/shibboleth/config/aai.class.php</h5><p>Modifiez les valeurs de l'objet &#36;result avec les nom des attributs retourné par votre serveur Shibboleth.</p>Les valeurs à modifier sont<ul><li>&#36;result-&gt;unique_id = 'mail';</li><li>&#36;result-&gt;firstname = 'cn';</li><li>&#36;result-&gt;lastname = 'uid';</li><li>&#36;result-&gt;email = 'mail';</li><li>&#36;result-&gt;language = '-';</li><li>&#36;result-&gt;gender = '-';</li><li>&#36;result-&gt;address = '-';</li><li>&#36;result-&gt;staff_category = '-';</li><li>&#36;result-&gt;home_organization_type = '-'; </li><li>&#36;result-&gt;home_organization = '-';</li><li>&#36;result-&gt;affiliation = '-';</li><li>&#36;result-&gt;persistent_id = '-';</li><li>...</li></ul><br/>Vous trouverez dans les <a href='settings.php?category=Shibboleth'>Plugin</a> un bouton 'Login Shibboleth', paramétrable, qui s'ajoutera sur la page d'accueil de votre campus Chamilo.";
$LdapDescriptionTitle = "Identification LDAP";
$FacebookMainActivateTitle = "Configuration de l'authentification via Facebook";
$FacebookMainActivateComment = "<p><h5>Créez votre application Facebook</h5>Vous devez, d'abord, créer une application Facebook (cf. <a href='https://developers.facebook.com/apps'>https://developers.facebook.com/apps</a>) avec votre compte Facebook.<br/>
<h5>Éditez le fichier app/config/configuration.php</h5>Et décommentez la ligne &#36;_configuration['facebook_auth'] = 1;<br/>
<h5>Éditez le fichier app/config/auth.conf.php<br/></h5>Entrez les valeurs 'appId' et 'secret', fournies par Facebook, pour la variable &#36;facebook_config.<br/>
<h5>Éditez le fichier main/inc/conf/auth.conf.php</h5>Et décommentez les lignes &#36;facebook_config<br/>
$FacebookMainActivateComment = "<p><h5>Créez votre application Facebook</h5>Vous devez, d'abord, créer une application Facebook (cf. <a href='https://developers.facebook.com/apps'>https://developers.facebook.com/apps</a>) avec votre compte Facebook.<br/>
<h5>Éditez le fichier app/config/configuration.php</h5>Et décommentez la ligne &#36;_configuration['facebook_auth'] = 1;<br/>
<h5>Éditez le fichier app/config/auth.conf.php<br/></h5>Entrez les valeurs 'appId' et 'secret', fournies par Facebook, pour la variable &#36;facebook_config.<br/>
<h5>Éditez le fichier main/inc/conf/auth.conf.php</h5>Et décommentez les lignes &#36;facebook_config<br/>
<h5>Activez le plugin Facebook de Chamilo<br/></h5>Et placez-le dans la région login_top ou login_bottom.<br/>Vous pouvez changer l'image de connexion dans les options de configuration du plugin.</p>";
$AnnouncementForGroup = "Annonce pour un groupe";
$AllGroups = "Tous les groupes";
@ -7435,7 +7435,7 @@ $CronRemindCourseExpirationFrequencyComment = "Nombre de jours avant la fin du c
$CronCourseFinishedActivateText = "Cron de fin du cours";
$CronCourseFinishedActivateComment = "Activez pour envoyer un courriel lorsque le cours est terminé";
$MailCronCourseFinishedSubject = "Fin du cours: %s";
$MailCronCourseFinishedBody = "Cher/Chère %s,<br/>Merci d'avoir participé au cours %s. Nous espérons que vous avez acquis de nouvelles connaissances et que vous avez pleinement profité du cours. Vous pouvez réviser votre progrès et votre développement personnel au sein du cours dans la section Mon Suivi.<br/>Cordialement,<br/>
$MailCronCourseFinishedBody = "Cher/Chère %s,<br/>Merci d'avoir participé au cours %s. Nous espérons que vous avez acquis de nouvelles connaissances et que vous avez pleinement profité du cours. Vous pouvez réviser votre progrès et votre développement personnel au sein du cours dans la section Mon Suivi.<br/>Cordialement,<br/>
%s";
$GenerateDefaultContent = "Générer du contenu par défaut";
$ThanksForYourSubscription = "Merci pour votre inscription";
@ -7524,7 +7524,7 @@ $Convert = "Convertir";
$PortalLimitType = "Type de limite du portail";
$PortalName = "Nom du portail";
$BestScore = "Meilleur score";
$AreYouSureToDeleteJS = "Êtes-vous certain de vouloir supprimer";
$AreYouSureToDeleteJS = "Êtes-vous certain de vouloir supprimer ?";
$ConversionToSameFileFormat = "Conversion au format original bloquée. Veuillez choisir un autre format.";
$FileFormatNotSupported = "Format de fichier non supporté.";
$FileConvertedFromXToY = "Fichier converti de %s à %s";
@ -7817,7 +7817,7 @@ $TooManyRepetitions = "Trop de répétitions";
$YourPasswordContainsSequences = "Votre mot de passe contient des séquences";
$PasswordVeryWeak = "Très faible";
$UserXHasBeenAssignedToBoss = "L'apprenant %s vous a été assigné";
$UserXHasBeenAssignedToBossWithUrlX = "Vous avez été assigné comme tuteur pour l'apprenant %s.<br/>
$UserXHasBeenAssignedToBossWithUrlX = "Vous avez été assigné comme tuteur pour l'apprenant %s.<br/>
Vous pouvez accéder à sa fiche ici: %s";
$ShortName = "Nom court";
$Portal = "Portail";
@ -7973,13 +7973,13 @@ $AddHrmToUser = "Ajouter Directeur des Ressources Humaines";
$HrmAssignedUsersCourseList = "Liste des cours des utilisateurs assignés au directeur des ressources humaines";
$GoToSurvey = "Aller à l'enquête";
$NotificationCertificateSubject = "Avis d'obtention de certificat";
$NotificationCertificateTemplate = "Cher/Chère ((user_first_name)), vous avez terminé ((course_title)). Votre note finale est de ((score)). Merci de laisser passer quelques jours avant l'apparition de le visualiser sur notre système. Nous espérons que vous en ayez pleinement profité et que nous vous reverrons bientôt dans l'un de vos prochains cours. Si nous pouvons vous être utile d'une quelconque manière, n'hésitez pas à nous contacter.
$NotificationCertificateTemplate = "Cher/Chère ((user_first_name)), vous avez terminé ((course_title)). Votre note finale est de ((score)). Merci de laisser passer quelques jours avant l'apparition de le visualiser sur notre système. Nous espérons que vous en ayez pleinement profité et que nous vous reverrons bientôt dans l'un de vos prochains cours. Si nous pouvons vous être utile d'une quelconque manière, n'hésitez pas à nous contacter.
Cordialement, ((author_first_name)) ((author_last_name)), ((portal_name))";
$SendCertificateNotifications = "Envoyer les avis de certificat à tous les utilisateurs";
$MailSubjectForwardShort = "Tr";
$ForwardedMessage = "Message transféré";
$ForwardMessage = "Transférer message";
$MyCoursePageCategoryIntroduction = "Vous trouverez ci-dessous la liste des catégories de cours.
$MyCoursePageCategoryIntroduction = "Vous trouverez ci-dessous la liste des catégories de cours.
Cliquez sur l'une pour voir la liste des cours qu'elle contient.";
$FeatureDisabledByAdministrator = "Fonctionnalité désactivée par l'administrateur";
$SubscribeUsersToLpCategory = "Inscrire les utilisateurs à la catégorie";
@ -8084,10 +8084,10 @@ $RedirectToTheDocumentList = "Rediriger vers la liste des documents";
$TheExerciseAutoLaunchSettingIsONStudentsWillBeRedirectToTheExerciseList = "La fonctionnalité d'auto-démarrage des exercices est activée. Les apprenants seront automatiquement redirigés vers la liste des exercices.";
$PostedExpirationDate = "Date limite affichée d'envoi du travail (visible par l'apprenant)";
$BossAlertMsgSentToUserXTitle = "Message de suivi concernant l'apprenant %s";
$BossAlertUserXSentMessageToUserYWithLinkZ = "Bonjour,<br/><br/>
L'utilisateur %s a envoyé un message de suivi concernant l'apprenant %s.<br/><br/>
$BossAlertUserXSentMessageToUserYWithLinkZ = "Bonjour,<br/><br/>
L'utilisateur %s a envoyé un message de suivi concernant l'apprenant %s.<br/><br/>
Le message est visible sur %s";
$include_services = "Inclure les services";
$culqi_enable = "Activé culqi";
@ -8190,8 +8190,8 @@ $SubSkill = "Sous-compétence";
$AddMultipleUsersToCalendar = "Ajouter plusieurs utilisateurs au calendrier";
$UpdateCalendar = "Mettre le calendrier à jour";
$ControlPoint = "Point de contrôle";
$MessageQuestionCertainty = "Suivez les instructions ci-dessous pour visualiser vos résultats pour le test %s:<br /><br />
1. Connectez-vous à la plateforme (utilisateur/mot de passe) sur: %s<br />
$MessageQuestionCertainty = "Suivez les instructions ci-dessous pour visualiser vos résultats pour le test %s:<br /><br />
1. Connectez-vous à la plateforme (utilisateur/mot de passe) sur: %s<br />
2. Suivez le lien suivant: %s<br />";
$SessionMinDuration = "Durée minimum de session";
$CanNotTranslate = "Impossible de traduire";
@ -8208,7 +8208,7 @@ $ScoreModel = "Modèle d'évaluation";
$SyncDatabaseWithSchema = "Synchroniser la base de données avec le schéma";
$SkillRelCourses = "Associations cours-compétences";
$UserRequestWaitingForAction = "Un(e) utilisateur/trice attend une action de votre part à propos d'une demande au sujet de ses données personnelles";
$TheUserXIsWaitingForAnActionGoHereX = "L'utilisateur/trice %s attend une action au sujet de sa demande de données personnelles.\n\n
$TheUserXIsWaitingForAnActionGoHereX = "L'utilisateur/trice %s attend une action au sujet de sa demande de données personnelles.\n\n
Pour gérer les demandes de données personnelles, suivez ce lien: %s";
$RequestType = "Type de demande";
$DeleteAccount = "Supprimer le compte";
@ -8217,8 +8217,8 @@ $RemoveTerms = "Supprimer l'accord légal";
$InformationRightToBeForgottenLinkX = "Vous trouverez plus d'information au sujet du droit à l'oubli des utilisateurs via le lien suivant: %s";
$ExplanationDeleteLegal = "Merci de bien vouloir nous donner une brève explication sur la raison de votre demande de retrait des permissions que vous nous aviez précédemment donné afin que nous puissions procéder à la modification de la meilleure manière possible.";
$ExplanationDeleteAccount = "Merci de bien vouloir nous donner une brève explication sur la raison de votre demande de suppression de votre compte, afin que nous puissions y procéder de la meilleure manière possible.";
$WhyYouWantToDeleteYourLegalAgreement = "Ci-dessous, vous pouvez faire une demande de retrait de votre accord avec nos conditions d'utilisation ou de suppression de votre compte.<br />
Dans le cas de l'accord avec nos conditions, une fois annulé, vous aurez à accepter à nouveau ces conditions lors de votre prochaine connexion afin d'accéder à notre plateforme, car il ne nous est pas possible de vous donner accès à une expérience personnalisée sans en même temps traiter vos données personnelles.<br />
$WhyYouWantToDeleteYourLegalAgreement = "Ci-dessous, vous pouvez faire une demande de retrait de votre accord avec nos conditions d'utilisation ou de suppression de votre compte.<br />
Dans le cas de l'accord avec nos conditions, une fois annulé, vous aurez à accepter à nouveau ces conditions lors de votre prochaine connexion afin d'accéder à notre plateforme, car il ne nous est pas possible de vous donner accès à une expérience personnalisée sans en même temps traiter vos données personnelles.<br />
Dans le cas d'une demande de suppression de votre compte, celui-ci sera effectivement supprimé, incluant toutes vos souscriptions à des cours et toute l'information liée à votre compte. Veuillez sélectionner l'option correspondante avec soin. Dans les deux cas, l'un de nos administrateurs révisera votre demande avant de l'exécuter afin d'éviter quelque malentendu que ce soit et la perte définitive de vos données si ce n'était pas voulu.";
$PersonalDataPrivacy = "Protection des données personnelles";
$RequestForAccountDeletion = "Demande de suppression de compte";
@ -8246,9 +8246,9 @@ $ProgressObtainedFromLPProgressAndTestsAverage = "Note: Le progrès ci-dessus es
$CreateNewSurveyDoodle = "Créer une nouvelle enquête de type Doodle";
$RemoveMultiplicateQuestions = "Supprimer les questions démultipliées";
$MultiplicateQuestions = "Multiplier les questions";
$QuestionTags = "Vous pouvez utiliser les balises {{class_name}} et {{student_full_name}} dans la question afin de multiplier les questions.
Sur la page de liste d'enquêtes dans la colonne d'action, vous avez un bouton pour multiplier les questions qui recherchera la balise {{class_name}} et dupliquera la question pour toutes les classes inscrites au cours et la renommera avec le nom de la classe.
Il ajoutera également un séparateur de page pour créer une nouvelle page pour chaque classe.
$QuestionTags = "Vous pouvez utiliser les balises {{class_name}} et {{student_full_name}} dans la question afin de multiplier les questions.
Sur la page de liste d'enquêtes dans la colonne d'action, vous avez un bouton pour multiplier les questions qui recherchera la balise {{class_name}} et dupliquera la question pour toutes les classes inscrites au cours et la renommera avec le nom de la classe.
Il ajoutera également un séparateur de page pour créer une nouvelle page pour chaque classe.
Ensuite, il recherchera la balise {{student_full_name}} et dupliquera la question pour tous les étudiants de la classe (pour chaque classe) et la renommera avec le nom complet de l'étudiant.";
$CreateMeeting = "Créer un sondage de réunion";
$QuestionForNextClass = "Questions pour la classe suivante";
@ -8488,8 +8488,8 @@ $CouldNotReadFileLines = "Impossible de lire les lignes du fichier.";
$CertificatesSessions = "Certificats en sessions";
$SessionFilterReport = "Filtrer les certificats dans les sessions";
$UpdateUserListXMLCSV = "Mise à jour d'utilisateurs";
$DonateToTheProject = "Chamilo est un projet Open Source et ce portail est offert gratuitement à la communauté par l'Association Chamilo, dont l'objectif est d'améliorer la disponibilité d'une éducation de qualité partout dans le monde.<br /><br />
Développer Chamilo et fournir ce service de portail gratuit sont néanmoins des tâches coûteuses, et un peu d'aide de votre part permettrait de soutenir nos efforts et de faire progresser le projet Chamilo plus rapidement sur le long terme.<br /><br />
$DonateToTheProject = "Chamilo est un projet Open Source et ce portail est offert gratuitement à la communauté par l'Association Chamilo, dont l'objectif est d'améliorer la disponibilité d'une éducation de qualité partout dans le monde.<br /><br />
Développer Chamilo et fournir ce service de portail gratuit sont néanmoins des tâches coûteuses, et un peu d'aide de votre part permettrait de soutenir nos efforts et de faire progresser le projet Chamilo plus rapidement sur le long terme.<br /><br />
Créer un cours sur ce portail est, par ailleurs, l'un des éléments qui consomme le plus de ressources. Merci de considérer le fait de contribuer de manière symbolique au projet et nous aider à maintenir ce service gratuit pour tous en nous faisant don de quelques euros avant de créer ce cours!";
$MyStudentPublications = "Mes travaux";
$AddToEditor = "Ajouter à l'éditeur";
@ -8652,4 +8652,45 @@ $ShowScoreEveryAttemptShowAnswersLastAttemptNoFeedback = "Montrer le score, le c
$AddGradebookComment = "Commentaire";
$LatestLoginInAnyCourse = "Dernier accès à un cours";
$The = "Le";
?>
$MultiplicateQuestionsByClass = "Multiplier les questions par classe";
$MultiplicateQuestionsByUser = "Multiplier les questions par utilisateur";
$QuestionForNextUser = "Questions concernant l'apprenant suivant";
$CourseCodeToEnteredCapitalLettersToConfirmDeletionX = "Code du cours à saisir en majuscules pour confirmer la suppression : %s";
$BadgeXTitle = "Badge : %s";
$PortfolioCommentFromXUser = "Commenté par %s";
$PortfolioItemFromXUser = "Item de Portfolio de %s";
$CopyToMyPortfolio = "Copier dans mon portfolio";
$CopyToStudentPortfolio = "Copier dans le portfolio de l'étudiant";
$OriginallyPublishedAsXTitleByYUser = "Publier à l'origine comme %s par %s";
$OriginallyCommentedByXUserInYItem = "Commenté à l'origine par %s dans %s";
$PortfolioItemAddedToStudents = "Item rajouter dans le portfolio de l'apprenant";
$MarkCommentAsImportant = "Marquer le commentaire comme important";
$UnmarkCommentAsImportant = "Enlever la marque d'importance sur le commentaire";
$CommentMarkedAsImportant = "Item de portfolio marqué comme important";
$SelectLearnerPortfolio = "Choisir le portfolio d'un apprenant";
$SeeMyPortfolio = "Voir mon portfolio dans ce cours";
$PortfolioDetails = "Détails du portfolio";
$PortfolioItemTitle = "Titre de l'item";
$CreationDateXDate = "Date de création : %s";
$UpdateDateXDate = "Date de mise à jour : %s";
$CategoryXName = "Catégorie : %s";
$DateXDate = "Date : %s";
$PortfolioItemTitleXName = "Titre de l'item : %s";
$NoItemsInYourPortfolio = "Aucun item dans votre portfolio";
$YouHaveNotCommented = "Vous n'avez pas commenté";
$PortfolioItems = "Items de portfolio";
$PortfolioComments = "Commentaires de portfolio";
$PortfolioCommentsMade = "Commentaires réalisés";
$QualifyThisPortfolioItem = "Noter cet item";
$PortfolioItemGraded = "L'item de portfolio a été noté";
$ContextForCommentToBeGrade = "Context pour le commentaire à noter";
$QualifyThisPortfolioComment = "Noter ce commentaire";
$PortfolioCommentGraded = "Le commentaire du portfolio a été noté";
$QualifyPortfolioItems = "Noter les items";
$QualifyPortfolioComments = "Évaluer les commentaires";
$HideCorrectAnsweredQuestions = "Cacher les questions qui ont eu une réponse correcte";
$TheSettingXWillChangeToX = "Le paramètre \"%s\" sera modifié avec \"%s\"";
$VerificationOfAnsweredQuestions = "Vérification des réponses aux questions";
$StudentPublicationToCorrect = "Travaux d'étudiant à corriger";
$StudentPublicationCorrectionWarning = "Vous trouverez ci-dessous tous les travaux qui ont été soumis par des étudiants dans l'un de vos cours (cela peut être dans le cours de base ou dans un cours en session). Vous pouvez filtrer la liste en sélectionnant un cours spécifique ou un statut de travail.";
?>

@ -619,7 +619,7 @@ $Stats = "Estadísticas";
$UplPage = "Enviar una página y enlazarla a la principal";
$LinkSite = "Añadir un enlace web en la página principal";
$HasDel = "ha sido suprimido";
$ByDel = "Si suprime el sitio web de este curso, suprimirá todos los documentos que contiene y todos sus miembros dejarán de estar inscritos en el mismo. <p>¿ Está seguro de querer suprimir este curso ?";
$ByDel = "Si suprime el sitio web de este curso, suprimirá todos los documentos que contiene y todos sus miembros dejarán de estar inscritos en el mismo.";
$Y = "SI";
$N = "NO";
$DepartmentUrl = "URL del departamento";
@ -6679,7 +6679,7 @@ $NewExercises = "Nuevo ejercicio";
$MyAverage = "Mi promedio";
$AllAttempts = "Todos los intentos";
$QuestionsToReview = "Preguntas que desea comprobar";
$QuestionWithNoAnswer = "Preguntas sin responder";
$QuestionWithNoAnswer = "Preguntas sin respuesta resaltadas en rojo a continuación";
$ValidateAnswers = "Validar respuestas";
$ReviewQuestions = "Revisar las preguntas seleccionadas";
$YouTriedToResolveThisExerciseEarlier = "Ya intentó resolver este ejercicio anteriormente";
@ -7607,7 +7607,7 @@ $Convert = "Convertir";
$PortalLimitType = "Tipo de límite del portal";
$PortalName = "Nombre del portal";
$BestScore = "Mejor calificación";
$AreYouSureToDeleteJS = "Está seguro de eliminar";
$AreYouSureToDeleteJS = "¿Está seguro de eliminar?";
$ConversionToSameFileFormat = "Conversión al mismo formato de archivo. Por favor, selecciones otro.";
$FileFormatNotSupported = "Formato de archivo no soportado.";
$FileConvertedFromXToY = "Archivo convertido de %s a %s";
@ -8748,4 +8748,45 @@ $ShowScoreEveryAttemptShowAnswersLastAttemptNoFeedback = "Mostrar el resultado a
$AddGradebookComment = "Comentario";
$LatestLoginInAnyCourse = "Último acceso en un curso";
$The = "El";
$MultiplicateQuestionsByClass = "Multiplicar las preguntas por clase";
$MultiplicateQuestionsByUser = "Multiplicar las preguntas por usuario";
$QuestionForNextUser = "Preguntas sobre el usuario siguiente";
$CourseCodeToEnteredCapitalLettersToConfirmDeletionX = "El código del curso que debe ingresar en mayúsculas para confirmar la eliminación: %s";
$BadgeXTitle = "Insignia: %s";
$PortfolioCommentFromXUser = "Comentario de %s";
$PortfolioItemFromXUser = "Artículo del portafolio de %s";
$CopyToMyPortfolio = "Copiar a mi portafolio";
$CopyToStudentPortfolio = "Copiar al portafolio del estudiante";
$OriginallyPublishedAsXTitleByYUser = "Originalmente publicado como \"%s\" por %s";
$OriginallyCommentedByXUserInYItem = "Originalmente comentado por %s en \"%s\"";
$PortfolioItemAddedToStudents = "Artículo agregado al portafolio de los estudiantes";
$MarkCommentAsImportant = "Marcar comentario como importante";
$UnmarkCommentAsImportant = "Desmarcar comentario como importante";
$CommentMarkedAsImportant = "Cometario marcado como importante";
$SelectLearnerPortfolio = "Seleccionar un portafolio de estudiante";
$SeeMyPortfolio = "Ver mi portafolio en este curso";
$PortfolioDetails = "Detalles del portafolio";
$PortfolioItemTitle = "Título del artículo";
$CreationDateXDate = "Fecha de creación: %s";
$UpdateDateXDate = "Fecha de actualización: %s";
$CategoryXName = "Categoría: %s";
$DateXDate = "Fecha: %s";
$PortfolioItemTitleXName = "Título del artículo: %s";
$NoItemsInYourPortfolio = "No hay artículos en su portafolio";
$YouHaveNotCommented = "Usted no ha comentado";
$PortfolioItems = "Artículos del portafolio";
$PortfolioComments = "Comentarios en portafolio";
$PortfolioCommentsMade = "Comentarios hechos";
$QualifyThisPortfolioItem = "Calificar este artículo";
$PortfolioItemGraded = "El artículo del portafolio fue calificado";
$ContextForCommentToBeGrade = "Contexto para el comentario a ser calificado";
$QualifyThisPortfolioComment = "Calificar este comentario";
$PortfolioCommentGraded = "El comentario en el portafolio fue calificado";
$QualifyPortfolioItems = "Calificar artículos";
$QualifyPortfolioComments = "Calificar comentarios";
$HideCorrectAnsweredQuestions = "Esconder las preguntas con respuestas correctas";
$TheSettingXWillChangeToX = "La opción \"%s\" será modificada con el valor \"%s\"";
$VerificationOfAnsweredQuestions = "Verificación de preguntas respondidas";
$StudentPublicationToCorrect = "Tareas de estudiante para ser corregidas";
$StudentPublicationCorrectionWarning = "A continuación encontrará todos los trabajos que han enviado los alumnos en uno de sus cursos (puede ser en el curso base o en un curso en una sesión). Puede filtrar la lista seleccionando un curso específico o un estado de tarea.";
?>

@ -2343,7 +2343,6 @@ class learnpath
$now = time();
if (Database::num_rows($rs) > 0) {
$row = Database::fetch_array($rs, 'ASSOC');
if (!empty($row['category_id'])) {
$category = self::getCategory($row['category_id']);
if (self::categoryIsVisibleForStudent($category, api_get_user_entity($student_id)) === false) {
@ -2548,7 +2547,7 @@ class learnpath
*/
public function getProgressBar($mode = null)
{
list($percentage, $text_add) = $this->get_progress_bar_text($mode);
[$percentage, $text_add] = $this->get_progress_bar_text($mode);
return self::get_progress_bar($percentage, $text_add);
}
@ -3577,7 +3576,7 @@ class learnpath
$lp_item_params = $row['liparams'];
if (empty($lp_item_params) && strpos($lp_item_path, '?') !== false) {
list($lp_item_path, $lp_item_params) = explode('?', $lp_item_path);
[$lp_item_path, $lp_item_params] = explode('?', $lp_item_path);
}
$sys_course_path = api_get_path(SYS_COURSE_PATH).api_get_course_path();
if ($type === 'http') {
@ -3640,23 +3639,27 @@ class learnpath
$file = 'lp_content.php?type=dir&'.api_get_cidreq();
break;
case 'link':
if (Link::is_youtube_link($file)) {
$src = Link::get_youtube_video_id($file);
$file = api_get_path(WEB_CODE_PATH).'lp/embed.php?type=youtube&source='.$src;
} elseif (Link::isVimeoLink($file)) {
$src = Link::getVimeoLinkId($file);
$file = api_get_path(WEB_CODE_PATH).'lp/embed.php?type=vimeo&source='.$src;
} else {
// If the current site is HTTPS and the link is
// HTTP, browsers will refuse opening the link
$urlId = api_get_current_access_url_id();
$url = api_get_access_url($urlId, false);
$protocol = substr($url['url'], 0, 5);
if ($protocol === 'https') {
$linkProtocol = substr($file, 0, 5);
if ($linkProtocol === 'http:') {
//this is the special intervention case
$file = api_get_path(WEB_CODE_PATH).'lp/embed.php?type=nonhttps&source='.urlencode($file);
if (!empty($file)) {
if (Link::is_youtube_link($file)) {
$src = Link::get_youtube_video_id($file);
$file = api_get_path(WEB_CODE_PATH).'lp/embed.php?type=youtube&source='.$src;
} elseif (Link::isVimeoLink($file)) {
$src = Link::getVimeoLinkId($file);
$file = api_get_path(WEB_CODE_PATH).'lp/embed.php?type=vimeo&source='.$src;
} else {
// If the current site is HTTPS and the link is
// HTTP, browsers will refuse opening the link
$urlId = api_get_current_access_url_id();
$url = api_get_access_url($urlId, false);
$protocol = substr($url['url'], 0, 5);
if ($protocol === 'https') {
$linkProtocol = substr($file, 0, 5);
if ($linkProtocol === 'http:') {
//this is the special intervention case
$file = api_get_path(
WEB_CODE_PATH
).'lp/embed.php?type=nonhttps&source='.urlencode($file);
}
}
}
}
@ -3755,7 +3758,7 @@ class learnpath
if (!is_file(realpath($sys_course_path.'/scorm/'.$lp_path.'/'.$lp_item_path))) {
// if file not found.
$decoded = html_entity_decode($lp_item_path);
list($decoded) = explode('?', $decoded);
[$decoded] = explode('?', $decoded);
if (!is_file(realpath($sys_course_path.'/scorm/'.$lp_path.'/'.$decoded))) {
$file = self::rl_get_resource_link_for_learnpath(
$course_id,
@ -4394,6 +4397,10 @@ class learnpath
*/
public static function toggle_visibility($lp_id, $set_visibility = 1)
{
if (empty($lp_id)) {
return false;
}
$action = 'visible';
if ($set_visibility != 1) {
$action = 'invisible';
@ -4416,11 +4423,6 @@ class learnpath
* @param int $id
* @param int $visibility
*
* @throws \Doctrine\ORM\NonUniqueResultException
* @throws \Doctrine\ORM\ORMException
* @throws \Doctrine\ORM\OptimisticLockException
* @throws \Doctrine\ORM\TransactionRequiredException
*
* @return bool
*/
public static function toggleCategoryVisibility($id, $visibility = 1)
@ -4452,6 +4454,9 @@ class learnpath
*/
public static function toggle_publish($lp_id, $set_visibility = 'v')
{
if (empty($lp_id)) {
return false;
}
$course_id = api_get_course_int_id();
$tbl_lp = Database::get_course_table(TABLE_LP_MAIN);
$lp_id = (int) $lp_id;
@ -4461,10 +4466,10 @@ class learnpath
if (Database::num_rows($result)) {
$row = Database::fetch_array($result);
$name = Database::escape_string($row['name']);
if ($set_visibility == 'i') {
if ($set_visibility === 'i') {
$v = 0;
}
if ($set_visibility == 'v') {
if ($set_visibility === 'v') {
$v = 1;
}
@ -4475,55 +4480,112 @@ class learnpath
$link = 'lp/lp_controller.php?action=view&lp_id='.$lp_id.'&id_session='.$session_id;
$oldLink = 'newscorm/lp_controller.php?action=view&lp_id='.$lp_id.'&id_session='.$session_id;
$extraLpCondition = '';
$extraLink = '';
if (!empty($session_id)) {
$extraLink = 'lp/lp_controller.php?action=view&lp_id='.$lp_id.'&id_session=0';
$extraLpCondition = " OR (link = '$link' AND session_id = $session_id ) ";
}
$sql = "SELECT * FROM $tbl_tool
WHERE
c_id = $course_id AND
(link = '$link' OR link = '$oldLink') AND
(link = '$link' OR link = '$oldLink' $extraLpCondition ) AND
image = 'scormbuilder.gif' AND
(
link LIKE '$link%' OR
link LIKE '$oldLink%'
$extraLpCondition
)
$session_condition
";
$result = Database::query($sql);
$num = Database::num_rows($result);
if ($set_visibility == 'i' && $num > 0) {
$sql = "DELETE FROM $tbl_tool
WHERE
c_id = $course_id AND
(link = '$link' OR link = '$oldLink') AND
image='scormbuilder.gif'
$session_condition";
Database::query($sql);
} elseif ($set_visibility == 'v' && $num == 0) {
$sql = "INSERT INTO $tbl_tool (category, c_id, name, link, image, visibility, admin, address, added_tool, session_id) VALUES
('authoring', $course_id, '$name', '$link', 'scormbuilder.gif', '$v', '0','pastillegris.gif', 0, $session_id)";
Database::query($sql);
$insertId = Database::insert_id();
if ($insertId) {
$sql = "UPDATE $tbl_tool SET id = iid WHERE iid = $insertId";
$resultTool = Database::fetch_array($result, 'ASSOC');
if ($set_visibility === 'i') {
if ($num > 0) {
$sql = "DELETE FROM $tbl_tool
WHERE
c_id = $course_id AND
(link = '$link' OR link = '$oldLink') AND
image='scormbuilder.gif'
$session_condition";
Database::query($sql);
}
// Disables the base course link inside a session.
if (!empty($session_id) && 0 === (int) $row['session_id']) {
$sql = "SELECT iid FROM $tbl_tool
WHERE
c_id = $course_id AND
(link = '$extraLink') AND
image = 'scormbuilder.gif' AND
session_id = $session_id
";
$resultBaseLp = Database::query($sql);
if (Database::num_rows($resultBaseLp)) {
$resultBaseLpRow = Database::fetch_array($resultBaseLp);
$id = $resultBaseLpRow['iid'];
/*$sql = "UPDATE $tbl_tool
SET visibility = 0
WHERE iid = $id ";
Database::query($sql);*/
$sql = "DELETE FROM $tbl_tool
WHERE iid = $id";
Database::query($sql);
} else {
/*$params = [
'category' => 'authoring',
'c_id' => $course_id,
'name' => $name,
'link' => $link,
'image' => 'scormbuilder.gif',
'visibility' => '0',
'admin' => '0',
'address' => 'pastillegris.gif',
'added_tool' => '0',
'session_id' => $session_id,
];
$insertId = Database::insert($tbl_tool, $params);
if ($insertId) {
$sql = "UPDATE $tbl_tool SET id = iid WHERE iid = $insertId";
Database::query($sql);
}*/
}
}
}
if ($set_visibility === 'v') {
if ($num == 0) {
$sql = "INSERT INTO $tbl_tool (category, c_id, name, link, image, visibility, admin, address, added_tool, session_id)
VALUES ('authoring', $course_id, '$name', '$link', 'scormbuilder.gif', '$v', '0','pastillegris.gif', 0, $session_id)";
Database::query($sql);
$insertId = Database::insert_id();
if ($insertId) {
$sql = "UPDATE $tbl_tool SET id = iid WHERE iid = $insertId";
Database::query($sql);
}
}
if ($num > 0) {
$id = $resultTool['iid'];
$sql = "UPDATE $tbl_tool SET
c_id = $course_id,
name = '$name',
link = '$link',
image = 'scormbuilder.gif',
visibility = '$v',
admin = '0',
address = 'pastillegris.gif',
added_tool = 0,
session_id = $session_id
WHERE
c_id = ".$course_id." AND
iid = $id
";
Database::query($sql);
}
} elseif ($set_visibility == 'v' && $num > 0) {
$sql = "UPDATE $tbl_tool SET
c_id = $course_id,
name = '$name',
link = '$link',
image = 'scormbuilder.gif',
visibility = '$v',
admin = '0',
address = 'pastillegris.gif',
added_tool = 0,
session_id = $session_id
WHERE
c_id = ".$course_id." AND
(link = '$link' OR link = '$oldLink') AND
image='scormbuilder.gif'
$session_condition
";
Database::query($sql);
}
}
@ -4537,11 +4599,6 @@ class learnpath
* @param int $id
* @param int $setVisibility
*
* @throws \Doctrine\ORM\NonUniqueResultException
* @throws \Doctrine\ORM\ORMException
* @throws \Doctrine\ORM\OptimisticLockException
* @throws \Doctrine\ORM\TransactionRequiredException
*
* @return bool
*/
public static function toggleCategoryPublish($id, $setVisibility = 1)
@ -4947,7 +5004,7 @@ class learnpath
if (!api_is_invitee()) {
// Save progress.
list($progress) = $this->get_progress_bar_text('%');
[$progress] = $this->get_progress_bar_text('%');
$scoreAsProgressSetting = api_get_configuration_value('lp_score_as_progress_enable');
$scoreAsProgress = $this->getUseScoreAsProgress();
if ($scoreAsProgress && $scoreAsProgressSetting && (null === $score || empty($score) || -1 == $score)) {
@ -12076,9 +12133,7 @@ EOD;
$cb->set_tools_to_build(['learnpaths']);
//Setting elements that will be copied
$cb->set_tools_specific_id_list(
['learnpaths' => [$this->lp_id]]
);
$cb->set_tools_specific_id_list(['learnpaths' => [$this->lp_id]]);
$course = $cb->build();
@ -12460,18 +12515,22 @@ EOD;
$cats = [get_lang('SelectACategory')];
}
$checkSession = false;
$sessionId = api_get_session_id();
$avoidCategoryInSession = false;
if (empty($sessionId)) {
$avoidCategoryInSession = true;
}
/*$checkSession = false;
if (api_get_configuration_value('allow_session_lp_category')) {
$checkSession = true;
}
}*/
if (!empty($items)) {
foreach ($items as $cat) {
$categoryId = $cat->getId();
if ($checkSession) {
if ($avoidCategoryInSession) {
$inSession = self::getCategorySessionId($categoryId);
if ($inSession != $sessionId) {
if (!empty($inSession)) {
continue;
}
}
@ -13259,10 +13318,10 @@ EOD;
return $main_dir_path.'exercise/overview.php?'.$extraParams.'&'
.http_build_query([
'lp_init' => 1,
'learnpath_item_view_id' => $learnpathItemViewId,
'learnpath_id' => $learningPathId,
'learnpath_item_id' => $id_in_path,
'exerciseId' => $id,
'learnpath_item_view_id' => (int) $learnpathItemViewId,
'learnpath_id' => (int) $learningPathId,
'learnpath_item_id' => (int) $id_in_path,
'exerciseId' => (int) $id,
]);
case TOOL_HOTPOTATOES: //lowercase because of strtolower above
$TBL_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
@ -13320,13 +13379,23 @@ EOD;
Session::write('openmethod', $openmethod);
Session::write('officedoc', $officedoc);
// Same validation as in document/download.php
$isVisible = DocumentManager::is_visible(
$document->getPath(),
api_get_course_info(),
api_get_session_id()
);
if (!api_is_allowed_to_edit() && !$isVisible) {
return '';
}
if ($showDirectUrl) {
$file = $main_course_path.'document'.$document->getPath().'?'.$extraParams;
if (api_get_configuration_value('allow_pdf_viewerjs_in_lp')) {
if (Link::isPdfLink($file)) {
$pdfUrl = api_get_path(WEB_LIBRARY_PATH).'javascript/ViewerJS/index.html#'.$file;
return $pdfUrl;
return api_get_path(WEB_LIBRARY_PATH).
'javascript/ViewerJS/index.html?zoom=page-width#'.$file;
}
}

@ -104,27 +104,52 @@ class LearnpathList
$showBlockedPrerequisite = api_get_configuration_value('show_prerequisite_as_blocked');
$names = [];
$isAllowToEdit = api_is_allowed_to_edit();
$toolSessionCondition = api_get_session_condition($session_id);
/** @var CLp $row */
foreach ($learningPaths as $row) {
$name = Database::escape_string($row->getName());
$link = 'lp/lp_controller.php?action=view&lp_id='.$row->getId().'&id_session='.$session_id;
$oldLink = 'newscorm/lp_controller.php?action=view&lp_id='.$row->getId().'&id_session='.$session_id;
$extraCondition = '';
if (!empty($session_id)) {
$extraLink = 'lp/lp_controller.php?action=view&lp_id='.$row->getId().'&id_session=0';
$extraCondition = " OR link LIKE '$extraLink' ";
}
$sql2 = "SELECT visibility FROM $tbl_tool
WHERE
c_id = $course_id AND
name = '$name' AND
image = 'scormbuilder.gif' AND
(
link LIKE '$link%' OR
link LIKE '$oldLink%'
$extraCondition
)
$toolSessionCondition
";
$res2 = Database::query($sql2);
$pub = 'i';
if (Database::num_rows($res2) > 0) {
$row2 = Database::fetch_array($res2);
$pub = $row2['visibility'];
$pub = (int) $row2['visibility'];
if (!empty($session_id)) {
$pub = 'v';
// Check exact value in session:
/*$sql3 = "SELECT visibility FROM $tbl_tool
WHERE
c_id = $course_id AND
image = 'scormbuilder.gif' AND
( link LIKE '$link'
)
$toolSessionCondition
";
$res3 = Database::query($sql3);
if (Database::num_rows($res3)) {
$pub = 'v';
}*/
//$pub = 0 === $pub ? 'i' : 'v';
}
}
// Check if visible.

@ -36,6 +36,7 @@ function activate_end_date() {
$is_allowed_to_edit = api_is_allowed_to_edit(null, true);
$isStudentView = isset($_REQUEST['isStudentView']) ? $_REQUEST['isStudentView'] : null;
$learnpath_id = isset($_REQUEST['lp_id']) ? $_REQUEST['lp_id'] : null;
$sessionId = api_get_session_id();
if (!$is_allowed_to_edit || $isStudentView) {
header('location:lp_controller.php?action=view&lp_id='.$learnpath_id.'&'.api_get_cidreq());

@ -286,7 +286,6 @@ $htmlHeadXtra[] = '
</script>';
$session_id = api_get_session_id();
$lpfound = false;
$myrefresh = 0;
$myrefresh_id = 0;
@ -491,6 +490,8 @@ if ($debug > 0) {
error_log('action "'.$action.'" triggered');
}
$lpListUrl = api_get_self().'?action=list&'.api_get_cidreq();
switch ($action) {
case 'author_view':
$teachers = [];
@ -876,7 +877,7 @@ switch ($action) {
require 'lp_list.php';
} else {
Session::write('refresh', 1);
if (isset($_POST['submit_button']) && !empty($post_title)) {
if (isset($_POST) && !empty($post_title)) {
// Updating the lp.modified_on
$_SESSION['oLP']->set_modified_on();
@ -907,7 +908,6 @@ switch ($action) {
$_SESSION['oLP']->edit_document($_course);
}
$is_success = true;
$extraFieldValues = new ExtraFieldValue('lp_item');
$extraFieldValues->saveFieldValues($_POST, true);
@ -1102,21 +1102,18 @@ switch ($action) {
learnpath::toggleCategoryVisibility($_REQUEST['id'], $_REQUEST['new_status']);
Display::addFlash(Display::return_message(get_lang('Updated')));
header('Location: '.api_get_self().'?'.api_get_cidreq());
exit;
api_location($lpListUrl);
break;
case 'toggle_visible':
// Change lp visibility (inside lp tool).
if (!$is_allowed_to_edit) {
api_not_allowed(true);
}
if (!$lp_found) {
require 'lp_list.php';
} else {
learnpath::toggle_visibility($_REQUEST['lp_id'], $_REQUEST['new_status']);
Display::addFlash(Display::return_message(get_lang('Updated')));
require 'lp_list.php';
}
learnpath::toggle_visibility($_REQUEST['lp_id'], $_REQUEST['new_status']);
Display::addFlash(Display::return_message(get_lang('Updated')));
api_location($lpListUrl);
break;
case 'toggle_category_publish':
if (!$is_allowed_to_edit) {
@ -1125,20 +1122,18 @@ switch ($action) {
learnpath::toggleCategoryPublish($_REQUEST['id'], $_REQUEST['new_status']);
Display::addFlash(Display::return_message(get_lang('Updated')));
require 'lp_list.php';
api_location($lpListUrl);
break;
case 'toggle_publish':
// Change lp published status (visibility on homepage).
if (!$is_allowed_to_edit) {
api_not_allowed(true);
}
if (!$lp_found) {
require 'lp_list.php';
} else {
learnpath::toggle_publish($_REQUEST['lp_id'], $_REQUEST['new_status']);
Display::addFlash(Display::return_message(get_lang('Updated')));
require 'lp_list.php';
}
learnpath::toggle_publish($_REQUEST['lp_id'], $_REQUEST['new_status']);
Display::addFlash(Display::return_message(get_lang('Updated')));
api_location($lpListUrl);
break;
case 'move_lp_up':
// Change lp published status (visibility on homepage)

@ -210,6 +210,7 @@ $courseSettingsDisableIcon = Display::return_icon(
$enableAutoLaunch = api_get_course_setting('enable_lp_auto_launch');
$gameMode = api_get_setting('gamification_mode');
$allowDatesForStudent = api_get_configuration_value('lp_start_and_end_date_visible_in_student_view');
$data = [];
$tableCategory = Database::get_course_table(TABLE_LP_CATEGORY);
@ -235,7 +236,6 @@ foreach ($categories as $item) {
continue;
}
}
if ($allowCategory && !empty($sessionId)) {
// Check base course
if (0 === $item->getSessionId()) {
@ -316,14 +316,14 @@ foreach ($categories as $item) {
}
$start_time = $end_time = '';
if ($is_allowed_to_edit) {
if (!empty($details['publicated_on'])) {
$start_time = api_convert_and_format_date($details['publicated_on'], DATE_TIME_FORMAT_LONG_24H);
}
if (!empty($details['expired_on'])) {
$end_time = api_convert_and_format_date($details['expired_on'], DATE_TIME_FORMAT_LONG_24H);
}
} else {
if (!empty($details['publicated_on'])) {
$start_time = api_convert_and_format_date($details['publicated_on'], DATE_TIME_FORMAT_LONG_24H);
}
if (!empty($details['expired_on'])) {
$end_time = api_convert_and_format_date($details['expired_on'], DATE_TIME_FORMAT_LONG_24H);
}
if (!$is_allowed_to_edit) {
$time_limits = false;
// This is an old LP (from a migration 1.8.7) so we do nothing
if (empty($details['created_on']) && empty($details['modified_on'])) {
@ -414,7 +414,6 @@ foreach ($categories as $item) {
$dsp_default_view = '';
$dsp_debug = '';
$dsp_order = '';
$progress = 0;
if (!$isInvitee) {
$progress = isset($progressList[$id]) && !empty($progressList[$id]) ? $progressList[$id] : 0;
@ -1028,6 +1027,8 @@ $template->assign('data', $data);
$template->assign('lp_is_shown', $lpIsShown);
$template->assign('filtered_category', $filteredCategoryId);
$template->assign('allow_min_time', $allowMinTime);
$template->assign('allow_dates_for_student', $allowDatesForStudent);
$templateName = $template->get_template('learnpath/list.tpl');
$content = $template->fetch($templateName);
$template->assign('content', $content);

@ -237,11 +237,10 @@ if ($debug) {
$get_toc_list = $lp->get_toc();
$get_teacher_buttons = $lp->get_teacher_toc_buttons();
$type_quiz = false;
$itemType = '';
foreach ($get_toc_list as $toc) {
if ($toc['id'] == $lp_item_id && $toc['type'] == 'quiz') {
$type_quiz = true;
if ($toc['id'] == $lp_item_id) {
$itemType = $toc['type'];
}
}
@ -260,6 +259,11 @@ if (!isset($src)) {
$get_toc_list
);
if (empty($src)) {
$src = 'blank.php?'.api_get_cidreq().'&error=document_protected';
break;
}
// Prevents FF 3.6 + Adobe Reader 9 bug see BT#794 when calling a pdf file in a LP.
$file_info = parse_url($src);
if (isset($file_info['path'])) {
@ -326,7 +330,6 @@ $autostart = 'true';
// Update status, total_time from lp_item_view table when you finish the exercises in learning path.
if ($debug) {
error_log('$type_quiz: '.$type_quiz);
error_log('$_REQUEST[exeId]: '.intval($_REQUEST['exeId']));
error_log('$lp_id: '.$lp_id);
error_log('$_REQUEST[lp_item_id]: '.intval($_REQUEST['lp_item_id']));
@ -349,13 +352,12 @@ if (!empty($_REQUEST['exeId']) &&
if (!empty($safe_id) && !empty($safe_item_id)) {
Exercise::saveExerciseInLp($safe_item_id, $safe_exe_id);
}
if (intval($_GET['fb_type']) != EXERCISE_FEEDBACK_TYPE_END) {
$src = 'blank.php?msg=exerciseFinished&'.api_get_cidreq(true, true, 'learnpath');
} else {
$src = api_get_path(WEB_CODE_PATH).'exercise/result.php?id='.$safe_exe_id.'&'.api_get_cidreq(true, true, 'learnpath');
if ($debug) {
error_log('Calling URL: '.$src);
}
/*if (intval($_GET['fb_type']) != EXERCISE_FEEDBACK_TYPE_END) {
$src = 'blank.php?msg=exerciseFinished&'.api_get_cidreq(true, true, 'learnpath');
} else {*/
$src = api_get_path(WEB_CODE_PATH).'exercise/result.php?id='.$safe_exe_id.'&'.api_get_cidreq(true, true, 'learnpath');
if ($debug) {
error_log('Calling URL: '.$src);
}
$autostart = 'false';
}
@ -617,9 +619,9 @@ $template->assign(
)
);
$frameReady = Display::getFrameReadyBlock('#content_id, #content_id_blank');
$frameReady = Display::getFrameReadyBlock('#content_id, #content_id_blank', $itemType);
$template->assign('frame_ready', $frameReady);
$view = $template->get_template('learnpath/view.tpl');
$content = $template->fetch($view);

@ -573,10 +573,10 @@ if (user_is_online($student_id)) {
$avg_student_progress = $avg_student_score = 0;
if (empty($sessionId)) {
$isSubscribedToCourse = CourseManager::is_user_subscribed_in_course($user_info['user_id'], $courseCode);
$isSubscribedToCourse = CourseManager::is_user_subscribed_in_course($student_id, $courseCode);
} else {
$isSubscribedToCourse = CourseManager::is_user_subscribed_in_course(
$user_info['user_id'],
$student_id,
$courseCode,
true,
$sessionId
@ -585,7 +585,7 @@ if (empty($sessionId)) {
if ($isSubscribedToCourse) {
$avg_student_progress = Tracking::get_avg_student_progress(
$user_info['user_id'],
$student_id,
$courseCode,
[],
$sessionId
@ -593,7 +593,7 @@ if ($isSubscribedToCourse) {
// the score inside the Reporting table
$avg_student_score = Tracking::get_avg_student_score(
$user_info['user_id'],
$student_id,
$courseCode,
[],
$sessionId
@ -605,7 +605,7 @@ $time_spent_on_the_course = 0;
if (!empty($courseInfo)) {
$time_spent_on_the_course = api_time_to_hms(
Tracking::get_time_spent_on_the_course(
$user_info['user_id'],
$student_id,
$courseInfo['real_id'],
$sessionId
)
@ -613,12 +613,12 @@ if (!empty($courseInfo)) {
}
// get information about connections on the platform by student
$first_connection_date = Tracking::get_first_connection_date($user_info['user_id']);
$first_connection_date = Tracking::get_first_connection_date($student_id);
if ($first_connection_date == '') {
$first_connection_date = get_lang('NoConnexion');
}
$last_connection_date = Tracking::get_last_connection_date($user_info['user_id'], true);
$last_connection_date = Tracking::get_last_connection_date($student_id, true);
if ($last_connection_date == '') {
$last_connection_date = get_lang('NoConnexion');
}
@ -661,15 +661,15 @@ $csv_content[] = [
$coachs_name = '';
$session_name = '';
$userPicture = UserManager::getUserPicture($user_info['user_id'], USER_IMAGE_SIZE_BIG);
$userPicture = UserManager::getUserPicture($student_id, USER_IMAGE_SIZE_BIG);
$userGroupManager = new UserGroup();
$userGroups = $userGroupManager->getNameListByUser(
$user_info['user_id'],
$student_id,
UserGroup::NORMAL_CLASS
);
$userInfo = [
'id' => $user_info['user_id'],
'id' => $student_id,
'complete_name' => $user_info['complete_name'],
'complete_name_link' => $user_info['complete_name_with_message_link'],
'phone' => $user_info['phone'],
@ -704,10 +704,7 @@ if (!empty($courseCode)) {
// Display timezone if the user selected one and if the admin allows the use of user's timezone
$timezone = null;
$timezone_user = UserManager::get_extra_user_data_by_field(
$user_info['user_id'],
'timezone'
);
$timezone_user = UserManager::get_extra_user_data_by_field($student_id, 'timezone');
$use_users_timezone = api_get_setting('use_users_timezone', 'timezones');
if ($timezone_user['timezone'] != null && $use_users_timezone === 'true') {
$timezone = $timezone_user['timezone'];
@ -727,7 +724,7 @@ $userInfo['student_progress'] = (float) $avg_student_progress;
$userInfo['first_connection'] = $first_connection_date;
$userInfo['last_connection'] = $last_connection_date;
$userInfo['last_connection_in_course'] = api_format_date(
Tracking::getLastConnectionInAnyCourse($user_info['user_id']),
Tracking::getLastConnectionInAnyCourse($student_id),
DATE_FORMAT_SHORT
);
if ($details === 'true') {
@ -933,11 +930,32 @@ $content = $tpl->fetch($templateName);
echo $content;
// Careers.
if (api_get_configuration_value('allow_career_users')) {
$careers = UserManager::getUserCareers($student_id);
if (!empty($careers)) {
echo '<br /><br />';
echo Display::page_subheader(get_lang('Careers'), null, 'h3', ['class' => 'section-title']);
$table = new HTML_Table(['class' => 'table table-hover table-striped data_table']);
$table->setHeaderContents(0, 0, get_lang('Career'));
$table->setHeaderContents(0, 1, get_lang('Diagram'));
$row = 1;
foreach ($careers as $careerData) {
$table->setCellContents($row, 0, $careerData['name']);
$url = api_get_path(WEB_CODE_PATH).'user/career_diagram.php?career_id='.$careerData['id'];
$diagram = Display::url(get_lang('Diagram'), $url);
$table->setCellContents($row, 1, $diagram);
$row++;
}
echo $table->toHtml();
}
}
$allowAll = api_get_configuration_value('allow_teacher_access_student_skills');
if ($allowAll) {
// Show all skills
echo Tracking::displayUserSkills(
$user_info['user_id'],
$student_id,
0,
0,
true
@ -945,7 +963,7 @@ if ($allowAll) {
} else {
// Default behaviour - Show all skills depending the course and session id
echo Tracking::displayUserSkills(
$user_info['user_id'],
$student_id,
$courseInfo ? $courseInfo['real_id'] : 0,
$sessionId
);
@ -1071,7 +1089,7 @@ if (empty($details)) {
if ($isSubscribed) {
$timeInSeconds = Tracking::get_time_spent_on_the_course(
$user_info['user_id'],
$student_id,
$courseId,
$sId
);
@ -1136,7 +1154,7 @@ if (empty($details)) {
}
$progress = Tracking::get_avg_student_progress(
$user_info['user_id'],
$student_id,
$courseCodeItem,
[],
$sId
@ -1145,7 +1163,7 @@ if (empty($details)) {
$totalProgress += $progress;
$score = Tracking::get_avg_student_score(
$user_info['user_id'],
$student_id,
$courseCodeItem,
[],
$sId
@ -1183,12 +1201,12 @@ if (empty($details)) {
<td>'.$attendances_faults_avg.'</td>
<td>'.$scoretotal_display.'</td>';
if (!empty($coachId)) {
echo '<td width="10"><a href="'.api_get_self().'?student='.$user_info['user_id']
echo '<td width="10"><a href="'.api_get_self().'?student='.$student_id
.'&details=true&course='.$courseInfoItem['code'].'&id_coach='.$coachId.'&origin='.$origin
.'&id_session='.$sId.'#infosStudent">'
.Display::return_icon('2rightarrow.png', get_lang('Details')).'</a></td>';
} else {
echo '<td width="10"><a href="'.api_get_self().'?student='.$user_info['user_id']
echo '<td width="10"><a href="'.api_get_self().'?student='.$student_id
.'&details=true&course='.$courseInfoItem['code'].'&origin='.$origin.'&id_session='.$sId
.'#infosStudent">'
.Display::return_icon('2rightarrow.png', get_lang('Details')).'</a></td>';
@ -1569,7 +1587,7 @@ if (empty($details)) {
$link = Display::url(
Display::return_icon('2rightarrow.png', get_lang('Details')),
'lp_tracking.php?cidReq='.$courseCode.'&course='.$courseCode.$from.'&origin='.$origin
.'&lp_id='.$lp_id.'&student_id='.$user_info['user_id'].'&id_session='.$sessionId
.'&lp_id='.$lp_id.'&student_id='.$student_id.'&id_session='.$sessionId
);
echo Display::tag('td', $link);
}
@ -1579,7 +1597,7 @@ if (empty($details)) {
if ($any_result === true) {
$url = 'myStudents.php?action=reset_lp&sec_token='.$token.'&cidReq='.$courseCode.'&course='
.$courseCode.'&details='.$details.'&origin='.$origin.'&lp_id='.$lp_id.'&student='
.$user_info['user_id'].'&details=true&id_session='.$sessionId;
.$student_id.'&details=true&id_session='.$sessionId;
echo Display::url(
Display::return_icon('clean.png', get_lang('Clean')),
$url,

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save