first commit
This commit is contained in:
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.API
|
||||
* @subpackage com_media
|
||||
*
|
||||
* @copyright (C) 2021 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Media\Api\Controller;
|
||||
|
||||
use Joomla\CMS\MVC\Controller\ApiController;
|
||||
use Joomla\Component\Media\Administrator\Exception\InvalidPathException;
|
||||
use Joomla\Component\Media\Administrator\Provider\ProviderManagerHelperTrait;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Media web service controller.
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
class AdaptersController extends ApiController
|
||||
{
|
||||
use ProviderManagerHelperTrait;
|
||||
|
||||
/**
|
||||
* The content type of the item.
|
||||
*
|
||||
* @var string
|
||||
* @since 4.1.0
|
||||
*/
|
||||
protected $contentType = 'adapters';
|
||||
|
||||
/**
|
||||
* The default view for the display method.
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
protected $default_view = 'adapters';
|
||||
|
||||
/**
|
||||
* Display one specific adapter.
|
||||
*
|
||||
* @param string $path The path of the file to display. Leave empty if you want to retrieve data from the request.
|
||||
*
|
||||
* @return static A \JControllerLegacy object to support chaining.
|
||||
*
|
||||
* @throws InvalidPathException
|
||||
* @throws \Exception
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public function displayItem($path = '')
|
||||
{
|
||||
// Set the id as the parent sets it as int
|
||||
$this->modelState->set('id', $this->input->get('id', '', 'string'));
|
||||
|
||||
return parent::displayItem();
|
||||
}
|
||||
}
|
||||
401
api/components/com_media/src/Controller/MediaController.php
Normal file
401
api/components/com_media/src/Controller/MediaController.php
Normal file
@ -0,0 +1,401 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.API
|
||||
* @subpackage com_media
|
||||
*
|
||||
* @copyright (C) 2021 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Media\Api\Controller;
|
||||
|
||||
use Joomla\CMS\Access\Exception\NotAllowed;
|
||||
use Joomla\CMS\Component\ComponentHelper;
|
||||
use Joomla\CMS\Filter\InputFilter;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\MVC\Controller\ApiController;
|
||||
use Joomla\Component\Media\Administrator\Exception\FileExistsException;
|
||||
use Joomla\Component\Media\Administrator\Exception\InvalidPathException;
|
||||
use Joomla\Component\Media\Administrator\Provider\ProviderManagerHelperTrait;
|
||||
use Joomla\Component\Media\Api\Model\MediumModel;
|
||||
use Joomla\String\Inflector;
|
||||
use Tobscure\JsonApi\Exception\InvalidParameterException;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Media web service controller.
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
class MediaController extends ApiController
|
||||
{
|
||||
use ProviderManagerHelperTrait;
|
||||
|
||||
/**
|
||||
* The content type of the item.
|
||||
*
|
||||
* @var string
|
||||
* @since 4.1.0
|
||||
*/
|
||||
protected $contentType = 'media';
|
||||
|
||||
/**
|
||||
* Query parameters => model state mappings
|
||||
*
|
||||
* @var array
|
||||
* @since 4.1.0
|
||||
*/
|
||||
private static $listQueryModelStateMap = [
|
||||
'path' => [
|
||||
'name' => 'path',
|
||||
'type' => 'STRING',
|
||||
],
|
||||
'url' => [
|
||||
'name' => 'url',
|
||||
'type' => 'BOOLEAN',
|
||||
],
|
||||
'temp' => [
|
||||
'name' => 'temp',
|
||||
'type' => 'BOOLEAN',
|
||||
],
|
||||
'content' => [
|
||||
'name' => 'content',
|
||||
'type' => 'BOOLEAN',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Item query parameters => model state mappings
|
||||
*
|
||||
* @var array
|
||||
* @since 4.1.0
|
||||
*/
|
||||
private static $itemQueryModelStateMap = [
|
||||
'path' => [
|
||||
'name' => 'path',
|
||||
'type' => 'STRING',
|
||||
],
|
||||
'url' => [
|
||||
'name' => 'url',
|
||||
'type' => 'BOOLEAN',
|
||||
],
|
||||
'temp' => [
|
||||
'name' => 'temp',
|
||||
'type' => 'BOOLEAN',
|
||||
],
|
||||
'content' => [
|
||||
'name' => 'content',
|
||||
'type' => 'BOOLEAN',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* The default view for the display method.
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
protected $default_view = 'media';
|
||||
|
||||
/**
|
||||
* Display a list of files and/or folders.
|
||||
*
|
||||
* @return static A \JControllerLegacy object to support chaining.
|
||||
*
|
||||
* @since 4.1.0
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function displayList()
|
||||
{
|
||||
// Set list specific request parameters in model state.
|
||||
$this->setModelState(self::$listQueryModelStateMap);
|
||||
|
||||
// Display files in specific path.
|
||||
if ($this->input->exists('path')) {
|
||||
$this->modelState->set('path', $this->input->get('path', '', 'STRING'));
|
||||
}
|
||||
|
||||
// Return files (not folders) as urls.
|
||||
if ($this->input->exists('url')) {
|
||||
$this->modelState->set('url', $this->input->get('url', true, 'BOOLEAN'));
|
||||
}
|
||||
|
||||
// Map JSON:API compliant filter[search] to com_media model state.
|
||||
$apiFilterInfo = $this->input->get('filter', [], 'array');
|
||||
$filter = InputFilter::getInstance();
|
||||
|
||||
// Search for files matching (part of) a name or glob pattern.
|
||||
if (\array_key_exists('search', $apiFilterInfo)) {
|
||||
$this->modelState->set('search', $filter->clean($apiFilterInfo['search'], 'STRING'));
|
||||
|
||||
// Tell model to search recursively
|
||||
$this->modelState->set('search_recursive', $this->input->get('search_recursive', false, 'BOOLEAN'));
|
||||
}
|
||||
|
||||
return parent::displayList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Display one specific file or folder.
|
||||
*
|
||||
* @param string $path The path of the file to display. Leave empty if you want to retrieve data from the request.
|
||||
*
|
||||
* @return static A \JControllerLegacy object to support chaining.
|
||||
*
|
||||
* @since 4.1.0
|
||||
*
|
||||
* @throws InvalidPathException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function displayItem($path = '')
|
||||
{
|
||||
// Set list specific request parameters in model state.
|
||||
$this->setModelState(self::$itemQueryModelStateMap);
|
||||
|
||||
// Display files in specific path.
|
||||
$this->modelState->set('path', $path ?: $this->input->get('path', '', 'STRING'));
|
||||
|
||||
// Return files (not folders) as urls.
|
||||
if ($this->input->exists('url')) {
|
||||
$this->modelState->set('url', $this->input->get('url', true, 'BOOLEAN'));
|
||||
}
|
||||
|
||||
return parent::displayItem();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set model state using a list of mappings between query parameters and model state names.
|
||||
*
|
||||
* @param array $mappings A list of mappings between query parameters and model state names.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
private function setModelState(array $mappings): void
|
||||
{
|
||||
foreach ($mappings as $queryName => $modelState) {
|
||||
if ($this->input->exists($queryName)) {
|
||||
$this->modelState->set($modelState['name'], $this->input->get($queryName, '', $modelState['type']));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to add a new file or folder.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 4.1.0
|
||||
*
|
||||
* @throws FileExistsException
|
||||
* @throws InvalidPathException
|
||||
* @throws InvalidParameterException
|
||||
* @throws \RuntimeException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function add(): void
|
||||
{
|
||||
$path = $this->input->json->get('path', '', 'STRING');
|
||||
$content = $this->input->json->get('content', '', 'RAW');
|
||||
|
||||
$missingParameters = [];
|
||||
|
||||
if (empty($path)) {
|
||||
$missingParameters[] = 'path';
|
||||
}
|
||||
|
||||
// Content is only required when it is a file
|
||||
if (empty($content) && strpos($path, '.') !== false) {
|
||||
$missingParameters[] = 'content';
|
||||
}
|
||||
|
||||
if (\count($missingParameters)) {
|
||||
throw new InvalidParameterException(
|
||||
Text::sprintf('WEBSERVICE_COM_MEDIA_MISSING_REQUIRED_PARAMETERS', implode(' & ', $missingParameters))
|
||||
);
|
||||
}
|
||||
|
||||
$this->modelState->set('path', $this->input->json->get('path', '', 'STRING'));
|
||||
|
||||
// Check if an existing file may be overwritten. Defaults to false.
|
||||
$this->modelState->set('override', $this->input->json->get('override', false));
|
||||
|
||||
parent::add();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to check if it's allowed to add a new file or folder
|
||||
*
|
||||
* @param array $data An array of input data.
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
protected function allowAdd($data = []): bool
|
||||
{
|
||||
$user = $this->app->getIdentity();
|
||||
|
||||
return $user->authorise('core.create', 'com_media');
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to modify an existing file or folder.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 4.1.0
|
||||
*
|
||||
* @throws FileExistsException
|
||||
* @throws InvalidPathException
|
||||
* @throws \RuntimeException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function edit(): void
|
||||
{
|
||||
// Access check.
|
||||
if (!$this->allowEdit()) {
|
||||
throw new NotAllowed('JLIB_APPLICATION_ERROR_CREATE_RECORD_NOT_PERMITTED', 403);
|
||||
}
|
||||
|
||||
$path = $this->input->json->get('path', '', 'STRING');
|
||||
$content = $this->input->json->get('content', '', 'RAW');
|
||||
|
||||
if (empty($path) && empty($content)) {
|
||||
throw new InvalidParameterException(
|
||||
Text::sprintf('WEBSERVICE_COM_MEDIA_MISSING_REQUIRED_PARAMETERS', 'path | content')
|
||||
);
|
||||
}
|
||||
|
||||
$this->modelState->set('path', $this->input->json->get('path', '', 'STRING'));
|
||||
// For renaming/moving files, we need the path to the existing file or folder.
|
||||
$this->modelState->set('old_path', $this->input->get('path', '', 'STRING'));
|
||||
// Check if an existing file may be overwritten. Defaults to true.
|
||||
$this->modelState->set('override', $this->input->json->get('override', true));
|
||||
|
||||
$recordId = $this->save();
|
||||
|
||||
$this->displayItem($recordId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to check if it's allowed to modify an existing file or folder.
|
||||
*
|
||||
* @param array $data An array of input data.
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
protected function allowEdit($data = [], $key = 'id'): bool
|
||||
{
|
||||
$user = $this->app->getIdentity();
|
||||
|
||||
// com_media's access rules contains no specific update rule.
|
||||
return $user->authorise('core.edit', 'com_media');
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to create or modify a file or folder.
|
||||
*
|
||||
* @param integer $recordKey The primary key of the item (if exists)
|
||||
*
|
||||
* @return string The path
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
protected function save($recordKey = null)
|
||||
{
|
||||
// Explicitly get the single item model name.
|
||||
$modelName = $this->input->get('model', Inflector::singularize($this->contentType));
|
||||
|
||||
/** @var MediumModel $model */
|
||||
$model = $this->getModel($modelName, '', ['ignore_request' => true, 'state' => $this->modelState]);
|
||||
|
||||
$json = $this->input->json;
|
||||
|
||||
// Decode content, if any
|
||||
if ($content = base64_decode($json->get('content', '', 'raw'))) {
|
||||
$this->checkContent();
|
||||
}
|
||||
|
||||
// If there is no content, com_media assumes the path refers to a folder.
|
||||
$this->modelState->set('content', $content);
|
||||
|
||||
return $model->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs various checks to see if it is allowed to save the content.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 4.1.0
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
private function checkContent(): void
|
||||
{
|
||||
$params = ComponentHelper::getParams('com_media');
|
||||
$helper = new \Joomla\CMS\Helper\MediaHelper();
|
||||
$serverlength = $this->input->server->getInt('CONTENT_LENGTH');
|
||||
|
||||
// Check if the size of the request body does not exceed various server imposed limits.
|
||||
if (
|
||||
($params->get('upload_maxsize', 0) > 0 && $serverlength > ($params->get('upload_maxsize', 0) * 1024 * 1024))
|
||||
|| $serverlength > $helper->toBytes(ini_get('upload_max_filesize'))
|
||||
|| $serverlength > $helper->toBytes(ini_get('post_max_size'))
|
||||
|| $serverlength > $helper->toBytes(ini_get('memory_limit'))
|
||||
) {
|
||||
throw new \RuntimeException(Text::_('COM_MEDIA_ERROR_WARNFILETOOLARGE'), 400);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to delete an existing file or folder.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 4.1.0
|
||||
*
|
||||
* @throws InvalidPathException
|
||||
* @throws \RuntimeException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function delete($id = null): void
|
||||
{
|
||||
if (!$this->allowDelete()) {
|
||||
throw new NotAllowed('JLIB_APPLICATION_ERROR_DELETE_NOT_PERMITTED', 403);
|
||||
}
|
||||
|
||||
$this->modelState->set('path', $this->input->get('path', '', 'STRING'));
|
||||
|
||||
$modelName = $this->input->get('model', Inflector::singularize($this->contentType));
|
||||
$model = $this->getModel($modelName, '', ['ignore_request' => true, 'state' => $this->modelState]);
|
||||
|
||||
$model->delete();
|
||||
|
||||
$this->app->setHeader('status', 204);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to check if it's allowed to delete an existing file or folder.
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
protected function allowDelete(): bool
|
||||
{
|
||||
$user = $this->app->getIdentity();
|
||||
|
||||
return $user->authorise('core.delete', 'com_media');
|
||||
}
|
||||
}
|
||||
55
api/components/com_media/src/Model/AdapterModel.php
Normal file
55
api/components/com_media/src/Model/AdapterModel.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.API
|
||||
* @subpackage com_media
|
||||
*
|
||||
* @copyright (C) 2021 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Media\Api\Model;
|
||||
|
||||
use Joomla\CMS\MVC\Model\BaseModel;
|
||||
use Joomla\Component\Media\Administrator\Provider\ProviderManagerHelperTrait;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Media web service model supporting a single adapter item.
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
class AdapterModel extends BaseModel
|
||||
{
|
||||
use ProviderManagerHelperTrait;
|
||||
|
||||
/**
|
||||
* Method to get a single adapter.
|
||||
*
|
||||
* @return \stdClass The adapter.
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public function getItem(): \stdClass
|
||||
{
|
||||
list($provider, $account) = array_pad(explode('-', $this->getState('id'), 2), 2, null);
|
||||
|
||||
if ($account === null) {
|
||||
throw new \Exception('Account was not set');
|
||||
}
|
||||
|
||||
$provider = $this->getProvider($provider);
|
||||
$adapter = $this->getAdapter($this->getState('id'));
|
||||
|
||||
$obj = new \stdClass();
|
||||
$obj->id = $provider->getID() . '-' . $adapter->getAdapterName();
|
||||
$obj->provider_id = $provider->getID();
|
||||
$obj->name = $adapter->getAdapterName();
|
||||
$obj->path = $provider->getID() . '-' . $adapter->getAdapterName() . ':/';
|
||||
|
||||
return $obj;
|
||||
}
|
||||
}
|
||||
105
api/components/com_media/src/Model/AdaptersModel.php
Normal file
105
api/components/com_media/src/Model/AdaptersModel.php
Normal file
@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.API
|
||||
* @subpackage com_media
|
||||
*
|
||||
* @copyright (C) 2021 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Media\Api\Model;
|
||||
|
||||
use Joomla\CMS\MVC\Model\BaseModel;
|
||||
use Joomla\CMS\MVC\Model\ListModelInterface;
|
||||
use Joomla\CMS\Pagination\Pagination;
|
||||
use Joomla\Component\Media\Administrator\Provider\ProviderManagerHelperTrait;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Media web service model supporting lists of media adapters.
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
class AdaptersModel extends BaseModel implements ListModelInterface
|
||||
{
|
||||
use ProviderManagerHelperTrait;
|
||||
|
||||
/**
|
||||
* A hacky way to enable the standard jsonapiView::displayList() to create a Pagination object,
|
||||
* since com_media's ApiModel does not support pagination as we know from regular ListModel derived models.
|
||||
*
|
||||
* @var int
|
||||
* @since 4.1.0
|
||||
*/
|
||||
private $total = 0;
|
||||
|
||||
/**
|
||||
* Method to get a list of files and/or folders.
|
||||
*
|
||||
* @return array An array of data items.
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public function getItems(): array
|
||||
{
|
||||
$adapters = [];
|
||||
foreach ($this->getProviderManager()->getProviders() as $provider) {
|
||||
foreach ($provider->getAdapters() as $adapter) {
|
||||
$obj = new \stdClass();
|
||||
$obj->id = $provider->getID() . '-' . $adapter->getAdapterName();
|
||||
$obj->provider_id = $provider->getID();
|
||||
$obj->name = $adapter->getAdapterName();
|
||||
$obj->path = $provider->getID() . '-' . $adapter->getAdapterName() . ':/';
|
||||
|
||||
$adapters[] = $obj;
|
||||
}
|
||||
}
|
||||
|
||||
// A hacky way to enable the standard jsonapiView::displayList() to create a Pagination object.
|
||||
$this->total = \count($adapters);
|
||||
|
||||
return $adapters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get a \JPagination object for the data set.
|
||||
*
|
||||
* @return Pagination A Pagination object for the data set.
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public function getPagination(): Pagination
|
||||
{
|
||||
return new Pagination($this->getTotal(), $this->getStart(), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get the starting number of items for the data set. Because com_media's ApiModel
|
||||
* does not support pagination as we know from regular ListModel derived models,
|
||||
* we always start at the top.
|
||||
*
|
||||
* @return integer The starting number of items available in the data set.
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public function getStart(): int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get the total number of items for the data set.
|
||||
*
|
||||
* @return integer The total number of items available in the data set.
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public function getTotal(): int
|
||||
{
|
||||
return $this->total;
|
||||
}
|
||||
}
|
||||
134
api/components/com_media/src/Model/MediaModel.php
Normal file
134
api/components/com_media/src/Model/MediaModel.php
Normal file
@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.API
|
||||
* @subpackage com_media
|
||||
*
|
||||
* @copyright (C) 2021 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Media\Api\Model;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\MVC\Controller\Exception\ResourceNotFound;
|
||||
use Joomla\CMS\MVC\Model\BaseModel;
|
||||
use Joomla\CMS\MVC\Model\ListModelInterface;
|
||||
use Joomla\CMS\Pagination\Pagination;
|
||||
use Joomla\Component\Media\Administrator\Exception\FileNotFoundException;
|
||||
use Joomla\Component\Media\Administrator\Model\ApiModel;
|
||||
use Joomla\Component\Media\Administrator\Provider\ProviderManagerHelperTrait;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Media web service model supporting lists of media items.
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
class MediaModel extends BaseModel implements ListModelInterface
|
||||
{
|
||||
use ProviderManagerHelperTrait;
|
||||
|
||||
/**
|
||||
* Instance of com_media's ApiModel
|
||||
*
|
||||
* @var ApiModel
|
||||
* @since 4.1.0
|
||||
*/
|
||||
private $mediaApiModel;
|
||||
|
||||
/**
|
||||
* A hacky way to enable the standard jsonapiView::displayList() to create a Pagination object,
|
||||
* since com_media's ApiModel does not support pagination as we know from regular ListModel derived models.
|
||||
*
|
||||
* @var int
|
||||
* @since 4.1.0
|
||||
*/
|
||||
private $total = 0;
|
||||
|
||||
public function __construct($config = [])
|
||||
{
|
||||
parent::__construct($config);
|
||||
|
||||
$this->mediaApiModel = new ApiModel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get a list of files and/or folders.
|
||||
*
|
||||
* @return array An array of data items.
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public function getItems(): array
|
||||
{
|
||||
// Map web service model state to com_media options.
|
||||
$options = [
|
||||
'url' => $this->getState('url', false),
|
||||
'temp' => $this->getState('temp', false),
|
||||
'search' => $this->getState('search', ''),
|
||||
'recursive' => $this->getState('search_recursive', false),
|
||||
'content' => $this->getState('content', false),
|
||||
];
|
||||
|
||||
['adapter' => $adapterName, 'path' => $path] = $this->resolveAdapterAndPath($this->getState('path', ''));
|
||||
try {
|
||||
$files = $this->mediaApiModel->getFiles($adapterName, $path, $options);
|
||||
} catch (FileNotFoundException $e) {
|
||||
throw new ResourceNotFound(
|
||||
Text::sprintf('WEBSERVICE_COM_MEDIA_FILE_NOT_FOUND', $path),
|
||||
404
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A hacky way to enable the standard jsonapiView::displayList() to create a Pagination object.
|
||||
* Because com_media's ApiModel does not support pagination as we know from regular ListModel
|
||||
* derived models, we always return all retrieved items.
|
||||
*/
|
||||
$this->total = \count($files);
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get a \JPagination object for the data set.
|
||||
*
|
||||
* @return Pagination A Pagination object for the data set.
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public function getPagination(): Pagination
|
||||
{
|
||||
return new Pagination($this->getTotal(), $this->getStart(), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get the starting number of items for the data set. Because com_media's ApiModel
|
||||
* does not support pagination as we know from regular ListModel derived models,
|
||||
* we always start at the top.
|
||||
*
|
||||
* @return int The starting number of items available in the data set.
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public function getStart(): int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get the total number of items for the data set.
|
||||
*
|
||||
* @return int The total number of items available in the data set.
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public function getTotal(): int
|
||||
{
|
||||
return $this->total;
|
||||
}
|
||||
}
|
||||
259
api/components/com_media/src/Model/MediumModel.php
Normal file
259
api/components/com_media/src/Model/MediumModel.php
Normal file
@ -0,0 +1,259 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.API
|
||||
* @subpackage com_media
|
||||
*
|
||||
* @copyright (C) 2021 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Media\Api\Model;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\MVC\Controller\Exception\ResourceNotFound;
|
||||
use Joomla\CMS\MVC\Controller\Exception\Save;
|
||||
use Joomla\CMS\MVC\Model\BaseModel;
|
||||
use Joomla\Component\Media\Administrator\Exception\FileExistsException;
|
||||
use Joomla\Component\Media\Administrator\Exception\FileNotFoundException;
|
||||
use Joomla\Component\Media\Administrator\Exception\InvalidPathException;
|
||||
use Joomla\Component\Media\Administrator\Model\ApiModel;
|
||||
use Joomla\Component\Media\Administrator\Provider\ProviderManagerHelperTrait;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Media web service model supporting a single media item.
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
class MediumModel extends BaseModel
|
||||
{
|
||||
use ProviderManagerHelperTrait;
|
||||
|
||||
/**
|
||||
* Instance of com_media's ApiModel
|
||||
*
|
||||
* @var ApiModel
|
||||
* @since 4.1.0
|
||||
*/
|
||||
private $mediaApiModel;
|
||||
|
||||
public function __construct($config = [])
|
||||
{
|
||||
parent::__construct($config);
|
||||
|
||||
$this->mediaApiModel = new ApiModel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get a single files or folder.
|
||||
*
|
||||
* @return \stdClass A file or folder object.
|
||||
*
|
||||
* @since 4.1.0
|
||||
* @throws ResourceNotFound
|
||||
*/
|
||||
public function getItem()
|
||||
{
|
||||
$options = [
|
||||
'path' => $this->getState('path', ''),
|
||||
'url' => $this->getState('url', false),
|
||||
'temp' => $this->getState('temp', false),
|
||||
'content' => $this->getState('content', false),
|
||||
];
|
||||
|
||||
['adapter' => $adapterName, 'path' => $path] = $this->resolveAdapterAndPath($this->getState('path', ''));
|
||||
|
||||
try {
|
||||
return $this->mediaApiModel->getFile($adapterName, $path, $options);
|
||||
} catch (FileNotFoundException $e) {
|
||||
throw new ResourceNotFound(
|
||||
Text::sprintf('WEBSERVICE_COM_MEDIA_FILE_NOT_FOUND', $path),
|
||||
404
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to save a file or folder.
|
||||
*
|
||||
* @param string $path The primary key of the item (if exists)
|
||||
*
|
||||
* @return string The path
|
||||
*
|
||||
* @since 4.1.0
|
||||
*
|
||||
* @throws Save
|
||||
*/
|
||||
public function save($path = null): string
|
||||
{
|
||||
$path = $this->getState('path', '');
|
||||
$oldPath = $this->getState('old_path', '');
|
||||
$content = $this->getState('content', null);
|
||||
$override = $this->getState('override', false);
|
||||
|
||||
['adapter' => $adapterName, 'path' => $path] = $this->resolveAdapterAndPath($path);
|
||||
|
||||
// Trim adapter information from path
|
||||
if ($pos = strpos($path, ':/')) {
|
||||
$path = substr($path, $pos + 1);
|
||||
}
|
||||
|
||||
// Trim adapter information from old path
|
||||
if ($pos = strpos($oldPath, ':/')) {
|
||||
$oldPath = substr($oldPath, $pos + 1);
|
||||
}
|
||||
|
||||
$resultPath = '';
|
||||
|
||||
/**
|
||||
* If we have a (new) path and an old path, we want to move an existing
|
||||
* file or folder. This must be done before updating the content of a file,
|
||||
* if also requested (see below).
|
||||
*/
|
||||
if ($path && $oldPath) {
|
||||
try {
|
||||
// ApiModel::move() (or actually LocalAdapter::move()) returns a path with leading slash.
|
||||
$resultPath = trim(
|
||||
$this->mediaApiModel->move($adapterName, $oldPath, $path, $override),
|
||||
'/'
|
||||
);
|
||||
} catch (FileNotFoundException $e) {
|
||||
throw new Save(
|
||||
Text::sprintf(
|
||||
'WEBSERVICE_COM_MEDIA_FILE_NOT_FOUND',
|
||||
$oldPath
|
||||
),
|
||||
404
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a (new) path but no old path, we want to create a
|
||||
// new file or folder.
|
||||
if ($path && !$oldPath) {
|
||||
// com_media expects separate directory and file name.
|
||||
// If we moved the file before, we must use the new path.
|
||||
$basename = basename($resultPath ?: $path);
|
||||
$dirname = \dirname($resultPath ?: $path);
|
||||
|
||||
try {
|
||||
// If there is content, com_media's assumes the new item is a file.
|
||||
// Otherwise a folder is assumed.
|
||||
$name = $content
|
||||
? $this->mediaApiModel->createFile(
|
||||
$adapterName,
|
||||
$basename,
|
||||
$dirname,
|
||||
$content,
|
||||
$override
|
||||
)
|
||||
: $this->mediaApiModel->createFolder(
|
||||
$adapterName,
|
||||
$basename,
|
||||
$dirname,
|
||||
$override
|
||||
);
|
||||
|
||||
$resultPath = $dirname . '/' . $name;
|
||||
} catch (FileNotFoundException $e) {
|
||||
throw new Save(
|
||||
Text::sprintf(
|
||||
'WEBSERVICE_COM_MEDIA_FILE_NOT_FOUND',
|
||||
$dirname . '/' . $basename
|
||||
),
|
||||
404
|
||||
);
|
||||
} catch (FileExistsException $e) {
|
||||
throw new Save(
|
||||
Text::sprintf(
|
||||
'WEBSERVICE_COM_MEDIA_FILE_EXISTS',
|
||||
$dirname . '/' . $basename
|
||||
),
|
||||
400
|
||||
);
|
||||
} catch (InvalidPathException $e) {
|
||||
throw new Save(
|
||||
Text::sprintf(
|
||||
'WEBSERVICE_COM_MEDIA_BAD_FILE_TYPE',
|
||||
$dirname . '/' . $basename
|
||||
),
|
||||
400
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// If we have no (new) path but we do have an old path and we have content,
|
||||
// we want to update the contents of an existing file.
|
||||
if ($oldPath && $content) {
|
||||
// com_media expects separate directory and file name.
|
||||
// If we moved the file before, we must use the new path.
|
||||
$basename = basename($resultPath ?: $oldPath);
|
||||
$dirname = \dirname($resultPath ?: $oldPath);
|
||||
|
||||
try {
|
||||
$this->mediaApiModel->updateFile(
|
||||
$adapterName,
|
||||
$basename,
|
||||
$dirname,
|
||||
$content
|
||||
);
|
||||
} catch (FileNotFoundException $e) {
|
||||
throw new Save(
|
||||
Text::sprintf(
|
||||
'WEBSERVICE_COM_MEDIA_FILE_NOT_FOUND',
|
||||
$dirname . '/' . $basename
|
||||
),
|
||||
404
|
||||
);
|
||||
} catch (InvalidPathException $e) {
|
||||
throw new Save(
|
||||
Text::sprintf(
|
||||
'WEBSERVICE_COM_MEDIA_BAD_FILE_TYPE',
|
||||
$dirname . '/' . $basename
|
||||
),
|
||||
400
|
||||
);
|
||||
}
|
||||
|
||||
$resultPath = $resultPath ?: $oldPath;
|
||||
}
|
||||
|
||||
// If we still have no result path, something fishy is going on.
|
||||
if (!$resultPath) {
|
||||
throw new Save(
|
||||
Text::_(
|
||||
'WEBSERVICE_COM_MEDIA_UNSUPPORTED_PARAMETER_COMBINATION'
|
||||
),
|
||||
400
|
||||
);
|
||||
}
|
||||
|
||||
return $resultPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to delete an existing file or folder.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 4.1.0
|
||||
* @throws Save
|
||||
*/
|
||||
public function delete(): void
|
||||
{
|
||||
['adapter' => $adapterName, 'path' => $path] = $this->resolveAdapterAndPath($this->getState('path', ''));
|
||||
|
||||
try {
|
||||
$this->mediaApiModel->delete($adapterName, $path);
|
||||
} catch (FileNotFoundException $e) {
|
||||
throw new Save(
|
||||
Text::sprintf('WEBSERVICE_COM_MEDIA_FILE_NOT_FOUND', $path),
|
||||
404
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
52
api/components/com_media/src/View/Adapters/JsonapiView.php
Normal file
52
api/components/com_media/src/View/Adapters/JsonapiView.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.API
|
||||
* @subpackage com_media
|
||||
*
|
||||
* @copyright (C) 2021 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Media\Api\View\Adapters;
|
||||
|
||||
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
|
||||
use Joomla\Component\Media\Administrator\Provider\ProviderManagerHelperTrait;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Media web service view
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
class JsonapiView extends BaseApiView
|
||||
{
|
||||
use ProviderManagerHelperTrait;
|
||||
|
||||
/**
|
||||
* The fields to render item in the documents
|
||||
*
|
||||
* @var array
|
||||
* @since 4.1.0
|
||||
*/
|
||||
protected $fieldsToRenderItem = [
|
||||
'provider_id',
|
||||
'name',
|
||||
'path',
|
||||
];
|
||||
|
||||
/**
|
||||
* The fields to render items in the documents
|
||||
*
|
||||
* @var array
|
||||
* @since 4.1.0
|
||||
*/
|
||||
protected $fieldsToRenderList = [
|
||||
'provider_id',
|
||||
'name',
|
||||
'path',
|
||||
];
|
||||
}
|
||||
97
api/components/com_media/src/View/Media/JsonapiView.php
Normal file
97
api/components/com_media/src/View/Media/JsonapiView.php
Normal file
@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.API
|
||||
* @subpackage com_media
|
||||
*
|
||||
* @copyright (C) 2021 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Media\Api\View\Media;
|
||||
|
||||
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
|
||||
use Joomla\Component\Media\Administrator\Provider\ProviderManagerHelperTrait;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Media web service view
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
class JsonapiView extends BaseApiView
|
||||
{
|
||||
use ProviderManagerHelperTrait;
|
||||
|
||||
/**
|
||||
* The fields to render item in the documents
|
||||
*
|
||||
* @var array
|
||||
* @since 4.1.0
|
||||
*/
|
||||
protected $fieldsToRenderItem = [
|
||||
'type',
|
||||
'name',
|
||||
'path',
|
||||
'extension',
|
||||
'size',
|
||||
'mime_type',
|
||||
'width',
|
||||
'height',
|
||||
'create_date',
|
||||
'create_date_formatted',
|
||||
'modified_date',
|
||||
'modified_date_formatted',
|
||||
'thumb_path',
|
||||
'adapter',
|
||||
'content',
|
||||
'url',
|
||||
'tempUrl',
|
||||
];
|
||||
|
||||
/**
|
||||
* The fields to render items in the documents
|
||||
*
|
||||
* @var array
|
||||
* @since 4.1.0
|
||||
*/
|
||||
protected $fieldsToRenderList = [
|
||||
'type',
|
||||
'name',
|
||||
'path',
|
||||
'extension',
|
||||
'size',
|
||||
'mime_type',
|
||||
'width',
|
||||
'height',
|
||||
'create_date',
|
||||
'create_date_formatted',
|
||||
'modified_date',
|
||||
'modified_date_formatted',
|
||||
'thumb_path',
|
||||
'adapter',
|
||||
'content',
|
||||
'url',
|
||||
'tempUrl',
|
||||
];
|
||||
|
||||
/**
|
||||
* Prepare item before render.
|
||||
*
|
||||
* @param object $item The model item
|
||||
*
|
||||
* @return object
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
protected function prepareItem($item)
|
||||
{
|
||||
// Media resources have no id.
|
||||
$item->id = '0';
|
||||
|
||||
return $item;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user