Julio Montoya пре 6 година
родитељ
комит
4b957af8e0

+ 1 - 1
main/blog/blog.php

@@ -436,7 +436,7 @@ $content = $tpl->fetch($blogLayout);
 if ($actionsLeft) {
     $tpl->assign(
         'actions',
-        Display::return_introduction_section(TOOL_BLOGS)
+        Display::return_introduction_section(TOOL_BLOGS."_$blog_id")
             .Display::toolbarAction('toolbar', [$actionsLeft])
     );
 }

+ 1 - 0
main/calendar/agenda_js.php

@@ -165,6 +165,7 @@ if ($type == 'course' && !empty($group_id)) {
 }
 
 $defaultView = api_get_setting('default_calendar_view');
+
 if (empty($defaultView)) {
     $defaultView = 'month';
 }

+ 7 - 11
main/cron/import_csv.php

@@ -1029,7 +1029,7 @@ class ImportCsv
                 }
 
                 if (empty($sessionId)) {
-                    $this->logger->addInfo("external_sessionID: ".$externalSessionId." does not exists.");
+                    $this->logger->addInfo("external_sessionID: $externalSessionId does not exists.");
                 }
                 $teacherId = null;
                 $sessionInfo = [];
@@ -1082,13 +1082,11 @@ class ImportCsv
                 $startDateMonth = substr($date, 4, 2);
                 $startDateDay = substr($date, 6, 8);
 
-                $startDate = $startDateYear.'-'.$startDateMonth.'-'.$startDateDay.' '.$startTime.":00";
-                $endDate = $startDateYear.'-'.$startDateMonth.'-'.$startDateDay.' '.$endTime.":00";
+                $startDate = $startDateYear.'-'.$startDateMonth.'-'.$startDateDay.' '.$startTime.':00';
+                $endDate = $startDateYear.'-'.$startDateMonth.'-'.$startDateDay.' '.$endTime.':00';
 
                 if (!api_is_valid_date($startDate) || !api_is_valid_date($endDate)) {
-                    $this->logger->addInfo(
-                        "Verify your dates:  '$startDate' : '$endDate' "
-                    );
+                    $this->logger->addInfo("Verify your dates:  '$startDate' : '$endDate' ");
                     $errorFound = true;
                 }
 
@@ -1124,7 +1122,7 @@ class ImportCsv
             }
 
             if (empty($eventsToCreate)) {
-                $this->logger->addInfo("No events to add");
+                $this->logger->addInfo('No events to add');
 
                 return 0;
             }
@@ -1134,9 +1132,7 @@ class ImportCsv
             $externalEventId = null;
 
             $extraField = new ExtraField('calendar_event');
-            $extraFieldInfo = $extraField->get_handler_field_info_by_field_variable(
-                $extraFieldName
-            );
+            $extraFieldInfo = $extraField->get_handler_field_info_by_field_variable($extraFieldName);
 
             if (empty($extraFieldInfo)) {
                 $this->logger->addInfo(
@@ -1356,7 +1352,7 @@ class ImportCsv
                             api_format_date($end, TIME_NO_SEC_FORMAT).')';
                     } else {
                         $date = api_format_date($start, DATE_TIME_FORMAT_LONG_24H).' - '.
-                            api_format_date($end, DATE_TIME_FORMAT_LONG_24H);
+                                api_format_date($end, DATE_TIME_FORMAT_LONG_24H);
                     }
 
                     $sessionName = '';

+ 2 - 14
main/document/showinframes.php

@@ -174,20 +174,8 @@ if (api_is_course_admin()) {
 }
 
 $js_glossary_in_documents = '
-  $.frameReady(function(){
-   //  $("<div>I am a div courses</div>").prependTo("body");
-  }, "top.mainFrame",
-  {
-    load: [
-        { type:"script", id:"_fr1", src:"'.api_get_jquery_web_path().'"},
-        { type:"script", id:"_fr7", src:"'.api_get_path(WEB_PUBLIC_PATH).'assets/MathJax/MathJax.js?config=AM_HTMLorMML"},
-        { type:"script", id:"_fr4", src:"'.api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/jquery-ui.min.js"},
-        { type:"stylesheet", id:"_fr5", src:"'.api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/themes/smoothness/jquery-ui.min.css"},
-        { type:"stylesheet", id:"_fr6", src:"'.api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/themes/smoothness/theme.css"},
-        { type:"script", id:"_fr2", src:"'.api_get_path(WEB_LIBRARY_PATH).'javascript/jquery.highlight.js"},
-        { type:"script", id:"_fr3", src:"'.api_get_path(WEB_CODE_PATH).'glossary/glossary.js.php?'.api_get_cidreq().'"}
-    ]
-  });';
+    setFrameReady("mainFrame");
+';
 
 $web_odf_supported_files = DocumentManager::get_web_odf_extension_list();
 // PDF should be displayed with viewerJS

+ 1 - 1
main/exercise/admin.php

@@ -127,7 +127,6 @@ $objAnswer = Session::read('objAnswer');
 $_course = api_get_course_info();
 
 // document path
-
 $documentPath = api_get_path(SYS_COURSE_PATH).$_course['path'].'/document';
 
 // picture path
@@ -308,6 +307,7 @@ if ($modifyIn == 'thisExercise') {
         $modifyIn = 'allExercises';
     }
 }
+
 $htmlHeadXtra[] = api_get_js('jqueryui-touch-punch/jquery.ui.touch-punch.min.js');
 $htmlHeadXtra[] = api_get_js('jquery.jsPlumb.all.js');
 

+ 8 - 8
main/exercise/exercise.class.php

@@ -8201,17 +8201,17 @@ class Exercise
                 '<table width="730" height="136" border="0" cellpadding="3" cellspacing="3">';
             $msg .= $open_question_list;
             $msg .= '</table><br />';
-            $msg1 = str_replace("#exercise#", $this->exercise, $msg);
-            $msg = str_replace("#firstName#", $user_info['firstname'], $msg1);
-            $msg1 = str_replace("#lastName#", $user_info['lastname'], $msg);
-            $msg = str_replace("#mail#", $user_info['email'], $msg1);
-            $msg = str_replace("#course#", $courseInfo['name'], $msg1);
+
+            $msg = str_replace("#exercise#", $this->exercise, $msg);
+            $msg = str_replace("#firstName#", $user_info['firstname'], $msg);
+            $msg = str_replace("#lastName#", $user_info['lastname'], $msg);
+            $msg = str_replace("#mail#", $user_info['email'], $msg);
+            $msg = str_replace("#course#", $courseInfo['name'], $msg);
 
             if ($origin != 'learnpath') {
                 $msg .= '<br /><a href="#url#">'.get_lang('ClickToCommentAndGiveFeedback').'</a>';
             }
-            $msg1 = str_replace("#url#", $url_email, $msg);
-            $mail_content = $msg1;
+            $msg = str_replace("#url#", $url_email, $msg);
             $subject = get_lang('OpenQuestionsAttempted');
 
             if (!empty($teachers)) {
@@ -8219,7 +8219,7 @@ class Exercise
                     MessageManager::send_message_simple(
                         $user_id,
                         $subject,
-                        $mail_content
+                        $msg
                     );
                 }
             }

+ 3 - 4
main/exercise/hotspot_admin.inc.php

@@ -11,7 +11,7 @@ use ChamiloSession as Session;
  *
  * @author Toon Keppens
  */
-$modifyAnswers = intval($_GET['hotspotadmin']);
+$modifyAnswers = (int) $_GET['hotspotadmin'];
 
 if (!is_object($objQuestion)) {
     $objQuestion = Question::read($modifyAnswers);
@@ -30,7 +30,7 @@ if ($modifyIn) {
         echo '$modifyIn was set'."<br />\n";
     }
     // if the user has chosen to modify the question only in the current exercise
-    if ($modifyIn == 'thisExercise') {
+    if ($modifyIn === 'thisExercise') {
         // duplicates the question
         $questionId = $objQuestion->duplicate();
 
@@ -71,14 +71,13 @@ $hotspot_admin_url = api_get_path(WEB_CODE_PATH).'exercise/admin.php?'.api_get_c
 // the answer form has been submitted
 $submitAnswers = isset($_POST['submitAnswers']) ? true : false;
 $buttonBack = isset($_POST['buttonBack']) ? true : false;
-$nbrAnswers = isset($_POST['nbrAnswers']) ? intval($_POST['nbrAnswers']) : 0;
+$nbrAnswers = isset($_POST['nbrAnswers']) ? (int) $_POST['nbrAnswers'] : 0;
 
 if ($submitAnswers || $buttonBack) {
     if ($answerType == HOT_SPOT) {
         if ($debug > 0) {
             echo '$submitAnswers or $buttonBack was set'."<br />\n";
         }
-
         $questionWeighting = $nbrGoodAnswers = 0;
         for ($i = 1; $i <= $nbrAnswers; $i++) {
             if ($debug > 0) {

+ 2 - 0
main/gradebook/certificate_report.php

@@ -1,6 +1,8 @@
 <?php
 /* For licensing terms, see /license.txt */
 
+use ChamiloSession as Session;
+
 /**
  * List all certificates filtered by session/course and month/year.
  *

+ 16 - 1
main/gradebook/gradebook_edit_result.php

@@ -37,8 +37,23 @@ if ($edit_result_form->validate()) {
         if (empty($score)) {
             $score = 0;
         }
-        $result->set_score(api_number_format($score, api_get_setting('gradebook_number_decimals')));
+        $score = api_number_format($score, api_get_setting('gradebook_number_decimals'));
+        $result->set_score($score);
         $result->save();
+
+        $allowMultipleAttempts = api_get_configuration_value('gradebook_multiple_evaluation_attempts');
+        if ($allowMultipleAttempts) {
+            $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_RESULT_ATTEMPT);
+            $now = api_get_utc_datetime();
+            $params = [
+                'result_id' => $result->get_id(),
+                'score' => $score,
+                'comment' => '',
+                'created_at' => $now,
+                'updated_at' => $now,
+            ];
+            Database::insert($table, $params);
+        }
     }
     Display::addFlash(Display::return_message(get_lang('AllResultsEdited')));
     header('Location: gradebook_view_result.php?selecteval='.$select_eval.'&'.api_get_cidreq());

+ 15 - 8
main/gradebook/gradebook_statistics.php

@@ -10,13 +10,20 @@ require_once __DIR__.'/../inc/global.inc.php';
 
 api_block_anonymous_users();
 
-$eval = Evaluation :: load($_GET['selecteval']);
-if ($eval[0]->get_category_id() < 0) {
+$categoryId = (int) $_GET['selecteval'];
+$eval = Evaluation::load($categoryId);
+if (!isset($eval[0])) {
+    api_not_allowed(true);
+}
+/** @var Evaluation $eval */
+$eval = $eval[0];
+
+if ($eval->get_category_id() < 0) {
     // if category id is negative, then the evaluation's origin is a link
-    $link = LinkFactory::get_evaluation_link($eval[0]->get_id());
+    $link = LinkFactory::get_evaluation_link($eval->get_id());
     $currentcat = Category::load($link->get_category_id());
 } else {
-    $currentcat = Category::load($eval[0]->get_category_id());
+    $currentcat = Category::load($eval->get_category_id());
 }
 
 $interbreadcrumb[] = [
@@ -26,7 +33,7 @@ $interbreadcrumb[] = [
 
 if (api_is_allowed_to_edit()) {
     $interbreadcrumb[] = [
-        'url' => 'gradebook_view_result.php?selecteval='.intval($_GET['selecteval']).'&'.api_get_cidreq(),
+        'url' => 'gradebook_view_result.php?selecteval='.$categoryId.'&'.api_get_cidreq(),
         'name' => get_lang('ViewResult'),
     ];
 }
@@ -34,7 +41,7 @@ $displayScore = ScoreDisplay::instance();
 
 Display::display_header(get_lang('EvaluationStatistics'));
 DisplayGradebook::display_header_result(
-    $eval[0],
+    $eval,
     $currentcat[0]->get_id(),
     0,
     'statistics'
@@ -48,7 +55,7 @@ if (!$displayScore->is_custom() || empty($displays)) {
         echo Display::return_message(get_lang('PleaseEnableScoringSystem'), 'error', false);
     }
 } else {
-    $allresults = Result::load(null, null, $eval[0]->get_id());
+    $allresults = Result::load(null, null, $eval->get_id());
     $nr_items = [];
     foreach ($displays as $itemsdisplay) {
         $nr_items[$itemsdisplay['display']] = 0;
@@ -59,7 +66,7 @@ if (!$displayScore->is_custom() || empty($displays)) {
         $score = $result->get_score();
         if (isset($score)) {
             $display = $displayScore->display_score(
-                [$score, $eval[0]->get_max()],
+                [$score, $eval->get_max()],
                 SCORE_CUSTOM,
                 SCORE_ONLY_CUSTOM,
                 true

+ 140 - 7
main/gradebook/gradebook_view_result.php

@@ -54,9 +54,130 @@ if (isset($_GET['selecteval'])) {
     $iscourse = !empty(api_get_course_id());
 }
 
+$allowMultipleAttempts = api_get_configuration_value('gradebook_multiple_evaluation_attempts');
+
+if (isset($_GET['action'])) {
+    switch ($_GET['action']) {
+        case 'delete_attempt':
+            $result = Result::load($_GET['editres']);
+            if ($allowMultipleAttempts && !empty($result) && isset($result[0]) && api_is_allowed_to_edit()) {
+                /** @var Result $result */
+                $result = $result[0];
+                $url = api_get_self().'?selecteval='.$select_eval.'&'.api_get_cidreq().'&editres='.$result->get_id();
+                $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_RESULT_ATTEMPT);
+                if (isset($_GET['result_attempt_id'])) {
+                    $attemptId = (int) $_GET['result_attempt_id'];
+                    $sql = "DELETE FROM $table WHERE result_id = ".$result->get_id()." AND id = $attemptId";
+                    Database::query($sql);
+                    Display::addFlash(Display::return_message(get_lang('Deleted')));
+                }
+
+                header('Location: '.$url.'&action=add_attempt');
+                exit;
+            }
+            break;
+        case 'add_attempt':
+            $result = Result::load($_GET['editres']);
+            if ($allowMultipleAttempts && !empty($result) && isset($result[0]) && api_is_allowed_to_edit()) {
+                /** @var Result $result */
+                $result = $result[0];
+                $backUrl = api_get_self().'?selecteval='.$select_eval.'&'.api_get_cidreq();
+                $interbreadcrumb[] = [
+                    'url' => $backUrl,
+                    'name' => get_lang('Details'),
+                ];
+
+                /** @var Evaluation $evaluation */
+                $evaluation = $eval[0];
+
+                $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_RESULT_ATTEMPT);
+                $now = api_get_utc_datetime();
+
+                $url = api_get_self().'?selecteval='.$select_eval.'&'.api_get_cidreq().'&editres='.$result->get_id();
+                $form = new FormValidator('attempt', 'post', $url.'&action=add_attempt');
+                $form->addHeader(get_lang('AddResult'));
+                $form->addLabel(get_lang('CurrentScore'), $result->get_score());
+
+                $form->addFloat(
+                    'score',
+                    [
+                        get_lang('Score'),
+                        null,
+                        '/ '.$evaluation->get_max(),
+                    ],
+                    true,
+                    [
+                        'size' => '4',
+                        'maxlength' => '5',
+                    ],
+                    false,
+                    0,
+                    $evaluation->get_max()
+                );
+
+                $form->addTextarea('comment', get_lang('Comment'));
+
+                /*$form->addRule(
+                    'score',
+                    get_lang('ValueTooBig'),
+                    'max_numeric_length',
+                    $evaluation->get_max()
+                );*/
+                $form->addButtonSave(get_lang('Save'));
+                $attemptList = ResultTable::getResultAttemptTable($result, $url);
+                $form->addLabel(get_lang('Attempts'), $attemptList);
+
+                if ($form->validate()) {
+                    $values = $form->getSubmitValues();
+                    $newScore = $values['score'];
+
+                    $newScore = api_number_format(
+                        $newScore,
+                        api_get_setting('gradebook_number_decimals')
+                    );
+
+                    $params = [
+                        'result_id' => $result->get_id(),
+                        'score' => $newScore,
+                        'comment' => $values['comment'],
+                        'created_at' => $now,
+                        'updated_at' => $now,
+                    ];
+
+                    Database::insert($table, $params);
+                    if ($newScore > $result->get_score()) {
+                        $result->set_score($newScore);
+                        $result->save();
+                    }
+                    Display::addFlash(Display::return_message(get_lang('Saved')));
+                    header('Location: '.api_get_self().'?selecteval='.$select_eval.'&'.api_get_cidreq());
+                    exit;
+                }
+
+                Display::display_header();
+
+                $items[] = [
+                    'url' => $backUrl,
+                    'content' => Display::return_icon(
+                        'back.png',
+                        get_lang('Back'),
+                        [],
+                        ICON_SIZE_MEDIUM
+                    ),
+                ];
+
+                echo Display::actions($items);
+                $form->display();
+                Display::display_footer();
+                exit;
+            }
+            break;
+    }
+}
+
 if (isset($_GET['editres'])) {
     $edit_res_xml = Security::remove_XSS($_GET['editres']);
-    $resultedit = Result :: load($edit_res_xml);
+    $resultedit = Result::load($edit_res_xml);
     $edit_res_form = new EvalForm(
         EvalForm::TYPE_RESULT_EDIT,
         $eval[0],
@@ -76,15 +197,27 @@ if (isset($_GET['editres'])) {
         $result->set_evaluation_id($select_eval);
         $row_value = isset($values['score']) ? $values['score'] : 0;
         if (!empty($row_value) || $row_value == 0) {
-            $result->set_score(
-                api_number_format(
-                    $row_value,
-                    api_get_setting('gradebook_number_decimals')
-                )
+            $row_value = api_number_format(
+                $row_value,
+                api_get_setting('gradebook_number_decimals')
             );
+            $result->set_score($row_value);
         }
         $result->save();
-        unset($result);
+
+        if ($allowMultipleAttempts && !empty($result->get_id())) {
+            $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_RESULT_ATTEMPT);
+            $now = api_get_utc_datetime();
+            $params = [
+                'result_id' => $result->get_id(),
+                'score' => $row_value,
+                'comment' => $values['comment'],
+                'created_at' => $now,
+                'updated_at' => $now,
+            ];
+
+            Database::insert($table, $params);
+        }
 
         Display::addFlash(Display::return_message(get_lang('ResultEdited'), 'normal', false));
         header('Location: gradebook_view_result.php?selecteval='.$select_eval.'&editresmessage=&'.api_get_cidreq());

+ 17 - 12
main/gradebook/lib/be/category.class.php

@@ -806,20 +806,25 @@ class Category implements GradebookItem
 
     /**
      * Shows all information of an category.
+     *
+     * @param int $categoryId
+     *
+     * @return array
      */
-    public function showAllCategoryInfo($categoryId = '')
+    public function showAllCategoryInfo($categoryId = 0)
     {
-        if ($categoryId == '') {
-            return null;
-        } else {
-            $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
-            $sql = 'SELECT * FROM '.$table.'
-                    WHERE id = '.intval($categoryId);
-            $result = Database::query($sql);
-            $row = Database::fetch_array($result, 'ASSOC');
-
-            return $row;
+        $categoryId = (int) $categoryId;
+        if (empty($categoryId)) {
+            return [];
         }
+
+        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
+        $sql = 'SELECT * FROM '.$table.'
+                WHERE id = '.$categoryId;
+        $result = Database::query($sql);
+        $row = Database::fetch_array($result, 'ASSOC');
+
+        return $row;
     }
 
     /**
@@ -913,7 +918,7 @@ class Category implements GradebookItem
      * Calculate the score of this category.
      *
      * @param int    $stud_id     student id (default: all students - then the average is returned)
-     * @param int    $session_id
+     * @param        $type
      * @param string $course_code
      * @param int    $session_id
      *

+ 6 - 0
main/gradebook/lib/be/result.class.php

@@ -282,5 +282,11 @@ class Result
         $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_RESULT);
         $sql = 'DELETE FROM '.$table.' WHERE id = '.$this->id;
         Database::query($sql);
+        $allowMultipleAttempts = api_get_configuration_value('gradebook_multiple_evaluation_attempts');
+        if ($allowMultipleAttempts) {
+            $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_RESULT_ATTEMPT);
+            $sql = "DELETE FROM $table WHERE result_id = ".$this->id;
+            Database::query($sql);
+        }
     }
 }

+ 13 - 10
main/gradebook/lib/fe/displaygradebook.php

@@ -11,7 +11,7 @@ class DisplayGradebook
     /**
      * Displays the header for the result page containing the navigation tree and links.
      *
-     * @param $evalobj
+     * @param Evaluation $evalobj
      * @param $selectcat
      * @param $shownavbar 1=show navigation bar
      * @param $forpdf only output for pdf file
@@ -74,6 +74,17 @@ class DisplayGradebook
                     'h3',
                     get_lang('Score').': '.$scoredisplay->display_score($student_score, SCORE_DIV_PERCENT)
                 );
+
+                $allowMultipleAttempts = api_get_configuration_value('gradebook_multiple_evaluation_attempts');
+                if ($allowMultipleAttempts) {
+                    $results = Result::load(null, api_get_user_id(), $evalobj->get_id());
+                    if (!empty($results)) {
+                        /** @var Result $resultData */
+                        foreach ($results as $resultData) {
+                            $student_score .= ResultTable::getResultAttemptTable($resultData);
+                        }
+                    }
+                }
             }
         }
         $description = '';
@@ -100,15 +111,7 @@ class DisplayGradebook
         if (!$evalobj->has_results()) {
             $evalinfo .= '<br /><i>'.get_lang('NoResultsInEvaluation').'</i>';
         }
-        /* Code comment without reason
-        elseif ($scoredisplay->is_custom() && api_get_self() != '/main/gradebook/gradebook_statistics.php') {
-            if (api_is_allowed_to_edit(null, true)) {
-                if ($page != 'statistics') {
-                    //$evalinfo .= '<br /><br /><a href="gradebook_view_result.php?selecteval='.Security::remove_XSS($_GET['selecteval']).'"> '.Display::return_icon(('evaluation_rate.png'),get_lang('ViewResult'),'',ICON_SIZE_MEDIUM) . '</a>';
-                }
-            }
-        }
-        */
+
         if ($page != 'statistics') {
             if (api_is_allowed_to_edit(null, true)) {
                 $evalinfo .= '<br /><a href="gradebook_statistics.php?'.api_get_cidreq().'&selecteval='.Security::remove_XSS($_GET['selecteval']).'"> '.

+ 5 - 0
main/gradebook/lib/fe/evalform.class.php

@@ -395,6 +395,11 @@ class EvalForm extends FormValidator
             $this->evaluation_object->get_max()
         );
 
+        $allowMultipleAttempts = api_get_configuration_value('gradebook_multiple_evaluation_attempts');
+        if ($allowMultipleAttempts) {
+            $this->addTextarea('comment', get_lang('Comment'));
+        }
+
         $this->addButtonSave(get_lang('Edit'), 'submit');
         $this->addElement('hidden', 'hid_user_id', $this->result_object->get_user_id());
     }

+ 68 - 3
main/gradebook/lib/fe/resulttable.class.php

@@ -164,6 +164,56 @@ class ResultTable extends SortableTable
         return $sortable_data;
     }
 
+    /**
+     * @param Result $result
+     * @param string $url
+     *
+     * @return string
+     *
+     */
+    public static function getResultAttemptTable($result, $url = '')
+    {
+        if (empty($result)) {
+
+            return '';
+        }
+
+        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_RESULT_ATTEMPT);
+
+        $sql = "SELECT * FROM $table WHERE result_id = ".$result->get_id().' ORDER BY created_at DESC';
+        $resultQuery = Database::query($sql);
+        $list = Database::store_result($resultQuery);
+
+        $htmlTable = new HTML_Table(['class' => 'data_table']);
+        $htmlTable->setHeaderContents(0, 0, get_lang('Score'));
+        $htmlTable->setHeaderContents(0, 1, get_lang('Comment'));
+        $htmlTable->setHeaderContents(0, 2, get_lang('CreatedAt'));
+
+        if (!empty($url)) {
+            $htmlTable->setHeaderContents(0, 3, get_lang('Actions'));
+        }
+
+        $row = 1;
+        foreach ($list as $data) {
+            $htmlTable->setCellContents($row, 0, $data['score']);
+            $htmlTable->setCellContents($row, 1, $data['comment']);
+            $htmlTable->setCellContents($row, 2, Display::dateToStringAgoAndLongDate($data['created_at']));
+            if (!empty($url)) {
+                $htmlTable->setCellContents(
+                    $row,
+                    3,
+                    Display::url(
+                        Display::return_icon('delete.png', get_lang('Delete')),
+                        $url.'&action=delete_attempt&result_attempt_id='.$data['id']
+                    )
+                );
+            }
+            $row++;
+        }
+
+        return $htmlTable->toHtml();
+    }
+
     /**
      * @param array $item
      *
@@ -172,10 +222,25 @@ class ResultTable extends SortableTable
     private function build_edit_column($item)
     {
         $locked_status = $this->evaluation->get_locked();
+        $allowMultipleAttempts = api_get_configuration_value('gradebook_multiple_evaluation_attempts');
+        $baseUrl = api_get_self().'?selecteval='.$this->evaluation->get_id().'&'.api_get_cidreq();
         if (api_is_allowed_to_edit(null, true) && $locked_status == 0) {
-            //api_is_course_admin()
-            $edit_column = '<a href="'.api_get_self().'?editres='.$item['result_id'].'&selecteval='.$this->evaluation->get_id().'&'.api_get_cidreq().'">'.
-                Display::return_icon('edit.png', get_lang('Modify'), '', '22').'</a>';
+            $edit_column = '';
+            if ($allowMultipleAttempts) {
+                if (!empty($item['percentage_score'])) {
+                    $edit_column .=
+                        Display::url(
+                            Display::return_icon('add.png', get_lang('AddAttempt'), '', '22'),
+                            $baseUrl.'&action=add_attempt&editres='.$item['result_id']
+                        );
+                } else {
+                    $edit_column .= '<a href="'.api_get_self().'?editres='.$item['result_id'].'&selecteval='.$this->evaluation->get_id().'&'.api_get_cidreq().'">'.
+                        Display::return_icon('edit.png', get_lang('Modify'), '', '22').'</a>';
+                }
+            } else {
+                $edit_column .= '<a href="'.api_get_self().'?editres='.$item['result_id'].'&selecteval='.$this->evaluation->get_id().'&'.api_get_cidreq().'">'.
+                    Display::return_icon('edit.png', get_lang('Modify'), '', '22').'</a>';
+            }
             $edit_column .= ' <a href="'.api_get_self().'?delete_mark='.$item['result_id'].'&selecteval='.$this->evaluation->get_id().'&'.api_get_cidreq().'">'.
                 Display::return_icon('delete.png', get_lang('Delete'), '', '22').'</a>';
         }

+ 5 - 4
main/inc/introductionSection.inc.php

@@ -32,6 +32,7 @@ use Chamilo\CourseBundle\Entity\CToolIntro;
 $em = Database::getManager();
 $intro_editAllowed = $is_allowed_to_edit = api_is_allowed_to_edit();
 $session_id = api_get_session_id();
+$blogParam = isset($_GET['blog_id']) ? ('&blog_id='.(int) $_GET['blog_id']) : '';
 
 $introduction_section = '';
 
@@ -46,7 +47,7 @@ if (!empty($courseId)) {
     $form = new FormValidator(
         'introduction_text',
         'post',
-        api_get_self().'?'.api_get_cidreq()
+        api_get_self().'?'.api_get_cidreq().$blogParam
     );
 } else {
     $form = new FormValidator('introduction_text');
@@ -304,7 +305,7 @@ if ($intro_dispCommand) {
         $toolbar .= '<div class="toolbar-edit">';
         $toolbar .= '<div class="btn-group pull-right" role="group">';
         if (!empty($courseId)) {
-            $textIntro = '<a class="btn btn-default" title="'.addslashes(get_lang('AddIntro')).'" href="'.api_get_self().'?'.api_get_cidreq().'&intro_cmdAdd=1">';
+            $textIntro = '<a class="btn btn-default" title="'.addslashes(get_lang('AddIntro')).'" href="'.api_get_self().'?'.api_get_cidreq().$blogParam.'&intro_cmdAdd=1">';
             $textIntro .= '<em class="fa fa-file-text"></em> ';
             $textIntro .= "</a>";
             $toolbar .= $textIntro.$editIconButton;
@@ -319,10 +320,10 @@ if ($intro_dispCommand) {
         $toolbar .= '<div class="btn-group pull-right" rol="group">';
         if (!empty($courseId)) {
             $toolbar .=
-                '<a class="btn btn-default" href="'.api_get_self().'?'.api_get_cidreq().'&intro_cmdEdit=1" title="'.get_lang('Modify').'">
+                '<a class="btn btn-default" href="'.api_get_self().'?'.api_get_cidreq().$blogParam.'&intro_cmdEdit=1" title="'.get_lang('Modify').'">
                 <em class="fa fa-pencil"></em></a>';
             $toolbar .= $editIconButton;
-            $toolbar .= "<a class=\"btn btn-default\" href=\"".api_get_self()."?".api_get_cidreq()."&intro_cmdDel=1\" onclick=\"javascript:
+            $toolbar .= "<a class=\"btn btn-default\" href=\"".api_get_self()."?".api_get_cidreq().$blogParam."&intro_cmdDel=1\" onclick=\"javascript:
                 if(!confirm('".addslashes(api_htmlentities(get_lang('ConfirmYourChoice'), ENT_QUOTES, $charset)).
                 "')) return false;\"><em class=\"fa fa-trash-o\"></em></a>";
         } else {

+ 4 - 0
main/inc/lib/add_course.lib.inc.php

@@ -469,6 +469,8 @@ class AddCourse
             'display_info_advance_inside_homecourse' => ['default' => 1, 'category' => 'thematic_advance'],
             'email_alert_students_on_new_homework' => ['default' => 0, 'category' => 'work'],
             'enable_lp_auto_launch' => ['default' => 0, 'category' => 'learning_path'],
+            'enable_exercise_auto_launch' => ['default' => 0, 'category' => 'exercise'],
+            'enable_document_auto_launch' => ['default' => 0, 'category' => 'document'],
             'pdf_export_watermark_text' => ['default' => '', 'category' => 'learning_path'],
             'allow_public_certificates' => [
                 'default' => api_get_setting('allow_public_certificates') === 'true' ? 1 : '',
@@ -476,7 +478,9 @@ class AddCourse
             ],
             'documents_default_visibility' => ['default' => 'visible', 'category' => 'document'],
             'show_course_in_user_language' => ['default' => 2, 'category' => null],
+            'email_to_teachers_on_new_work_feedback' => ['default' => 1, 'category' => null],
         ];
+
         $counter = 1;
         foreach ($settings as $variable => $setting) {
             $title = isset($setting['title']) ? $setting['title'] : '';

+ 0 - 1
main/inc/lib/agenda.lib.php

@@ -57,7 +57,6 @@ class Agenda
 
                 // Setting the course object if we are in a course
                 $courseInfo = api_get_course_info_by_id($courseId);
-
                 if (!empty($courseInfo)) {
                     $this->set_course($courseInfo);
                 }

+ 4 - 3
main/inc/lib/certificate.lib.php

@@ -218,12 +218,13 @@ class Certificate extends Model
         }
 
         $params['hide_print_button'] = isset($params['hide_print_button']) ? true : false;
-
+        $categoryId = 0;
         if (isset($this->certificate_data) && isset($this->certificate_data['cat_id'])) {
-            $my_category = Category::load($this->certificate_data['cat_id']);
+            $categoryId = $this->certificate_data['cat_id'];
+            $my_category = Category::load($categoryId);
         }
 
-        if (isset($my_category[0]) &&
+        if (isset($my_category[0]) && !empty($categoryId) &&
             $my_category[0]->is_certificate_available($this->user_id)
         ) {
             $courseInfo = api_get_course_info($my_category[0]->get_course_code());

+ 1 - 1
main/inc/lib/security.lib.php

@@ -309,7 +309,7 @@ class Security
             }
         }
 
-        if ($user_status === COURSEMANAGERLOWSECURITY) {
+        if ($user_status == COURSEMANAGERLOWSECURITY) {
             return $var; // No filtering.
         }
 

+ 5 - 5
main/inc/lib/sortable_table.class.php

@@ -130,15 +130,15 @@ class SortableTable extends HTML_Table
             $table_id = $table_name.uniqid();
         }
         $this->table_id = $table_id;
-        parent::__construct(['class' => 'data_table table', 'id' => $table_id]);
+        parent::__construct(['class' => 'table table-striped table-hover', 'id' => $table_id]);
         $this->table_name = $table_name;
         $this->additional_parameters = [];
         $this->param_prefix = $table_name.'_';
 
         $this->page_nr = Session::read($this->param_prefix.'page_nr', 1);
-        $this->page_nr = isset($_GET[$this->param_prefix.'page_nr']) ? intval($_GET[$this->param_prefix.'page_nr']) : $this->page_nr;
+        $this->page_nr = isset($_GET[$this->param_prefix.'page_nr']) ? (int) $_GET[$this->param_prefix.'page_nr'] : $this->page_nr;
         $this->column = Session::read($this->param_prefix.'column', $default_column);
-        $this->column = isset($_GET[$this->param_prefix.'column']) ? intval($_GET[$this->param_prefix.'column']) : $this->column;
+        $this->column = isset($_GET[$this->param_prefix.'column']) ? (int) $_GET[$this->param_prefix.'column'] : $this->column;
 
         // Default direction.
         if (in_array(strtoupper($default_order_direction), ['ASC', 'DESC'])) {
@@ -163,9 +163,9 @@ class SortableTable extends HTML_Table
             if (!in_array($my_get_direction, ['ASC', 'DESC'])) {
                 $this->direction = 'ASC';
             } else {
-                if ($my_get_direction == 'ASC') {
+                if ($my_get_direction === 'ASC') {
                     $this->direction = 'ASC';
-                } elseif ($my_get_direction == 'DESC') {
+                } elseif ($my_get_direction === 'DESC') {
                     $this->direction = 'DESC';
                 }
             }

+ 4 - 0
main/portfolio/index.php

@@ -8,6 +8,10 @@ use Chamilo\CoreBundle\Entity\PortfolioCategory;
 use Chamilo\CoreBundle\Entity\Session;
 use Chamilo\UserBundle\Entity\User;
 
+// Make sure we void the course context if we are in the social network section
+if (empty($_GET['cidReq'])) {
+    $cidReset = true;
+}
 require_once __DIR__.'/../inc/global.inc.php';
 
 api_block_anonymous_users();

+ 1 - 3
main/social/group_topics.php

@@ -52,9 +52,7 @@ if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'delete') {
 }
 
 // My friends
-$friend_html = SocialManager::listMyFriendsBlock(
-    $user_id
-);
+$friend_html = SocialManager::listMyFriendsBlock(api_get_user_id());
 $content = null;
 $social_right_content = '';
 

+ 2 - 1
main/work/work.lib.php

@@ -5111,7 +5111,8 @@ function getFileContents($id, $courseInfo, $sessionId = 0, $correction = false,
             $is_editor = api_is_allowed_to_edit(true, true, true);
             $student_is_owner_of_work = user_is_author($row['id'], api_get_user_id());
 
-            if ($is_editor ||
+            if (($forceAccessForCourseAdmins && $isAllow) ||
+                $is_editor ||
                 $student_is_owner_of_work ||
                 ($doc_visible_for_all && $work_is_visible)
             ) {