primo commit
This commit is contained in:
24
administrator/components/com_privacy/config.xml
Normal file
24
administrator/components/com_privacy/config.xml
Normal file
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<config>
|
||||
<help key="Privacy:_Options"/>
|
||||
<inlinehelp button="show"/>
|
||||
<fieldset
|
||||
name="privacy"
|
||||
label="COM_PRIVACY_OPTION_LABEL"
|
||||
>
|
||||
|
||||
<field
|
||||
name="notify"
|
||||
type="integer"
|
||||
label="COM_PRIVACY_NOTIFY_LABEL"
|
||||
description="COM_PRIVACY_NOTIFY_DESC"
|
||||
first="1"
|
||||
last="29"
|
||||
step="1"
|
||||
default="14"
|
||||
filter="int"
|
||||
validate="number"
|
||||
/>
|
||||
|
||||
</fieldset>
|
||||
</config>
|
||||
@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form>
|
||||
<fields name="filter">
|
||||
<field
|
||||
name="search"
|
||||
type="text"
|
||||
inputmode="search"
|
||||
label="COM_PRIVACY_FILTER_SEARCH_LABEL"
|
||||
description="COM_PRIVACY_SEARCH_IN_USERNAME"
|
||||
hint="JSEARCH_FILTER"
|
||||
/>
|
||||
|
||||
<field
|
||||
name="state"
|
||||
type="list"
|
||||
label="COM_PRIVACY_CONSENTS_FILTER_STATE"
|
||||
class="js-select-submit-on-change"
|
||||
validate="options"
|
||||
>
|
||||
<option value="">JOPTION_SELECT_PUBLISHED</option>
|
||||
<option value="1">COM_PRIVACY_CONSENTS_STATE_VALID</option>
|
||||
<option value="0">COM_PRIVACY_CONSENTS_STATE_OBSOLETE</option>
|
||||
<option value="-1">COM_PRIVACY_CONSENTS_STATE_INVALIDATED</option>
|
||||
</field>
|
||||
|
||||
<field
|
||||
name="subject"
|
||||
type="sql"
|
||||
label="COM_PRIVACY_CONSENTS_FILTER_SUBJECT"
|
||||
sql_select="subject"
|
||||
sql_from="#__privacy_consents"
|
||||
sql_group="subject"
|
||||
sql_order="subject ASC"
|
||||
key_field="subject"
|
||||
translate="true"
|
||||
class="js-select-submit-on-change"
|
||||
>
|
||||
<option value="">COM_PRIVACY_CONSENTS_SUBJECT_DEFAULT</option>
|
||||
</field>
|
||||
</fields>
|
||||
|
||||
<fields name="list">
|
||||
<field
|
||||
name="fullordering"
|
||||
type="list"
|
||||
label="JGLOBAL_SORT_BY"
|
||||
class="js-select-submit-on-change"
|
||||
default="a.id DESC"
|
||||
validate="options"
|
||||
>
|
||||
<option value="a.state ASC">COM_PRIVACY_HEADING_STATUS_ASC</option>
|
||||
<option value="a.state DESC">COM_PRIVACY_HEADING_STATUS_DESC</option>
|
||||
<option value="u.name ASC">JGLOBAL_NAME_ASC</option>
|
||||
<option value="u.name DESC">JGLOBAL_NAME_DESC</option>
|
||||
<option value="u.username ASC">COM_PRIVACY_HEADING_USERNAME_ASC</option>
|
||||
<option value="u.username DESC">COM_PRIVACY_HEADING_USERNAME_DESC</option>
|
||||
<option value="a.user_id ASC">COM_PRIVACY_HEADING_USERID_ASC</option>
|
||||
<option value="a.user_id DESC">COM_PRIVACY_HEADING_USERID_DESC</option>
|
||||
<option value="a.subject ASC">COM_PRIVACY_HEADING_SUBJECT_ASC</option>
|
||||
<option value="a.subject DESC">COM_PRIVACY_HEADING_SUBJECT_DESC</option>
|
||||
<option value="a.created ASC">COM_PRIVACY_HEADING_CREATED_ASC</option>
|
||||
<option value="a.created DESC">COM_PRIVACY_HEADING_CREATED_DESC</option>
|
||||
<option value="a.id ASC">JGRID_HEADING_ID_ASC</option>
|
||||
<option value="a.id DESC">JGRID_HEADING_ID_DESC</option>
|
||||
</field>
|
||||
|
||||
<field
|
||||
name="limit"
|
||||
type="limitbox"
|
||||
label="JGLOBAL_LIST_LIMIT"
|
||||
default="25"
|
||||
class="input-mini js-select-submit-on-change"
|
||||
/>
|
||||
</fields>
|
||||
</form>
|
||||
@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form addfieldprefix="Joomla\Component\Privacy\Administrator\Field">
|
||||
<fields name="filter">
|
||||
<field
|
||||
name="search"
|
||||
type="text"
|
||||
inputmode="search"
|
||||
label="COM_PRIVACY_FILTER_SEARCH_LABEL"
|
||||
description="COM_PRIVACY_SEARCH_IN_EMAIL"
|
||||
hint="JSEARCH_FILTER"
|
||||
/>
|
||||
|
||||
<field
|
||||
name="status"
|
||||
type="requeststatus"
|
||||
label="JSTATUS"
|
||||
class="js-select-submit-on-change"
|
||||
>
|
||||
<option value="">JOPTION_SELECT_PUBLISHED</option>
|
||||
</field>
|
||||
|
||||
<field
|
||||
name="request_type"
|
||||
type="requesttype"
|
||||
label="COM_PRIVACY_HEADING_REQUEST_TYPE"
|
||||
class="js-select-submit-on-change"
|
||||
>
|
||||
<option value="">COM_PRIVACY_SELECT_REQUEST_TYPE</option>
|
||||
</field>
|
||||
</fields>
|
||||
|
||||
<fields name="list">
|
||||
<field
|
||||
name="fullordering"
|
||||
type="list"
|
||||
label="JGLOBAL_SORT_BY"
|
||||
class="js-select-submit-on-change"
|
||||
default="a.id DESC"
|
||||
validate="options"
|
||||
>
|
||||
<option value="">JGLOBAL_SORT_BY</option>
|
||||
<option value="a.email ASC">COM_PRIVACY_HEADING_EMAIL_ASC</option>
|
||||
<option value="a.email DESC">COM_PRIVACY_HEADING_EMAIL_DESC</option>
|
||||
<option value="a.request_type ASC">COM_PRIVACY_HEADING_REQUEST_TYPE_ASC</option>
|
||||
<option value="a.request_type DESC">COM_PRIVACY_HEADING_REQUEST_TYPE_DESC</option>
|
||||
<option value="a.requested_at ASC">COM_PRIVACY_HEADING_REQUESTED_AT_ASC</option>
|
||||
<option value="a.requested_at DESC">COM_PRIVACY_HEADING_REQUESTED_AT_DESC</option>
|
||||
<option value="a.id ASC">JGRID_HEADING_ID_ASC</option>
|
||||
<option value="a.id DESC">JGRID_HEADING_ID_DESC</option>
|
||||
</field>
|
||||
|
||||
<field
|
||||
name="limit"
|
||||
type="limitbox"
|
||||
label="JGLOBAL_LIST_LIMIT"
|
||||
default="25"
|
||||
class="input-mini js-select-submit-on-change"
|
||||
/>
|
||||
</fields>
|
||||
</form>
|
||||
51
administrator/components/com_privacy/forms/request.xml
Normal file
51
administrator/components/com_privacy/forms/request.xml
Normal file
@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form>
|
||||
<fieldset>
|
||||
<field
|
||||
name="email"
|
||||
type="email"
|
||||
label="JGLOBAL_EMAIL"
|
||||
description="COM_PRIVACY_USER_FIELD_EMAIL_DESC"
|
||||
required="true"
|
||||
validate="email"
|
||||
/>
|
||||
|
||||
<field
|
||||
name="status"
|
||||
type="list"
|
||||
label="COM_PRIVACY_FIELD_STATUS_LABEL"
|
||||
filter="int"
|
||||
default="0"
|
||||
validate="options"
|
||||
readonly="true"
|
||||
>
|
||||
<option value="0">COM_PRIVACY_STATUS_PENDING</option>
|
||||
<option value="-1">COM_PRIVACY_STATUS_INVALID</option>
|
||||
<option value="1">COM_PRIVACY_STATUS_CONFIRMED</option>
|
||||
<option value="2">COM_PRIVACY_STATUS_COMPLETED</option>
|
||||
</field>
|
||||
|
||||
<field
|
||||
name="request_type"
|
||||
type="list"
|
||||
label="COM_PRIVACY_FIELD_REQUEST_TYPE_LABEL"
|
||||
filter="string"
|
||||
default="export"
|
||||
validate="options"
|
||||
>
|
||||
<option value="export">COM_PRIVACY_HEADING_REQUEST_TYPE_TYPE_EXPORT</option>
|
||||
<option value="remove">COM_PRIVACY_HEADING_REQUEST_TYPE_TYPE_REMOVE</option>
|
||||
</field>
|
||||
|
||||
<field
|
||||
name="id"
|
||||
type="number"
|
||||
label="JGLOBAL_FIELD_ID_LABEL"
|
||||
description="JGLOBAL_FIELD_ID_DESC"
|
||||
class="readonly"
|
||||
default="0"
|
||||
readonly="true"
|
||||
/>
|
||||
|
||||
</fieldset>
|
||||
</form>
|
||||
38
administrator/components/com_privacy/privacy.xml
Normal file
38
administrator/components/com_privacy/privacy.xml
Normal file
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<extension type="component" method="upgrade">
|
||||
<name>com_privacy</name>
|
||||
<author>Joomla! Project</author>
|
||||
<creationDate>2018-05</creationDate>
|
||||
<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
|
||||
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
|
||||
<authorEmail>admin@joomla.org</authorEmail>
|
||||
<authorUrl>www.joomla.org</authorUrl>
|
||||
<version>3.9.0</version>
|
||||
<description>COM_PRIVACY_XML_DESCRIPTION</description>
|
||||
<namespace path="src">Joomla\Component\Privacy</namespace>
|
||||
<files folder="site">
|
||||
<folder>forms</folder>
|
||||
<folder>src</folder>
|
||||
<folder>tmpl</folder>
|
||||
</files>
|
||||
<languages folder="site">
|
||||
<language tag="en-GB">language/en-GB/com_privacy.ini</language>
|
||||
</languages>
|
||||
<administration>
|
||||
<files folder="admin">
|
||||
<filename>config.xml</filename>
|
||||
<filename>privacy.xml</filename>
|
||||
<folder>forms</folder>
|
||||
<folder>services</folder>
|
||||
<folder>src</folder>
|
||||
<folder>tmpl</folder>
|
||||
</files>
|
||||
<languages folder="admin">
|
||||
<language tag="en-GB">language/en-GB/com_privacy.ini</language>
|
||||
<language tag="en-GB">language/en-GB/com_privacy.sys.ini</language>
|
||||
</languages>
|
||||
</administration>
|
||||
<dashboards>
|
||||
<dashboard title="COM_PRIVACY_DASHBOARD_TITLE" icon="icon-lock">privacy</dashboard>
|
||||
</dashboards>
|
||||
</extension>
|
||||
59
administrator/components/com_privacy/services/provider.php
Normal file
59
administrator/components/com_privacy/services/provider.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @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
|
||||
*/
|
||||
|
||||
\defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Component\Router\RouterFactoryInterface;
|
||||
use Joomla\CMS\Dispatcher\ComponentDispatcherFactoryInterface;
|
||||
use Joomla\CMS\Extension\ComponentInterface;
|
||||
use Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory;
|
||||
use Joomla\CMS\Extension\Service\Provider\MVCFactory;
|
||||
use Joomla\CMS\Extension\Service\Provider\RouterFactory;
|
||||
use Joomla\CMS\HTML\Registry;
|
||||
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
|
||||
use Joomla\Component\Privacy\Administrator\Extension\PrivacyComponent;
|
||||
use Joomla\DI\Container;
|
||||
use Joomla\DI\ServiceProviderInterface;
|
||||
|
||||
/**
|
||||
* The privacy component service provider.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
return new class () implements ServiceProviderInterface {
|
||||
/**
|
||||
* Registers the service provider with a DI container.
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function register(Container $container)
|
||||
{
|
||||
$container->registerServiceProvider(new MVCFactory('\\Joomla\\Component\\Privacy'));
|
||||
$container->registerServiceProvider(new ComponentDispatcherFactory('\\Joomla\\Component\\Privacy'));
|
||||
$container->registerServiceProvider(new RouterFactory('\\Joomla\\Component\\Privacy'));
|
||||
|
||||
$container->set(
|
||||
ComponentInterface::class,
|
||||
function (Container $container) {
|
||||
$component = new PrivacyComponent($container->get(ComponentDispatcherFactoryInterface::class));
|
||||
|
||||
$component->setMVCFactory($container->get(MVCFactoryInterface::class));
|
||||
$component->setRegistry($container->get(Registry::class));
|
||||
$component->setRouterFactory($container->get(RouterFactoryInterface::class));
|
||||
|
||||
return $component;
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Privacy\Administrator\Controller;
|
||||
|
||||
use Joomla\CMS\Application\CMSApplication;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\MVC\Controller\FormController;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\Component\Privacy\Administrator\Model\ConsentsModel;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Consents management controller class.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
class ConsentsController extends FormController
|
||||
{
|
||||
/**
|
||||
* Method to invalidate specific consents.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function invalidate()
|
||||
{
|
||||
// Check for request forgeries
|
||||
$this->checkToken();
|
||||
|
||||
$ids = (array) $this->input->get('cid', [], 'int');
|
||||
|
||||
// Remove zero values resulting from input filter
|
||||
$ids = array_filter($ids);
|
||||
|
||||
if (empty($ids)) {
|
||||
$this->app->enqueueMessage(Text::_('JERROR_NO_ITEMS_SELECTED'), CMSApplication::MSG_ERROR);
|
||||
} else {
|
||||
/** @var ConsentsModel $model */
|
||||
$model = $this->getModel();
|
||||
|
||||
if (!$model->invalidate($ids)) {
|
||||
$this->setMessage($model->getError());
|
||||
} else {
|
||||
$this->setMessage(Text::plural('COM_PRIVACY_N_CONSENTS_INVALIDATED', \count($ids)));
|
||||
}
|
||||
}
|
||||
|
||||
$this->setRedirect(Route::_('index.php?option=com_privacy&view=consents', false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to invalidate all consents of a specific subject.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function invalidateAll()
|
||||
{
|
||||
// Check for request forgeries
|
||||
$this->checkToken();
|
||||
|
||||
$filters = $this->input->get('filter', [], 'array');
|
||||
|
||||
$this->setRedirect(Route::_('index.php?option=com_privacy&view=consents', false));
|
||||
|
||||
if (isset($filters['subject']) && $filters['subject'] != '') {
|
||||
$subject = $filters['subject'];
|
||||
} else {
|
||||
$this->app->enqueueMessage(Text::_('JERROR_NO_ITEMS_SELECTED'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var ConsentsModel $model */
|
||||
$model = $this->getModel();
|
||||
|
||||
if (!$model->invalidateAll($subject)) {
|
||||
$this->setMessage($model->getError());
|
||||
}
|
||||
|
||||
$this->setMessage(Text::_('COM_PRIVACY_CONSENTS_INVALIDATED_ALL'));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Privacy\Administrator\Controller;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\MVC\Controller\BaseController;
|
||||
use Joomla\CMS\Response\JsonResponse;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Session\Session;
|
||||
use Joomla\Component\Privacy\Administrator\Model\RequestsModel;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Privacy Controller
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
class DisplayController extends BaseController
|
||||
{
|
||||
/**
|
||||
* The default view.
|
||||
*
|
||||
* @var string
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected $default_view = 'requests';
|
||||
|
||||
/**
|
||||
* Method to display a view.
|
||||
*
|
||||
* @param boolean $cachable If true, the view output will be cached
|
||||
* @param array $urlparams An array of safe URL parameters and their variable types.
|
||||
* @see \Joomla\CMS\Filter\InputFilter::clean() for valid values.
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function display($cachable = false, $urlparams = [])
|
||||
{
|
||||
// Get the document object.
|
||||
$document = $this->app->getDocument();
|
||||
|
||||
// Set the default view name and format from the Request.
|
||||
$vName = $this->input->get('view', $this->default_view);
|
||||
$vFormat = $document->getType();
|
||||
$lName = $this->input->get('layout', 'default', 'string');
|
||||
|
||||
// Get and render the view.
|
||||
if ($view = $this->getView($vName, $vFormat)) {
|
||||
$model = $this->getModel($vName);
|
||||
$view->setModel($model, true);
|
||||
|
||||
if ($vName === 'request') {
|
||||
// For the default layout, we need to also push the action logs model into the view
|
||||
if ($lName === 'default') {
|
||||
$logsModel = $this->app->bootComponent('com_actionlogs')
|
||||
->getMVCFactory()->createModel('Actionlogs', 'Administrator', ['ignore_request' => true]);
|
||||
|
||||
// Set default ordering for the context
|
||||
$logsModel->setState('list.fullordering', 'a.log_date DESC');
|
||||
|
||||
// And push the model into the view
|
||||
$view->setModel($logsModel, false);
|
||||
}
|
||||
|
||||
// For the edit layout, if mail sending is disabled then redirect back to the list view as the form is unusable in this state
|
||||
if ($lName === 'edit' && !$this->app->get('mailonline', 1)) {
|
||||
$this->setRedirect(
|
||||
Route::_('index.php?option=com_privacy&view=requests', false),
|
||||
Text::_('COM_PRIVACY_WARNING_CANNOT_CREATE_REQUEST_WHEN_SENDMAIL_DISABLED'),
|
||||
'warning'
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
$view->setLayout($lName);
|
||||
|
||||
// Push document object into the view.
|
||||
$view->document = $document;
|
||||
|
||||
$view->display();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and report number urgent privacy requests in JSON format, for AJAX requests
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function getNumberUrgentRequests()
|
||||
{
|
||||
// Check for a valid token. If invalid, send a 403 with the error message.
|
||||
if (!Session::checkToken('get')) {
|
||||
$this->app->setHeader('status', 403, true);
|
||||
$this->app->sendHeaders();
|
||||
echo new JsonResponse(new \Exception(Text::_('JINVALID_TOKEN'), 403));
|
||||
$this->app->close();
|
||||
}
|
||||
|
||||
/** @var RequestsModel $model */
|
||||
$model = $this->getModel('requests');
|
||||
$numberUrgentRequests = $model->getNumberUrgentRequests();
|
||||
|
||||
echo new JsonResponse(['number_urgent_requests' => $numberUrgentRequests]);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,403 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Privacy\Administrator\Controller;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\MVC\Controller\FormController;
|
||||
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
use Joomla\Component\Privacy\Administrator\Model\ExportModel;
|
||||
use Joomla\Component\Privacy\Administrator\Model\RemoveModel;
|
||||
use Joomla\Component\Privacy\Administrator\Model\RequestModel;
|
||||
use Joomla\Component\Privacy\Administrator\Table\RequestTable;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Request management controller class.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
class RequestController extends FormController
|
||||
{
|
||||
/**
|
||||
* Method to complete a request.
|
||||
*
|
||||
* @param string $key The name of the primary key of the URL variable.
|
||||
* @param string $urlVar The name of the URL variable if different from the primary key (sometimes required to avoid router collisions).
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function complete($key = null, $urlVar = null)
|
||||
{
|
||||
// Check for request forgeries.
|
||||
$this->checkToken();
|
||||
|
||||
/** @var RequestModel $model */
|
||||
$model = $this->getModel();
|
||||
|
||||
/** @var RequestTable $table */
|
||||
$table = $model->getTable();
|
||||
|
||||
// Determine the name of the primary key for the data.
|
||||
if (empty($key)) {
|
||||
$key = $table->getKeyName();
|
||||
}
|
||||
|
||||
// To avoid data collisions the urlVar may be different from the primary key.
|
||||
if (empty($urlVar)) {
|
||||
$urlVar = $key;
|
||||
}
|
||||
|
||||
$recordId = $this->input->getInt($urlVar);
|
||||
|
||||
$item = $model->getItem($recordId);
|
||||
|
||||
// Ensure this record can transition to the requested state
|
||||
if (!$this->canTransition($item, '2')) {
|
||||
$this->setMessage(Text::_('COM_PRIVACY_ERROR_COMPLETE_TRANSITION_NOT_PERMITTED'), 'error');
|
||||
|
||||
$this->setRedirect(
|
||||
Route::_(
|
||||
'index.php?option=com_privacy&view=request&id=' . $recordId,
|
||||
false
|
||||
)
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build the data array for the update
|
||||
$data = [
|
||||
$key => $recordId,
|
||||
'status' => '2',
|
||||
];
|
||||
|
||||
// Access check.
|
||||
if (!$this->allowSave($data, $key)) {
|
||||
$this->setMessage(Text::_('JLIB_APPLICATION_ERROR_SAVE_NOT_PERMITTED'), 'error');
|
||||
|
||||
$this->setRedirect(
|
||||
Route::_(
|
||||
'index.php?option=com_privacy&view=request&id=' . $recordId,
|
||||
false
|
||||
)
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Attempt to save the data.
|
||||
if (!$model->save($data)) {
|
||||
// Redirect back to the edit screen.
|
||||
$this->setMessage(Text::sprintf('JLIB_APPLICATION_ERROR_SAVE_FAILED', $model->getError()), 'error');
|
||||
|
||||
$this->setRedirect(
|
||||
Route::_(
|
||||
'index.php?option=com_privacy&view=request&id=' . $recordId,
|
||||
false
|
||||
)
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Log the request completed
|
||||
$model->logRequestCompleted($recordId);
|
||||
|
||||
$this->setMessage(Text::_('COM_PRIVACY_REQUEST_COMPLETED'));
|
||||
|
||||
$url = 'index.php?option=com_privacy&view=requests';
|
||||
|
||||
// Check if there is a return value
|
||||
$return = $this->input->get('return', null, 'base64');
|
||||
|
||||
if (!\is_null($return) && Uri::isInternal(base64_decode($return))) {
|
||||
$url = base64_decode($return);
|
||||
}
|
||||
|
||||
// Redirect to the list screen.
|
||||
$this->setRedirect(Route::_($url, false));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to email the data export for a request.
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function emailexport()
|
||||
{
|
||||
// Check for request forgeries.
|
||||
$this->checkToken('get');
|
||||
|
||||
/** @var ExportModel $model */
|
||||
$model = $this->getModel('Export');
|
||||
|
||||
$recordId = $this->input->getUint('id');
|
||||
|
||||
if (!$model->emailDataExport($recordId)) {
|
||||
// Redirect back to the edit screen.
|
||||
$this->setMessage(Text::sprintf('COM_PRIVACY_ERROR_EXPORT_EMAIL_FAILED', $model->getError()), 'error');
|
||||
} else {
|
||||
$this->setMessage(Text::_('COM_PRIVACY_EXPORT_EMAILED'));
|
||||
}
|
||||
|
||||
$url = 'index.php?option=com_privacy&view=requests';
|
||||
|
||||
// Check if there is a return value
|
||||
$return = $this->input->get('return', null, 'base64');
|
||||
|
||||
if (!\is_null($return) && Uri::isInternal(base64_decode($return))) {
|
||||
$url = base64_decode($return);
|
||||
}
|
||||
|
||||
// Redirect to the list screen.
|
||||
$this->setRedirect(Route::_($url, false));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to export the data for a request.
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function export()
|
||||
{
|
||||
$this->input->set('view', 'export');
|
||||
|
||||
return $this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to invalidate a request.
|
||||
*
|
||||
* @param string $key The name of the primary key of the URL variable.
|
||||
* @param string $urlVar The name of the URL variable if different from the primary key (sometimes required to avoid router collisions).
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function invalidate($key = null, $urlVar = null)
|
||||
{
|
||||
// Check for request forgeries.
|
||||
$this->checkToken();
|
||||
|
||||
/** @var RequestModel $model */
|
||||
$model = $this->getModel();
|
||||
|
||||
/** @var RequestTable $table */
|
||||
$table = $model->getTable();
|
||||
|
||||
// Determine the name of the primary key for the data.
|
||||
if (empty($key)) {
|
||||
$key = $table->getKeyName();
|
||||
}
|
||||
|
||||
// To avoid data collisions the urlVar may be different from the primary key.
|
||||
if (empty($urlVar)) {
|
||||
$urlVar = $key;
|
||||
}
|
||||
|
||||
$recordId = $this->input->getInt($urlVar);
|
||||
|
||||
$item = $model->getItem($recordId);
|
||||
|
||||
// Ensure this record can transition to the requested state
|
||||
if (!$this->canTransition($item, '-1')) {
|
||||
$this->setMessage(Text::_('COM_PRIVACY_ERROR_INVALID_TRANSITION_NOT_PERMITTED'), 'error');
|
||||
|
||||
$this->setRedirect(
|
||||
Route::_(
|
||||
'index.php?option=com_privacy&view=request&id=' . $recordId,
|
||||
false
|
||||
)
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build the data array for the update
|
||||
$data = [
|
||||
$key => $recordId,
|
||||
'status' => '-1',
|
||||
];
|
||||
|
||||
// Access check.
|
||||
if (!$this->allowSave($data, $key)) {
|
||||
$this->setMessage(Text::_('JLIB_APPLICATION_ERROR_SAVE_NOT_PERMITTED'), 'error');
|
||||
|
||||
$this->setRedirect(
|
||||
Route::_(
|
||||
'index.php?option=com_privacy&view=request&id=' . $recordId,
|
||||
false
|
||||
)
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Attempt to save the data.
|
||||
if (!$model->save($data)) {
|
||||
// Redirect back to the edit screen.
|
||||
$this->setMessage(Text::sprintf('JLIB_APPLICATION_ERROR_SAVE_FAILED', $model->getError()), 'error');
|
||||
|
||||
$this->setRedirect(
|
||||
Route::_(
|
||||
'index.php?option=com_privacy&view=request&id=' . $recordId,
|
||||
false
|
||||
)
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Log the request invalidated
|
||||
$model->logRequestInvalidated($recordId);
|
||||
|
||||
$this->setMessage(Text::_('COM_PRIVACY_REQUEST_INVALIDATED'));
|
||||
|
||||
$url = 'index.php?option=com_privacy&view=requests';
|
||||
|
||||
// Check if there is a return value
|
||||
$return = $this->input->get('return', null, 'base64');
|
||||
|
||||
if (!\is_null($return) && Uri::isInternal(base64_decode($return))) {
|
||||
$url = base64_decode($return);
|
||||
}
|
||||
|
||||
// Redirect to the list screen.
|
||||
$this->setRedirect(Route::_($url, false));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to remove the user data for a privacy remove request.
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function remove()
|
||||
{
|
||||
// Check for request forgeries.
|
||||
$this->checkToken('request');
|
||||
|
||||
/** @var RemoveModel $model */
|
||||
$model = $this->getModel('Remove');
|
||||
|
||||
$recordId = $this->input->getUint('id');
|
||||
|
||||
if (!$model->removeDataForRequest($recordId)) {
|
||||
// Redirect back to the edit screen.
|
||||
$this->setMessage(Text::sprintf('COM_PRIVACY_ERROR_REMOVE_DATA_FAILED', $model->getError()), 'error');
|
||||
|
||||
$this->setRedirect(
|
||||
Route::_(
|
||||
'index.php?option=com_privacy&view=request&id=' . $recordId,
|
||||
false
|
||||
)
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->setMessage(Text::_('COM_PRIVACY_DATA_REMOVED'));
|
||||
|
||||
$url = 'index.php?option=com_privacy&view=requests';
|
||||
|
||||
// Check if there is a return value
|
||||
$return = $this->input->get('return', null, 'base64');
|
||||
|
||||
if (!\is_null($return) && Uri::isInternal(base64_decode($return))) {
|
||||
$url = base64_decode($return);
|
||||
}
|
||||
|
||||
// Redirect to the list screen.
|
||||
$this->setRedirect(Route::_($url, false));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that allows child controller access to model data after the data has been saved.
|
||||
*
|
||||
* @param BaseDatabaseModel $model The data model object.
|
||||
* @param array $validData The validated data.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected function postSaveHook(BaseDatabaseModel $model, $validData = [])
|
||||
{
|
||||
// This hook only processes new items
|
||||
if (!$model->getState($model->getName() . '.new', false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$model->logRequestCreated($model->getState($model->getName() . '.id'))) {
|
||||
if ($error = $model->getError()) {
|
||||
$this->app->enqueueMessage($error, 'warning');
|
||||
}
|
||||
}
|
||||
|
||||
if (!$model->notifyUserAdminCreatedRequest($model->getState($model->getName() . '.id'))) {
|
||||
if ($error = $model->getError()) {
|
||||
$this->app->enqueueMessage($error, 'warning');
|
||||
}
|
||||
} else {
|
||||
$this->app->enqueueMessage(Text::_('COM_PRIVACY_MSG_CONFIRM_EMAIL_SENT_TO_USER'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to determine if an item can transition to the specified status.
|
||||
*
|
||||
* @param object $item The item being updated.
|
||||
* @param string $newStatus The new status of the item.
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
private function canTransition($item, $newStatus)
|
||||
{
|
||||
switch ($item->status) {
|
||||
case '0':
|
||||
// A pending item can only move to invalid through this controller due to the requirement for a user to confirm the request
|
||||
return $newStatus === '-1';
|
||||
|
||||
case '1':
|
||||
// A confirmed item can be marked completed or invalid
|
||||
return \in_array($newStatus, ['-1', '2'], true);
|
||||
|
||||
case '-1':
|
||||
case '2':
|
||||
default:
|
||||
// An item which is already in an invalid or complete state cannot transition, likewise if we don't know the state don't change anything
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Privacy\Administrator\Controller;
|
||||
|
||||
use Joomla\CMS\MVC\Controller\AdminController;
|
||||
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Requests management controller class.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
class RequestsController extends AdminController
|
||||
{
|
||||
/**
|
||||
* Method to get a model object, loading it if required.
|
||||
*
|
||||
* @param string $name The model name. Optional.
|
||||
* @param string $prefix The class prefix. Optional.
|
||||
* @param array $config Configuration array for model. Optional.
|
||||
*
|
||||
* @return BaseDatabaseModel|boolean Model object on success; otherwise false on failure.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function getModel($name = 'Request', $prefix = 'Administrator', $config = ['ignore_request' => true])
|
||||
{
|
||||
return parent::getModel($name, $prefix, $config);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @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\Administrator\Dispatcher;
|
||||
|
||||
use Joomla\CMS\Access\Exception\NotAllowed;
|
||||
use Joomla\CMS\Dispatcher\ComponentDispatcher;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Component dispatcher class for com_privacy
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
class Dispatcher extends ComponentDispatcher
|
||||
{
|
||||
/**
|
||||
* Method to check component access permission
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function checkAccess()
|
||||
{
|
||||
// Check the user has permission to access this component if in the backend
|
||||
if ($this->app->isClient('administrator') && !$this->app->getIdentity()->authorise('core.admin', $this->option)) {
|
||||
throw new NotAllowed($this->app->getLanguage()->_('JERROR_ALERTNOAUTHOR'), 403);
|
||||
}
|
||||
}
|
||||
}
|
||||
75
administrator/components/com_privacy/src/Export/Domain.php
Normal file
75
administrator/components/com_privacy/src/Export/Domain.php
Normal file
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Privacy\Administrator\Export;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Data object representing all data contained in a domain.
|
||||
*
|
||||
* A domain is typically a single database table and the items within the domain are separate rows from the table.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
class Domain
|
||||
{
|
||||
/**
|
||||
* The name of this domain
|
||||
*
|
||||
* @var string
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* A short description of the data in this domain
|
||||
*
|
||||
* @var string
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public $description;
|
||||
|
||||
/**
|
||||
* The items belonging to this domain
|
||||
*
|
||||
* @var Item[]
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected $items = [];
|
||||
|
||||
/**
|
||||
* Add an item to the domain
|
||||
*
|
||||
* @param Item $item The item to add
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function addItem(Item $item)
|
||||
{
|
||||
$this->items[] = $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the domain's items
|
||||
*
|
||||
* @return Item[]
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function getItems()
|
||||
{
|
||||
return $this->items;
|
||||
}
|
||||
}
|
||||
39
administrator/components/com_privacy/src/Export/Field.php
Normal file
39
administrator/components/com_privacy/src/Export/Field.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Privacy\Administrator\Export;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Data object representing a field within an item.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
class Field
|
||||
{
|
||||
/**
|
||||
* The name of this field
|
||||
*
|
||||
* @var string
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* The field's value
|
||||
*
|
||||
* @var mixed
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public $value;
|
||||
}
|
||||
67
administrator/components/com_privacy/src/Export/Item.php
Normal file
67
administrator/components/com_privacy/src/Export/Item.php
Normal file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Privacy\Administrator\Export;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Data object representing a single item within a domain.
|
||||
*
|
||||
* An item is typically a single row from a database table.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
class Item
|
||||
{
|
||||
/**
|
||||
* The primary identifier of this item, typically the primary key for a database row.
|
||||
*
|
||||
* @var integer
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* The fields belonging to this item
|
||||
*
|
||||
* @var Field[]
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected $fields = [];
|
||||
|
||||
/**
|
||||
* Add a field to the item
|
||||
*
|
||||
* @param Field $field The field to add
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function addField(Field $field)
|
||||
{
|
||||
$this->fields[] = $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the item's fields
|
||||
*
|
||||
* @return Field[]
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function getFields()
|
||||
{
|
||||
return $this->fields;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @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\Administrator\Extension;
|
||||
|
||||
use Joomla\CMS\Component\Router\RouterServiceInterface;
|
||||
use Joomla\CMS\Component\Router\RouterServiceTrait;
|
||||
use Joomla\CMS\Extension\BootableExtensionInterface;
|
||||
use Joomla\CMS\Extension\MVCComponent;
|
||||
use Joomla\CMS\HTML\HTMLRegistryAwareTrait;
|
||||
use Joomla\Component\Privacy\Administrator\Service\HTML\Privacy;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Component class for com_privacy
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
class PrivacyComponent extends MVCComponent implements BootableExtensionInterface, RouterServiceInterface
|
||||
{
|
||||
use HTMLRegistryAwareTrait;
|
||||
use RouterServiceTrait;
|
||||
|
||||
/**
|
||||
* Booting the extension. This is the function to set up the environment of the extension like
|
||||
* registering new class loaders, etc.
|
||||
*
|
||||
* If required, some initial set up can be done from services of the container, eg.
|
||||
* registering HTML services.
|
||||
*
|
||||
* @param ContainerInterface $container The container
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public function boot(ContainerInterface $container)
|
||||
{
|
||||
$this->getRegistry()->register('privacy', new Privacy());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Privacy\Administrator\Field;
|
||||
|
||||
use Joomla\CMS\Form\Field\PredefinedlistField;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Form Field to load a list of request statuses
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
class RequeststatusField extends PredefinedlistField
|
||||
{
|
||||
/**
|
||||
* The form field type.
|
||||
*
|
||||
* @var string
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public $type = 'RequestStatus';
|
||||
|
||||
/**
|
||||
* Available statuses
|
||||
*
|
||||
* @var array
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected $predefinedOptions = [
|
||||
'-1' => 'COM_PRIVACY_STATUS_INVALID',
|
||||
'0' => 'COM_PRIVACY_STATUS_PENDING',
|
||||
'1' => 'COM_PRIVACY_STATUS_CONFIRMED',
|
||||
'2' => 'COM_PRIVACY_STATUS_COMPLETED',
|
||||
];
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Privacy\Administrator\Field;
|
||||
|
||||
use Joomla\CMS\Form\Field\PredefinedlistField;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Form Field to load a list of request types
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
class RequesttypeField extends PredefinedlistField
|
||||
{
|
||||
/**
|
||||
* The form field type.
|
||||
*
|
||||
* @var string
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public $type = 'RequestType';
|
||||
|
||||
/**
|
||||
* Available types
|
||||
*
|
||||
* @var array
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected $predefinedOptions = [
|
||||
'export' => 'COM_PRIVACY_HEADING_REQUEST_TYPE_TYPE_EXPORT',
|
||||
'remove' => 'COM_PRIVACY_HEADING_REQUEST_TYPE_TYPE_REMOVE',
|
||||
];
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Privacy\Administrator\Helper;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Helper\ContentHelper;
|
||||
use Joomla\Component\Privacy\Administrator\Export\Domain;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Privacy component helper.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
class PrivacyHelper extends ContentHelper
|
||||
{
|
||||
/**
|
||||
* Render the data request as a XML document.
|
||||
*
|
||||
* @param Domain[] $exportData The data to be exported.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public static function renderDataAsXml(array $exportData)
|
||||
{
|
||||
$export = new \SimpleXMLElement('<?xml version="1.0" encoding="utf-8"?><data-export />');
|
||||
|
||||
foreach ($exportData as $domain) {
|
||||
$xmlDomain = $export->addChild('domain');
|
||||
$xmlDomain->addAttribute('name', $domain->name);
|
||||
$xmlDomain->addAttribute('description', $domain->description);
|
||||
|
||||
foreach ($domain->getItems() as $item) {
|
||||
$xmlItem = $xmlDomain->addChild('item');
|
||||
|
||||
if ($item->id) {
|
||||
$xmlItem->addAttribute('id', $item->id);
|
||||
}
|
||||
|
||||
foreach ($item->getFields() as $field) {
|
||||
$xmlItem->{$field->name} = $field->value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$dom = new \DOMDocument();
|
||||
$dom->loadXML($export->asXML());
|
||||
$dom->formatOutput = true;
|
||||
|
||||
return $dom->saveXML();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the privacyconsent system plugin extension id.
|
||||
*
|
||||
* @return integer The privacyconsent system plugin extension id.
|
||||
*
|
||||
* @since 3.9.2
|
||||
*/
|
||||
public static function getPrivacyConsentPluginId()
|
||||
{
|
||||
$db = Factory::getDbo();
|
||||
$query = $db->getQuery(true)
|
||||
->select($db->quoteName('extension_id'))
|
||||
->from($db->quoteName('#__extensions'))
|
||||
->where($db->quoteName('folder') . ' = ' . $db->quote('system'))
|
||||
->where($db->quoteName('element') . ' = ' . $db->quote('privacyconsent'));
|
||||
|
||||
$db->setQuery($query);
|
||||
|
||||
return (int) $db->loadResult();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Privacy\Administrator\Model;
|
||||
|
||||
use Joomla\CMS\Component\ComponentHelper;
|
||||
use Joomla\CMS\Event\Privacy\CollectCapabilitiesEvent;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\MVC\Model\BaseModel;
|
||||
use Joomla\CMS\Plugin\PluginHelper;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Capabilities model class.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
class CapabilitiesModel extends BaseModel
|
||||
{
|
||||
/**
|
||||
* Retrieve the extension capabilities.
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function getCapabilities()
|
||||
{
|
||||
$app = Factory::getApplication();
|
||||
|
||||
/*
|
||||
* Capabilities will be collected in two parts:
|
||||
*
|
||||
* 1) Core capabilities - This will cover the core API, i.e. all library level classes
|
||||
* 2) Extension capabilities - This will be collected by a plugin hook to select plugin groups
|
||||
*
|
||||
* Plugins which report capabilities should return an associative array with a single root level key which is used as the title
|
||||
* for the reporting section and an array with each value being a separate capability. All capability messages should be translated
|
||||
* by the extension when building the array. An example of the structure expected to be returned from plugins can be found in the
|
||||
* $coreCapabilities array below.
|
||||
*/
|
||||
|
||||
$coreCapabilities = [
|
||||
Text::_('COM_PRIVACY_HEADING_CORE_CAPABILITIES') => [
|
||||
Text::_('COM_PRIVACY_CORE_CAPABILITY_SESSION_IP_ADDRESS_AND_COOKIE'),
|
||||
Text::sprintf('COM_PRIVACY_CORE_CAPABILITY_LOGGING_IP_ADDRESS', $app->get('log_path', JPATH_ADMINISTRATOR . '/logs')),
|
||||
Text::_('COM_PRIVACY_CORE_CAPABILITY_COMMUNICATION_WITH_JOOMLA_ORG'),
|
||||
],
|
||||
];
|
||||
|
||||
/*
|
||||
* We will search for capabilities from the following plugin groups:
|
||||
*
|
||||
* - Authentication: These plugins by design process user information and may have capabilities such as creating cookies
|
||||
* - Captcha: These plugins may communicate information to third party systems
|
||||
* - Installer: These plugins can add additional install capabilities to the Extension Manager, such as the Install from Web service
|
||||
* - Privacy: These plugins are the primary integration point into this component
|
||||
* - User: These plugins are intended to extend the user management system
|
||||
*
|
||||
* This is in addition to plugin groups which are imported before this method is triggered, generally this is the system group.
|
||||
*/
|
||||
|
||||
$dispatcher = $app->getDispatcher();
|
||||
|
||||
PluginHelper::importPlugin('authentication', null, true, $dispatcher);
|
||||
PluginHelper::importPlugin('captcha', null, true, $dispatcher);
|
||||
PluginHelper::importPlugin('installer', null, true, $dispatcher);
|
||||
PluginHelper::importPlugin('privacy', null, true, $dispatcher);
|
||||
PluginHelper::importPlugin('user', null, true, $dispatcher);
|
||||
|
||||
$pluginResults = $dispatcher->dispatch(
|
||||
'onPrivacyCollectAdminCapabilities',
|
||||
new CollectCapabilitiesEvent('onPrivacyCollectAdminCapabilities')
|
||||
)->getArgument('result', []);
|
||||
|
||||
// We are going to "cheat" here and include this component's capabilities without using a plugin
|
||||
$extensionCapabilities = [
|
||||
Text::_('COM_PRIVACY') => [
|
||||
Text::_('COM_PRIVACY_EXTENSION_CAPABILITY_PERSONAL_INFO'),
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($pluginResults as $pluginResult) {
|
||||
$extensionCapabilities += $pluginResult;
|
||||
}
|
||||
|
||||
// Sort the extension list alphabetically
|
||||
ksort($extensionCapabilities);
|
||||
|
||||
// Always prepend the core capabilities to the array
|
||||
return $coreCapabilities + $extensionCapabilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to auto-populate the model state.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected function populateState()
|
||||
{
|
||||
// Load the parameters.
|
||||
$this->setState('params', ComponentHelper::getParams('com_privacy'));
|
||||
}
|
||||
}
|
||||
226
administrator/components/com_privacy/src/Model/ConsentsModel.php
Normal file
226
administrator/components/com_privacy/src/Model/ConsentsModel.php
Normal file
@ -0,0 +1,226 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Privacy\Administrator\Model;
|
||||
|
||||
use Joomla\CMS\Component\ComponentHelper;
|
||||
use Joomla\CMS\MVC\Model\ListModel;
|
||||
use Joomla\Database\Exception\ExecutionFailureException;
|
||||
use Joomla\Database\ParameterType;
|
||||
use Joomla\Database\QueryInterface;
|
||||
use Joomla\Utilities\ArrayHelper;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Consents management model class.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
class ConsentsModel extends ListModel
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $config An optional associative array of configuration settings.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function __construct($config = [])
|
||||
{
|
||||
if (empty($config['filter_fields'])) {
|
||||
$config['filter_fields'] = [
|
||||
'id', 'a.id',
|
||||
'user_id', 'a.user_id',
|
||||
'subject', 'a.subject',
|
||||
'created', 'a.created',
|
||||
'username', 'u.username',
|
||||
'name', 'u.name',
|
||||
'state', 'a.state',
|
||||
];
|
||||
}
|
||||
|
||||
parent::__construct($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get a QueryInterface object for retrieving the data set from a database.
|
||||
*
|
||||
* @return QueryInterface
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected function getListQuery()
|
||||
{
|
||||
// Create a new query object.
|
||||
$db = $this->getDatabase();
|
||||
$query = $db->getQuery(true);
|
||||
|
||||
// Select the required fields from the table.
|
||||
$query->select($this->getState('list.select', 'a.*'));
|
||||
$query->from($db->quoteName('#__privacy_consents', 'a'));
|
||||
|
||||
// Join over the users for the username and name.
|
||||
$query->select($db->quoteName('u.username', 'username'))
|
||||
->select($db->quoteName('u.name', 'name'));
|
||||
$query->join('LEFT', $db->quoteName('#__users', 'u') . ' ON u.id = a.user_id');
|
||||
|
||||
// Filter by search in email
|
||||
$search = $this->getState('filter.search');
|
||||
|
||||
if (!empty($search)) {
|
||||
if (stripos($search, 'id:') === 0) {
|
||||
$ids = (int) substr($search, 3);
|
||||
$query->where($db->quoteName('a.id') . ' = :id')
|
||||
->bind(':id', $ids, ParameterType::INTEGER);
|
||||
} elseif (stripos($search, 'uid:') === 0) {
|
||||
$uid = (int) substr($search, 4);
|
||||
$query->where($db->quoteName('a.user_id') . ' = :uid')
|
||||
->bind(':uid', $uid, ParameterType::INTEGER);
|
||||
} elseif (stripos($search, 'name:') === 0) {
|
||||
$search = '%' . substr($search, 5) . '%';
|
||||
$query->where($db->quoteName('u.name') . ' LIKE :search')
|
||||
->bind(':search', $search);
|
||||
} else {
|
||||
$search = '%' . $search . '%';
|
||||
$query->where('(' . $db->quoteName('u.username') . ' LIKE :search)')
|
||||
->bind(':search', $search);
|
||||
}
|
||||
}
|
||||
|
||||
$state = $this->getState('filter.state');
|
||||
|
||||
if ($state != '') {
|
||||
$state = (int) $state;
|
||||
$query->where($db->quoteName('a.state') . ' = :state')
|
||||
->bind(':state', $state, ParameterType::INTEGER);
|
||||
}
|
||||
|
||||
$subject = $this->getState('filter.subject');
|
||||
|
||||
if (!empty($subject)) {
|
||||
$query->where($db->quoteName('a.subject') . ' = :subject')
|
||||
->bind(':subject', $subject, ParameterType::STRING);
|
||||
}
|
||||
|
||||
// Handle the list ordering.
|
||||
$ordering = $this->getState('list.ordering');
|
||||
$direction = $this->getState('list.direction');
|
||||
|
||||
if (!empty($ordering)) {
|
||||
$query->order($db->escape($ordering) . ' ' . $db->escape($direction));
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get a store id based on model configuration state.
|
||||
*
|
||||
* This is necessary because the model is used by the component and
|
||||
* different modules that might need different sets of data or different
|
||||
* ordering requirements.
|
||||
*
|
||||
* @param string $id A prefix for the store id.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected function getStoreId($id = '')
|
||||
{
|
||||
// Compile the store id.
|
||||
$id .= ':' . $this->getState('filter.search');
|
||||
|
||||
return parent::getStoreId($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to auto-populate the model state.
|
||||
*
|
||||
* Note. Calling getState in this method will result in recursion.
|
||||
*
|
||||
* @param string $ordering An optional ordering field.
|
||||
* @param string $direction An optional direction (asc|desc).
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected function populateState($ordering = 'a.id', $direction = 'desc')
|
||||
{
|
||||
// Load the parameters.
|
||||
$this->setState('params', ComponentHelper::getParams('com_privacy'));
|
||||
|
||||
// List state information.
|
||||
parent::populateState($ordering, $direction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to invalidate specific consents.
|
||||
*
|
||||
* @param array $pks The ids of the consents to invalidate.
|
||||
*
|
||||
* @return boolean True on success.
|
||||
*/
|
||||
public function invalidate($pks)
|
||||
{
|
||||
// Sanitize the ids.
|
||||
$pks = (array) $pks;
|
||||
$pks = ArrayHelper::toInteger($pks);
|
||||
|
||||
try {
|
||||
$db = $this->getDatabase();
|
||||
$query = $db->getQuery(true)
|
||||
->update($db->quoteName('#__privacy_consents'))
|
||||
->set($db->quoteName('state') . ' = -1')
|
||||
->whereIn($db->quoteName('id'), $pks)
|
||||
->where($db->quoteName('state') . ' = 1');
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
} catch (ExecutionFailureException $e) {
|
||||
$this->setError($e->getMessage());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to invalidate a group of specific consents.
|
||||
*
|
||||
* @param array $subject The subject of the consents to invalidate.
|
||||
*
|
||||
* @return boolean True on success.
|
||||
*/
|
||||
public function invalidateAll($subject)
|
||||
{
|
||||
try {
|
||||
$db = $this->getDatabase();
|
||||
$query = $db->getQuery(true)
|
||||
->update($db->quoteName('#__privacy_consents'))
|
||||
->set($db->quoteName('state') . ' = -1')
|
||||
->where($db->quoteName('subject') . ' = :subject')
|
||||
->where($db->quoteName('state') . ' = 1')
|
||||
->bind(':subject', $subject);
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
} catch (ExecutionFailureException $e) {
|
||||
$this->setError($e->getMessage());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
335
administrator/components/com_privacy/src/Model/ExportModel.php
Normal file
335
administrator/components/com_privacy/src/Model/ExportModel.php
Normal file
@ -0,0 +1,335 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Privacy\Administrator\Model;
|
||||
|
||||
use Joomla\CMS\Component\ComponentHelper;
|
||||
use Joomla\CMS\Event\Privacy\ExportRequestEvent;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Language\Language;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Mail\MailTemplate;
|
||||
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
|
||||
use Joomla\CMS\Plugin\PluginHelper;
|
||||
use Joomla\CMS\Table\Table;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
use Joomla\CMS\User\UserFactoryAwareInterface;
|
||||
use Joomla\CMS\User\UserFactoryAwareTrait;
|
||||
use Joomla\Component\Actionlogs\Administrator\Model\ActionlogModel;
|
||||
use Joomla\Component\Privacy\Administrator\Export\Domain;
|
||||
use Joomla\Component\Privacy\Administrator\Helper\PrivacyHelper;
|
||||
use Joomla\Component\Privacy\Administrator\Table\RequestTable;
|
||||
use PHPMailer\PHPMailer\Exception as phpmailerException;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Export model class.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
class ExportModel extends BaseDatabaseModel implements UserFactoryAwareInterface
|
||||
{
|
||||
use UserFactoryAwareTrait;
|
||||
|
||||
/**
|
||||
* Create the export document for an information request.
|
||||
*
|
||||
* @param integer $id The request ID to process
|
||||
*
|
||||
* @return Domain[]|boolean A SimpleXMLElement object for a successful export or boolean false on an error
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function collectDataForExportRequest($id = null)
|
||||
{
|
||||
$id = !empty($id) ? $id : (int) $this->getState($this->getName() . '.request_id');
|
||||
|
||||
if (!$id) {
|
||||
$this->setError(Text::_('COM_PRIVACY_ERROR_REQUEST_ID_REQUIRED_FOR_EXPORT'));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @var RequestTable $table */
|
||||
$table = $this->getTable();
|
||||
|
||||
if (!$table->load($id)) {
|
||||
$this->setError($table->getError());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($table->request_type !== 'export') {
|
||||
$this->setError(Text::_('COM_PRIVACY_ERROR_REQUEST_TYPE_NOT_EXPORT'));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($table->status != 1) {
|
||||
$this->setError(Text::_('COM_PRIVACY_ERROR_CANNOT_EXPORT_UNCONFIRMED_REQUEST'));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// If there is a user account associated with the email address, load it here for use in the plugins
|
||||
$db = $this->getDatabase();
|
||||
|
||||
$userId = (int) $db->setQuery(
|
||||
$db->getQuery(true)
|
||||
->select($db->quoteName('id'))
|
||||
->from($db->quoteName('#__users'))
|
||||
->where('LOWER(' . $db->quoteName('email') . ') = LOWER(:email)')
|
||||
->bind(':email', $table->email)
|
||||
->setLimit(1)
|
||||
)->loadResult();
|
||||
|
||||
$user = $userId ? $this->getUserFactory()->loadUserById($userId) : null;
|
||||
|
||||
// Log the export
|
||||
$this->logExport($table);
|
||||
|
||||
$dispatcher = $this->getDispatcher();
|
||||
|
||||
PluginHelper::importPlugin('privacy', null, true, $dispatcher);
|
||||
|
||||
$pluginResults = $dispatcher->dispatch('onPrivacyExportRequest', new ExportRequestEvent('onPrivacyExportRequest', [
|
||||
'subject' => $table,
|
||||
'user' => $user,
|
||||
]))->getArgument('result', []);
|
||||
|
||||
$domains = [];
|
||||
|
||||
foreach ($pluginResults as $pluginDomains) {
|
||||
$domains = array_merge($domains, $pluginDomains);
|
||||
}
|
||||
|
||||
return $domains;
|
||||
}
|
||||
|
||||
/**
|
||||
* Email the data export to the user.
|
||||
*
|
||||
* @param integer $id The request ID to process
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function emailDataExport($id = null)
|
||||
{
|
||||
$id = !empty($id) ? $id : (int) $this->getState($this->getName() . '.request_id');
|
||||
|
||||
if (!$id) {
|
||||
$this->setError(Text::_('COM_PRIVACY_ERROR_REQUEST_ID_REQUIRED_FOR_EXPORT'));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$exportData = $this->collectDataForExportRequest($id);
|
||||
|
||||
if ($exportData === false) {
|
||||
// Error is already set, we just need to bail
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @var RequestTable $table */
|
||||
$table = $this->getTable();
|
||||
|
||||
if (!$table->load($id)) {
|
||||
$this->setError($table->getError());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($table->request_type !== 'export') {
|
||||
$this->setError(Text::_('COM_PRIVACY_ERROR_REQUEST_TYPE_NOT_EXPORT'));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($table->status != 1) {
|
||||
$this->setError(Text::_('COM_PRIVACY_ERROR_CANNOT_EXPORT_UNCONFIRMED_REQUEST'));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Log the email
|
||||
$this->logExportEmailed($table);
|
||||
|
||||
/*
|
||||
* If there is an associated user account, we will attempt to send this email in the user's preferred language.
|
||||
* Because of this, it is expected that Language::_() is directly called and that the Text class is NOT used
|
||||
* for translating all messages.
|
||||
*
|
||||
* Error messages will still be displayed to the administrator, so those messages should continue to use the Text class.
|
||||
*/
|
||||
|
||||
$lang = Factory::getLanguage();
|
||||
|
||||
$db = $this->getDatabase();
|
||||
|
||||
$userId = (int) $db->setQuery(
|
||||
$db->getQuery(true)
|
||||
->select($db->quoteName('id'))
|
||||
->from($db->quoteName('#__users'))
|
||||
->where('LOWER(' . $db->quoteName('email') . ') = LOWER(:email)')
|
||||
->bind(':email', $table->email),
|
||||
0,
|
||||
1
|
||||
)->loadResult();
|
||||
|
||||
if ($userId) {
|
||||
$receiver = $this->getUserFactory()->loadUserById($userId);
|
||||
|
||||
/*
|
||||
* We don't know if the user has admin access, so we will check if they have an admin language in their parameters,
|
||||
* falling back to the site language, falling back to the currently active language
|
||||
*/
|
||||
|
||||
$langCode = $receiver->getParam('admin_language', '');
|
||||
|
||||
if (!$langCode) {
|
||||
$langCode = $receiver->getParam('language', $lang->getTag());
|
||||
}
|
||||
|
||||
$lang = Language::getInstance($langCode, $lang->getDebug());
|
||||
}
|
||||
|
||||
// Ensure the right language files have been loaded
|
||||
$lang->load('com_privacy', JPATH_ADMINISTRATOR)
|
||||
|| $lang->load('com_privacy', JPATH_ADMINISTRATOR . '/components/com_privacy');
|
||||
|
||||
// The mailer can be set to either throw Exceptions or return boolean false, account for both
|
||||
try {
|
||||
$app = Factory::getApplication();
|
||||
$mailer = new MailTemplate('com_privacy.userdataexport', $app->getLanguage()->getTag());
|
||||
|
||||
$templateData = [
|
||||
'sitename' => $app->get('sitename'),
|
||||
'url' => Uri::root(),
|
||||
];
|
||||
|
||||
$mailer->addRecipient($table->email);
|
||||
$mailer->addTemplateData($templateData);
|
||||
$mailer->addAttachment('user-data_' . Uri::getInstance()->toString(['host']) . '.xml', PrivacyHelper::renderDataAsXml($exportData));
|
||||
|
||||
if ($mailer->send() === false) {
|
||||
$this->setError($mailer->ErrorInfo);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (phpmailerException $exception) {
|
||||
$this->setError($exception->getMessage());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get a table object, load it if necessary.
|
||||
*
|
||||
* @param string $name The table name. Optional.
|
||||
* @param string $prefix The class prefix. Optional.
|
||||
* @param array $options Configuration array for model. Optional.
|
||||
*
|
||||
* @return Table A Table object
|
||||
*
|
||||
* @throws \Exception
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function getTable($name = 'Request', $prefix = 'Administrator', $options = [])
|
||||
{
|
||||
return parent::getTable($name, $prefix, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the data export to the action log system.
|
||||
*
|
||||
* @param RequestTable $request The request record being processed
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function logExport(RequestTable $request)
|
||||
{
|
||||
$user = $this->getCurrentUser();
|
||||
|
||||
$message = [
|
||||
'action' => 'export',
|
||||
'id' => $request->id,
|
||||
'itemlink' => 'index.php?option=com_privacy&view=request&id=' . $request->id,
|
||||
'userid' => $user->id,
|
||||
'username' => $user->username,
|
||||
'accountlink' => 'index.php?option=com_users&task=user.edit&id=' . $user->id,
|
||||
];
|
||||
|
||||
$this->getActionlogModel()->addLog([$message], 'COM_PRIVACY_ACTION_LOG_EXPORT', 'com_privacy.request', $user->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the data export email to the action log system.
|
||||
*
|
||||
* @param RequestTable $request The request record being processed
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function logExportEmailed(RequestTable $request)
|
||||
{
|
||||
$user = $this->getCurrentUser();
|
||||
|
||||
$message = [
|
||||
'action' => 'export_emailed',
|
||||
'id' => $request->id,
|
||||
'itemlink' => 'index.php?option=com_privacy&view=request&id=' . $request->id,
|
||||
'userid' => $user->id,
|
||||
'username' => $user->username,
|
||||
'accountlink' => 'index.php?option=com_users&task=user.edit&id=' . $user->id,
|
||||
];
|
||||
|
||||
$this->getActionlogModel()->addLog([$message], 'COM_PRIVACY_ACTION_LOG_EXPORT_EMAILED', 'com_privacy.request', $user->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to auto-populate the model state.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected function populateState()
|
||||
{
|
||||
// Get the pk of the record from the request.
|
||||
$this->setState($this->getName() . '.request_id', Factory::getApplication()->getInput()->getUint('id'));
|
||||
|
||||
// Load the parameters.
|
||||
$this->setState('params', ComponentHelper::getParams('com_privacy'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to fetch an instance of the action log model.
|
||||
*
|
||||
* @return ActionlogModel
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
private function getActionlogModel(): ActionlogModel
|
||||
{
|
||||
return Factory::getApplication()->bootComponent('com_actionlogs')
|
||||
->getMVCFactory()->createModel('Actionlog', 'Administrator', ['ignore_request' => true]);
|
||||
}
|
||||
}
|
||||
227
administrator/components/com_privacy/src/Model/RemoveModel.php
Normal file
227
administrator/components/com_privacy/src/Model/RemoveModel.php
Normal file
@ -0,0 +1,227 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Privacy\Administrator\Model;
|
||||
|
||||
use Joomla\CMS\Component\ComponentHelper;
|
||||
use Joomla\CMS\Event\Privacy\CanRemoveDataEvent;
|
||||
use Joomla\CMS\Event\Privacy\RemoveDataEvent;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
|
||||
use Joomla\CMS\Plugin\PluginHelper;
|
||||
use Joomla\CMS\Table\Table;
|
||||
use Joomla\CMS\User\UserFactoryAwareInterface;
|
||||
use Joomla\CMS\User\UserFactoryAwareTrait;
|
||||
use Joomla\Component\Actionlogs\Administrator\Model\ActionlogModel;
|
||||
use Joomla\Component\Privacy\Administrator\Removal\Status;
|
||||
use Joomla\Component\Privacy\Administrator\Table\RequestTable;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Remove model class.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
class RemoveModel extends BaseDatabaseModel implements UserFactoryAwareInterface
|
||||
{
|
||||
use UserFactoryAwareTrait;
|
||||
|
||||
/**
|
||||
* Remove the user data.
|
||||
*
|
||||
* @param integer $id The request ID to process
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function removeDataForRequest($id = null)
|
||||
{
|
||||
$id = !empty($id) ? $id : (int) $this->getState($this->getName() . '.request_id');
|
||||
|
||||
if (!$id) {
|
||||
$this->setError(Text::_('COM_PRIVACY_ERROR_REQUEST_ID_REQUIRED_FOR_REMOVE'));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @var RequestTable $table */
|
||||
$table = $this->getTable();
|
||||
|
||||
if (!$table->load($id)) {
|
||||
$this->setError($table->getError());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($table->request_type !== 'remove') {
|
||||
$this->setError(Text::_('COM_PRIVACY_ERROR_REQUEST_TYPE_NOT_REMOVE'));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($table->status != 1) {
|
||||
$this->setError(Text::_('COM_PRIVACY_ERROR_CANNOT_REMOVE_UNCONFIRMED_REQUEST'));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// If there is a user account associated with the email address, load it here for use in the plugins
|
||||
$db = $this->getDatabase();
|
||||
|
||||
$userId = (int) $db->setQuery(
|
||||
$db->getQuery(true)
|
||||
->select($db->quoteName('id'))
|
||||
->from($db->quoteName('#__users'))
|
||||
->where('LOWER(' . $db->quoteName('email') . ') = LOWER(:email)')
|
||||
->bind(':email', $table->email)
|
||||
->setLimit(1)
|
||||
)->loadResult();
|
||||
|
||||
$user = $userId ? $this->getUserFactory()->loadUserById($userId) : null;
|
||||
|
||||
$canRemove = true;
|
||||
$dispatcher = $this->getDispatcher();
|
||||
|
||||
PluginHelper::importPlugin('privacy', null, true, $dispatcher);
|
||||
|
||||
/** @var Status[] $pluginResults */
|
||||
$pluginResults = $dispatcher->dispatch('onPrivacyCanRemoveData', new CanRemoveDataEvent('onPrivacyCanRemoveData', [
|
||||
'subject' => $table,
|
||||
'user' => $user,
|
||||
]))->getArgument('result', []);
|
||||
|
||||
foreach ($pluginResults as $status) {
|
||||
if (!$status->canRemove) {
|
||||
$this->setError($status->reason ?: Text::_('COM_PRIVACY_ERROR_CANNOT_REMOVE_DATA'));
|
||||
|
||||
$canRemove = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$canRemove) {
|
||||
$this->logRemoveBlocked($table, $this->getErrors());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Log the removal
|
||||
$this->logRemove($table);
|
||||
|
||||
$dispatcher->dispatch('onPrivacyRemoveData', new RemoveDataEvent('onPrivacyRemoveData', [
|
||||
'subject' => $table,
|
||||
'user' => $user,
|
||||
]));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get a table object, load it if necessary.
|
||||
*
|
||||
* @param string $name The table name. Optional.
|
||||
* @param string $prefix The class prefix. Optional.
|
||||
* @param array $options Configuration array for model. Optional.
|
||||
*
|
||||
* @return Table A Table object
|
||||
*
|
||||
* @throws \Exception
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function getTable($name = 'Request', $prefix = 'Administrator', $options = [])
|
||||
{
|
||||
return parent::getTable($name, $prefix, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the data removal to the action log system.
|
||||
*
|
||||
* @param RequestTable $request The request record being processed
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function logRemove(RequestTable $request)
|
||||
{
|
||||
$user = $this->getCurrentUser();
|
||||
|
||||
$message = [
|
||||
'action' => 'remove',
|
||||
'id' => $request->id,
|
||||
'itemlink' => 'index.php?option=com_privacy&view=request&id=' . $request->id,
|
||||
'userid' => $user->id,
|
||||
'username' => $user->username,
|
||||
'accountlink' => 'index.php?option=com_users&task=user.edit&id=' . $user->id,
|
||||
];
|
||||
|
||||
$this->getActionlogModel()->addLog([$message], 'COM_PRIVACY_ACTION_LOG_REMOVE', 'com_privacy.request', $user->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the data removal being blocked to the action log system.
|
||||
*
|
||||
* @param RequestTable $request The request record being processed
|
||||
* @param string[] $reasons The reasons given why the record could not be removed.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function logRemoveBlocked(RequestTable $request, array $reasons)
|
||||
{
|
||||
$user = $this->getCurrentUser();
|
||||
|
||||
$message = [
|
||||
'action' => 'remove-blocked',
|
||||
'id' => $request->id,
|
||||
'itemlink' => 'index.php?option=com_privacy&view=request&id=' . $request->id,
|
||||
'userid' => $user->id,
|
||||
'username' => $user->username,
|
||||
'accountlink' => 'index.php?option=com_users&task=user.edit&id=' . $user->id,
|
||||
'reasons' => implode('; ', $reasons),
|
||||
];
|
||||
|
||||
$this->getActionlogModel()->addLog([$message], 'COM_PRIVACY_ACTION_LOG_REMOVE_BLOCKED', 'com_privacy.request', $user->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to auto-populate the model state.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected function populateState()
|
||||
{
|
||||
// Get the pk of the record from the request.
|
||||
$this->setState($this->getName() . '.request_id', Factory::getApplication()->getInput()->getUint('id'));
|
||||
|
||||
// Load the parameters.
|
||||
$this->setState('params', ComponentHelper::getParams('com_privacy'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to fetch an instance of the action log model.
|
||||
*
|
||||
* @return ActionlogModel
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
private function getActionlogModel(): ActionlogModel
|
||||
{
|
||||
return Factory::getApplication()->bootComponent('com_actionlogs')
|
||||
->getMVCFactory()->createModel('Actionlog', 'Administrator', ['ignore_request' => true]);
|
||||
}
|
||||
}
|
||||
446
administrator/components/com_privacy/src/Model/RequestModel.php
Normal file
446
administrator/components/com_privacy/src/Model/RequestModel.php
Normal file
@ -0,0 +1,446 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Privacy\Administrator\Model;
|
||||
|
||||
use Joomla\CMS\Application\ApplicationHelper;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Form\Form;
|
||||
use Joomla\CMS\Language\Language;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Mail\Exception\MailDisabledException;
|
||||
use Joomla\CMS\Mail\MailTemplate;
|
||||
use Joomla\CMS\MVC\Model\AdminModel;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Table\Table;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
use Joomla\CMS\User\UserFactoryAwareInterface;
|
||||
use Joomla\CMS\User\UserFactoryAwareTrait;
|
||||
use Joomla\CMS\User\UserHelper;
|
||||
use Joomla\Component\Actionlogs\Administrator\Model\ActionlogModel;
|
||||
use Joomla\Component\Privacy\Administrator\Table\RequestTable;
|
||||
use Joomla\Database\Exception\ExecutionFailureException;
|
||||
use PHPMailer\PHPMailer\Exception as phpmailerException;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Request item model class.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
class RequestModel extends AdminModel implements UserFactoryAwareInterface
|
||||
{
|
||||
use UserFactoryAwareTrait;
|
||||
|
||||
/**
|
||||
* Clean the cache
|
||||
*
|
||||
* @param string $group The cache group
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected function cleanCache($group = 'com_privacy')
|
||||
{
|
||||
parent::cleanCache('com_privacy');
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for getting the form from the model.
|
||||
*
|
||||
* @param array $data Data for the form.
|
||||
* @param boolean $loadData True if the form is to load its own data (default case), false if not.
|
||||
*
|
||||
* @return Form|boolean A Form object on success, false on failure
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function getForm($data = [], $loadData = true)
|
||||
{
|
||||
// Get the form.
|
||||
$form = $this->loadForm('com_privacy.request', 'request', ['control' => 'jform', 'load_data' => $loadData]);
|
||||
|
||||
if (empty($form)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get a table object, load it if necessary.
|
||||
*
|
||||
* @param string $name The table name. Optional.
|
||||
* @param string $prefix The class prefix. Optional.
|
||||
* @param array $options Configuration array for model. Optional.
|
||||
*
|
||||
* @return Table A Table object
|
||||
*
|
||||
* @throws \Exception
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function getTable($name = 'Request', $prefix = 'Administrator', $options = [])
|
||||
{
|
||||
return parent::getTable($name, $prefix, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get the data that should be injected in the form.
|
||||
*
|
||||
* @return array The default data is an empty array.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected function loadFormData()
|
||||
{
|
||||
// Check the session for previously entered form data.
|
||||
$data = Factory::getApplication()->getUserState('com_privacy.edit.request.data', []);
|
||||
|
||||
if (empty($data)) {
|
||||
$data = $this->getItem();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the completion of a request to the action log system.
|
||||
*
|
||||
* @param integer $id The ID of the request to process.
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function logRequestCompleted($id)
|
||||
{
|
||||
/** @var RequestTable $table */
|
||||
$table = $this->getTable();
|
||||
|
||||
if (!$table->load($id)) {
|
||||
$this->setError($table->getError());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$user = $this->getCurrentUser();
|
||||
|
||||
$message = [
|
||||
'action' => 'request-completed',
|
||||
'requesttype' => $table->request_type,
|
||||
'subjectemail' => $table->email,
|
||||
'id' => $table->id,
|
||||
'itemlink' => 'index.php?option=com_privacy&view=request&id=' . $table->id,
|
||||
'userid' => $user->id,
|
||||
'username' => $user->username,
|
||||
'accountlink' => 'index.php?option=com_users&task=user.edit&id=' . $user->id,
|
||||
];
|
||||
|
||||
$this->getActionlogModel()->addLog([$message], 'COM_PRIVACY_ACTION_LOG_ADMIN_COMPLETED_REQUEST', 'com_privacy.request', $user->id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the creation of a request to the action log system.
|
||||
*
|
||||
* @param integer $id The ID of the request to process.
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function logRequestCreated($id)
|
||||
{
|
||||
/** @var RequestTable $table */
|
||||
$table = $this->getTable();
|
||||
|
||||
if (!$table->load($id)) {
|
||||
$this->setError($table->getError());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$user = $this->getCurrentUser();
|
||||
|
||||
$message = [
|
||||
'action' => 'request-created',
|
||||
'requesttype' => $table->request_type,
|
||||
'subjectemail' => $table->email,
|
||||
'id' => $table->id,
|
||||
'itemlink' => 'index.php?option=com_privacy&view=request&id=' . $table->id,
|
||||
'userid' => $user->id,
|
||||
'username' => $user->username,
|
||||
'accountlink' => 'index.php?option=com_users&task=user.edit&id=' . $user->id,
|
||||
];
|
||||
|
||||
$this->getActionlogModel()->addLog([$message], 'COM_PRIVACY_ACTION_LOG_ADMIN_CREATED_REQUEST', 'com_privacy.request', $user->id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the invalidation of a request to the action log system.
|
||||
*
|
||||
* @param integer $id The ID of the request to process.
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function logRequestInvalidated($id)
|
||||
{
|
||||
/** @var RequestTable $table */
|
||||
$table = $this->getTable();
|
||||
|
||||
if (!$table->load($id)) {
|
||||
$this->setError($table->getError());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$user = $this->getCurrentUser();
|
||||
|
||||
$message = [
|
||||
'action' => 'request-invalidated',
|
||||
'requesttype' => $table->request_type,
|
||||
'subjectemail' => $table->email,
|
||||
'id' => $table->id,
|
||||
'itemlink' => 'index.php?option=com_privacy&view=request&id=' . $table->id,
|
||||
'userid' => $user->id,
|
||||
'username' => $user->username,
|
||||
'accountlink' => 'index.php?option=com_users&task=user.edit&id=' . $user->id,
|
||||
];
|
||||
|
||||
$this->getActionlogModel()->addLog([$message], 'COM_PRIVACY_ACTION_LOG_ADMIN_INVALIDATED_REQUEST', 'com_privacy.request', $user->id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the user that an information request has been created by a site administrator.
|
||||
*
|
||||
* Because confirmation tokens are stored in the database as a hashed value, this method will generate a new confirmation token
|
||||
* for the request.
|
||||
*
|
||||
* @param integer $id The ID of the request to process.
|
||||
*
|
||||
* @return boolean
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function notifyUserAdminCreatedRequest($id)
|
||||
{
|
||||
/** @var RequestTable $table */
|
||||
$table = $this->getTable();
|
||||
|
||||
if (!$table->load($id)) {
|
||||
$this->setError($table->getError());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is an associated user account, we will attempt to send this email in the user's preferred language.
|
||||
* Because of this, it is expected that Language::_() is directly called and that the Text class is NOT used
|
||||
* for translating all messages.
|
||||
*
|
||||
* Error messages will still be displayed to the administrator, so those messages should continue to use the Text class.
|
||||
*/
|
||||
|
||||
$lang = Factory::getLanguage();
|
||||
|
||||
$db = $this->getDatabase();
|
||||
|
||||
$userId = (int) $db->setQuery(
|
||||
$db->getQuery(true)
|
||||
->select($db->quoteName('id'))
|
||||
->from($db->quoteName('#__users'))
|
||||
->where('LOWER(' . $db->quoteName('email') . ') = LOWER(:email)')
|
||||
->bind(':email', $table->email)
|
||||
->setLimit(1)
|
||||
)->loadResult();
|
||||
|
||||
if ($userId) {
|
||||
$receiver = $this->getUserFactory()->loadUserById($userId);
|
||||
|
||||
/*
|
||||
* We don't know if the user has admin access, so we will check if they have an admin language in their parameters,
|
||||
* falling back to the site language, falling back to the currently active language
|
||||
*/
|
||||
|
||||
$langCode = $receiver->getParam('admin_language', '');
|
||||
|
||||
if (!$langCode) {
|
||||
$langCode = $receiver->getParam('language', $lang->getTag());
|
||||
}
|
||||
|
||||
$lang = Language::getInstance($langCode, $lang->getDebug());
|
||||
}
|
||||
|
||||
// Ensure the right language files have been loaded
|
||||
$lang->load('com_privacy', JPATH_ADMINISTRATOR)
|
||||
|| $lang->load('com_privacy', JPATH_ADMINISTRATOR . '/components/com_privacy');
|
||||
|
||||
// Regenerate the confirmation token
|
||||
$token = ApplicationHelper::getHash(UserHelper::genRandomPassword());
|
||||
$hashedToken = UserHelper::hashPassword($token);
|
||||
|
||||
$table->confirm_token = $hashedToken;
|
||||
$table->confirm_token_created_at = Factory::getDate()->toSql();
|
||||
|
||||
try {
|
||||
$table->store();
|
||||
} catch (ExecutionFailureException $exception) {
|
||||
$this->setError($exception->getMessage());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// The mailer can be set to either throw Exceptions or return boolean false, account for both
|
||||
try {
|
||||
$app = Factory::getApplication();
|
||||
|
||||
$linkMode = $app->get('force_ssl', 0) == 2 ? Route::TLS_FORCE : Route::TLS_IGNORE;
|
||||
|
||||
$templateData = [
|
||||
'sitename' => $app->get('sitename'),
|
||||
'url' => Uri::root(),
|
||||
'tokenurl' => Route::link('site', 'index.php?option=com_privacy&view=confirm&confirm_token=' . $token, false, $linkMode, true),
|
||||
'formurl' => Route::link('site', 'index.php?option=com_privacy&view=confirm', false, $linkMode, true),
|
||||
'token' => $token,
|
||||
];
|
||||
|
||||
switch ($table->request_type) {
|
||||
case 'export':
|
||||
$mailer = new MailTemplate('com_privacy.notification.admin.export', $app->getLanguage()->getTag());
|
||||
|
||||
break;
|
||||
|
||||
case 'remove':
|
||||
$mailer = new MailTemplate('com_privacy.notification.admin.remove', $app->getLanguage()->getTag());
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->setError(Text::_('COM_PRIVACY_ERROR_UNKNOWN_REQUEST_TYPE'));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$mailer->addTemplateData($templateData);
|
||||
$mailer->addRecipient($table->email);
|
||||
|
||||
$mailer->send();
|
||||
|
||||
return true;
|
||||
} catch (MailDisabledException | phpmailerException $exception) {
|
||||
$this->setError($exception->getMessage());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to save the form data.
|
||||
*
|
||||
* @param array $data The form data.
|
||||
*
|
||||
* @return boolean True on success, False on error.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function save($data)
|
||||
{
|
||||
$table = $this->getTable();
|
||||
$key = $table->getKeyName();
|
||||
$pk = !empty($data[$key]) ? $data[$key] : (int) $this->getState($this->getName() . '.id');
|
||||
|
||||
if (!$pk && !Factory::getApplication()->get('mailonline', 1)) {
|
||||
$this->setError(Text::_('COM_PRIVACY_ERROR_CANNOT_CREATE_REQUEST_WHEN_SENDMAIL_DISABLED'));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return parent::save($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to validate the form data.
|
||||
*
|
||||
* @param Form $form The form to validate against.
|
||||
* @param array $data The data to validate.
|
||||
* @param string $group The name of the field group to validate.
|
||||
*
|
||||
* @return array|boolean Array of filtered data if valid, false otherwise.
|
||||
*
|
||||
* @see \Joomla\CMS\Form\FormRule
|
||||
* @see \Joomla\CMS\Filter\InputFilter
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function validate($form, $data, $group = null)
|
||||
{
|
||||
$validatedData = parent::validate($form, $data, $group);
|
||||
|
||||
// If parent validation failed there's no point in doing our extended validation
|
||||
if ($validatedData === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure the status is always 0
|
||||
$validatedData['status'] = 0;
|
||||
|
||||
// The user cannot create a request for their own account
|
||||
if (strtolower($this->getCurrentUser()->email) === strtolower($validatedData['email'])) {
|
||||
$this->setError(Text::_('COM_PRIVACY_ERROR_CANNOT_CREATE_REQUEST_FOR_SELF'));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for an active request for this email address
|
||||
$db = $this->getDatabase();
|
||||
|
||||
$query = $db->getQuery(true)
|
||||
->select('COUNT(id)')
|
||||
->from($db->quoteName('#__privacy_requests'))
|
||||
->where($db->quoteName('email') . ' = :email')
|
||||
->where($db->quoteName('request_type') . ' = :requesttype')
|
||||
->whereIn($db->quoteName('status'), [0, 1])
|
||||
->bind(':email', $validatedData['email'])
|
||||
->bind(':requesttype', $validatedData['request_type']);
|
||||
|
||||
$activeRequestCount = (int) $db->setQuery($query)->loadResult();
|
||||
|
||||
if ($activeRequestCount > 0) {
|
||||
$this->setError(Text::_('COM_PRIVACY_ERROR_ACTIVE_REQUEST_FOR_EMAIL'));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return $validatedData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to fetch an instance of the action log model.
|
||||
*
|
||||
* @return ActionlogModel
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
private function getActionlogModel(): ActionlogModel
|
||||
{
|
||||
return Factory::getApplication()->bootComponent('com_actionlogs')
|
||||
->getMVCFactory()->createModel('Actionlog', 'Administrator', ['ignore_request' => true]);
|
||||
}
|
||||
}
|
||||
181
administrator/components/com_privacy/src/Model/RequestsModel.php
Normal file
181
administrator/components/com_privacy/src/Model/RequestsModel.php
Normal file
@ -0,0 +1,181 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Privacy\Administrator\Model;
|
||||
|
||||
use Joomla\CMS\Component\ComponentHelper;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\MVC\Model\ListModel;
|
||||
use Joomla\Database\ParameterType;
|
||||
use Joomla\Database\QueryInterface;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Requests management model class.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
class RequestsModel extends ListModel
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $config An optional associative array of configuration settings.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function __construct($config = [])
|
||||
{
|
||||
if (empty($config['filter_fields'])) {
|
||||
$config['filter_fields'] = [
|
||||
'id', 'a.id',
|
||||
'email', 'a.email',
|
||||
'requested_at', 'a.requested_at',
|
||||
'request_type', 'a.request_type',
|
||||
'status', 'a.status',
|
||||
];
|
||||
}
|
||||
|
||||
parent::__construct($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get a QueryInterface object for retrieving the data set from a database.
|
||||
*
|
||||
* @return QueryInterface
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected function getListQuery()
|
||||
{
|
||||
// Create a new query object.
|
||||
$db = $this->getDatabase();
|
||||
$query = $db->getQuery(true);
|
||||
|
||||
// Select the required fields from the table.
|
||||
$query->select($this->getState('list.select', 'a.*'));
|
||||
$query->from($db->quoteName('#__privacy_requests', 'a'));
|
||||
|
||||
// Filter by status
|
||||
$status = $this->getState('filter.status');
|
||||
|
||||
if (is_numeric($status)) {
|
||||
$status = (int) $status;
|
||||
$query->where($db->quoteName('a.status') . ' = :status')
|
||||
->bind(':status', $status, ParameterType::INTEGER);
|
||||
}
|
||||
|
||||
// Filter by request type
|
||||
$requestType = $this->getState('filter.request_type', '');
|
||||
|
||||
if ($requestType) {
|
||||
$query->where($db->quoteName('a.request_type') . ' = :requesttype')
|
||||
->bind(':requesttype', $requestType);
|
||||
}
|
||||
|
||||
// Filter by search in email
|
||||
$search = $this->getState('filter.search');
|
||||
|
||||
if (!empty($search)) {
|
||||
if (stripos($search, 'id:') === 0) {
|
||||
$ids = (int) substr($search, 3);
|
||||
$query->where($db->quoteName('a.id') . ' = :id')
|
||||
->bind(':id', $ids, ParameterType::INTEGER);
|
||||
} else {
|
||||
$search = '%' . $search . '%';
|
||||
$query->where('(' . $db->quoteName('a.email') . ' LIKE :search)')
|
||||
->bind(':search', $search);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the list ordering.
|
||||
$ordering = $this->getState('list.ordering');
|
||||
$direction = $this->getState('list.direction');
|
||||
|
||||
if (!empty($ordering)) {
|
||||
$query->order($db->escape($ordering) . ' ' . $db->escape($direction));
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get a store id based on model configuration state.
|
||||
*
|
||||
* This is necessary because the model is used by the component and
|
||||
* different modules that might need different sets of data or different
|
||||
* ordering requirements.
|
||||
*
|
||||
* @param string $id A prefix for the store id.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected function getStoreId($id = '')
|
||||
{
|
||||
// Compile the store id.
|
||||
$id .= ':' . $this->getState('filter.search');
|
||||
$id .= ':' . $this->getState('filter.status');
|
||||
$id .= ':' . $this->getState('filter.request_type');
|
||||
|
||||
return parent::getStoreId($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to auto-populate the model state.
|
||||
*
|
||||
* Note. Calling getState in this method will result in recursion.
|
||||
*
|
||||
* @param string $ordering An optional ordering field.
|
||||
* @param string $direction An optional direction (asc|desc).
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected function populateState($ordering = 'a.id', $direction = 'desc')
|
||||
{
|
||||
// Load the parameters.
|
||||
$this->setState('params', ComponentHelper::getParams('com_privacy'));
|
||||
|
||||
// List state information.
|
||||
parent::populateState($ordering, $direction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to return number privacy requests older than X days.
|
||||
*
|
||||
* @return integer
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function getNumberUrgentRequests()
|
||||
{
|
||||
// Load the parameters.
|
||||
$params = ComponentHelper::getComponent('com_privacy')->getParams();
|
||||
$notify = (int) $params->get('notify', 14);
|
||||
$now = Factory::getDate()->toSql();
|
||||
$period = '-' . $notify;
|
||||
|
||||
$db = $this->getDatabase();
|
||||
$query = $db->getQuery(true)
|
||||
->select('COUNT(*)');
|
||||
$query->from($db->quoteName('#__privacy_requests'));
|
||||
$query->where($db->quoteName('status') . ' = 1 ');
|
||||
$query->where($query->dateAdd($db->quote($now), $period, 'DAY') . ' > ' . $db->quoteName('requested_at'));
|
||||
$db->setQuery($query);
|
||||
|
||||
return (int) $db->loadResult();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Privacy\Administrator\Plugin;
|
||||
|
||||
use Joomla\CMS\Plugin\CMSPlugin;
|
||||
use Joomla\CMS\Table\Table;
|
||||
use Joomla\Component\Fields\Administrator\Helper\FieldsHelper;
|
||||
use Joomla\Component\Privacy\Administrator\Export\Domain;
|
||||
use Joomla\Component\Privacy\Administrator\Export\Field;
|
||||
use Joomla\Component\Privacy\Administrator\Export\Item;
|
||||
use Joomla\Database\DatabaseAwareTrait;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Base class for privacy plugins
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
abstract class PrivacyPlugin extends CMSPlugin
|
||||
{
|
||||
use DatabaseAwareTrait;
|
||||
|
||||
/**
|
||||
* Database object
|
||||
*
|
||||
* @var \Joomla\Database\DatabaseDriver
|
||||
* @since 3.9.0
|
||||
* @deprecated 4.4.0 will be removed in 6.0 use $this->getDatabase() instead
|
||||
*/
|
||||
protected $db;
|
||||
|
||||
/**
|
||||
* Affects constructor behaviour. If true, language files will be loaded automatically.
|
||||
*
|
||||
* @var boolean
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected $autoloadLanguage = true;
|
||||
|
||||
/**
|
||||
* Create a new domain object
|
||||
*
|
||||
* @param string $name The domain's name
|
||||
* @param string $description The domain's description
|
||||
*
|
||||
* @return Domain
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected function createDomain($name, $description = '')
|
||||
{
|
||||
$domain = new Domain();
|
||||
$domain->name = $name;
|
||||
$domain->description = $description;
|
||||
|
||||
return $domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an item object for an array
|
||||
*
|
||||
* @param array $data The array data to convert
|
||||
* @param integer|null $itemId The ID of this item
|
||||
*
|
||||
* @return Item
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected function createItemFromArray(array $data, $itemId = null)
|
||||
{
|
||||
$item = new Item();
|
||||
$item->id = $itemId;
|
||||
|
||||
foreach ($data as $key => $value) {
|
||||
if (\is_object($value)) {
|
||||
$value = (array) $value;
|
||||
}
|
||||
|
||||
if (\is_array($value)) {
|
||||
$value = print_r($value, true);
|
||||
}
|
||||
|
||||
$field = new Field();
|
||||
$field->name = $key;
|
||||
$field->value = $value;
|
||||
|
||||
$item->addField($field);
|
||||
}
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an item object for a Table object
|
||||
*
|
||||
* @param Table $table The Table object to convert
|
||||
*
|
||||
* @return Item
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected function createItemForTable($table)
|
||||
{
|
||||
$data = [];
|
||||
|
||||
foreach (array_keys($table->getFields()) as $fieldName) {
|
||||
$data[$fieldName] = $table->$fieldName;
|
||||
}
|
||||
|
||||
return $this->createItemFromArray($data, $table->{$table->getKeyName(false)});
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to create the domain for the items custom fields.
|
||||
*
|
||||
* @param string $context The context
|
||||
* @param array $items The items
|
||||
*
|
||||
* @return Domain
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected function createCustomFieldsDomain($context, $items = [])
|
||||
{
|
||||
if (!\is_array($items)) {
|
||||
$items = [$items];
|
||||
}
|
||||
|
||||
$parts = FieldsHelper::extract($context);
|
||||
|
||||
if (!$parts) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$type = str_replace('com_', '', $parts[0]);
|
||||
|
||||
$domain = $this->createDomain($type . '_' . $parts[1] . '_custom_fields', 'joomla_' . $type . '_' . $parts[1] . '_custom_fields_data');
|
||||
|
||||
foreach ($items as $item) {
|
||||
// Get item's fields, also preparing their value property for manual display
|
||||
$fields = FieldsHelper::getFields($parts[0] . '.' . $parts[1], $item);
|
||||
|
||||
foreach ($fields as $field) {
|
||||
$fieldValue = \is_array($field->value) ? implode(', ', $field->value) : $field->value;
|
||||
|
||||
$data = [
|
||||
$type . '_id' => $item->id,
|
||||
'field_name' => $field->name,
|
||||
'field_title' => $field->title,
|
||||
'field_value' => $fieldValue,
|
||||
];
|
||||
|
||||
$domain->addItem($this->createItemFromArray($data));
|
||||
}
|
||||
}
|
||||
|
||||
return $domain;
|
||||
}
|
||||
}
|
||||
41
administrator/components/com_privacy/src/Removal/Status.php
Normal file
41
administrator/components/com_privacy/src/Removal/Status.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Privacy\Administrator\Removal;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Data object communicating the status of whether the data for an information request can be removed.
|
||||
*
|
||||
* Typically, this object will only be used to communicate data will be removed.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
class Status
|
||||
{
|
||||
/**
|
||||
* Flag indicating the status reported by the plugin on whether the information can be removed
|
||||
*
|
||||
* @var boolean
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public $canRemove = true;
|
||||
|
||||
/**
|
||||
* A status message indicating the reason data can or cannot be removed
|
||||
*
|
||||
* @var string
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public $reason;
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Privacy\Administrator\Service\HTML;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Privacy component HTML helper.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
class Privacy
|
||||
{
|
||||
/**
|
||||
* Render a status badge
|
||||
*
|
||||
* @param integer $status The item status
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function statusLabel($status)
|
||||
{
|
||||
switch ($status) {
|
||||
case 2:
|
||||
return '<span class="badge bg-success">' . Text::_('COM_PRIVACY_STATUS_COMPLETED') . '</span>';
|
||||
|
||||
case 1:
|
||||
return '<span class="badge bg-info">' . Text::_('COM_PRIVACY_STATUS_CONFIRMED') . '</span>';
|
||||
|
||||
case -1:
|
||||
return '<span class="badge bg-danger">' . Text::_('COM_PRIVACY_STATUS_INVALID') . '</span>';
|
||||
|
||||
default:
|
||||
case 0:
|
||||
return '<span class="badge bg-warning">' . Text::_('COM_PRIVACY_STATUS_PENDING') . '</span>';
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Privacy\Administrator\Table;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Table\Table;
|
||||
use Joomla\Database\DatabaseDriver;
|
||||
use Joomla\Event\DispatcherInterface;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Table interface class for the #__privacy_consents table
|
||||
*
|
||||
* @property integer $id Item ID (primary key)
|
||||
* @property integer $remind The status of the reminder request
|
||||
* @property string $token Hashed token for the reminder request
|
||||
* @property integer $user_id User ID (pseudo foreign key to the #__users table) if the request is associated to a user account
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
class ConsentTable extends Table
|
||||
{
|
||||
/**
|
||||
* The class constructor.
|
||||
*
|
||||
* @param DatabaseDriver $db Database connector object
|
||||
* @param ?DispatcherInterface $dispatcher Event dispatcher for this table
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function __construct(DatabaseDriver $db, ?DispatcherInterface $dispatcher = null)
|
||||
{
|
||||
parent::__construct('#__privacy_consents', 'id', $db, $dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to store a row in the database from the Table instance properties.
|
||||
*
|
||||
* @param boolean $updateNulls True to update fields even if they are null.
|
||||
*
|
||||
* @return boolean True on success.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function store($updateNulls = false)
|
||||
{
|
||||
$date = Factory::getDate();
|
||||
|
||||
// Set default values for new records
|
||||
if (!$this->id) {
|
||||
if (!$this->remind) {
|
||||
$this->remind = '0';
|
||||
}
|
||||
|
||||
if (!$this->created) {
|
||||
$this->created = $date->toSql();
|
||||
}
|
||||
}
|
||||
|
||||
return parent::store($updateNulls);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Privacy\Administrator\Table;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Table\Table;
|
||||
use Joomla\Database\DatabaseDriver;
|
||||
use Joomla\Event\DispatcherInterface;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Table interface class for the #__privacy_requests table
|
||||
*
|
||||
* @property integer $id Item ID (primary key)
|
||||
* @property string $email The email address of the individual requesting the data
|
||||
* @property string $requested_at The time the request was created at
|
||||
* @property integer $status The status of the information request
|
||||
* @property string $request_type The type of information request
|
||||
* @property string $confirm_token Hashed token for confirming the information request
|
||||
* @property string $confirm_token_created_at The time the confirmation token was generated
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
class RequestTable extends Table
|
||||
{
|
||||
/**
|
||||
* Indicates that columns fully support the NULL value in the database
|
||||
*
|
||||
* @var boolean
|
||||
* @since 4.0.0
|
||||
*/
|
||||
protected $_supportNullValue = true;
|
||||
|
||||
/**
|
||||
* The class constructor.
|
||||
*
|
||||
* @param DatabaseDriver $db Database connector object
|
||||
* @param ?DispatcherInterface $dispatcher Event dispatcher for this table
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function __construct(DatabaseDriver $db, ?DispatcherInterface $dispatcher = null)
|
||||
{
|
||||
parent::__construct('#__privacy_requests', 'id', $db, $dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to store a row in the database from the Table instance properties.
|
||||
*
|
||||
* @param boolean $updateNulls True to update fields even if they are null.
|
||||
*
|
||||
* @return boolean True on success.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function store($updateNulls = true)
|
||||
{
|
||||
$date = Factory::getDate();
|
||||
|
||||
// Set default values for new records
|
||||
if (!$this->id) {
|
||||
if (!$this->status) {
|
||||
$this->status = '0';
|
||||
}
|
||||
|
||||
if (!$this->requested_at) {
|
||||
$this->requested_at = $date->toSql();
|
||||
}
|
||||
|
||||
if (!$this->confirm_token_created_at) {
|
||||
$this->confirm_token_created_at = null;
|
||||
}
|
||||
}
|
||||
|
||||
return parent::store($updateNulls);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Privacy\Administrator\View\Capabilities;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\MVC\View\GenericDataException;
|
||||
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
|
||||
use Joomla\CMS\Toolbar\ToolbarHelper;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Capabilities view class
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
class HtmlView extends BaseHtmlView
|
||||
{
|
||||
/**
|
||||
* The reported extension capabilities
|
||||
*
|
||||
* @var array
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected $capabilities;
|
||||
|
||||
/**
|
||||
* The state information
|
||||
*
|
||||
* @var \Joomla\Registry\Registry
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* Execute and display a template script.
|
||||
*
|
||||
* @param string $tpl The name of the template file to parse; automatically searches through the template paths.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @see BaseHtmlView::loadTemplate()
|
||||
* @since 3.9.0
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function display($tpl = null)
|
||||
{
|
||||
// Initialise variables
|
||||
$this->capabilities = $this->get('Capabilities');
|
||||
$this->state = $this->get('State');
|
||||
|
||||
// Check for errors.
|
||||
if (\count($errors = $this->get('Errors'))) {
|
||||
throw new Genericdataexception(implode("\n", $errors), 500);
|
||||
}
|
||||
|
||||
$this->addToolbar();
|
||||
|
||||
parent::display($tpl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the page title and toolbar.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected function addToolbar()
|
||||
{
|
||||
$toolbar = $this->getDocument()->getToolbar();
|
||||
|
||||
ToolbarHelper::title(Text::_('COM_PRIVACY_VIEW_CAPABILITIES'), 'lock');
|
||||
|
||||
$toolbar->preferences('com_privacy');
|
||||
$toolbar->help('Privacy:_Extension_Capabilities');
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Privacy\Administrator\View\Consents;
|
||||
|
||||
use Joomla\CMS\Form\Form;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\MVC\View\GenericDataException;
|
||||
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
|
||||
use Joomla\CMS\Pagination\Pagination;
|
||||
use Joomla\CMS\Toolbar\ToolbarHelper;
|
||||
use Joomla\Component\Privacy\Administrator\Model\ConsentsModel;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Consents view class
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
class HtmlView extends BaseHtmlView
|
||||
{
|
||||
/**
|
||||
* The active search tools filters
|
||||
*
|
||||
* @var array
|
||||
* @since 3.9.0
|
||||
* @note Must be public to be accessed from the search tools layout
|
||||
*/
|
||||
public $activeFilters;
|
||||
|
||||
/**
|
||||
* Form instance containing the search tools filter form
|
||||
*
|
||||
* @var Form
|
||||
* @since 3.9.0
|
||||
* @note Must be public to be accessed from the search tools layout
|
||||
*/
|
||||
public $filterForm;
|
||||
|
||||
/**
|
||||
* The items to display
|
||||
*
|
||||
* @var array
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected $items;
|
||||
|
||||
/**
|
||||
* The pagination object
|
||||
*
|
||||
* @var Pagination
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected $pagination;
|
||||
|
||||
/**
|
||||
* The state information
|
||||
*
|
||||
* @var \Joomla\Registry\Registry
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* Is this view an Empty State
|
||||
*
|
||||
* @var boolean
|
||||
* @since 4.0.0
|
||||
*/
|
||||
private $isEmptyState = false;
|
||||
|
||||
/**
|
||||
* Execute and display a template script.
|
||||
*
|
||||
* @param string $tpl The name of the template file to parse; automatically searches through the template paths.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @see BaseHtmlView::loadTemplate()
|
||||
* @since 3.9.0
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function display($tpl = null)
|
||||
{
|
||||
/** @var ConsentsModel $model */
|
||||
$model = $this->getModel();
|
||||
$this->items = $model->getItems();
|
||||
$this->pagination = $model->getPagination();
|
||||
$this->state = $model->getState();
|
||||
$this->filterForm = $model->getFilterForm();
|
||||
$this->activeFilters = $model->getActiveFilters();
|
||||
|
||||
if (!\count($this->items) && $this->isEmptyState = $this->get('IsEmptyState')) {
|
||||
$this->setLayout('emptystate');
|
||||
}
|
||||
|
||||
// Check for errors.
|
||||
if (\count($errors = $this->get('Errors'))) {
|
||||
throw new Genericdataexception(implode("\n", $errors), 500);
|
||||
}
|
||||
|
||||
$this->addToolbar();
|
||||
|
||||
parent::display($tpl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the page title and toolbar.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected function addToolbar()
|
||||
{
|
||||
ToolbarHelper::title(Text::_('COM_PRIVACY_VIEW_CONSENTS'), 'lock');
|
||||
|
||||
$toolbar = $this->getDocument()->getToolbar();
|
||||
|
||||
// Add a button to invalidate a consent
|
||||
if (!$this->isEmptyState) {
|
||||
$toolbar->confirmButton('trash', 'COM_PRIVACY_CONSENTS_TOOLBAR_INVALIDATE', 'consents.invalidate')
|
||||
->message('COM_PRIVACY_CONSENTS_TOOLBAR_INVALIDATE')
|
||||
->icon('icon-trash')
|
||||
->listCheck(true);
|
||||
}
|
||||
|
||||
// If the filter is restricted to a specific subject, show the "Invalidate all" button
|
||||
if ($this->state->get('filter.subject') != '') {
|
||||
$toolbar->confirmButton('cancel', 'COM_PRIVACY_CONSENTS_TOOLBAR_INVALIDATE_ALL', 'consents.invalidateAll')
|
||||
->message('COM_PRIVACY_CONSENTS_TOOLBAR_INVALIDATE_ALL_CONFIRM_MSG')
|
||||
->icon('icon-cancel')
|
||||
->listCheck(false);
|
||||
}
|
||||
|
||||
$toolbar->preferences('com_privacy');
|
||||
$toolbar->help('Privacy:_Consents');
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Privacy\Administrator\View\Export;
|
||||
|
||||
use Joomla\CMS\MVC\View\AbstractView;
|
||||
use Joomla\CMS\MVC\View\GenericDataException;
|
||||
use Joomla\Component\Privacy\Administrator\Helper\PrivacyHelper;
|
||||
use Joomla\Component\Privacy\Administrator\Model\ExportModel;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Export view class
|
||||
*
|
||||
* @since 3.9.0
|
||||
*
|
||||
* @property-read \Joomla\CMS\Document\XmlDocument $document
|
||||
*/
|
||||
class XmlView extends AbstractView
|
||||
{
|
||||
/**
|
||||
* Execute and display a template script.
|
||||
*
|
||||
* @param string $tpl The name of the template file to parse; automatically searches through the template paths.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.9.0
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function display($tpl = null)
|
||||
{
|
||||
/** @var ExportModel $model */
|
||||
$model = $this->getModel();
|
||||
|
||||
$exportData = $model->collectDataForExportRequest();
|
||||
|
||||
// Check for errors.
|
||||
if (\count($errors = $this->get('Errors'))) {
|
||||
throw new GenericDataException(implode("\n", $errors), 500);
|
||||
}
|
||||
|
||||
$requestId = $model->getState($model->getName() . '.request_id');
|
||||
|
||||
// This document should always be downloaded
|
||||
$this->getDocument()->setDownload(true);
|
||||
$this->getDocument()->setName('export-request-' . $requestId);
|
||||
|
||||
echo PrivacyHelper::renderDataAsXml($exportData);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,183 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Privacy\Administrator\View\Request;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Form\Form;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\MVC\View\GenericDataException;
|
||||
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Session\Session;
|
||||
use Joomla\CMS\Toolbar\ToolbarHelper;
|
||||
use Joomla\Component\Privacy\Administrator\Model\RequestModel;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Request view class
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
class HtmlView extends BaseHtmlView
|
||||
{
|
||||
/**
|
||||
* The action logs for the item
|
||||
*
|
||||
* @var array
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected $actionlogs;
|
||||
|
||||
/**
|
||||
* The form object
|
||||
*
|
||||
* @var Form
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected $form;
|
||||
|
||||
/**
|
||||
* The item record
|
||||
*
|
||||
* @var \stdClass
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected $item;
|
||||
|
||||
/**
|
||||
* The state information
|
||||
*
|
||||
* @var \Joomla\Registry\Registry
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* Execute and display a template script.
|
||||
*
|
||||
* @param string $tpl The name of the template file to parse; automatically searches through the template paths.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @see BaseHtmlView::loadTemplate()
|
||||
* @since 3.9.0
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function display($tpl = null)
|
||||
{
|
||||
/** @var RequestModel $model */
|
||||
$model = $this->getModel();
|
||||
$this->item = $model->getItem();
|
||||
$this->state = $model->getState();
|
||||
|
||||
// Variables only required for the default layout
|
||||
if ($this->getLayout() === 'default') {
|
||||
/** @var \Joomla\Component\Actionlogs\Administrator\Model\ActionlogsModel $logsModel */
|
||||
$logsModel = $this->getModel('actionlogs');
|
||||
|
||||
$this->actionlogs = $logsModel->getLogsForItem('com_privacy.request', $this->item->id);
|
||||
|
||||
// Load the com_actionlogs language strings for use in the layout
|
||||
$lang = $this->getLanguage();
|
||||
$lang->load('com_actionlogs', JPATH_ADMINISTRATOR)
|
||||
|| $lang->load('com_actionlogs', JPATH_ADMINISTRATOR . '/components/com_actionlogs');
|
||||
}
|
||||
|
||||
// Variables only required for the edit layout
|
||||
if ($this->getLayout() === 'edit') {
|
||||
$this->form = $this->get('Form');
|
||||
}
|
||||
|
||||
// Check for errors.
|
||||
if (\count($errors = $this->get('Errors'))) {
|
||||
throw new GenericDataException(implode("\n", $errors), 500);
|
||||
}
|
||||
|
||||
$this->addToolbar();
|
||||
|
||||
parent::display($tpl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the page title and toolbar.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected function addToolbar()
|
||||
{
|
||||
Factory::getApplication()->getInput()->set('hidemainmenu', true);
|
||||
|
||||
$toolbar = $this->getDocument()->getToolbar();
|
||||
|
||||
// Set the title and toolbar based on the layout
|
||||
if ($this->getLayout() === 'edit') {
|
||||
ToolbarHelper::title(Text::_('COM_PRIVACY_VIEW_REQUEST_ADD_REQUEST'), 'lock');
|
||||
|
||||
$toolbar->save('request.save');
|
||||
$toolbar->cancel('request.cancel');
|
||||
$toolbar->help('Privacy:_New_Information_Request');
|
||||
} else {
|
||||
ToolbarHelper::title(Text::_('COM_PRIVACY_VIEW_REQUEST_SHOW_REQUEST'), 'lock');
|
||||
|
||||
// Add transition and action buttons based on item status
|
||||
switch ($this->item->status) {
|
||||
case '0':
|
||||
$toolbar->standardButton('cancel', 'COM_PRIVACY_TOOLBAR_INVALIDATE', 'request.invalidate')
|
||||
->listCheck(false)
|
||||
->icon('icon-cancel-circle');
|
||||
|
||||
break;
|
||||
|
||||
case '1':
|
||||
$return = '&return=' . base64_encode('index.php?option=com_privacy&view=request&id=' . (int) $this->item->id);
|
||||
|
||||
$toolbar->standardButton('apply', 'COM_PRIVACY_TOOLBAR_COMPLETE', 'request.complete')
|
||||
->listCheck(false)
|
||||
->icon('icon-apply');
|
||||
|
||||
$toolbar->standardButton('invalidate', 'COM_PRIVACY_TOOLBAR_INVALIDATE', 'request.invalidate')
|
||||
->listCheck(false)
|
||||
->icon('icon-cancel-circle');
|
||||
|
||||
if ($this->item->request_type === 'export') {
|
||||
$toolbar->linkButton('download', 'COM_PRIVACY_ACTION_EXPORT_DATA')
|
||||
->url(Route::_('index.php?option=com_privacy&task=request.export&format=xml&id=' . (int) $this->item->id . $return));
|
||||
|
||||
if (Factory::getApplication()->get('mailonline', 1)) {
|
||||
$toolbar->linkButton('mail', 'COM_PRIVACY_ACTION_EMAIL_EXPORT_DATA')
|
||||
->url(Route::_('index.php?option=com_privacy&task=request.emailexport&id=' . (int) $this->item->id . $return
|
||||
. '&' . Session::getFormToken() . '=1'));
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->item->request_type === 'remove') {
|
||||
$toolbar->standardButton('delete', 'COM_PRIVACY_ACTION_DELETE_DATA', 'request.remove')
|
||||
->listCheck(false)
|
||||
->icon('icon-delete');
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
// Item is in a "locked" state and cannot transition
|
||||
break;
|
||||
}
|
||||
|
||||
$toolbar->cancel('request.cancel');
|
||||
$toolbar->help('Privacy:_Review_Information_Request');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Component\Privacy\Administrator\View\Requests;
|
||||
|
||||
use Joomla\CMS\Component\ComponentHelper;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Form\Form;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\MVC\View\GenericDataException;
|
||||
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
|
||||
use Joomla\CMS\Pagination\Pagination;
|
||||
use Joomla\CMS\Toolbar\ToolbarHelper;
|
||||
use Joomla\Component\Privacy\Administrator\Model\RequestsModel;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Requests view class
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
class HtmlView extends BaseHtmlView
|
||||
{
|
||||
/**
|
||||
* The active search tools filters
|
||||
*
|
||||
* @var array
|
||||
* @since 3.9.0
|
||||
* @note Must be public to be accessed from the search tools layout
|
||||
*/
|
||||
public $activeFilters;
|
||||
|
||||
/**
|
||||
* Form instance containing the search tools filter form
|
||||
*
|
||||
* @var Form
|
||||
* @since 3.9.0
|
||||
* @note Must be public to be accessed from the search tools layout
|
||||
*/
|
||||
public $filterForm;
|
||||
|
||||
/**
|
||||
* The items to display
|
||||
*
|
||||
* @var array
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected $items;
|
||||
|
||||
/**
|
||||
* The pagination object
|
||||
*
|
||||
* @var Pagination
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected $pagination;
|
||||
|
||||
/**
|
||||
* Flag indicating the site supports sending email
|
||||
*
|
||||
* @var boolean
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected $sendMailEnabled;
|
||||
|
||||
/**
|
||||
* The state information
|
||||
*
|
||||
* @var \Joomla\Registry\Registry
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* The age of urgent requests
|
||||
*
|
||||
* @var integer
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected $urgentRequestAge;
|
||||
|
||||
/**
|
||||
* Execute and display a template script.
|
||||
*
|
||||
* @param string $tpl The name of the template file to parse; automatically searches through the template paths.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @see BaseHtmlView::loadTemplate()
|
||||
* @since 3.9.0
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function display($tpl = null)
|
||||
{
|
||||
/** @var RequestsModel $model */
|
||||
$model = $this->getModel();
|
||||
$this->items = $model->getItems();
|
||||
$this->pagination = $model->getPagination();
|
||||
$this->state = $model->getState();
|
||||
$this->filterForm = $model->getFilterForm();
|
||||
$this->activeFilters = $model->getActiveFilters();
|
||||
$this->urgentRequestAge = (int) ComponentHelper::getParams('com_privacy')->get('notify', 14);
|
||||
$this->sendMailEnabled = (bool) Factory::getApplication()->get('mailonline', 1);
|
||||
|
||||
if (!\count($this->items) && $this->get('IsEmptyState')) {
|
||||
$this->setLayout('emptystate');
|
||||
}
|
||||
|
||||
// Check for errors.
|
||||
if (\count($errors = $this->get('Errors'))) {
|
||||
throw new Genericdataexception(implode("\n", $errors), 500);
|
||||
}
|
||||
|
||||
$this->addToolbar();
|
||||
|
||||
parent::display($tpl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the page title and toolbar.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
protected function addToolbar()
|
||||
{
|
||||
ToolbarHelper::title(Text::_('COM_PRIVACY_VIEW_REQUESTS'), 'lock');
|
||||
|
||||
$toolbar = $this->getDocument()->getToolbar();
|
||||
|
||||
// Requests can only be created if mail sending is enabled
|
||||
if (Factory::getApplication()->get('mailonline', 1)) {
|
||||
$toolbar->addNew('request.add');
|
||||
}
|
||||
|
||||
$toolbar->preferences('com_privacy');
|
||||
$toolbar->help('Privacy:_Information_Requests');
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
/** @var \Joomla\Component\Privacy\Administrator\View\Capabilities\HtmlView $this */
|
||||
|
||||
?>
|
||||
<div id="j-main-container" class="main-card p-4">
|
||||
<div class="alert alert-info">
|
||||
<h2 class="alert-heading"><?php echo Text::_('COM_PRIVACY_MSG_CAPABILITIES_ABOUT_THIS_INFORMATION'); ?></h2>
|
||||
<?php echo Text::_('COM_PRIVACY_MSG_CAPABILITIES_INTRODUCTION'); ?>
|
||||
</div>
|
||||
<?php if (empty($this->capabilities)) : ?>
|
||||
<div class="alert alert-info">
|
||||
<span class="icon-info-circle" aria-hidden="true"></span><span class="visually-hidden"><?php echo Text::_('INFO'); ?></span>
|
||||
<?php echo Text::_('COM_PRIVACY_MSG_CAPABILITIES_NO_CAPABILITIES'); ?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<?php foreach ($this->capabilities as $extension => $capabilities) : ?>
|
||||
<details>
|
||||
<summary><?php echo $extension; ?></summary>
|
||||
<?php if (empty($capabilities)) : ?>
|
||||
<div class="alert alert-info">
|
||||
<span class="icon-info-circle" aria-hidden="true"></span><span class="visually-hidden"><?php echo Text::_('INFO'); ?></span>
|
||||
<?php echo Text::_('COM_PRIVACY_MSG_EXTENSION_NO_CAPABILITIES'); ?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<ul>
|
||||
<?php foreach ($capabilities as $capability) : ?>
|
||||
<li><?php echo $capability; ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
</details>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
130
administrator/components/com_privacy/tmpl/consents/default.php
Normal file
130
administrator/components/com_privacy/tmpl/consents/default.php
Normal file
@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Date\Date;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Layout\LayoutHelper;
|
||||
use Joomla\CMS\Router\Route;
|
||||
|
||||
/** @var \Joomla\Component\Privacy\Administrator\View\Consents\HtmlView $this */
|
||||
|
||||
/** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */
|
||||
$wa = $this->getDocument()->getWebAssetManager();
|
||||
$wa->useScript('table.columns')
|
||||
->useScript('multiselect');
|
||||
|
||||
$user = $this->getCurrentUser();
|
||||
$listOrder = $this->escape($this->state->get('list.ordering'));
|
||||
$listDirn = $this->escape($this->state->get('list.direction'));
|
||||
$now = Factory::getDate();
|
||||
$stateIcons = [-1 => 'delete', 0 => 'archive', 1 => 'publish'];
|
||||
$stateMsgs = [
|
||||
-1 => Text::_('COM_PRIVACY_CONSENTS_STATE_INVALIDATED'),
|
||||
0 => Text::_('COM_PRIVACY_CONSENTS_STATE_OBSOLETE'),
|
||||
1 => Text::_('COM_PRIVACY_CONSENTS_STATE_VALID')
|
||||
];
|
||||
$this->getLanguage()->load('plg_system_privacyconsent', JPATH_ADMINISTRATOR);
|
||||
|
||||
?>
|
||||
<form action="<?php echo Route::_('index.php?option=com_privacy&view=consents'); ?>" method="post" name="adminForm" id="adminForm">
|
||||
<div id="j-main-container">
|
||||
<?php echo LayoutHelper::render('joomla.searchtools.default', ['view' => $this]); ?>
|
||||
<?php if (empty($this->items)) : ?>
|
||||
<div class="alert alert-info">
|
||||
<span class="icon-info-circle" aria-hidden="true"></span><span class="visually-hidden"><?php echo Text::_('INFO'); ?></span>
|
||||
<?php echo Text::_('JGLOBAL_NO_MATCHING_RESULTS'); ?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<table class="table" id="consentList">
|
||||
<caption class="visually-hidden">
|
||||
<?php echo Text::_('COM_PRIVACY_TABLE_CONSENTS_CAPTION'); ?>,
|
||||
<span id="orderedBy"><?php echo Text::_('JGLOBAL_SORTED_BY'); ?> </span>,
|
||||
<span id="filteredBy"><?php echo Text::_('JGLOBAL_FILTERED_BY'); ?></span>
|
||||
</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<td class="w-1 text-center">
|
||||
<?php echo HTMLHelper::_('grid.checkall'); ?>
|
||||
</td>
|
||||
<th scope="col" class="w-5 text-center">
|
||||
<?php echo HTMLHelper::_('searchtools.sort', 'JSTATUS', 'a.state', $listDirn, $listOrder); ?>
|
||||
</th>
|
||||
<th scope="col" class="w-10">
|
||||
<?php echo HTMLHelper::_('searchtools.sort', 'JGLOBAL_USERNAME', 'u.username', $listDirn, $listOrder); ?>
|
||||
</th>
|
||||
<th scope="col" class="w-10">
|
||||
<?php echo HTMLHelper::_('searchtools.sort', 'COM_PRIVACY_HEADING_NAME', 'u.name', $listDirn, $listOrder); ?>
|
||||
</th>
|
||||
<th scope="col" class="w-1">
|
||||
<?php echo HTMLHelper::_('searchtools.sort', 'COM_PRIVACY_HEADING_USERID', 'a.user_id', $listDirn, $listOrder); ?>
|
||||
</th>
|
||||
<th scope="col" class="w-10">
|
||||
<?php echo HTMLHelper::_('searchtools.sort', 'COM_PRIVACY_HEADING_CONSENTS_SUBJECT', 'a.subject', $listDirn, $listOrder); ?>
|
||||
</th>
|
||||
<th scope="col">
|
||||
<?php echo Text::_('COM_PRIVACY_HEADING_CONSENTS_BODY'); ?>
|
||||
</th>
|
||||
<th scope="col" class="w-15">
|
||||
<?php echo HTMLHelper::_('searchtools.sort', 'COM_PRIVACY_HEADING_CONSENTS_CREATED', 'a.created', $listDirn, $listOrder); ?>
|
||||
</th>
|
||||
<th scope="col" class="w-1">
|
||||
<?php echo HTMLHelper::_('searchtools.sort', 'JGRID_HEADING_ID', 'a.id', $listDirn, $listOrder); ?>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($this->items as $i => $item) : ?>
|
||||
<tr>
|
||||
<td class="text-center">
|
||||
<?php echo HTMLHelper::_('grid.id', $i, $item->id, false, 'cid', 'cb', $item->username); ?>
|
||||
</td>
|
||||
<td class="tbody-icon">
|
||||
<span class="icon-<?php echo $stateIcons[$item->state]; ?>" aria-hidden="true" title="<?php echo $stateMsgs[$item->state]; ?>"></span>
|
||||
<span class="visually-hidden"><?php echo $stateMsgs[$item->state]; ?>"></span>
|
||||
</td>
|
||||
<th scope="row">
|
||||
<?php echo $item->username; ?>
|
||||
</th>
|
||||
<td>
|
||||
<?php echo $item->name; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo $item->user_id; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo Text::_($item->subject); ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo $item->body; ?>
|
||||
</td>
|
||||
<td class="break-word">
|
||||
<?php echo HTMLHelper::_('date.relative', new Date($item->created), null, $now); ?>
|
||||
<div class="small">
|
||||
<?php echo HTMLHelper::_('date', $item->created, Text::_('DATE_FORMAT_LC6')); ?>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo (int) $item->id; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
|
||||
<input type="hidden" name="task" value="" />
|
||||
<input type="hidden" name="boxchecked" value="0" />
|
||||
<?php echo HTMLHelper::_('form.token'); ?>
|
||||
</div>
|
||||
</form>
|
||||
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<metadata>
|
||||
<layout title="COM_PRIVACY_CONSENTS_VIEW_DEFAULT_TITLE">
|
||||
<message>
|
||||
<![CDATA[COM_PRIVACY_CONSENTS_VIEW_DEFAULT_DESC]]>
|
||||
</message>
|
||||
</layout>
|
||||
</metadata>
|
||||
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2021 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Layout\LayoutHelper;
|
||||
|
||||
$displayData = [
|
||||
'textPrefix' => 'COM_PRIVACY_CONSENTS',
|
||||
'formURL' => 'index.php?option=com_privacy&view=consents',
|
||||
'helpURL' => 'https://docs.joomla.org/Special:MyLanguage/Help5.x:Privacy:_Consents',
|
||||
'icon' => 'icon-lock',
|
||||
];
|
||||
|
||||
echo LayoutHelper::render('joomla.content.emptystate', $displayData);
|
||||
@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\Component\Actionlogs\Administrator\Helper\ActionlogsHelper;
|
||||
|
||||
/** @var \Joomla\Component\Privacy\Administrator\View\Request\HtmlView $this */
|
||||
|
||||
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
|
||||
$wa = $this->getDocument()->getWebAssetManager();
|
||||
$wa->useScript('keepalive')
|
||||
->useScript('form.validate');
|
||||
?>
|
||||
<form action="<?php echo Route::_('index.php?option=com_privacy&view=request&id=' . (int) $this->item->id); ?>" method="post" name="adminForm" id="item-form" class="form-validate">
|
||||
<div class="row mt-3">
|
||||
<div class="col-12 col-md-4 mb-3">
|
||||
<div class="card">
|
||||
<h3 class="card-header"><?php echo Text::_('COM_PRIVACY_HEADING_REQUEST_INFORMATION'); ?></h3>
|
||||
<div class="card-body">
|
||||
<dl class="dl-horizontal">
|
||||
<dt><?php echo Text::_('JGLOBAL_EMAIL'); ?>:</dt>
|
||||
<dd><?php echo $this->item->email; ?></dd>
|
||||
|
||||
<dt><?php echo Text::_('JSTATUS'); ?>:</dt>
|
||||
<dd><?php echo HTMLHelper::_('privacy.statusLabel', $this->item->status); ?></dd>
|
||||
|
||||
<dt><?php echo Text::_('COM_PRIVACY_FIELD_REQUEST_TYPE_LABEL'); ?>:</dt>
|
||||
<dd><?php echo Text::_('COM_PRIVACY_HEADING_REQUEST_TYPE_TYPE_' . $this->item->request_type); ?></dd>
|
||||
|
||||
<dt><?php echo Text::_('COM_PRIVACY_FIELD_REQUESTED_AT_LABEL'); ?>:</dt>
|
||||
<dd><?php echo HTMLHelper::_('date', $this->item->requested_at, Text::_('DATE_FORMAT_LC6')); ?></dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-8 mb-3">
|
||||
<div class="card">
|
||||
<h3 class="card-header"><?php echo Text::_('COM_PRIVACY_HEADING_ACTION_LOG'); ?></h3>
|
||||
<div class="card-body">
|
||||
<?php if (empty($this->actionlogs)) : ?>
|
||||
<div class="alert alert-info">
|
||||
<span class="icon-info-circle" aria-hidden="true"></span><span class="visually-hidden"><?php echo Text::_('INFO'); ?></span>
|
||||
<?php echo Text::_('JGLOBAL_NO_MATCHING_RESULTS'); ?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<table class="table">
|
||||
<caption class="visually-hidden">
|
||||
<?php echo Text::_('COM_PRIVACY_HEADING_ACTION_LOG'); ?>
|
||||
</caption>
|
||||
<thead>
|
||||
<th scope="col">
|
||||
<?php echo Text::_('COM_ACTIONLOGS_ACTION'); ?>
|
||||
</th>
|
||||
<th scope="col">
|
||||
<?php echo Text::_('COM_ACTIONLOGS_DATE'); ?>
|
||||
</th>
|
||||
<th scope="col">
|
||||
<?php echo Text::_('COM_ACTIONLOGS_NAME'); ?>
|
||||
</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($this->actionlogs as $i => $item) : ?>
|
||||
<tr class="row<?php echo $i % 2; ?>">
|
||||
<th scope="row">
|
||||
<?php echo ActionlogsHelper::getHumanReadableLogMessage($item); ?>
|
||||
</th>
|
||||
<td>
|
||||
<?php echo HTMLHelper::_('date', $item->log_date, Text::_('DATE_FORMAT_LC6')); ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo $item->name; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="task" value="" />
|
||||
<?php echo HTMLHelper::_('form.token'); ?>
|
||||
</form>
|
||||
41
administrator/components/com_privacy/tmpl/request/edit.php
Normal file
41
administrator/components/com_privacy/tmpl/request/edit.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Router\Route;
|
||||
|
||||
/** @var \Joomla\Component\Privacy\Administrator\View\Request\HtmlView $this */
|
||||
|
||||
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
|
||||
$wa = $this->getDocument()->getWebAssetManager();
|
||||
$wa->useScript('keepalive')
|
||||
->useScript('form.validate');
|
||||
|
||||
?>
|
||||
|
||||
<form action="<?php echo Route::_('index.php?option=com_privacy&view=request&layout=edit&id=' . (int) $this->item->id); ?>" method="post" name="adminForm" id="item-form" aria-label="<?php echo Text::_('COM_PRIVACY_REQUEST_FORM_' . ((int) $this->item->id === 0 ? 'NEW' : 'EDIT'), true); ?>" class="form-validate">
|
||||
<div class="form-horizontal">
|
||||
<div class="card mt-3">
|
||||
<div class="card-body">
|
||||
<fieldset class="adminform">
|
||||
<?php echo $this->form->renderField('email'); ?>
|
||||
<?php echo $this->form->renderField('status'); ?>
|
||||
<?php echo $this->form->renderField('request_type'); ?>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="task" value="" />
|
||||
<?php echo HTMLHelper::_('form.token'); ?>
|
||||
</div>
|
||||
</form>
|
||||
130
administrator/components/com_privacy/tmpl/requests/default.php
Normal file
130
administrator/components/com_privacy/tmpl/requests/default.php
Normal file
@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Date\Date;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Layout\LayoutHelper;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\String\PunycodeHelper;
|
||||
|
||||
/** @var \Joomla\Component\Privacy\Administrator\View\Requests\HtmlView $this */
|
||||
|
||||
/** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */
|
||||
$wa = $this->getDocument()->getWebAssetManager();
|
||||
$wa->useScript('table.columns')
|
||||
->useScript('multiselect');
|
||||
|
||||
$user = $this->getCurrentUser();
|
||||
$listOrder = $this->escape($this->state->get('list.ordering'));
|
||||
$listDirn = $this->escape($this->state->get('list.direction'));
|
||||
$now = Factory::getDate();
|
||||
|
||||
$urgentRequestDate = clone $now;
|
||||
$urgentRequestDate->sub(new DateInterval('P' . $this->urgentRequestAge . 'D'));
|
||||
|
||||
?>
|
||||
<form action="<?php echo Route::_('index.php?option=com_privacy&view=requests'); ?>" method="post" name="adminForm" id="adminForm">
|
||||
<div id="j-main-container">
|
||||
<?php echo LayoutHelper::render('joomla.searchtools.default', ['view' => $this]); ?>
|
||||
<?php if (empty($this->items)) : ?>
|
||||
<div class="alert alert-info">
|
||||
<span class="icon-info-circle" aria-hidden="true"></span><span class="visually-hidden"><?php echo Text::_('INFO'); ?></span>
|
||||
<?php echo Text::_('JGLOBAL_NO_MATCHING_RESULTS'); ?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<table class="table" id="requestList">
|
||||
<caption class="visually-hidden">
|
||||
<?php echo Text::_('COM_PRIVACY_TABLE_CAPTION'); ?>,
|
||||
<span id="orderedBy"><?php echo Text::_('JGLOBAL_SORTED_BY'); ?> </span>,
|
||||
<span id="filteredBy"><?php echo Text::_('JGLOBAL_FILTERED_BY'); ?></span>
|
||||
</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="w-5 text-center">
|
||||
<?php echo Text::_('COM_PRIVACY_HEADING_ACTIONS'); ?>
|
||||
</th>
|
||||
<th scope="col" class="w-5 text-center">
|
||||
<?php echo Text::_('JSTATUS'); ?>
|
||||
</th>
|
||||
<th scope="col">
|
||||
<?php echo HTMLHelper::_('searchtools.sort', 'JGLOBAL_EMAIL', 'a.email', $listDirn, $listOrder); ?>
|
||||
</th>
|
||||
<th scope="col" class="w-10">
|
||||
<?php echo HTMLHelper::_('searchtools.sort', 'COM_PRIVACY_HEADING_REQUEST_TYPE', 'a.request_type', $listDirn, $listOrder); ?>
|
||||
</th>
|
||||
<th scope="col" class="w-15">
|
||||
<?php echo HTMLHelper::_('searchtools.sort', 'COM_PRIVACY_HEADING_REQUESTED_AT', 'a.requested_at', $listDirn, $listOrder); ?>
|
||||
</th>
|
||||
<th scope="col" class="w-1">
|
||||
<?php echo HTMLHelper::_('searchtools.sort', 'JGRID_HEADING_ID', 'a.id', $listDirn, $listOrder); ?>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($this->items as $i => $item) : ?>
|
||||
<?php
|
||||
$itemRequestedAt = new Date($item->requested_at);
|
||||
?>
|
||||
<tr>
|
||||
<td class="text-center">
|
||||
<div class="btn-group">
|
||||
<?php if ($item->status == 1 && $item->request_type === 'export') : ?>
|
||||
<a class="btn tbody-icon" href="<?php echo Route::_('index.php?option=com_privacy&task=request.export&format=xml&id=' . (int) $item->id); ?>" title="<?php echo Text::_('COM_PRIVACY_ACTION_EXPORT_DATA'); ?>"><span class="icon-download" aria-hidden="true"></span><span class="visually-hidden"><?php echo Text::_('COM_PRIVACY_ACTION_EXPORT_DATA'); ?></span></a>
|
||||
<?php if ($this->sendMailEnabled) : ?>
|
||||
<a class="btn tbody-icon" href="<?php echo Route::_('index.php?option=com_privacy&task=request.emailexport&id=' . (int) $item->id . '&' . Factory::getSession()->getFormToken() . '=1'); ?>" title="<?php echo Text::_('COM_PRIVACY_ACTION_EMAIL_EXPORT_DATA'); ?>"><span class="icon-mail" aria-hidden="true"></span><span class="visually-hidden"><?php echo Text::_('COM_PRIVACY_ACTION_EMAIL_EXPORT_DATA'); ?></span></a>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
<?php if ($item->status == 1 && $item->request_type === 'remove') : ?>
|
||||
<a class="btn tbody-icon" href="<?php echo Route::_('index.php?option=com_privacy&task=request.remove&id=' . (int) $item->id . '&' . Factory::getSession()->getFormToken() . '=1'); ?>" title="<?php echo Text::_('COM_PRIVACY_ACTION_DELETE_DATA'); ?>"><span class="icon-times" aria-hidden="true"></span><span class="visually-hidden"><?php echo Text::_('COM_PRIVACY_ACTION_DELETE_DATA'); ?></span></a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<?php echo HTMLHelper::_('privacy.statusLabel', $item->status); ?>
|
||||
</td>
|
||||
<th scope="row">
|
||||
<?php if ($item->status == 1 && $urgentRequestDate >= $itemRequestedAt) : ?>
|
||||
<span class="float-end badge bg-danger"><?php echo Text::_('COM_PRIVACY_BADGE_URGENT_REQUEST'); ?></span>
|
||||
<?php endif; ?>
|
||||
<a href="<?php echo Route::_('index.php?option=com_privacy&view=request&id=' . (int) $item->id); ?>" title="<?php echo Text::_('COM_PRIVACY_ACTION_VIEW'); ?>">
|
||||
<?php echo $this->escape(PunycodeHelper::emailToUTF8($item->email)); ?>
|
||||
</a>
|
||||
</th>
|
||||
<td>
|
||||
<?php echo Text::_('COM_PRIVACY_HEADING_REQUEST_TYPE_TYPE_' . $item->request_type); ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo HTMLHelper::_('date.relative', $itemRequestedAt, null, $now); ?>
|
||||
<div class="small">
|
||||
<?php echo HTMLHelper::_('date', $item->requested_at, Text::_('DATE_FORMAT_LC6')); ?>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo (int) $item->id; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<?php // load the pagination. ?>
|
||||
<?php echo $this->pagination->getListFooter(); ?>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
<input type="hidden" name="task" value="" />
|
||||
<input type="hidden" name="boxchecked" value="0" />
|
||||
<?php echo HTMLHelper::_('form.token'); ?>
|
||||
</div>
|
||||
</form>
|
||||
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<metadata>
|
||||
<layout title="COM_PRIVACY_REQUESTS_VIEW_DEFAULT_TITLE">
|
||||
<message>
|
||||
<![CDATA[COM_PRIVACY_REQUESTS_VIEW_DEFAULT_DESC]]>
|
||||
</message>
|
||||
</layout>
|
||||
</metadata>
|
||||
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Administrator
|
||||
* @subpackage com_privacy
|
||||
*
|
||||
* @copyright (C) 2021 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Layout\LayoutHelper;
|
||||
|
||||
$displayData = [
|
||||
'textPrefix' => 'COM_PRIVACY_REQUESTS',
|
||||
'formURL' => 'index.php?option=com_privacy&view=requests',
|
||||
'helpURL' => 'https://docs.joomla.org/Special:MyLanguage/Help5.x:Privacy:_Information_Requests',
|
||||
'icon' => 'icon-lock',
|
||||
];
|
||||
|
||||
if (Factory::getApplication()->get('mailonline', 1)) {
|
||||
$displayData['createURL'] = 'index.php?option=com_privacy&task=request.add';
|
||||
}
|
||||
|
||||
echo LayoutHelper::render('joomla.content.emptystate', $displayData);
|
||||
Reference in New Issue
Block a user