Merge branch 'MDL-64656-master' of git://github.com/jleyva/moodle
authorEloy Lafuente (stronk7) <stronk7@moodle.org>
Thu, 11 Apr 2019 18:12:13 +0000 (20:12 +0200)
committerEloy Lafuente (stronk7) <stronk7@moodle.org>
Thu, 11 Apr 2019 18:12:13 +0000 (20:12 +0200)
1  2 
course/externallib.php
lib/db/services.php
mod/forum/externallib.php
mod/forum/tests/externallib_test.php
mod/forum/upgrade.txt
version.php

diff --combined course/externallib.php
@@@ -494,6 -494,10 +494,10 @@@ class core_course_external extends exte
                                                    'userid' => new external_value(PARAM_INT, 'User who added this content to moodle'),
                                                    'author' => new external_value(PARAM_TEXT, 'Content owner'),
                                                    'license' => new external_value(PARAM_TEXT, 'Content license'),
+                                                   'tags' => new external_multiple_structure(
+                                                        \core_tag\external\tag_item_exporter::get_read_structure(), 'Tags',
+                                                             VALUE_OPTIONAL
+                                                    ),
                                                )
                                            ), VALUE_DEFAULT, array()
                                        ),
              if (!isset($excludedcats[$category->id])) {
  
                  // Final check to see if the category is visible to the user.
 -                if ($category->visible or has_capability('moodle/category:viewhiddencategories', $context)) {
 +                if (core_course_category::can_view_category($category)) {
  
                      $categoryinfo = array();
                      $categoryinfo['id'] = $category->id;
                      'Optional list of required capabilities (used to filter the list)', VALUE_DEFAULT, array()
                  ),
                  'limittoenrolled' => new external_value(PARAM_BOOL, 'limit to enrolled courses', VALUE_DEFAULT, 0),
 +                'onlywithcompletion' => new external_value(PARAM_BOOL, 'limit to courses where completion is enabled',
 +                    VALUE_DEFAULT, 0),
              )
          );
      }
       * @param int $perpage          Items per page
       * @param array $requiredcapabilities Optional list of required capabilities (used to filter the list).
       * @param int $limittoenrolled  Limit to only enrolled courses
 +     * @param int onlywithcompletion Limit to only courses where completion is enabled
       * @return array of course objects and warnings
       * @since Moodle 3.0
       * @throws moodle_exception
                                            $page=0,
                                            $perpage=0,
                                            $requiredcapabilities=array(),
 -                                          $limittoenrolled=0) {
 +                                          $limittoenrolled=0,
 +                                          $onlywithcompletion=0) {
          global $CFG;
  
          $warnings = array();
              'criteriavalue' => $criteriavalue,
              'page'          => $page,
              'perpage'       => $perpage,
 -            'requiredcapabilities' => $requiredcapabilities
 +            'requiredcapabilities' => $requiredcapabilities,
 +            'limittoenrolled' => $limittoenrolled,
 +            'onlywithcompletion' => $onlywithcompletion
          );
          $params = self::validate_parameters(self::search_courses_parameters(), $parameters);
          self::validate_context(context_system::instance());
          // Prepare the search API options.
          $searchcriteria = array();
          $searchcriteria[$params['criterianame']] = $params['criteriavalue'];
 +        if ($params['onlywithcompletion']) {
 +            $searchcriteria['onlywithcompletion'] = true;
 +        }
  
          $options = array();
          if ($params['perpage'] != 0) {
              }
              // Get the public course information, even if we are not enrolled.
              $courseinlist = new core_course_list_element($course);
 -            $coursesdata[$course->id] = self::get_course_public_information($courseinlist, $context);
  
              // Now, check if we have access to the course.
              try {
                  self::validate_context($context);
              } catch (Exception $e) {
 +                // User can not access the course, check if they can see the public information about the course and return it.
 +                if (core_course_category::can_view_course_info($course)) {
 +                    $coursesdata[$course->id] = self::get_course_public_information($courseinlist, $context);
 +                }
                  continue;
              }
 +            $coursesdata[$course->id] = self::get_course_public_information($courseinlist, $context);
              // Return information for any user that can access the course.
              $coursefields = array('format', 'showgrades', 'newsitems', 'startdate', 'enddate', 'maxbytes', 'showreports', 'visible',
                  'groupmode', 'groupmodeforce', 'defaultgroupingid', 'enablecompletion', 'completionnotify', 'lang', 'theme',
diff --combined lib/db/services.php
@@@ -74,33 -74,6 +74,33 @@@ $functions = array
          'ajax'          => true,
          'loginrequired' => false,
      ),
 +    'core_backup_get_async_backup_progress' => array(
 +        'classname'   => 'core_backup_external',
 +        'classpath' => 'backup/externallib.php',
 +        'methodname'  => 'get_async_backup_progress',
 +        'description' => 'Get the progress of an Asyncronhous backup.',
 +        'type'        => 'read',
 +        'ajax'          => true,
 +        'loginrequired' => true,
 +    ),
 +    'core_backup_get_async_backup_links_backup' => array(
 +        'classname'   => 'core_backup_external',
 +        'classpath' => 'backup/externallib.php',
 +        'methodname'  => 'get_async_backup_links_backup',
 +        'description' => 'Gets the data to use when updating the status table row in the UI for when an async backup completes.',
 +        'type'        => 'read',
 +        'ajax'          => true,
 +        'loginrequired' => true,
 +   ),
 +   'core_backup_get_async_backup_links_restore' => array(
 +        'classname'   => 'core_backup_external',
 +        'classpath' => 'backup/externallib.php',
 +        'methodname'  => 'get_async_backup_links_restore',
 +        'description' => 'Gets the data to use when updating the status table row in the UI for when an async restore completes.',
 +        'type'        => 'read',
 +        'ajax'          => true,
 +        'loginrequired' => true,
 +    ),
      'core_badges_get_user_badges' => array(
          'classname'     => 'core_badges_external',
          'methodname'    => 'get_user_badges',
          'description' => 'Gets tag index page for one tag and one tag area',
          'type' => 'read',
          'ajax' => true,
+         'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
      ),
      'core_tag_get_tags' => array(
          'classname' => 'core_tag_external',
          'type' => 'write',
          'ajax' => true,
      ),
+     'core_tag_get_tagindex_per_area' => array(
+         'classname' => 'core_tag_external',
+         'methodname' => 'get_tagindex_per_area',
+         'description' => 'Gets tag index page per different areas.',
+         'type' => 'read',
+         'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
+     ),
+     'core_tag_get_tag_areas' => array(
+         'classname' => 'core_tag_external',
+         'methodname' => 'get_tag_areas',
+         'description' => 'Retrieves existing tag areas.',
+         'type' => 'read',
+         'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
+     ),
+     'core_tag_get_tag_collections' => array(
+         'classname' => 'core_tag_external',
+         'methodname' => 'get_tag_collections',
+         'description' => 'Retrieves existing tag collections.',
+         'type' => 'read',
+         'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
+     ),
+     'core_tag_get_tag_cloud' => array(
+         'classname' => 'core_tag_external',
+         'methodname' => 'get_tag_cloud',
+         'description' => 'Retrieves a tag cloud for the given collection and/or query search.',
+         'type' => 'read',
+         'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
+     ),
      'core_update_inplace_editable' => array(
          'classname' => 'core_external',
          'methodname' => 'update_inplace_editable',
@@@ -127,8 -127,6 +127,8 @@@ class mod_forum_external extends extern
                      'intro' => new external_value(PARAM_RAW, 'The forum intro'),
                      'introformat' => new external_format_value('intro'),
                      'introfiles' => new external_files('Files in the introduction text', VALUE_OPTIONAL),
 +                    'duedate' => new external_value(PARAM_INT, 'duedate for the user', VALUE_OPTIONAL),
 +                    'cutoffdate' => new external_value(PARAM_INT, 'cutoffdate for the user', VALUE_OPTIONAL),
                      'assessed' => new external_value(PARAM_INT, 'Aggregate type'),
                      'assesstimestart' => new external_value(PARAM_INT, 'Assess start time'),
                      'assesstimefinish' => new external_value(PARAM_INT, 'Assess finish time'),
              if (!empty($messageinlinefiles)) {
                  $post->messageinlinefiles = $messageinlinefiles;
              }
+             // Post tags.
+             $post->tags = \core_tag\external\util::get_item_tags('mod_forum', 'forum_posts', $post->id);
  
              $posts[] = $post;
          }
                                  'userpictureurl' => new external_value(PARAM_URL, 'Post author picture.', VALUE_OPTIONAL),
                                  'deleted' => new external_value(PARAM_BOOL, 'This post has been removed.'),
                                  'isprivatereply' => new external_value(PARAM_BOOL, 'The post is a private reply'),
+                                 'tags' => new external_multiple_structure(
+                                     \core_tag\external\tag_item_exporter::get_read_structure(), 'Tags', VALUE_OPTIONAL
+                                 ),
                              ), 'post'
                          )
                      ),
@@@ -260,6 -260,7 +260,7 @@@ class mod_forum_external_testcase exten
  
          $record->parent = $discussion1reply1->id;
          $record->userid = $user3->id;
+         $record->tags = array('Cats', 'Dogs');
          $discussion1reply2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
  
          // Enrol the user in the  course.
              'userpictureurl' => '',
              'deleted' => false,
              'isprivatereply' => false,
+             'tags' => \core_tag\external\util::get_item_tags('mod_forum', 'forum_posts', $discussion1reply2->id),
          );
+         // Cast to expected.
+         $this->assertCount(2, $expectedposts['posts'][0]['tags']);
+         $expectedposts['posts'][0]['tags'][0]['isstandard'] = (bool) $expectedposts['posts'][0]['tags'][0]['isstandard'];
+         $expectedposts['posts'][0]['tags'][1]['isstandard'] = (bool) $expectedposts['posts'][0]['tags'][1]['isstandard'];
  
          $expectedposts['posts'][] = array(
              'id' => $discussion1reply1->id,
              'userpictureurl' => '',
              'deleted' => false,
              'isprivatereply' => false,
+             'tags' => array(),
          );
  
          // Test a discussion with two additional posts (total 3 posts).
          $this->assertTrue($result['status']);
          $this->assertTrue($result['canpindiscussions']);
          $this->assertTrue($result['cancreateattachment']);
 +    }
 +
 +    /*
 +     * A basic test to make sure users cannot post to forum after the cutoff date.
 +     */
 +    public function test_can_add_discussion_after_cutoff() {
 +        $this->resetAfterTest(true);
 +
 +        // Create courses to add the modules.
 +        $course = self::getDataGenerator()->create_course();
 +
 +        $user = self::getDataGenerator()->create_user();
 +
 +        // Create a forum with cutoff date set to a past date.
 +        $forum = self::getDataGenerator()->create_module('forum', ['course' => $course->id, 'cutoffdate' => time() - 1]);
  
 +        // User with no mod/forum:canoverridecutoff capability.
 +        self::setUser($user);
 +        $this->getDataGenerator()->enrol_user($user->id, $course->id);
 +
 +        $result = mod_forum_external::can_add_discussion($forum->id);
 +        $result = external_api::clean_returnvalue(mod_forum_external::can_add_discussion_returns(), $result);
 +        $this->assertFalse($result['status']);
 +
 +        self::setAdminUser();
 +        $result = mod_forum_external::can_add_discussion($forum->id);
 +        $result = external_api::clean_returnvalue(mod_forum_external::can_add_discussion_returns(), $result);
 +        $this->assertTrue($result['status']);
      }
  
      /**
diff --combined mod/forum/upgrade.txt
@@@ -9,8 -9,7 +9,8 @@@ information provided here is intended e
    * The get_forum_discussion_posts web service has been deprecated in favour of get_discussion_posts.
    * The forum_count_replies function has been deprecated in favour of get_reply_count_for_post_id_in_discussion_id in
      the Post vault.
-   * External function get_forums_by_courses now returns two additional fields "duedate" and "cutoffdate" containing the due date and the cutoff date
-     for posting to the forums respectively.
++  * External function get_forums_by_courses now returns two additional fields "duedate" and "cutoffdate" containing the due date and the cutoff date for posting to the forums respectively.
+   * External function get_forum_discussion_posts now returns an additional field "tags" returning the post tags.
  
  === 3.6 ===
  
diff --combined version.php
  
  defined('MOODLE_INTERNAL') || die();
  
- $version  = 2019041000.03;              // YYYYMMDD      = weekly release date of this DEV branch.
 -$version  = 2019040600.01;              // YYYYMMDD      = weekly release date of this DEV branch.
++$version  = 2019041000.04;              // YYYYMMDD      = weekly release date of this DEV branch.
                                          //         RR    = release increments - 00 in DEV branches.
                                          //           .XX = incremental changes.
  
 -$release  = '3.7dev+ (Build: 20190406)'; // Human-friendly version name
 +$release  = '3.7dev+ (Build: 20190410)'; // Human-friendly version name
  
  $branch   = '37';                       // This version's branch.
  $maturity = MATURITY_ALPHA;             // This version's maturity level.