Просмотр исходного кода

Merge pull request #720 from AngelFQC/BT9887

Search session by their courses tag - refs BT#9887 #TMI
Angel Fernando Quiroz Campos 9 лет назад
Родитель
Сommit
824929e545

+ 1 - 20
main/admin/user_list.php

@@ -125,25 +125,6 @@ $(document).ready(function() {
             document.getElementById(\'extra_data_text\').style.display="none";
         }
     }
-
-    $(".agenda_opener").click(function() {
-        var url = this.href;
-        var dialog = $("#dialog");
-
-        if ($("#dialog").length == 0) {
-            dialog = $(\'<div id="dialog" style="display:hidden"></div> \').appendTo(\'body\');
-        }
-        // load remote content
-        dialog.load(
-            url,
-            {},
-            function(responseText, textStatus, XMLHttpRequest) {
-                dialog.dialog({width:720, height:550, modal:true});
-            }
-        );
-        //prevent the browser to follow the link
-        return false;
-    });
 });
 
 //Load user calendar
@@ -591,7 +572,7 @@ function modify_filter($user_id, $url_params, $row) {
 	}
 
     if (api_is_platform_admin()) {
-        $result .= ' <a href="'.api_get_path(WEB_AJAX_PATH).'agenda.ajax.php?a=get_user_agenda&amp;user_id='.$user_id.'" class="agenda_opener">'.
+        $result .= ' <a href="'.api_get_path(WEB_AJAX_PATH).'agenda.ajax.php?a=get_user_agenda&amp;user_id='.$user_id.'&modal_size=lg" class="agenda_opener ajax">'.
             Display::return_icon('month.png', get_lang('FreeBusyCalendar'), array(), ICON_SIZE_SMALL).'</a>';
         $deleteAllowed = !api_get_configuration_value('deny_delete_users');
         if ($deleteAllowed) {

+ 5 - 30
main/auth/courses.php

@@ -15,35 +15,6 @@ require_once '../inc/global.inc.php';
 
 $ctok = Security::get_existing_token();
 
-if (api_get_setting('show_courses_descriptions_in_catalog') == 'true') {
-    $htmlHeadXtra[] = '
-    <script>
-    $(document).ready(function() {
-        $(\'.ajax\').click(function() {
-            var url     = this.href;
-            var dialog  = $("#dialog");
-            if ($("#dialog").length == 0) {
-                dialog  = $(\'<div id="dialog" style="display:hidden"></div>\').appendTo(\'body\');
-            }
-
-            // load remote content
-            dialog.load(
-                url,
-                {},
-                function(responseText, textStatus, XMLHttpRequest) {
-                    dialog.dialog({
-                    modal : true,
-                    width : 540,
-                    height : 400
-                });
-            });
-            //prevent the browser to follow the link
-            return false;
-        });
-    });
-    </script>';
-}
-
 // Get Limit data
 $limit = getLimitArray();
 
@@ -77,7 +48,8 @@ $actions = array(
     'display_random_courses',
     'subscribe_user_with_password',
     'display_sessions',
-    'subscribe_to_session'
+    'subscribe_to_session',
+    'search_tag'
 );
 
 $action = CoursesAndSessionsCatalog::is(CATALOG_SESSIONS) ? 'display_sessions' : 'display_random_courses';
@@ -262,4 +234,7 @@ switch ($action) {
         }
         //else show error message?
         break;
+    case 'search_tag':
+        $courses_controller->sessionsListByCoursesTag($limit);
+        break;
 }

+ 86 - 0
main/auth/courses_controller.php

@@ -633,4 +633,90 @@ class CoursesController
 
         $tpl->display($contentTemplate);
     }
+
+    /**
+     * Show the Session Catalogue with filtered session by course tags
+     * @param array $limit Limit info
+     */
+    public function sessionsListByCoursesTag(array $limit)
+    {
+        $searchTag = isset($_POST['search_tag']) ? $_POST['search_tag'] : null;
+        $searchDate = isset($_POST['date']) ? $_POST['date'] : date('Y-m-d');
+        $hiddenLinks = isset($_GET['hidden_links']) ? intval($_GET['hidden_links']) == 1 : false;
+        $courseUrl = getCourseCategoryUrl(1, $limit['length'], null, 0, 'subscribe');
+        $userId = api_get_user_id();
+
+        $sessionsBlocks = array();
+        $sessions = $this->model->browseSessionsByTags($searchTag, $limit);
+
+        $key = 'name';
+        $catalogSessionAutoSubscriptionAllowed = false;
+
+        if (api_get_setting('catalog_allow_session_auto_subscription') === 'true') {
+            $key = 'id';
+            $catalogSessionAutoSubscriptionAllowed = true;
+        }
+
+        foreach ($sessions as $session) {
+            $sessionDates = SessionManager::parseSessionDates([
+                'display_start_date' => $session->getDisplayStartDate(),
+                'display_end_date' => $session->getDisplayEndDate(),
+                'access_start_date' => $session->getAccessStartDate(),
+                'access_end_date' => $session->getAccessEndDate(),
+                'coach_access_start_date' => $session->getCoachAccessStartDate(),
+                'coach_access_end_date' => $session->getCoachAccessEndDate()
+            ]);
+
+            $sessionsBlock = array(
+                'id' => $session->getId(),
+                'name' => $session->getName(),
+                'nbr_courses' => $session->getNbrCourses(),
+                'nbr_users' => $session->getNbrUsers(),
+                'coach_name' => $session->getGeneralCoach()->getCompleteName(),
+                'is_subscribed' => SessionManager::isUserSubscribedAsStudent($session->getId(), $userId),
+                'icon' => $this->getSessionIcon($session->getName()),
+                'date' => $sessionDates['display'],
+                'subscribe_button' => $this->getRegisteredInSessionButton(
+                    $key === 'id' ? $session->getId() : $session->getName(),
+                    $catalogSessionAutoSubscriptionAllowed
+                ),
+                'show_description' => $session->getShowDescription(),
+            );
+
+            /** @var \Chamilo\CoreBundle\Entity\Repository\SequenceRepository $repo */
+            $repo = Database::getManager()->getRepository('ChamiloCoreBundle:SequenceResource');
+            $requirementAndDependencies = $repo->getRequirementAndDependencies(
+                $session->getId(),
+                SequenceResource::SESSION_TYPE
+            );
+
+            $sessionsBlock = array_merge($sessionsBlock, $requirementAndDependencies);
+            $sessionsBlocks[] = $sessionsBlock;
+        }
+
+        $tpl = new Template();
+        $tpl->assign('show_courses', CoursesAndSessionsCatalog::showCourses());
+        $tpl->assign('show_sessions', CoursesAndSessionsCatalog::showSessions());
+        $tpl->assign('show_tutor', (api_get_setting('show_session_coach')==='true' ? true : false));
+
+        $tpl->assign('course_url', $courseUrl);
+
+        $tpl->assign('course_category_list', $this->getCoursesCategoriesBlock(null, false, $limit));
+        $tpl->assign('already_subscribed_label', $this->getAlreadyRegisteredInSessionLabel());
+
+        $tpl->assign('hidden_links', $hiddenLinks);
+
+        $tpl->assign('search_date', Security::remove_XSS($searchDate));
+        $tpl->assign('search_tag', Security::remove_XSS($searchTag));
+        $tpl->assign('sessions', $sessionsBlocks);
+
+        if (empty($sessionsBlocks)) {
+            $tpl->assign('message', Display::return_message(get_lang('NoResults'), 'warning'));
+        }
+
+        $contentTemplate = $tpl->get_template('auth/session_catalog.tpl');
+
+        $tpl->display($contentTemplate);
+    }
+
 }

+ 164 - 2
main/inc/lib/auth.lib.php

@@ -370,9 +370,9 @@ class Auth
         $category_id = intval($category_id);
         $result = false;
         $sql_delete = "DELETE FROM $tucc
-                       WHERE id='" . $category_id . "' and user_id='" . $current_user_id . "'";
+                      WHERE id='" . $category_id . "' and user_id='" . $current_user_id . "'";
         $resultQuery = Database::query($sql_delete);
-        if (Database::affected_rows($resultQuery)) {
+       if (Database::affected_rows($resultQuery)) {
             $result = true;
         }
         $sql = "UPDATE $TABLECOURSUSER
@@ -386,6 +386,104 @@ class Auth
         return $result;
     }
 
+    /**
+     * Search the courses database for a course that matches the search term.
+     * The search is done on the code, title and tutor field of the course table.
+     * @param string $search_term The string that the user submitted, what we are looking for
+     * @param array $limit
+     * @return array An array containing a list of all the courses matching the the search term.
+     */
+    public function search_courses($search_term, $limit)
+    {
+        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
+        $extraFieldTable = Database :: get_main_table(TABLE_EXTRA_FIELD);
+        $extraFieldValuesTable = Database :: get_main_table(TABLE_EXTRA_FIELD_VALUES);
+
+        $limitFilter = getLimitFilterFromArray($limit);
+
+        // get course list auto-register
+        $sql = "SELECT item_id
+                FROM $extraFieldValuesTable tcfv
+                INNER JOIN $extraFieldTable tcf ON tcfv.field_id =  tcf.id
+                WHERE
+                    tcf.variable = 'special_course' AND
+                    tcfv.value = 1 ";
+
+        $special_course_result = Database::query($sql);
+        if (Database::num_rows($special_course_result) > 0) {
+            $special_course_list = array();
+            while ($result_row = Database::fetch_array($special_course_result)) {
+                $special_course_list[] = '"' . $result_row['item_id'] . '"';
+            }
+        }
+        $without_special_courses = '';
+        if (!empty($special_course_list)) {
+            $without_special_courses = ' AND course.code NOT IN (' . implode(',', $special_course_list) . ')';
+        }
+
+        $search_term_safe = Database::escape_string($search_term);
+        $sql_find = "SELECT * FROM $courseTable
+                    WHERE (
+                            code LIKE '%" . $search_term_safe . "%' OR
+                            title LIKE '%" . $search_term_safe . "%' OR
+                            tutor_name LIKE '%" . $search_term_safe . "%'
+                        )
+                        $without_special_courses
+                    ORDER BY title, visual_code ASC
+                    $limitFilter
+                    ";
+
+        if (api_is_multiple_url_enabled()) {
+            $url_access_id = api_get_current_access_url_id();
+            if ($url_access_id != -1) {
+                $tbl_url_rel_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
+                $sql_find = "SELECT *
+                            FROM $courseTable as course
+                            INNER JOIN $tbl_url_rel_course as url_rel_course
+                            ON (url_rel_course.c_id = course.id)
+                            WHERE
+                                access_url_id = $url_access_id AND (
+                                    code LIKE '%" . $search_term_safe . "%' OR
+                                    title LIKE '%" . $search_term_safe . "%' OR
+                                    tutor_name LIKE '%" . $search_term_safe . "%'
+                                )
+                                $without_special_courses
+                            ORDER BY title, visual_code ASC
+                            $limitFilter
+                            ";
+            }
+        }
+        $result_find = Database::query($sql_find);
+        $courses = array();
+        while ($row = Database::fetch_array($result_find)) {
+            $row['registration_code'] = !empty($row['registration_code']);
+            $count_users = count(CourseManager::get_user_list_from_course_code($row['code']));
+            $count_connections_last_month = Tracking::get_course_connections_count(
+                    $row['id'], 0, api_get_utc_datetime(time() - (30 * 86400))
+            );
+
+            $point_info = CourseManager::get_course_ranking($row['id'], 0);
+
+            $courses[] = array(
+                'real_id' => $row['id'],
+                'point_info' => $point_info,
+                'code' => $row['code'],
+                'directory' => $row['directory'],
+                'visual_code' => $row['visual_code'],
+                'title' => $row['title'],
+                'tutor' => $row['tutor_name'],
+                'subscribe' => $row['subscribe'],
+                'unsubscribe' => $row['unsubscribe'],
+                'registration_code' => $row['registration_code'],
+                'creation_date' => $row['creation_date'],
+                'visibility' => $row['visibility'],
+                'count_users' => $count_users,
+                'count_connections' => $count_connections_last_month
+            );
+        }
+        return $courses;
+    }
+
     /**
      * unsubscribe the user from a given course
      * @param   string  Course code
@@ -622,4 +720,68 @@ SQL;
 
         return $count;
     }
+
+    /**
+     * Search sessions by the tags in their courses
+     * @param string $termTag Term for search in tags
+     * @param array $limit Limit info
+     * @return array The sessions
+     */
+    public function browseSessionsByTags($termTag, array $limit)
+    {
+        $em = Database::getManager();
+        $qb = $em->createQueryBuilder();
+
+        $sessions = $qb->select('s')
+            ->distinct(true)
+            ->from('ChamiloCoreBundle:Session', 's')
+            ->innerJoin(
+                'ChamiloCoreBundle:SessionRelCourse',
+                'src',
+                \Doctrine\ORM\Query\Expr\Join::WITH,
+                's.id = src.session'
+            )
+            ->innerJoin(
+                'ChamiloCoreBundle:ExtraFieldRelTag',
+                'frt',
+                \Doctrine\ORM\Query\Expr\Join::WITH,
+                'src.course = frt.itemId'
+            )
+            ->innerJoin(
+                'ChamiloCoreBundle:Tag',
+                't',
+                \Doctrine\ORM\Query\Expr\Join::WITH,
+                'frt.tagId = t.id'
+            )
+            ->innerJoin(
+                'ChamiloCoreBundle:ExtraField',
+                'f',
+                \Doctrine\ORM\Query\Expr\Join::WITH,
+                'frt.fieldId = f.id'
+            )
+            ->where(
+                $qb->expr()->like('t.tag', ":tag")
+            )
+            ->andWhere(
+                $qb->expr()->eq('f.extraFieldType', Chamilo\CoreBundle\Entity\ExtraField::COURSE_FIELD_TYPE)
+            )
+            ->setFirstResult($limit['start'])
+            ->setMaxResults($limit['length'])
+            ->setParameter('tag', "$termTag%")
+            ->getQuery()
+            ->getResult();
+
+        $sessionsToBrowse = [];
+
+        foreach ($sessions as $session) {
+            if ($session->getNbrCourses() === 0) {
+                continue;
+            }
+
+            $sessionsToBrowse[] = $session;
+        }
+
+        return $sessionsToBrowse;
+    }
+
 }

+ 1 - 0
main/install/data.sql

@@ -756,6 +756,7 @@ INSERT INTO extra_field (extra_field_type, field_type, variable, display_text, v
 INSERT INTO extra_field (extra_field_type, field_type, variable, display_text, visible, changeable) VALUES (1, 1, 'google_calendar_url','Google Calendar URL',0,0);
 
 INSERT INTO extra_field (extra_field_type, field_type, variable, display_text, visible, changeable, default_value) VALUES (2, 1, 'special_course', 'Special course', 1 , 1, '');
+INSERT INTO extra_field (extra_field_type, field_type, variable, display_text, visible, changeable) VALUES (2, 10, 'tags', 'Tags', 1, 1);
 
 INSERT INTO extra_field_options (field_id, option_value, display_text, option_order) VALUES (8, '1', 'AtOnce',1);
 INSERT INTO extra_field_options (field_id, option_value, display_text, option_order) VALUES (8, '8', 'Daily',2);

+ 58 - 55
main/lang/english/trad4all.inc.php

@@ -325,18 +325,18 @@ $DeleteUsersNotInList = "Unsubscribe students which are not in the imported list
 $IfSessionExistsUpdate = "If a session exists, update it";
 $CreatedByXYOnZ = "Create by <a href=\"%s\">%s</a> on %s";
 $LoginWithExternalAccount = "Login without an institutional account";
-$ImportAikenQuizExplanationExample = "This is the text for question 1
-A. Answer 1
-B. Answer 2
-C. Answer 3
-ANSWER: B
-
-This is the text for question 2
-A. Answer 1
-B. Answer 2
-C. Answer 3
-D. Answer 4
-ANSWER: D
+$ImportAikenQuizExplanationExample = "This is the text for question 1
+A. Answer 1
+B. Answer 2
+C. Answer 3
+ANSWER: B
+
+This is the text for question 2
+A. Answer 1
+B. Answer 2
+C. Answer 3
+D. Answer 4
+ANSWER: D
 ANSWER_EXPLANATION: this is an optional feedback comment that will appear next to the correct answer.";
 $ImportAikenQuizExplanation = "The Aiken format comes in a simple text (.txt) file, with several question blocks, each separated by a blank line. The first line is the question, the answer lines are prefixed by a letter and a dot, and the correct answer comes next with the ANSWER: prefix. See example below.";
 $ExerciseAikenErrorNoAnswerOptionGiven = "The imported file has at least one question without any answer (or the answers do not include the required prefix letter). Please make sure each question has at least one answer and that it is prefixed by a letter and a dot or a parenthesis, like this: A. answer one";
@@ -425,18 +425,18 @@ $VersionUpToDate = "Your version is up-to-date";
 $LatestVersionIs = "The latest version is";
 $YourVersionNotUpToDate = "Your version is not up-to-date";
 $Hotpotatoes = "Hotpotatoes";
-$ZeroMeansNoQuestionWillBeSelectedMinusOneMeansThatAllQuestionsWillBeSelected = "-1 = All questions will be selected.
+$ZeroMeansNoQuestionWillBeSelectedMinusOneMeansThatAllQuestionsWillBeSelected = "-1 = All questions will be selected.
  0 = No questions will be selected.";
-$EmailNotificationTemplateDescription = "You can customize the email sent to users when they finished the exercise. You can use tags like these:
-
-1. {{ student.username }}
-2. {{ student.firstname }}
-3. {{ student.lastname }}
-4. {{ student.official_code }}
-5. {{ exercise.title }}
-6. {{ exercise.start_time }}
-7. {{ exercise.end_time }}
-8. {{ course.title }}
+$EmailNotificationTemplateDescription = "You can customize the email sent to users when they finished the exercise. You can use tags like these:
+
+1. {{ student.username }}
+2. {{ student.firstname }}
+3. {{ student.lastname }}
+4. {{ student.official_code }}
+5. {{ exercise.title }}
+6. {{ exercise.start_time }}
+7. {{ exercise.end_time }}
+8. {{ course.title }}
 9. {{ course.code }}";
 $EmailNotificationTemplate = "Email notification template";
 $ExerciseEndButtonDisconnect = "Logout";
@@ -844,10 +844,10 @@ $AllowVisitors = "Allow visitors";
 $EnableIframeInclusionComment = "Allowing arbitrary iframes in the HTML Editor will enhance the edition capabilities of the users, but it can represent a security risk. Please make sure you can rely on your users (i.e. you know who they are) before enabling this feature.";
 $AddedToLPCannotBeAccessed = "This exercise has been included in a learning path, so it cannot be accessed by students directly from here. If you want to put the same exercise available through the exercises tool, please make a copy of the current exercise using the copy icon.";
 $EnableIframeInclusionTitle = "Allow iframes in HTML Editor";
-$MailTemplateRegistrationMessage = "Dear ((firstname)) ((lastname)),\n\nYou are registered on
-((sitename)) with the following settings:\n\nUsername :
-((username))\nPass : ((password))\n\nThe address of ((sitename)) is :
-((url))\n\nIn case of trouble, contact us.\n\nYours sincerely
+$MailTemplateRegistrationMessage = "Dear ((firstname)) ((lastname)),\n\nYou are registered on
+((sitename)) with the following settings:\n\nUsername :
+((username))\nPass : ((password))\n\nThe address of ((sitename)) is :
+((url))\n\nIn case of trouble, contact us.\n\nYours sincerely
 \n((admin_name)) ((admin_surname)).";
 $Explanation = "Once you click on \"Create a course\", a course is created with a section for Tests, Project based learning, Assessments, Courses, Dropbox, Agenda and much more. Logging in as teacher provides you with editing privileges for this course.";
 $CodeTaken = "This training code is already in use.  <br>Use the <b>Back</b> button on your browser and try again";
@@ -2640,16 +2640,16 @@ $NoPosts = "No posts";
 $WithoutAchievedSkills = "Without achieved skills";
 $TypeMessage = "Please type your message!";
 $ConfirmReset = "Do you really want to delete all messages?";
-$MailCronCourseExpirationReminderBody = "Dear %s,
-
-It has come to our attention that you have not completed the course %s although its expiration date had been set on %s, remaining %s days to finish it.
-
-We remind you that you have only the possibility to follow this course once a year, that is why we invite you insistently to complete your course on time.
-
-You can return to the course connecting to the platform through this address: %s
-
-Best Regards,
-
+$MailCronCourseExpirationReminderBody = "Dear %s,
+
+It has come to our attention that you have not completed the course %s although its expiration date had been set on %s, remaining %s days to finish it.
+
+We remind you that you have only the possibility to follow this course once a year, that is why we invite you insistently to complete your course on time.
+
+You can return to the course connecting to the platform through this address: %s
+
+Best Regards,
+
 %s Team";
 $MailCronCourseExpirationReminderSubject = "Urgent: %s course expiration reminder";
 $ExerciseAndLearningPath = "Exercise and learning path";
@@ -5778,8 +5778,8 @@ $CheckThatYouHaveEnoughQuestionsInYourCategories = "Make sure you have enough qu
 $PortalCoursesLimitReached = "Sorry, this installation has a courses limit, which has now been reached. To increase the number of courses allowed on this Chamilo installation, please contact your hosting provider or, if available, upgrade to a superior hosting plan.";
 $PortalTeachersLimitReached = "Sorry, this installation has a teachers limit, which has now been reached. To increase the number of teachers allowed on this Chamilo installation, please contact your hosting provider or, if available, upgrade to a superior hosting plan.";
 $PortalUsersLimitReached = "Sorry, this installation has a users limit, which has now been reached. To increase the number of users allowed on this Chamilo installation, please contact your hosting provider or, if available, upgrade to a superior hosting plan.";
-$GenerateSurveyAccessLinkExplanation = "By copying the link below and pasting it in an e-mail or on a website, you will allow any anonymous person to enter and answer this survey.
-You can test this feature by clicking the link above and answering the survey.
+$GenerateSurveyAccessLinkExplanation = "By copying the link below and pasting it in an e-mail or on a website, you will allow any anonymous person to enter and answer this survey.
+You can test this feature by clicking the link above and answering the survey.
 This is particularly useful if you want to allow anyone on a forum to answer you survey and you don't know their e-mail addresses.";
 $LinkOpenSelf = "Open self";
 $LinkOpenBlank = "Open blank";
@@ -5832,8 +5832,8 @@ $Item = "Item";
 $ConfigureDashboardPlugin = "Configure Dashboard Plugin";
 $EditBlocks = "Edit blocks";
 $Never = "Never";
-$YourAccountIsActiveYouCanLoginAndCheckYourCourses = "Dear user, 
-
+$YourAccountIsActiveYouCanLoginAndCheckYourCourses = "Dear user, 
+
 Your account has now been activated on the platform. Please login and enjoy your courses.";
 $SessionFields = "Session fields";
 $CopyLabelSuffix = "Copy";
@@ -5895,7 +5895,7 @@ $CourseSettingsRegisterDirectLink = "If your course is public or open, you can u
 $DirectLink = "Direct link";
 $here = "here";
 $GoAheadAndBrowseOurCourseCatalogXOnceRegisteredYouWillSeeTheCourseHereX = "<p>Go ahead and browse our course catalog %s to register to any course you like. Once registered, you will see the course appear right %s, instead of this message.</p>";
-$HelloXAsYouCanSeeYourCourseListIsEmpty = "<p>Hello <strong>%s</strong> and welcome,</p>
+$HelloXAsYouCanSeeYourCourseListIsEmpty = "<p>Hello <strong>%s</strong> and welcome,</p>
 <p>As you can see, your courses list is still empty. That's because you are not registered to any course yet! </p>";
 $UnsubscribeUsersAlreadyAddedInCourse = "Unsubscribe users already added";
 $ImportUsers = "Import users";
@@ -6159,7 +6159,7 @@ $AverageScore = "Average score";
 $LastConnexionDate = "Last connexion date";
 $ToolVideoconference = "Videoconference";
 $BigBlueButtonEnableTitle = "BigBlueButton videoconference tool";
-$BigBlueButtonEnableComment = "Choose whether you want to enable the BigBlueButton videoconference tool. Once enabled, it will show as an additional course tool in all courses' homepage, and teachers will be able to launch a conference at any time. Learners will not be able to launch a conference, only join one. If you don't have a BigBlueButton server, please <a href=\"http://bigbluebutton.org/\" target=\"_blank\">set one up</a> or ask the <a href=\"http://www.chamilo.org/en/providers\" target=\"_blank\">Chamilo official providers</a> for a quote.
+$BigBlueButtonEnableComment = "Choose whether you want to enable the BigBlueButton videoconference tool. Once enabled, it will show as an additional course tool in all courses' homepage, and teachers will be able to launch a conference at any time. Learners will not be able to launch a conference, only join one. If you don't have a BigBlueButton server, please <a href=\"http://bigbluebutton.org/\" target=\"_blank\">set one up</a> or ask the <a href=\"http://www.chamilo.org/en/providers\" target=\"_blank\">Chamilo official providers</a> for a quote.
 BigBlueButton is a free (as in freedom *and* beer), but its installation requires a set of technical skills that might not be immediately available to all. You can install it on your own or seek professional help to assist you or do it for you. This help, however, will generate a certain cost. In the pure logic of the free software, we offer you the tools to make your work easier and recommend professionals (the Chamilo Official Providers) that will be able to help you if this were too difficult.";
 $BigBlueButtonHostTitle = "BigBlueButton server host";
 $BigBlueButtonHostComment = "This is the name of the server where your BigBlueButton server is running. Might be <i>localhost</i>, an IP address (e.g. 192.168.13.54) or a domain name (e.g. my.video.com).";
@@ -6170,14 +6170,14 @@ $OnlyAccessFromYourGroup = "Only accessible from your group";
 $CreateAssignmentPage = "This will create a special wiki page in which the teacher can describe the task and which will be automatically linked to the wiki pages where learners perform the task. Both the teacher's and the learners' pages are created automatically. In these tasks, learners can only edit and view theirs pages, but this can be changed easily if you need to.";
 $UserFolders = "Folders of users";
 $UserFolder = "User folder";
-$HelpUsersFolder = "INFORMATION VISIBLE TO THE TEACHER ONLY:\nThe users folder contains a folder for each user who has accessed it through the documents tool, or when any file has been sent in the course through the online editor. If neither circumstances has occurred, then no user folder will have been created. In the case of groups, files that are sent through the editor will be added in the folder of each group, which is only accessible by students from this group.
-<br /><br />
-The users folder and each of the included folders will be hidden by default in for all students, but each student can see the contents of his/her directory through the online editor. However, if a student knows the address of a file or folder of another student, he may be able to access it.
-<br /><br />
-If the folder of a student is visible, other students can see what it contains. In this case, the student that owns the folder can also (from the documents tool and only in his/her folder): create and edit web documents, convert a document into a template for personal use, create and edit drawings in SVG and PNG formats, record audio files in WAV format, make audio files in MP3 from a text, make snapshops from a webcam, send documents, create folders, move folders and files, delete folders and files, and download backup of his/her folder.
-<br /><br />
-Moreover, the documents tool is synchronized with the file manager of the online editor, so changes in the documents triggered in any one of these will affect both.
-<br /><br />
+$HelpUsersFolder = "INFORMATION VISIBLE TO THE TEACHER ONLY:\nThe users folder contains a folder for each user who has accessed it through the documents tool, or when any file has been sent in the course through the online editor. If neither circumstances has occurred, then no user folder will have been created. In the case of groups, files that are sent through the editor will be added in the folder of each group, which is only accessible by students from this group.
+<br /><br />
+The users folder and each of the included folders will be hidden by default in for all students, but each student can see the contents of his/her directory through the online editor. However, if a student knows the address of a file or folder of another student, he may be able to access it.
+<br /><br />
+If the folder of a student is visible, other students can see what it contains. In this case, the student that owns the folder can also (from the documents tool and only in his/her folder): create and edit web documents, convert a document into a template for personal use, create and edit drawings in SVG and PNG formats, record audio files in WAV format, make audio files in MP3 from a text, make snapshops from a webcam, send documents, create folders, move folders and files, delete folders and files, and download backup of his/her folder.
+<br /><br />
+Moreover, the documents tool is synchronized with the file manager of the online editor, so changes in the documents triggered in any one of these will affect both.
+<br /><br />
 As such, the user folder is not only a place to deposit files, it becomes a complete manager of the documents students use during the course. Also, remember that any user can copy a file that is visible from any folder in the documents tool (whether or not he is the owner) to his/her portfolios or personal documents area of social network, which will be available to him/her for use in other courses.";
 $HelpFolderChat = "INFORMATION VISIBLE TO THE TEACHER ONLY:\nThis folder contains all sessions that have been opened in the chat. Although the chat sessions can often be trivial, others can be really interesting and worthy of being incorporated as an additional work document. To do this without changing the visibility of this folder, make the file visible and link it from where you deem appropriate. It is not recommended to make this folder visible to all.";
 $HelpFolderCertificates = "INFORMATION VISIBLE TO THE TEACHER ONLY:\nThis folder contains the various certificates templates that have been created for the rating tool. It is not recommended to make this folder visible to all.";
@@ -6227,8 +6227,8 @@ $Pediaphon = "Use Pediaphon audio services";
 $HelpPediaphon = "Supports text with several thousands characters, in various types of male and female voices (depending on the language). Audio files will be generated and automatically saved to the Chamilo directory in which you are.";
 $FirstSelectALanguage = "Please select a language";
 $MoveUserStats = "Move users results from/to a session";
-$CompareUserResultsBetweenCoursesAndCoursesInASession = "This advanced tool allows you to manually improve the tracking of users results when moving from courses methodology to sessions methodology. In most cases, you won't need to use it.<br />
-On this screen, you can compare results of users between the context of a standalone course, and the context of the same course inside a session.<br />
+$CompareUserResultsBetweenCoursesAndCoursesInASession = "This advanced tool allows you to manually improve the tracking of users results when moving from courses methodology to sessions methodology. In most cases, you won't need to use it.<br />
+On this screen, you can compare results of users between the context of a standalone course, and the context of the same course inside a session.<br />
 Once you are sure about what to do, you can choose to move the tracking data of the students (exercises results and learning paths tracking) from a course to a session.";
 $PDFExportWatermarkEnableTitle = "Enable watermark in PDF export";
 $PDFExportWatermarkEnableComment = "By enabling this option, you can upload an image or a text that will be automatically added as watermark to all PDF exports of documents on the system.";
@@ -6363,8 +6363,8 @@ $MailNotifyInvitation = "Notify by mail on new invitation received";
 $MailNotifyMessage = "Notify by mail on new personal message received";
 $MailNotifyGroupMessage = "Notify by mail on new message received in group";
 $SearchEnabledTitle = "Fulltext search";
-$SearchEnabledComment = "This feature allows you to index most of the documents uploaded to your portal, then provide a search feature for users.<br />
-This feature will not index documents that have already been uploaded, so it is important to enable (if wanted) at the beginning of your implementation.<br />
+$SearchEnabledComment = "This feature allows you to index most of the documents uploaded to your portal, then provide a search feature for users.<br />
+This feature will not index documents that have already been uploaded, so it is important to enable (if wanted) at the beginning of your implementation.<br />
 Once enabled, a search box will appear in the courses list of every user. Searching for a specific term will bring a list of corresponding documents, exercises or forum topics, filtered depending on the availability of these contents to the user.";
 $SpecificSearchFieldsAvailable = "Available custom search fields";
 $XapianModuleInstalled = "Xapian module installed";
@@ -7357,4 +7357,7 @@ $LevelX = "Level %s";
 $SeeCourse = "View course";
 $XPoints = "%s points";
 $FromXUntilY = "From %s until %s";
+$CreateForumForThisLearningPath = "Create forum for this learning path";
+$ByDate = "By date";
+$ByTag = "By tag";
 ?>

Разница между файлами не показана из-за своего большого размера
+ 56 - 56
main/lang/spanish/trad4all.inc.php


+ 185 - 156
main/template/default/auth/session_catalog.tpl

@@ -1,187 +1,216 @@
 {% extends template ~ "/layout/main.tpl" %}
 
 {% block body %}
-<script type="text/javascript">
-    $(document).ready(function() {
-        $('#date').datepicker({
-            dateFormat: 'yy-mm-dd'
-        });
-
-        $('a[data-session]').on('click', function(e) {
-            e.preventDefault();
+    <script type="text/javascript">
+        $(document).ready(function () {
+            $('#date').datepicker({
+                dateFormat: 'yy-mm-dd'
+            });
 
-            var link = $(this),
-                sessionId = parseInt(link.data('session')),
-                collapsible = $('#collapse-' + sessionId),
-                courseList = link.data('courses') || [];
+            $('a[data-session]').on('click', function (e) {
+                e.preventDefault();
 
-            if (courseList.length === 0) {
-                var getCourseList = $.getJSON(
-                    '{{ web_session_courses_ajax_url }}',
-                    {
-                        a: 'display_sessions_courses',
-                        session: sessionId
-                    }
-                );
+                var link = $(this),
+                        sessionId = parseInt(link.data('session')),
+                        collapsible = $('#collapse-' + sessionId),
+                        courseList = link.data('courses') || [];
 
-                $.when(getCourseList).done(function(courses) {
-                    courseList = courses;
-                    link.data('courses', courses);
+                if (courseList.length === 0) {
+                    var getCourseList = $.getJSON(
+                            '{{ _p.web_ajax }}course.ajax.php',
+                            {
+                                a: 'display_sessions_courses',
+                                session: sessionId
+                            }
+                    );
 
-                    var coursesUL = '';
+                    $.when(getCourseList).done(function (courses) {
+                        courseList = courses;
+                        link.data('courses', courses);
 
-                    $.each(courseList, function(index, course) {
-                        coursesUL += '<li><img src="{{ _p.web }}main/img/check.png"/> <strong>' + course.name + '</strong>';
+                        var coursesUL = '';
 
-                        if (course.coachName !== '') {
-                            coursesUL += ' (' + course.coachName + ')';
-                        }
+                        $.each(courseList, function (index, course) {
+                            coursesUL += '<li><img src="{{ _p.web }}main/img/check.png"/> <strong>' + course.name + '</strong>';
 
-                        coursesUL += '</li>';
-                    });
+                            if (course.coachName !== '') {
+                                coursesUL += ' (' + course.coachName + ')';
+                            }
 
-                    collapsible.html('<div class="panel-body"><ul class="list-unstyled items-session">' + coursesUL + '</ul></div>');
+                            coursesUL += '</li>';
+                        });
 
-                    collapsible.collapse('show');
-                });
-            } else {
-                collapsible.collapse('toggle');
-            }
-        });
+                        collapsible.html('<div class="panel-body"><ul class="list-unstyled items-session">' + coursesUL + '</ul></div>');
 
-        $('.collapse').collapse('hide');
-    });
-</script>
-
-<div class="col-md-3">
-    {% if show_courses %}
-    <div class="panel panel-default">
-        <div class="panel-body">
-            {% if not hidden_links %}
-            <form class="form-search" method="post" action="{{ course_url }}">
-                <input type="hidden" name="sec_token" value="{{ search_token }}">
-                <input type="hidden" name="search_course" value="1" />
-                <div class="form-group">
-                    <input  type="text" name="search_term" class="form-control"/>
-                    <button class="btn btn-block btn-default" type="submit"><i class="fa fa-search"></i> {{ 'Search' | get_lang }}</button>
-                </div>
-            </form>
-            {% endif %}
+                        collapsible.collapse('show');
+                    });
+                } else {
+                    collapsible.collapse('toggle');
+                }
+            });
 
-            {% if course_category_list is not empty %}
-            <a class="btn btn-block btn-default" href="{{ api_get_self }}?action=display_random_courses">{{ 'RandomPick' | get_lang }}</a>
-            {% endif %}
-        </div>
-    </div>
+            $('.collapse').collapse('hide');
+        });
+    </script>
 
-    {% if coursesCategoriesList is not empty %}
-        <div class="sidebar-nav">
+    <div class="col-md-3">
+        {% if show_courses %}
             <div class="panel panel-default">
-                <div class="panel-heading">
-                    {{ 'CourseCategories' | get_lang }}
-                </div>
+                <div class="panel-heading">{{ "Courses"|get_lang }}</div>
                 <div class="panel-body">
-                    <ul class="list-categories">
-                        {{ coursesCategoriesList }}
-                    </ul>
+                    {% if not hidden_links %}
+                        <div class="row">
+                            <div class="col-xs-12">
+                                <form class="form-search" method="post" action="{{ course_url }}">
+                                    <div class="input-group">
+                                        <input type="text" name="search_term" class="form-control" />
+                                        <input type="hidden" name="sec_token" value="{{ search_token }}">
+                                        <input type="hidden" name="search_course" value="1" />
+                                        <span class="input-group-btn">
+                                            <button class="btn btn-default" type="submit"><i class="fa fa-search"></i> {{ 'Search'|get_lang }}</button>
+                                        </span>
+                                    </div>
+                                </form>
+                            </div>
+                        </div>
+                    {% endif %}
+
+                    {% if course_category_list is not empty %}
+                        <br>
+                        <a class="btn btn-block btn-default" href="{{ _p.web_self }}?action=display_random_courses">{{ 'RandomPick'|get_lang }}</a>
+                    {% endif %}
                 </div>
             </div>
-        </div>
-    {% endif %}
-{% endif %}
-
-{% if show_sessions %}
-    <div class="sidebar-nav">
-        <div class="panel panel-default">
-            <div class="panel-heading">
-                {{ 'Sessions' | get_lang }}
-            </div>
-            <div class="panel-body">
-                <form class="form-search" method="post" action="{{ api_get_self }}?action=display_sessions">
-                    <div class="form-group">
-                        <input type="date" name="date" id="date" class="form-control" value="{{ search_date }}" readonly>
-                        <button class="btn btn-block btn-default" type="submit"><i class="fa fa-search"></i> {{ 'Search' | get_lang }}</button>
+
+            {% if coursesCategoriesList is not empty %}
+                <div class="sidebar-nav">
+                    <div class="panel panel-default">
+                        <div class="panel-heading">
+                            {{ 'CourseCategories'|get_lang }}
+                        </div>
+                        <div class="panel-body">
+                            <ul class="list-categories">
+                                {{ coursesCategoriesList }}
+                            </ul>
+                        </div>
+                    </div>
+                </div>
+            {% endif %}
+        {% endif %}
+
+        {% if show_sessions %}
+            <div class="sidebar-nav">
+                <div class="panel panel-default">
+                    <div class="panel-heading">
+                        {{ 'Sessions'|get_lang }}
                     </div>
-                </form>
+                    <div class="panel-body">
+                        <div class="row">
+                            <div class="col-xs-12">
+                                <form class="form-search" method="post" action="{{ _p.web_self }}?action=display_sessions">
+                                    <fieldset>
+                                        <legend>{{ "ByDate"|get_lang }}</legend>
+                                        <div class="input-group">
+                                            <input type="date" name="date" id="date" class="form-control" value="{{ search_date }}" readonly>
+                                            <span class="input-group-btn">
+                                                <button class="btn btn-default" type="submit"><i class="fa fa-search"></i> {{ 'Search'|get_lang }}</button>
+                                            </span>
+                                        </div>
+                                    </fieldset>
+                                </form>
+                                <br>
+                                <form class="form-search" method="post" action="{{ _p.web_self }}?action=search_tag">
+                                    <fieldset>
+                                        <legend>{{ "ByTag"|get_lang }}</legend>
+                                        <div class="input-group">
+                                            <input type="text" name="search_tag" class="form-control" value="{{ search_tag }}" />
+                                            <span class="input-group-btn">
+                                                <button class="btn btn-default" type="submit"><i class="fa fa-search"></i> {{ 'Search'|get_lang }}</button>
+                                            </span>
+                                        </div>
+                                    </fieldset>
+                                </form>
+                            </div>
+                        </div>
+                    </div>
+                </div>
             </div>
-        </div>
+        {% endif %}
     </div>
-{% endif %}
-</div>
-<div class="col-md-9">
-    {% for session in sessions %}
-
-        <div class="panel panel-default" id="panel-{{ session.id }}">
-            <div class="panel-heading">
-                {{ session.icon }} {{ session.name }}
-            </div>
-            <div class="panel-body">
-                <div class="row">
-                    <div class="col-md-9">
-                        {% if show_tutor %}
-                        <p class="tutor">
-                            <img src="{{ 'teacher.png' | icon(22) }}" width="16">
-                            {{ 'GeneralCoach' | get_lang }} {{ session.coach_name }}
-                        </p>
-                        {% endif %}
-
-                        {% if session.requirements %}
-                            <h4>{{ 'Requirements' | get_lang }}</h4>
-                            <p>
-                            {% for requirement in session.requirements %}
-                                {{ requirement.name  }}
-                            {% endfor %}
-                            </p>
-                        {% endif %}
-
-                        {% if session.dependencies %}
-                            <h4>{{ 'Dependencies' | get_lang }}</h4>
-                            <p>
-                            {% for dependency in session.dependencies %}
-                                {{ dependency.name  }}
-                            {% endfor %}
-                            </p>
-                        {% endif %}
-
-                        <div class="panel-group" role="tablist">
-                            <div class="panel panel-default">
-                                <div class="panel-heading" role="tab" id="heading-session-{{ session.id }}">
-                                    <h4 class="panel-title">
-                                        <a class="collapsed" data-session="{{ session.id }}" data-toggle="false" href="#collapse-{{ session.id }}" aria-expanded="true" aria-controls="collapse-{{ session.id }}">
-                                            {{ 'CourseList' | get_lang }}
-                                        </a>
-                                    </h4>
+    <div class="col-md-9">
+        {% for session in sessions %}
+            <div class="panel panel-default" id="panel-{{ session.id }}">
+                <div class="panel-heading">
+                    {{ session.icon }} {{ session.name }}
+                </div>
+                <div class="panel-body">
+                    <div class="row">
+                        <div class="col-md-9">
+                            {% if show_tutor %}
+                                <p class="tutor">
+                                    <img src="{{ 'teacher.png' | icon(22) }}" width="16">
+                                    {{ 'GeneralCoach'|get_lang }} {{ session.coach_name }}
+                                </p>
+                            {% endif %}
+
+                            {% if session.requirements %}
+                                <h4>{{ 'Requirements'|get_lang }}</h4>
+                                <p>
+                                    {% for requirement in session.requirements %}
+                                        {{ requirement.name  }}
+                                    {% endfor %}
+                                </p>
+                            {% endif %}
+
+                            {% if session.dependencies %}
+                                <h4>{{ 'Dependencies'|get_lang }}</h4>
+                                <p>
+                                    {% for dependency in session.dependencies %}
+                                        {{ dependency.name  }}
+                                    {% endfor %}
+                                </p>
+                            {% endif %}
+
+                            <div class="panel-group" role="tablist">
+                                <div class="panel panel-default">
+                                    <div class="panel-heading" role="tab" id="heading-session-{{ session.id }}">
+                                        <h4 class="panel-title">
+                                            <a class="collapsed" data-session="{{ session.id }}" data-toggle="false" href="#collapse-{{ session.id }}" aria-expanded="true" aria-controls="collapse-{{ session.id }}">
+                                                {{ 'CourseList'|get_lang }}
+                                            </a>
+                                        </h4>
+                                    </div>
+                                    <div id="collapse-{{ session.id }}" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="heading-session-{{ session.id }}"></div>
                                 </div>
-                                <div id="collapse-{{ session.id }}" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="heading-session-{{ session.id }}"></div>
                             </div>
                         </div>
-                    </div>
-                    <div class="col-md-3">
-                        {% if session.show_description %}
-                        <p class="buttom-subscribed">
-                            <a class="ajax btn btn-large btn-info" href="{{ _p.web_ajax }}session.ajax.php?a=get_description&session={{ session.id }}">
-                                {{ 'Description' | get_lang }}
-                            </a>
-                        </p>
-                        {% endif %}
-
-                        <p class="buttom-subscribed">
-                            {% if session.is_subscribed %}
-                                {{ already_subscribed_label }}
-                            {% else %}
-                                {{ session.subscribe_button }}
+                        <div class="col-md-3">
+                            {% if session.show_description %}
+                                <p class="buttom-subscribed">
+                                    <a class="ajax btn btn-large btn-info" href="{{ _p.web_ajax }}session.ajax.php?a=get_description&session={{ session.id }}">
+                                        {{ 'Description'|get_lang }}
+                                    </a>
+                                </p>
                             {% endif %}
-                        </p>
-                        <p class="time">
-                            <img src="{{ 'agenda.png' | icon(22) }}"> {{ session.date }}
-                        </p>
+
+                            <p class="buttom-subscribed">
+                                {% if session.is_subscribed %}
+                                    {{ already_subscribed_label }}
+                                {% else %}
+                                    {{ session.subscribe_button }}
+                                {% endif %}
+                            </p>
+                            <p class="time">
+                                <img src="{{ 'agenda.png' | icon(22) }}"> {{ session.date }}
+                            </p>
+                        </div>
                     </div>
                 </div>
-
             </div>
-        </div>
-    {% endfor %}
-    {{ catalog_pagination }}
-</div>
+        {% else %}
+            {{ message }}
+        {% endfor %}
+        {{ catalog_pagination }}
+    </div>
 
 {% endblock %}

+ 35 - 0
src/Chamilo/CoreBundle/Migrations/Schema/V110/Version20150609113500.php

@@ -0,0 +1,35 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace Chamilo\CoreBundle\Migrations\Schema\V110;
+
+use Chamilo\CoreBundle\Migrations\AbstractMigrationChamilo;
+use Doctrine\DBAL\Schema\Schema;
+
+/**
+ * Session date changes
+ */
+class Version20150609113500 extends AbstractMigrationChamilo
+{
+    /**
+     * @param Schema $schema
+     */
+    public function up(Schema $schema)
+    {
+        $this->addSql("INSERT INTO extra_field
+            (extra_field_type, field_type, variable, display_text, visible, changeable)
+            VALUES (2, 10, 'tags', 'Tags', 1, 1)");
+    }
+
+    /**
+     * @param Schema $schema
+     */
+    public function down(Schema $schema)
+    {
+        $this->addSql("DELETE FROM extra_field
+            WHERE variable = 'tags' AND
+                extra_field_type = 2 AND
+                field_type = 10");
+    }
+
+}

Некоторые файлы не были показаны из-за большого количества измененных файлов