Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.
   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * REST interface to Nextcloud's implementation of Open Collaboration Services.
  19   *
  20   * @package    repository_nextcloud
  21   * @copyright  2017 Jan Dageförde (Learnweb, University of Münster)
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  namespace repository_nextcloud;
  25  
  26  use core\oauth2\client;
  27  use core\oauth2\rest;
  28  
  29  defined('MOODLE_INTERNAL') || die();
  30  
  31  /**
  32   * REST interface to Nextcloud's implementation of Open Collaboration Services.
  33   *
  34   * @package    repository_nextcloud
  35   * @copyright  2017 Jan Dageförde (Learnweb, University of Münster)
  36   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  37   */
  38  class ocs_client extends rest {
  39  
  40      /**
  41       * shareType=0 creates a private user share.
  42       */
  43      const SHARE_TYPE_USER = 0;
  44  
  45      /**
  46       * shareType=3 creates a public share.
  47       */
  48      const SHARE_TYPE_PUBLIC = 3;
  49  
  50      /**
  51       * permissions=1 gives read permission for a share.
  52       */
  53      const SHARE_PERMISSION_READ = 1;
  54  
  55      /**
  56       * permissions=1 gives read permission for a share.
  57       */
  58      const SHARE_PERMISSION_ALL = 31;
  59  
  60      /**
  61       * OCS endpoint as configured for the used issuer.
  62       * @var \moodle_url
  63       */
  64      private $ocsendpoint;
  65  
  66  
  67      /**
  68       * Get endpoint URLs from the used issuer to use them in get_api_functions().
  69       * @param client $oauthclient OAuth-authenticated Nextcloud client
  70       * @throws configuration_exception Exception if critical endpoints are missing.
  71       * @throws \moodle_exception when trying to construct a moodleurl
  72       */
  73      public function __construct(client $oauthclient) {
  74          parent::__construct($oauthclient);
  75  
  76          $issuer = $oauthclient->get_issuer();
  77          $ocsendpoint = $issuer->get_endpoint_url('ocs');
  78          if ($ocsendpoint === false) {
  79              throw new configuration_exception('Endpoint ocs_endpoint not defined.');
  80          }
  81          $this->ocsendpoint = new \moodle_url($ocsendpoint);
  82          if (empty($this->ocsendpoint->get_param('format'))) {
  83              $this->ocsendpoint->params(array('format' => 'xml'));
  84          }
  85      }
  86  
  87      /**
  88       * Define relevant functions of the OCS API.
  89       *
  90       * Previously, the instruction to create a oauthclient recommended the user to enter the return format (format=xml).
  91       * However, in this case the shareid is appended at the wrong place. Therefore, a new url is build which inserts the
  92       * shareid at the suitable place for delete_share and get_information_of_share.
  93       * create_share docs: https://docs.nextcloud.com/server/13/developer_manual/core/ocs-share-api.html#create-a-new-share
  94       *
  95       */
  96      public function get_api_functions() {
  97          return [
  98              'create_share' => [
  99                  'endpoint' => $this->ocsendpoint->out(false),
 100                  'method' => 'post',
 101                  'args' => [
 102                      'path' => PARAM_TEXT, // Could be PARAM_PATH, we really don't want to enforce a Moodle understanding of paths.
 103                      'shareType' => PARAM_INT,
 104                      'shareWith' => PARAM_TEXT, // Name of receiving user/group. Required if SHARE_TYPE_USER.
 105                      'publicUpload' => PARAM_RAW, // Actually Boolean, but neither String-Boolean ('false') nor PARAM_BOOL (0/1).
 106                      'permissions' => PARAM_INT,
 107                      'shareWith' => PARAM_TEXT,
 108                      'expireDate' => PARAM_TEXT
 109                  ],
 110                  'response' => 'text/xml'
 111              ],
 112              'delete_share' => [
 113                  'endpoint' => $this->build_share_url(),
 114                  'method' => 'delete',
 115                  'args' => [
 116                      'share_id' => PARAM_INT
 117                  ],
 118                  'response' => 'text/xml'
 119              ],
 120              'get_shares' => [
 121                  'endpoint' => $this->ocsendpoint->out(false),
 122                  'method' => 'get',
 123                  'args' => [
 124                      'path' => PARAM_TEXT,
 125                      'reshares' => PARAM_RAW, // Returns not only the shares from the current user but all of the given file.
 126                      'subfiles' => PARAM_RAW, // Returns all shares within a folder, given that path defines a folder.
 127                  ],
 128                  'response' => 'text/xml'
 129              ],
 130              'get_information_of_share' => [
 131                  'endpoint' => $this->build_share_url(),
 132                  'method' => 'get',
 133                  'args' => [
 134                      'share_id' => PARAM_INT
 135                  ],
 136                  'response' => 'text/xml'
 137              ],
 138          ];
 139      }
 140  
 141      /**
 142       * Private Function to return a url with the shareid in the path.
 143       * @return string
 144       */
 145      private function build_share_url() {
 146          // Out_omit_querystring() in combination with ocsendpoint->get_path() is not used since both function include
 147          // /ocs/v1.php.
 148          $shareurl = $this->ocsendpoint->get_scheme() . '://' . $this->ocsendpoint->get_host() . ':' .
 149              $this->ocsendpoint->get_port() . $this->ocsendpoint->get_path() . '/{share_id}?' .
 150              $this->ocsendpoint->get_query_string(false);
 151          return $shareurl;
 152      }
 153  
 154      /**
 155       * In POST requests, Moodle's REST API assumes that params are
 156       * - transmitted as part of the URL or
 157       * - expressed in JSON.
 158       * Neither is true; we are passing an array to $functionargs which is then put into CURLOPT_POSTFIELDS.
 159       * Curl assumes the content type to be `multipart/form-data` then, but the Moodle REST API tries to put
 160       * a JSON content type. As a result, clients would fail.
 161       * To make this less tedious to use, we assume that the params-as-array-in-$functionargs is the default for us.
 162       *
 163       * @param string $functionname Name of a function from get_api_functions()
 164       * @param array $functionargs Request parameters
 165       * @param bool|string $rawpost Optional param to include in the body of a post
 166       * @param bool|string $contenttype Content type of the request body. Default: multipart/form-data if !$rawpost, JSON otherwise
 167       * @return object|string
 168       * @throws \coding_exception
 169       * @throws \core\oauth2\rest_exception
 170       */
 171      public function call($functionname, $functionargs, $rawpost = false, $contenttype = false) {
 172          if ($rawpost === false && $contenttype === false) {
 173              return parent::call($functionname, $functionargs, false, 'multipart/form-data');
 174          } else {
 175              return parent::call($functionname, $functionargs, $rawpost, $contenttype);
 176          }
 177      }
 178  
 179  }