first commit

This commit is contained in:
2025-06-17 11:53:18 +02:00
commit 9f0f7ba12b
8804 changed files with 1369176 additions and 0 deletions

View File

@ -0,0 +1,41 @@
<?php
/**
* @package Joomla.API
* @subpackage com_banners
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Banners\Api\Controller;
use Joomla\CMS\MVC\Controller\ApiController;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The banners controller
*
* @since 4.0.0
*/
class BannersController extends ApiController
{
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'banners';
/**
* The default view for the display method.
*
* @var string
* @since 3.0
*/
protected $default_view = 'banners';
}

View File

@ -0,0 +1,41 @@
<?php
/**
* @package Joomla.API
* @subpackage com_banners
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Banners\Api\Controller;
use Joomla\CMS\MVC\Controller\ApiController;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The clients controller
*
* @since 4.0.0
*/
class ClientsController extends ApiController
{
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'clients';
/**
* The default view for the display method.
*
* @var string
* @since 3.0
*/
protected $default_view = 'clients';
}

View File

@ -0,0 +1,101 @@
<?php
/**
* @package Joomla.API
* @subpackage com_banners
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Banners\Api\View\Banners;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The banners view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* The fields to render item in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderItem = [
'typeAlias',
'id',
'cid',
'type',
'name',
'alias',
'imptotal',
'impmade',
'clicks',
'clickurl',
'state',
'catid',
'description',
'custombannercode',
'sticky',
'ordering',
'metakey',
'params',
'own_prefix',
'metakey_prefix',
'purchase_type',
'track_clicks',
'track_impressions',
'checked_out',
'checked_out_time',
'publish_up',
'publish_down',
'reset',
'created',
'language',
'created_by',
'created_by_alias',
'modified',
'modified_by',
'version',
'contenthistoryHelper',
];
/**
* The fields to render items in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderList = [
'id',
'name',
'alias',
'checked_out',
'checked_out_time',
'catid',
'clicks',
'metakey',
'sticky',
'impmade',
'imptotal',
'state',
'ordering',
'purchase_type',
'language',
'publish_up',
'publish_down',
'language_image',
'editor',
'category_title',
'client_name',
'client_purchase_type',
];
}

View File

@ -0,0 +1,73 @@
<?php
/**
* @package Joomla.API
* @subpackage com_banners
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Banners\Api\View\Clients;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The clients view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* The fields to render item in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderItem = [
'typeAlias',
'id',
'checked_out_time',
'name',
'contact',
'email',
'checked_out',
'checked_out_time',
'extrainfo',
'state',
'metakey',
'own_prefix',
'metakey_prefix',
'purchase_type',
'track_clicks',
'track_impressions',
];
/**
* The fields to render items in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderList = [
'id',
'name',
'contact',
'checked_out',
'checked_out_time',
'state',
'metakey',
'purchase_type',
'nbanners',
'editor',
'count_published',
'count_unpublished',
'count_trashed',
'count_archived',
];
}

View File

@ -0,0 +1,144 @@
<?php
/**
* @package Joomla.API
* @subpackage com_categories
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Categories\Api\Controller;
use Joomla\CMS\MVC\Controller\ApiController;
use Joomla\CMS\Table\Category;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The categories controller
*
* @since 4.0.0
*/
class CategoriesController extends ApiController
{
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'categories';
/**
* The default view for the display method.
*
* @var string
* @since 3.0
*/
protected $default_view = 'categories';
/**
* Method to allow extended classes to manipulate the data to be saved for an extension.
*
* @param array $data An array of input data.
*
* @return array
*
* @since 4.0.0
*/
protected function preprocessSaveData(array $data): array
{
$extension = $this->getExtensionFromInput();
$data['extension'] = $extension;
// @todo: This is a hack to drop the extension into the global input object - to satisfy how state is built
// we should be able to improve this in the future
$this->input->set('extension', $extension);
return $data;
}
/**
* Method to save a record.
*
* @param integer $recordKey The primary key of the item (if exists)
*
* @return integer The record ID on success, false on failure
*
* @since 4.0.6
*/
protected function save($recordKey = null)
{
$recordId = parent::save($recordKey);
if (!$recordId) {
return $recordId;
}
$data = $this->input->get('data', json_decode($this->input->json->getRaw(), true), 'array');
if (empty($data['location'])) {
return $recordId;
}
/** @var Category $category */
$category = $this->getModel('Category')->getTable('Category');
$category->load((int) $recordId);
$reference = $category->parent_id;
if (!empty($data['location_reference'])) {
$reference = (int) $data['location_reference'];
}
$category->setLocation($reference, $data['location']);
$category->store();
return $recordId;
}
/**
* Basic display of an item view
*
* @param integer $id The primary key to display. Leave empty if you want to retrieve data from the request
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function displayItem($id = null)
{
$this->modelState->set('filter.extension', $this->getExtensionFromInput());
return parent::displayItem($id);
}
/**
* Basic display of a list view
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function displayList()
{
$this->modelState->set('filter.extension', $this->getExtensionFromInput());
return parent::displayList();
}
/**
* Get extension from input
*
* @return string
*
* @since 4.0.0
*/
private function getExtensionFromInput()
{
return $this->input->exists('extension') ?
$this->input->get('extension') : $this->input->post->get('extension');
}
}

View File

@ -0,0 +1,164 @@
<?php
/**
* @package Joomla.API
* @subpackage com_categories
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Categories\Api\View\Categories;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
use Joomla\CMS\Router\Exception\RouteNotFoundException;
use Joomla\Component\Fields\Administrator\Helper\FieldsHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The categories view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* The fields to render item in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderItem = [
'id',
'title',
'alias',
'note',
'published',
'access',
'checked_out',
'checked_out_time',
'created_user_id',
'parent_id',
'level',
'extension',
'lft',
'rgt',
'language',
'language_title',
'language_image',
'editor',
'access_level',
'author_name',
'count_trashed',
'count_unpublished',
'count_published',
'count_archived',
'params',
'description',
];
/**
* The fields to render items in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderList = [
'id',
'title',
'alias',
'note',
'published',
'access',
'checked_out',
'checked_out_time',
'created_user_id',
'parent_id',
'level',
'lft',
'rgt',
'language',
'language_title',
'language_image',
'editor',
'access_level',
'author_name',
'count_trashed',
'count_unpublished',
'count_published',
'count_archived',
'params',
'description',
];
/**
* Execute and display a template script.
*
* @param array|null $items Array of items
*
* @return string
*
* @since 4.0.0
*/
public function displayList(array $items = null)
{
foreach (FieldsHelper::getFields('com_content.categories') as $field) {
$this->fieldsToRenderList[] = $field->name;
}
return parent::displayList();
}
/**
* Execute and display a template script.
*
* @param object $item Item
*
* @return string
*
* @since 4.0.0
*/
public function displayItem($item = null)
{
foreach (FieldsHelper::getFields('com_content.categories') as $field) {
$this->fieldsToRenderItem[] = $field->name;
}
if ($item === null) {
/** @var \Joomla\CMS\MVC\Model\AdminModel $model */
$model = $this->getModel();
$item = $this->prepareItem($model->getItem());
}
if ($item->id === null) {
throw new RouteNotFoundException('Item does not exist');
}
if ($item->extension != $this->getModel()->getState('filter.extension')) {
throw new RouteNotFoundException('Item does not exist');
}
return parent::displayItem($item);
}
/**
* Prepare item before render.
*
* @param object $item The model item
*
* @return object
*
* @since 4.0.0
*/
protected function prepareItem($item)
{
foreach (FieldsHelper::getFields('com_content.categories', $item, true) as $field) {
$item->{$field->name} = $field->apivalue ?? $field->rawvalue;
}
return parent::prepareItem($item);
}
}

View File

@ -0,0 +1,146 @@
<?php
/**
* @package Joomla.API
* @subpackage com_config
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Config\Api\Controller;
use Joomla\CMS\Access\Exception\NotAllowed;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\ApiController;
use Joomla\Component\Config\Administrator\Model\ApplicationModel;
use Joomla\Component\Config\Api\View\Application\JsonapiView;
use Tobscure\JsonApi\Exception\InvalidParameterException;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The application controller
*
* @since 4.0.0
*/
class ApplicationController extends ApiController
{
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'application';
/**
* The default view for the display method.
*
* @var string
* @since 3.0
*/
protected $default_view = 'application';
/**
* Basic display of a list view
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function displayList()
{
$viewType = $this->app->getDocument()->getType();
$viewLayout = $this->input->get('layout', 'default', 'string');
try {
/** @var JsonapiView $view */
$view = $this->getView(
$this->default_view,
$viewType,
'',
['base_path' => $this->basePath, 'layout' => $viewLayout, 'contentType' => $this->contentType]
);
} catch (\Exception $e) {
throw new \RuntimeException($e->getMessage());
}
/** @var ApplicationModel $model */
$model = $this->getModel($this->contentType);
if (!$model) {
throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_MODEL_CREATE'), 500);
}
// Push the model into the view (as default)
$view->setModel($model, true);
$view->document = $this->app->getDocument();
$view->displayList();
return $this;
}
/**
* Method to edit an existing record.
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function edit()
{
/** @var ApplicationModel $model */
$model = $this->getModel($this->contentType);
if (!$model) {
throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_MODEL_CREATE'), 500);
}
// Access check.
if (!$this->allowEdit()) {
throw new NotAllowed('JLIB_APPLICATION_ERROR_CREATE_RECORD_NOT_PERMITTED', 403);
}
$data = json_decode($this->input->json->getRaw(), true);
// Complete data array if needed
$oldData = $model->getData();
$data = array_replace($oldData, $data);
// @todo: Not the cleanest thing ever but it works...
Form::addFormPath(JPATH_COMPONENT_ADMINISTRATOR . '/forms');
// Must load after serving service-requests
$form = $model->getForm();
// Validate the posted data.
$validData = $model->validate($form, $data);
// Check for validation errors.
if ($validData === false) {
$errors = $model->getErrors();
$messages = [];
for ($i = 0, $n = \count($errors); $i < $n && $i < 3; $i++) {
if ($errors[$i] instanceof \Exception) {
$messages[] = "{$errors[$i]->getMessage()}";
} else {
$messages[] = "{$errors[$i]}";
}
}
throw new InvalidParameterException(implode("\n", $messages));
}
if (!$model->save($validData)) {
throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_SERVER'), 500);
}
return $this;
}
}

View File

@ -0,0 +1,157 @@
<?php
/**
* @package Joomla.API
* @subpackage com_config
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Config\Api\Controller;
use Joomla\CMS\Access\Exception\NotAllowed;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Extension\ExtensionHelper;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\ApiController;
use Joomla\Component\Config\Administrator\Model\ComponentModel;
use Joomla\Component\Config\Api\View\Component\JsonapiView;
use Tobscure\JsonApi\Exception\InvalidParameterException;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The component controller
*
* @since 4.0.0
*/
class ComponentController extends ApiController
{
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'component';
/**
* The default view for the display method.
*
* @var string
* @since 3.0
*/
protected $default_view = 'component';
/**
* Basic display of a list view
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function displayList()
{
$viewType = $this->app->getDocument()->getType();
$viewLayout = $this->input->get('layout', 'default', 'string');
try {
/** @var JsonapiView $view */
$view = $this->getView(
$this->default_view,
$viewType,
'',
['base_path' => $this->basePath, 'layout' => $viewLayout, 'contentType' => $this->contentType]
);
} catch (\Exception $e) {
throw new \RuntimeException($e->getMessage());
}
/** @var ComponentModel $model */
$model = $this->getModel($this->contentType);
if (!$model) {
throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_MODEL_CREATE'), 500);
}
// Push the model into the view (as default)
$view->setModel($model, true);
$view->set('component_name', $this->input->get('component_name'));
$view->document = $this->app->getDocument();
$view->displayList();
return $this;
}
/**
* Method to edit an existing record.
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function edit()
{
/** @var ComponentModel $model */
$model = $this->getModel($this->contentType);
if (!$model) {
throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_MODEL_CREATE'), 500);
}
// Access check.
if (!$this->allowEdit()) {
throw new NotAllowed('JLIB_APPLICATION_ERROR_CREATE_RECORD_NOT_PERMITTED', 403);
}
$option = $this->input->get('component_name');
// @todo: Not the cleanest thing ever but it works...
Form::addFormPath(JPATH_ADMINISTRATOR . '/components/' . $option);
// Must load after serving service-requests
$form = $model->getForm();
$data = json_decode($this->input->json->getRaw(), true);
$component = ComponentHelper::getComponent($option);
$oldData = $component->getParams()->toArray();
$data = array_replace($oldData, $data);
// Validate the posted data.
$validData = $model->validate($form, $data);
if ($validData === false) {
$errors = $model->getErrors();
$messages = [];
for ($i = 0, $n = \count($errors); $i < $n && $i < 3; $i++) {
if ($errors[$i] instanceof \Exception) {
$messages[] = "{$errors[$i]->getMessage()}";
} else {
$messages[] = "{$errors[$i]}";
}
}
throw new InvalidParameterException(implode("\n", $messages));
}
// Attempt to save the configuration.
$data = [
'params' => $validData,
'id' => ExtensionHelper::getExtensionRecord($option, 'component')->extension_id,
'option' => $option,
];
if (!$model->save($data)) {
throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_SERVER'), 500);
}
return $this;
}
}

View File

@ -0,0 +1,123 @@
<?php
/**
* @package Joomla.API
* @subpackage com_config
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Config\Api\View\Application;
use Joomla\CMS\Extension\ExtensionHelper;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
use Joomla\CMS\Serializer\JoomlaSerializer;
use Joomla\CMS\Uri\Uri;
use Joomla\Component\Config\Administrator\Model\ApplicationModel;
use Tobscure\JsonApi\Collection;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The application view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* Execute and display a template script.
*
* @param array|null $items Array of items
*
* @return string
*
* @since 4.0.0
*/
public function displayList(array $items = null)
{
/** @var ApplicationModel $model */
$model = $this->getModel();
$items = [];
foreach ($model->getData() as $key => $value) {
$item = (object) [$key => $value];
$items[] = $this->prepareItem($item);
}
// Set up links for pagination
$currentUrl = Uri::getInstance();
$currentPageDefaultInformation = ['offset' => 0, 'limit' => 20];
$currentPageQuery = $currentUrl->getVar('page', $currentPageDefaultInformation);
$offset = $currentPageQuery['offset'];
$limit = $currentPageQuery['limit'];
$totalItemsCount = \count($items);
$totalPagesAvailable = ceil($totalItemsCount / $limit);
$items = array_splice($items, $offset, $limit);
$this->getDocument()->addMeta('total-pages', $totalPagesAvailable)
->addLink('self', (string) $currentUrl);
// Check for first and previous pages
if ($offset > 0) {
$firstPage = clone $currentUrl;
$firstPageQuery = $currentPageQuery;
$firstPageQuery['offset'] = 0;
$firstPage->setVar('page', $firstPageQuery);
$previousPage = clone $currentUrl;
$previousPageQuery = $currentPageQuery;
$previousOffset = $currentPageQuery['offset'] - $limit;
$previousPageQuery['offset'] = max($previousOffset, 0);
$previousPage->setVar('page', $previousPageQuery);
$this->getDocument()->addLink('first', $this->queryEncode((string) $firstPage))
->addLink('previous', $this->queryEncode((string) $previousPage));
}
// Check for next and last pages
if ($offset + $limit < $totalItemsCount) {
$nextPage = clone $currentUrl;
$nextPageQuery = $currentPageQuery;
$nextOffset = $currentPageQuery['offset'] + $limit;
$nextPageQuery['offset'] = ($nextOffset > ($totalPagesAvailable * $limit)) ? $totalPagesAvailable - $limit : $nextOffset;
$nextPage->setVar('page', $nextPageQuery);
$lastPage = clone $currentUrl;
$lastPageQuery = $currentPageQuery;
$lastPageQuery['offset'] = ($totalPagesAvailable - 1) * $limit;
$lastPage->setVar('page', $lastPageQuery);
$this->getDocument()->addLink('next', $this->queryEncode((string) $nextPage))
->addLink('last', $this->queryEncode((string) $lastPage));
}
$collection = (new Collection($items, new JoomlaSerializer($this->type)));
// Set the data into the document and render it
$this->getDocument()->setData($collection);
return $this->getDocument()->render();
}
/**
* Prepare item before render.
*
* @param object $item The model item
*
* @return object
*
* @since 4.0.0
*/
protected function prepareItem($item)
{
$item->id = ExtensionHelper::getExtensionRecord('joomla', 'file')->extension_id;
return $item;
}
}

View File

@ -0,0 +1,135 @@
<?php
/**
* @package Joomla.API
* @subpackage com_config
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Config\Api\View\Component;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Extension\ExtensionHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
use Joomla\CMS\Serializer\JoomlaSerializer;
use Joomla\CMS\Uri\Uri;
use Tobscure\JsonApi\Collection;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The component view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* Execute and display a template script.
*
* @param array|null $items Array of items
*
* @return string
*
* @since 4.0.0
*/
public function displayList(array $items = null)
{
try {
$component = ComponentHelper::getComponent($this->get('component_name'));
if ($component === null || !$component->enabled) {
// @todo: exception component unavailable
throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_INVALID_COMPONENT_NAME'), 400);
}
$data = $component->getParams()->toObject();
} catch (\Exception $e) {
throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_SERVER'), 500, $e);
}
$items = [];
foreach ($data as $key => $value) {
$item = (object) [$key => $value];
$items[] = $this->prepareItem($item);
}
// Set up links for pagination
$currentUrl = Uri::getInstance();
$currentPageDefaultInformation = ['offset' => 0, 'limit' => 20];
$currentPageQuery = $currentUrl->getVar('page', $currentPageDefaultInformation);
$offset = $currentPageQuery['offset'];
$limit = $currentPageQuery['limit'];
$totalItemsCount = \count($items);
$totalPagesAvailable = ceil($totalItemsCount / $limit);
$items = array_splice($items, $offset, $limit);
$this->getDocument()->addMeta('total-pages', $totalPagesAvailable)
->addLink('self', (string) $currentUrl);
// Check for first and previous pages
if ($offset > 0) {
$firstPage = clone $currentUrl;
$firstPageQuery = $currentPageQuery;
$firstPageQuery['offset'] = 0;
$firstPage->setVar('page', $firstPageQuery);
$previousPage = clone $currentUrl;
$previousPageQuery = $currentPageQuery;
$previousOffset = $currentPageQuery['offset'] - $limit;
$previousPageQuery['offset'] = max($previousOffset, 0);
$previousPage->setVar('page', $previousPageQuery);
$this->getDocument()->addLink('first', $this->queryEncode((string) $firstPage))
->addLink('previous', $this->queryEncode((string) $previousPage));
}
// Check for next and last pages
if ($offset + $limit < $totalItemsCount) {
$nextPage = clone $currentUrl;
$nextPageQuery = $currentPageQuery;
$nextOffset = $currentPageQuery['offset'] + $limit;
$nextPageQuery['offset'] = ($nextOffset > ($totalPagesAvailable * $limit)) ? $totalPagesAvailable - $limit : $nextOffset;
$nextPage->setVar('page', $nextPageQuery);
$lastPage = clone $currentUrl;
$lastPageQuery = $currentPageQuery;
$lastPageQuery['offset'] = ($totalPagesAvailable - 1) * $limit;
$lastPage->setVar('page', $lastPageQuery);
$this->getDocument()->addLink('next', $this->queryEncode((string) $nextPage))
->addLink('last', $this->queryEncode((string) $lastPage));
}
$collection = (new Collection($items, new JoomlaSerializer($this->type)));
// Set the data into the document and render it
$this->getDocument()->setData($collection);
return $this->getDocument()->render();
}
/**
* Prepare item before render.
*
* @param object $item The model item
*
* @return object
*
* @since 4.0.0
*/
protected function prepareItem($item)
{
$item->id = ExtensionHelper::getExtensionRecord($this->get('component_name'), 'component')->extension_id;
return $item;
}
}

View File

@ -0,0 +1,268 @@
<?php
/**
* @package Joomla.API
* @subpackage com_contact
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Contact\Api\Controller;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Event\Contact\SubmitContactEvent;
use Joomla\CMS\Event\Contact\ValidateContactEvent;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Log\Log;
use Joomla\CMS\Mail\Exception\MailDisabledException;
use Joomla\CMS\Mail\MailTemplate;
use Joomla\CMS\MVC\Controller\ApiController;
use Joomla\CMS\MVC\Controller\Exception\SendEmail;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\Router\Exception\RouteNotFoundException;
use Joomla\CMS\String\PunycodeHelper;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\User\UserFactoryAwareInterface;
use Joomla\CMS\User\UserFactoryAwareTrait;
use Joomla\Component\Fields\Administrator\Helper\FieldsHelper;
use Joomla\Registry\Registry;
use Joomla\String\Inflector;
use PHPMailer\PHPMailer\Exception as phpMailerException;
use Tobscure\JsonApi\Exception\InvalidParameterException;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The contact controller
*
* @since 4.0.0
*/
class ContactController extends ApiController implements UserFactoryAwareInterface
{
use UserFactoryAwareTrait;
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'contacts';
/**
* The default view for the display method.
*
* @var string
* @since 3.0
*/
protected $default_view = 'contacts';
/**
* Method to allow extended classes to manipulate the data to be saved for an extension.
*
* @param array $data An array of input data.
*
* @return array
*
* @since 4.0.0
*/
protected function preprocessSaveData(array $data): array
{
foreach (FieldsHelper::getFields('com_contact.contact') as $field) {
if (isset($data[$field->name])) {
!isset($data['com_fields']) && $data['com_fields'] = [];
$data['com_fields'][$field->name] = $data[$field->name];
unset($data[$field->name]);
}
}
return $data;
}
/**
* Submit contact form
*
* @param integer $id Leave empty if you want to retrieve data from the request
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function submitForm($id = null)
{
if ($id === null) {
$id = $this->input->post->get('id', 0, 'int');
}
$modelName = Inflector::singularize($this->contentType);
/** @var \Joomla\Component\Contact\Site\Model\ContactModel $model */
$model = $this->getModel($modelName, 'Site');
if (!$model) {
throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_MODEL_CREATE'));
}
$model->setState('filter.published', 1);
$data = $this->input->get('data', json_decode($this->input->json->getRaw(), true), 'array');
$contact = $model->getItem($id);
if ($contact->id === null) {
throw new RouteNotFoundException('Item does not exist');
}
$contactParams = new Registry($contact->params);
if (!$contactParams->get('show_email_form')) {
throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_DISPLAY_EMAIL_FORM'));
}
// Contact plugins
PluginHelper::importPlugin('contact');
Form::addFormPath(JPATH_COMPONENT_SITE . '/forms');
// Validate the posted data.
$form = $model->getForm();
if (!$form) {
throw new \RuntimeException($model->getError(), 500);
}
if (!$model->validate($form, $data)) {
$errors = $model->getErrors();
$messages = [];
for ($i = 0, $n = \count($errors); $i < $n && $i < 3; $i++) {
if ($errors[$i] instanceof \Exception) {
$messages[] = "{$errors[$i]->getMessage()}";
} else {
$messages[] = "{$errors[$i]}";
}
}
throw new InvalidParameterException(implode("\n", $messages));
}
// Validation succeeded, continue with custom handlers
$results = $this->getDispatcher()->dispatch('onValidateContact', new ValidateContactEvent('onValidateContact', [
'subject' => $contact,
'data' => &$data, // @todo: Remove reference in Joomla 6, @deprecated: Data modification onValidateContact is not allowed, use onSubmitContact instead
]))->getArgument('result', []);
foreach ($results as $result) {
if ($result instanceof \Exception) {
throw new InvalidParameterException($result->getMessage());
}
}
// Passed Validation: Process the contact plugins to integrate with other applications
$event = $this->getDispatcher()->dispatch('onSubmitContact', new SubmitContactEvent('onSubmitContact', [
'subject' => $contact,
'data' => &$data, // @todo: Remove reference in Joomla 6, see SubmitContactEvent::__constructor()
]));
// Get the final data
$data = $event->getArgument('data', $data);
// Send the email
$sent = false;
$params = ComponentHelper::getParams('com_contact');
if (!$params->get('custom_reply')) {
$sent = $this->_sendEmail($data, $contact, $params->get('show_email_copy', 0));
}
if (!$sent) {
throw new SendEmail('Error sending message');
}
return $this;
}
/**
* Method to get a model object, loading it if required.
*
* @param array $data The data to send in the email.
* @param \stdClass $contact The user information to send the email to
* @param boolean $emailCopyToSender True to send a copy of the email to the user.
*
* @return boolean True on success sending the email, false on failure.
*
* @since 1.6.4
*/
private function _sendEmail($data, $contact, $emailCopyToSender)
{
$app = $this->app;
$app->getLanguage()->load('com_contact', JPATH_SITE, $app->getLanguage()->getTag(), true);
if ($contact->email_to == '' && $contact->user_id != 0) {
$contact_user = $this->getUserFactory()->loadUserById($contact->user_id);
$contact->email_to = $contact_user->get('email');
}
$templateData = [
'sitename' => $app->get('sitename'),
'name' => $data['contact_name'],
'contactname' => $contact->name,
'email' => PunycodeHelper::emailToPunycode($data['contact_email']),
'subject' => $data['contact_subject'],
'body' => stripslashes($data['contact_message']),
'url' => Uri::base(),
'customfields' => '',
];
// Load the custom fields
if (!empty($data['com_fields']) && $fields = FieldsHelper::getFields('com_contact.mail', $contact, true, $data['com_fields'])) {
$output = FieldsHelper::render(
'com_contact.mail',
'fields.render',
[
'context' => 'com_contact.mail',
'item' => $contact,
'fields' => $fields,
]
);
if ($output) {
$templateData['customfields'] = $output;
}
}
try {
$mailer = new MailTemplate('com_contact.mail', $app->getLanguage()->getTag());
$mailer->addRecipient($contact->email_to);
$mailer->setReplyTo($templateData['email'], $templateData['name']);
$mailer->addTemplateData($templateData);
$sent = $mailer->send();
// If we are supposed to copy the sender, do so.
if ($emailCopyToSender == true && !empty($data['contact_email_copy'])) {
$mailer = new MailTemplate('com_contact.mail.copy', $app->getLanguage()->getTag());
$mailer->addRecipient($templateData['email']);
$mailer->setReplyTo($templateData['email'], $templateData['name']);
$mailer->addTemplateData($templateData);
$sent = $mailer->send();
}
} catch (MailDisabledException | phpMailerException $exception) {
try {
Log::add(Text::_($exception->getMessage()), Log::WARNING, 'jerror');
$sent = false;
} catch (\RuntimeException $exception) {
Factory::getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning');
$sent = false;
}
}
return $sent;
}
}

View File

@ -0,0 +1,134 @@
<?php
/**
* Joomla! Content Management System
*
* @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\Contact\Api\Serializer;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Serializer\JoomlaSerializer;
use Joomla\CMS\Tag\TagApiSerializerTrait;
use Joomla\CMS\Uri\Uri;
use Tobscure\JsonApi\Collection;
use Tobscure\JsonApi\Relationship;
use Tobscure\JsonApi\Resource;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Temporary serializer
*
* @since 4.0.0
*/
class ContactSerializer extends JoomlaSerializer
{
use TagApiSerializerTrait;
/**
* Build content relationships by associations
*
* @param \stdClass $model Item model
*
* @return Relationship
*
* @since 4.0.0
*/
public function languageAssociations($model)
{
$resources = [];
// @todo: This can't be hardcoded in the future?
$serializer = new JoomlaSerializer($this->type);
foreach ($model->associations as $association) {
$resources[] = (new Resource($association, $serializer))
->addLink('self', Route::link('site', Uri::root() . 'api/index.php/v1/contact/' . $association->id));
}
$collection = new Collection($resources, $serializer);
return new Relationship($collection);
}
/**
* Build category relationship
*
* @param \stdClass $model Item model
*
* @return Relationship
*
* @since 4.0.0
*/
public function category($model)
{
$serializer = new JoomlaSerializer('categories');
$resource = (new Resource($model->catid, $serializer))
->addLink('self', Route::link('site', Uri::root() . 'api/index.php/v1/content/categories/' . $model->catid));
return new Relationship($resource);
}
/**
* Build category relationship
*
* @param \stdClass $model Item model
*
* @return Relationship
*
* @since 4.0.0
*/
public function createdBy($model)
{
$serializer = new JoomlaSerializer('users');
$resource = (new Resource($model->created_by, $serializer))
->addLink('self', Route::link('site', Uri::root() . 'api/index.php/v1/users/' . $model->created_by));
return new Relationship($resource);
}
/**
* Build editor relationship
*
* @param \stdClass $model Item model
*
* @return Relationship
*
* @since 4.0.0
*/
public function modifiedBy($model)
{
$serializer = new JoomlaSerializer('users');
$resource = (new Resource($model->modified_by, $serializer))
->addLink('self', Route::link('site', Uri::root() . 'api/index.php/v1/users/' . $model->modified_by));
return new Relationship($resource);
}
/**
* Build contact user relationship
*
* @param \stdClass $model Item model
*
* @return Relationship
*
* @since 4.0.0
*/
public function userId($model)
{
$serializer = new JoomlaSerializer('users');
$resource = (new Resource($model->user_id, $serializer))
->addLink('self', Route::link('site', Uri::root() . 'api/index.php/v1/users/' . $model->user_id));
return new Relationship($resource);
}
}

View File

@ -0,0 +1,214 @@
<?php
/**
* @package Joomla.API
* @subpackage com_contact
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Contact\Api\View\Contacts;
use Joomla\CMS\Language\Multilanguage;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
use Joomla\Component\Contact\Api\Serializer\ContactSerializer;
use Joomla\Component\Content\Api\Helper\ContentHelper;
use Joomla\Component\Fields\Administrator\Helper\FieldsHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The contacts view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* The fields to render item in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderItem = [
'id',
'alias',
'name',
'category',
'created',
'created_by',
'created_by_alias',
'modified',
'modified_by',
'image',
'tags',
'featured',
'publish_up',
'publish_down',
'version',
'hits',
'metakey',
'metadesc',
'metadata',
'con_position',
'address',
'suburb',
'state',
'country',
'postcode',
'telephone',
'fax',
'misc',
'email_to',
'default_con',
'user_id',
'access',
'mobile',
'webpage',
'sortname1',
'sortname2',
'sortname3',
];
/**
* The fields to render items in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderList = [
'id',
'alias',
'name',
'category',
'created',
'created_by',
'created_by_alias',
'modified',
'modified_by',
'image',
'tags',
'user_id',
];
/**
* The relationships the item has
*
* @var array
* @since 4.0.0
*/
protected $relationship = [
'category',
'created_by',
'modified_by',
'user_id',
'tags',
];
/**
* Constructor.
*
* @param array $config A named configuration array for object construction.
* contentType: the name (optional) of the content type to use for the serialization
*
* @since 4.0.0
*/
public function __construct($config = [])
{
if (\array_key_exists('contentType', $config)) {
$this->serializer = new ContactSerializer($config['contentType']);
}
parent::__construct($config);
}
/**
* Execute and display a template script.
*
* @param array|null $items Array of items
*
* @return string
*
* @since 4.0.0
*/
public function displayList(array $items = null)
{
foreach (FieldsHelper::getFields('com_contact.contact') as $field) {
$this->fieldsToRenderList[] = $field->name;
}
return parent::displayList();
}
/**
* Execute and display a template script.
*
* @param object $item Item
*
* @return string
*
* @since 4.0.0
*/
public function displayItem($item = null)
{
foreach (FieldsHelper::getFields('com_contact.contact') as $field) {
$this->fieldsToRenderItem[] = $field->name;
}
if (Multilanguage::isEnabled()) {
$this->fieldsToRenderItem[] = 'languageAssociations';
$this->relationship[] = 'languageAssociations';
}
return parent::displayItem();
}
/**
* Prepare item before render.
*
* @param object $item The model item
*
* @return object
*
* @since 4.0.0
*/
protected function prepareItem($item)
{
foreach (FieldsHelper::getFields('com_contact.contact', $item, true) as $field) {
$item->{$field->name} = $field->apivalue ?? $field->rawvalue;
}
if (Multilanguage::isEnabled() && !empty($item->associations)) {
$associations = [];
foreach ($item->associations as $language => $association) {
$itemId = explode(':', $association)[0];
$associations[] = (object) [
'id' => $itemId,
'language' => $language,
];
}
$item->associations = $associations;
}
if (!empty($item->tags->tags)) {
$tagsIds = explode(',', $item->tags->tags);
$tagsNames = $item->tagsHelper->getTagNames($tagsIds);
$item->tags = array_combine($tagsIds, $tagsNames);
} else {
$item->tags = [];
}
if (isset($item->image)) {
$item->image = ContentHelper::resolve($item->image);
}
return parent::prepareItem($item);
}
}

View File

@ -0,0 +1,119 @@
<?php
/**
* @package Joomla.API
* @subpackage com_content
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Content\Api\Controller;
use Joomla\CMS\Filter\InputFilter;
use Joomla\CMS\MVC\Controller\ApiController;
use Joomla\Component\Fields\Administrator\Helper\FieldsHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The article controller
*
* @since 4.0.0
*/
class ArticlesController extends ApiController
{
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'articles';
/**
* The default view for the display method.
*
* @var string
* @since 3.0
*/
protected $default_view = 'articles';
/**
* Article list view amended to add filtering of data
*
* @return static A BaseController object to support chaining.
*
* @since 4.0.0
*/
public function displayList()
{
$apiFilterInfo = $this->input->get('filter', [], 'array');
$filter = InputFilter::getInstance();
if (\array_key_exists('author', $apiFilterInfo)) {
$this->modelState->set('filter.author_id', $filter->clean($apiFilterInfo['author'], 'INT'));
}
if (\array_key_exists('category', $apiFilterInfo)) {
$this->modelState->set('filter.category_id', $filter->clean($apiFilterInfo['category'], 'INT'));
}
if (\array_key_exists('search', $apiFilterInfo)) {
$this->modelState->set('filter.search', $filter->clean($apiFilterInfo['search'], 'STRING'));
}
if (\array_key_exists('state', $apiFilterInfo)) {
$this->modelState->set('filter.published', $filter->clean($apiFilterInfo['state'], 'INT'));
}
if (\array_key_exists('featured', $apiFilterInfo)) {
$this->modelState->set('filter.featured', $filter->clean($apiFilterInfo['featured'], 'INT'));
}
if (\array_key_exists('tag', $apiFilterInfo)) {
$this->modelState->set('filter.tag', $filter->clean($apiFilterInfo['tag'], 'INT'));
}
if (\array_key_exists('language', $apiFilterInfo)) {
$this->modelState->set('filter.language', $filter->clean($apiFilterInfo['language'], 'STRING'));
}
$apiListInfo = $this->input->get('list', [], 'array');
if (\array_key_exists('ordering', $apiListInfo)) {
$this->modelState->set('list.ordering', $filter->clean($apiListInfo['ordering'], 'STRING'));
}
if (\array_key_exists('direction', $apiListInfo)) {
$this->modelState->set('list.direction', $filter->clean($apiListInfo['direction'], 'STRING'));
}
return parent::displayList();
}
/**
* Method to allow extended classes to manipulate the data to be saved for an extension.
*
* @param array $data An array of input data.
*
* @return array
*
* @since 4.0.0
*/
protected function preprocessSaveData(array $data): array
{
foreach (FieldsHelper::getFields('com_content.article') as $field) {
if (isset($data[$field->name])) {
!isset($data['com_fields']) && $data['com_fields'] = [];
$data['com_fields'][$field->name] = $data[$field->name];
unset($data[$field->name]);
}
}
return $data;
}
}

View File

@ -0,0 +1,42 @@
<?php
/**
* @package Joomla.Api
* @subpackage com_content
*
* @copyright (C) 2020 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Content\Api\Helper;
use Joomla\CMS\Uri\Uri;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Content api helper.
*
* @since 4.0.0
*/
class ContentHelper
{
/**
* Fully Qualified Domain name for the image url
*
* @param string $uri The uri to resolve
*
* @return string
*/
public static function resolve(string $uri): string
{
// Check if external URL.
if (stripos($uri, 'http') !== 0) {
return Uri::root() . $uri;
}
return $uri;
}
}

View File

@ -0,0 +1,112 @@
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Content\Api\Serializer;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Serializer\JoomlaSerializer;
use Joomla\CMS\Uri\Uri;
use Tobscure\JsonApi\Collection;
use Tobscure\JsonApi\Relationship;
use Tobscure\JsonApi\Resource;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Temporary serializer
*
* @since 4.0.0
*/
class ContentSerializer extends JoomlaSerializer
{
/**
* Build content relationships by associations
*
* @param \stdClass $model Item model
*
* @return Relationship
*
* @since 4.0.0
*/
public function languageAssociations($model)
{
$resources = [];
// @todo: This can't be hardcoded in the future?
$serializer = new JoomlaSerializer($this->type);
foreach ($model->associations as $association) {
$resources[] = (new Resource($association, $serializer))
->addLink('self', Route::link('site', Uri::root() . 'api/index.php/v1/content/articles/' . $association->id));
}
$collection = new Collection($resources, $serializer);
return new Relationship($collection);
}
/**
* Build category relationship
*
* @param \stdClass $model Item model
*
* @return Relationship
*
* @since 4.0.0
*/
public function category($model)
{
$serializer = new JoomlaSerializer('categories');
$resource = (new Resource($model->catid, $serializer))
->addLink('self', Route::link('site', Uri::root() . 'api/index.php/v1/content/categories/' . $model->catid));
return new Relationship($resource);
}
/**
* Build category relationship
*
* @param \stdClass $model Item model
*
* @return Relationship
*
* @since 4.0.0
*/
public function createdBy($model)
{
$serializer = new JoomlaSerializer('users');
$resource = (new Resource($model->created_by, $serializer))
->addLink('self', Route::link('site', Uri::root() . 'api/index.php/v1/users/' . $model->created_by));
return new Relationship($resource);
}
/**
* Build editor relationship
*
* @param \stdClass $model Item model
*
* @return Relationship
*
* @since 4.0.0
*/
public function modifiedBy($model)
{
$serializer = new JoomlaSerializer('users');
$resource = (new Resource($model->modified_by, $serializer))
->addLink('self', Route::link('site', Uri::root() . 'api/index.php/v1/users/' . $model->modified_by));
return new Relationship($resource);
}
}

View File

@ -0,0 +1,250 @@
<?php
/**
* @package Joomla.API
* @subpackage com_content
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Content\Api\View\Articles;
use Joomla\CMS\Factory;
use Joomla\CMS\Helper\TagsHelper;
use Joomla\CMS\Language\Multilanguage;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\Component\Content\Api\Helper\ContentHelper;
use Joomla\Component\Content\Api\Serializer\ContentSerializer;
use Joomla\Component\Fields\Administrator\Helper\FieldsHelper;
use Joomla\Registry\Registry;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The article view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* The fields to render item in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderItem = [
'id',
'typeAlias',
'asset_id',
'title',
'text',
'tags',
'language',
'state',
'category',
'images',
'metakey',
'metadesc',
'metadata',
'access',
'featured',
'alias',
'note',
'publish_up',
'publish_down',
'urls',
'created',
'created_by',
'created_by_alias',
'modified',
'modified_by',
'hits',
'version',
'featured_up',
'featured_down',
];
/**
* The fields to render items in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderList = [
'id',
'typeAlias',
'asset_id',
'title',
'text',
'tags',
'language',
'state',
'category',
'images',
'metakey',
'metadesc',
'metadata',
'access',
'featured',
'alias',
'note',
'publish_up',
'publish_down',
'urls',
'created',
'created_by',
'created_by_alias',
'modified',
'hits',
'version',
'featured_up',
'featured_down',
];
/**
* The relationships the item has
*
* @var array
* @since 4.0.0
*/
protected $relationship = [
'category',
'created_by',
'tags',
];
/**
* Constructor.
*
* @param array $config A named configuration array for object construction.
* contentType: the name (optional) of the content type to use for the serialization
*
* @since 4.0.0
*/
public function __construct($config = [])
{
if (\array_key_exists('contentType', $config)) {
$this->serializer = new ContentSerializer($config['contentType']);
}
parent::__construct($config);
}
/**
* Execute and display a template script.
*
* @param array|null $items Array of items
*
* @return string
*
* @since 4.0.0
*/
public function displayList(array $items = null)
{
foreach (FieldsHelper::getFields('com_content.article') as $field) {
$this->fieldsToRenderList[] = $field->name;
}
return parent::displayList();
}
/**
* Execute and display a template script.
*
* @param object $item Item
*
* @return string
*
* @since 4.0.0
*/
public function displayItem($item = null)
{
$this->relationship[] = 'modified_by';
foreach (FieldsHelper::getFields('com_content.article') as $field) {
$this->fieldsToRenderItem[] = $field->name;
}
if (Multilanguage::isEnabled()) {
$this->fieldsToRenderItem[] = 'languageAssociations';
$this->relationship[] = 'languageAssociations';
}
return parent::displayItem();
}
/**
* Prepare item before render.
*
* @param object $item The model item
*
* @return object
*
* @since 4.0.0
*/
protected function prepareItem($item)
{
if (!$item) {
return $item;
}
$item->text = $item->introtext . ' ' . $item->fulltext;
// Process the content plugins.
PluginHelper::importPlugin('content');
Factory::getApplication()->triggerEvent('onContentPrepare', ['com_content.article', &$item, &$item->params]);
foreach (FieldsHelper::getFields('com_content.article', $item, true) as $field) {
$item->{$field->name} = $field->apivalue ?? $field->rawvalue;
}
if (Multilanguage::isEnabled() && !empty($item->associations)) {
$associations = [];
foreach ($item->associations as $language => $association) {
$itemId = explode(':', $association)[0];
$associations[] = (object) [
'id' => $itemId,
'language' => $language,
];
}
$item->associations = $associations;
}
if (!empty($item->tags->tags)) {
$tagsIds = explode(',', $item->tags->tags);
$item->tags = $item->tagsHelper->getTags($tagsIds);
} else {
$item->tags = [];
$tags = new TagsHelper();
$tagsIds = $tags->getTagIds($item->id, 'com_content.article');
if (!empty($tagsIds)) {
$tagsIds = explode(',', $tagsIds);
$item->tags = $tags->getTags($tagsIds);
}
}
if (isset($item->images)) {
$registry = new Registry($item->images);
$item->images = $registry->toArray();
if (!empty($item->images['image_intro'])) {
$item->images['image_intro'] = ContentHelper::resolve($item->images['image_intro']);
}
if (!empty($item->images['image_fulltext'])) {
$item->images['image_fulltext'] = ContentHelper::resolve($item->images['image_fulltext']);
}
}
return parent::prepareItem($item);
}
}

View File

@ -0,0 +1,132 @@
<?php
/**
* @package Joomla.API
* @subpackage com_contenthistory
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Contenthistory\Api\Controller;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\ApiController;
use Joomla\CMS\MVC\Controller\Exception;
use Joomla\Component\Contenthistory\Administrator\Model\HistoryModel;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The history controller
*
* @since 4.0.0
*/
class HistoryController extends ApiController
{
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'history';
/**
* The default view for the display method.
*
* @var string
* @since 3.0
*/
protected $default_view = 'history';
/**
* Basic display of a list view
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function displayList()
{
$this->modelState->set('type_alias', $this->getTypeAliasFromInput());
$this->modelState->set('type_id', $this->getTypeIdFromInput());
$this->modelState->set('item_id', $this->getTypeAliasFromInput() . '.' . $this->getItemIdFromInput());
$this->modelState->set('list.ordering', 'h.save_date');
$this->modelState->set('list.direction', 'DESC');
return parent::displayList();
}
/**
* Method to edit an existing record.
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function keep()
{
/** @var HistoryModel $model */
$model = $this->getModel($this->contentType);
if (!$model) {
throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_MODEL_CREATE'));
}
$recordId = $this->input->getInt('id');
if (!$recordId) {
throw new Exception\ResourceNotFound(Text::_('JLIB_APPLICATION_ERROR_RECORD'), 404);
}
$cid = [$recordId];
if (!$model->keep($cid)) {
throw new Exception\Save(Text::plural('COM_CONTENTHISTORY_N_ITEMS_KEEP_TOGGLE', \count($cid)));
}
return $this;
}
/**
* Get item id from input
*
* @return string
*
* @since 4.0.0
*/
private function getItemIdFromInput()
{
return $this->input->exists('id') ?
$this->input->get('id') : $this->input->post->get('id');
}
/**
* Get type id from input
*
* @return string
*
* @since 4.0.0
*/
private function getTypeIdFromInput()
{
return $this->input->exists('type_id') ?
$this->input->get('type_id') : $this->input->post->get('type_id');
}
/**
* Get type alias from input
*
* @return string
*
* @since 4.0.0
*/
private function getTypeAliasFromInput()
{
return $this->input->exists('type_alias') ?
$this->input->get('type_alias') : $this->input->post->get('type_alias');
}
}

View File

@ -0,0 +1,64 @@
<?php
/**
* @package Joomla.API
* @subpackage com_contenthistory
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Contenthistory\Api\View\History;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The history view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* The fields to render items in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderList = [
'id',
'ucm_item_id',
'ucm_type_id',
'version_note',
'save_date',
'editor_user_id',
'character_count',
'sha1_hash',
'version_data',
'keep_forever',
'editor',
];
/**
* Prepare item before render.
*
* @param object $item The model item
*
* @return object
*
* @since 4.0.0
*/
protected function prepareItem($item)
{
$item->id = $item->version_id;
unset($item->version_id);
$item->version_data = (array) json_decode($item->version_data, true);
return parent::prepareItem($item);
}
}

View File

@ -0,0 +1,84 @@
<?php
/**
* @package Joomla.API
* @subpackage com_fields
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Fields\Api\Controller;
use Joomla\CMS\MVC\Controller\ApiController;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The fields controller
*
* @since 4.0.0
*/
class FieldsController extends ApiController
{
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'fields';
/**
* The default view for the display method.
*
* @var string
* @since 3.0
*/
protected $default_view = 'fields';
/**
* Basic display of an item view
*
* @param integer $id The primary key to display. Leave empty if you want to retrieve data from the request
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function displayItem($id = null)
{
$this->modelState->set('filter.context', $this->getContextFromInput());
return parent::displayItem($id);
}
/**
* Basic display of a list view
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function displayList()
{
$this->modelState->set('filter.context', $this->getContextFromInput());
return parent::displayList();
}
/**
* Get extension from input
*
* @return string
*
* @since 4.0.0
*/
private function getContextFromInput()
{
return $this->input->exists('context') ?
$this->input->get('context') : $this->input->post->get('context');
}
}

View File

@ -0,0 +1,84 @@
<?php
/**
* @package Joomla.API
* @subpackage com_fields
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Fields\Api\Controller;
use Joomla\CMS\MVC\Controller\ApiController;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The groups controller
*
* @since 4.0.0
*/
class GroupsController extends ApiController
{
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'groups';
/**
* The default view for the display method.
*
* @var string
* @since 3.0
*/
protected $default_view = 'groups';
/**
* Basic display of an item view
*
* @param integer $id The primary key to display. Leave empty if you want to retrieve data from the request
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function displayItem($id = null)
{
$this->modelState->set('filter.context', $this->getContextFromInput());
return parent::displayItem($id);
}
/**
* Basic display of a list view
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function displayList()
{
$this->modelState->set('filter.context', $this->getContextFromInput());
return parent::displayList();
}
/**
* Get extension from input
*
* @return string
*
* @since 4.0.0
*/
private function getContextFromInput()
{
return $this->input->exists('context') ?
$this->input->get('context') : $this->input->post->get('context');
}
}

View File

@ -0,0 +1,128 @@
<?php
/**
* @package Joomla.API
* @subpackage com_fields
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Fields\Api\View\Fields;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
use Joomla\CMS\Router\Exception\RouteNotFoundException;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The fields view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* The fields to render item in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderItem = [
'typeAlias',
'id',
'asset_id',
'context',
'group_id',
'title',
'name',
'label',
'default_value',
'type',
'note',
'description',
'state',
'required',
'checked_out',
'checked_out_time',
'ordering',
'params',
'fieldparams',
'language',
'created_time',
'created_user_id',
'modified_time',
'modified_by',
'access',
'assigned_cat_ids',
];
/**
* The fields to render items in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderList = [
'id',
'title',
'name',
'checked_out',
'checked_out_time',
'note',
'state',
'access',
'created_time',
'created_user_id',
'ordering',
'language',
'fieldparams',
'params',
'type',
'default_value',
'context',
'group_id',
'label',
'description',
'required',
'language_title',
'language_image',
'editor',
'access_level',
'author_name',
'group_title',
'group_access',
'group_state',
'group_note',
];
/**
* Execute and display a template script.
*
* @param object $item Item
*
* @return string
*
* @since 4.0.0
*/
public function displayItem($item = null)
{
if ($item === null) {
/** @var \Joomla\CMS\MVC\Model\AdminModel $model */
$model = $this->getModel();
$item = $this->prepareItem($model->getItem());
}
if ($item->id === null) {
throw new RouteNotFoundException('Item does not exist');
}
if ($item->context != $this->getModel()->getState('filter.context')) {
throw new RouteNotFoundException('Item does not exist');
}
return parent::displayItem($item);
}
}

View File

@ -0,0 +1,121 @@
<?php
/**
* @package Joomla.API
* @subpackage com_fields
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Fields\Api\View\Groups;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
use Joomla\CMS\Router\Exception\RouteNotFoundException;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The groups view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* The fields to render item in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderItem = [
'typeAlias',
'id',
'asset_id',
'context',
'title',
'note',
'description',
'state',
'checked_out',
'checked_out_time',
'ordering',
'params',
'language',
'created',
'created_by',
'modified',
'modified_by',
'access',
'type',
];
/**
* The fields to render items in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderList = [
'id',
'title',
'name',
'checked_out',
'checked_out_time',
'note',
'state',
'access',
'created_time',
'created_user_id',
'ordering',
'language',
'fieldparams',
'params',
'type',
'default_value',
'context',
'group_id',
'label',
'description',
'required',
'language_title',
'language_image',
'editor',
'access_level',
'author_name',
'group_title',
'group_access',
'group_state',
'group_note',
];
/**
* Execute and display a template script.
*
* @param object $item Item
*
* @return string
*
* @since 4.0.0
*/
public function displayItem($item = null)
{
if ($item === null) {
/** @var \Joomla\CMS\MVC\Model\AdminModel $model */
$model = $this->getModel();
$item = $this->prepareItem($model->getItem());
}
if ($item->id === null) {
throw new RouteNotFoundException('Item does not exist');
}
if ($item->context != $this->getModel()->getState('filter.context')) {
throw new RouteNotFoundException('Item does not exist');
}
return parent::displayItem($item);
}
}

View File

@ -0,0 +1,71 @@
<?php
/**
* @package Joomla.API
* @subpackage com_installer
*
* @copyright (C) 2020 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Installer\Api\Controller;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\ApiController;
use Tobscure\JsonApi\Exception\InvalidParameterException;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The manage controller
*
* @since 4.0.0
*/
class ManageController extends ApiController
{
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'manage';
/**
* The default view for the display method.
*
* @var string
* @since 4.0.0
*/
protected $default_view = 'manage';
/**
* Extension list view amended to add filtering of data
*
* @return static A BaseController object to support chaining.
*
* @since 4.0.0
*/
public function displayList()
{
$requestBool = $this->input->get('core', $this->input->get->get('core'));
if (!\is_null($requestBool) && $requestBool !== 'true' && $requestBool !== 'false') {
// Send the error response
$error = Text::sprintf('JLIB_FORM_VALIDATE_FIELD_INVALID', 'core');
throw new InvalidParameterException($error, 400, null, 'core');
}
if (!\is_null($requestBool)) {
$this->modelState->set('filter.core', ($requestBool === 'true') ? '1' : '0');
}
$this->modelState->set('filter.status', $this->input->get('status', $this->input->get->get('status', null, 'INT'), 'INT'));
$this->modelState->set('filter.type', $this->input->get('type', $this->input->get->get('type', null, 'STRING'), 'STRING'));
return parent::displayList();
}
}

View File

@ -0,0 +1,58 @@
<?php
/**
* @package Joomla.API
* @subpackage com_installer
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Installer\Api\View\Manage;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The manage view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* The fields to render item in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderList = [
'id',
'name',
'type',
'version',
'folder',
'status',
'client_id',
];
/**
* Prepare item before render.
*
* @param object $item The model item
*
* @return object
*
* @since 4.0.0
*/
protected function prepareItem($item)
{
$item->id = $item->extension_id;
unset($item->extension_id);
return $item;
}
}

View File

@ -0,0 +1,41 @@
<?php
/**
* @package Joomla.API
* @subpackage com_languages
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Languages\Api\Controller;
use Joomla\CMS\MVC\Controller\ApiController;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The languages controller
*
* @since 4.0.0
*/
class LanguagesController extends ApiController
{
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'languages';
/**
* The default view for the display method.
*
* @var string
* @since 3.0
*/
protected $default_view = 'languages';
}

View File

@ -0,0 +1,187 @@
<?php
/**
* @package Joomla.API
* @subpackage com_languages
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Languages\Api\Controller;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\ApiController;
use Joomla\CMS\MVC\Controller\Exception;
use Joomla\String\Inflector;
use Tobscure\JsonApi\Exception\InvalidParameterException;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The overrides controller
*
* @since 4.0.0
*/
class OverridesController extends ApiController
{
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'overrides';
/**
* The default view for the display method.
*
* @var string
* @since 3.0
*/
protected $default_view = 'overrides';
/**
* Basic display of an item view
*
* @param integer $id The primary key to display. Leave empty if you want to retrieve data from the request
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function displayItem($id = null)
{
$this->modelState->set('filter.language', $this->getLanguageFromInput());
$this->modelState->set('filter.client', $this->getClientFromInput());
return parent::displayItem($id);
}
/**
* Basic display of a list view
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function displayList()
{
$this->modelState->set('filter.language', $this->getLanguageFromInput());
$this->modelState->set('filter.client', $this->getClientFromInput());
return parent::displayList();
}
/**
* Method to save a record.
*
* @param integer $recordKey The primary key of the item (if exists)
*
* @return integer The record ID on success, false on failure
*
* @since 4.0.0
*/
protected function save($recordKey = null)
{
/** @var \Joomla\CMS\MVC\Model\AdminModel $model */
$model = $this->getModel(Inflector::singularize($this->contentType));
if (!$model) {
throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_MODEL_CREATE'));
}
$model->setState('filter.language', $this->input->post->get('lang_code'));
$model->setState('filter.client', $this->input->post->get('app'));
$data = $this->input->get('data', json_decode($this->input->json->getRaw(), true), 'array');
// @todo: Not the cleanest thing ever but it works...
Form::addFormPath(JPATH_COMPONENT_ADMINISTRATOR . '/forms');
// Validate the posted data.
$form = $model->getForm($data, false);
if (!$form) {
throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_FORM_CREATE'));
}
// Test whether the data is valid.
$validData = $model->validate($form, $data);
// Check for validation errors.
if ($validData === false) {
$errors = $model->getErrors();
$messages = [];
for ($i = 0, $n = \count($errors); $i < $n && $i < 3; $i++) {
if ($errors[$i] instanceof \Exception) {
$messages[] = "{$errors[$i]->getMessage()}";
} else {
$messages[] = "{$errors[$i]}";
}
}
throw new InvalidParameterException(implode("\n", $messages));
}
if (!isset($validData['tags'])) {
$validData['tags'] = [];
}
if (!$model->save($validData)) {
throw new Exception\Save(Text::sprintf('JLIB_APPLICATION_ERROR_SAVE_FAILED', $model->getError()));
}
return $validData['key'];
}
/**
* Removes an item.
*
* @param integer $id The primary key to delete item.
*
* @return void
*
* @since 4.0.0
*/
public function delete($id = null)
{
$id = $this->input->get('id', '', 'string');
$this->input->set('model', $this->contentType);
$this->modelState->set('filter.language', $this->getLanguageFromInput());
$this->modelState->set('filter.client', $this->getClientFromInput());
parent::delete($id);
}
/**
* Get client code from input
*
* @return string
*
* @since 4.0.0
*/
private function getClientFromInput()
{
return $this->input->exists('app') ? $this->input->get('app') : $this->input->post->get('app');
}
/**
* Get language code from input
*
* @return string
*
* @since 4.0.0
*/
private function getLanguageFromInput()
{
return $this->input->exists('lang_code') ?
$this->input->get('lang_code') : $this->input->post->get('lang_code');
}
}

View File

@ -0,0 +1,125 @@
<?php
/**
* @package Joomla.API
* @subpackage com_languages
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Languages\Api\Controller;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\ApiController;
use Tobscure\JsonApi\Exception\InvalidParameterException;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The strings controller
*
* @since 4.0.0
*/
class StringsController extends ApiController
{
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'strings';
/**
* The default view for the display method.
*
* @var string
* @since 3.0
*/
protected $default_view = 'strings';
/**
* Search by languages constants
*
* @return static A \JControllerLegacy object to support chaining.
*
* @throws InvalidParameterException
* @since 4.0.0
*/
public function search()
{
$data = $this->input->get('data', json_decode($this->input->json->getRaw(), true), 'array');
if (!isset($data['searchstring']) || !\is_string($data['searchstring'])) {
throw new InvalidParameterException("Invalid param 'searchstring'");
}
if (!isset($data['searchtype']) || !\in_array($data['searchtype'], ['constant', 'value'])) {
throw new InvalidParameterException("Invalid param 'searchtype'");
}
$this->input->set('searchstring', $data['searchstring']);
$this->input->set('searchtype', $data['searchtype']);
$this->input->set('more', 0);
$viewType = $this->app->getDocument()->getType();
$viewName = $this->input->get('view', $this->default_view);
$viewLayout = $this->input->get('layout', 'default', 'string');
try {
/** @var \Joomla\Component\Languages\Api\View\Strings\JsonapiView $view */
$view = $this->getView(
$viewName,
$viewType,
'',
['base_path' => $this->basePath, 'layout' => $viewLayout, 'contentType' => $this->contentType]
);
} catch (\Exception $e) {
throw new \RuntimeException($e->getMessage());
}
/** @var \Joomla\Component\Languages\Administrator\Model\StringsModel $model */
$model = $this->getModel($this->contentType, '', ['ignore_request' => true]);
if (!$model) {
throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_MODEL_CREATE'));
}
// Push the model into the view (as default)
$view->setModel($model, true);
$view->document = $this->app->getDocument();
$view->displayList();
return $this;
}
/**
* Refresh cache
*
* @return static A \JControllerLegacy object to support chaining.
*
* @throws \Exception
* @since 4.0.0
*/
public function refresh()
{
/** @var \Joomla\Component\Languages\Administrator\Model\StringsModel $model */
$model = $this->getModel($this->contentType, '', ['ignore_request' => true]);
if (!$model) {
throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_MODEL_CREATE'));
}
$result = $model->refresh();
if ($result instanceof \Exception) {
throw $result;
}
return $this;
}
}

View File

@ -0,0 +1,92 @@
<?php
/**
* @package Joomla.API
* @subpackage com_languages
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Languages\Api\View\Languages;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The languages view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* The fields to render item in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderItem = [
'id',
'asset_id',
'lang_code',
'title',
'title_native',
'sef',
'image',
'description',
'metakey',
'metadesc',
'sitename',
'published',
'access',
'ordering',
'access_level',
'home',
];
/**
* The fields to render items in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderList = [
'id',
'asset_id',
'lang_code',
'title',
'title_native',
'sef',
'image',
'description',
'metakey',
'metadesc',
'sitename',
'published',
'access',
'ordering',
'access_level',
'home',
];
/**
* Prepare item before render.
*
* @param object $item The model item
*
* @return object
*
* @since 4.0.0
*/
protected function prepareItem($item)
{
$item->id = $item->lang_id;
unset($item->lang->id);
return parent::prepareItem($item);
}
}

View File

@ -0,0 +1,105 @@
<?php
/**
* @package Joomla.API
* @subpackage com_languages
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Languages\Api\View\Overrides;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The overrides view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* The fields to render item in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderItem = ['value'];
/**
* The fields to render items in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderList = ['value'];
/**
* Execute and display a template script.
*
* @param object $item Item
*
* @return string
*
* @since 4.0.0
*/
public function displayItem($item = null)
{
/** @var \Joomla\Component\Languages\Administrator\Model\OverrideModel $model */
$model = $this->getModel();
$id = $model->getState($model->getName() . '.id');
$item = $this->prepareItem($model->getItem($id));
return parent::displayItem($item);
}
/**
* Execute and display a template script.
*
* @param array|null $items Array of items
*
* @return string
*
* @since 4.0.0
*/
public function displayList(array $items = null)
{
/** @var \Joomla\Component\Languages\Administrator\Model\OverridesModel $model */
$model = $this->getModel();
$items = [];
foreach ($model->getOverrides() as $key => $override) {
$item = (object) [
'key' => $key,
'override' => $override,
];
$items[] = $this->prepareItem($item);
}
return parent::displayList($items);
}
/**
* Prepare item before render.
*
* @param object $item The model item
*
* @return object
*
* @since 4.0.0
*/
protected function prepareItem($item)
{
$item->id = $item->key;
$item->value = $item->override;
unset($item->key);
unset($item->override);
return parent::prepareItem($item);
}
}

View File

@ -0,0 +1,101 @@
<?php
/**
* @package Joomla.API
* @subpackage com_languages
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Languages\Api\View\Strings;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\GenericDataException;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
use Joomla\CMS\Serializer\JoomlaSerializer;
use Tobscure\JsonApi\Collection;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The strings view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* The fields to render items in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderList = [
'id',
'string',
'file',
];
/**
* Execute and display a template script.
*
* @param array|null $items Array of items
*
* @return string
*
* @since 4.0.0
*/
public function displayList(array $items = null)
{
/** @var \Joomla\Component\Languages\Administrator\Model\StringsModel $model */
$model = $this->getModel();
$result = $model->search();
if ($result instanceof \Exception) {
throw $result;
}
$items = [];
foreach ($result['results'] as $item) {
$items[] = $this->prepareItem($item);
}
// Check for errors.
if (\count($errors = $this->get('Errors'))) {
throw new GenericDataException(implode("\n", $errors), 500);
}
if ($this->type === null) {
throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_CONTENT_TYPE_MISSING'), 400);
}
$collection = (new Collection($items, new JoomlaSerializer($this->type)))
->fields([$this->type => $this->fieldsToRenderList]);
// Set the data into the document and render it
$this->getDocument()->setData($collection);
return $this->getDocument()->render();
}
/**
* Prepare item before render.
*
* @param object $item The model item
*
* @return object
*
* @since 4.0.0
*/
protected function prepareItem($item)
{
$item->id = $item->constant;
unset($item->constant);
return parent::prepareItem($item);
}
}

View File

@ -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();
}
}

View 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');
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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
);
}
}
}

View 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',
];
}

View 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;
}
}

View File

@ -0,0 +1,189 @@
<?php
/**
* @package Joomla.API
* @subpackage com_menus
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Api\Controller;
use Joomla\CMS\Access\Exception\NotAllowed;
use Joomla\CMS\Filter\InputFilter;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\ApiController;
use Joomla\CMS\MVC\Model\ListModel;
use Joomla\Component\Menus\Api\View\Items\JsonapiView;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The items controller
*
* @since 4.0.0
*/
class ItemsController extends ApiController
{
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'items';
/**
* The default view for the display method.
*
* @var string
* @since 3.0
*/
protected $default_view = 'items';
/**
* Basic display of an item view
*
* @param integer $id The primary key to display. Leave empty if you want to retrieve data from the request
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function displayItem($id = null)
{
$this->modelState->set('filter.client_id', $this->getClientIdFromInput());
return parent::displayItem($id);
}
/**
* Basic display of a list view
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function displayList()
{
$apiFilterInfo = $this->input->get('filter', [], 'array');
$filter = InputFilter::getInstance();
if (\array_key_exists('menutype', $apiFilterInfo)) {
$this->modelState->set('filter.menutype', $filter->clean($apiFilterInfo['menutype'], 'STRING'));
}
$this->modelState->set('filter.client_id', $this->getClientIdFromInput());
return parent::displayList();
}
/**
* Method to add a new record.
*
* @return void
*
* @since 4.0.0
* @throws NotAllowed
* @throws \RuntimeException
*/
public function add()
{
$data = $this->input->get('data', json_decode($this->input->json->getRaw(), true), 'array');
if (isset($data['menutype'])) {
$this->input->set('menutype', $data['menutype']);
$this->input->set('com_menus.items.menutype', $data['menutype']);
}
isset($data['type']) && $this->input->set('type', $data['type']);
isset($data['parent_id']) && $this->input->set('parent_id', $data['parent_id']);
isset($data['link']) && $this->input->set('link', $data['link']);
$this->input->set('id', '0');
parent::add();
}
/**
* Method to edit an existing record.
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function edit()
{
$data = $this->input->get('data', json_decode($this->input->json->getRaw(), true), 'array');
if (isset($data['menutype'])) {
$this->input->set('menutype', $data['menutype']);
$this->input->set('com_menus.items.menutype', $data['menutype']);
}
isset($data['type']) && $this->input->set('type', $data['type']);
isset($data['parent_id']) && $this->input->set('parent_id', $data['parent_id']);
isset($data['link']) && $this->input->set('link', $data['link']);
return parent::edit();
}
/**
* Return menu items types
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function getTypes()
{
$viewType = $this->app->getDocument()->getType();
$viewName = $this->input->get('view', $this->default_view);
$viewLayout = $this->input->get('layout', 'default', 'string');
try {
/** @var JsonapiView $view */
$view = $this->getView(
$viewName,
$viewType,
'',
['base_path' => $this->basePath, 'layout' => $viewLayout, 'contentType' => $this->contentType]
);
} catch (\Exception $e) {
throw new \RuntimeException($e->getMessage());
}
/** @var ListModel $model */
$model = $this->getModel('menutypes', '', ['ignore_request' => true]);
if (!$model) {
throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_MODEL_CREATE'));
}
$model->setState('client_id', $this->getClientIdFromInput());
$view->setModel($model, true);
$view->document = $this->app->getDocument();
$view->displayListTypes();
return $this;
}
/**
* Get client id from input
*
* @return string
*
* @since 4.0.0
*/
private function getClientIdFromInput()
{
return $this->input->exists('client_id') ?
$this->input->get('client_id') : $this->input->post->get('client_id');
}
}

View File

@ -0,0 +1,84 @@
<?php
/**
* @package Joomla.API
* @subpackage com_menus
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Api\Controller;
use Joomla\CMS\MVC\Controller\ApiController;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The menus controller
*
* @since 4.0.0
*/
class MenusController extends ApiController
{
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'menus';
/**
* The default view for the display method.
*
* @var string
* @since 3.0
*/
protected $default_view = 'menus';
/**
* Basic display of an item view
*
* @param integer $id The primary key to display. Leave empty if you want to retrieve data from the request
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function displayItem($id = null)
{
$this->modelState->set('filter.client_id', $this->getClientIdFromInput());
return parent::displayItem($id);
}
/**
* Basic display of a list view
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function displayList()
{
$this->modelState->set('filter.client_id', $this->getClientIdFromInput());
return parent::displayList();
}
/**
* Get client id from input
*
* @return string
*
* @since 4.0.0
*/
private function getClientIdFromInput()
{
return $this->input->exists('client_id') ?
$this->input->get('client_id') : $this->input->post->get('client_id');
}
}

View File

@ -0,0 +1,209 @@
<?php
/**
* @package Joomla.API
* @subpackage com_menus
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Api\View\Items;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
use Joomla\CMS\Serializer\JoomlaSerializer;
use Joomla\CMS\Uri\Uri;
use Tobscure\JsonApi\Collection;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The items view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* The fields to render item in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderItem = [
'id',
'parent_id',
'level',
'lft',
'rgt',
'alias',
'typeAlias',
'menutype',
'title',
'note',
'path',
'link',
'type',
'published',
'component_id',
'checked_out',
'checked_out_time',
'browserNav',
'access',
'img',
'template_style_id',
'params',
'home',
'language',
'client_id',
'publish_up',
'publish_down',
'request',
'associations',
'menuordering',
];
/**
* The fields to render items in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderList = [
'id',
'menutype',
'title',
'alias',
'note',
'path',
'link',
'type',
'parent_id',
'level',
'a.published',
'component_id',
'checked_out',
'checked_out_time',
'browserNav',
'access',
'img',
'template_style_id',
'params',
'lft',
'rgt',
'home',
'language',
'client_id',
'enabled',
'publish_up',
'publish_down',
'published',
'language_title',
'language_image',
'language_sef',
'editor',
'componentname',
'access_level',
'menutype_id',
'menutype_title',
'association',
'name',
];
/**
* Execute and display a list items types.
*
* @return string
*
* @since 4.0.0
*/
public function displayListTypes()
{
/** @var \Joomla\Component\Menus\Administrator\Model\MenutypesModel $model */
$model = $this->getModel();
$items = [];
foreach ($model->getTypeOptions() as $type => $data) {
$groupItems = [];
foreach ($data as $item) {
$item->id = implode('/', $item->request);
$item->title = Text::_($item->title);
$item->description = Text::_($item->description);
$item->group = Text::_($type);
$groupItems[] = $item;
}
$items = array_merge($items, $groupItems);
}
// Set up links for pagination
$currentUrl = Uri::getInstance();
$currentPageDefaultInformation = ['offset' => 0, 'limit' => 20];
$currentPageQuery = $currentUrl->getVar('page', $currentPageDefaultInformation);
$offset = $currentPageQuery['offset'];
$limit = $currentPageQuery['limit'];
$totalItemsCount = \count($items);
$totalPagesAvailable = ceil($totalItemsCount / $limit);
$items = array_splice($items, $offset, $limit);
$firstPage = clone $currentUrl;
$firstPageQuery = $currentPageQuery;
$firstPageQuery['offset'] = 0;
$firstPage->setVar('page', $firstPageQuery);
$nextPage = clone $currentUrl;
$nextPageQuery = $currentPageQuery;
$nextOffset = $currentPageQuery['offset'] + $limit;
$nextPageQuery['offset'] = ($nextOffset > ($totalPagesAvailable * $limit)) ? $totalPagesAvailable - $limit : $nextOffset;
$nextPage->setVar('page', $nextPageQuery);
$previousPage = clone $currentUrl;
$previousPageQuery = $currentPageQuery;
$previousOffset = $currentPageQuery['offset'] - $limit;
$previousPageQuery['offset'] = max($previousOffset, 0);
$previousPage->setVar('page', $previousPageQuery);
$lastPage = clone $currentUrl;
$lastPageQuery = $currentPageQuery;
$lastPageQuery['offset'] = $totalPagesAvailable - $limit;
$lastPage->setVar('page', $lastPageQuery);
$collection = (new Collection($items, new JoomlaSerializer('menutypes')));
// Set the data into the document and render it
$this->getDocument()->addMeta('total-pages', $totalPagesAvailable)
->setData($collection)
->addLink('self', (string) $currentUrl)
->addLink('first', (string) $firstPage)
->addLink('next', (string) $nextPage)
->addLink('previous', (string) $previousPage)
->addLink('last', (string) $lastPage);
return $this->getDocument()->render();
}
/**
* Prepare item before render.
*
* @param object $item The model item
*
* @return object
*
* @since 4.0.0
*/
protected function prepareItem($item)
{
if (\is_string($item->params)) {
$item->params = json_decode($item->params);
}
return parent::prepareItem($item);
}
}

View File

@ -0,0 +1,57 @@
<?php
/**
* @package Joomla.API
* @subpackage com_menus
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Menus\Api\View\Menus;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The menus view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* The fields to render item in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderItem = [
'id',
'menutype',
'title',
'description',
'client_id',
'count_published',
'count_unpublished',
'count_trashed',
];
/**
* The fields to render items in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderList = [
'id',
'asset_id',
'menutype',
'title',
'description',
'client_id',
];
}

View File

@ -0,0 +1,41 @@
<?php
/**
* @package Joomla.API
* @subpackage com_messages
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Messages\Api\Controller;
use Joomla\CMS\MVC\Controller\ApiController;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The messages controller
*
* @since 4.0.0
*/
class MessagesController extends ApiController
{
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'messages';
/**
* The default view for the display method.
*
* @var string
* @since 3.0
*/
protected $default_view = 'messages';
}

View File

@ -0,0 +1,78 @@
<?php
/**
* @package Joomla.API
* @subpackage com_messages
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Messages\Api\View\Messages;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The messages view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* The fields to render item in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderItem = [
'id',
'user_id_from',
'user_id_to',
'date_time',
'priority',
'subject',
'message',
'state',
'user_from',
];
/**
* The fields to render items in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderList = [
'id',
'user_id_from',
'user_id_to',
'date_time',
'priority',
'subject',
'message',
'state',
'user_from',
];
/**
* Prepare item before render.
*
* @param object $item The model item
*
* @return object
*
* @since 4.0.0
*/
protected function prepareItem($item)
{
$item->id = $item->message_id;
unset($item->message_id);
return parent::prepareItem($item);
}
}

View File

@ -0,0 +1,130 @@
<?php
/**
* @package Joomla.API
* @subpackage com_modules
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Modules\Api\Controller;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\ApiController;
use Joomla\Component\Modules\Administrator\Model\SelectModel;
use Joomla\Component\Modules\Api\View\Modules\JsonapiView;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The modules controller
*
* @since 4.0.0
*/
class ModulesController extends ApiController
{
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'modules';
/**
* The default view for the display method.
*
* @var string
* @since 3.0
*/
protected $default_view = 'modules';
/**
* Basic display of an item view
*
* @param integer $id The primary key to display. Leave empty if you want to retrieve data from the request
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function displayItem($id = null)
{
$this->modelState->set('client_id', $this->getClientIdFromInput());
return parent::displayItem($id);
}
/**
* Basic display of a list view
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function displayList()
{
$this->modelState->set('client_id', $this->getClientIdFromInput());
return parent::displayList();
}
/**
* Return module items types
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function getTypes()
{
$viewType = $this->app->getDocument()->getType();
$viewName = $this->input->get('view', $this->default_view);
$viewLayout = $this->input->get('layout', 'default', 'string');
try {
/** @var JsonapiView $view */
$view = $this->getView(
$viewName,
$viewType,
'',
['base_path' => $this->basePath, 'layout' => $viewLayout, 'contentType' => $this->contentType]
);
} catch (\Exception $e) {
throw new \RuntimeException($e->getMessage());
}
/** @var SelectModel $model */
$model = $this->getModel('select', '', ['ignore_request' => true]);
if (!$model) {
throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_MODEL_CREATE'));
}
$model->setState('client_id', $this->getClientIdFromInput());
$view->setModel($model, true);
$view->document = $this->app->getDocument();
$view->displayListTypes();
return $this;
}
/**
* Get client id from input
*
* @return string
*
* @since 4.0.0
*/
private function getClientIdFromInput()
{
return $this->input->exists('client_id') ?
$this->input->get('client_id') : $this->input->post->get('client_id');
}
}

View File

@ -0,0 +1,141 @@
<?php
/**
* @package Joomla.API
* @subpackage com_modules
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Modules\Api\View\Modules;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
use Joomla\CMS\Router\Exception\RouteNotFoundException;
use Joomla\Component\Modules\Administrator\Model\SelectModel;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The modules view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* The fields to render item in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderItem = [
'id',
'typeAlias',
'asset_id',
'title',
'note',
'content',
'ordering',
'position',
'checked_out',
'checked_out_time',
'publish_up',
'publish_down',
'published',
'module',
'access',
'showtitle',
'params',
'client_id',
'language',
'assigned',
'assignment',
'xml',
];
/**
* The fields to render items in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderList = [
'id',
'title',
'note',
'position',
'module',
'language',
'checked_out',
'checked_out_time',
'published',
'enabled',
'access',
'ordering',
'publish_up',
'publish_down',
'language_title',
'language_image',
'editor',
'access_level',
'pages',
'name',
];
/**
* Execute and display a template script.
*
* @param object $item Item
*
* @return string
*
* @since 4.0.0
*/
public function displayItem($item = null)
{
/** @var \Joomla\CMS\MVC\Model\AdminModel $model */
$model = $this->getModel();
if ($item === null) {
$item = $this->prepareItem($model->getItem());
}
if ($item->id === null) {
throw new RouteNotFoundException('Item does not exist');
}
if ((int) $model->getState('client_id') !== $item->client_id) {
throw new RouteNotFoundException('Item does not exist');
}
return parent::displayItem($item);
}
/**
* Execute and display a list modules types.
*
* @return string
*
* @since 4.0.0
*/
public function displayListTypes()
{
/** @var SelectModel $model */
$model = $this->getModel();
$items = [];
foreach ($model->getItems() as $item) {
$item->id = $item->extension_id;
unset($item->extension_id);
$items[] = $item;
}
$this->fieldsToRenderList = ['id', 'name', 'module', 'xml', 'desc'];
return parent::displayList($items);
}
}

View File

@ -0,0 +1,41 @@
<?php
/**
* @package Joomla.API
* @subpackage com_newsfeeds
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Newsfeeds\Api\Controller;
use Joomla\CMS\MVC\Controller\ApiController;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The feeds controller
*
* @since 4.0.0
*/
class FeedsController extends ApiController
{
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'newsfeeds';
/**
* The default view for the display method.
*
* @var string
* @since 3.0
*/
protected $default_view = 'feeds';
}

View File

@ -0,0 +1,115 @@
<?php
/**
* Joomla! Content Management System
*
* @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\Newsfeeds\Api\Serializer;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Serializer\JoomlaSerializer;
use Joomla\CMS\Tag\TagApiSerializerTrait;
use Joomla\CMS\Uri\Uri;
use Tobscure\JsonApi\Collection;
use Tobscure\JsonApi\Relationship;
use Tobscure\JsonApi\Resource;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Temporary serializer
*
* @since 4.0.0
*/
class NewsfeedSerializer extends JoomlaSerializer
{
use TagApiSerializerTrait;
/**
* Build content relationships by associations
*
* @param \stdClass $model Item model
*
* @return Relationship
*
* @since 4.0.0
*/
public function languageAssociations($model)
{
$resources = [];
// @todo: This can't be hardcoded in the future?
$serializer = new JoomlaSerializer($this->type);
foreach ($model->associations as $association) {
$resources[] = (new Resource($association, $serializer))
->addLink('self', Route::link('site', Uri::root() . 'api/index.php/v1/newsfeeds/feeds/' . $association->id));
}
$collection = new Collection($resources, $serializer);
return new Relationship($collection);
}
/**
* Build category relationship
*
* @param \stdClass $model Item model
*
* @return Relationship
*
* @since 4.0.0
*/
public function category($model)
{
$serializer = new JoomlaSerializer('categories');
$resource = (new Resource($model->catid, $serializer))
->addLink('self', Route::link('site', Uri::root() . 'api/index.php/v1/newfeeds/categories/' . $model->catid));
return new Relationship($resource);
}
/**
* Build category relationship
*
* @param \stdClass $model Item model
*
* @return Relationship
*
* @since 4.0.0
*/
public function createdBy($model)
{
$serializer = new JoomlaSerializer('users');
$resource = (new Resource($model->created_by, $serializer))
->addLink('self', Route::link('site', Uri::root() . 'api/index.php/v1/users/' . $model->created_by));
return new Relationship($resource);
}
/**
* Build editor relationship
*
* @param \stdClass $model Item model
*
* @return Relationship
*
* @since 4.0.0
*/
public function modifiedBy($model)
{
$serializer = new JoomlaSerializer('users');
$resource = (new Resource($model->modified_by, $serializer))
->addLink('self', Route::link('site', Uri::root() . 'api/index.php/v1/users/' . $model->modified_by));
return new Relationship($resource);
}
}

View File

@ -0,0 +1,182 @@
<?php
/**
* @package Joomla.API
* @subpackage com_newsfeeds
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Newsfeeds\Api\View\Feeds;
use Joomla\CMS\Language\Multilanguage;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
use Joomla\Component\Newsfeeds\Api\Serializer\NewsfeedSerializer;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The feeds view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* The fields to render item in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderItem = [
'id',
'category',
'name',
'alias',
'link',
'published',
'numarticles',
'cache_time',
'checked_out',
'checked_out_time',
'ordering',
'rtl',
'access',
'language',
'params',
'created',
'created_by',
'created_by_alias',
'modified',
'modified_by',
'metakey',
'metadesc',
'metadata',
'publish_up',
'publish_down',
'description',
'version',
'hits',
'images',
'tags',
];
/**
* The fields to render items in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderList = [
'id',
'name',
'alias',
'checked_out',
'checked_out_time',
'category',
'numarticles',
'cache_time',
'created_by',
'published',
'access',
'ordering',
'language',
'publish_up',
'publish_down',
'language_title',
'language_image',
'editor',
'access_level',
'category_title',
];
/**
* The relationships the item has
*
* @var array
* @since 4.0.0
*/
protected $relationship = [
'category',
'created_by',
'modified_by',
'tags',
];
/**
* Constructor.
*
* @param array $config A named configuration array for object construction.
* contentType: the name (optional) of the content type to use for the serialization
*
* @since 4.0.0
*/
public function __construct($config = [])
{
if (\array_key_exists('contentType', $config)) {
$this->serializer = new NewsfeedSerializer($config['contentType']);
}
parent::__construct($config);
}
/**
* Execute and display a template script.
*
* @param object $item Item
*
* @return string
*
* @since 4.0.0
*/
public function displayItem($item = null)
{
if (Multilanguage::isEnabled()) {
$this->fieldsToRenderItem[] = 'languageAssociations';
$this->relationship[] = 'languageAssociations';
}
return parent::displayItem();
}
/**
* Prepare item before render.
*
* @param object $item The model item
*
* @return object
*
* @since 4.0.0
*/
protected function prepareItem($item)
{
if (Multilanguage::isEnabled() && !empty($item->associations)) {
$associations = [];
foreach ($item->associations as $language => $association) {
$itemId = explode(':', $association)[0];
$associations[] = (object) [
'id' => $itemId,
'language' => $language,
];
}
$item->associations = $associations;
}
if (!empty($item->tags->tags)) {
$tagsIds = explode(',', $item->tags->tags);
$tagsNames = $item->tagsHelper->getTagNames($tagsIds);
$item->tags = array_combine($tagsIds, $tagsNames);
} else {
$item->tags = [];
}
return parent::prepareItem($item);
}
}

View File

@ -0,0 +1,123 @@
<?php
/**
* @package Joomla.API
* @subpackage com_plugins
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Plugins\Api\Controller;
use Joomla\CMS\Filter\InputFilter;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\ApiController;
use Joomla\CMS\MVC\Controller\Exception;
use Joomla\CMS\Router\Exception\RouteNotFoundException;
use Joomla\String\Inflector;
use Tobscure\JsonApi\Exception\InvalidParameterException;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The plugins controller
*
* @since 4.0.0
*/
class PluginsController extends ApiController
{
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'plugins';
/**
* The default view for the display method.
*
* @var string
*
* @since 3.0
*/
protected $default_view = 'plugins';
/**
* Method to edit an existing record.
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function edit()
{
$recordId = $this->input->getInt('id');
if (!$recordId) {
throw new Exception\ResourceNotFound(Text::_('JLIB_APPLICATION_ERROR_RECORD'), 404);
}
$data = json_decode($this->input->json->getRaw(), true);
foreach ($data as $key => $value) {
if (!\in_array($key, ['enabled', 'access', 'ordering'])) {
throw new InvalidParameterException("Invalid parameter {$key}.", 400);
}
}
/** @var \Joomla\Component\Plugins\Administrator\Model\PluginModel $model */
$model = $this->getModel(Inflector::singularize($this->contentType), '', ['ignore_request' => true]);
if (!$model) {
throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_MODEL_CREATE'));
}
$item = $model->getItem($recordId);
if (!isset($item->extension_id)) {
throw new RouteNotFoundException('Item does not exist');
}
$data['folder'] = $item->folder;
$data['element'] = $item->element;
$this->input->set('data', $data);
return parent::edit();
}
/**
* Plugin list view with filtering of data
*
* @return static A BaseController object to support chaining.
*
* @since 4.0.0
*/
public function displayList()
{
$apiFilterInfo = $this->input->get('filter', [], 'array');
$filter = InputFilter::getInstance();
if (\array_key_exists('element', $apiFilterInfo)) {
$this->modelState->set('filter.element', $filter->clean($apiFilterInfo['element'], 'STRING'));
}
if (\array_key_exists('status', $apiFilterInfo)) {
$this->modelState->set('filter.enabled', $filter->clean($apiFilterInfo['status'], 'INT'));
}
if (\array_key_exists('search', $apiFilterInfo)) {
$this->modelState->set('filter.search', $filter->clean($apiFilterInfo['search'], 'STRING'));
}
if (\array_key_exists('type', $apiFilterInfo)) {
$this->modelState->set('filter.folder', $filter->clean($apiFilterInfo['type'], 'STRING'));
}
return parent::displayList();
}
}

View File

@ -0,0 +1,85 @@
<?php
/**
* @package Joomla.API
* @subpackage com_plugins
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Plugins\Api\View\Plugins;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The plugins view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* The fields to render item in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderItem = [
'id',
'name',
'type',
'element',
'changelogurl',
'folder',
'client_id',
'enabled',
'access',
'protected',
'checked_out',
'checked_out_time',
'ordering',
'state',
];
/**
* The fields to render items in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderList = [
'id',
'name',
'element',
'folder',
'checked_out',
'checked_out_time',
'enabled',
'access',
'ordering',
'editor',
'access_level',
];
/**
* Prepare item before render.
*
* @param object $item The model item
*
* @return object
*
* @since 4.0.0
*/
protected function prepareItem($item)
{
$item->id = $item->extension_id;
unset($item->extension_id);
return $item;
}
}

View File

@ -0,0 +1,61 @@
<?php
/**
* @package Joomla.API
* @subpackage com_privacy
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Privacy\Api\Controller;
use Joomla\CMS\MVC\Controller\ApiController;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The consents controller
*
* @since 4.0.0
*/
class ConsentsController extends ApiController
{
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'consents';
/**
* The default view for the display method.
*
* @var string
* @since 3.0
*/
protected $default_view = 'consents';
/**
* Basic display of an item view
*
* @param integer $id The primary key to display. Leave empty if you want to retrieve data from the request
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function displayItem($id = null)
{
if ($id === null) {
$id = $this->input->get('id', 0, 'int');
}
$this->input->set('model', $this->contentType);
return parent::displayItem($id);
}
}

View File

@ -0,0 +1,91 @@
<?php
/**
* @package Joomla.API
* @subpackage com_privacy
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Privacy\Api\Controller;
use Joomla\CMS\MVC\Controller\ApiController;
use Joomla\Component\Privacy\Api\View\Requests\JsonapiView;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The requests controller
*
* @since 4.0.0
*/
class RequestsController extends ApiController
{
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'requests';
/**
* The default view for the display method.
*
* @var string
* @since 3.0
*/
protected $default_view = 'requests';
/**
* Export request data
*
* @param integer $id The primary key to display. Leave empty if you want to retrieve data from the request
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function export($id = null)
{
if ($id === null) {
$id = $this->input->get('id', 0, 'int');
}
$viewType = $this->app->getDocument()->getType();
$viewName = $this->input->get('view', $this->default_view);
$viewLayout = $this->input->get('layout', 'default', 'string');
try {
/** @var JsonapiView $view */
$view = $this->getView(
$viewName,
$viewType,
'',
['base_path' => $this->basePath, 'layout' => $viewLayout, 'contentType' => $this->contentType]
);
} catch (\Exception $e) {
throw new \RuntimeException($e->getMessage());
}
$model = $this->getModel('export');
try {
$modelName = $model->getName();
} catch (\Exception $e) {
throw new \RuntimeException($e->getMessage());
}
$model->setState($modelName . '.request_id', $id);
$view->setModel($model, true);
$view->document = $this->app->getDocument();
$view->export();
return $this;
}
}

View File

@ -0,0 +1,120 @@
<?php
/**
* @package Joomla.API
* @subpackage com_privacy
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Privacy\Api\View\Consents;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\GenericDataException;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
use Joomla\CMS\Router\Exception\RouteNotFoundException;
use Joomla\CMS\Serializer\JoomlaSerializer;
use Joomla\CMS\Uri\Uri;
use Tobscure\JsonApi\Resource;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The consents view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* The fields to render item in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderItem = [
'id',
'user_id',
'state',
'created',
'subject',
'body',
'remind',
'token',
'username',
];
/**
* The fields to render items in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderList = [
'id',
'user_id',
'state',
'created',
'subject',
'body',
'remind',
'token',
'username',
];
/**
* Execute and display a template script.
*
* @param object $item Item
*
* @return string
*
* @since 4.0.0
*/
public function displayItem($item = null)
{
$id = $this->get('state')->get($this->getName() . '.id');
if ($id === null) {
throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_ITEMID_MISSING'));
}
/** @var \Joomla\CMS\MVC\Model\ListModel $model */
$model = $this->getModel();
$displayItem = null;
foreach ($model->getItems() as $item) {
$item = $this->prepareItem($item);
if ($item->id === $id) {
$displayItem = $item;
break;
}
}
if ($displayItem === null) {
throw new RouteNotFoundException('Item does not exist');
}
// Check for errors.
if (\count($errors = $this->get('Errors'))) {
throw new GenericDataException(implode("\n", $errors), 500);
}
if ($this->type === null) {
throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_CONTENT_TYPE_MISSING'));
}
$serializer = new JoomlaSerializer($this->type);
$element = (new Resource($displayItem, $serializer))
->fields([$this->type => $this->fieldsToRenderItem]);
$this->getDocument()->setData($element);
$this->getDocument()->addLink('self', Uri::current());
return $this->getDocument()->render();
}
}

View File

@ -0,0 +1,73 @@
<?php
/**
* @package Joomla.API
* @subpackage com_privacy
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Privacy\Api\View\Requests;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
use Joomla\CMS\Router\Exception\RouteNotFoundException;
use Joomla\CMS\Serializer\JoomlaSerializer;
use Joomla\CMS\Uri\Uri;
use Joomla\Component\Privacy\Administrator\Model\ExportModel;
use Tobscure\JsonApi\Resource;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The requests view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* The fields to render item in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderItem = ['id', 'typeAlias', 'email', 'requested_at', 'status', 'request_type'];
/**
* The fields to render items in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderList = ['id', 'email', 'requested_at', 'status', 'request_type'];
/**
* Execute and display a template script.
*
* @return string
*
* @since 4.0.0
*/
public function export()
{
/** @var ExportModel $model */
$model = $this->getModel();
$exportData = $model->collectDataForExportRequest();
if ($exportData == false) {
throw new RouteNotFoundException('Item does not exist');
}
$serializer = new JoomlaSerializer('export');
$element = (new Resource($exportData, $serializer));
$this->getDocument()->setData($element);
$this->getDocument()->addLink('self', Uri::current());
return $this->getDocument()->render();
}
}

View File

@ -0,0 +1,41 @@
<?php
/**
* @package Joomla.API
* @subpackage com_redirect
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Redirect\Api\Controller;
use Joomla\CMS\MVC\Controller\ApiController;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The redirect controller
*
* @since 4.0.0
*/
class RedirectController extends ApiController
{
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'links';
/**
* The default view for the display method.
*
* @var string
* @since 3.0
*/
protected $default_view = 'redirect';
}

View File

@ -0,0 +1,63 @@
<?php
/**
* @package Joomla.API
* @subpackage com_redirect
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Redirect\Api\View\Redirect;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The redirect view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* The fields to render item in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderItem = [
'id',
'old_url',
'new_url',
'referer',
'comment',
'hits',
'published',
'created_date',
'modified_date',
'header',
];
/**
* The fields to render items in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderList = [
'id',
'old_url',
'new_url',
'referer',
'comment',
'hits',
'published',
'created_date',
'modified_date',
'header',
];
}

View File

@ -0,0 +1,41 @@
<?php
/**
* @package Joomla.API
* @subpackage com_tags
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Tags\Api\Controller;
use Joomla\CMS\MVC\Controller\ApiController;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The tags controller
*
* @since 4.0.0
*/
class TagsController extends ApiController
{
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'tags';
/**
* The default view for the display method.
*
* @var string
* @since 3.0
*/
protected $default_view = 'tags';
}

View File

@ -0,0 +1,95 @@
<?php
/**
* @package Joomla.API
* @subpackage com_tags
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Tags\Api\View\Tags;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The tags view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* The fields to render item in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderItem = [
'id',
'parent_id',
'level',
'lft',
'rgt',
'alias',
'typeAlias',
'path',
'title',
'note',
'description',
'published',
'checked_out',
'checked_out_time',
'access',
'params',
'metadesc',
'metakey',
'metadata',
'created_user_id',
'created_time',
'created_by_alias',
'modified_user_id',
'modified_time',
'images',
'urls',
'hits',
'language',
'version',
'publish_up',
'publish_down',
];
/**
* The fields to render items in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderList = [
'id',
'title',
'alias',
'note',
'published',
'access',
'description',
'checked_out',
'checked_out_time',
'created_user_id',
'path',
'parent_id',
'level',
'lft',
'rgt',
'language',
'language_title',
'language_image',
'editor',
'author_name',
'access_title',
];
}

View File

@ -0,0 +1,112 @@
<?php
/**
* @package Joomla.API
* @subpackage com_templates
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Templates\Api\Controller;
use Joomla\CMS\MVC\Controller\ApiController;
use Joomla\String\Inflector;
use Tobscure\JsonApi\Exception\InvalidParameterException;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The styles controller
*
* @since 4.0.0
*/
class StylesController extends ApiController
{
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'styles';
/**
* The default view for the display method.
*
* @var string
* @since 3.0
*/
protected $default_view = 'styles';
/**
* Basic display of an item view
*
* @param integer $id The primary key to display. Leave empty if you want to retrieve data from the request
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function displayItem($id = null)
{
$this->modelState->set('client_id', $this->getClientIdFromInput());
return parent::displayItem($id);
}
/**
* Basic display of a list view
*
* @return static A \JControllerLegacy object to support chaining.
*
* @since 4.0.0
*/
public function displayList()
{
$this->modelState->set('client_id', $this->getClientIdFromInput());
return parent::displayList();
}
/**
* Method to allow extended classes to manipulate the data to be saved for an extension.
*
* @param array $data An array of input data.
*
* @return array
*
* @since 4.0.0
* @throws InvalidParameterException
*/
protected function preprocessSaveData(array $data): array
{
$data['client_id'] = $this->getClientIdFromInput();
// If we are updating an item the template is a readonly property based on the ID
if ($this->input->getMethod() === 'PATCH') {
if (\array_key_exists('template', $data)) {
unset($data['template']);
}
$model = $this->getModel(Inflector::singularize($this->contentType), '', ['ignore_request' => true]);
$data['template'] = $model->getItem($this->input->getInt('id'))->template;
}
return $data;
}
/**
* Get client id from input
*
* @return string
*
* @since 4.0.0
*/
private function getClientIdFromInput()
{
return $this->input->exists('client_id') ? $this->input->get('client_id') : $this->input->post->get('client_id');
}
}

View File

@ -0,0 +1,79 @@
<?php
/**
* @package Joomla.API
* @subpackage com_templates
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Templates\Api\View\Styles;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
use Joomla\CMS\Router\Exception\RouteNotFoundException;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The styles view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* The fields to render item in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderItem = [
'id',
'template',
'client_id',
'home',
'title',
'params',
'xml',
];
/**
* The fields to render items in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderList = [
'id',
'template',
'title',
'home',
'client_id',
'language_title',
'image',
'language_sef',
'assigned',
'e_id',
];
/**
* Prepare item before render.
*
* @param object $item The model item
*
* @return object
*
* @since 4.0.0
*/
protected function prepareItem($item)
{
if ($item->client_id != $this->getModel()->getState('client_id')) {
throw new RouteNotFoundException('Item does not exist');
}
return parent::prepareItem($item);
}
}

View File

@ -0,0 +1,41 @@
<?php
/**
* @package Joomla.API
* @subpackage com_users
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Api\Controller;
use Joomla\CMS\MVC\Controller\ApiController;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The groups controller
*
* @since 4.0.0
*/
class GroupsController extends ApiController
{
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'groups';
/**
* The default view for the display method.
*
* @var string
* @since 3.0
*/
protected $default_view = 'groups';
}

View File

@ -0,0 +1,41 @@
<?php
/**
* @package Joomla.API
* @subpackage com_users
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Api\Controller;
use Joomla\CMS\MVC\Controller\ApiController;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The levels controller
*
* @since 4.0.0
*/
class LevelsController extends ApiController
{
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'levels';
/**
* The default view for the display method.
*
* @var string
* @since 4.0.0
*/
protected $default_view = 'levels';
}

View File

@ -0,0 +1,181 @@
<?php
/**
* @package Joomla.API
* @subpackage com_users
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Api\Controller;
use Joomla\CMS\Date\Date;
use Joomla\CMS\Filter\InputFilter;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\ApiController;
use Joomla\Component\Fields\Administrator\Helper\FieldsHelper;
use Tobscure\JsonApi\Exception\InvalidParameterException;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The users controller
*
* @since 4.0.0
*/
class UsersController extends ApiController
{
/**
* The content type of the item.
*
* @var string
* @since 4.0.0
*/
protected $contentType = 'users';
/**
* The default view for the display method.
*
* @var string
* @since 4.0.0
*/
protected $default_view = 'users';
/**
* Method to allow extended classes to manipulate the data to be saved for an extension.
*
* @param array $data An array of input data.
*
* @return array
*
* @since 4.0.0
*/
protected function preprocessSaveData(array $data): array
{
foreach (FieldsHelper::getFields('com_users.user') as $field) {
if (isset($data[$field->name])) {
!isset($data['com_fields']) && $data['com_fields'] = [];
$data['com_fields'][$field->name] = $data[$field->name];
unset($data[$field->name]);
}
}
if ($this->input->getMethod() === 'PATCH') {
$body = $this->input->get('data', json_decode($this->input->json->getRaw(), true), 'array');
if (!\array_key_exists('password', $body)) {
unset($data['password']);
}
}
if ($this->input->getMethod() === 'POST') {
if (isset($data['password'])) {
$data['password2'] = $data['password'];
}
}
return $data;
}
/**
* User list view with filtering of data
*
* @return static A BaseController object to support chaining.
*
* @since 4.0.0
* @throws InvalidParameterException
*/
public function displayList()
{
$apiFilterInfo = $this->input->get('filter', [], 'array');
$filter = InputFilter::getInstance();
if (\array_key_exists('state', $apiFilterInfo)) {
$this->modelState->set('filter.state', $filter->clean($apiFilterInfo['state'], 'INT'));
}
if (\array_key_exists('active', $apiFilterInfo)) {
$this->modelState->set('filter.active', $filter->clean($apiFilterInfo['active'], 'INT'));
}
if (\array_key_exists('groupid', $apiFilterInfo)) {
$this->modelState->set('filter.group_id', $filter->clean($apiFilterInfo['groupid'], 'INT'));
}
if (\array_key_exists('search', $apiFilterInfo)) {
$this->modelState->set('filter.search', $filter->clean($apiFilterInfo['search'], 'STRING'));
}
if (\array_key_exists('registrationDateStart', $apiFilterInfo)) {
$registrationStartInput = $filter->clean($apiFilterInfo['registrationDateStart'], 'STRING');
$registrationStartDate = Date::createFromFormat(\DateTimeInterface::RFC3339, $registrationStartInput);
if (!$registrationStartDate) {
// Send the error response
$error = Text::sprintf('JLIB_FORM_VALIDATE_FIELD_INVALID', 'registrationDateStart');
throw new InvalidParameterException($error, 400, null, 'registrationDateStart');
}
$this->modelState->set('filter.registrationDateStart', $registrationStartDate);
}
if (\array_key_exists('registrationDateEnd', $apiFilterInfo)) {
$registrationEndInput = $filter->clean($apiFilterInfo['registrationDateEnd'], 'STRING');
$registrationEndDate = Date::createFromFormat(\DateTimeInterface::RFC3339, $registrationEndInput);
if (!$registrationEndDate) {
// Send the error response
$error = Text::sprintf('JLIB_FORM_VALIDATE_FIELD_INVALID', 'registrationDateEnd');
throw new InvalidParameterException($error, 400, null, 'registrationDateEnd');
}
$this->modelState->set('filter.registrationDateEnd', $registrationEndDate);
} elseif (
\array_key_exists('registrationDateStart', $apiFilterInfo)
&& !\array_key_exists('registrationDateEnd', $apiFilterInfo)
) {
// If no end date specified the end date is now
$this->modelState->set('filter.registrationDateEnd', new Date());
}
if (\array_key_exists('lastVisitDateStart', $apiFilterInfo)) {
$lastVisitStartInput = $filter->clean($apiFilterInfo['lastVisitDateStart'], 'STRING');
$lastVisitStartDate = Date::createFromFormat(\DateTimeInterface::RFC3339, $lastVisitStartInput);
if (!$lastVisitStartDate) {
// Send the error response
$error = Text::sprintf('JLIB_FORM_VALIDATE_FIELD_INVALID', 'lastVisitDateStart');
throw new InvalidParameterException($error, 400, null, 'lastVisitDateStart');
}
$this->modelState->set('filter.lastVisitStart', $lastVisitStartDate);
}
if (\array_key_exists('lastVisitDateEnd', $apiFilterInfo)) {
$lastVisitEndInput = $filter->clean($apiFilterInfo['lastVisitDateEnd'], 'STRING');
$lastVisitEndDate = Date::createFromFormat(\DateTimeInterface::RFC3339, $lastVisitEndInput);
if (!$lastVisitEndDate) {
// Send the error response
$error = Text::sprintf('JLIB_FORM_VALIDATE_FIELD_INVALID', 'lastVisitDateEnd');
throw new InvalidParameterException($error, 400, null, 'lastVisitDateEnd');
}
$this->modelState->set('filter.lastVisitEnd', $lastVisitEndDate);
} elseif (
\array_key_exists('lastVisitDateStart', $apiFilterInfo)
&& !\array_key_exists('lastVisitDateEnd', $apiFilterInfo)
) {
// If no end date specified the end date is now
$this->modelState->set('filter.lastVisitEnd', new Date());
}
return parent::displayList();
}
}

View File

@ -0,0 +1,53 @@
<?php
/**
* @package Joomla.API
* @subpackage com_users
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Api\View\Groups;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The groups view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* The fields to render item in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderItem = [
'id',
'parent_id',
'lft',
'rgt',
'title',
];
/**
* The fields to render items in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderList = [
'id',
'parent_id',
'lft',
'rgt',
'title',
];
}

View File

@ -0,0 +1,49 @@
<?php
/**
* @package Joomla.API
* @subpackage com_users
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Api\View\Levels;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The levels view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* The fields to render item in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderItem = [
'id',
'title',
'rules',
];
/**
* The fields to render items in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderList = [
'id',
'title',
'rules',
];
}

View File

@ -0,0 +1,126 @@
<?php
/**
* @package Joomla.API
* @subpackage com_users
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Api\View\Users;
use Joomla\CMS\MVC\View\JsonApiView as BaseApiView;
use Joomla\CMS\Router\Exception\RouteNotFoundException;
use Joomla\Component\Fields\Administrator\Helper\FieldsHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* The users view
*
* @since 4.0.0
*/
class JsonapiView extends BaseApiView
{
/**
* The fields to render item in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderItem = [
'id',
'groups',
'name',
'username',
'email',
'registerDate',
'lastvisitDate',
'lastResetTime',
'resetCount',
'sendEmail',
'block',
];
/**
* The fields to render items in the documents
*
* @var array
* @since 4.0.0
*/
protected $fieldsToRenderList = [
'id',
'name',
'username',
'email',
'group_count',
'group_names',
'registerDate',
'lastvisitDate',
'lastResetTime',
'resetCount',
'sendEmail',
'block',
];
/**
* Execute and display a template script.
*
* @param array|null $items Array of items
*
* @return string
*
* @since 4.0.0
*/
public function displayList(array $items = null)
{
foreach (FieldsHelper::getFields('com_users.user') as $field) {
$this->fieldsToRenderList[] = $field->name;
}
return parent::displayList();
}
/**
* Execute and display a template script.
*
* @param object $item Item
*
* @return string
*
* @since 4.0.0
*/
public function displayItem($item = null)
{
foreach (FieldsHelper::getFields('com_users.user') as $field) {
$this->fieldsToRenderItem[] = $field->name;
}
return parent::displayItem();
}
/**
* Prepare item before render.
*
* @param object $item The model item
*
* @return object
*
* @since 4.0.0
*/
protected function prepareItem($item)
{
if (empty($item->username)) {
throw new RouteNotFoundException('Item does not exist');
}
foreach (FieldsHelper::getFields('com_users.user', $item, true) as $field) {
$item->{$field->name} = $field->apivalue ?? $field->rawvalue;
}
return parent::prepareItem($item);
}
}